diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index 400cb3f3a..fa51056c8 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -688,6 +688,7 @@ public final class NavigationHelper { } public static void openSettings(final Context context) { + // TODO: Replace with "ContextKt.navigateTo(context, Destination.Settings.INSTANCE);" later final Intent intent = new Intent(context, SettingsActivity.class); context.startActivity(intent); } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index fe5524336..59f348ab1 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -37,7 +37,8 @@ kotlin { compilerOptions { freeCompilerArgs.addAll( - "-Xexpect-actual-classes" + "-Xexpect-actual-classes", + "-Xexplicit-backing-fields" ) optIn.addAll( "androidx.compose.material3.ExperimentalMaterial3Api", diff --git a/shared/src/androidMain/kotlin/net/newpipe/app/platform/AndroidBuildInfo.kt b/shared/src/androidMain/kotlin/net/newpipe/app/platform/AndroidBuildInfo.kt new file mode 100644 index 000000000..a32d7ca66 --- /dev/null +++ b/shared/src/androidMain/kotlin/net/newpipe/app/platform/AndroidBuildInfo.kt @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package net.newpipe.app.platform + +import android.annotation.SuppressLint +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import androidx.core.content.pm.PackageInfoCompat +import co.touchlab.kermit.Logger +import org.koin.core.annotation.Singleton + +@Singleton(binds = [BuildInfo::class]) +class AndroidBuildInfo(private val context: Context) : BuildInfo { + + override val isDebug: Boolean = + context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE != 0 + + @get:SuppressLint("NewApi") + @OptIn(ExperimentalStdlibApi::class) + override val isReleaseApk: Boolean by lazy { + val certificates = mapOf( + RELEASE_CERT_PUBLIC_KEY_SHA256.hexToByteArray() to PackageManager.CERT_INPUT_SHA256 + ) + try { + PackageInfoCompat.hasSignatures( + context.packageManager, + context.packageName, + certificates, + false + ) + } catch (exception: PackageManager.NameNotFoundException) { + Logger.e(messageString = "Could not find package info", throwable = exception) + false + } + } + + companion object { + private const val RELEASE_CERT_PUBLIC_KEY_SHA256 = + "cb84069bd68116bafae5ee4ee5b08a567aa6d898404e7cb12f9e756df5cf5cab" + } +} diff --git a/shared/src/commonMain/composeResources/drawable/ic_bug_report.xml b/shared/src/commonMain/composeResources/drawable/ic_bug_report.xml new file mode 100644 index 000000000..846859a57 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_bug_report.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_cloud_download.xml b/shared/src/commonMain/composeResources/drawable/ic_cloud_download.xml new file mode 100644 index 000000000..7ff641b5d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_cloud_download.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_file_download.xml b/shared/src/commonMain/composeResources/drawable/ic_file_download.xml new file mode 100644 index 000000000..f5cf7cbcc --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_file_download.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_headset.xml b/shared/src/commonMain/composeResources/drawable/ic_headset.xml new file mode 100644 index 000000000..d6d34cbe2 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_headset.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_history.xml b/shared/src/commonMain/composeResources/drawable/ic_history.xml new file mode 100644 index 000000000..447becbb9 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_history.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_language.xml b/shared/src/commonMain/composeResources/drawable/ic_language.xml new file mode 100644 index 000000000..699ee683d --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_language.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_notifications.xml b/shared/src/commonMain/composeResources/drawable/ic_notifications.xml new file mode 100644 index 000000000..114b84677 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_notifications.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_palette.xml b/shared/src/commonMain/composeResources/drawable/ic_palette.xml new file mode 100644 index 000000000..fbe0b3925 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_palette.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_search.xml b/shared/src/commonMain/composeResources/drawable/ic_search.xml new file mode 100644 index 000000000..51b1a1e55 --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_search.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/drawable/ic_settings_backup_restore.xml b/shared/src/commonMain/composeResources/drawable/ic_settings_backup_restore.xml new file mode 100644 index 000000000..317859a1e --- /dev/null +++ b/shared/src/commonMain/composeResources/drawable/ic_settings_backup_restore.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/shared/src/commonMain/composeResources/values/strings.xml b/shared/src/commonMain/composeResources/values/strings.xml index d56afc50b..c738a1c13 100644 --- a/shared/src/commonMain/composeResources/values/strings.xml +++ b/shared/src/commonMain/composeResources/values/strings.xml @@ -34,4 +34,17 @@ Open in browser Done Not available + + + Settings + Search + Content + Notifications + Video and audio + Download + Appearance + History and cache + Updates + Backup and restore + Debug diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/composable/PreferenceRow.kt b/shared/src/commonMain/kotlin/net/newpipe/app/composable/PreferenceRow.kt new file mode 100644 index 000000000..dbec1f8e3 --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/composable/PreferenceRow.kt @@ -0,0 +1,59 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.composable + +import androidx.compose.foundation.clickable +import androidx.compose.material3.Icon +import androidx.compose.material3.ListItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.tooling.preview.PreviewWrapper +import net.newpipe.app.preview.ThemePreviewProvider +import newpipe.shared.generated.resources.Res +import newpipe.shared.generated.resources.ic_headset +import newpipe.shared.generated.resources.settings_category_video_audio_title +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource + +/** + * A row that mirrors the standard AndroidX preference item + * + * @param title Title text of the preference + * @param modifier Modifier applied to the row + * @param icon Leading icon painter; null hides the leading slot + * @param summary Optional secondary line under the title + * @param onClick Action executed when the row is tapped + */ +@Composable +fun PreferenceRow( + title: String, + modifier: Modifier = Modifier, + icon: Painter? = null, + summary: String? = null, + onClick: () -> Unit = {} +) { + ListItem( + modifier = modifier.clickable(onClick = onClick), + headlineContent = { Text(text = title) }, + supportingContent = summary?.let { text -> { Text(text = text) } }, + leadingContent = icon?.let { painter -> + { Icon(painter = painter, contentDescription = null) } + } + ) +} + +@PreviewWrapper(ThemePreviewProvider::class) +@PreviewLightDark +@Composable +private fun PreferenceRowPreview() { + PreferenceRow( + title = stringResource(Res.string.settings_category_video_audio_title), + icon = painterResource(Res.drawable.ic_headset) + ) +} diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt index bf0d11557..367285066 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/Destination.kt @@ -15,6 +15,9 @@ import net.newpipe.app.model.License @Serializable sealed interface Destination : NavKey { + @Serializable + data object Settings : Destination + @Serializable data object About : Destination } diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt index 4367d50a0..fe1f30f91 100644 --- a/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt +++ b/shared/src/commonMain/kotlin/net/newpipe/app/navigation/NavModule.kt @@ -8,6 +8,7 @@ package net.newpipe.app.navigation import androidx.compose.runtime.mutableStateListOf import co.touchlab.kermit.Logger import net.newpipe.app.screen.about.AboutScreen +import net.newpipe.app.screen.settings.SettingsHomeScreen import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.annotation.Provided import org.koin.core.annotation.Singleton @@ -27,6 +28,10 @@ fun navModule() = module { navigation { AboutScreen() } + + navigation { + SettingsHomeScreen() + } } /** diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/platform/BuildInfo.kt b/shared/src/commonMain/kotlin/net/newpipe/app/platform/BuildInfo.kt new file mode 100644 index 000000000..983ffb8cc --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/platform/BuildInfo.kt @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: 2026 NewPipe e.V. + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package net.newpipe.app.platform + +/** + * Information about the currently running build. + */ + +interface BuildInfo { + val isReleaseApk: Boolean + val isDebug: Boolean +} diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt new file mode 100644 index 000000000..1eea3c149 --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreen.kt @@ -0,0 +1,106 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.screen.settings + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.tooling.preview.PreviewWrapper +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import net.newpipe.app.composable.PreferenceRow +import net.newpipe.app.composable.TopAppBar +import net.newpipe.app.navigation.Navigator +import net.newpipe.app.preview.ThemePreviewProvider +import net.newpipe.app.screen.settings.model.SettingsCategory +import net.newpipe.app.screen.settings.model.SettingsCategoryType +import net.newpipe.app.viewmodel.settings.SettingsViewModel +import newpipe.shared.generated.resources.Res +import newpipe.shared.generated.resources.ic_search +import newpipe.shared.generated.resources.search +import newpipe.shared.generated.resources.settings +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel + +@Composable +fun SettingsHomeScreen( + navigator: Navigator = koinInject(), + viewModel: SettingsViewModel = koinViewModel() +) { + val categories by viewModel.categories.collectAsStateWithLifecycle() + + SettingsHomeScreenContent( + categories = categories.map { type -> + SettingsCategory( + title = type.title, + icon = type.icon, + // TODO: Replace with a Destination once sub-screens are migrated + onClick = {} + ) + }, + onNavigateUp = { navigator.navigateUp() } + ) +} + +@Composable +fun SettingsHomeScreenContent( + categories: List = SettingsCategoryType.entries.map { type -> + SettingsCategory(title = type.title, icon = type.icon) + }, + onNavigateUp: () -> Unit = {}, + onSearchClick: () -> Unit = {} +) { + Scaffold( + topBar = { + TopAppBar( + title = stringResource(Res.string.settings), + onNavigateUp = onNavigateUp, + actions = { + IconButton(onClick = onSearchClick) { + Icon( + painter = painterResource(Res.drawable.ic_search), + contentDescription = stringResource(Res.string.search) + ) + } + } + ) + } + ) { paddingValues -> + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(top = paddingValues.calculateTopPadding()), + contentPadding = WindowInsets.navigationBars.asPaddingValues() + ) { + items(items = categories) { category -> + PreferenceRow( + title = stringResource(category.title), + icon = painterResource(category.icon), + onClick = category.onClick + ) + } + } + } +} + +@PreviewWrapper(ThemePreviewProvider::class) +@PreviewLightDark +@Composable +private fun SettingsHomeScreenPreview() { + SettingsHomeScreenContent() +} diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategory.kt b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategory.kt new file mode 100644 index 000000000..b4bcf8718 --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategory.kt @@ -0,0 +1,16 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.screen.settings.model + +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource + +data class SettingsCategory( + val title: StringResource, + val icon: DrawableResource, + // TODO: Replace with a Destination once sub-screens are migrated + val onClick: () -> Unit = {} +) diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategoryType.kt b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategoryType.kt new file mode 100644 index 000000000..93ae3bc6e --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/screen/settings/model/SettingsCategoryType.kt @@ -0,0 +1,41 @@ +package net.newpipe.app.screen.settings.model + +import newpipe.shared.generated.resources.Res +import newpipe.shared.generated.resources.content +import newpipe.shared.generated.resources.ic_bug_report +import newpipe.shared.generated.resources.ic_cloud_download +import newpipe.shared.generated.resources.ic_file_download +import newpipe.shared.generated.resources.ic_headset +import newpipe.shared.generated.resources.ic_history +import newpipe.shared.generated.resources.ic_language +import newpipe.shared.generated.resources.ic_notifications +import newpipe.shared.generated.resources.ic_palette +import newpipe.shared.generated.resources.ic_settings_backup_restore +import newpipe.shared.generated.resources.notifications +import newpipe.shared.generated.resources.settings_category_appearance_title +import newpipe.shared.generated.resources.settings_category_backup_restore_title +import newpipe.shared.generated.resources.settings_category_debug_title +import newpipe.shared.generated.resources.settings_category_downloads_title +import newpipe.shared.generated.resources.settings_category_history_title +import newpipe.shared.generated.resources.settings_category_updates_title +import newpipe.shared.generated.resources.settings_category_video_audio_title +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource + +/** + * Categories on the settings home screen. + */ +enum class SettingsCategoryType( + val title: StringResource, + val icon: DrawableResource +) { + VIDEO_AUDIO(Res.string.settings_category_video_audio_title, Res.drawable.ic_headset), + DOWNLOADS(Res.string.settings_category_downloads_title, Res.drawable.ic_file_download), + APPEARANCE(Res.string.settings_category_appearance_title, Res.drawable.ic_palette), + HISTORY(Res.string.settings_category_history_title, Res.drawable.ic_history), + CONTENT(Res.string.content, Res.drawable.ic_language), + NOTIFICATIONS(Res.string.notifications, Res.drawable.ic_notifications), + UPDATES(Res.string.settings_category_updates_title, Res.drawable.ic_cloud_download), + BACKUP_RESTORE(Res.string.settings_category_backup_restore_title, Res.drawable.ic_settings_backup_restore), + DEBUG(Res.string.settings_category_debug_title, Res.drawable.ic_bug_report) +} diff --git a/shared/src/commonMain/kotlin/net/newpipe/app/viewmodel/settings/SettingsViewModel.kt b/shared/src/commonMain/kotlin/net/newpipe/app/viewmodel/settings/SettingsViewModel.kt new file mode 100644 index 000000000..20d4f3056 --- /dev/null +++ b/shared/src/commonMain/kotlin/net/newpipe/app/viewmodel/settings/SettingsViewModel.kt @@ -0,0 +1,30 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.viewmodel.settings + +import androidx.lifecycle.ViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import net.newpipe.app.platform.BuildInfo +import net.newpipe.app.screen.settings.model.SettingsCategoryType +import org.koin.core.annotation.KoinViewModel + +@KoinViewModel +class SettingsViewModel(buildInfo: BuildInfo) : ViewModel() { + + val categories: StateFlow> + field = MutableStateFlow(computeVisible(buildInfo)) + + private fun computeVisible(buildInfo: BuildInfo): List = + SettingsCategoryType.entries.filter { type -> + when (type) { + SettingsCategoryType.UPDATES -> buildInfo.isReleaseApk + SettingsCategoryType.DEBUG -> buildInfo.isDebug + else -> true + } + } +} + diff --git a/shared/src/commonTest/kotlin/net/newpipe/app/composable/PreferenceRowTest.kt b/shared/src/commonTest/kotlin/net/newpipe/app/composable/PreferenceRowTest.kt new file mode 100644 index 000000000..0746d7ad6 --- /dev/null +++ b/shared/src/commonTest/kotlin/net/newpipe/app/composable/PreferenceRowTest.kt @@ -0,0 +1,48 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.composable + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.v2.runComposeUiTest +import kotlin.test.Test +import kotlin.test.assertTrue + +@OptIn(ExperimentalTestApi::class) +class PreferenceRowTest { + + @Test + fun testPreferenceRowTitleAndClick() = runComposeUiTest { + val title = "Test title" + var clicked = false + setContent { + PreferenceRow( + title = title, + onClick = { clicked = true } + ) + } + + onNodeWithText(title).apply { + assertIsDisplayed() + performClick() + } + assertTrue(clicked) + } + + @Test + fun testPreferenceRowShowsSummary() = runComposeUiTest { + val title = "Test title" + val summary = "Test summary" + setContent { + PreferenceRow(title = title, summary = summary) + } + + onNodeWithText(title).assertIsDisplayed() + onNodeWithText(summary).assertIsDisplayed() + } +} diff --git a/shared/src/commonTest/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreenTest.kt b/shared/src/commonTest/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreenTest.kt new file mode 100644 index 000000000..f28eef7aa --- /dev/null +++ b/shared/src/commonTest/kotlin/net/newpipe/app/screen/settings/SettingsHomeScreenTest.kt @@ -0,0 +1,66 @@ +/* +* SPDX-FileCopyrightText: 2026 NewPipe e.V. +* SPDX-License-Identifier: GPL-3.0-or-later +*/ + +package net.newpipe.app.screen.settings + +import androidx.compose.ui.test.ExperimentalTestApi +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.v2.runComposeUiTest +import com.russhwolf.settings.MapSettings +import com.russhwolf.settings.Settings +import net.newpipe.app.extensions.withKoin +import net.newpipe.app.screen.settings.model.SettingsCategory +import kotlin.test.Test +import kotlin.test.assertTrue +import newpipe.shared.generated.resources.Res +import newpipe.shared.generated.resources.ic_headset +import newpipe.shared.generated.resources.settings +import newpipe.shared.generated.resources.settings_category_video_audio_title +import org.jetbrains.compose.resources.getString +import org.koin.dsl.module + +@OptIn(ExperimentalTestApi::class) +class SettingsHomeScreenTest { + + private val emptySettings = module { + single { MapSettings() } + } + + @Test + fun testTitleAndCategoriesRender() = runComposeUiTest { + withKoin( + modules = listOf(emptySettings), + content = { SettingsHomeScreenContent() }, + onContent = { + onNodeWithText(getString(Res.string.settings)).assertIsDisplayed() + onNodeWithText(getString(Res.string.settings_category_video_audio_title)) + .assertIsDisplayed() + } + ) + } + + @Test + fun testCategoryClickFires() = runComposeUiTest { + var clicked = false + val categories = listOf( + SettingsCategory( + title = Res.string.settings_category_video_audio_title, + icon = Res.drawable.ic_headset, + onClick = { clicked = true } + ) + ) + withKoin( + modules = listOf(emptySettings), + content = { SettingsHomeScreenContent(categories = categories) }, + onContent = { + onNodeWithText(getString(Res.string.settings_category_video_audio_title)) + .performClick() + assertTrue(clicked) + } + ) + } +} diff --git a/shared/src/iosMain/kotlin/net/newpipe/app/platform/IOSBuildInfo.kt b/shared/src/iosMain/kotlin/net/newpipe/app/platform/IOSBuildInfo.kt new file mode 100644 index 000000000..34818bcbc --- /dev/null +++ b/shared/src/iosMain/kotlin/net/newpipe/app/platform/IOSBuildInfo.kt @@ -0,0 +1,9 @@ +package net.newpipe.app.platform + +import org.koin.core.annotation.Singleton + +@Singleton(binds = [BuildInfo::class]) +class IOSBuildInfo : BuildInfo { + override val isReleaseApk: Boolean = false + override val isDebug: Boolean = false +} diff --git a/shared/src/jvmMain/kotlin/net/newpipe/app/platform/JVMBuildInfo.kt b/shared/src/jvmMain/kotlin/net/newpipe/app/platform/JVMBuildInfo.kt new file mode 100644 index 000000000..952067c5f --- /dev/null +++ b/shared/src/jvmMain/kotlin/net/newpipe/app/platform/JVMBuildInfo.kt @@ -0,0 +1,9 @@ +package net.newpipe.app.platform + +import org.koin.core.annotation.Singleton + +@Singleton(binds = [BuildInfo::class]) +class JVMBuildInfo : BuildInfo { + override val isReleaseApk: Boolean = false + override val isDebug: Boolean = false +}