mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-14 18:26:11 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
911a09c743 | ||
|
|
2672dbdcf6 |
@@ -1,3 +1,2 @@
|
||||
worktrees/
|
||||
tmp/
|
||||
scheduled_tasks.lock
|
||||
+10
-36
@@ -29,44 +29,18 @@ Quick build check: `./gradlew assembleFossDebug`
|
||||
|
||||
- Use `assembleFossDebug` as the fastest build variant for iteration
|
||||
- Follow existing patterns — the codebase uses MVVM + Hilt + Coroutines
|
||||
- Always use string resources for user-facing text
|
||||
- Always use string resources for user-facing text (see localization rules)
|
||||
- Check `git log --oneline -20` for commit message style before committing
|
||||
- Ordinary unit tests use JUnit 5 + kotest assertions + mockk and extend `testhelpers.BaseTest` — not
|
||||
the Android defaults. `testFossDebugUnitTest` does not run `testGplay` tests
|
||||
- Changing a production screen that backs a `@PreviewTest` entry in `PlayStoreScreenshots.kt` means
|
||||
regenerating the smoke screenshot set
|
||||
|
||||
## Rules Reference
|
||||
|
||||
Always loaded:
|
||||
Detailed guidelines are in `.claude/rules/`:
|
||||
|
||||
| Rule | Covers |
|
||||
|------|--------|
|
||||
| `.claude/rules/architecture.md` | BLE vs AAP paths, `DeviceMonitor` merge boundary, FOSS pro gating |
|
||||
| `.claude/rules/build-commands.md` | Gradle commands and what CI actually gates |
|
||||
| `.claude/rules/commit-guidelines.md` | Commit message format and prefixes |
|
||||
| `.claude/rules/pull-requests.md` | PR title and description conventions |
|
||||
| `.claude/rules/agent-instructions.md` | Delegation limits and implementation scope |
|
||||
| `.claude/rules/release.md` | Release guardrails — never hand-edit versions or tags |
|
||||
|
||||
Loaded on demand, when a matching file is read (`paths:` frontmatter):
|
||||
|
||||
| Rule | Loads for |
|
||||
|------|-----------|
|
||||
| `.claude/rules/architecture-aap-protocol.md` | `**/aap/**`, conversation reaction |
|
||||
| `.claude/rules/code-style.md` | Kotlin/Compose sources in `main/`, `foss/`, `gplay/`, `debug/` |
|
||||
| `.claude/rules/testing.md` | `app/src/test/`, `testFoss/`, `testGplay/` |
|
||||
| `.claude/rules/localization.md` | `**/res/values/strings.xml` (base locale) |
|
||||
| `.claude/rules/screenshots.md` | Screenshot composables, `screenshotTest/`, fastlane scripts |
|
||||
|
||||
Skills, invoked by name:
|
||||
|
||||
| Skill | Purpose |
|
||||
|-------|---------|
|
||||
| `/release` | Release workflow dispatch, inputs, channel mapping, rollback |
|
||||
|
||||
## Scratch space
|
||||
|
||||
`.claude/tmp/` is gitignored. Put plans, repro screenshots, throwaway scripts, and captured logs
|
||||
there rather than in `/tmp` — they stay greppable and survive across sessions without being
|
||||
committed.
|
||||
- `architecture.md` — Module structure, key components, data flow, dependencies
|
||||
- `build-commands.md` — Build, test, lint, and release commands
|
||||
- `localization.md` — String resource naming conventions
|
||||
- `commit-guidelines.md` — Commit message format and prefixes
|
||||
- `pull-requests.md` — PR title and description conventions
|
||||
- `agent-instructions.md` — Sub-agent delegation and critical thinking
|
||||
- `screenshots.md` — Play Store screenshot pipeline, commands, adding new screens
|
||||
- `release.md` — Release workflow (`Release prepare` dispatch), inputs, channel mapping, rollback
|
||||
|
||||
@@ -1,32 +1,39 @@
|
||||
---
|
||||
description: Sub-agent delegation limits and implementation scope for this project
|
||||
description: Instructions for Claude Code sub-agents and task delegation
|
||||
globs:
|
||||
- "**"
|
||||
---
|
||||
|
||||
# Agent Instructions
|
||||
|
||||
## Delegation
|
||||
## Critical Thinking
|
||||
|
||||
Delegation adds coordination overhead and multiplies token cost, so it has to earn its place through
|
||||
genuine independence and parallel speedup.
|
||||
- Do not blindly accept information at face value
|
||||
- Verify assumptions against actual code before proceeding
|
||||
- When encountering unexpected behavior, investigate root causes rather than applying workarounds
|
||||
- If something seems wrong, it probably is — dig deeper
|
||||
|
||||
- Delegate only for large, genuinely independent work that parallelizes — a wide multi-file
|
||||
investigation across unrelated areas, for example
|
||||
- Don't delegate what you'd finish yourself in a handful of tool calls
|
||||
- Don't spawn a sub-agent to verify or double-check your own work
|
||||
- If one sub-agent can do it, use one rather than several
|
||||
- Sub-agents don't inherit your conversation — state the full task, the relevant paths, and
|
||||
whether you want research only or research plus implementation
|
||||
- `Explore` is the right type for read-only codebase investigation
|
||||
## Explore vs. Implement
|
||||
|
||||
Running Gradle through the build-runner agent is a separate standing rule in the user's global
|
||||
CLAUDE.md; it is context isolation, not delegation, and this file does not restate it.
|
||||
- **Explore first**: Before making changes, understand the existing code structure and patterns
|
||||
- **Read before writing**: Always read relevant files before modifying them
|
||||
- **Follow existing patterns**: Match the code style and architecture already in use
|
||||
- **Minimal changes**: Only change what's necessary to accomplish the task
|
||||
|
||||
## Implementation scope
|
||||
## Sub-Agent Delegation
|
||||
|
||||
- Follow existing patterns — match the code style and architecture already in use
|
||||
- Change only what the task needs
|
||||
- When behavior is unexpected, fix the root cause rather than working around it
|
||||
- Don't create new files when editing an existing one would do
|
||||
- Don't refactor surrounding code while fixing a bug
|
||||
- Don't add comments or docs to code you didn't change
|
||||
- Don't guess at file paths — use Glob/Grep
|
||||
When using Task tool to spawn sub-agents:
|
||||
|
||||
- Provide complete context — sub-agents don't share your conversation history unless noted
|
||||
- Be specific about what you need: research only, or research + implementation
|
||||
- Use `Explore` agent type for codebase investigation
|
||||
- Use `Bash` agent type for running builds and tests
|
||||
- Parallelize independent sub-agent tasks for efficiency
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Don't create new files when editing existing ones would suffice
|
||||
- Don't add features beyond what was requested
|
||||
- Don't refactor surrounding code when fixing a bug
|
||||
- Don't add comments or documentation to code you didn't change
|
||||
- Don't guess at file paths — use Glob/Grep to find them
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
---
|
||||
description: AAP protocol landmines and settled dead ends — what not to send, and what has already been proven impossible
|
||||
paths:
|
||||
- "app/src/main/java/**/aap/**"
|
||||
- "app/src/main/java/**/monitor/core/aap/**"
|
||||
- "app/src/main/java/**/reaction/core/conversation/**"
|
||||
---
|
||||
|
||||
# AAP Protocol — Landmines and Dead Ends
|
||||
|
||||
This file holds only what the code doesn't already say. The Conversational Awareness status
|
||||
taxonomy is KDoc'd on `ConversationAwarenessEvent`, the `0x4B` frame shapes are documented at the
|
||||
decode site in `DefaultAapDeviceProfile`, and known control IDs are catalogued in `AapControlId` —
|
||||
read those, don't duplicate them here.
|
||||
|
||||
## Never send `0x0001` mid-session
|
||||
|
||||
`AapMessageType.CAPABILITIES_REQUEST` (`0x0001`) is a **handshake-phase opcode only**. Sending
|
||||
`04 00 04 00 01 00` on an established session makes the device close the L2CAP stream
|
||||
(`Stream closed by remote`), forcing a full reconnect. Verified experimentally on AirPods Pro 3
|
||||
(fw `81.2675000075000000.6503`). The Stream State Info payload also differs between the original
|
||||
connection (45B) and the forced reconnect (28B), suggesting device-side state loss.
|
||||
|
||||
The enum lists it with no warning, so it looks callable. It isn't.
|
||||
|
||||
This came up as a "cheap refresh settings" probe after writing `DYNAMIC_END_OF_CHARGE` (`0x3B`),
|
||||
because the device doesn't echo that write in-session. **There is no read-setting primitive in AAP.**
|
||||
Settings are push-only — on connect, on external change, or not at all. The supported pattern is
|
||||
optimistic UI state + profile-learned persistence + let reconnects refresh.
|
||||
|
||||
## `0x37` does not use the Apple-bool encoding
|
||||
|
||||
Hearing Protection PPE (`0x37`, the EN 352 82 dBA media cap) is **Pro 3 only** and encodes as a
|
||||
plain `01 = on` / `00 = off`. Every other AAP boolean uses the Apple-bool convention where false is
|
||||
`0x02` — `encodeAppleBool` is wrong for this one. Companion `0x38` carries the cap level
|
||||
(observed `0x52` = 82 dBA).
|
||||
|
||||
Hardware-confirmed reads on Pro 3 (A3064), 2026-06-10. A full settings flood on Pro 2 USB-C (A3048)
|
||||
never contains `0x37` or `0x38`. Write-effect is **not** yet hardware-verified; it goes over the same
|
||||
PSM `0x1001` channel CAPod already writes ANC and CA to, so the risk is low, but it is untested.
|
||||
|
||||
## Settled dead ends — do not re-investigate
|
||||
|
||||
**Real-time ambient dB level (#521) is not implementable.** AirPods send no dB or attenuation
|
||||
telemetry over any AAP opcode or ATT characteristic. Apple's feature measures SPL with the Watch or
|
||||
iPhone microphone and subtracts a *static per-model lookup table* held in the private
|
||||
`HearingUtilities.framework`; AirPods contribute only their current listening mode. Established via
|
||||
the iOS 26.1 decompile plus a sweep of librepods, apple-wireshark, and the tyalie AAP definitions.
|
||||
`0x50` is PerfStats, `0x53` a PME config blob, `0x58` an Opus mic audio stream — none is a metric.
|
||||
|
||||
**Loud Sound Reduction (#520) has no non-root toggle.** LSR lives on a separate raw ATT channel, not
|
||||
AAP: a second L2CAP socket to **PSM 31 (`0x001F`)**, handle `0x1B`, plain `0x01`/`0x00`. Connecting
|
||||
and *reading* works without Apple vendor-ID spoofing. **Writes are silently ignored** — the pods
|
||||
return a Write Response (`13`) and the immediate read-back is unchanged. Reproduced back-to-back on
|
||||
Pixel 8 + Pro 2 USB-C, 2026-06-10. This matches librepods only exposing the toggle behind their
|
||||
root/Xposed VID-spoofing hook. A functional toggle is root-only; a read-only status indicator is
|
||||
feasible today.
|
||||
|
||||
Not to be confused with `0x37` above — different feature, different channel, and that one is a
|
||||
normal writable AAP setting.
|
||||
|
||||
## Session exclusivity
|
||||
|
||||
The pods accept exactly **one AAP session**. Any debug activity that boots the app starts
|
||||
`MonitorService`, which auto-connects and wins the socket — a proof-of-concept activity will connect
|
||||
at the L2CAP layer and then receive nothing. Protocol experiments have to go through the monitor's
|
||||
own session, i.e. the real feature write path.
|
||||
@@ -1,61 +1,123 @@
|
||||
---
|
||||
description: Load-bearing architectural invariants that are not obvious from reading the code
|
||||
description: Architecture overview, module structure, key components, data flow, and dependencies
|
||||
globs:
|
||||
- "app/**/*.kt"
|
||||
- "**/*.gradle.kts"
|
||||
---
|
||||
|
||||
# Architecture
|
||||
|
||||
Invariants worth knowing before you touch device state, the AAP stack, or the upgrade flow. Class
|
||||
inventories and source-set layout are omitted deliberately — read the tree for those.
|
||||
## Single-Module Structure
|
||||
|
||||
## BLE vs AAP
|
||||
One Gradle module: `app/`. Source sets:
|
||||
|
||||
Two independent data paths. Which one a feature can use decides whether it is even possible.
|
||||
- `main` — shared code (Compose UI, services, monitor, bluetooth, AAP protocol, widgets)
|
||||
- `foss` / `gplay` — flavor-specific code (e.g. upgrade/billing implementations)
|
||||
- `debug` — debug-only code including screenshot content composables
|
||||
- `test` / `testFoss` / `testGplay` — unit tests
|
||||
- `screenshotTest` — Compose Preview Screenshot tests for Play Store assets
|
||||
|
||||
A previous `app-common/` module was merged into `app/` (commit `be8f4919`).
|
||||
|
||||
## Core Patterns
|
||||
|
||||
- **MVVM**: ViewModels with LiveData/StateFlow for UI state management
|
||||
- **Dependency Injection**: Hilt/Dagger for dependency management
|
||||
- **Coroutines**: Kotlin coroutines for async operations
|
||||
- **Repository Pattern**: Data layer abstraction for monitoring and settings
|
||||
|
||||
## Key Components
|
||||
|
||||
### Device Monitoring
|
||||
|
||||
`monitor/core/` is split into two data-source siblings that `DeviceMonitor` merges:
|
||||
|
||||
- `monitor/core/ble/BlePodMonitor` — passive BLE scanning; reads Apple advertisement beacons (battery, case state, in-ear, etc.). Works for any pod in range; no pairing required
|
||||
- `monitor/core/aap/` — AAP connection lifecycle layer on top of `AapConnectionManager`:
|
||||
- `AapLifecycleManager` — starts/stops the AAP subsystem
|
||||
- `AapAutoConnect` — auto-opens AAP sessions for bonded/known devices
|
||||
- `AapKeyPersister`, `AapLearnedSettingsPersister` — persist session keys and learned pod settings across app restarts
|
||||
- `StemConfigSender`, `StemPressReaction`, `AncGestureResolver` — push config and react to stem/HID events
|
||||
- `monitor/core/cache/DeviceStateCache` — persisted last-known state so profiles still show data when a device is out of range
|
||||
- `DeviceMonitor` — singleton that `combine`s `BlePodMonitor.devices + AapConnectionManager.allStates + DeviceStateCache + profiles` into unified `PodDevice` objects. ViewModels observe `DeviceMonitor.devices`; they do **not** reach into `BlePodMonitor` or the AAP layer directly
|
||||
- `MonitorControl` / `MonitorService` — foreground service lifecycle holding the scan awake
|
||||
- `BluetoothEventReceiver`, `BootCompletedReceiver` — system triggers that wake the service
|
||||
|
||||
**BLE vs AAP — what each path gives you:**
|
||||
|
||||
| | BLE (advertisements) | AAP (L2CAP session) |
|
||||
|---|---|---|
|
||||
| Direction | Read-only, passive | Bidirectional commands + events |
|
||||
| Prerequisite | `BLUETOOTH_SCAN` on Android 12+, Bluetooth/location permissions below | Bonded + `BLUETOOTH_CONNECT` + active L2CAP socket |
|
||||
| Data | Battery, case open, in-ear, pod model | Settings, ANC control, press controls, stem events, device info |
|
||||
| Prerequisite | Bluetooth on | Bonded + `BLUETOOTH_CONNECT` + active L2CAP socket |
|
||||
| Data | Battery, case open, in-ear, pod model | Settings, ANC mode control, press controls, stem events, device info |
|
||||
| Availability | Any pod in range | Only your own paired pods |
|
||||
|
||||
A figure BLE never advertises cannot be obtained without a bonded AAP session, and anything
|
||||
requiring a write is AAP-only.
|
||||
### Reaction System
|
||||
|
||||
## `DeviceMonitor` is the state merge boundary
|
||||
- `ReactionsCard`: Compose UI for reaction settings, embedded in the device settings screen
|
||||
- `PopUpWindow`: Displays AirPods status when case is opened
|
||||
- `PopUpContent`: Compose pod rendering — model-specific UI branches inline, no factory class
|
||||
|
||||
`DeviceMonitor` (singleton) `combine`s four live sources — `BlePodMonitor.devices`,
|
||||
`AapConnectionManager.allStates`, `BluetoothManager2.connectedDevices` (supplies `isSystemConnected`),
|
||||
and `DeviceProfilesRepo.profiles` — then merges `DeviceStateCache` on top, deliberately after the
|
||||
combine so cache writes don't feed back into it.
|
||||
### Widget System (Glance)
|
||||
|
||||
The invariant is about **state**, not about the whole AAP layer:
|
||||
- `BatteryGlanceWidget`, `AncGlanceWidget`: Jetpack Glance-based home-screen widgets
|
||||
- `WidgetConfigurationActivity`: Configuration UI launched on widget placement
|
||||
- Lives under `app/src/main/java/eu/darken/capod/main/ui/widget/`
|
||||
|
||||
- Unified device state comes from `DeviceMonitor.devices` — don't assemble your own from `BlePodMonitor`
|
||||
- Commands go **through** `AapConnectionManager.sendCommand(...)`. ViewModels legitimately inject it
|
||||
(`OverviewViewModel`, `DeviceSettingsViewModel`, `PressControlsViewModel` all do)
|
||||
- Nothing outside the AAP engine touches `AapConnection` (the L2CAP socket wrapper) directly
|
||||
- `TroubleShooterViewModel` reaching into `BlePodMonitor` for raw diagnostic scans is an intentional
|
||||
exception, not a pattern to copy
|
||||
### Upgrade / Pro Features
|
||||
|
||||
Because the cache is merged in, a `PodDevice` may carry data while the device is out of range —
|
||||
presence in the flow does not imply a live connection.
|
||||
- `UpgradeRepo` interface with two flavor implementations:
|
||||
- `UpgradeRepoGplay` — billing-client backed, includes grace-period handling for interrupted purchases
|
||||
- `UpgradeControlFoss` — cache/sponsor-backed; users are `isPro = false` until they call `upgrade()`, after which the pro flag is persisted via DataStore
|
||||
- FOSS is **not** "always pro" — it's opt-in via a local sponsor flow
|
||||
|
||||
## `AapConnectionManager` owns sessions
|
||||
### AAP (Apple Accessory Protocol) Stack
|
||||
|
||||
It holds every open AAP session keyed by `BluetoothAddress`. Consumers call `sendCommand(...)` and
|
||||
observe `allStates`.
|
||||
Three-layer structure under `pods/core/apple/aap/`:
|
||||
|
||||
The stack under `pods/core/apple/aap/` splits into `protocol/` (pure data) and `engine/` (per-connection
|
||||
state machine). The glue in `monitor/core/aap/` wires it into the foreground service and persists
|
||||
learned settings and session keys across restarts.
|
||||
- **`protocol/`** — pure data: `AapMessage`, `AapCommand`, `AapSetting`, `AapDeviceProfile`, `AapDeviceInfo`, `StemPressEvent`, `KeyExchangeResult`. Plus `DefaultAapDeviceProfile` and `Model.Features` capturing per-model capability
|
||||
- **`engine/`** — session state machine for one connection:
|
||||
- `AapConnection` — the L2CAP socket wrapper
|
||||
- `AapSessionEngine` — drives the session lifecycle; tested in `AapSessionEngineTest`
|
||||
- `AapInboundInterpreter` / `AapOutboundController` — decode incoming messages, encode outgoing
|
||||
- `AapSettingsCoordinator`, `AapAncController`, `HidTracker`, `AapDeviceInfoDiagnostics` — feature-specific coordinators that sit on top of the session
|
||||
- **`AapConnectionManager`** (singleton) — owns all open AAP sessions keyed by `BluetoothAddress`, uses `L2capSocketFactory` to create sockets. Consumers don't touch `AapConnection` directly — they call `sendCommand(...)` and observe `allStates`
|
||||
|
||||
## FOSS is not "always pro"
|
||||
The monitor-layer glue (`monitor/core/aap/`) described above wires this stack into the foreground service and persists its learned state.
|
||||
|
||||
`UpgradeRepo` has two flavor implementations. `UpgradeControlFoss` starts users at `isPro = false`
|
||||
and only persists the pro flag after `upgrade()` is called via the local sponsor flow. Do not assume
|
||||
the FOSS flavor bypasses pro gating.
|
||||
### Common Utilities
|
||||
|
||||
## Navigation is mid-migration
|
||||
- `EdgeToEdgeHelper`: Handles Android edge-to-edge display insets
|
||||
|
||||
Navigation3 (`addNavigation3()`) drives current Compose routing, but legacy `androidx.navigation`
|
||||
helpers still exist (`NavDirectionsExtensions`, `ViewModel3`). Don't assume SafeArgs is fully gone.
|
||||
## Build Configuration
|
||||
|
||||
### Flavors
|
||||
|
||||
- **FOSS**: Open-source version without Google Play dependencies
|
||||
- **Google Play (gplay)**: Version with billing client for in-app purchases
|
||||
|
||||
### Build Types
|
||||
|
||||
- **debug**: Unobfuscated, full logging, no minification
|
||||
- **beta**: Obfuscated, production-ready with strict lint checks
|
||||
- **release**: Fully optimized for production distribution
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. `BluetoothEventReceiver` / `BootCompletedReceiver` wake `MonitorService` (foreground)
|
||||
2. `MonitorService` keeps `BlePodMonitor` scanning (passive advertisements) and `AapLifecycleManager` running (active L2CAP sessions via `AapConnectionManager`)
|
||||
3. `DeviceMonitor` merges BLE + AAP + cached state + profiles into `PodDevice` objects
|
||||
4. ViewModels (`OverviewViewModel`, `DeviceSettingsViewModel`, `PressControlsViewModel`, widget view models) observe `DeviceMonitor.devices`; settings/command changes are sent back through `AapConnectionManager.sendCommand(...)`
|
||||
5. Reaction triggers (case-open popup, auto-play, notifications) and widget state updates react to the merged flow
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
- **Unit Tests**: `app/src/test/` (shared), `app/src/testFoss/`, `app/src/testGplay/` (flavor-specific — e.g. `UpgradeRepoGplayTest`, `FossUpgradeSerializationTest`)
|
||||
- **Screenshot Tests**: `app/src/screenshotTest/` — Compose Preview Screenshot Testing, powers the Play Store screenshot pipeline
|
||||
|
||||
## Key Dependencies
|
||||
|
||||
- **Hilt**: Dependency injection framework
|
||||
- **Navigation**: Navigation3 (`addNavigation3()`) drives current Compose screen routing. Some legacy `androidx.navigation` helpers still exist (`NavDirectionsExtensions`, `ViewModel3`) — don't assume SafeArgs is fully gone
|
||||
- **kotlinx.serialization**: JSON serialization for configuration and caching
|
||||
- **Material Design 3**: Compose Material3 UI components
|
||||
|
||||
@@ -1,55 +1,71 @@
|
||||
---
|
||||
description: Gradle build, test, and lint commands, and what CI actually gates
|
||||
description: Build, test, lint, and release commands for Gradle
|
||||
globs:
|
||||
- "**/*.gradle.kts"
|
||||
- "**/*.gradle"
|
||||
- "gradle/**"
|
||||
---
|
||||
|
||||
# Build Commands
|
||||
|
||||
## Quick local check
|
||||
## Build
|
||||
|
||||
```bash
|
||||
./gradlew assembleFossDebug testFossDebugUnitTest
|
||||
# Build debug version
|
||||
./gradlew assembleDebug
|
||||
|
||||
# Build all variants (FOSS and Google Play flavors)
|
||||
./gradlew assemble
|
||||
|
||||
# Build specific flavor and type
|
||||
./gradlew assembleFossDebug
|
||||
./gradlew assembleGplayRelease
|
||||
|
||||
# Build app bundles for Play Store
|
||||
./gradlew bundleGplayRelease
|
||||
```
|
||||
|
||||
`assembleFossDebug` is the fastest variant — use it for iteration.
|
||||
|
||||
## What CI gates
|
||||
|
||||
`.github/workflows/code-checks.yml`, on every PR. Core Gradle gates:
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Lint vitals — flavor x variant matrix. Note: Beta/Release only, never Debug.
|
||||
./gradlew lintVitalFossBeta lintVitalFossRelease lintVitalGplayBeta lintVitalGplayRelease
|
||||
# Run all unit tests
|
||||
./gradlew test
|
||||
|
||||
# Builds — Debug only
|
||||
./gradlew app:assembleFossDebug app:assembleGplayDebug
|
||||
# Run unit tests for specific variant
|
||||
./gradlew testFossDebugUnitTest
|
||||
|
||||
# Unit tests — both flavors
|
||||
./gradlew testFossDebugUnitTest testGplayDebugUnitTest
|
||||
# Run instrumentation tests (requires connected device/emulator)
|
||||
./gradlew connectedAndroidTest
|
||||
./gradlew connectedFossDebugAndroidTest
|
||||
|
||||
# Run all checks (lint + tests)
|
||||
./gradlew check
|
||||
```
|
||||
|
||||
Four non-Gradle checks also run, **unconditionally** — there is no path filter, so they gate your PR
|
||||
even if you didn't touch those areas:
|
||||
## Code Quality
|
||||
|
||||
```bash
|
||||
bash fastlane/check_metadata_length.sh # Play Store metadata length limits
|
||||
shellcheck tools/release/bump.sh
|
||||
bats tools/release/bump.bats
|
||||
./tools/release/bump.sh --mode=check # version.properties + VERSION consistency
|
||||
# Run lint for all variants
|
||||
./gradlew lint
|
||||
|
||||
# Run lint for specific variant
|
||||
./gradlew lintFossDebug
|
||||
|
||||
# Auto-fix lint issues where possible
|
||||
./gradlew lintFix
|
||||
|
||||
# Update lint baseline
|
||||
./gradlew updateLintBaseline
|
||||
```
|
||||
|
||||
Reproducing those locally is usually only worth it when you changed fastlane metadata or release
|
||||
tooling, but a failure there blocks the PR regardless.
|
||||
|
||||
**Do not run `./gradlew check` as a pre-submit gate.** It runs the full non-vital `lint` task, which
|
||||
is already failing on `main` for reasons unrelated to your change — you'll burn time chasing
|
||||
pre-existing findings that CI never looks at. CI gates `lintVital*`, not `lint`.
|
||||
|
||||
## Other commands
|
||||
## Release
|
||||
|
||||
```bash
|
||||
./gradlew assembleGplayRelease # release build
|
||||
./gradlew bundleGplayRelease # Play Store bundle
|
||||
./gradlew connectedFossDebugAndroidTest # instrumentation, needs a device/emulator
|
||||
./gradlew lintFix # auto-fix where possible
|
||||
./gradlew updateLintBaseline # refresh the baseline
|
||||
./gradlew assembleFossRelease assembleGplayRelease
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Use `assembleFossDebug` as the default quick-check build (fastest variant)
|
||||
- Run `./gradlew check` before submitting changes to catch lint and test issues
|
||||
- Instrumentation tests require a connected device or running emulator
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
description: Kotlin and Compose conventions — logging, ViewModel base classes, the ScreenHost/Screen split, DataStore settings
|
||||
paths:
|
||||
- "app/src/main/**/*.kt"
|
||||
- "app/src/foss/**/*.kt"
|
||||
- "app/src/gplay/**/*.kt"
|
||||
- "app/src/debug/**/*.kt"
|
||||
---
|
||||
|
||||
# Code Style
|
||||
|
||||
## Logging
|
||||
|
||||
`logTag()` builds the tag; `log()` takes a lambda so the message is only built if it's emitted.
|
||||
|
||||
```kotlin
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.*
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Profiles", "Repo") // multi-part tags are the norm
|
||||
}
|
||||
|
||||
log(TAG) { "Processing $item" } // DEBUG is the default
|
||||
log(TAG, VERBOSE) { "Devices changed" }
|
||||
log(TAG, ERROR) { "Failed: ${e.asLog()}" } // asLog() for stacktraces
|
||||
```
|
||||
|
||||
Never suppress protocol logging — downgrading a level is fine, removing the call is not.
|
||||
|
||||
## ViewModel base classes
|
||||
|
||||
Four exist. Use **`ViewModel4`** for new work — it's the current one (12 subclasses) and wires
|
||||
`NavigationEventSource` + `ErrorEventSource2`.
|
||||
|
||||
- `ViewModel4` — current, use this
|
||||
- `ViewModel2` — plain base, no nav/error event sources (4 subclasses)
|
||||
- `ViewModel1` — legacy (1 subclass)
|
||||
- `ViewModel3` — **dead, zero subclasses.** It's the `ViewModel4` shape against the older
|
||||
`NavEventSource`/`ErrorEventSource` interfaces. Don't extend it.
|
||||
|
||||
## Compose: the Host/Screen split
|
||||
|
||||
Every screen is two composables.
|
||||
|
||||
**`<Feature>ScreenHost`** — the only place that touches `hiltViewModel()`, installs the event
|
||||
handlers, and collects state.
|
||||
|
||||
**`<Feature>Screen`** — presentation only. Takes a plain state object plus `on*` callbacks, so it
|
||||
previews without Hilt.
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun SettingsScreenHost(vm: SettingsViewModel = hiltViewModel()) {
|
||||
ErrorEventHandler(vm)
|
||||
NavigationEventHandler(vm)
|
||||
|
||||
val state by vm.state.collectAsStateWithLifecycle(initialValue = null)
|
||||
state?.let {
|
||||
SettingsScreen(
|
||||
state = it,
|
||||
onNavigateUp = { vm.navUp() },
|
||||
onWiki = { vm.openUrl("https://github.com/d4rken-org/capod/wiki") },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
state: SettingsViewModel.State,
|
||||
onNavigateUp: () -> Unit,
|
||||
onWiki: () -> Unit,
|
||||
modifier: Modifier = Modifier, // last, after the required params
|
||||
) { ... }
|
||||
```
|
||||
|
||||
- `modifier: Modifier = Modifier` goes after the required parameters — i.e. it is the first
|
||||
*optional* one, per the Compose API guidelines. capod is not fully consistent here (roughly 10
|
||||
composables put it after required params, 3 put it genuinely first); match the file you're in
|
||||
rather than reformatting neighbours
|
||||
- The Host null-guards state; `collectAsStateWithLifecycle(initialValue = null)` is the usual shape
|
||||
- Wrap previews in `PreviewWrapper` (`common/compose/PreviewWrapper.kt`), which applies `CapodTheme`
|
||||
plus a background `Surface`
|
||||
- Trailing commas on multi-line parameter lists and argument lists
|
||||
|
||||
## DataStore settings
|
||||
|
||||
`createValue()` is overloaded. Primitives need no serializer:
|
||||
|
||||
```kotlin
|
||||
val monitorMode = dataStore.createValue("core.monitor.mode", MonitorMode.AUTOMATIC)
|
||||
```
|
||||
|
||||
`@Serializable` types take a `Json`, and optionally fall back instead of throwing on corrupt or
|
||||
legacy stored JSON:
|
||||
|
||||
```kotlin
|
||||
val config = dataStore.createValue("some.config", SomeConfig(), json, onErrorFallbackToDefault = true)
|
||||
```
|
||||
|
||||
Read and write via `.value()` / `.value(x)` (suspend) or `.flow` (reactive). Both `value` functions
|
||||
are **extension functions**, not members — see `.claude/rules/testing.md` for what that means when
|
||||
mocking.
|
||||
|
||||
## General
|
||||
|
||||
- Package by feature, not by layer
|
||||
- Prefer adding to an existing file over creating a new one
|
||||
- Prefer flow-based, cancellable solutions
|
||||
- No comments for self-evident code
|
||||
- Place `@Suppress` as close to the affected code as possible — on the function or constructor,
|
||||
not the whole class
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
description: Git commit message format and conventions
|
||||
globs:
|
||||
- "**"
|
||||
---
|
||||
|
||||
# Commit Guidelines
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
description: Guidelines for adding and naming Android string resources
|
||||
paths:
|
||||
- "**/res/values/strings.xml"
|
||||
globs:
|
||||
- "**/res/values*/strings.xml"
|
||||
---
|
||||
|
||||
# Localization Guidelines
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
---
|
||||
description: Pull request title and description conventions
|
||||
description: Pull request naming and description conventions
|
||||
globs:
|
||||
- "**"
|
||||
---
|
||||
|
||||
# Pull Request Guidelines
|
||||
|
||||
## Title
|
||||
## PR Title Format
|
||||
|
||||
```
|
||||
<Category>: <Short user-facing summary>
|
||||
```
|
||||
|
||||
Titles appear in auto-generated changelogs and are read by users. Use ELI5, user-facing language —
|
||||
no class names, library names, or implementation details. `refactor(settings): Migrate preferences
|
||||
to DataStore` is the shape to avoid; `General: Remember settings between app restarts` is the shape
|
||||
to use.
|
||||
PR titles appear in auto-generated changelogs and are read by users. Use **ELI5, user-facing language** — no internal class names, library names, or implementation details.
|
||||
|
||||
| Category | Covers |
|
||||
## Category Prefixes
|
||||
|
||||
| Prefix | Covers |
|
||||
|--------|--------|
|
||||
| **Widget** | Home screen widget |
|
||||
| **Reaction** | Case-open popup, auto-play/pause, notification triggers |
|
||||
@@ -23,44 +24,76 @@ to use.
|
||||
| **General** | Dashboard, settings, notifications, themes, onboarding, support, app-wide UI |
|
||||
| **Fix** | Bug fixes spanning multiple areas |
|
||||
|
||||
## Description
|
||||
### Title Examples
|
||||
|
||||
PRs are reviewed in GitHub's web UI, which already shows the file tree, the diff, and the tests.
|
||||
The description answers what the diff can't. Use exactly these sections, in this order:
|
||||
- `Widget: Add color themes and transparency slider`
|
||||
- `Reaction: Fix popup appearing twice when opening AirPods case`
|
||||
- `Device: Add support for AirPods 4 with ANC`
|
||||
- `General: Add dark mode and color theme settings`
|
||||
- `Fix: Fix battery display stuck at 0% after reconnecting`
|
||||
|
||||
### Bad Titles (too technical)
|
||||
|
||||
- `refactor(settings): Migrate preferences to AndroidX DataStore`
|
||||
- `feat(widget): Migrate to Jetpack Glance`
|
||||
- `refactor(ui): Migrate from Fragments to Jetpack Compose`
|
||||
|
||||
## PR Description Format
|
||||
|
||||
PRs are reviewed in **GitHub's web UI**, which already shows the file tree, the diff, and the tests. Don't duplicate any
|
||||
of it. The description should answer questions the diff can't — not restate it.
|
||||
|
||||
Only these sections, in this order:
|
||||
|
||||
1. `## What changed`
|
||||
2. `## Technical Context`
|
||||
3. `## Review checklist` *(optional)*
|
||||
|
||||
No `Scope`, `Files changed`, `Tests`, or `Review guidance` sections.
|
||||
No `Scope`, `Files changed`, `Tests`, or `Review guidance` sub-sections — GitHub shows the files and tests, and review
|
||||
notes belong in the checklist. Fold anything critical into a Technical Context bullet.
|
||||
|
||||
**What changed** — user-facing explanation: the problem fixed or the feature added, from the user's
|
||||
perspective. For refactors, tests, CI, and dependency bumps, write "No user-facing behavior change"
|
||||
followed by a brief internal description.
|
||||
### What changed
|
||||
|
||||
**Technical Context** — one bullet per point, no prose paragraphs, no nested `**Bug 1**` headers.
|
||||
Cover only what the diff can't show:
|
||||
- **Why** this approach, and what was rejected
|
||||
- **Root cause** for bug fixes — the diff shows the fix, not what caused it
|
||||
- **Non-obvious side effects** or behavioral changes
|
||||
User-friendly explanation of what this PR does. Describe the problem that was fixed or the feature that was added from the user's perspective. No internal class or method names.
|
||||
|
||||
**Review checklist** — `- [ ]` items, only when there are several non-trivial things to verify.
|
||||
A single tricky point stays a Technical Context bullet.
|
||||
For non-user-facing PRs (refactors, tests, CI, dependency bumps): write "No user-facing behavior change" followed by a brief internal description.
|
||||
|
||||
## Labels
|
||||
### Technical Context
|
||||
|
||||
Apply labels that match the change. Run `gh label list` to confirm what exists — do not invent new
|
||||
ones. Skip labels that don't fit; no labels beats wrong labels.
|
||||
Explain what's hard to extract from the diff alone. Focus on:
|
||||
|
||||
- **Type**: `bug` for fixes, `enhancement` for new features or improvements
|
||||
- **Transport**: `coms/AAP` when the change touches the L2CAP session path, `coms/BLE` when it
|
||||
touches advertisement parsing. Both if it spans the merge in `DeviceMonitor`
|
||||
- **Scope**: `device support` for new or fixed pod models, `Translations` for string/locale work,
|
||||
`Build/Deploy` for CI, Gradle, and release tooling
|
||||
- `Needs Info/Repro` is a triage label for issues — not for your own PRs
|
||||
- **Why** this approach was chosen (and alternatives considered/rejected)
|
||||
- **Root cause** for bug fixes (the diff shows the fix, not what caused it)
|
||||
- **Non-obvious side effects** or behavioral changes not apparent from reading the code
|
||||
|
||||
Format rules:
|
||||
|
||||
- **One bullet per point.** No prose paragraphs, no nested sub-headers like `**Bug 1** / **Bug 2**` — if a PR fixes
|
||||
multiple bugs, one bullet per bug is enough.
|
||||
- **Don't restate the diff.** File paths, class renames, test names, and line-level changes are all visible in the web
|
||||
UI.
|
||||
|
||||
### Review checklist (optional)
|
||||
|
||||
For PRs with multiple non-trivial review points, add a `## Review checklist` section with `- [ ]` tasks the reviewer can
|
||||
tick off as they verify. Skip it for small PRs — a single tricky thing can stay as a Technical Context bullet.
|
||||
|
||||
### Example
|
||||
|
||||
```markdown
|
||||
## What changed
|
||||
|
||||
Fixed a crash that could happen when the AirPods case is opened while Bluetooth is turning off.
|
||||
|
||||
## Technical Context
|
||||
|
||||
- Root cause: `MonitorService` continued processing scan results during Bluetooth adapter state change, hitting a null adapter reference
|
||||
- Chose to gate on adapter state in the scan callback rather than adding a separate BroadcastReceiver, since the service already observes adapter state for restart logic
|
||||
- The timing window is ~200ms between ACTION_STATE_CHANGING and ACTION_STATE_OFF — only reproducible on Pixel devices with aggressive Bluetooth power management
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- Link issues with "Closes #123" / "Fixes #123" / "Resolves #123"
|
||||
- Prefix breaking changes with "BREAKING:"
|
||||
- No `Co-authored-by` trailers
|
||||
- **Issue references**: Use "Closes #123", "Fixes #123", or "Resolves #123"
|
||||
- **Breaking changes**: Mark with "BREAKING:" prefix if applicable
|
||||
- **No `Co-authored-by` trailers** (per project convention)
|
||||
|
||||
+75
-14
@@ -1,17 +1,78 @@
|
||||
---
|
||||
description: Release guardrails — what never to do by hand. Full procedure is the /release skill.
|
||||
---
|
||||
# Release Process
|
||||
|
||||
# Release
|
||||
Releases are cut via the **Release prepare** workflow (`.github/workflows/release-prepare.yml`). It bumps `version.properties` and `VERSION`, commits to `main`, tags `v<version>`, pushes atomically, and dispatches `release-tag.yml` which builds, signs, and uploads.
|
||||
|
||||
The procedure lives in the `/release` skill (invoke it deliberately; it does not auto-load).
|
||||
These constraints apply regardless of whether that skill was invoked.
|
||||
## Dispatch
|
||||
|
||||
- **`release-prepare.yml` is the only sanctioned path** for bumping a version or creating a release
|
||||
tag. Do not edit `version.properties` or `VERSION` by hand, and do not create `v*` tags manually —
|
||||
`validate-tag` in `release-tag.yml` rejects anything not matching `v<M.m.p>-(rc|beta)N`.
|
||||
- **`tools/release/bump.sh` is the single source of truth for version logic.** Its versionCode
|
||||
formula mirrors `buildSrc/src/main/java/ProjectConfig.kt` — the two must stay in sync.
|
||||
- CI runs `./tools/release/bump.sh --mode=check` on every PR (`check-release-tooling` in
|
||||
`code-checks.yml`). If you did touch `version.properties` or `VERSION`, run that locally first.
|
||||
- All numeric version fields are bounded `0..99`; the versionCode formula collapses at ≥100.
|
||||
```bash
|
||||
# Plan only — no commit, no tag, no push.
|
||||
gh workflow run release-prepare.yml -f bump_kind=build -f dry_run=true
|
||||
|
||||
# Real cut.
|
||||
gh workflow run release-prepare.yml -f bump_kind=build -f dry_run=false
|
||||
```
|
||||
|
||||
After `dry_run=false`: Job 1 computes + writes the summary, then Job 2 immediately commits/tags/pushes (no env gate — cancel the run between Job 1 and Job 2 if the summary looks wrong; you have ~seconds). The tag push naturally triggers `release-tag.yml` (the App-token push fires `on: push:` workflows; only `GITHUB_TOKEN`-pushes are suppressed). `release-tag.yml` then runs `validate-tag` and the existing `release-github` (`foss-production` approval) + `release-gplay` (`gplay-production` approval) jobs — those are the two human checkpoints, matching the pre-migration UX.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Default | Notes |
|
||||
|---|---|---|
|
||||
| `bump_kind` | `build` | `build` \| `patch` \| `minor` \| `major` |
|
||||
| `version_type` | `keep-current` | Preserves current `rc`/`beta`. Set explicitly to switch. |
|
||||
| `version_override` | empty | e.g. `5.1.2-rc0`. Bypasses bump_kind/version_type. |
|
||||
| `expected_current` | empty | Optional: fail if `version.properties` ≠ this. Useful for tight coordination. |
|
||||
| `dry_run` | `true` | Default is plan-only. |
|
||||
|
||||
Bump rules: `build` increments build; `patch`/`minor`/`major` zero everything to the right of the bumped field. All numeric fields bounded `0..99` (the `versionCode` formula collapses at ≥100).
|
||||
|
||||
## Local
|
||||
|
||||
```bash
|
||||
./tools/release/bump.sh --mode=plan --bump-kind=build --version-type=keep-current
|
||||
./tools/release/bump.sh --mode=check
|
||||
bats tools/release/bump.bats
|
||||
```
|
||||
|
||||
## Channel mapping
|
||||
|
||||
| Tag suffix | FOSS APK | GitHub release | Fastlane lane | Play track | Rollout |
|
||||
|---|---|---|---|---|---|
|
||||
| `-beta*` | `assembleFossBeta` | pre-release | `beta` | `beta` | 10% |
|
||||
| `-rc*` (or anything else) | `assembleFossRelease` | full release | `production` | **`beta`** | 10% |
|
||||
|
||||
`lane :production` in `Fastfile` uploads to Play's **beta** track at 10% — manually promoted to production via Play Console.
|
||||
|
||||
## Rollback
|
||||
|
||||
| Stage reached | Steps |
|
||||
|---|---|
|
||||
| Bump on `main`, downstream not started | `git push origin :refs/tags/v<bad>`, `git revert <bump-sha>`, push |
|
||||
| GitHub release created | Above + `gh release delete v<bad> --yes --cleanup-tag` |
|
||||
| Play upload completed | Above + halt rollout in Play Console (or `bundle exec fastlane supply --track beta --rollout 0 --version-code <bad-code>`) |
|
||||
| Job 2 ran but downstream rejected at env approval | Treat as first row — bump+tag are public on `main` regardless of downstream outcome |
|
||||
|
||||
`bump.sh` enforces strict `versionCode` monotonicity, so re-using a code is impossible without manually editing `version.properties`.
|
||||
|
||||
## Auth setup
|
||||
|
||||
`release-prepare.yml` Job 2 uses a GitHub App token (not `GITHUB_TOKEN`) to push the bump commit and tag. The App identity is in the rulesets' bypass list, which is what allows the push to bypass branch protection + tag-creation restrictions.
|
||||
|
||||
Required org secrets (set on the d4rken-org organization, accessible to `capod`):
|
||||
|
||||
- `RELEASE_APP_CLIENT_ID` — Client ID of the `d4rken-org-releaser` GitHub App (visible on the App's settings page, format `Iv1.<hex>` or similar)
|
||||
- `RELEASE_APP_PRIVATE_KEY` — full `.pem` contents (including BEGIN/END lines)
|
||||
|
||||
The App is installed on this repo and added as a bypass actor to:
|
||||
- The main-branch ruleset (PR + status check requirements)
|
||||
- The tag ruleset (creation restriction on `v*`)
|
||||
|
||||
Other apps in the org can reuse the same App + secrets — just install the App on each repo and add it to that repo's rulesets' bypass lists.
|
||||
|
||||
## Defense in depth
|
||||
|
||||
`release-tag.yml` includes `validate-tag` which: (1) regex-checks `github.ref_name`, (2) runs `bump.sh --mode=check`, (3) asserts the parsed name matches the tag. Manual `gh workflow run release-tag.yml --ref vfoo` or hand-pushed tags fail before any build.
|
||||
|
||||
## Stuck-dispatch recovery
|
||||
|
||||
If Job 2's atomic push lands but the natural `on: push:` trigger doesn't fire `release-tag.yml` (rare — would mean GitHub dropped the event), the tag is public but no pipeline runs. Re-dispatch manually: `gh workflow run release-tag.yml --ref v<new> -f dry_run=false`.
|
||||
@@ -1,14 +1,3 @@
|
||||
---
|
||||
description: Play Store screenshot pipeline — generation, copying, and adding or removing screens
|
||||
paths:
|
||||
- "app/src/debug/**/screenshots/**"
|
||||
- "app/src/screenshotTest/**"
|
||||
- "fastlane/generate_screenshots.sh"
|
||||
- "fastlane/copy_screenshots.sh"
|
||||
- "fastlane/Fastfile"
|
||||
- "fastlane/metadata/android/*/images/phoneScreenshots/**"
|
||||
---
|
||||
|
||||
# Play Store Screenshot Pipeline
|
||||
|
||||
## Overview
|
||||
@@ -30,7 +19,7 @@ ScreenshotContent.kt (mock data + composables)
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `app/src/debug/java/.../screenshots/ScreenshotContent.kt` | Mock data composables (7 exist; `HomescreenWidgetContent` has an IDE preview only and is **not** in the Play Store pipeline) |
|
||||
| `app/src/debug/java/.../screenshots/ScreenshotContent.kt` | Mock data composables for each screen (7 screens) |
|
||||
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreScreenshots.kt` | `@PreviewTest` functions (currently: `DashboardLight`, `DashboardDark`, `CasePopUp`, `DeviceProfiles`, `AddProfile`, `DeviceSettingsReactions`, `WidgetConfiguration`) |
|
||||
| `app/src/screenshotTest/kotlin/.../screenshots/PlayStoreLocales.kt` | Multi-preview annotations (auto-generated by batch script) |
|
||||
| `fastlane/generate_screenshots.sh` | Batched generation; locale list (`ALL_LOCALES`) and `BATCH_SIZE` are defined inside the script |
|
||||
@@ -88,7 +77,7 @@ When modifying a screen that appears in screenshots (check `ScreenshotContent.kt
|
||||
Periodic, manual operation — not per-PR:
|
||||
|
||||
```bash
|
||||
./fastlane/generate_screenshots.sh # full, ~30 min, 476 PNGs (68 locales x 7)
|
||||
./fastlane/generate_screenshots.sh # full, ~30 min, 477 PNGs
|
||||
./fastlane/copy_screenshots.sh --clean
|
||||
bundle exec fastlane screenshots_only # uploads all 68 locales to Play Store
|
||||
git checkout -- fastlane/metadata/android/ # discard non-smoke changes (gitignored anyway)
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
---
|
||||
description: Unit test conventions — JUnit 5, kotest assertions, mockk, BaseTest, and which Gradle task runs which source set
|
||||
paths:
|
||||
- "app/src/test/**"
|
||||
- "app/src/testFoss/**"
|
||||
- "app/src/testGplay/**"
|
||||
- "app/build.gradle.kts"
|
||||
- "buildSrc/src/main/java/Dependencies.kt"
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
The stack here is not the Android default — check this before reaching for a familiar library.
|
||||
|
||||
## Libraries
|
||||
|
||||
- **JUnit 5** (`org.junit.jupiter.api.Test`). Gradle sets `useJUnitPlatform()`.
|
||||
- **kotest** for assertions: `io.kotest.matchers.shouldBe`, `shouldBeNull`, `shouldBeInstanceOf`,
|
||||
`shouldContainExactly`, `io.kotest.assertions.throwables.shouldThrow`. Use kotest for new
|
||||
assertions — `MediaControlTest` still uses JUnit `Assertions.*` and is a legacy exception.
|
||||
- **mockk** for mocking. Not Mockito.
|
||||
- **Turbine is not a dependency.** `testhelpers.flow.FlowTest` provides a `Flow<T>.test()` helper —
|
||||
use it rather than adding one.
|
||||
|
||||
## Base classes
|
||||
|
||||
Extend `testhelpers.BaseTest`, or the applicable specialized base that already extends it:
|
||||
|
||||
- `BaseBlePodsTest` — BLE advertisement parsing per pod model
|
||||
- `BaseAapSessionTest` — AAP protocol/session tests
|
||||
|
||||
`BaseTest` installs a `JUnitLogger` and calls `unmockkAll()` in `@AfterAll`. Skipping it can leave
|
||||
global mockk and logging state behind for later test classes.
|
||||
|
||||
The only exceptions are the Robolectric-backed tests (Compose UI via
|
||||
`testhelpers.compose.BaseComposeRobolectricTest`, and the few DataStore-backed ones such as
|
||||
`CurriculumVitaeProHistoryTest`), which use JUnit 4 `@RunWith`/`@Rule` via `junit-vintage-engine`.
|
||||
Don't copy that pattern for a plain unit test.
|
||||
|
||||
## Source sets and Gradle tasks
|
||||
|
||||
Each task compiles and runs only its own flavor — running the wrong one silently skips your test.
|
||||
|
||||
| Test location | Task |
|
||||
|---|---|
|
||||
| `app/src/test/` (shared) | either; run both before pushing |
|
||||
| `app/src/testFoss/` | `./gradlew testFossDebugUnitTest` |
|
||||
| `app/src/testGplay/` | `./gradlew testGplayDebugUnitTest` |
|
||||
|
||||
CI runs both. Flavor-specific tests are for code that only exists in that flavor — billing in
|
||||
`gplay`, the sponsor-based upgrade flow in `foss`.
|
||||
|
||||
## Helpers that already exist
|
||||
|
||||
- `runTest2(autoCancel, context, expectedError, testBody)` in `testhelpers/coroutine/TestExtensions.kt` —
|
||||
use `expectedError = SomeException::class` instead of hand-rolling a throws-assertion around `runTest`
|
||||
- `FakeDataStoreValue<T>(initial)` in `testhelpers/datastore/` — a working fake with a real backing
|
||||
`MutableStateFlow`; read/write it through `.value` and pass `.mock` to the code under test
|
||||
|
||||
## Mocking `DataStoreValue`
|
||||
|
||||
`DataStoreValue.value()` and `.value(T)` are **extension functions** (`DataStoreValue.kt:54,56`), not
|
||||
members, so MockK cannot stub them. They delegate to `flow.first()` and `update { }` — stub those:
|
||||
|
||||
```kotlin
|
||||
every { someSetting.flow } returns flowOf(value) // covers .value() reads
|
||||
coVerify { someSetting.update(any()) } // verifies .value(x) writes
|
||||
```
|
||||
|
||||
`UpgradeRepoGplayTest` uses this shape. Prefer `FakeDataStoreValue` when you need reads and writes to
|
||||
actually round-trip.
|
||||
|
||||
## Reading ViewModel state
|
||||
|
||||
`ViewModel2.asLiveState()` is `stateIn(..., initialValue = null).filterNotNull()` with
|
||||
`SharingStarted.WhileSubscribed(5_000)` — so `vm.state` is a `Flow`, not a `StateFlow`, and has no
|
||||
`.value` to read. Collect it: `vm.state.first()` is the established pattern across the existing
|
||||
ViewModel tests. Because the upstream only runs while subscribed, a test that never collects sees
|
||||
nothing happen at all.
|
||||
@@ -12,8 +12,6 @@
|
||||
"jvm-tools@claude-code-cafe": true,
|
||||
"frontend-design@claude-plugins-official": true,
|
||||
"kotlin-lsp@claude-plugins-official": true,
|
||||
"support-investigator@claude-code-cafe": true,
|
||||
"google-play@claude-code-cafe": true,
|
||||
"devtools@claude-code-cafe": true
|
||||
"support-investigator@claude-code-cafe": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
---
|
||||
description: Cut a capod release via the "Release prepare" workflow — dispatch inputs, channel mapping, rollback, and auth setup.
|
||||
disable-model-invocation: true
|
||||
argument-hint: "[bump_kind] [version_type|version_override]"
|
||||
---
|
||||
|
||||
# Release Process
|
||||
|
||||
Releases are cut via the **Release prepare** workflow (`.github/workflows/release-prepare.yml`). It bumps `version.properties` and `VERSION`, commits to `main`, tags `v<version>`, pushes atomically, and dispatches `release-tag.yml` which builds, signs, and uploads.
|
||||
|
||||
## Required order
|
||||
|
||||
A real cut pushes a commit and a tag to `main` and is public the moment it lands. Do not skip ahead.
|
||||
|
||||
1. Run the dry run first and read its summary — never dispatch `dry_run=false` blind.
|
||||
2. Report the planned version and `versionCode` back to the user.
|
||||
3. Get explicit confirmation for that specific version before dispatching `dry_run=false`.
|
||||
4. If the user named `bump_kind`/`version_type`/`version_override`, use exactly those. If the request
|
||||
is ambiguous about which field moves, ask rather than assuming `build`.
|
||||
|
||||
## Dispatch
|
||||
|
||||
`gh workflow run` only fires the dispatch — it returns nothing about the result. The summary is
|
||||
written asynchronously, so you have to go fetch it.
|
||||
|
||||
```bash
|
||||
# Step 1 — plan only. No commit, no tag, no push. Always run this first.
|
||||
gh workflow run release-prepare.yml -f bump_kind=build -f dry_run=true
|
||||
|
||||
# Step 2 — find the run just dispatched and wait for it.
|
||||
gh run list --workflow=release-prepare.yml --limit 1 # note the run id
|
||||
gh run watch <run-id> --exit-status
|
||||
|
||||
# Step 3 — read the computed plan (version + versionCode) before going further.
|
||||
gh run view <run-id> --log | tail -40
|
||||
```
|
||||
|
||||
Report the planned version and `versionCode`, get explicit confirmation, then:
|
||||
|
||||
```bash
|
||||
# Step 4 — real cut. Repeat the dry run's inputs EXACTLY; change only dry_run.
|
||||
gh workflow run release-prepare.yml -f bump_kind=build -f dry_run=false
|
||||
```
|
||||
|
||||
The `bump_kind=build` above is only an example. If the confirmed plan came from a `patch`/`minor`/
|
||||
`major` bump, a `version_type` switch, or a `version_override`, Step 4 must carry those same flags —
|
||||
otherwise you cut a different version than the one that was approved.
|
||||
|
||||
After `dry_run=false`: Job 1 computes + writes the summary, then Job 2 immediately commits/tags/pushes (no env gate — cancel the run between Job 1 and Job 2 if the summary looks wrong; you have ~seconds). The tag push naturally triggers `release-tag.yml` (the App-token push fires `on: push:` workflows; only `GITHUB_TOKEN`-pushes are suppressed). `release-tag.yml` then runs `validate-tag` and the existing `release-github` (`foss-production` approval) + `release-gplay` (`gplay-production` approval) jobs — those are the two human checkpoints, matching the pre-migration UX.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Default | Notes |
|
||||
|---|---|---|
|
||||
| `bump_kind` | `build` | `build` \| `patch` \| `minor` \| `major` |
|
||||
| `version_type` | `keep-current` | Preserves current `rc`/`beta`. Set explicitly to switch. |
|
||||
| `version_override` | empty | e.g. `5.1.2-rc0`. Bypasses bump_kind/version_type. |
|
||||
| `expected_current` | empty | Optional: fail if `version.properties` ≠ this. Useful for tight coordination. |
|
||||
| `dry_run` | `true` | Default is plan-only. |
|
||||
|
||||
Bump rules: `build` increments build; `patch`/`minor`/`major` zero everything to the right of the bumped field. All numeric fields bounded `0..99` (the `versionCode` formula collapses at ≥100).
|
||||
|
||||
## Local
|
||||
|
||||
```bash
|
||||
./tools/release/bump.sh --mode=plan --bump-kind=build --version-type=keep-current
|
||||
./tools/release/bump.sh --mode=check
|
||||
bats tools/release/bump.bats
|
||||
```
|
||||
|
||||
## Channel mapping
|
||||
|
||||
| Tag suffix | FOSS APK | GitHub release | Fastlane lane | Play track | Rollout |
|
||||
|---|---|---|---|---|---|
|
||||
| `-beta*` | `assembleFossBeta` | pre-release | `beta` | `beta` | 10% |
|
||||
| `-rc*` | `assembleFossRelease` | full release | `production` | **`beta`** | 10% |
|
||||
|
||||
`release-tag.yml` accepts only `v<M.m.p>-rcN` or `v<M.m.p>-betaN` — any other suffix fails
|
||||
`validate-tag` before a build starts. There is no third channel.
|
||||
|
||||
`lane :production` in `Fastfile` uploads to Play's **beta** track at 10% — manually promoted to production via Play Console.
|
||||
|
||||
## Rollback
|
||||
|
||||
| Stage reached | Steps |
|
||||
|---|---|
|
||||
| Bump on `main`, downstream not started | `git push origin :refs/tags/v<bad>`, `git revert <bump-sha>`, push |
|
||||
| GitHub release created | Above + `gh release delete v<bad> --yes --cleanup-tag` |
|
||||
| Play upload completed | Above + halt rollout in Play Console (or `bundle exec fastlane supply --track beta --rollout 0 --version-code <bad-code>`) |
|
||||
| Job 2 ran but downstream rejected at env approval | Treat as first row — bump+tag are public on `main` regardless of downstream outcome |
|
||||
|
||||
`bump.sh` enforces strict `versionCode` monotonicity, so re-using a code is impossible without manually editing `version.properties`.
|
||||
|
||||
## Auth setup
|
||||
|
||||
`release-prepare.yml` Job 2 uses a GitHub App token (not `GITHUB_TOKEN`) to push the bump commit and tag. The App identity is in the rulesets' bypass list, which is what allows the push to bypass branch protection + tag-creation restrictions.
|
||||
|
||||
Required org secrets (set on the d4rken-org organization, accessible to `capod`):
|
||||
|
||||
- `RELEASE_APP_CLIENT_ID` — Client ID of the `d4rken-org-releaser` GitHub App (visible on the App's settings page, format `Iv1.<hex>` or similar)
|
||||
- `RELEASE_APP_PRIVATE_KEY` — full `.pem` contents (including BEGIN/END lines)
|
||||
|
||||
The App is installed on this repo and added as a bypass actor to:
|
||||
- The main-branch ruleset (PR + status check requirements)
|
||||
- The tag ruleset (creation restriction on `v*`)
|
||||
|
||||
Other apps in the org can reuse the same App + secrets — just install the App on each repo and add it to that repo's rulesets' bypass lists.
|
||||
|
||||
## Defense in depth
|
||||
|
||||
`release-tag.yml` includes `validate-tag` which: (1) regex-checks `github.ref_name`, (2) runs `bump.sh --mode=check`, (3) asserts the parsed name matches the tag. Manual `gh workflow run release-tag.yml --ref vfoo` or hand-pushed tags fail before any build.
|
||||
|
||||
## Stuck-dispatch recovery
|
||||
|
||||
If Job 2's atomic push lands but the natural `on: push:` trigger doesn't fire `release-tag.yml` (rare — would mean GitHub dropped the event), the tag is public but no pipeline runs. Re-dispatch manually: `gh workflow run release-tag.yml --ref v<new> -f dry_run=false`.
|
||||
@@ -1,26 +0,0 @@
|
||||
name: Thumbnail images
|
||||
|
||||
# Shrinks oversized screenshots in issues and comments into clickable
|
||||
# thumbnails. The logic lives in d4rken-org/.github so every app repo shares
|
||||
# one copy; this stub only supplies the triggers, because workflow_call cannot
|
||||
# be triggered by issue_comment directly.
|
||||
#
|
||||
# The shared workflow splits into an unprivileged parsing job and a privileged
|
||||
# job that only makes the API call, so issues:write below is the ceiling, not
|
||||
# what the parsing half receives.
|
||||
#
|
||||
# Add <!-- no-thumbnail --> to a body to opt it out.
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
thumbnail:
|
||||
permissions:
|
||||
issues: write
|
||||
uses: d4rken-org/.github/.github/workflows/thumbnail-images.yml@3756372c3c844e4817c03d27983691f9991a19f4
|
||||
+2
-11
@@ -195,17 +195,8 @@ dependencies {
|
||||
|
||||
addTesting()
|
||||
|
||||
"gplayImplementation"("com.android.billingclient:billing:8.3.0")
|
||||
"gplayImplementation"("com.android.billingclient:billing-ktx:8.3.0")
|
||||
|
||||
"gplayImplementation"("com.google.android.play:review:2.0.2")
|
||||
"gplayImplementation"("com.google.android.play:review-ktx:2.0.2")
|
||||
|
||||
// Robolectric-backed Compose UI tests (run as regular unit tests via the vintage engine).
|
||||
testImplementation(platform("androidx.compose:compose-bom:${Versions.Compose.bom}"))
|
||||
testImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
testImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
testImplementation("org.robolectric:robolectric:4.15.1")
|
||||
"gplayImplementation"("com.android.billingclient:billing:8.0.0")
|
||||
"gplayImplementation"("com.android.billingclient:billing-ktx:8.0.0")
|
||||
|
||||
"screenshotTestImplementation"(platform("androidx.compose:compose-bom:${Versions.Compose.bom}"))
|
||||
"screenshotTestImplementation"("com.android.tools.screenshot:screenshot-validation-api:0.0.1-alpha13")
|
||||
|
||||
@@ -19,7 +19,6 @@ import eu.darken.capod.common.compose.PreviewWrapper
|
||||
import eu.darken.capod.common.compose.preview.MOCK_NOW
|
||||
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
||||
import eu.darken.capod.common.theming.CapodTheme
|
||||
import eu.darken.capod.main.core.MonitorMode
|
||||
import eu.darken.capod.main.ui.overview.OverviewScreen
|
||||
import eu.darken.capod.main.ui.overview.OverviewViewModel
|
||||
import eu.darken.capod.monitor.core.battery.BatteryEstimate
|
||||
@@ -86,7 +85,6 @@ internal fun DashboardContent(showAap: Boolean = false) = PreviewWrapper {
|
||||
devices = devices,
|
||||
isDebug = false,
|
||||
isBluetoothEnabled = true,
|
||||
effectiveMode = MonitorMode.AUTOMATIC,
|
||||
profiles = listOf(
|
||||
MockPodDataProvider.profile("My AirPods Pro", PodModel.AIRPODS_PRO2),
|
||||
MockPodDataProvider.profile("AirPods Max", PodModel.AIRPODS_MAX),
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package eu.darken.capod.common.review
|
||||
|
||||
import android.app.Activity
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.INFO
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class FossReviewTool @Inject constructor() : ReviewTool {
|
||||
|
||||
|
||||
override val state: Flow<ReviewTool.State> = flowOf(ReviewTool.State())
|
||||
|
||||
override suspend fun dismiss() {
|
||||
log(TAG, INFO) { "dismiss()" }
|
||||
// NOOP
|
||||
}
|
||||
|
||||
override suspend fun reviewNow(activity: Activity) {
|
||||
log(TAG, INFO) { "reviewNow($activity)" }
|
||||
// NOOP
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = logTag("Review", "Tool", "FOSS")
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package eu.darken.capod.common.review
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class ReviewModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun reviewTool(tool: FossReviewTool): ReviewTool
|
||||
}
|
||||
@@ -4,8 +4,7 @@ import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import eu.darken.capod.common.upgrade.core.UpgradeDiagnosticsFoss
|
||||
import eu.darken.capod.common.upgrade.core.UpgradeRepoFoss
|
||||
import eu.darken.capod.common.upgrade.core.UpgradeControlFoss
|
||||
import javax.inject.Singleton
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@@ -13,10 +12,6 @@ import javax.inject.Singleton
|
||||
abstract class UpgradeModule {
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun control(foss: UpgradeRepoFoss): UpgradeRepo
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun diagnostics(foss: UpgradeDiagnosticsFoss): UpgradeDiagnostics
|
||||
abstract fun control(foss: UpgradeControlFoss): UpgradeRepo
|
||||
|
||||
}
|
||||
@@ -12,25 +12,18 @@ import kotlinx.serialization.json.Json
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
// Retained legacy migration: installs that predate the DataStore move still carry their upgrade
|
||||
// state in the "settings_foss" SharedPreferences file.
|
||||
private val Context.fossCacheDataStore by preferencesDataStore(
|
||||
name = "settings_foss",
|
||||
produceMigrations = { ctx -> listOf(SharedPreferencesMigration(ctx, "settings_foss")) },
|
||||
)
|
||||
|
||||
@Singleton
|
||||
class FossCache internal constructor(
|
||||
// Test seam: the store is handed in so a test can supply its own DataStore instead of the
|
||||
// Context-bound production delegate. Same pattern as BillingCache.
|
||||
private val dataStore: DataStore<Preferences>,
|
||||
json: Json,
|
||||
class FossCache @Inject constructor(
|
||||
@ApplicationContext context: Context,
|
||||
@SerializationCapod json: Json,
|
||||
) {
|
||||
|
||||
@Inject constructor(
|
||||
@ApplicationContext context: Context,
|
||||
@SerializationCapod json: Json,
|
||||
) : this(context.fossCacheDataStore, json)
|
||||
private val Context.dataStore by preferencesDataStore(
|
||||
name = "settings_foss",
|
||||
produceMigrations = { ctx -> listOf(SharedPreferencesMigration(ctx, "settings_foss")) }
|
||||
)
|
||||
|
||||
private val dataStore: DataStore<Preferences> = context.dataStore
|
||||
|
||||
val upgrade = dataStore.createValue<FossUpgrade?>(
|
||||
key = "foss.upgrade",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package eu.darken.capod.common.upgrade.core
|
||||
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import eu.darken.capod.common.datastore.valueBlocking
|
||||
|
||||
@Singleton
|
||||
class UpgradeControlFoss @Inject constructor(
|
||||
private val fossCache: FossCache,
|
||||
) : UpgradeRepo {
|
||||
|
||||
override val upgradeInfo: Flow<UpgradeRepo.Info> = fossCache.upgrade.flow.map { data ->
|
||||
if (data == null) {
|
||||
Info()
|
||||
} else {
|
||||
Info(
|
||||
isPro = true,
|
||||
upgradedAt = data.upgradedAt,
|
||||
upgradeReason = data.reason
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun upgrade(reason: FossUpgrade.Reason) {
|
||||
fossCache.upgrade.valueBlocking = FossUpgrade(
|
||||
upgradedAt = Instant.now(),
|
||||
reason = reason
|
||||
)
|
||||
}
|
||||
|
||||
data class Info(
|
||||
override val isPro: Boolean = false,
|
||||
override val upgradedAt: Instant? = null,
|
||||
val upgradeReason: FossUpgrade.Reason? = null,
|
||||
override val error: Throwable? = null,
|
||||
) : UpgradeRepo.Info {
|
||||
override val type: UpgradeRepo.Type = UpgradeRepo.Type.FOSS
|
||||
}
|
||||
|
||||
override fun getSponsorUrl(): String = "https://github.com/sponsors/d4rken"
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package eu.darken.capod.common.upgrade.core
|
||||
|
||||
import eu.darken.capod.common.upgrade.UpgradeDiagnostics
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* FOSS has no store entitlement to reconcile: the upgrade state is a local sponsor record, already
|
||||
* covered by the existing header fields. Nothing to add.
|
||||
*/
|
||||
@Singleton
|
||||
class UpgradeDiagnosticsFoss @Inject constructor() : UpgradeDiagnostics {
|
||||
|
||||
override suspend fun debugInfo(): String? = null
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package eu.darken.capod.common.upgrade.core
|
||||
|
||||
import eu.darken.capod.common.WebpageTool
|
||||
import eu.darken.capod.common.coroutine.AppScope
|
||||
import eu.darken.capod.common.debug.logging.Logging.Priority.WARN
|
||||
import eu.darken.capod.common.debug.logging.asLog
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.flow.setupCommonEventHandlers
|
||||
import eu.darken.capod.common.upgrade.UpgradeRepo
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class UpgradeRepoFoss @Inject constructor(
|
||||
@AppScope private val appScope: CoroutineScope,
|
||||
private val fossCache: FossCache,
|
||||
private val webpageTool: WebpageTool,
|
||||
) : UpgradeRepo {
|
||||
|
||||
override val storeSite: String = STORE_SITE
|
||||
override val upgradeSite: String = UPGRADE_SITE
|
||||
override val betaSite: String = BETA_SITE
|
||||
|
||||
private val refreshTrigger = MutableStateFlow(UUID.randomUUID())
|
||||
|
||||
// Written only from the sharing coroutine (single collector) — no synchronization needed.
|
||||
// Recorded INSIDE the flatMapLatest block, upstream of its channel buffer: a downstream onEach
|
||||
// can still be waiting on a buffered emission when the inner flow throws, and the catch below
|
||||
// would then read a stale (null) value and revoke an entitlement we already saw.
|
||||
private var lastKnownInfo: Info? = null
|
||||
|
||||
override val upgradeInfo: Flow<UpgradeRepo.Info> = refreshTrigger
|
||||
.flatMapLatest {
|
||||
fossCache.upgrade.flow
|
||||
.map { data ->
|
||||
if (data == null) {
|
||||
Info()
|
||||
} else {
|
||||
Info(
|
||||
isPro = true,
|
||||
upgradedAt = data.upgradedAt,
|
||||
upgradeReason = data.reason,
|
||||
)
|
||||
}
|
||||
}
|
||||
// Same coroutine as the throw below, so the ordering is guaranteed. Only
|
||||
// successfully mapped elements pass here — catch emissions go straight downstream
|
||||
// and never record themselves as a last known state.
|
||||
.onEach { lastKnownInfo = it }
|
||||
.catch { e ->
|
||||
// A SharedFlow cannot fail: without this, a thrown cache read dies inside
|
||||
// shareIn's sharing coroutine and every collector hangs forever (VM state stuck
|
||||
// on Loading, checkSponsorReturn suspended mid-unlock). The catch sits INSIDE
|
||||
// flatMapLatest so the error completes only this inner subscription — refresh()
|
||||
// resubscribes the cache and recovery stays possible. Last-known preservation:
|
||||
// a late read failure must not revoke an entitlement we already saw; the error
|
||||
// rides on the previous Info instead. Contrast: gplay keeps a retryWhen loop
|
||||
// because billing re-settles in-place — the FOSS read is a local one-shot, and
|
||||
// refresh-driven resubscription IS the retry.
|
||||
if (e is CancellationException) throw e
|
||||
log(TAG, WARN) { "upgradeInfo read failed: ${e.asLog()}" }
|
||||
emit((lastKnownInfo ?: Info()).copy(error = e))
|
||||
}
|
||||
}
|
||||
.setupCommonEventHandlers(TAG) { "upgradeInfo" }
|
||||
.shareIn(appScope, SharingStarted.WhileSubscribed(3000L, 0L), replay = 1)
|
||||
|
||||
// Synchronous so the caller learns whether the page actually opened: the FOSS unlock heuristic
|
||||
// only arms on a successful launch, and a fire-and-forget coroutine can't report that back.
|
||||
fun openGithubSponsorsPage(): Boolean {
|
||||
log(TAG) { "openGithubSponsorsPage()" }
|
||||
return webpageTool.open(upgradeSite)
|
||||
}
|
||||
|
||||
// Writes capod's RETAINED persistence schema: existing supporter records are serialized with
|
||||
// `reason` (foss.upgrade.reason.*). Adopting canonical's `upgradeType` schema would decode
|
||||
// every stored record as null and strip those supporters' entitlement.
|
||||
/**
|
||||
* Create-only-if-absent inside the store transaction: an existing record (and its upgradedAt —
|
||||
* the user-visible "supporter since" date) is never replaced. The VM-level isPro guard alone is
|
||||
* not race-free: it reads a shareIn replay that can be stale. Note the kept record is still
|
||||
* re-encoded through the current schema — decoded fields are preserved exactly.
|
||||
*
|
||||
* Caveat from [FossCache]'s `onErrorFallbackToDefault = true`: a stored record that fails to
|
||||
* decode reads as null and therefore counts as ABSENT to this transaction, i.e. it gets
|
||||
* replaced. That matches the pre-existing read behaviour — such a record already presents the
|
||||
* user as free — and re-creating it on the next successful sponsor visit is the recovery path.
|
||||
* Decode failures therefore fall back to absent by design (the flag), so the error path around
|
||||
* [upgradeInfo] covers IO/corruption throws, not schema mismatches.
|
||||
*
|
||||
* @return true if a new record was created, false if an existing record was kept.
|
||||
*/
|
||||
internal suspend fun persistUpgrade(): Boolean {
|
||||
log(TAG) { "persistUpgrade()" }
|
||||
val updated = fossCache.upgrade.update { existing ->
|
||||
existing ?: FossUpgrade(
|
||||
upgradedAt = Instant.now(),
|
||||
reason = FossUpgrade.Reason.DONATED,
|
||||
)
|
||||
}
|
||||
// A returned transaction proves the store is readable again: revive a possibly error-stuck
|
||||
// inner flow so the record propagates to collectors still holding the error replay.
|
||||
refresh()
|
||||
return if (updated.old == null) {
|
||||
true
|
||||
} else {
|
||||
log(TAG, WARN) {
|
||||
"persistUpgrade(): Record already exists (upgradedAt=${updated.old.upgradedAt}), keeping it"
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun refresh() {
|
||||
log(TAG) { "refresh()" }
|
||||
refreshTrigger.value = UUID.randomUUID()
|
||||
}
|
||||
|
||||
data class Info(
|
||||
override val isPro: Boolean = false,
|
||||
override val upgradedAt: Instant? = null,
|
||||
val upgradeReason: FossUpgrade.Reason? = null,
|
||||
override val error: Throwable? = null,
|
||||
) : UpgradeRepo.Info {
|
||||
override val type: UpgradeRepo.Type = UpgradeRepo.Type.FOSS
|
||||
|
||||
// The FOSS entitlement is a local cache read — authoritative from the first emission,
|
||||
// there is no billing handshake to wait out.
|
||||
override val isSettled: Boolean = true
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val STORE_SITE = "https://github.com/d4rken-org/capod/releases"
|
||||
private const val UPGRADE_SITE = "https://github.com/sponsors/d4rken"
|
||||
private const val BETA_SITE = "https://github.com/d4rken-org/capod/releases"
|
||||
private val TAG = logTag("Upgrade", "Foss", "Repo")
|
||||
}
|
||||
}
|
||||
@@ -1,326 +0,0 @@
|
||||
package eu.darken.capod.common.upgrade.ui
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.twotone.AutoAwesome
|
||||
import androidx.compose.material.icons.twotone.Favorite
|
||||
import androidx.compose.material.icons.twotone.Info
|
||||
import androidx.compose.material.icons.twotone.Verified
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.compose.Preview2
|
||||
import eu.darken.capod.common.compose.PreviewWrapper
|
||||
import eu.darken.capod.common.error.ErrorEventHandler
|
||||
import eu.darken.capod.common.navigation.NavigationEventHandler
|
||||
import eu.darken.capod.common.navigation.Nav
|
||||
import androidx.compose.ui.unit.dp
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
// Which presentation the FOSS upgrade screen shows: the classic support pitch, or one of the
|
||||
// status views behind the settings "upgrade status" entry.
|
||||
internal enum class FossUpgradeView {
|
||||
PITCH,
|
||||
STATUS_FREE,
|
||||
STATUS_UPGRADED,
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UpgradeScreenHost(
|
||||
route: Nav.Main.Upgrade = Nav.Main.Upgrade(),
|
||||
vm: UpgradeViewModel = hiltViewModel(),
|
||||
) {
|
||||
LaunchedEffect(route) { vm.bindRoute(route) }
|
||||
ErrorEventHandler(vm)
|
||||
NavigationEventHandler(vm)
|
||||
|
||||
val context = LocalContext.current
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
// Seeded from the ViewModel's handle-backed pending launch: after a process death while the
|
||||
// sponsor page was open, a blank tracker would swallow the very first return. The handle is the
|
||||
// authority on whether a return is still expected, so it reconstructs the tracker's state.
|
||||
val sponsorReturnTracker = remember(vm) {
|
||||
SponsorReturnTracker(wentToBackground = vm.hasPendingSponsorLaunch())
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
vm.snackbarEvents.collect { stringRes ->
|
||||
snackbarHostState.showSnackbar(context.getString(stringRes))
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
vm.toastEvents.collect { stringRes ->
|
||||
Toast.makeText(context, context.getString(stringRes), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
|
||||
sponsorReturnTracker.onStop()
|
||||
}
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) {
|
||||
if (sponsorReturnTracker.consumeResumeReturn()) {
|
||||
vm.checkSponsorReturn()
|
||||
}
|
||||
}
|
||||
|
||||
val state by vm.state.collectAsStateWithLifecycle()
|
||||
|
||||
UpgradeScreen(
|
||||
// Until the route binding lands (one frame): the default route keeps rendering the pitch
|
||||
// exactly as before, only the manage route waits for the status decision.
|
||||
view = state?.view ?: FossUpgradeView.PITCH.takeIf { !route.manage },
|
||||
supporterSince = state?.supporterSince,
|
||||
snackbarHostState = snackbarHostState,
|
||||
onGithubSponsors = vm::goGithubSponsors,
|
||||
onOpenSponsors = vm::openSponsors,
|
||||
onShowUpgradeOptions = vm::onShowUpgradeOptions,
|
||||
onNavigateUp = vm::navUp,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun UpgradeScreen(
|
||||
view: FossUpgradeView? = FossUpgradeView.PITCH,
|
||||
supporterSince: Instant? = null,
|
||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||
onGithubSponsors: () -> Unit = {},
|
||||
onOpenSponsors: () -> Unit = {},
|
||||
onShowUpgradeOptions: () -> Unit = {},
|
||||
onNavigateUp: () -> Unit = {},
|
||||
) {
|
||||
UpgradeScreenScaffold(
|
||||
// Status views describe the existing install, not a support ask — they get the composed
|
||||
// flavor title, with the postfix highlighted for supporters like the dashboard does it.
|
||||
title = if (view == FossUpgradeView.PITCH) {
|
||||
AnnotatedString(stringResource(R.string.settings_upgrade_status_label))
|
||||
} else {
|
||||
// "CAPod FOSS", not "CAPod Pro": the FOSS flavor's own qualifier resource supplies the
|
||||
// tier word, so the title names this build. The upgraded gate keeps the highlight for
|
||||
// supporters only.
|
||||
upgradeScreenTitle(upgraded = view == FossUpgradeView.STATUS_UPGRADED)
|
||||
},
|
||||
onNavigateUp = onNavigateUp,
|
||||
snackbarHostState = snackbarHostState,
|
||||
) { paddingValues ->
|
||||
when (view) {
|
||||
null -> Unit // Route not bound yet (single frame); content lands with the next state.
|
||||
FossUpgradeView.PITCH -> UpgradePitchContent(
|
||||
paddingValues = paddingValues,
|
||||
onGithubSponsors = onGithubSponsors,
|
||||
)
|
||||
|
||||
FossUpgradeView.STATUS_FREE -> UpgradeStatusFreeContent(
|
||||
paddingValues = paddingValues,
|
||||
onShowUpgradeOptions = onShowUpgradeOptions,
|
||||
)
|
||||
|
||||
FossUpgradeView.STATUS_UPGRADED -> UpgradeStatusUpgradedContent(
|
||||
paddingValues = paddingValues,
|
||||
supporterSince = supporterSince,
|
||||
onOpenSponsors = onOpenSponsors,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpgradePitchContent(
|
||||
paddingValues: PaddingValues,
|
||||
onGithubSponsors: () -> Unit,
|
||||
) {
|
||||
UpgradeScreenContent(
|
||||
paddingValues = paddingValues,
|
||||
) {
|
||||
UpgradeHeroCard(
|
||||
text = stringResource(R.string.upgrade_foss_preamble),
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
),
|
||||
)
|
||||
|
||||
UpgradeSectionCard(
|
||||
title = stringResource(R.string.upgrade_screen_why_title),
|
||||
icon = Icons.TwoTone.AutoAwesome,
|
||||
) {
|
||||
UpgradeFeatureList(text = upgradeBenefitsText())
|
||||
}
|
||||
|
||||
UpgradeSectionCard(
|
||||
title = stringResource(R.string.upgrade_screen_how_title),
|
||||
icon = Icons.TwoTone.Favorite,
|
||||
) {
|
||||
UpgradeSectionBody(text = stringResource(R.string.upgrade_screen_how_body))
|
||||
}
|
||||
|
||||
UpgradeActionCard(
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
),
|
||||
) {
|
||||
Button(
|
||||
onClick = onGithubSponsors,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(UpgradeScreenTags.FOSS_SPONSOR),
|
||||
) {
|
||||
Text(stringResource(R.string.upgrade_foss_sponsor_action))
|
||||
}
|
||||
|
||||
UpgradeHintText(text = stringResource(R.string.upgrade_foss_sponsor_subtitle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpgradeStatusFreeContent(
|
||||
paddingValues: PaddingValues,
|
||||
onShowUpgradeOptions: () -> Unit,
|
||||
) {
|
||||
UpgradeScreenContent(
|
||||
paddingValues = paddingValues,
|
||||
) {
|
||||
UpgradeHeader(
|
||||
mascotSize = 104.dp,
|
||||
)
|
||||
|
||||
UpgradeSectionCard(
|
||||
title = stringResource(R.string.upgrade_screen_status_free_title),
|
||||
icon = Icons.TwoTone.Info,
|
||||
modifier = Modifier.testTag(UpgradeScreenTags.FOSS_STATUS_FREE),
|
||||
) {
|
||||
UpgradeSectionBody(text = stringResource(R.string.upgrade_screen_status_free_body))
|
||||
Button(
|
||||
onClick = onShowUpgradeOptions,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(UpgradeScreenTags.FOSS_SHOW_OPTIONS),
|
||||
) {
|
||||
Text(stringResource(R.string.upgrade_screen_status_free_action))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpgradeStatusUpgradedContent(
|
||||
paddingValues: PaddingValues,
|
||||
supporterSince: Instant? = null,
|
||||
onOpenSponsors: () -> Unit,
|
||||
) {
|
||||
UpgradeScreenContent(
|
||||
paddingValues = paddingValues,
|
||||
) {
|
||||
UpgradeHeader(
|
||||
mascotSize = 104.dp,
|
||||
)
|
||||
|
||||
UpgradeSectionCard(
|
||||
title = stringResource(R.string.upgrade_screen_status_upgraded_title),
|
||||
icon = Icons.TwoTone.Verified,
|
||||
modifier = Modifier.testTag(UpgradeScreenTags.FOSS_STATUS_UPGRADED),
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_foss_supporter_thanks),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
supporterSince?.let { since ->
|
||||
val formatter = remember {
|
||||
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withZone(ZoneId.systemDefault())
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_foss_supporter_since, formatter.format(since)),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeSectionCard(
|
||||
title = stringResource(R.string.upgrade_screen_recurring_title),
|
||||
icon = Icons.TwoTone.Favorite,
|
||||
) {
|
||||
UpgradeSectionBody(text = stringResource(R.string.upgrade_screen_recurring_body))
|
||||
OutlinedButton(
|
||||
onClick = onOpenSponsors,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.testTag(UpgradeScreenTags.FOSS_DONATE),
|
||||
) {
|
||||
Text(stringResource(R.string.upgrade_foss_sponsor_again_action))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SponsorReturnTracker(
|
||||
private var wentToBackground: Boolean = false,
|
||||
) {
|
||||
|
||||
fun onStop() {
|
||||
wentToBackground = true
|
||||
}
|
||||
|
||||
fun consumeResumeReturn(): Boolean {
|
||||
return if (wentToBackground) {
|
||||
wentToBackground = false
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun UpgradeScreenPreview() {
|
||||
PreviewWrapper {
|
||||
UpgradeScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun UpgradeScreenStatusFreePreview() {
|
||||
PreviewWrapper {
|
||||
UpgradeScreen(view = FossUpgradeView.STATUS_FREE)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun UpgradeScreenStatusUpgradedPreview() {
|
||||
PreviewWrapper {
|
||||
UpgradeScreen(
|
||||
view = FossUpgradeView.STATUS_UPGRADED,
|
||||
supporterSince = Instant.ofEpochMilli(1_700_000_000_000L),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
package eu.darken.capod.common.upgrade.ui
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.debug.logging.log
|
||||
import eu.darken.capod.common.debug.logging.logTag
|
||||
import eu.darken.capod.common.flow.SingleEventFlow
|
||||
import eu.darken.capod.common.navigation.Nav
|
||||
import eu.darken.capod.common.uix.ViewModel4
|
||||
import eu.darken.capod.common.upgrade.core.UpgradeRepoFoss
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.take
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class UpgradeViewModel @Inject constructor(
|
||||
private val handle: SavedStateHandle,
|
||||
dispatcherProvider: DispatcherProvider,
|
||||
private val upgradeRepo: UpgradeRepoFoss,
|
||||
) : ViewModel4(dispatcherProvider = dispatcherProvider) {
|
||||
|
||||
// Route is bound from the Host via bindRoute(); SavedStateHandle.toRoute<>() crashes under Nav3.
|
||||
private val routeFlow = MutableStateFlow<Nav.Main.Upgrade?>(null)
|
||||
|
||||
fun bindRoute(route: Nav.Main.Upgrade) {
|
||||
if (routeFlow.value != null) return
|
||||
routeFlow.value = route
|
||||
}
|
||||
|
||||
val snackbarEvents = SingleEventFlow<Int>()
|
||||
val toastEvents = SingleEventFlow<Int>()
|
||||
|
||||
// Which presentation the screen shows. The manage route (settings "upgrade status" entry)
|
||||
// gets a status view first; the pitch only appears once a free user asks for the upgrade
|
||||
// options. Upgrading wins over that choice — completing the sponsor flow from the pitch must
|
||||
// land on the upgraded status, not back on the ask. null until the route is bound.
|
||||
internal val state: StateFlow<State?> = combine(
|
||||
routeFlow,
|
||||
upgradeRepo.upgradeInfo,
|
||||
handle.getStateFlow(KEY_SHOW_UPGRADE_OPTIONS, false),
|
||||
) { route, info, showOptions ->
|
||||
val view = when {
|
||||
route == null -> null
|
||||
route.manage && info.isPro -> FossUpgradeView.STATUS_UPGRADED
|
||||
route.manage && !showOptions -> FossUpgradeView.STATUS_FREE
|
||||
else -> FossUpgradeView.PITCH
|
||||
}
|
||||
// Derived in the same emission as the view on purpose: a sibling flow would let the
|
||||
// upgraded status render for a frame without the date it is supposed to carry.
|
||||
view?.let {
|
||||
State(
|
||||
view = it,
|
||||
supporterSince = info.upgradedAt.takeIf { _ -> it == FossUpgradeView.STATUS_UPGRADED },
|
||||
)
|
||||
}
|
||||
}.safeStateIn(
|
||||
initialValue = null,
|
||||
onError = { State(view = FossUpgradeView.PITCH) },
|
||||
)
|
||||
|
||||
// internal like FossUpgradeView: the view enum is a screen-local presentation detail.
|
||||
internal data class State(
|
||||
val view: FossUpgradeView,
|
||||
val supporterSince: Instant? = null,
|
||||
)
|
||||
|
||||
init {
|
||||
routeFlow
|
||||
.filterNotNull()
|
||||
.take(1)
|
||||
.onEach { route ->
|
||||
// The manage route is the settings "upgrade status" entry — upgraded users must
|
||||
// not be bounced out. Forced routes keep their existing don't-auto-close semantics.
|
||||
if (!route.forced && !route.manage) {
|
||||
upgradeRepo.upgradeInfo
|
||||
.filter { it.isPro }
|
||||
.take(1)
|
||||
.onEach { navUp() }
|
||||
.launchInViewModel()
|
||||
}
|
||||
}
|
||||
.launchInViewModel()
|
||||
|
||||
upgradeRepo.upgradeInfo
|
||||
.filter { !it.isPro && it.error != null }
|
||||
.onEach { current ->
|
||||
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
errorEvents.tryEmit(current.error!!)
|
||||
}
|
||||
.launchInViewModel()
|
||||
}
|
||||
|
||||
fun onShowUpgradeOptions() {
|
||||
log(TAG) { "onShowUpgradeOptions()" }
|
||||
// Handle-backed: surviving process recreation keeps the user on the pitch they asked for.
|
||||
handle[KEY_SHOW_UPGRADE_OPTIONS] = true
|
||||
}
|
||||
|
||||
/** Armed variant: the pitch's sponsor button, which starts the return-after-5s unlock heuristic. */
|
||||
fun goGithubSponsors() {
|
||||
log(TAG) { "goGithubSponsors()" }
|
||||
if (hasPendingSponsorLaunch()) {
|
||||
log(TAG) { "A sponsor launch is already awaiting its return" }
|
||||
return
|
||||
}
|
||||
// Only arm the heuristic if the page actually opened; otherwise an unrelated later
|
||||
// background/foreground round-trip would grant supporter status with no page ever shown.
|
||||
if (!upgradeRepo.openGithubSponsorsPage()) {
|
||||
log(TAG) { "Sponsor page didn't open; not arming the unlock heuristic" }
|
||||
return
|
||||
}
|
||||
handle[KEY_SPONSOR_PRESSED_AT] = SystemClock.elapsedRealtime()
|
||||
}
|
||||
|
||||
/**
|
||||
* Unarmed variant: the status view's donate button. An existing supporter re-visiting the page
|
||||
* must not re-arm the unlock heuristic — there is nothing left to unlock.
|
||||
*/
|
||||
fun openSponsors() {
|
||||
log(TAG) { "openSponsors()" }
|
||||
upgradeRepo.openGithubSponsorsPage()
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a sponsor-page launch is still awaiting its return.
|
||||
*
|
||||
* Handle-backed, so it survives process recreation while the browser is in front — the screen's
|
||||
* in-memory return tracker does not, and gating on that alone drops the first return after a
|
||||
* recreation.
|
||||
*/
|
||||
fun hasPendingSponsorLaunch(): Boolean = handle.contains(KEY_SPONSOR_PRESSED_AT)
|
||||
|
||||
fun checkSponsorReturn() = launch {
|
||||
val pressedAt = handle.remove<Long>(KEY_SPONSOR_PRESSED_AT) ?: return@launch
|
||||
|
||||
try {
|
||||
// Evaluated before the duration: an already upgraded supporter (recurring donation
|
||||
// button) has nothing left to unlock, so this fast path exists for the UX — return
|
||||
// quietly, no redundant write attempt and no thanks toast for an unlock that already
|
||||
// happened. Data integrity is not this guard's job: the repo's create-only transaction
|
||||
// owns that.
|
||||
if (upgradeRepo.upgradeInfo.first().isPro) {
|
||||
log(TAG) { "checkSponsorReturn(): Already upgraded, staying quiet" }
|
||||
return@launch
|
||||
}
|
||||
|
||||
val elapsed = SystemClock.elapsedRealtime() - pressedAt
|
||||
log(TAG) { "checkSponsorReturn(): elapsed=${elapsed}ms" }
|
||||
|
||||
if (elapsed < SPONSOR_DELAY_MS) {
|
||||
log(TAG) { "checkSponsorReturn(): Too quick, showing snackbar" }
|
||||
snackbarEvents.tryEmit(R.string.upgrade_foss_sponsor_returned_early)
|
||||
} else {
|
||||
log(TAG) { "checkSponsorReturn(): Delay passed, persisting upgrade" }
|
||||
val created = upgradeRepo.persistUpgrade()
|
||||
if (created) {
|
||||
toastEvents.tryEmit(R.string.upgrade_foss_supporter_thanks)
|
||||
} else {
|
||||
// The isPro fast-path read a stale emission; the transaction kept the existing record.
|
||||
log(TAG) { "checkSponsorReturn(): Record already existed, staying quiet" }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// The marker was consumed above; neither a failed entitlement read nor a failed write may
|
||||
// eat the user's valid sponsor visit — restore it so the next return/resume can retry the
|
||||
// unlock. Conditional: the user may have armed a NEWER launch while this attempt was
|
||||
// suspended, and that one must survive. The contains-check has a small check-then-act
|
||||
// window against a concurrent new arm; accepted — the create-only transaction owns data
|
||||
// integrity, a wrong winner only changes which REAL visit's timestamp gates the unlock.
|
||||
// Rethrow unconditionally: cancellation is not swallowed, other errors surface via the
|
||||
// normal error path. A restored marker after a successful persist is harmless — the next
|
||||
// evaluation hits the quiet isPro path.
|
||||
if (!handle.contains(KEY_SPONSOR_PRESSED_AT)) {
|
||||
handle[KEY_SPONSOR_PRESSED_AT] = pressedAt
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_SPONSOR_PRESSED_AT = "sponsor_pressed_at"
|
||||
private const val KEY_SHOW_UPGRADE_OPTIONS = "show_upgrade_options"
|
||||
private const val SPONSOR_DELAY_MS = 5_000L
|
||||
private val TAG = logTag("Upgrade", "ViewModel")
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package eu.darken.capod.common.upgrade.ui
|
||||
package eu.darken.capod.upgrade.ui
|
||||
|
||||
import androidx.navigation3.runtime.EntryProviderScope
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
@@ -13,7 +13,7 @@ import javax.inject.Inject
|
||||
|
||||
class UpgradeNavigation @Inject constructor() : NavigationEntry {
|
||||
override fun EntryProviderScope<NavKey>.setup() {
|
||||
entry<Nav.Main.Upgrade> { key -> UpgradeScreenHost(route = key) }
|
||||
entry<Nav.Main.Upgrade> { UpgradeScreenHost() }
|
||||
}
|
||||
|
||||
@Module
|
||||
@@ -0,0 +1,271 @@
|
||||
package eu.darken.capod.upgrade.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.twotone.Message
|
||||
import androidx.compose.material.icons.twotone.BluetoothConnected
|
||||
import androidx.compose.material.icons.twotone.Favorite
|
||||
import androidx.compose.material.icons.twotone.Palette
|
||||
import androidx.compose.material.icons.twotone.PlayCircle
|
||||
import androidx.compose.material.icons.twotone.Headphones
|
||||
import androidx.compose.material.icons.twotone.Tune
|
||||
import androidx.compose.material.icons.twotone.Widgets
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import eu.darken.capod.R
|
||||
import eu.darken.capod.common.compose.Preview2
|
||||
import eu.darken.capod.common.compose.PreviewWrapper
|
||||
import eu.darken.capod.common.error.ErrorEventHandler
|
||||
import eu.darken.capod.common.navigation.NavigationEventHandler
|
||||
|
||||
@Composable
|
||||
fun UpgradeScreenHost(vm: UpgradeViewModel = hiltViewModel()) {
|
||||
ErrorEventHandler(vm)
|
||||
NavigationEventHandler(vm)
|
||||
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val returnedEarlyMessage = stringResource(R.string.upgrade_foss_sponsor_returned_early)
|
||||
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
vm.onResume()
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
vm.sponsorEvents.collect { event ->
|
||||
when (event) {
|
||||
UpgradeViewModel.SponsorEvent.ReturnedTooEarly -> {
|
||||
snackbarHostState.showSnackbar(returnedEarlyMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpgradeScreen(
|
||||
snackbarHostState = snackbarHostState,
|
||||
onNavigateUp = { vm.navUp() },
|
||||
onSponsor = { vm.sponsor() },
|
||||
)
|
||||
}
|
||||
|
||||
private data class Benefit(val icon: ImageVector, val textRes: Int)
|
||||
|
||||
@Composable
|
||||
fun UpgradeScreen(
|
||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||
onNavigateUp: () -> Unit,
|
||||
onSponsor: () -> Unit,
|
||||
) {
|
||||
val benefits = listOf(
|
||||
Benefit(Icons.TwoTone.Palette, R.string.upgrade_benefit_themes),
|
||||
Benefit(Icons.TwoTone.PlayCircle, R.string.upgrade_benefit_autoplay),
|
||||
|
||||
Benefit(Icons.AutoMirrored.TwoTone.Message, R.string.upgrade_benefit_popups),
|
||||
Benefit(Icons.TwoTone.Widgets, R.string.upgrade_benefit_widgets),
|
||||
Benefit(Icons.TwoTone.Tune, R.string.upgrade_benefit_device_settings),
|
||||
Benefit(Icons.TwoTone.Headphones, R.string.upgrade_benefit_device_controls),
|
||||
Benefit(Icons.TwoTone.Favorite, R.string.upgrade_benefit_support),
|
||||
)
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
) { paddingValues ->
|
||||
Box(modifier = Modifier.padding(paddingValues)) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 24.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(48.dp))
|
||||
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Surface(
|
||||
modifier = Modifier.size(120.dp),
|
||||
shape = CircleShape,
|
||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.5f),
|
||||
) {}
|
||||
Image(
|
||||
painter = painterResource(R.drawable.splash_graphic2),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(80.dp),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
append("CAPod ")
|
||||
withStyle(SpanStyle(color = colorResource(R.color.brand_secondary), fontWeight = FontWeight.Bold)) {
|
||||
append("FOSS")
|
||||
}
|
||||
},
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Card(
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_foss_preamble),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(vertical = 4.dp)) {
|
||||
benefits.forEach { benefit ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
modifier = Modifier.size(28.dp),
|
||||
) {
|
||||
Box(contentAlignment = Alignment.Center) {
|
||||
Icon(
|
||||
imageVector = benefit.icon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Text(
|
||||
text = stringResource(benefit.textRes),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_benefit_disclaimer),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Button(
|
||||
onClick = onSponsor,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(52.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.TwoTone.Favorite,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_foss_sponsor_action),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.upgrade_foss_sponsor_subtitle),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = onNavigateUp,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.padding(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.TwoTone.ArrowBack,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview2
|
||||
@Composable
|
||||
private fun UpgradeScreenPreview() = PreviewWrapper {
|
||||
UpgradeScreen(
|
||||
onNavigateUp = {},
|
||||
onSponsor = {},
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package eu.darken.capod.upgrade.ui
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import eu.darken.capod.common.WebpageTool
|
||||
import eu.darken.capod.common.coroutine.DispatcherProvider
|
||||
import eu.darken.capod.common.flow.SingleEventFlow
|
||||
import eu.darken.capod.common.uix.ViewModel4
|
||||
import eu.darken.capod.common.upgrade.core.FossUpgrade
|
||||
import eu.darken.capod.common.upgrade.core.UpgradeControlFoss
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class UpgradeViewModel @Inject constructor(
|
||||
private val savedStateHandle: SavedStateHandle,
|
||||
dispatcherProvider: DispatcherProvider,
|
||||
private val upgradeControlFoss: UpgradeControlFoss,
|
||||
private val webpageTool: WebpageTool,
|
||||
) : ViewModel4(dispatcherProvider) {
|
||||
|
||||
sealed interface SponsorEvent {
|
||||
data object ReturnedTooEarly : SponsorEvent
|
||||
}
|
||||
|
||||
val sponsorEvents = SingleEventFlow<SponsorEvent>()
|
||||
|
||||
fun sponsor() {
|
||||
savedStateHandle[KEY_SPONSOR_OPENED_AT] = SystemClock.elapsedRealtime()
|
||||
webpageTool.open("https://github.com/sponsors/d4rken")
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
val openedAt = savedStateHandle.get<Long>(KEY_SPONSOR_OPENED_AT) ?: return
|
||||
savedStateHandle.remove<Long>(KEY_SPONSOR_OPENED_AT)
|
||||
|
||||
if (SystemClock.elapsedRealtime() - openedAt >= 5_000L) {
|
||||
upgradeControlFoss.upgrade(FossUpgrade.Reason.DONATED)
|
||||
navUp()
|
||||
} else {
|
||||
sponsorEvents.tryEmit(SponsorEvent.ReturnedTooEarly)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_SPONSOR_OPENED_AT = "sponsor_opened_at"
|
||||
}
|
||||
}
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Borg ontwikkeling</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Geen advertensies. Geen opsporing. Geen Google Play-binding.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Alreeds terug? U ondersteuning hou CAPod aan die lewe.</string>
|
||||
<string name="upgrade_foss_supporter_since">Ondersteuner sedert %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Dankie dat jy CAPod se ontwikkeling ondersteun!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Maak borgblad oop</string>
|
||||
<string name="settings_upgrade_status_label">Ondersteun CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Jou ondersteunersstatus.</string>
|
||||
<string name="upgrade_screen_why_title">Opgraderingsvoordele</string>
|
||||
<string name="upgrade_screen_how_title">Hoe om te help</string>
|
||||
<string name="upgrade_screen_how_body">Word \'n beskermheer en borg ontwikkeling! Tik die knoppie hieronder om alle ekstra funksies te aktiveer en my GitHub Sponsors profiel oop te maak.</string>
|
||||
<string name="upgrade_screen_status_free_title">Gratis weergawe</string>
|
||||
<string name="upgrade_screen_status_free_body">Jy gebruik die gratis weergawe van CAPod. Ekstra funksies kan ontsluit word deur die ontwikkeling te ondersteun.</string>
|
||||
<string name="upgrade_screen_status_free_action">Sien opgraderingsopsies</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Opgradering aktief</string>
|
||||
<string name="upgrade_screen_recurring_title">Hou dit voort</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod bly verbeter deur opdaterings en regstellings. As jy dit wil volhou, oorweeg \'n herhalende skenking via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ልማትን ይደግፉ</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ምንም ማስታወቂያ የሉም። ምንም ክትትል የሉም። ምንም Google Play ቆለፋ የሉም።</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ቀድሞ ተመለሱ፡ ድጋፏዎ CAPodን ህያው ያቆይላል።</string>
|
||||
<string name="upgrade_foss_supporter_since">ደጋፊ ከ%s ጀምሮ</string>
|
||||
<string name="upgrade_foss_supporter_thanks">የCAPod ልማትን ስለደገፉ እናመሰግናለን!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">የስፖንሰር ገጽን ክፈት</string>
|
||||
<string name="settings_upgrade_status_label">CAPod ን ደግፍ</string>
|
||||
<string name="settings_upgrade_status_description">የእርስዎ ደጋፊ ሁኔታ።</string>
|
||||
<string name="upgrade_screen_why_title">የማሻሻል ጥቅማጥቅሞች</string>
|
||||
<string name="upgrade_screen_how_title">እንዴት መርዳት እንደሚችሉ</string>
|
||||
<string name="upgrade_screen_how_body">ደጋፊ ይሁኑ እና ልማትን ይደግፉ! ሁሉንም ተጨማሪ ባህሪያት ለማንቃት እና የእኔን GitHub Sponsors መገለጫ ለመክፈት ከታች ያለውን ቁልፍ ይንኩ።</string>
|
||||
<string name="upgrade_screen_status_free_title">ነጻ ስሪት</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod ነጻ ስሪት ይጠቀማሉ። ተጨማሪ ባህሪዎች በልማት ድጋፍ ሊከፈቱ ይችላሉ።</string>
|
||||
<string name="upgrade_screen_status_free_action">የማሻሻል አማራጮችን ይመልከቱ</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">ማሻሻል ንቁ ነው</string>
|
||||
<string name="upgrade_screen_recurring_title">ይህን ይቀጥሉ</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod በዝመናዎች እና ማስተካከያዎች ሁሉ ጊዜ ይሻሻላል። ይህንን ለማቆየት ከወደዱ፣ በGitHub Sponsors ደግሞ ምስዋትን ያስቡ።</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="foss_upgrade_donate_label">تبرع</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">لقد تبرعت بالفعل</string>
|
||||
<string name="foss_upgrade_no_money_label">أنفق كل أموالي على سماعات أيربودز</string>
|
||||
<string name="upgrade_foss_preamble">برنامج كابود FOSS مجاني ومفتوح المصدر. إذا وجدته مفيدًا، ففكر في دعم تطويره للمساعدة في استمرار المشروع.</string>
|
||||
<string name="foss_upgrade_donate_label">تبرُّع</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">لقد تبرّعتُ بالفعل</string>
|
||||
<string name="foss_upgrade_no_money_label">أنفق كل أموالي على سمّاعات AirPods</string>
|
||||
<string name="upgrade_foss_preamble">برنامج CAPod FOSS مجاني ومفتوح المصدر. إذا وجدتهُ مفيدًا، ففكّر في دعم تطويره للمساعدة في استمرار المشروع.</string>
|
||||
<string name="upgrade_foss_sponsor_action">دعم التطوير</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبع. لا قيود من جوجل بلاي.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">هل عدت بالفعل؟ دعمك يبقي كابود حيًّا.</string>
|
||||
<string name="upgrade_foss_supporter_since">داعم منذ %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">شكرًا لدعمك تطوير CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">فتح صفحة الرعاية</string>
|
||||
<string name="settings_upgrade_status_label">دعم كابود</string>
|
||||
<string name="settings_upgrade_status_description">حالة دعمك.</string>
|
||||
<string name="upgrade_screen_why_title">مزايا الترقية</string>
|
||||
<string name="upgrade_screen_how_title">كيفية المساعدة</string>
|
||||
<string name="upgrade_screen_how_body">كُن راعيًا وساهم في تطوير المشروع! اضغط على الزرّ أدناه لتفعيل جميع الميزات الإضافية وفتح ملفّي الشخصي على GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">النسخة المجّانية</string>
|
||||
<string name="upgrade_screen_status_free_body">أنت تستخدم النسخة المجّانية من كابود. يمكنك فتح ميزات إضافية من خلال دعم التطوير.</string>
|
||||
<string name="upgrade_screen_status_free_action">الاطّلاع على خيارات الترقية</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">الترقية نشطة</string>
|
||||
<string name="upgrade_screen_recurring_title">أبقِ التطبيق مستمرًّا</string>
|
||||
<string name="upgrade_screen_recurring_body">يستمرّ كابود في التطوّر من خلال التحديثات والإصلاحات. إذا كنت ترغب في دعم هذا التطوّر، ففكّر في التبرّع بشكل دوري عبر GitHub Sponsors.</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">لا إعلانات. لا تتبُّع. لا قيود من جوجل بلاي.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">هل عدت بالفعل؟ دعمك يُبقي CAPod حيًّا.</string>
|
||||
<string name="upgrade_badge_label">البرمجيات الحرة والمفتوحة المصدر</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">İnkişafı sponsor edin</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Reklam yoxdur. İzləmə yoxdur. Google Play bağlılığı yoxdur.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Artıq geri qayıtdınız? Dəstəyiniz CAPod-u yaşadır.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s tarixindən bəri dəstəkçi</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod-un inkişafını dəstəklədiyiniz üçün təşəkkürlər!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Sponsor səhifəsini aç</string>
|
||||
<string name="settings_upgrade_status_label">CAPod-u sponsorlaşdırın</string>
|
||||
<string name="settings_upgrade_status_description">Sizin tərəfdar statusu.</string>
|
||||
<string name="upgrade_screen_why_title">Yüksəltmə üstünləri</string>
|
||||
<string name="upgrade_screen_how_title">Necə kömək etmək</string>
|
||||
<string name="upgrade_screen_how_body">Himayədar olun və inkişafı sponsor edin! Bütün əlavə xüsusiyyətləri aktivləşdirmək və mənim GitHub Sponsors profilimi açmaq üçün aşağıdakı düyməni toxunun.</string>
|
||||
<string name="upgrade_screen_status_free_title">Pulsuz versiya</string>
|
||||
<string name="upgrade_screen_status_free_body">Siz CAPod-un pulsuz versiyasından istifadə edirsiniz. Əlavə xüsusiyyətlər inkişafı dəstəkləyərək açılır.</string>
|
||||
<string name="upgrade_screen_status_free_action">Yüksəltmə variantlarına baxın</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Yüksəltmə aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Davam etdirin</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod yeniləmələr və düzəltmələr vasitəsilə təkamül etməkdə davam edir. Bunu dəstəkləmək istəsəniz, GitHub Sponsors vasitəsilə təkrari donasiya nəzərdən keçirin.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Падтрымаць распрацоўку</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Ніякай рэкламы. Ніякай адсочкі. Ніякай залежнасці ад Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Ужо вяртаецеся? Ваша падтрымка трымае CAPod ў жывых.</string>
|
||||
<string name="upgrade_foss_supporter_since">Спонсар з %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Дзякуй за падтрымку развіцця CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Адкрыць старонку спонсарства</string>
|
||||
<string name="settings_upgrade_status_label">Спонсараваць CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Ваш статус прыхільніка.</string>
|
||||
<string name="upgrade_screen_why_title">Перавагі абнаўлення</string>
|
||||
<string name="upgrade_screen_how_title">Як дапамагчы</string>
|
||||
<string name="upgrade_screen_how_body">Станьце спонсарам распрацоўкі! Націсніце кнопку ніжэй, каб актывіраваць усе дадатковыя функцыі і адкрыць мой профіль на GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Бясплатная версія</string>
|
||||
<string name="upgrade_screen_status_free_body">Вы выкарыстоўваеце бясплатную версію CAPod. Дадатковыя функцыі можна разблакаваць, падтрымаўшы развіццё.</string>
|
||||
<string name="upgrade_screen_status_free_action">Прагледзець варыянты абнаўлення</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Абнаўленне актыўнае</string>
|
||||
<string name="upgrade_screen_recurring_title">Падтрымайце далей</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod пастаянна развіваецца дзякуючы абнаўленням і выпраўленням. Калі вы хочаце гэта падтрымаць, разгледзьце магчымасць рэгулярнага ахвяравання праз GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Спонсорирайте разработката</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без следене. Без заключване в Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Вече ли? Вашата подкрепа поддържа CAPod жив.</string>
|
||||
<string name="upgrade_foss_supporter_since">Поддържник от %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Благодарим ви, че подкрепяте развитието на CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Отвори страницата за спонсорство</string>
|
||||
<string name="settings_upgrade_status_label">Спонсорирайте CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Вашият статус на поддръжник.</string>
|
||||
<string name="upgrade_screen_why_title">Преимущества на надстройката</string>
|
||||
<string name="upgrade_screen_how_title">Как да помогнете</string>
|
||||
<string name="upgrade_screen_how_body">Станете покровител и спонсорирайте разработката! Докоснете бутона по-долу, за да активирате всички допълнителни функции и да отворите моя GitHub Sponsors профил.</string>
|
||||
<string name="upgrade_screen_status_free_title">Безплатна версия</string>
|
||||
<string name="upgrade_screen_status_free_body">Използвате безплатната версия на CAPod. Допълнителни функции могат да бъдат отключени чрез подкрепа на разработката.</string>
|
||||
<string name="upgrade_screen_status_free_action">Вижте опциите за надстройка</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Надстройката е активна</string>
|
||||
<string name="upgrade_screen_recurring_title">Поддържете това</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod продължава да се развива чрез актуализации и корекции. Ако искате да подкрепите това, разгледайте възможност за редовно дарение чрез GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">স্পনসর ডেভলপমেন্ট</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">কোনো বিজ্ঞাপন নেই। কোনো ট্র্যাকিং নেই। Google Play-এর সাথে বাঁধানো নেই।</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ইতোমধ্যে ফিরে গেলেন? আপনার সমর্থন CAPodকে বাঁচিয়ে রাখে।</string>
|
||||
<string name="upgrade_foss_supporter_since">%s থেকে সমর্থক</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod-এর উন্নয়নে সমর্থন করার জন্য আপনাকে ধন্যবাদ!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">স্পনসর পৃষ্ঠা খুলুন</string>
|
||||
<string name="settings_upgrade_status_label">CAPod-কে স্পন্সর করুন</string>
|
||||
<string name="settings_upgrade_status_description">আপনার সমর্থক স্থিতি।</string>
|
||||
<string name="upgrade_screen_why_title">আপগ্রেড সুবিধা</string>
|
||||
<string name="upgrade_screen_how_title">কিভাবে সাহায্য করতে পারি</string>
|
||||
<string name="upgrade_screen_how_body">একটি পৃষ্ঠপোষক এবং স্পনসর উন্নয়ন হয়ে! সমস্ত অতিরিক্ত বৈশিষ্ট্য সক্রিয় করতে নীচের বোতামটি আলতো চাপুন এবং আমার GitHub স্পনসর প্রোফাইল খুলুন।</string>
|
||||
<string name="upgrade_screen_status_free_title">বিনামূল্যে সংস্করণ</string>
|
||||
<string name="upgrade_screen_status_free_body">আপনি CAPod এর বিনামূল্যে সংস্করণ ব্যবহার করছেন। উন্নয়ন সমর্থন করে অতিরিক্ত বৈশিষ্ট্য আনলক করা যায়।</string>
|
||||
<string name="upgrade_screen_status_free_action">আপগ্রেড বিকল্পগুলি দেখুন</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">আপগ্রেড সক্রিয়</string>
|
||||
<string name="upgrade_screen_recurring_title">এটি চালু রাখুন</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod আপডেট এবং সংশোধনের মাধ্যমে ক্রমাগত উন্নত হচ্ছে। আপনি যদি তা বজায় রাখতে চান তবে GitHub Sponsors এর মাধ্যমে নিয়মিত দান বিবেচনা করুন।</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocina el desenvolupament</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sense anuncis. Sense seguiment. Sense dependència del Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Ja heu tornat? El vostre suport manté viu el CAPod.</string>
|
||||
<string name="upgrade_foss_supporter_since">Col·laborador des de %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Gràcies per donar suport al desenvolupament del CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Obre la pàgina del patrocinador</string>
|
||||
<string name="settings_upgrade_status_label">Patrocineu el CAPod</string>
|
||||
<string name="settings_upgrade_status_description">El vostre estat de col·laborador.</string>
|
||||
<string name="upgrade_screen_why_title">Beneficis de la millora</string>
|
||||
<string name="upgrade_screen_how_title">Com ajudar</string>
|
||||
<string name="upgrade_screen_how_body">Convertiu-vos en mecenes i patrocinadors del desenvolupament! Toqueu el botó següent per activar totes les funcions addicionals i obrir el meu perfil de patrocinadors del GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versió gratuïta</string>
|
||||
<string name="upgrade_screen_status_free_body">Esteu utilitzant la versió gratuïta de CAPod. Podeu desbloquejar funcions addicionals donant suport al desenvolupament.</string>
|
||||
<string name="upgrade_screen_status_free_action">Veure opcions de millora</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Millora activa</string>
|
||||
<string name="upgrade_screen_recurring_title">Manteniu-ho en marxa</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continua evolucionant a través d\'actualitzacions i correccions. Si voleu sostenir-ho, considereu una donació recurrent a través de GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponzorovat vývoj</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Žádné reklamy. Žádné sledování. Žádná závislost na Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Už jste zpět? Vaše podpora udržuje CAPod naživu.</string>
|
||||
<string name="upgrade_foss_supporter_since">Podporovatel od %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Děkujeme za podporu vývoje CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Otevřít stránku sponzora</string>
|
||||
<string name="settings_upgrade_status_label">Sponzorovat CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Váš stav podporovatele.</string>
|
||||
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
||||
<string name="upgrade_screen_how_title">Jak pomoci</string>
|
||||
<string name="upgrade_screen_how_body">Staňte se patronem a sponzorem vývoje! Klepnutím na tlačítko níže aktivujete všechny další funkce a otevřete můj profil sponzora na GitHubu.</string>
|
||||
<string name="upgrade_screen_status_free_title">Bezplatná verze</string>
|
||||
<string name="upgrade_screen_status_free_body">Používáte bezplatnou verzi CAPod. Další funkce lze odemknout podporou vývoje.</string>
|
||||
<string name="upgrade_screen_status_free_action">Zobrazit možnosti upgradu</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade je aktivní</string>
|
||||
<string name="upgrade_screen_recurring_title">Pokračuj v tom</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod se neustále vyvíjí prostřednictvím aktualizací a oprav. Pokud to chcete podporovat, zvažte pravidelný příspěvek prostřednictvím GitHub sponzorů.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsorudvikling</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Ingen annoncer. Ingen sporing. Ingen Google Play-lås.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Allerede tilbage? Din støtte holder CAPod i live.</string>
|
||||
<string name="upgrade_foss_supporter_since">Støtte siden %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Tak fordi du støtter udviklingen af CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Åbn sponsorside</string>
|
||||
<string name="settings_upgrade_status_label">Sponsor CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
||||
<string name="upgrade_screen_why_title">Opgraderingens fordele</string>
|
||||
<string name="upgrade_screen_how_title">Sådan hjælper du</string>
|
||||
<string name="upgrade_screen_how_body">Bliv patron og sponsorér udvikling! Tryk på knappen nedenfor for at aktivere alle ekstra funktioner og åbne min GitHub-sponsorprofil.</string>
|
||||
<string name="upgrade_screen_status_free_title">Gratis version</string>
|
||||
<string name="upgrade_screen_status_free_body">Du bruger den gratis version af CAPod. Ekstra funktioner kan låses op ved at støtte udviklingen.</string>
|
||||
<string name="upgrade_screen_status_free_action">Se opgraderingsmuligheder</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Opgradering aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Hold det kørende</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod udvikles løbende gennem opdateringer og fejlrettelser. Hvis du gerne vil understøtte det, kan du overveje en tilbagevendende donation via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Fördere Entwicklung</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Keine Werbung. Kein Tracking. Keine Google-Play-Bindung.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Schon zurück? Deine Unterstützung hält CAPod am Leben.</string>
|
||||
<string name="upgrade_foss_supporter_since">Unterstützer seit %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Vielen Dank, dass du die Entwicklung von CAPod unterstützt!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Sponsoring-Seite öffnen</string>
|
||||
<string name="settings_upgrade_status_label">CAPod unterstützen</string>
|
||||
<string name="settings_upgrade_status_description">Dein Unterstützerstatus.</string>
|
||||
<string name="upgrade_screen_why_title">Vorteile des Upgrades</string>
|
||||
<string name="upgrade_screen_how_title">Wie man hilft</string>
|
||||
<string name="upgrade_screen_how_body">Werde Unterstützer und fördere die Entwicklung! Tippe auf den Button unten, um alle Zusatzfunktionen zu aktivieren und mein GitHub-Sponsors-Profil zu öffnen.</string>
|
||||
<string name="upgrade_screen_status_free_title">Kostenlose Version</string>
|
||||
<string name="upgrade_screen_status_free_body">Du verwendest die kostenlose Version von CAPod. Zusätzliche Funktionen können durch die Unterstützung der Entwicklung freigeschaltet werden.</string>
|
||||
<string name="upgrade_screen_status_free_action">Upgrade-Optionen ansehen</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Projekt unterstützen</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod entwickelt sich durch Updates und Fehlerbehebungen kontinuierlich weiter. Wenn du das unterstützen möchtest, ziehe eine wiederkehrende Spende über GitHub Sponsors in Betracht.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Χορηγήστε την ανάπτυξη</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Χωρίς διαφημίσεις. Χωρίς παρακολούθηση. Χωρίς δέσμευση στο Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Επιστρέψατε ήδη; Η υποστήριξή σας κρατά το CAPod ζωντανό.</string>
|
||||
<string name="upgrade_foss_supporter_since">Υποστηρικτής από %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Σας ευχαριστούμε που υποστηρίζετε την ανάπτυξη του CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Άνοιγμα σελίδας χορηγίας</string>
|
||||
<string name="settings_upgrade_status_label">Χορηγήστε το CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Η κατάστασή σας ως υποστηρικτή.</string>
|
||||
<string name="upgrade_screen_why_title">Πλεονεκτήματα αναβάθμισης</string>
|
||||
<string name="upgrade_screen_how_title">Πώς να βοηθήσετε</string>
|
||||
<string name="upgrade_screen_how_body">Γίνετε patron και χορηγήστε την ανάπτυξη! Πατήστε το κουμπί παρακάτω για να ενεργοποιήσετε όλα τα επιπλέον χαρακτηριστικά και ανοίξτε το προφίλ μου GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Δωρεάν έκδοση</string>
|
||||
<string name="upgrade_screen_status_free_body">Χρησιμοποιείτε τη δωρεάν έκδοση του CAPod. Επιπλέον δυνατότητες μπορούν να ξεκλειδωθούν υποστηρίζοντας την ανάπτυξη.</string>
|
||||
<string name="upgrade_screen_status_free_action">Δείτε τις επιλογές αναβάθμισης</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Αναβάθμιση ενεργή</string>
|
||||
<string name="upgrade_screen_recurring_title">Κρατήστε το ζωντανό</string>
|
||||
<string name="upgrade_screen_recurring_body">Το CAPod συνεχίζει να εξελίσσεται μέσω ενημερώσεων και διορθώσεων. Αν θέλετε να το στηρίξετε, σκεφτείτε μια επαναλαμβανόμενη δωρεά μέσω του GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsorear el desarrollo</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sin publicidad. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">¿Ya te vas? Tu apoyo mantiene CAPod vivo.</string>
|
||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||
<string name="settings_upgrade_status_label">Apoyá CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
||||
<string name="upgrade_screen_why_title">Beneficios de la mejora</string>
|
||||
<string name="upgrade_screen_how_title">Como ayudar</string>
|
||||
<string name="upgrade_screen_how_body">¡Conviértete en patrocinador y patrocina el desarrollo! Toque el botón de abajo para activar todas las funciones adicionales y abrir mi perfil de Patrocinadores de GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versión gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Estás usando la versión gratuita de CAPod. Se pueden desbloquear características adicionales apoyando el desarrollo.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opciones de mejora</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Mejora activa</string>
|
||||
<string name="upgrade_screen_recurring_title">Mantené el impulso</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod sigue evolucionando a través de actualizaciones y correcciones. Si querés sostener eso, considera una donación recurrente a través de GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocinar el desarrollo</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">¿Ya de vuelta? Tu apoyo mantiene CAPod con vida.</string>
|
||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||
<string name="settings_upgrade_status_label">Patrocina CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Tu estado de patrocinador.</string>
|
||||
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
||||
<string name="upgrade_screen_how_title">Cómo ayudar</string>
|
||||
<string name="upgrade_screen_how_body">¡Conviértete en un patrocinador y apoya el desarrollo constante de la aplicación! Presiona el botón a continuación para activar todas las funciones adicionales además de abrir mi perfil de Patrocinadores en GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versión gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Estás usando la versión gratuita de CAPod. Puedes desbloquear características extra apoyando el desarrollo.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opciones de actualización</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Actualización activa</string>
|
||||
<string name="upgrade_screen_recurring_title">Sigue adelante</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod sigue evolucionando con actualizaciones y correcciones. Si quieres sostener eso, considera una donación recurrente a través de GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocinadores</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sin anuncios. Sin rastreo. Sin dependencia de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">¿Ya de vuelta? Tu apoyo mantiene CAPod vivo.</string>
|
||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">¡Gracias por apoyar el desarrollo de CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocinio</string>
|
||||
<string name="settings_upgrade_status_label">Patrocinar CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Tu estado como patrocinador.</string>
|
||||
<string name="upgrade_screen_why_title">Beneficios de la actualización</string>
|
||||
<string name="upgrade_screen_how_title">Como ayudar</string>
|
||||
<string name="upgrade_screen_how_body">¡Conviértete en patrocinador y patrocina el desarrollo! Toque el botón de abajo para activar todas las funciones adicionales y abrir mi perfil de Patrocinadores de GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versión gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Estás usando la versión gratuita de CAPod. Puedes desbloquear funciones adicionales apoyando el desarrollo.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opciones de actualización</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Actualización activa</string>
|
||||
<string name="upgrade_screen_recurring_title">Apóyalo</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod sigue evolucionando gracias a actualizaciones y correcciones. Si quieres mantener eso en marcha, considera una donación recurrente a través de GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Rahasta arendamist</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Reklaami pole. Jälgimist pole. Google Play lukustust pole.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Juba tagasi? Sinu toetus hoiab CAPodi elus.</string>
|
||||
<string name="upgrade_foss_supporter_since">Toetaja alates %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Täname, et toetad CAPodi arendust!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Ava sponsorlehekülg</string>
|
||||
<string name="settings_upgrade_status_label">Rahasta CAPodi</string>
|
||||
<string name="settings_upgrade_status_description">Sinu toetaja staatus.</string>
|
||||
<string name="upgrade_screen_why_title">Uuendamise eelised</string>
|
||||
<string name="upgrade_screen_how_title">Kuidas aidata?</string>
|
||||
<string name="upgrade_screen_how_body">Hakake toetajaks ja rahastage arendamist. Kõikide lisavõimaluste kasutamiseks ja minu GitHub Sponsors profiili avamiseks puudutage alumist nuppu.</string>
|
||||
<string name="upgrade_screen_status_free_title">Tasuta versioon</string>
|
||||
<string name="upgrade_screen_status_free_body">Kasutate CAPodi tasuta versiooni. Lisavõimaluste kasutamiseks toetage arendust.</string>
|
||||
<string name="upgrade_screen_status_free_action">Vaadake täiendamise valikuid</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Uuendus kasutatav</string>
|
||||
<string name="upgrade_screen_recurring_title">Jätkake nii</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod areneb pidevalt värskenduste ja paranduste kaudu. Kui soovite seda toetada, kaaluge korduvat annetust GitHub Sponsorsi kaudu.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Garapena babestu</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Iragarkirik ez. Jarraipenik ez. Google Play-ren lotura ez.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Dagoeneko itzuli? Zure laguntzak CAPod bizirik mantentzen du.</string>
|
||||
<string name="upgrade_foss_supporter_since">Laguntzaile %s(e)tik aurrera</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Eskerrik asko CAPod-en garapena babesten duzulako!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Ireki babesle-orria</string>
|
||||
<string name="settings_upgrade_status_label">CAPod babeslatu</string>
|
||||
<string name="settings_upgrade_status_description">Zure babesle egoera</string>
|
||||
<string name="upgrade_screen_why_title">Hobekuntza-onurak</string>
|
||||
<string name="upgrade_screen_how_title">Nola lagundu</string>
|
||||
<string name="upgrade_screen_how_body">Izan babesle eta garapen babeslari! Egin klik beheko botoian eginbide gehigarri guztiak aktibatzeko eta nire GitHub Sponsors profila irekitzeko.</string>
|
||||
<string name="upgrade_screen_status_free_title">Doako bertsioa</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod-en doako bertsioa erabiltzen ari zara. Funtzio gehigarriak desblokeatu ditzakezu garapena lagunduz.</string>
|
||||
<string name="upgrade_screen_status_free_action">Hobekuntza-aukerak ikusi</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Hobekuntza aktiboa</string>
|
||||
<string name="upgrade_screen_recurring_title">Jarraitu</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod eguneratzen eta konpondutzen jarraitzen du. Hori mantendu nahi baduzu, dohaintza periodikoa GitHub Sponsors bidez kontuan hartu.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">حامی توسعه دهنده</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">بدون تبلیغ. بدون ردیابی. بدون وابستگی به Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">زود برگشتیدی؟ حمایت شما CAPod را زنده نگه میدارد.</string>
|
||||
<string name="upgrade_foss_supporter_since">حامی از %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">از حمایت شما از توسعه CAPod سپاسگزاریم!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">باز کردن صفحه حمایت مالی</string>
|
||||
<string name="settings_upgrade_status_label">حمایت از CAPod</string>
|
||||
<string name="settings_upgrade_status_description">وضعیت حمایتی شما.</string>
|
||||
<string name="upgrade_screen_why_title">مزایای ارتقا</string>
|
||||
<string name="upgrade_screen_how_title">چگونه کمک کنیم</string>
|
||||
<string name="upgrade_screen_how_body">به حامی تبدیل شوید و توسعه را حمایت کنید! برای فعال کردن همه ویژگیهای اضافی و باز کردن نمایه GitHub Sponsors من، روی دکمه زیر ضربه بزنید.</string>
|
||||
<string name="upgrade_screen_status_free_title">نسخه رایگان</string>
|
||||
<string name="upgrade_screen_status_free_body">شما از نسخه رایگان CAPod استفاده میکنید. ویژگیهای اضافی با حمایت از توسعه فعال میشوند.</string>
|
||||
<string name="upgrade_screen_status_free_action">مشاهده گزینههای ارتقا</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">ارتقا فعال</string>
|
||||
<string name="upgrade_screen_recurring_title">ادامه دهید</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod از طریق بروزرسانیها و رفعهای خطا به تکامل خود ادامه میدهد. اگر میخواهید این تکامل ادامه یابد، کمک مالی مکرر از طریق GitHub Sponsors را در نظر بگیرید.</string>
|
||||
<string name="upgrade_badge_label">منبعآزاد</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsoroi kehitystä</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Ei mainoksia. Ei seurantaa. Ei Google Play -riippuvuutta.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Jo takaisin? Tukesi pitää CAPod-sovelluksen hengissä.</string>
|
||||
<string name="upgrade_foss_supporter_since">Tukija %s lähtien</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Kiitos, että tuet CAPodin kehitystä!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Avaa sponsorisivu</string>
|
||||
<string name="settings_upgrade_status_label">Tue CAPodia</string>
|
||||
<string name="settings_upgrade_status_description">Kannattajantila</string>
|
||||
<string name="upgrade_screen_why_title">Päivityksen edut</string>
|
||||
<string name="upgrade_screen_how_title">Kuinka auttaa</string>
|
||||
<string name="upgrade_screen_how_body">Ryhdy tukijaksi ja sponsoroi kehitystä! Napauta alla olevaa painiketta aktivoidaksesi kaikki lisäominaisuudet ja avataksesi GitHub Sponsors -profiilini.</string>
|
||||
<string name="upgrade_screen_status_free_title">Ilmainen versio</string>
|
||||
<string name="upgrade_screen_status_free_body">Käytät CAPodin ilmaista versiota. Lisäominaisuudet voidaan avata tukemalla kehitystä.</string>
|
||||
<string name="upgrade_screen_status_free_action">Katso päivitysvaihtoehdot</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Päivitys aktiivinen</string>
|
||||
<string name="upgrade_screen_recurring_title">Pidä se käynnissä</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod kehittyy jatkuvasti päivitysten ja korjausten kautta. Jos haluat tukea sitä, harkitse toistuvaa lahjoitusta GitHub Sponsorien kautta.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Mag-sponsor ng development</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Walang ads. Walang tracking. Walang Google Play lock-in.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Bumalik na? Ang iyong suporta ay nagpapanatiling buhay ng CAPod.</string>
|
||||
<string name="upgrade_foss_supporter_since">Tagasuporta simula %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Salamat sa pagsuporta sa development ng CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Buksan ang sponsor page</string>
|
||||
<string name="settings_upgrade_status_label">Suportahan ang CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Ang iyong status bilang supporter.</string>
|
||||
<string name="upgrade_screen_why_title">Mga benepisyo ng upgrade</string>
|
||||
<string name="upgrade_screen_how_title">Paano tumulong</string>
|
||||
<string name="upgrade_screen_how_body">Maging patron at mag-sponsor ng development! I-tap ang button sa ibaba para ma-activate ang lahat ng extra features at buksan ang aking GitHub Sponsors profile.</string>
|
||||
<string name="upgrade_screen_status_free_title">Libreng bersyon</string>
|
||||
<string name="upgrade_screen_status_free_body">Gumagamit ka ng libreng bersyon ng CAPod. Ang mga extra features ay maaaring ma-unlock sa pamamagitan ng pag-suporta sa development.</string>
|
||||
<string name="upgrade_screen_status_free_action">Tingnan ang mga opsyon sa upgrade</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Aktibong upgrade</string>
|
||||
<string name="upgrade_screen_recurring_title">Panatilihin ang pagpapatuloy</string>
|
||||
<string name="upgrade_screen_recurring_body">Ang CAPod ay patuloy na umuunlad sa pamamagitan ng updates at fixes. Kung gusto mong suportahan iyan, isaalang-alang ang recurring donation sa pamamagitan ng GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Soutenir le développement</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Pas de publicités. Pas de suivi à la trace. Pas de dépendance à Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Déjà de retour ? Votre soutien maintient CAPod en vie.</string>
|
||||
<string name="upgrade_foss_supporter_since">Soutien depuis %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Merci de soutenir le développement de CAPod !</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Ouvrir la page de parrainage</string>
|
||||
<string name="settings_upgrade_status_label">Soutenir CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Votre statut de supporter.</string>
|
||||
<string name="upgrade_screen_why_title">Avantages de la mise à niveau</string>
|
||||
<string name="upgrade_screen_how_title">Comment aider</string>
|
||||
<string name="upgrade_screen_how_body">Devenez mécène et soutenez le développement. Touchez le bouton ci-dessous pour activer toutes les fonctions supplémentaires et ouvrir mon profil GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Version gratuite</string>
|
||||
<string name="upgrade_screen_status_free_body">Vous utilisez la version gratuite de CAPod. Des fonctionnalités supplémentaires peuvent être déverrouillées en soutenant le développement.</string>
|
||||
<string name="upgrade_screen_status_free_action">Voir les options de mise à niveau</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Mise à niveau active</string>
|
||||
<string name="upgrade_screen_recurring_title">Gardez ça en route</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continue à évoluer grâce aux mises à jour et aux corrections. Si vous souhaitez soutenir cela, envisagez un don récurrent via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">Logiciel libre</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocinar desenvolvemento</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sen anuncios. Sen rastrexo. Sen dependencia de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">És rápido/a! O teu apoio mantén CAPod vivo.</string>
|
||||
<string name="upgrade_foss_supporter_since">Colaborador desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Grazas por apoiar o desenvolvemento de CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir a páxina de patrocinio</string>
|
||||
<string name="settings_upgrade_status_label">Apoia CAPod</string>
|
||||
<string name="settings_upgrade_status_description">O teu estado de apoiador.</string>
|
||||
<string name="upgrade_screen_why_title">Vantaxes da actualización</string>
|
||||
<string name="upgrade_screen_how_title">Como axudar</string>
|
||||
<string name="upgrade_screen_how_body">Convértete en mecenas e patrocina o desenvolvemento! Toca o botón de abaixo para activar todas as características extra e abrir o meu perfil de GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versión gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Estás usando a versión gratuita de CAPod. As características adicionais pódense desbloquear apoiando o desenvolvemento.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opcións de actualización</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Actualización activa</string>
|
||||
<string name="upgrade_screen_recurring_title">Manténo en marcha</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod segue evolucionando a través de actualizacións e correccións. Se queres mantelo así, considera unha doación recorrente a través de GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">विकास को प्रायोजक करें</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">कोई विज्ञापन नहीं। कोई ट्रैकिंग नहीं। Google Play पर निर्भरता नहीं।</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">अभी वापस? आपका समर्थन CAPod को जीवित रखता है।</string>
|
||||
<string name="upgrade_foss_supporter_since">%s से समर्थक</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod के विकास का समर्थन करने के लिए धन्यवाद!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">स्पॉन्सर पेज खोलें</string>
|
||||
<string name="settings_upgrade_status_label">CAPod को प्रायोजित करें</string>
|
||||
<string name="settings_upgrade_status_description">आपकी समर्थक स्थिति।</string>
|
||||
<string name="upgrade_screen_why_title">अपग्रेड के लाभ</string>
|
||||
<string name="upgrade_screen_how_title">कैसे सहायता करें</string>
|
||||
<string name="upgrade_screen_how_body">संरक्षक बनें और विकास को प्रायोजित करें! सभी अतिरिक्त सुविधाओं को सक्रिय करने और मेरी GitHub Sponsors प्रोफ़ाइल खोलने के लिए नीचे दिए गए बटन को टैप करें।</string>
|
||||
<string name="upgrade_screen_status_free_title">मुफ़्त संस्करण</string>
|
||||
<string name="upgrade_screen_status_free_body">आप CAPod के मुफ़्त संस्करण का उपयोग कर रहे हैं। विकास का समर्थन करके अतिरिक्त सुविधाओं को अनलॉक किया जा सकता है।</string>
|
||||
<string name="upgrade_screen_status_free_action">अपग्रेड विकल्प देखें</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">अपग्रेड सक्रिय</string>
|
||||
<string name="upgrade_screen_recurring_title">जारी रखें</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod अपडेट और सुधार के माध्यम से विकसित होता रहता है। यदि आप इसे जारी रखना चाहते हैं, तो GitHub Sponsors के माध्यम से आवर्ती दान पर विचार करें।</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Podržite razvoj</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Bez oglasa. Bez praćenja. Bez zaključanosti na Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Već se vraćate? Vaša podrška čuva CAPod na životu.</string>
|
||||
<string name="upgrade_foss_supporter_since">Podržavatelj od %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Hvala vam što podržavate razvoj CAPoda!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Otvori stranicu za sponzoriranje</string>
|
||||
<string name="settings_upgrade_status_label">Sponzorirajte CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Vaš status sponzora</string>
|
||||
<string name="upgrade_screen_why_title">Prednosti nadogradnje</string>
|
||||
<string name="upgrade_screen_how_title">Kako pomoći</string>
|
||||
<string name="upgrade_screen_how_body">Postanite pokrovitelj i sponzorirajte razvoj! Dodirnite gumb ispod da biste aktivirali sve dodatne značajke i otvorili moj GitHub sponzorski profil.</string>
|
||||
<string name="upgrade_screen_status_free_title">Besplatna verzija</string>
|
||||
<string name="upgrade_screen_status_free_body">Koristite besplatnu verziju aplikacije CAPod. Dodatne mogućnosti mogu se otključati podržavanjem razvoja.</string>
|
||||
<string name="upgrade_screen_status_free_action">Pogledajte mogućnosti nadogradnje</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Nadogradnja je aktivna</string>
|
||||
<string name="upgrade_screen_recurring_title">Nastavi dalje</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod se nastavlja razvijati kroz ažuriranja i ispravke. Ako želite održati to, razmislite o ponavljajućoj donaciji putem GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Szponzori fejlesztés</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Nincs hirdetés. Nincs nyomkövetés. Nincs Google Play-függőség.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Már visszamész? A támogatásodnak köszönhetően él tovább a CAPod.</string>
|
||||
<string name="upgrade_foss_supporter_since">Támogató %s óta</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Köszönjük, hogy támogatod a CAPod fejlesztését!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Támogatói oldal megnyitása</string>
|
||||
<string name="settings_upgrade_status_label">Támogasson CAPod-ot</string>
|
||||
<string name="settings_upgrade_status_description">Az Ön támogató státusza.</string>
|
||||
<string name="upgrade_screen_why_title">Frissítési előnyök</string>
|
||||
<string name="upgrade_screen_how_title">Hogyan lehet segíteni</string>
|
||||
<string name="upgrade_screen_how_body">Legyen patron támogató és szponzorálja a fejlesztést! Kattintson az alábbi gombra az összes extra funkció aktiválásához és a GitHub Sponsors profilom megnyitásához.</string>
|
||||
<string name="upgrade_screen_status_free_title">Ingyenes verzió</string>
|
||||
<string name="upgrade_screen_status_free_body">A CAPod ingyenes verzióját használod. A további funkciókat a fejlesztés támogatásával feloldhatod.</string>
|
||||
<string name="upgrade_screen_status_free_action">Frissítési lehetőségek</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Frissítés aktív</string>
|
||||
<string name="upgrade_screen_recurring_title">Folytasd a támogatást</string>
|
||||
<string name="upgrade_screen_recurring_body">A CAPod folyamatosan fejlődik frissítéseken és hibajavításokon keresztül. Ha szeretnéd ezt fenntartani, fontold meg az ismétlődő adományt a GitHub Sponsors-on.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Հովանավորել զարգացումը</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Լրատնություն չկա: հետքխկություն չկա: Google Play-ի կապվածություն չկա:</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Արդևն հետ? ձևր աիկտակցությունը CAPod-ին կենդանի պահում:</string>
|
||||
<string name="upgrade_foss_supporter_since">Հովանավոր է %s-ից</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Շնորհակալություն CAPod-ի զարգացումն աջակցելու համար!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Բացել հովանավորության էջը</string>
|
||||
<string name="settings_upgrade_status_label">Աջակեք CAPod-ին</string>
|
||||
<string name="settings_upgrade_status_description">Ձեր աջակցողի վիճակը:</string>
|
||||
<string name="upgrade_screen_why_title">Թարմացման առավելությունները</string>
|
||||
<string name="upgrade_screen_how_title">Ինչպես օգնել</string>
|
||||
<string name="upgrade_screen_how_body">Դարձեք հովանավոր և հովանավորեք զարգացումը: Սեղմեք ստորև գտնվող կոճակը՝ բոլոր լրացուցիչ գործառույթները ակտիվացնելու և իմ GitHub Sponsors պրոֆիլը բացելու համար:</string>
|
||||
<string name="upgrade_screen_status_free_title">Անվճար տարբերակ</string>
|
||||
<string name="upgrade_screen_status_free_body">Դուք օգտագործում եք CAPod-ի անվճար տարբերակը: Լրացուցիչ գործառույթները կարող են բացվել, աջակցելով զարգացմանը:</string>
|
||||
<string name="upgrade_screen_status_free_action">Տեսնել թարմացման տարբերակները</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Թարմացումն ակտիվ է</string>
|
||||
<string name="upgrade_screen_recurring_title">Շարունակեք</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod-ը շարունակում է զարգանալ թարմացումների և ուղղումների միջոցով: Եթե ցանկանում եք աջակցել դրան, դիտարկեք պարբերական նվիրատվություն GitHub Sponsors-ի միջոցով:</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Pengembangan sponsor</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Tanpa iklan. Tanpa pelacakan. Tanpa ketergantungan Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Sudah kembali? Dukungan Anda menjaga CAPod tetap hidup.</string>
|
||||
<string name="upgrade_foss_supporter_since">Pendukung sejak %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Terima kasih karena telah mendukung pengembangan CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Buka halaman sponsor</string>
|
||||
<string name="settings_upgrade_status_label">Sponsori CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Status pendukung Anda.</string>
|
||||
<string name="upgrade_screen_why_title">Manfaat upgrade</string>
|
||||
<string name="upgrade_screen_how_title">Cara membantu</string>
|
||||
<string name="upgrade_screen_how_body">Jadilah pelindung dan sponsor pengembangan! Ketuk tombol di bawah untuk mengaktifkan semua fitur tambahan dan membuka profil GitHub Sponsors saya.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versi gratis</string>
|
||||
<string name="upgrade_screen_status_free_body">Anda menggunakan versi gratis CAPod. Fitur tambahan dapat dibuka dengan mendukung pengembangan.</string>
|
||||
<string name="upgrade_screen_status_free_action">Lihat opsi upgrade</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade aktif</string>
|
||||
<string name="upgrade_screen_recurring_title">Terus berkembang</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod terus berkembang melalui pembaruan dan perbaikan. Jika Anda ingin mendukung itu, pertimbangkan donasi berulang melalui GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Styrkja þróun</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Engar auglysíngar. Engin rakning. Ekkert Google Play-lás.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Aftur þegar? Styðjað þít heldur CAPod lifandi.</string>
|
||||
<string name="upgrade_foss_supporter_since">Styrktaraðili síðan %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Takk fyrir að styðja þróun CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Opna styrktarsíðu</string>
|
||||
<string name="settings_upgrade_status_label">Styrktu CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Staða þín sem stuðningsmaður</string>
|
||||
<string name="upgrade_screen_why_title">Uppfærslukostir</string>
|
||||
<string name="upgrade_screen_how_title">Hvernig á að hjálpa</string>
|
||||
<string name="upgrade_screen_how_body">Vertu styrktaraðili og styrktu þróun! Ýttu á hnappinn hér að neðan til að virkja alla viðbótareiginleika og opna GitHub Sponsors prófílinn minn.</string>
|
||||
<string name="upgrade_screen_status_free_title">Ókeypis útgáfa</string>
|
||||
<string name="upgrade_screen_status_free_body">Þú ert að nota ókeypis útgáfu CAPod. Hægt er að aflása aukaeiginleikum með því að styðja þróun.</string>
|
||||
<string name="upgrade_screen_status_free_action">Skoðaðu uppfærsluvalkosti</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Uppfærsla virk</string>
|
||||
<string name="upgrade_screen_recurring_title">Haltu því gangandi</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod heldur áfram að þróast með uppfærslum og lagfæringum. Ef þú vilt standa við það, skaltu íhuga endurtekna framlög í gegnum GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Finanzia lo sviluppo</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Nessuna pubblicità. Nessun tracciamento. Nessun vincolo con Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Già via? Il tuo supporto mantiene CAPod in vita.</string>
|
||||
<string name="upgrade_foss_supporter_since">Sostenitore dal %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Grazie per supportare lo sviluppo di CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Apri la pagina sponsor</string>
|
||||
<string name="settings_upgrade_status_label">Sponsorizza CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Il tuo status di sostenitore.</string>
|
||||
<string name="upgrade_screen_why_title">Vantaggi dell\'aggiornamento</string>
|
||||
<string name="upgrade_screen_how_title">Come aiutare</string>
|
||||
<string name="upgrade_screen_how_body">Diventa un sostenitore e sponsorizza lo sviluppo! Clicca il pulsante qui sotto per attivare tutte le funzioni extra e apri il mio profilo Sponsor Github.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versione gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Stai usando la versione gratuita di CAPod. Funzionalità aggiuntive possono essere sbloccate supportando lo sviluppo.</string>
|
||||
<string name="upgrade_screen_status_free_action">Visualizza opzioni di aggiornamento</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Aggiornamento attivo</string>
|
||||
<string name="upgrade_screen_recurring_title">Continua così</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continua a evolversi con aggiornamenti e correzioni. Se desideri sostenerlo, considera una donazione ricorrente via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">פיתוח חסות</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">אין פרסומות. אין מעקב. אין תלות ב-Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">כבר חוזר? התמיכה שלך שומרת את CAPod בחיים.</string>
|
||||
<string name="upgrade_foss_supporter_since">תומך מאז %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">תודה שאתה תומך בפיתוח של CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">פתח את דף התמיכה</string>
|
||||
<string name="settings_upgrade_status_label">תמוך ב-CAPod</string>
|
||||
<string name="settings_upgrade_status_description">סטטוס התומך שלך.</string>
|
||||
<string name="upgrade_screen_why_title">יתרונות השדרוג</string>
|
||||
<string name="upgrade_screen_how_title">איך לעזור</string>
|
||||
<string name="upgrade_screen_how_body">הפוך לפטרון ונותן חסות לפיתוח! הקש על הכפתור למטה כדי להפעיל את כל התכונות הנוספות ולפתוח את פרופיל הספונסרים בגיטהאב שלי.</string>
|
||||
<string name="upgrade_screen_status_free_title">גרסה חינם</string>
|
||||
<string name="upgrade_screen_status_free_body">אתה משתמש בגרסה החינם של CAPod. ניתן לפתוח תכונות נוספות על ידי תמיכה בפיתוח.</string>
|
||||
<string name="upgrade_screen_status_free_action">צפה באפשרויות השדרוג</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">השדרוג פעיל</string>
|
||||
<string name="upgrade_screen_recurring_title">תמשך בכך</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod ממשיך להתפתח דרך עדכונים ותיקונים. אם אתה רוצה לתמוך בכך, שקול תרומה חוזרת דרך GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">開発支援者</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">広告なし。追跡なし。Google Play依存なし。</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">もう戻りますか?あなたのサポートがCAPodを支えています。</string>
|
||||
<string name="upgrade_foss_supporter_since">%sからのサポーター</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPodの開発を支援していただきありがとうございます!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">スポンサーページを開く</string>
|
||||
<string name="settings_upgrade_status_label">CAPod をスポンサーする</string>
|
||||
<string name="settings_upgrade_status_description">サポーターステータス。</string>
|
||||
<string name="upgrade_screen_why_title">アップグレードの特典</string>
|
||||
<string name="upgrade_screen_how_title">協力するには</string>
|
||||
<string name="upgrade_screen_how_body">パトロンとスポンサーの開発になりましょう!下のボタンをタップすると、すべての追加機能が有効になり、GitHub Sponsors プロファイルを開きます。</string>
|
||||
<string name="upgrade_screen_status_free_title">無料版</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod の無料版を使用しています。開発を支援することで、追加機能をアンロックできます。</string>
|
||||
<string name="upgrade_screen_status_free_action">アップグレード オプションを確認</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">アップグレード有効</string>
|
||||
<string name="upgrade_screen_recurring_title">サポート継続</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod は更新と修正を通じて進化し続けています。サポートを続けたい場合は、GitHub Sponsors を通じて定期的な寄付を検討してください。</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">სპონსორის განვითარება</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">რეკლამა არა. თვალთვალება არა. Google Play-ზე დამოკიდება არა.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">უკვე დაბრუნდით? თქვენი მხარდაჯერა CAPod-ს გადარჩენებას ეხმარება.</string>
|
||||
<string name="upgrade_foss_supporter_since">მხარდამჭერი %s-დან</string>
|
||||
<string name="upgrade_foss_supporter_thanks">მადლობა CAPod-ის განვითარების მხარდაჭერისთვის!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">სპონსორის გვერდის გახსნა</string>
|
||||
<string name="settings_upgrade_status_label">მხარი დაუჭიროთ CAPod-ს</string>
|
||||
<string name="settings_upgrade_status_description">თქვენი მხარდამჭერის მდგომარეობა.</string>
|
||||
<string name="upgrade_screen_why_title">განახლების უპირატესობები</string>
|
||||
<string name="upgrade_screen_how_title">როგორ დაგეხმაროთ</string>
|
||||
<string name="upgrade_screen_how_body">გახდით მფარველი და სპონსორობა გაუწიეთ განვითარებას! შეეხეთ ქვემოთ მოცემულ ღილაკს, რათა ააქტიუროთ ყველა დამატებითი ფუნქცია და გახსნათ ჩემი GitHub Sponsors პროფილი.</string>
|
||||
<string name="upgrade_screen_status_free_title">უფასო ვერსია</string>
|
||||
<string name="upgrade_screen_status_free_body">თქვენ იყენებთ CAPod-ის უფასო ვერსიას. დამატებითი ფუნქციები შეიძლება აშვებული იყოს განვითარების მხარდასაჭერით.</string>
|
||||
<string name="upgrade_screen_status_free_action">განახლების ვარიანტების ნახვა</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">განახლება აქტიური</string>
|
||||
<string name="upgrade_screen_recurring_title">ამის გაგრძელება</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod განაგრძობს განვითარებას განახლებებისა და შეასწორებების მეშვეობით. თუ გსურთ ამის შენარჩუნება, განიხილეთ რეგულარული დონაცია GitHub Sponsors-ის მეშვეობით.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ឧបត្ថម្ភការអភិវឌ្ឍន៍</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">គ្មានការផ្សាយពាណិជ្ជកម្ម។ គ្មានការតាមដាន។ គ្មានការចាក់សោ Google Play។</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ត្រលប់មកវិញហើយ។? ការគាំទ្ររបស់អ្នកចិញ្ចឹម CAPod ឥ្សរិយនៅរស់។</string>
|
||||
<string name="upgrade_foss_supporter_since">អ្នកគាំទ្រតាំងពី %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">សូមអរគុណសម្រាប់ការគាំទ្រការអភិវឌ្ឍន៍ CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">បើកទំព័រឧបត្ថម្ភ</string>
|
||||
<string name="settings_upgrade_status_label">ឧបត្ថម្ភ CAPod</string>
|
||||
<string name="settings_upgrade_status_description">ស្ថានភាពអ្នកគាំទ្ររបស់អ្នក។</string>
|
||||
<string name="upgrade_screen_why_title">អត្ថប្រយោជន៍លើកកម្ពស់</string>
|
||||
<string name="upgrade_screen_how_title">របៀបជួយ</string>
|
||||
<string name="upgrade_screen_how_body">ក្លាយជាអ្នកឧបត្ថម្ភ និងឧបត្ថម្ភការអភិវឌ្ឍន៍! ចុចប៊ូតុងខាងក្រោមដើម្បីធ្វើឱ្យមុខងារបន្ថែមទាំងអស់សកម្ម និងបើកប្រវត្តិរូប GitHub Sponsors របស់ខ្ញុំ។</string>
|
||||
<string name="upgrade_screen_status_free_title">កំណែឥតគិតថ្លៃ</string>
|
||||
<string name="upgrade_screen_status_free_body">អ្នកកំពុងប្រើប្រាស់កំណែឥតគិតថ្លៃរបស់ CAPod។ មុខងារលម្អិតបន្ថែមលេចឡើងដោយការគាំទ័របង្កើនលេខ។</string>
|
||||
<string name="upgrade_screen_status_free_action">មើលជម្រើសលើកកម្ពស់</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">លើកកម្ពស់សកម្ម</string>
|
||||
<string name="upgrade_screen_recurring_title">បន្តដង្ហើម</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod បន្តលូតលាស់តាមរយៈការធ្វើឱ្យថ្មីនិងការកែប្រែ។ ប្រសិនបើអ្នកចង់រក្សាវាឱ្យរស់រាន, ពិចារណាការរួមចំណែកម្តងម្កាលរបស់អ្នកតាមរយៈ GitHub Sponsors។</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Pêşdebiriyê teref bike</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Reklam tune. Śopandin tune. Girêdana Google Play tune.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Zirû vegeriya? Piştgiriya we CAPod sax dihêle.</string>
|
||||
<string name="upgrade_foss_supporter_since">Piştgir ji %s ve</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Spas ji bo piştgiriya te ya pêşxistina CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Rûpela piştgiriyê veke</string>
|
||||
<string name="settings_upgrade_status_label">CAPod-ê piştgirî bike</string>
|
||||
<string name="settings_upgrade_status_description">Rewşa piştgiriya te.</string>
|
||||
<string name="upgrade_screen_why_title">Feydeyên Bardiyê</string>
|
||||
<string name="upgrade_screen_how_title">Çawa Alîkarî Bike</string>
|
||||
<string name="upgrade_screen_how_body">Bibin patronê û pîşesaziyê xwehûnand bikin! Bişka jêrîn dakirin da ku hemî taybetiyên zêde çalak bikin û profîla GitHub Sponsors-a min vekirin.</string>
|
||||
<string name="upgrade_screen_status_free_title">Guhertoya Belaş</string>
|
||||
<string name="upgrade_screen_status_free_body">Hûn guhertoya belaş ya CAPod bikar tîne. Taybetiyên zêde dikarin bê pîşesaziyê xwehûnandê tê de vebirîn.</string>
|
||||
<string name="upgrade_screen_status_free_action">Vebijarkên Bardiya Bibînin</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Bardiya Çalak e</string>
|
||||
<string name="upgrade_screen_recurring_title">Berdewam Bike</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod di navberê nûkariyan û raskariyan de cardin pêşve diçe. Ger hûn dixwazin vê berdewam bikin, hemî kirînên danûstî di riya GitHub Sponsors-a de bifikirin.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ಅಭಿವೃದ್ಧಿಗೆ ಪ್ರಾಯೋಜಕತ್ವ ನೀಡಿ</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ಜಾಹೀರಾತುಗಳಿಲ್ಲ. ಭಕ್ಷಣೆ ಇಲ್ಲ. Google Play ಲಾಕ್-ಇನ್ ಇಲ್ಲ.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ಇಷ್ಟೇ ಹಿಂದಿರುಗಿದಿರಿ? ನಿಮ್ಮ ಬೆಂಬಲ CAPod ಅನ್ನು ಜೀವಂತವಾಗಿಡುತ್ತದೆ.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s ರಿಂದ ಬೆಂಬಲಿಗ</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod ಅಭಿವೃದ್ಧಿಗೆ ಬೆಂಬಲ ನೀಡಿದ್ದಕ್ಕಾಗಿ ಧನ್ಯವಾದಗಳು!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">ಪ್ರಾಯೋಜಕ ಪುಟ ತೆರೆಯಿರಿ</string>
|
||||
<string name="settings_upgrade_status_label">CAPod ಬೆಂಬಲಿಸಿ</string>
|
||||
<string name="settings_upgrade_status_description">ನಿಮ್ಮ ಬೆಂಬಲಕಾರ ಸ್ಥಿತಿ.</string>
|
||||
<string name="upgrade_screen_why_title">ನವೀಕರಣ ಪ್ರಯೋಜನಗಳು</string>
|
||||
<string name="upgrade_screen_how_title">ಸಹಾಯ ಮಾಡುವುದು ಹೇಗೆ</string>
|
||||
<string name="upgrade_screen_how_body">ಆಶ್ರಯದಾತ ಮತ್ತು ಅಭಿವೃದ್ಧಿ ಸ್ಪನ್ಸರ್ ಆಗಿ ಮಾರ್ಪಡಿ! ಎಲ್ಲಾ ಹೆಚ್ಚುವರಿ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ಮತ್ತು ನನ್ನ ಗಿಟ್ಹಬ್ ಸ್ಪನ್ಸರ್ಗಳ ಪ್ರೊಫೈಲ್ ತೆರೆಯಲು ಕೆಳಗಿನ ಬಟನ್ ಟ್ಯಾಪ್ ಮಾಡಿ.</string>
|
||||
<string name="upgrade_screen_status_free_title">ಉಚಿತ ಆವೃತ್ತಿ</string>
|
||||
<string name="upgrade_screen_status_free_body">ನೀವು ಸಿಎಪಿಪಾಡ್ನ ಉಚಿತ ಆವೃತ್ತಿಯನ್ನು ಬಳಸುತ್ತಿದ್ದೀರಿ. ಅಭಿವೃದ್ಧಿಯನ್ನು ಬೆಂಬಲಿಸುವ ಮೂಲಕ ಹೆಚ್ಚುವರಿ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಬಹುದು.</string>
|
||||
<string name="upgrade_screen_status_free_action">ನವೀಕರಣ ಆಯ್ಕೆಗಳನ್ನು ನೋಡಿ</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">ನವೀಕರಣ ಕ್ರಿಯಾಶೀಲ</string>
|
||||
<string name="upgrade_screen_recurring_title">ಅದನ್ನು ಮುಂದುವರಿಸಿ</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod ನವೀಕರಣ ಮತ್ತು ಸುಧಾರೆಗಳ ಮೂಲಕ ನಿರಂತರವಾಗಿ ಅಭಿವೃದ್ಧಿ ಆಗುತ್ತಿದೆ. ನೀವು ಇದನ್ನು ಮುಂದುವರಿಸಲು ಬಯಸಿದರೆ, GitHub Sponsors ಮೂಲಕ ನಿಯಮಿತ ದಾನವನ್ನು ಪರಿಗಣಿಸಿ.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">개발 후원하기</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">광고 없음. 추적 없음. Google Play 의존 없음.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">벌써 돌아가세요? 여러분의 지원이 CAPod를 유지합니다.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s부터 후원자</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod 개발을 후원해 주셔서 감사합니다!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">후원 페이지 열기</string>
|
||||
<string name="settings_upgrade_status_label">CAPod 후원하기</string>
|
||||
<string name="settings_upgrade_status_description">후원자 상태</string>
|
||||
<string name="upgrade_screen_why_title">업그레이드 혜택</string>
|
||||
<string name="upgrade_screen_how_title">도움 주기</string>
|
||||
<string name="upgrade_screen_how_body">후원자가 되어 개발을 지원하세요! 아래 버튼을 눌러 Github Sponsors 프로필을 열고 추가 기능을 잠금해제하세요.</string>
|
||||
<string name="upgrade_screen_status_free_title">무료 버전</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod의 무료 버전을 사용 중입니다. 개발을 지원하여 추가 기능을 잠금 해제할 수 있습니다.</string>
|
||||
<string name="upgrade_screen_status_free_action">업그레이드 옵션 보기</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">업그레이드 활성화됨</string>
|
||||
<string name="upgrade_screen_recurring_title">계속 지원하기</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod는 업데이트와 수정을 통해 계속 발전합니다. 이를 지속하고 싶다면 GitHub Sponsors를 통한 정기 기부를 고려해 주세요.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Иштелеп чыгууну колдоо</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Жарнама. Кадалоолоо жок. Google Playга байланма.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Артка кайттыңызбы? Сиздин колдооңуз CAPodты тирүү сактайт.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s\'дан бери колдоочу</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod\'дун өнүгүшүн колдогонуңуз үчүн рахмат!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Демөөрчүлүк баракчасын ачуу</string>
|
||||
<string name="settings_upgrade_status_label">CAPod-ды спонсорлоо</string>
|
||||
<string name="settings_upgrade_status_description">Колдоочу абалы</string>
|
||||
<string name="upgrade_screen_why_title">Жогорулоонун пайдалары</string>
|
||||
<string name="upgrade_screen_how_title">Жардам бергүүнүн жолу</string>
|
||||
<string name="upgrade_screen_how_body">Демеки болуп, иштөөсүнө спонсорлик кылыңыз! Бардык кошумча өзгөчөлүктөрдүн ишке кирүүсүнө жана GitHub Sponsors профилимди ачуу үчүн төмөндөгү баскычын басыңыз.</string>
|
||||
<string name="upgrade_screen_status_free_title">Акысыз версия</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod программасынын акысыз версиясын колдонуп жатасыз. Иштөөнүн өнүгүүсүнө спонсорлик кылсаңыз кошумча өзгөчөлүктөрдүн ишке кирүүсүн ачуп ала аласыз.</string>
|
||||
<string name="upgrade_screen_status_free_action">Жогорулоо вариантларын көрүңүз</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Жогорулоо активтүү</string>
|
||||
<string name="upgrade_screen_recurring_title">Улантуу</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod жаңыланууларды жана оңдуулар аркылуу өнүгүп турат. Эгерде сиз муну сактоону кааласаңыз, GitHub Sponsors аркылуу спонсорлук туурасында ойлонуңүз.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ສະໜັບສະໜູນການພັດທະນາ</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ບໍ່ມີໂຄສະນາ. ບໍ່ມີການຕິດຕາມ. ບໍ່ຕິດ Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ກັບມາແລ້ວ? ການສະໜັບສະໜູນຂອງທ່ານຮັກສາ CAPod ໃຫ້ດຳເນີນຕໍ່ໄປ.</string>
|
||||
<string name="upgrade_foss_supporter_since">ຜູ້ສະໜັບສະໜູນຕັ້ງແຕ່ %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">ຂອບຊູ່ສຳລັບການສະໜັບສະໜູນການພັດທະນາຂອງ CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">ເປິດໝ້າສະໜັບສະໜູນ</string>
|
||||
<string name="settings_upgrade_status_label">ສະໜັບສະໜູນ CAPod</string>
|
||||
<string name="settings_upgrade_status_description">ສະຖານະຜູ້ສະໜັບສະໜູນຂອງທ່ານ</string>
|
||||
<string name="upgrade_screen_why_title">ປະໂຫຍດຂອງການອັບເກຣດ</string>
|
||||
<string name="upgrade_screen_how_title">ວິທີການຊ່ວຍເຫຼືອ</string>
|
||||
<string name="upgrade_screen_how_body">ກາຍເປັນຜູ້ອຸປະຖໍາ ແລະ ໃຫ້ການສະໜັບສະໜູນການພັດທະນາ! ກົດປຸ່ມຂ້າງລຸ່ມເພື່ອເປີດໃຊ້ງານຄຸນສົມບັດເພີ່ມເຕີມທັງໝົດ ແລະ ເປີດໂປຣໄຟລ໌ GitHub Sponsors ຂອງຂ້ອຍ.</string>
|
||||
<string name="upgrade_screen_status_free_title">ເວີຊັນຟຣີ</string>
|
||||
<string name="upgrade_screen_status_free_body">ທ່ານກຳລັງໃຊ້ເວີຊັນຟຣີຂອງ CAPod. ຄຸນສົມບັດພິເສດສາມາດປົດລັອກໄດ້ໂດຍການສະຫນັບສະຫນູນການພັດທະນາ.</string>
|
||||
<string name="upgrade_screen_status_free_action">ເບິ່ງທາງເລືອກການອັບເກຣດ</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">ອັບເກຣດເປີດໃຊ້ງານ</string>
|
||||
<string name="upgrade_screen_recurring_title">ສືບຕໍ່ໃຫ້ໄປ</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod ສືບຕໍ່ວິວັດທະນາການຜ່ານການອັບເດດ ແລະການແກ້ໄຂ. ຖ້າທ່ານຕ້ອງການຮັກສາສະຖານະນັ້ນ, ກະລຸນາພິຈາລະນາການບໍລິຈາກປະຈຳຜ່ານ GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Remti plėtrą</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Jokių reklamų. Jokio sekimo. Jokio „Google Play“ priklausomybės.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Jau grįžte? Jūsų parama palaiko CAPod gyvybę.</string>
|
||||
<string name="upgrade_foss_supporter_since">Rėmėjas nuo %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Ačiū, kad remiate CAPod kūrimą!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Atidaryti rėmėjo puslapį</string>
|
||||
<string name="settings_upgrade_status_label">Remti CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Jūsų rėmėjo statusas.</string>
|
||||
<string name="upgrade_screen_why_title">Atnaujinimo privalumai</string>
|
||||
<string name="upgrade_screen_how_title">Kaip padėti</string>
|
||||
<string name="upgrade_screen_how_body">Tapkite globėju ir rėmėju plėtros! Palieskite žemiau esantį mygtuką, kad suaktyvintumėte visas papildomas funkcijas ir atidarytumėte mano GitHub Sponsors profilį.</string>
|
||||
<string name="upgrade_screen_status_free_title">Nemokama versija</string>
|
||||
<string name="upgrade_screen_status_free_body">Jūs naudojate nemokamą CAPod versiją. Papildomos funkcijos gali būti atblokuotos palaikant kūrimą.</string>
|
||||
<string name="upgrade_screen_status_free_action">Žiūrėti atnaujinimo galimybes</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Atnaujinimas aktyvus</string>
|
||||
<string name="upgrade_screen_recurring_title">Tęskime toliau</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod nuolat tobulėja per atnaujinimus ir pataisas. Jei norite tai palaikyti, apsvarstyti pasikartojančią donaciją per GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsorēt attīstību</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Bez reklamām. Bez izsekošanas. Bez Google Play saistībām.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Jau atpakaļ? Tavs atbalsts uztur CAPod esamību.</string>
|
||||
<string name="upgrade_foss_supporter_since">Atbalstītājs kopš %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Paldies, ka atbalsti CAPod izstrādi!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Atvērt sponsorēšanas lapu</string>
|
||||
<string name="settings_upgrade_status_label">Atbalstīt CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Jūsu atbalstītāja statuss.</string>
|
||||
<string name="upgrade_screen_why_title">Jaunināšanas priekšrocības</string>
|
||||
<string name="upgrade_screen_how_title">Kā palīdzēt</string>
|
||||
<string name="upgrade_screen_how_body">Kļūstiet par aizbildni un sponsorējiet attīstību! Pieskarieties pogas zemāk, lai aktivizētu visas papildu funkcijas un atvērtu manu GitHub Sponsors profilu.</string>
|
||||
<string name="upgrade_screen_status_free_title">Bezmaksas versija</string>
|
||||
<string name="upgrade_screen_status_free_body">Jūs izmantojat CAPod bezmaksas versiju. Papildu funkcijas var atbloķēt, atbalstot izstrādi.</string>
|
||||
<string name="upgrade_screen_status_free_action">Skatīt jaunināšanas opcijas</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Jaunināšana aktīva</string>
|
||||
<string name="upgrade_screen_recurring_title">Turpiniet atbalstu</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod nepārtraukti attīstās caur atjauninājumiem un labojumiem. Ja vēlaties to atbalstīt, izsveriet regulāru ziedojumu caur GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Спонзорирај развој</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без пратење. Без зависност од Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Веќе се вративте? Вашата поддршка го одржува CAPod жив.</string>
|
||||
<string name="upgrade_foss_supporter_since">Поддржувач од %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Ти благодариме што го поддржуваш развојот на CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Отвори ја страницата за спонзорство</string>
|
||||
<string name="settings_upgrade_status_label">Поддржи CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Твојот статус на поддржувач.</string>
|
||||
<string name="upgrade_screen_why_title">Предности на надградување</string>
|
||||
<string name="upgrade_screen_how_title">Како да помогнете</string>
|
||||
<string name="upgrade_screen_how_body">Станете покровител и спонзорирајте го развојот! Допрете го копчето подолу за да ги активирате сите дополнителни функции и да го отворите мојот GitHub Sponsors профил.</string>
|
||||
<string name="upgrade_screen_status_free_title">Бесплатна верзија</string>
|
||||
<string name="upgrade_screen_status_free_body">Користете ја бесплатната верзија на CAPod. Дополнителни функции може да ги отклучите со поддршка на развојот.</string>
|
||||
<string name="upgrade_screen_status_free_action">Видете опции за надградување</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Активна надградување</string>
|
||||
<string name="upgrade_screen_recurring_title">Подржи развој</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod постојано се развива преку ажурирања и поправки. Ако сакате да го поддржите тоа, размислувајте за повторена донација преку GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">വികസനം സ്പോൺസർ ചെയ്യുക</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">പരസ്യങ്ങൾ ഇല്ല. ട്രാക്കിംഗ് ഇല്ല. Google Play ലോക്ക്-ഇൻ ഇല്ല.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ഇത്ര പെട്ടെന്ന് തിരിച്ചു പോകുന്നോ? നിങ്ങളുടെ പിന്തുണ CAPod നിലനിർത്തുന്നു.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s മുതൽ പിന്തുണക്കാൻ</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod-ന്റെ വികസനത്തെ പിന്തുണച്ചതിന് നന്ദി!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">സ്പോൺസർ പേജ് തുറക്കുക</string>
|
||||
<string name="settings_upgrade_status_label">CAPod നെ സ്പോൺസർ ചെയ്യുക</string>
|
||||
<string name="settings_upgrade_status_description">നിങ്ങളുടെ പിന്തുണയ സ്ഥിതി.</string>
|
||||
<string name="upgrade_screen_why_title">അപ്ഗ്രേഡ് നേട്ടങ്ങൾ</string>
|
||||
<string name="upgrade_screen_how_title">എങ്ങനെ സഹായിക്കാം</string>
|
||||
<string name="upgrade_screen_how_body">പാട്രോൺ ആകുകയും വികസനം സ്പോൺസർ ചെയ്യുകയും ചെയ്യുക! എല്ലാ അധിക സവിശേഷതകളും സജീവമാക്കാനും എന്റെ GitHub Sponsors പ്രൊഫൈൽ തുറക്കാനും താഴെയുള്ള ബട്ടൺ ടാപ്പ് ചെയ്യുക.</string>
|
||||
<string name="upgrade_screen_status_free_title">സൗജന്യ പതിപ്പ്</string>
|
||||
<string name="upgrade_screen_status_free_body">നിങ്ങൾ CAPod-ന്റെ സൗജന്യ പതിപ്പ് ഉപയോഗിക്കുന്നു. വികസനത്തെ പിന്തുണയ്ക്കുന്നതിലൂടെ അതിരിക്ത ഫീച്ചറുകൾ അൻലോക്ക് ചെയ്യാൻ കഴിയും.</string>
|
||||
<string name="upgrade_screen_status_free_action">അപ്ഗ്രേഡ് ഓപ്ഷനുകൾ നോക്കുക</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">അപ്ഗ്രേഡ് സജീവമാണ്</string>
|
||||
<string name="upgrade_screen_recurring_title">ഇത് തുടരുക</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod അപ്ഡേറ്റുകളിലൂടെയും പരിഷ്കാരങ്ങളിലൂടെയും വികസിച്ചുകൊണ്ടിരിക്കുന്നു. നിങ്ങൾ അത് നിലനിർത്താൻ ആഗ്രഹിക്കുന്നുണ്ടെങ്കിൽ, GitHub സ്പോണ്സറുകൾ മുഖേന ആവർത്തിച്ച് ദാനം നൽകാൻ പരിഗണിക്കുക.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Хөгжлийг дэмжих</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Реклам байхгүй. Хяналт байхгүй. Google Play-д хамааралгүй.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Аль хэдэйн буцаж ирлээ? Таны дэмжлэг CAPod-ийг амьд байлгадаг.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s-с хойш дэмжигч</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod-ын хөгжлийг дэмжсэнд баярлалаа!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Дэмжигчийн хуудсыг нээх</string>
|
||||
<string name="settings_upgrade_status_label">CAPod-ыг спонсорлох</string>
|
||||
<string name="settings_upgrade_status_description">Таны дэмжигч статус.</string>
|
||||
<string name="upgrade_screen_why_title">Давуу талууд</string>
|
||||
<string name="upgrade_screen_how_title">Хэрхэн тусламж үзүүлэх</string>
|
||||
<string name="upgrade_screen_how_body">Ивээн тэтгэгч болж хөгжлийг дэмжээрэй! Бүх нэмэлт боломжуудыг идэвхжүүлж, миний GitHub Sponsors профайлыг нээхийн тулд доорх товчийг дарна уу.</string>
|
||||
<string name="upgrade_screen_status_free_title">Үнэгүй хувилбар</string>
|
||||
<string name="upgrade_screen_status_free_body">Та CAPod-ын үнэгүй хувилбарыг ашиглаж байна. Хөгжлийг дэмжих замаар нэмэлт функцийг нээх боломжтой.</string>
|
||||
<string name="upgrade_screen_status_free_action">Сонголтыг харах</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Идэвхтэй</string>
|
||||
<string name="upgrade_screen_recurring_title">Үргэлжүүлэх</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod шинэчлэлт, засварын тусламжтайгаар үргэлжлэн хөгжиж байна. Үүнийг дэмжихийг хүссэн бол GitHub Sponsors-ээр давтан төлбөрийн хандив хийхийг авч үзэхэй.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">विकासास प्रायोजित करा</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">कोणत्याही जाहिराती नाहीत. कोणतेही ट्रॅकिंग नाही. Google Play चे बंधन नाही.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">आधीच परत? तुमचा पाठिंबा CAPod जिवंत ठेवतो.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s पासून समर्थक</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod च्या विकासाला पाठिंबा दिल्याबद्दल धन्यवाद!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ उघडा</string>
|
||||
<string name="settings_upgrade_status_label">CAPod ला प्रायोजित करा</string>
|
||||
<string name="settings_upgrade_status_description">आपल्या समर्थक स्थिती.</string>
|
||||
<string name="upgrade_screen_why_title">अपग्रेड लाभ</string>
|
||||
<string name="upgrade_screen_how_title">मदत कसे करायची</string>
|
||||
<string name="upgrade_screen_how_body">संरक्षक बनून विकास प्रायोजित करा! सर्व अतिरिक्त वैशिष्ट्ये सक्रिय करण्यासाठी आणि माझे GitHub Sponsors प्रोफाइल उघडण्यासाठी खाली दिलेल्या बटणावर टॅप करा.</string>
|
||||
<string name="upgrade_screen_status_free_title">विनामूल्य आवृत्ती</string>
|
||||
<string name="upgrade_screen_status_free_body">आप CAPod चे विनामूल्य आवृत्ती वापरत आहात. विकासाला समर्थन देऊन अतिरिक्त वैशिष्ट्ये अनलॉक केली जाऊ शकतात.</string>
|
||||
<string name="upgrade_screen_status_free_action">अपग्रेड पर्याय पहा</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">अपग्रेड सक्रिय</string>
|
||||
<string name="upgrade_screen_recurring_title">चालू ठेवा</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod अद्यतने आणि दुरुस्त्यांद्वारे विकसित होत राहते. जर आपल्याला तेच टिकवून ठेवायचे असेल तर GitHub Sponsors द्वारे आवर्ती दान विचारात घ्या.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Pembangunan penaja</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Tiada iklan. Tiada penjejakan. Tiada ikatan Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Sudah kembali? Sokongan anda mengekalkan CAPod.</string>
|
||||
<string name="upgrade_foss_supporter_since">Penyokong sejak %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Terima kasih kerana menyokong pembangunan CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Buka halaman penaja</string>
|
||||
<string name="settings_upgrade_status_label">Menajakan CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Status penyokong anda.</string>
|
||||
<string name="upgrade_screen_why_title">Manfaat peningkatan</string>
|
||||
<string name="upgrade_screen_how_title">Bagaimana untuk membantu</string>
|
||||
<string name="upgrade_screen_how_body">Menjadi penaung dan penaja pembangunan! Ketik butang di bawah untuk mengaktifkan semua ciri tambahan dan buka profil Penaja GitHub saya.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versi percuma</string>
|
||||
<string name="upgrade_screen_status_free_body">Anda menggunakan versi percuma CAPod. Ciri-ciri tambahan boleh dibuka kunci dengan menyokong pembangunan.</string>
|
||||
<string name="upgrade_screen_status_free_action">Lihat pilihan peningkatan</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Peningkatan aktif</string>
|
||||
<string name="upgrade_screen_recurring_title">Teruskan</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod terus berkembang melalui kemas kini dan pembetulan. Jika anda ingin menopang itu, pertimbangkan sumbangan berulang melalui GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ဖွံ့ဖြိုးတိုးတက်မှုကို ကမကထပံ့ပိုးရန်</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ကြောင်ညာမရှိ။ ခြေရာမခံ။ Google Play ချုပ်ချယ်မြုမရှိ။</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ပြန်သွားပြီးလါ? သင်၏ ပံ့ပိုးမှု CAPod ကို ရှင်သန်ဆက်လက်ကေစေသည်။</string>
|
||||
<string name="upgrade_foss_supporter_since">%s မှစ၍ ပံ့ပိုးသူ</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod ၏ ဖွံ့ဖြိုးတိုးတက်မှုကို ပံ့ပိုးပေးသည့်အတွက် ကျေးဇူးတင်ပါသည်!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">ပံ့ပိုးသူစာမျက်နှာကို ဖွင့်ပါ</string>
|
||||
<string name="settings_upgrade_status_label">CAPod ကို ပံ့ပိုးပါ</string>
|
||||
<string name="settings_upgrade_status_description">သင်၏ ပံ့ပိုးသူ အခြေအနေ။</string>
|
||||
<string name="upgrade_screen_why_title">အဆင့်မြှင့်တင်မှု အကျိုးအကျေးမများ</string>
|
||||
<string name="upgrade_screen_how_title">ကူညီနည်းလမ်း</string>
|
||||
<string name="upgrade_screen_how_body">ကူညီသူဖြစ်ပြီး ဖွံ့ဖြိုးတိုးတက်မှုကို ကမကထပံ့ပိုးပါ! အပိုဝန်ဆောင်မှုများအားလုံးကို ဖွင့်ပြီး ကျွန်ုပ်၏ GitHub Sponsors ပရိုဖိုင်းကို ဖွင့်ရန် အောက်ပါခလုတ်ကို နှိပ်ပါ။</string>
|
||||
<string name="upgrade_screen_status_free_title">အခမဲ့ ဗားရှင်း</string>
|
||||
<string name="upgrade_screen_status_free_body">သင် CAPod ၏ အခမဲ့ ဗားရှင်း ကို အသုံးပြုနေသည်။ ဖွံ့ဖြိုးတိုးတက်မှုကို ပံ့ပိုးခြင်းအားဖြင့် ထပ်ဆောင်း လုပ်ဆောင်ချက်များ အသုံးပြုခွင့်ရှိနိုင်သည်။</string>
|
||||
<string name="upgrade_screen_status_free_action">အဆင့်မြှင့်တင်မှု ရွေးချယ်စရာများ ကြည့်ပါ</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">အဆင့်မြှင့်တင်မှု ကျင်လည်နေသည်</string>
|
||||
<string name="upgrade_screen_recurring_title">ဆက်လက်စွာ ပံ့ပိုးပါ</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod သည် အဆင့်မြှင့်တင်မှု နှင့် ပြုပြင်ဖြေရှင်းမှုများ မှတစ်ဆင့် ဆက်လက်စွာ ကောင်းမွန်လာသည်။ ထိုကဲ့သို့ ကျေးဇူးတင်သည့်အတွက် GitHub Sponsors မှ ပုံမှန် လှူဒါန်းမှုကို စဉ်းစားကြည့်ပါ။</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Støtt utviklingen</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Ingen reklame. Ingen sporing. Ingen Google Play-avhengighet.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Allerede tilbake? Din støtte holder CAPod i live.</string>
|
||||
<string name="upgrade_foss_supporter_since">Støttespiller siden %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Takk for at du støtter utviklingen av CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Åpne sponsorside</string>
|
||||
<string name="settings_upgrade_status_label">Støtt CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Din status som støtter.</string>
|
||||
<string name="upgrade_screen_why_title">Oppgraderingsfordeler</string>
|
||||
<string name="upgrade_screen_how_title">Hvordan hjelpe</string>
|
||||
<string name="upgrade_screen_how_body">Bli en patron og støtt utviklingen! Trykk på knappen under for å aktivere alle ekstra funksjoner og åpne sponsorprofilen min på GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Gratis versjon</string>
|
||||
<string name="upgrade_screen_status_free_body">Du bruker den gratis versjonen av CAPod. Ekstra funksjoner kan låses opp ved å støtte utviklingen.</string>
|
||||
<string name="upgrade_screen_status_free_action">Se oppgraderingsalternativene</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Oppgradering aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Hold det gående</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod fortsetter å utvikle seg gjennom oppdateringer og rettinger. Hvis du vil opprettholde det, kan du vurdere en gjentakende donasjon via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">विकासलाई प्रायोजन गर्नुहोस्</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">कुनै विज्ञापन छैन। कुनै ट्रैकिङ छैन। Google Playमा बाँधिएको छैन।</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">पहिले नै फिर्नुभयो? तपाईंको सहयोगले CAPod जीवित राख्छ।</string>
|
||||
<string name="upgrade_foss_supporter_since">%s देखि समर्थक</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod को विकासलाई समर्थन गर्नुभएकोमा धन्यवाद!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">प्रायोजक पृष्ठ खोल्नुहोस्</string>
|
||||
<string name="settings_upgrade_status_label">CAPod को प्रायोजन गर्नुहोस्</string>
|
||||
<string name="settings_upgrade_status_description">आफ्नो समर्थक स्थिति।</string>
|
||||
<string name="upgrade_screen_why_title">अपग्रेड लाभहरु</string>
|
||||
<string name="upgrade_screen_how_title">कसरी मद्दत गर्ने</string>
|
||||
<string name="upgrade_screen_how_body">संरक्षक बन्नुहोस् र विकासलाई प्रायोजन गर्नुहोस्! सबै अतिरिक्त सुविधाहरू सक्रिय पार्न र मेरो GitHub Sponsors प्रोफाइल खोल्न तलको बटन ट्याप गर्नुहोस्।</string>
|
||||
<string name="upgrade_screen_status_free_title">निःशुल्क संस्करण</string>
|
||||
<string name="upgrade_screen_status_free_body">तपाईं CAPod को निःशुल्क संस्करण प्रयोग गरिरहनुभएको छ। विकास समर्थन गरेर अतिरिक्त सुविधा अनलक गर्न सकिन्छ।</string>
|
||||
<string name="upgrade_screen_status_free_action">अपग्रेड विकल्पहरु हेर्नुहोस्</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">अपग्रेड सक्रिय छ</string>
|
||||
<string name="upgrade_screen_recurring_title">यो जारी राख्नुहोस्</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod अद्यावधिक र सुधार मार्फत विकसित भइरहेको छ। यदि तपाई यो जारी राख्न चाहनुहुन्छ भने, GitHub Sponsors मार्फत आवर्ती दान विचार गर्नुहोस्।</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsor ontwikkeling</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Geen advertenties. Geen tracking. Geen Google Play-vergrendeling.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Alweer terug? Jouw steun houdt CAPod in leven.</string>
|
||||
<string name="upgrade_foss_supporter_since">Supporter sinds %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Bedankt voor je steun aan de ontwikkeling van CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Open de sponsorpagina</string>
|
||||
<string name="settings_upgrade_status_label">Sponsor CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Je ondersteunersstatus.</string>
|
||||
<string name="upgrade_screen_why_title">Voordelen van de upgrade</string>
|
||||
<string name="upgrade_screen_how_title">Hoe kun je helpen</string>
|
||||
<string name="upgrade_screen_how_body">Word mecenas en sponsor ontwikkelaar! Tik op de onderstaande knop om alle extra functies te activeren en mijn GitHub Sponsors-profiel te openen.</string>
|
||||
<string name="upgrade_screen_status_free_title">Gratis versie</string>
|
||||
<string name="upgrade_screen_status_free_body">Je gebruikt de gratis versie van CAPod. Extra functies kunnen worden ontgrendeld door de ontwikkeling te ondersteunen.</string>
|
||||
<string name="upgrade_screen_status_free_action">Bekijk upgrade-opties</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade actief</string>
|
||||
<string name="upgrade_screen_recurring_title">Ga zo door</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod blijft zich ontwikkelen door middel van updates en bugfixes. Als je dit wilt blijven ondersteunen, kun je overwegen om een terugkerende donatie te doen via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -3,22 +3,9 @@
|
||||
<string name="foss_upgrade_donate_label">Wesprzyj</string>
|
||||
<string name="foss_upgrade_alreadydonated_label">Już wsparłem</string>
|
||||
<string name="foss_upgrade_no_money_label">Wydałem wszystkie pieniądze na AirPods</string>
|
||||
<string name="upgrade_foss_preamble">CAPod Foss jest bezpłatny i otwarto-źródłowy. Jeśli uważasz go za użyteczny, rozważ sponsorowanie rozwoju, aby pomóc kontynuować projekt.</string>
|
||||
<string name="upgrade_foss_preamble">CAPod FOSS jest bezpłatny i otwartoźródłowy. Jeśli uważasz go za użyteczny, rozważ sponsorowanie rozwoju, aby pomóc kontynuować projekt.</string>
|
||||
<string name="upgrade_foss_sponsor_action">Wesprzyj rozwój</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Bez reklam. Bez śledzenia. Bez uzależnienia od Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Już wróciłeś? Twoje wsparcie utrzymuje CAPod przy życiu.</string>
|
||||
<string name="upgrade_foss_supporter_since">Wspierający od %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Dziękuję za wsparcie rozwoju CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Otwórz stronę wspierającego</string>
|
||||
<string name="settings_upgrade_status_label">Sponsoruj CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Status twojego wsparcia.</string>
|
||||
<string name="upgrade_screen_why_title">Korzyści z uaktualnienia</string>
|
||||
<string name="upgrade_screen_how_title">Jak pomóc</string>
|
||||
<string name="upgrade_screen_how_body">Zostań patronem i wspieraj rozwój! Dotknij przycisku poniżej, aby aktywować wszystkie dodatkowe funkcje i otworzyć mój profil GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Wersja darmowa</string>
|
||||
<string name="upgrade_screen_status_free_body">Korzystasz z bezpłatnej wersji CAPod. Dodatkowe funkcje można odblokować poprzez wsparcie programisty.</string>
|
||||
<string name="upgrade_screen_status_free_action">Zobacz opcje aktualizacji</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Aktualizacja aktywna</string>
|
||||
<string name="upgrade_screen_recurring_title">Wspieraj dalej</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod stale się rozwija dzięki aktualizacjom i poprawkom. Jeśli chcesz go wspierać, rozważ cykliczną darowiznę za pośrednictwem GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocinador do desenvolvimento</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Já voltou? Seu apoio mantém o CAPod vivo.</string>
|
||||
<string name="upgrade_foss_supporter_since">Apoiador desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiar o desenvolvimento do CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
||||
<string name="settings_upgrade_status_label">Patrocine o CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Seu status de apoiador.</string>
|
||||
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
||||
<string name="upgrade_screen_how_title">Como ajudar</string>
|
||||
<string name="upgrade_screen_how_body">Torne-se um patrocinador e financie o desenvolvimento! Clique no botão abaixo para ativar todos os recursos extras e abrir meu perfil Github Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versão gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Você está usando a versão gratuita do CAPod. Recursos extras podem ser desbloqueados apoiando o desenvolvimento.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opções de atualização</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Atualização ativa</string>
|
||||
<string name="upgrade_screen_recurring_title">Mantenha assim</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continua evoluindo com atualizações e correções. Se você quiser sustentá-lo, considere fazer uma doação recorrente via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Patrocine o desenvolvimento</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Sem anúncios. Sem rastreamento. Sem dependência do Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Já está a sair? O seu apoio mantém o CAPod ativo.</string>
|
||||
<string name="upgrade_foss_supporter_since">Apoiante desde %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Obrigado por apoiares o desenvolvimento do CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Abrir página de patrocínio</string>
|
||||
<string name="settings_upgrade_status_label">Apoie o CAPod</string>
|
||||
<string name="settings_upgrade_status_description">O seu estado de apoiante.</string>
|
||||
<string name="upgrade_screen_why_title">Benefícios da atualização</string>
|
||||
<string name="upgrade_screen_how_title">Como ajudar</string>
|
||||
<string name="upgrade_screen_how_body">Torne-se patrono e apoie o desenvolvimento! Toque no botão abaixo para ativar todas as funcionalidades adicionais e abrir o meu perfil no GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versão gratuita</string>
|
||||
<string name="upgrade_screen_status_free_body">Você está usando a versão gratuita do CAPod. Recursos extras podem ser desbloqueados ao apoiar o desenvolvimento.</string>
|
||||
<string name="upgrade_screen_status_free_action">Ver opções de atualização</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Atualização ativa</string>
|
||||
<string name="upgrade_screen_recurring_title">Continue a apoiar</string>
|
||||
<string name="upgrade_screen_recurring_body">O CAPod continua evoluindo por meio de atualizações e correções. Se você quiser ajudar a manter isso, considere fazer uma doação recorrente pelo GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsurisar il sviluppament</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Nagins annunzis. Nagin tracking. Nagin blocadi da Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Gia enavos? Tes sustegn mantegn CAPod viv.</string>
|
||||
<string name="upgrade_foss_supporter_since">Sustegnider dapi %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Grazia per sustegnair il svilup da CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Avrir la pagina da sponsurisaziun</string>
|
||||
<string name="settings_upgrade_status_label">Sponsurar CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Tes status da supporter.</string>
|
||||
<string name="upgrade_screen_why_title">Bials da l\'upgrade</string>
|
||||
<string name="upgrade_screen_how_title">Sco gidar</string>
|
||||
<string name="upgrade_screen_how_body">Vign patrun e sustegna l\'svilup! Tucha il buttun sut per activar tut las funcziuns extrasas e per avrir miu profil da GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versiun gratuitusa</string>
|
||||
<string name="upgrade_screen_status_free_body">Tu utilizzas la versiun gratuitusa da CAPod. Funcziuns extrasas pon vegnir deblochadas cun sustegnair l\'svilup.</string>
|
||||
<string name="upgrade_screen_status_free_action">Vesair las opcziuns da upgrade</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade activà</string>
|
||||
<string name="upgrade_screen_recurring_title">Mantegnair d\'en viva</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continua a sa sviluppar tras actualizaziuns e reparas. Sche ti vuls sustegnair quai, cunsiglia ina donazziun ricorrent via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsorizează dezvoltarea</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Fara reclame. Fara urmarire. Fara dependenta de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Ati revenit deja? Sprijinul dvs. mentine CAPod in viata.</string>
|
||||
<string name="upgrade_foss_supporter_since">Susținător din %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Mulțumim că sprijini dezvoltarea CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Deschide pagina de sponsorizare</string>
|
||||
<string name="settings_upgrade_status_label">Sponsorizează CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Statusul tău de susținător.</string>
|
||||
<string name="upgrade_screen_why_title">Beneficiile upgrade-ului</string>
|
||||
<string name="upgrade_screen_how_title">Cum să ajuți</string>
|
||||
<string name="upgrade_screen_how_body">Devino susținător și sponsorizează dezvoltarea! Apasă butonul de mai jos pentru a activa toate funcțiile suplimentare și a deschide profilul meu GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versiune gratuită</string>
|
||||
<string name="upgrade_screen_status_free_body">Folosești versiunea gratuită a CAPod. Poți debloca funcții suplimentare susținând dezvoltarea.</string>
|
||||
<string name="upgrade_screen_status_free_action">Vezi opțiunile de upgrade</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade activ</string>
|
||||
<string name="upgrade_screen_recurring_title">Ține-o în viață</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod continuă să evolueze prin actualizări și corecturi. Dacă ai dori să susții asta, ia în considerare o donație recurentă prin GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Поддержать разработку</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Без рекламы. Без слежки. Без привязки к Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Вернулись? Ваша поддержка помогает CAPod жить.</string>
|
||||
<string name="upgrade_foss_supporter_since">Спонсор с %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Спасибо за поддержку разработки CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Открыть страницу спонсорства</string>
|
||||
<string name="settings_upgrade_status_label">Поддержать CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Статус Вашей поддержки.</string>
|
||||
<string name="upgrade_screen_why_title">Преимущества обновления</string>
|
||||
<string name="upgrade_screen_how_title">Как помочь</string>
|
||||
<string name="upgrade_screen_how_body">Станьте спонсором и поддержите разработку! Нажмите кнопку ниже, чтобы активировать все дополнительные функции и открыть мой профиль GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Бесплатная версия</string>
|
||||
<string name="upgrade_screen_status_free_body">Вы используете бесплатную версию CAPod. Дополнительные функции можно разблокировать, поддерживая разработку.</string>
|
||||
<string name="upgrade_screen_status_free_action">Посмотреть варианты обновления</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Обновление активно</string>
|
||||
<string name="upgrade_screen_recurring_title">Поддержите развитие</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod продолжает развиваться через обновления и исправления. Если Вы хотите осуществить поддержку, рассмотрите возможность периодического пожертвования через спонсоров GitHub.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsoriza s\'isvilupu</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Peroe publicidade. Peroe trachiamentu. Peroe dipendentzia de Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Zas torradas giai? Su sostegnu tuyu mantenet CAPod in vida.</string>
|
||||
<string name="upgrade_foss_supporter_since">Sustentadore dae su %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Gràtzias pro sustènnere s\'isvilupu de CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Aberi sa pàgina de sponsorizatzione</string>
|
||||
<string name="settings_upgrade_status_label">Sostene CAPod</string>
|
||||
<string name="settings_upgrade_status_description">S\'istadu tuo de sustentadore.</string>
|
||||
<string name="upgrade_screen_why_title">Benefitzios de s\'agiornamentu</string>
|
||||
<string name="upgrade_screen_how_title">Comente agiudare</string>
|
||||
<string name="upgrade_screen_how_body">Diventa patronu e sponsoriza s\'isvilupu! Tocca su butone in bassu pro ativare totu sas funtzionalidades addizionales e abèrrere su profilu meu de GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versione lìbera</string>
|
||||
<string name="upgrade_screen_status_free_body">Tù ses usende sa versione lìbera de CAPod. Benefitzios extras podent esse desblocados si supportas su sviluppu.</string>
|
||||
<string name="upgrade_screen_status_free_action">Bide sas optziones de agiornamentu</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Agiornamentu attivu</string>
|
||||
<string name="upgrade_screen_recurring_title">Fide an\'abantis</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod cuntìnua a evolutionare cun agiornamentos e corretziones. Si tù bolis mantenere custu, pentziona a una donatzione reciclica pro via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">සංවර්ධනයට අනුග්රහය දෙන්න</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">අළු නැත. ට්රැකිං නැත. Google Play සලකත්වය නැත.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">එක්බේන්මට පළ්ට? ඔබ෪් සහය් CAPod ක්රියාත්මකව තබා ගෙනයි.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s සිට අනුග්රාහකයෙකි</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod හි සංවර්ධනයට සහාය දැක්වූ ඔබට ස්තූතියි!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">අනුග්රාහක පිටුව විවෘත කරන්න</string>
|
||||
<string name="settings_upgrade_status_label">CAPod සඳහා අනුග්රහක්</string>
|
||||
<string name="settings_upgrade_status_description">ඔබේ සහයෝගිතා තත්වය.</string>
|
||||
<string name="upgrade_screen_why_title">උඩ්ග්රේඩ් ප්රතිලාභ</string>
|
||||
<string name="upgrade_screen_how_title">උදව් කරන්නේ කෙසේද</string>
|
||||
<string name="upgrade_screen_how_body">අනුග්රාහකයෙකු වී සංවර්ධනයට අනුග්රහ කරන්න! සියලු අමතර විශේෂාංග සක්රිය කර මගේ GitHub Sponsors පැතිකඩ විවෘත කිරීමට පහත බොත්තම ස්පර්ශ කරන්න.</string>
|
||||
<string name="upgrade_screen_status_free_title">නිදහස් සංස්කරණය</string>
|
||||
<string name="upgrade_screen_status_free_body">ඔබ CAPod හි නිදහස් සංස්කරණය භාවිතා කරමින් පවතී. අතිරේක විශේෂාංග සංවර්ධනයට සහයෝගය දීමෙන් අඩුවිය හැක.</string>
|
||||
<string name="upgrade_screen_status_free_action">උඩ්ග්රේඩ් විකල්ප බලන්න</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">උඩ්ග්රේඩ් සක්රිය</string>
|
||||
<string name="upgrade_screen_recurring_title">එයින් දිගටම</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod දිගටම සංවර්ධනය වෙමින් පවතී යාවත්කාලීනයන් සහ නිවැරදි කිරීම් මගින්. ඔබ එය පවතින්නට කිරීමට අවශ්ය නම්, GitHub Sponsors හරහා පුනරාවර්තක පරිත්යාගයක් සලකා බලන්න.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponzorovaný vývoj</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Žiadne reklamy. Žiadne sledovanie. Žiadna závislosť od Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Už späť? Vaša podpora udržiava CAPod pri živote.</string>
|
||||
<string name="upgrade_foss_supporter_since">Podporovateľ od %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Ďakujeme, že podporujete vývoj CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Otvoriť stránku sponzorstva</string>
|
||||
<string name="settings_upgrade_status_label">Podporiť CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Váš status podporovateľa.</string>
|
||||
<string name="upgrade_screen_why_title">Výhody upgradu</string>
|
||||
<string name="upgrade_screen_how_title">Ako pomôcť</string>
|
||||
<string name="upgrade_screen_how_body">Staňte sa patrónom a sponzorujte rozvoj! Klepnutím na tlačidlo nižšie aktivujete všetky ďalšie funkcie a otvoríte môj profil sponzorov GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Bezplatná verzia</string>
|
||||
<string name="upgrade_screen_status_free_body">Používate bezplatnú verziu aplikácie CAPod. Dodatočné funkcie je možné odomknúť podporou vývoja.</string>
|
||||
<string name="upgrade_screen_status_free_action">Zobraziť možnosti upgradu</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Upgrade aktívny</string>
|
||||
<string name="upgrade_screen_recurring_title">Pokračuj ďalej</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod sa neustále vyvíja prostredníctvom aktualizácií a oprav. Ak chcete to podporiť, zvážte si opakujúcu sa donáciu prostredníctvom GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Podpri razvoj</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Brez oglasov. Brez sledenja. Brez vezave na Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Že nazaj? Vaša podpora ohranja CAPod pri življenju.</string>
|
||||
<string name="upgrade_foss_supporter_since">Podpornik od %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Hvala, ker podpirate razvoj CAPod-a!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Odpri stran za sponzorstvo</string>
|
||||
<string name="settings_upgrade_status_label">Podpri CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Tvoj status podpornika.</string>
|
||||
<string name="upgrade_screen_why_title">Prednosti nadgradnje</string>
|
||||
<string name="upgrade_screen_how_title">Kako pomagati.</string>
|
||||
<string name="upgrade_screen_how_body">Postanite pokrovitelj in prispevajte k razvoju! Dotaknite se spodnjega gumba, da omogočite dodatne funkcije in odprete moj pokroviteljski profil na GitHubu.</string>
|
||||
<string name="upgrade_screen_status_free_title">Brezplačna različica</string>
|
||||
<string name="upgrade_screen_status_free_body">Uporabljate brezplačno različico CAPoda. Dodatne funkcionalnosti se odklenejo s podporo razvoju.</string>
|
||||
<string name="upgrade_screen_status_free_action">Prikaži možnosti nadgradnje</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Nadgradnja je aktivna</string>
|
||||
<string name="upgrade_screen_recurring_title">Nadaljuj s tem</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod se stalno razvija z posodobitvami in popravki. Če želite to podpreti, razmislite o ponavljajočem se prispevku prek GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Zhvillimi i sponsorëve</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Pa reklama. Pa gjurmim. Pa varësi nga Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Ktheheni tashmjë? Mbështjetja juaj e mban CAPod gjallë.</string>
|
||||
<string name="upgrade_foss_supporter_since">Mbështetës që nga %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Faleminderit për mbështetjen e zhvillimit të CAPod-it!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Hap faqen e sponsorizimit</string>
|
||||
<string name="settings_upgrade_status_label">Mbështesni CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Statusi juaj si mbështetës.</string>
|
||||
<string name="upgrade_screen_why_title">Përfitime të përmirësimit</string>
|
||||
<string name="upgrade_screen_how_title">Si të ndihmoj</string>
|
||||
<string name="upgrade_screen_how_body">Bëhuni një mbrojtës dhe sponsor i zhvillimit! Prekni butonin më poshtë për të aktivizuar të gjitha veçoritë shtesë dhe për të hapur profilin tim të sponsorëve të GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Versioni falas</string>
|
||||
<string name="upgrade_screen_status_free_body">Jeni duke përdorur versionin falas të CAPod. Veçoritë shtesë mund të aktivizohen duke mbështetur zhvillimin.</string>
|
||||
<string name="upgrade_screen_status_free_action">Shikoni opsionet e përmirësimit</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Përmirësimi aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Mbajeni të vazhdueshme</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod vazhdon të zhvillohet përmes përditësimeve dhe përmirësimesh. Nëse dëshironi ta mbështetin atë, shqyrtoni një donacion të përsëritur përmes GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Спонзориши развој</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Без реклама. Без праћења. Без зависности од Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Већ одлазите? Ваша подршка чува CAPod живим.</string>
|
||||
<string name="upgrade_foss_supporter_since">Подржавалац од %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Хвала вам што подржавате развој CAPod-а!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Отворите страницу за спонзорство</string>
|
||||
<string name="settings_upgrade_status_label">Подржите CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Статус вашег подржавања.</string>
|
||||
<string name="upgrade_screen_why_title">Предности надградње</string>
|
||||
<string name="upgrade_screen_how_title">Како помоћи</string>
|
||||
<string name="upgrade_screen_how_body">Постаните покровитељ и спонзоришите развој! Додирните дугме испод да активирате све додатне функције и отворите мој GitHub Sponsors профил.</string>
|
||||
<string name="upgrade_screen_status_free_title">Бесплатна верзија</string>
|
||||
<string name="upgrade_screen_status_free_body">Користите бесплатну верзију CAPod. Додатне функције можете откључати подржавањем развоја.</string>
|
||||
<string name="upgrade_screen_status_free_action">Погледајте опције надградње</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Надградња је активна</string>
|
||||
<string name="upgrade_screen_recurring_title">Подржите развој</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod се наставља развијати кроз ажурирања и исправке. Ако желите да то подржите, размотрите редовну донацију преко GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Sponsra utvecklingen</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Inga annonser. Ingen spårning. Ingen bindning till Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Redan tillbaka? Ditt stöd håller CAPod vid liv.</string>
|
||||
<string name="upgrade_foss_supporter_since">Supporter sedan %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Tack för att du stödjer utvecklingen av CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Öppna sponsorsidan</string>
|
||||
<string name="settings_upgrade_status_label">Sponsra CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Din supporterstatus.</string>
|
||||
<string name="upgrade_screen_why_title">Uppgraderingsfördelar</string>
|
||||
<string name="upgrade_screen_how_title">Hur du kan hjälpa</string>
|
||||
<string name="upgrade_screen_how_body">Bli en beskyddare och sponsra utvecklingen! Tryck på knappen nedan för att aktivera alla extra funktioner och öppna min GitHub Sponsors-profil.</string>
|
||||
<string name="upgrade_screen_status_free_title">Gratis version</string>
|
||||
<string name="upgrade_screen_status_free_body">Du använder den kostnadsfria versionen av CAPod. Extrafunktioner kan låsas upp genom att stödja utvecklingen.</string>
|
||||
<string name="upgrade_screen_status_free_action">Se uppgraderingsalternativ</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Uppgradering aktiv</string>
|
||||
<string name="upgrade_screen_recurring_title">Håll det igång</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod utvecklas ständigt genom uppdateringar och felkorrigeringar. Om du vill stödja det, överväg en återkommande donation via GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Faidhi maendeleo</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Hakuna matangazo. Hakuna ufuatiliaji. Hakuna kufungwa kwa Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Unarudi tayari? Msaada wako unaweka CAPod iwe hai.</string>
|
||||
<string name="upgrade_foss_supporter_since">Msaidizi tangu %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Asante kwa kuunga mkono maendeleo ya CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Fungua ukurasa wa udhamini</string>
|
||||
<string name="settings_upgrade_status_label">Kuunga mkono CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Hali yako ya kuunga mkono.</string>
|
||||
<string name="upgrade_screen_why_title">Faida za kuboreshwa</string>
|
||||
<string name="upgrade_screen_how_title">Jinsi ya kusaidia</string>
|
||||
<string name="upgrade_screen_how_body">Kuwa mfumo na mfadhili wa maendeleo! Gusa kitufe kilicho hapa chini ili kuwezesha vipengele vyote vya ziada na kufungua wasifu wangu wa GitHub Sponsors.</string>
|
||||
<string name="upgrade_screen_status_free_title">Toleo la bure</string>
|
||||
<string name="upgrade_screen_status_free_body">Unatumia toleo la bure la CAPod. Huduma za ziada zinaweza kufunguliwa kwa kusaidia maendeleo.</string>
|
||||
<string name="upgrade_screen_status_free_action">Tazama chaguo za kuboreshwa</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Kuboreshwa kimefanya kazi</string>
|
||||
<string name="upgrade_screen_recurring_title">Endelea na hilo</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod inaendelea kupitia sasisho na marekebisho. Ikiwa ungependa kusaidia, fikiria kumfanya mchango wa mara kwa mara kupitia GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">மேம்பாட்டை ஸ்பான்சர் செய்யுங்கள்</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ஐவிளம்பரம் இல்லை. கண்காணிப்பு இல்லை. Google Play கட்டுப்பாட்டு இல்லை.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">இத்தனை இருக்கிறீரகளா? உங்கள் ஆதரவு CAPodஐ உயிருடன் வைத்திருக்கிறது.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s முதல் ஆதரவாளர்</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod-இன் மேம்பாட்டை ஆதரித்ததற்கு நன்றி!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">ஸ்பான்சர் பக்கத்தைத் திற</string>
|
||||
<string name="settings_upgrade_status_label">CAPod ஐ ஆதரிக்கவும்</string>
|
||||
<string name="settings_upgrade_status_description">உங்கள் ஆதரவாளர் நிலை.</string>
|
||||
<string name="upgrade_screen_why_title">மேம்படுத்தல் நன்மைகள்</string>
|
||||
<string name="upgrade_screen_how_title">எப்படி உதவுவது</string>
|
||||
<string name="upgrade_screen_how_body">புரவலராக மாறி மேம்பாட்டை ஸ்பான்சர் செய்யுங்கள்! அனைத்து கூடுதல் அம்சங்களையும் செயல்படுத்த மற்றும் எனது GitHub Sponsors சுயவிவரத்தைத் திறக்க கீழே உள்ள பொத்தானைத் தட்டவும்.</string>
|
||||
<string name="upgrade_screen_status_free_title">இலவச பதிப்பு</string>
|
||||
<string name="upgrade_screen_status_free_body">நீங்கள் CAPod இன் இலவச பதிப்பைப் பயன்படுத்துகிறீர்கள். வளர்ச்சியை ஆதரிப்பதன் மூலம் கூடுதல் அம்சங்களைத் திறக்க முடியும்.</string>
|
||||
<string name="upgrade_screen_status_free_action">மேம்படுத்தல் விருப்பங்களைப் பார்க்கவும்</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">மேம்படுத்தல் செயல்பட்டுள்ளது</string>
|
||||
<string name="upgrade_screen_recurring_title">இதைத் தொடரவும்</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod புதுப்பிப்புகள் மற்றும் திருத்தங்களின் மூலம் தொடர்ந்து உருவாகிறது. நீங்கள் அதை நிலைத்து வைக்க விரும்பினால், GitHub Sponsors மூலம் தொடர்ச்சியான தான வழங்கலை பரிசீலியுங்கள்.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">అభివృద్ధిని స్పాన్సర్ చేయండి</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">జాహీరాతులు లేవు. ట్రాకింగ్ లేదు. Google Play ఒక్కటికి పరిమితం కాదు.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">ఇర్వై వెనక్కి వెళ్ళారా? మీ మద్దతు CAPodను సజీవంగా ఉంచుతుంది.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s నుండి సపోర్టర్</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod అభివృద్ధికి మద్దతు ఇచ్చినందుకు ధన్యవాదాలు!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">స్పాన్సర్ పేజీని తెరవండి</string>
|
||||
<string name="settings_upgrade_status_label">CAPodకు స్పాన్సర్ చేయండి</string>
|
||||
<string name="settings_upgrade_status_description">మీ సపోర్టర్ స్థితి.</string>
|
||||
<string name="upgrade_screen_why_title">అప్గ్రేడ్ ప్రయోజనాలు</string>
|
||||
<string name="upgrade_screen_how_title">ఎలా సహాయం చేయాలి</string>
|
||||
<string name="upgrade_screen_how_body">పేట్రన్ అవ్వండి మరియు అభివృద్ధిని స్పాన్సర్ చేయండి! అన్ని అదనపు ఫీచర్లను యాక్టివేట్ చేయడానికి మరియు నా GitHub Sponsors ప్రొఫైల్ను తెరవడానికి దిగువ బటన్ను నొక్కండి.</string>
|
||||
<string name="upgrade_screen_status_free_title">ఉచిత సంస్కరణ</string>
|
||||
<string name="upgrade_screen_status_free_body">మీరు CAPod యొక్క ఉచిత సంస్కరణని ఉపయోగిస్తున్నారు. అభివృద్ధిని సపోర్ట్ చేయడం ద్వారా అతిరిక్త ఫీచర్లను అన్లాక్ చేయవచ్చు.</string>
|
||||
<string name="upgrade_screen_status_free_action">అప్గ్రేడ్ ఎంపికలను చూడండి</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">అప్గ్రేడ్ క్రియాశీలమైనది</string>
|
||||
<string name="upgrade_screen_recurring_title">దీన్నిని కొనసాగించండి</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod నవీకరణలు మరియు సరిదిద్దుకుల ద్వారా వికసిస్తూ ఉంది. మీరు దీన్నిని కొనసాగించాలనుకుంటే, GitHub Sponsors ద్వారా పునరావృత దానం గురించి ఆలోచించండి.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">สปอนเซอร์การพัฒนา</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">ไม่มีโฆษณา ไม่ติดตาม ไม่ผูกขาด Google Play</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">กลับมาแล้ว? การสนับสนุนของคุณช่วยให้ CAPod ดำเนินต่อไป</string>
|
||||
<string name="upgrade_foss_supporter_since">ผู้สนับสนุนตั้งแต่ %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">ขอบคุณที่สนับสนุนการพัฒนา CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">เปิดหน้าสนับสนุน</string>
|
||||
<string name="settings_upgrade_status_label">สนับสนุน CAPod</string>
|
||||
<string name="settings_upgrade_status_description">สถานะผู้สนับสนุนของคุณ</string>
|
||||
<string name="upgrade_screen_why_title">ประโยชน์ของการอัปเกรด</string>
|
||||
<string name="upgrade_screen_how_title">วิธีการช่วยเหลือ</string>
|
||||
<string name="upgrade_screen_how_body">เป็นผู้อุปถัมภ์และสปอนเซอร์การพัฒนา! แตะปุ่มด้านล่างเพื่อเปิดใช้ฟีเจอร์เพิ่มเติมทั้งหมดและเปิดโปรไฟล์ GitHub Sponsors ของฉัน</string>
|
||||
<string name="upgrade_screen_status_free_title">เวอร์ชันฟรี</string>
|
||||
<string name="upgrade_screen_status_free_body">คุณกำลังใช้เวอร์ชันฟรีของ CAPod คุณลักษณะเพิ่มเติมสามารถปลดล็อกได้โดยการสนับสนุนการพัฒนา</string>
|
||||
<string name="upgrade_screen_status_free_action">ดูตัวเลือกการอัปเกรด</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">เปิดใช้งานการอัปเกรด</string>
|
||||
<string name="upgrade_screen_recurring_title">ทำให้มันดำเนินต่อไป</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod ยังคงพัฒนาต่อไปผ่านการอัปเดตและการแก้ไข หากคุณต้องการสนับสนุนสิ่งนั้นต่อไป โปรดพิจารณาการบริจาคที่เกิดขึ้นซ้ำผ่าน GitHub Sponsors</string>
|
||||
<string name="upgrade_badge_label">บังคับ</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Geliştirmeyi destekleyin</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Reklam yok. Takip yok. Google Play sınırlaması yok.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Şimdiden döndün mü? Desteğin CAPod\'u ayakta tutuyor.</string>
|
||||
<string name="upgrade_foss_supporter_since">%s tarihinden beri destekçi</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod\'un geliştirilmesini desteklediğin için teşekkürler!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Sponsor sayfasını aç</string>
|
||||
<string name="settings_upgrade_status_label">CAPod\'u destekle</string>
|
||||
<string name="settings_upgrade_status_description">Destekçi durumun.</string>
|
||||
<string name="upgrade_screen_why_title">Yükseltme Avantajları</string>
|
||||
<string name="upgrade_screen_how_title">Nasıl yardım edilir</string>
|
||||
<string name="upgrade_screen_how_body">Haminiz olun ve gelişime sponsor olun! Tüm ekstra özellikleri etkinleştirmek ve GitHub Sponsorları profilimi açmak için aşağıdaki düğmeye dokunun.</string>
|
||||
<string name="upgrade_screen_status_free_title">Ücretsiz Sürüm</string>
|
||||
<string name="upgrade_screen_status_free_body">CAPod\'un ücretsiz sürümünü kullanıyorsunuz. Ek özellikler, geliştirmeyi destekleyerek kilidini açabilir.</string>
|
||||
<string name="upgrade_screen_status_free_action">Yükseltme Seçeneklerini Gör</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Yükseltme Etkin</string>
|
||||
<string name="upgrade_screen_recurring_title">Devam Ettirin</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod güncellemeler ve düzeltmeler aracılığıyla gelişmeye devam ediyor. Bunu sürdürmek istiyorsanız, GitHub Sponsors aracılığıyla yinelenen bir bağış yapmayı düşünün.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">Розвиток спонсорів</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">Без реклами. Без стеження. Без прив\'язки до Google Play.</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">Вже повертаєтеся? Ваша підтримка зберігає CAPod.</string>
|
||||
<string name="upgrade_foss_supporter_since">Підтримує з %s</string>
|
||||
<string name="upgrade_foss_supporter_thanks">Дякуємо за підтримку розробки CAPod!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">Відкрити сторінку спонсорства</string>
|
||||
<string name="settings_upgrade_status_label">Спонсорувати CAPod</string>
|
||||
<string name="settings_upgrade_status_description">Ваш статус прихильника.</string>
|
||||
<string name="upgrade_screen_why_title">Переваги оновлення</string>
|
||||
<string name="upgrade_screen_how_title">Як допомогти</string>
|
||||
<string name="upgrade_screen_how_body">Стань меценатом і спонсором розробки! Торкніться кнопки нижче, щоб активувати всі додаткові функції та відкрити мій профіль спонсорів GitHub.</string>
|
||||
<string name="upgrade_screen_status_free_title">Безплатна версія</string>
|
||||
<string name="upgrade_screen_status_free_body">Ви використовуєте безплатну версію CAPod. Додаткові функції можна розблокувати, підтримавши розробку.</string>
|
||||
<string name="upgrade_screen_status_free_action">Переглянути варіанти оновлення</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">Оновлення активне</string>
|
||||
<string name="upgrade_screen_recurring_title">Підтримайте розвиток</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod постійно розвивається завдяки оновленням та виправленням. Якщо ви хочете підтримати це, розгляньте можливість регулярного пожертвування через GitHub Sponsors.</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,18 +7,5 @@
|
||||
<string name="upgrade_foss_sponsor_action">ترقی کو اسپانسر کریں</string>
|
||||
<string name="upgrade_foss_sponsor_subtitle">کوئی اشتہار نہیں۔ کوئی ٹریکنگ نہیں۔ کوئی Google Play کی قید نہیں۔</string>
|
||||
<string name="upgrade_foss_sponsor_returned_early">پہلے ہی واپس؟ آپ کی مدد CAPod کو زندہ رکھتی ہے۔</string>
|
||||
<string name="upgrade_foss_supporter_since">%s سے سپورٹر</string>
|
||||
<string name="upgrade_foss_supporter_thanks">CAPod کی ترقی کی حمایت کرنے کا شکریہ!</string>
|
||||
<string name="upgrade_foss_sponsor_again_action">سپانسر پیج کھولیں</string>
|
||||
<string name="settings_upgrade_status_label">CAPod کی سرپرستی کریں</string>
|
||||
<string name="settings_upgrade_status_description">آپ کی حامی حالت۔</string>
|
||||
<string name="upgrade_screen_why_title">اپ گریڈ کے فوائد</string>
|
||||
<string name="upgrade_screen_how_title">کیسے مدد کریں</string>
|
||||
<string name="upgrade_screen_how_body">سرپرست بنیں اور ترقی کو اسپانسر کریں! تمام اضافی خصوصیات کو فعال کرنے اور میری GitHub Sponsors پروفائل کھولنے کے لیے نیچے دیا گیا بٹن دبائیں۔</string>
|
||||
<string name="upgrade_screen_status_free_title">مفت ورژن</string>
|
||||
<string name="upgrade_screen_status_free_body">آپ CAPod کے مفت ورژن کا استعمال کر رہے ہیں۔ ترقی کی حمایت کر کے اضافی خصوصیات کو کھولا جا سکتا ہے۔</string>
|
||||
<string name="upgrade_screen_status_free_action">اپ گریڈ کے آپشنز دیکھیں</string>
|
||||
<string name="upgrade_screen_status_upgraded_title">اپ گریڈ فعال ہے</string>
|
||||
<string name="upgrade_screen_recurring_title">اسے جاری رکھیں</string>
|
||||
<string name="upgrade_screen_recurring_body">CAPod اپ ڈیٹس اور اصلاحات کے ذریعے ترقی کرتا رہتا ہے۔ اگر آپ اسے برقرار رکھنا چاہتے ہیں، تو GitHub Sponsors کے ذریعے بار بار عطیہ کرنے پر غور کریں۔</string>
|
||||
<string name="upgrade_badge_label">FOSS</string>
|
||||
</resources>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user