Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
c75a07c9da
6 changed files with 77 additions and 2 deletions
|
|
@ -124,4 +124,5 @@ data class ReaderScreenState(
|
|||
val customAppThemes: List<CustomAppTheme> = emptyList(),
|
||||
val allTags: List<TagEntity> = emptyList(),
|
||||
val showTagSelectionDialogFor: Set<String> = emptySet(),
|
||||
val isScreenCaptureProtectionEnabled: Boolean = false,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -359,6 +359,15 @@ fun HomeScreen(
|
|||
onExportLogsClick = { viewModel.exportLogsToFile(context) },
|
||||
onToggleHideReaderAi = {
|
||||
saveHideReaderAiFeatures(context, !loadHideReaderAiFeatures(context))
|
||||
},
|
||||
onScreenCaptureProtectionChange = { enabled ->
|
||||
viewModel.setScreenCaptureProtectionEnabled(enabled)
|
||||
val messageRes = if (enabled) {
|
||||
R.string.banner_screen_capture_protection_on
|
||||
} else {
|
||||
R.string.banner_screen_capture_protection_off
|
||||
}
|
||||
viewModel.showBanner(context.getString(messageRes))
|
||||
}
|
||||
)
|
||||
} else {
|
||||
|
|
@ -1019,7 +1028,8 @@ fun DefaultTopAppBar(
|
|||
onTestSpeechBubbleDetectionClick: () -> Unit,
|
||||
onLanguageClick: () -> Unit,
|
||||
onExportLogsClick: () -> Unit,
|
||||
onToggleHideReaderAi: () -> Unit
|
||||
onToggleHideReaderAi: () -> Unit,
|
||||
onScreenCaptureProtectionChange: (Boolean) -> Unit
|
||||
) {
|
||||
var showOptionsMenu by remember { mutableStateOf(false) }
|
||||
var showLimitMenu by remember { mutableStateOf(false) }
|
||||
|
|
@ -1090,6 +1100,19 @@ fun DefaultTopAppBar(
|
|||
}
|
||||
})
|
||||
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(R.string.options_screen_capture_protection)) },
|
||||
onClick = {
|
||||
onScreenCaptureProtectionChange(!uiState.isScreenCaptureProtectionEnabled)
|
||||
showOptionsMenu = false
|
||||
},
|
||||
trailingIcon = {
|
||||
if (uiState.isScreenCaptureProtectionEnabled) {
|
||||
Icon(Icons.Default.Check, contentDescription = stringResource(R.string.content_desc_enabled))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
DropdownMenuItem(text = { Text(stringResource(R.string.options_external_file_behavior)) }, onClick = {
|
||||
onExternalFileBehaviorClick()
|
||||
showOptionsMenu = false
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package com.aryan.reader
|
|||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import android.webkit.WebView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.activity.compose.setContent
|
||||
|
|
@ -34,6 +35,8 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
||||
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
|
|
@ -87,6 +90,8 @@ class MainActivity : AppCompatActivity() {
|
|||
setContent {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
ScreenCaptureProtectionEffect(enabled = uiState.isScreenCaptureProtectionEnabled)
|
||||
|
||||
val darkTheme = when (uiState.appThemeMode) {
|
||||
AppThemeMode.LIGHT -> false
|
||||
AppThemeMode.DARK -> true
|
||||
|
|
@ -132,3 +137,20 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MainActivity.ScreenCaptureProtectionEffect(enabled: Boolean) {
|
||||
DisposableEffect(enabled) {
|
||||
if (enabled) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
|
||||
onDispose {
|
||||
if (enabled) {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -544,6 +544,7 @@ open class MainViewModel(application: Application) : AndroidViewModel(applicatio
|
|||
activeTabBookId = prefs.getString(KEY_ACTIVE_TAB, null),
|
||||
externalFileBehavior = prefs.getString(KEY_EXTERNAL_FILE_BEHAVIOR, "ASK") ?: "ASK",
|
||||
useStrictFileFilter = prefs.getBoolean(KEY_USE_STRICT_FILE_FILTER, false),
|
||||
isScreenCaptureProtectionEnabled = prefs.getBoolean(KEY_SCREEN_CAPTURE_PROTECTION, false),
|
||||
appThemeMode = try {
|
||||
AppThemeMode.valueOf(prefs.getString(KEY_APP_THEME_MODE, AppThemeMode.SYSTEM.name) ?: AppThemeMode.SYSTEM.name)
|
||||
} catch (_: Exception) { AppThemeMode.SYSTEM },
|
||||
|
|
@ -5227,6 +5228,11 @@ open class MainViewModel(application: Application) : AndroidViewModel(applicatio
|
|||
_internalState.update { it.copy(useStrictFileFilter = enabled) }
|
||||
}
|
||||
|
||||
fun setScreenCaptureProtectionEnabled(enabled: Boolean) {
|
||||
prefs.edit { putBoolean(KEY_SCREEN_CAPTURE_PROTECTION, enabled) }
|
||||
_internalState.update { it.copy(isScreenCaptureProtectionEnabled = enabled) }
|
||||
}
|
||||
|
||||
private fun loadCustomAppThemes(prefs: SharedPreferences): List<CustomAppTheme> {
|
||||
val jsonString = prefs.getString(KEY_CUSTOM_APP_THEMES, "[]") ?: "[]"
|
||||
val themes = mutableListOf<CustomAppTheme>()
|
||||
|
|
@ -5506,6 +5512,7 @@ open class MainViewModel(application: Application) : AndroidViewModel(applicatio
|
|||
private const val KEY_LAST_OPEN_FILE_TYPE = "last_open_file_type"
|
||||
private const val KEY_EXTERNAL_FILE_BEHAVIOR = "external_file_behavior"
|
||||
private const val KEY_USE_STRICT_FILE_FILTER = "use_strict_file_filter"
|
||||
private const val KEY_SCREEN_CAPTURE_PROTECTION = "screen_capture_protection_enabled"
|
||||
private const val KEY_APP_THEME_MODE = "app_theme_mode"
|
||||
private const val KEY_APP_CONTRAST_OPTION = "app_contrast_option"
|
||||
private const val KEY_APP_SEED_COLOR = "app_seed_color"
|
||||
|
|
|
|||
|
|
@ -1304,4 +1304,7 @@
|
|||
<string name="action_exit_smart_zoom">Exit Smart Zoom</string>
|
||||
<string name="action_smart_comic_zoom">Smart Comic Zoom</string>
|
||||
<string name="desc_toggle_smart_comic_zoom">Toggle Smart Comic Zoom</string>
|
||||
<string name="options_screen_capture_protection">Screen capture protection</string>
|
||||
<string name="banner_screen_capture_protection_on">Screen capture protection is on</string>
|
||||
<string name="banner_screen_capture_protection_off">Screen capture protection is off</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -319,6 +319,25 @@ class MainViewModelTest {
|
|||
verify { mockEditor.putString("external_file_behavior", "KEEP") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `screen capture protection persists and updates state`() = runTest {
|
||||
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
viewModel.uiState.collect {}
|
||||
}
|
||||
|
||||
viewModel.setScreenCaptureProtectionEnabled(true)
|
||||
|
||||
val enabledState = viewModel.uiState.first { it.isScreenCaptureProtectionEnabled }
|
||||
assertTrue(enabledState.isScreenCaptureProtectionEnabled)
|
||||
verify { mockEditor.putBoolean("screen_capture_protection_enabled", true) }
|
||||
|
||||
viewModel.setScreenCaptureProtectionEnabled(false)
|
||||
|
||||
val disabledState = viewModel.uiState.first { !it.isScreenCaptureProtectionEnabled }
|
||||
assertFalse(disabledState.isScreenCaptureProtectionEnabled)
|
||||
verify { mockEditor.putBoolean("screen_capture_protection_enabled", false) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setSortOrder persists preference and reorders visible home and library lists`() = runTest {
|
||||
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue