Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/manual_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:

# Step 2: Configure Java environment with integrated caching
- name: Setup Java
uses: actions/setup-java@v6.0.0
uses: actions/setup-java@v6.0.1
with:
java-version: '21'
distribution: 'temurin'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
# Sets up JDK 21 with Temurin and configures server-id for
# potential publication to Maven-style repositories.
- name: Set up JDK 21
uses: actions/setup-java@v6.0.0
uses: actions/setup-java@v6.0.1
with:
java-version: '21'
distribution: 'temurin'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
# Uses Temurin distribution (OpenJDK) and enables Gradle caching
# to significantly reduce subsequent build times.
- name: Setup Java
uses: actions/setup-java@v6.0.0
uses: actions/setup-java@v6.0.1
with:
java-version: '21'
distribution: 'temurin'
Expand Down
10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file serves as the central "Source of Truth" for all AI agents (Gemini, Cur

- **Name:** PiPup
- **Purpose:** An Android application designed to display notifications and media in a Picture-in-Picture (PiP) window, primarily optimized for Android TV.
- **Technology Stack:** Kotlin, Android SDK, Jackson (JSON), SharedPreferences.
- **Technology Stack:** Kotlin, Android SDK, org.json, SharedPreferences, NanoHTTPD (WebServer), Media3 (Video), Glide (Images).

## Coding Standards & Preferences

Expand All @@ -17,6 +17,14 @@ This file serves as the central "Source of Truth" for all AI agents (Gemini, Cur
- **UI/UX:** Ensure all UI changes are optimized for Android TV (high contrast, readable font sizes, D-pad navigation support). Use the project's preset color resources.
- **Documentation:** Use KDoc for all public-facing methods and classes.

## Core Knowledge Base

Before proposing architectural changes, adding new features, or implementing modules, you MUST read the following documentation:

- **[Architecture Overview](docs/architecture.md)**: Design principles and component interactions.
- **[Module Development Guide](docs/module-development.md)**: Blueprint and recipe for adding new modular features.
- **[HTTP API Reference](docs/api.md)**: Precision specification for remote requests.

## Interaction Guidelines

- **Language:** All instructions, code comments, and technical documentation within the codebase MUST be in English.
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ PiPup uses an embedded webserver (NanoHTTPD) which runs on port 7979.
### Sending notifications

You can send notifications either as an **application/json** payload (for external media URLs) or as **multipart/form-data** (to upload a local image file).
For a detailed list of all endpoints and response formats, please refer to the [Full API Reference](API.md).
For a detailed list of all endpoints and response formats, please refer to the [Full API Reference](docs/api.md).

| _Property_ | _Value_ |
| ----------------- | ------------------------------------------- |
Expand Down Expand Up @@ -287,9 +287,12 @@ Retrieves a JSON object containing all current styling and layout configurations
"mediaRetries": 3,
"appTheme": 0,
"advancedMode": false,
"powerModuleEnabled": true,
"discoveryModuleEnabled": true,
"mediaModuleEnabled": true,
"moduleModes": {
"power": 1,
"discovery": 1,
"media": 2,
"vendor": 0
},
"updateChannel": 0,
"language": "default"
}
Expand Down
57 changes: 21 additions & 36 deletions app/src/main/java/nl/rogro82/pipup/AppSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -186,21 +186,6 @@ class AppSettings(context: Context) {
/** The application theme (0: Dark, 1: Light). */
var appTheme by IntPref("app_theme", 0)

/** Whether the power control module is enabled. */
var powerModuleEnabled: Boolean
get() = getModuleMode("power") != ModuleMode.OFF
set(value) = setModuleMode("power", if (value) getPreferredMode("power").takeIf { it != ModuleMode.OFF } ?: ModuleMode.ON else ModuleMode.OFF)

/** Whether the network discovery module is enabled. */
var discoveryModuleEnabled: Boolean
get() = getModuleMode("discovery") != ModuleMode.OFF
set(value) = setModuleMode("discovery", if (value) ModuleMode.ON else ModuleMode.OFF)

/** Whether the rich media (WebView/WHEP) module is enabled. */
var mediaModuleEnabled: Boolean
get() = getModuleMode("media") != ModuleMode.OFF
set(value) = setModuleMode("media", if (value) getPreferredMode("media").takeIf { it != ModuleMode.OFF } ?: ModuleMode.ECO else ModuleMode.OFF)

/** The preferred language for the application UI. */
var language by StringPref("language", "default")
/** The timestamp of the last daily permission nag. */
Expand Down Expand Up @@ -278,9 +263,7 @@ class AppSettings(context: Context) {
val mediaRetries: Int,
val appTheme: Int,
val advancedMode: Boolean,
val powerModuleEnabled: Boolean,
val discoveryModuleEnabled: Boolean,
val mediaModuleEnabled: Boolean,
val moduleModes: Map<String, Int>,
val updateChannel: Int,
val updateInterval: Int,
val updateNotificationStyle: Int,
Expand Down Expand Up @@ -317,9 +300,7 @@ class AppSettings(context: Context) {
put("mediaRetries", mediaRetries)
put("appTheme", appTheme)
put("advancedMode", advancedMode)
put("powerModuleEnabled", powerModuleEnabled)
put("discoveryModuleEnabled", discoveryModuleEnabled)
put("mediaModuleEnabled", mediaModuleEnabled)
put("moduleModes", JSONObject(moduleModes))
put("updateChannel", updateChannel)
put("updateInterval", updateInterval)
put("updateNotificationStyle", updateNotificationStyle)
Expand Down Expand Up @@ -360,9 +341,11 @@ class AppSettings(context: Context) {
mediaRetries = j.optInt("mediaRetries", 3),
appTheme = j.optInt("appTheme", 0),
advancedMode = j.optBoolean("advancedMode", false),
powerModuleEnabled = j.optBoolean("powerModuleEnabled", false),
discoveryModuleEnabled = j.optBoolean("discoveryModuleEnabled", false),
mediaModuleEnabled = j.optBoolean("mediaModuleEnabled", false),
moduleModes = j.optJSONObject("moduleModes")?.let { modes ->
val map = mutableMapOf<String, Int>()
modes.keys().forEach { key -> map[key] = modes.getInt(key) }
map
} ?: emptyMap(),
updateChannel = j.optInt("updateChannel", 0),
updateInterval = j.optInt("updateInterval", 4),
updateNotificationStyle = j.optInt("updateNotificationStyle", 1),
Expand All @@ -384,6 +367,9 @@ class AppSettings(context: Context) {
* Retrieves all current settings as a [SettingsData] object.
*/
fun getAll(): SettingsData {
val mm = (appContext as? PiPupApp)?.moduleManager
val modes = mm?.getAllModules()?.associate { it.id to getModuleMode(it.id).value } ?: emptyMap()

return SettingsData(
positionIndex = positionIndex,
backgroundColor = backgroundColor,
Expand All @@ -406,9 +392,7 @@ class AppSettings(context: Context) {
mediaRetries = mediaRetries,
appTheme = appTheme,
advancedMode = advancedMode,
powerModuleEnabled = powerModuleEnabled,
discoveryModuleEnabled = discoveryModuleEnabled,
mediaModuleEnabled = mediaModuleEnabled,
moduleModes = modes,
updateChannel = updateChannel,
updateInterval = updateInterval,
updateNotificationStyle = updateNotificationStyle,
Expand All @@ -419,8 +403,7 @@ class AppSettings(context: Context) {
pendingUpdateId = pendingUpdateId,
pendingUpdateDigest = pendingUpdateDigest,
pendingUpdateTagName = pendingUpdateTagName,
language = language,
moduleModeMedia = getModuleMode("media").value
language = language
)
}

Expand Down Expand Up @@ -449,9 +432,15 @@ class AppSettings(context: Context) {
mediaRetries = data.mediaRetries.coerceIn(0, 10)
appTheme = data.appTheme.coerceIn(0, 1)
advancedMode = data.advancedMode
powerModuleEnabled = data.powerModuleEnabled
discoveryModuleEnabled = data.discoveryModuleEnabled
mediaModuleEnabled = data.mediaModuleEnabled

val mm = (appContext as? PiPupApp)?.moduleManager
data.moduleModes.forEach { (id, modeValue) ->
ModuleMode.entries.find { it.value == modeValue }?.let { mode ->
setModuleMode(id, mode)
mm?.updateModuleState(id, mode)
}
}

updateChannel = data.updateChannel.coerceIn(-1, 1)
updateInterval = data.updateInterval.coerceIn(0, 4)
updateNotificationStyle = data.updateNotificationStyle.coerceIn(0, 2)
Expand All @@ -464,10 +453,6 @@ class AppSettings(context: Context) {
pendingUpdateTagName = data.pendingUpdateTagName
language = data.language

data.moduleModeMedia?.let {
ModuleMode.entries.find { m -> m.value == it }?.let { m -> setModuleMode("media", m) }
}

cachedFullBgColor = null
}

Expand Down
10 changes: 6 additions & 4 deletions app/src/main/java/nl/rogro82/pipup/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.media3.common.util.UnstableApi
import java.util.Calendar
import nl.rogro82.pipup.core.PowerController
import nl.rogro82.pipup.service.PipUpService
import nl.rogro82.pipup.ui.SettingsActivity

Expand Down Expand Up @@ -147,11 +146,14 @@ class MainActivity : AppCompatActivity() {
missing.add(getString(R.string.permission_overlay))
}

if (appSettings.powerModuleEnabled && PowerController.getSleepMethod(this) == null) {
missing.add(getString(R.string.settings_module_power))
// Generic module permission check
val mm = (application as PiPupApp).moduleManager
val moduleMissing = mm.getEnabledModulesMissingPermissions(this).map { key ->
Permissions.getLabel(this, key)
}
missing.addAll(moduleMissing)

return missing
return missing.distinct()
}

/**
Expand Down
Loading
Loading