mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-23 20:54:13 -04:00
Implemented proper dark mode for ZIM files.
* Removed the custom logic for color inversion of WebView content so that ZIM files can automatically apply the `prefered-color-scheme` setting based on the app theme. * Removed unused code and test cases from the project.
This commit is contained in:
parent
484c425597
commit
6c0ac69043
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.main
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.compose.ui.test.filter
|
|
||||||
import androidx.compose.ui.test.hasContentDescription
|
|
||||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
|
||||||
import androidx.compose.ui.test.onAllNodesWithTag
|
|
||||||
import androidx.compose.ui.test.onFirst
|
|
||||||
import androidx.compose.ui.test.performClick
|
|
||||||
import applyWithViewHierarchyPrinting
|
|
||||||
import org.junit.Assert.assertEquals
|
|
||||||
import org.kiwix.kiwixmobile.BaseRobot
|
|
||||||
import org.kiwix.kiwixmobile.core.R
|
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
|
||||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
|
||||||
import org.kiwix.kiwixmobile.core.settings.DIALOG_PREFERENCE_ITEM_TESTING_TAG
|
|
||||||
import org.kiwix.kiwixmobile.testutils.TestUtils.testFlakyView
|
|
||||||
import org.kiwix.kiwixmobile.utils.StandardActions.enterSettings
|
|
||||||
import org.kiwix.kiwixmobile.utils.StandardActions.openDrawer
|
|
||||||
|
|
||||||
fun darkModeViewPainter(func: DarkModeViewPainterRobot.() -> Unit) =
|
|
||||||
DarkModeViewPainterRobot().applyWithViewHierarchyPrinting(func)
|
|
||||||
|
|
||||||
class DarkModeViewPainterRobot : BaseRobot() {
|
|
||||||
fun openSettings(coreMainActivity: CoreMainActivity, composeContentTest: ComposeContentTestRule) {
|
|
||||||
openDrawer(coreMainActivity)
|
|
||||||
enterSettings(composeContentTest)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enableTheDarkMode(composeContentTest: ComposeContentTestRule) {
|
|
||||||
testFlakyView({
|
|
||||||
composeContentTest.apply {
|
|
||||||
waitForIdle()
|
|
||||||
onAllNodesWithTag(DIALOG_PREFERENCE_ITEM_TESTING_TAG)
|
|
||||||
.filter(hasContentDescription(context.getString(R.string.on)))
|
|
||||||
.onFirst()
|
|
||||||
.performClick()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enableTheLightMode(composeContentTest: ComposeContentTestRule) {
|
|
||||||
testFlakyView({
|
|
||||||
composeContentTest.apply {
|
|
||||||
waitForIdle()
|
|
||||||
onAllNodesWithTag(DIALOG_PREFERENCE_ITEM_TESTING_TAG)
|
|
||||||
.filter(hasContentDescription(context.getString(R.string.off)))
|
|
||||||
.onFirst()
|
|
||||||
.performClick()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNightModeEnabled(kiwixWebView: KiwixWebView) {
|
|
||||||
assertEquals(kiwixWebView.layerType, View.LAYER_TYPE_HARDWARE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertLightModeEnabled(kiwixWebView: KiwixWebView) {
|
|
||||||
assertEquals(kiwixWebView.layerType, View.LAYER_TYPE_NONE)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,223 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.main
|
|
||||||
|
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
|
||||||
import androidx.compose.ui.test.onNodeWithTag
|
|
||||||
import androidx.compose.ui.test.performClick
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.navigation.NavOptions
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.test.espresso.accessibility.AccessibilityChecks
|
|
||||||
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import androidx.test.uiautomator.UiDevice
|
|
||||||
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesCheck
|
|
||||||
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils.matchesViews
|
|
||||||
import com.google.android.apps.common.testing.accessibility.framework.checks.SpeakableTextPresentCheck
|
|
||||||
import com.google.android.apps.common.testing.accessibility.framework.checks.TouchTargetSizeCheck
|
|
||||||
import org.hamcrest.Matchers.allOf
|
|
||||||
import org.hamcrest.Matchers.anyOf
|
|
||||||
import org.junit.After
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
|
||||||
import org.kiwix.kiwixmobile.BaseActivityTest
|
|
||||||
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.setNavigationResultOnCurrent
|
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
|
||||||
import org.kiwix.kiwixmobile.core.main.ZIM_FILE_URI_KEY
|
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.NAVIGATION_ICON_TESTING_TAG
|
|
||||||
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
|
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
|
||||||
import org.kiwix.kiwixmobile.core.utils.TestingUtils.COMPOSE_TEST_RULE_ORDER
|
|
||||||
import org.kiwix.kiwixmobile.core.utils.TestingUtils.RETRY_RULE_ORDER
|
|
||||||
import org.kiwix.kiwixmobile.nav.destination.reader.KiwixReaderFragment
|
|
||||||
import org.kiwix.kiwixmobile.settings.settingsRobo
|
|
||||||
import org.kiwix.kiwixmobile.testutils.RetryRule
|
|
||||||
import org.kiwix.kiwixmobile.testutils.TestUtils
|
|
||||||
import org.kiwix.kiwixmobile.testutils.TestUtils.TEST_PAUSE_MS_FOR_DOWNLOAD_TEST
|
|
||||||
import org.kiwix.kiwixmobile.testutils.TestUtils.waitUntilTimeout
|
|
||||||
import org.kiwix.kiwixmobile.ui.KiwixDestination
|
|
||||||
import java.io.File
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
|
|
||||||
class DarkModeViewPainterTest : BaseActivityTest() {
|
|
||||||
@Rule(order = RETRY_RULE_ORDER)
|
|
||||||
@JvmField
|
|
||||||
val retryRule = RetryRule()
|
|
||||||
|
|
||||||
@get:Rule(order = COMPOSE_TEST_RULE_ORDER)
|
|
||||||
val composeTestRule = createAndroidComposeRule<KiwixMainActivity>()
|
|
||||||
private lateinit var kiwixMainActivity: KiwixMainActivity
|
|
||||||
|
|
||||||
@Before
|
|
||||||
override fun waitForIdle() {
|
|
||||||
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).apply {
|
|
||||||
if (TestUtils.isSystemUINotRespondingDialogVisible(this)) {
|
|
||||||
TestUtils.closeSystemDialogs(context, this)
|
|
||||||
}
|
|
||||||
waitForIdle()
|
|
||||||
}
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(
|
|
||||||
InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
|
|
||||||
).edit {
|
|
||||||
putBoolean(SharedPreferenceUtil.PREF_SHOW_INTRO, false)
|
|
||||||
putBoolean(SharedPreferenceUtil.PREF_WIFI_ONLY, false)
|
|
||||||
putBoolean(SharedPreferenceUtil.PREF_IS_TEST, true)
|
|
||||||
putBoolean(SharedPreferenceUtil.PREF_EXTERNAL_LINK_POPUP, true)
|
|
||||||
putBoolean(SharedPreferenceUtil.PREF_SHOW_SHOWCASE, false)
|
|
||||||
putString(SharedPreferenceUtil.PREF_LANG, "en")
|
|
||||||
}
|
|
||||||
composeTestRule.apply {
|
|
||||||
kiwixMainActivity = activity
|
|
||||||
runOnUiThread {
|
|
||||||
LanguageUtils.handleLocaleChange(
|
|
||||||
kiwixMainActivity,
|
|
||||||
"en",
|
|
||||||
SharedPreferenceUtil(context)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
waitForIdle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
AccessibilityChecks.enable().apply {
|
|
||||||
setRunChecksFromRootView(true)
|
|
||||||
setSuppressingResultMatcher(
|
|
||||||
anyOf(
|
|
||||||
allOf(
|
|
||||||
matchesCheck(TouchTargetSizeCheck::class.java),
|
|
||||||
matchesViews(withContentDescription("More options"))
|
|
||||||
),
|
|
||||||
matchesCheck(SpeakableTextPresentCheck::class.java)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testDarkMode() {
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
composeTestRule.runOnUiThread {
|
|
||||||
composeTestRule.activity.navigate(KiwixDestination.Library.route)
|
|
||||||
}
|
|
||||||
toggleDarkMode(true)
|
|
||||||
openZimFileInReader()
|
|
||||||
verifyDarkMode(true)
|
|
||||||
toggleDarkMode(false)
|
|
||||||
openZimFileInReader()
|
|
||||||
verifyDarkMode(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openZimFileInReader() {
|
|
||||||
kiwixMainActivity = composeTestRule.activity
|
|
||||||
composeTestRule.apply {
|
|
||||||
waitForIdle()
|
|
||||||
waitUntilTimeout()
|
|
||||||
onNodeWithTag(NAVIGATION_ICON_TESTING_TAG).performClick()
|
|
||||||
waitUntilTimeout()
|
|
||||||
onNodeWithTag(BOTTOM_NAV_LIBRARY_ITEM_TESTING_TAG).performClick()
|
|
||||||
waitUntilTimeout()
|
|
||||||
}
|
|
||||||
loadZimFileInReader()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleDarkMode(enable: Boolean) {
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
darkModeViewPainter { openSettings(kiwixMainActivity as CoreMainActivity, composeTestRule) }
|
|
||||||
settingsRobo { clickNightModePreference(composeTestRule) }
|
|
||||||
darkModeViewPainter {
|
|
||||||
if (enable) {
|
|
||||||
enableTheDarkMode(composeTestRule)
|
|
||||||
} else {
|
|
||||||
enableTheLightMode(composeTestRule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun verifyDarkMode(isEnabled: Boolean) {
|
|
||||||
var kiwixReaderFragment: KiwixReaderFragment? = null
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
kiwixMainActivity = composeTestRule.activity
|
|
||||||
composeTestRule.waitUntil(TEST_PAUSE_MS_FOR_DOWNLOAD_TEST.toLong()) {
|
|
||||||
kiwixReaderFragment =
|
|
||||||
kiwixMainActivity.supportFragmentManager.fragments
|
|
||||||
.filterIsInstance<KiwixReaderFragment>()
|
|
||||||
.firstOrNull()
|
|
||||||
kiwixReaderFragment?.getCurrentWebView() != null
|
|
||||||
}
|
|
||||||
val currentWebView = kiwixReaderFragment?.getCurrentWebView()
|
|
||||||
currentWebView?.let {
|
|
||||||
darkModeViewPainter {
|
|
||||||
if (isEnabled) {
|
|
||||||
assertNightModeEnabled(it)
|
|
||||||
} else {
|
|
||||||
assertLightModeEnabled(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
composeTestRule.waitUntilTimeout()
|
|
||||||
} ?: run {
|
|
||||||
throw RuntimeException(
|
|
||||||
"Could not check the dark mode enable or not because zim file is not loaded in the reader"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadZimFileInReader() {
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
val loadFileStream =
|
|
||||||
DarkModeViewPainterTest::class.java.classLoader.getResourceAsStream("testzim.zim")
|
|
||||||
val zimFile =
|
|
||||||
File(
|
|
||||||
context.getExternalFilesDirs(null)[0],
|
|
||||||
"testzim.zim"
|
|
||||||
)
|
|
||||||
if (zimFile.exists()) zimFile.delete()
|
|
||||||
zimFile.createNewFile()
|
|
||||||
loadFileStream.use { inputStream ->
|
|
||||||
val outputStream: OutputStream = FileOutputStream(zimFile)
|
|
||||||
outputStream.use { it ->
|
|
||||||
val buffer = ByteArray(inputStream.available())
|
|
||||||
var length: Int
|
|
||||||
while (inputStream.read(buffer).also { length = it } > 0) {
|
|
||||||
it.write(buffer, 0, length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTestRule.runOnIdle {
|
|
||||||
val navOptions = NavOptions.Builder()
|
|
||||||
.setPopUpTo(KiwixDestination.Reader.route, false)
|
|
||||||
.build()
|
|
||||||
composeTestRule.activity.apply {
|
|
||||||
navigate(KiwixDestination.Reader.route, navOptions)
|
|
||||||
setNavigationResultOnCurrent(zimFile.toUri().toString(), ZIM_FILE_URI_KEY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composeTestRule.waitForIdle()
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
fun finish() {
|
|
||||||
TestUtils.deleteTemporaryFilesOfTestCases(context)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2020 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.kiwix.kiwixmobile.core.main
|
|
||||||
|
|
||||||
import android.graphics.ColorMatrixColorFilter
|
|
||||||
import android.graphics.Paint
|
|
||||||
import android.view.View
|
|
||||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DarkModeViewPainter class is used to apply respective filters to the views
|
|
||||||
* depending whether the app is in dark mode or not
|
|
||||||
* Created by yashk2000 on 24/03/2020.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class DarkModeViewPainter @Inject constructor(
|
|
||||||
private val darkModeConfig: DarkModeConfig
|
|
||||||
) {
|
|
||||||
private val invertedPaint =
|
|
||||||
Paint().apply { colorFilter = ColorMatrixColorFilter(KiwixWebView.DARK_MODE_COLORS) }
|
|
||||||
|
|
||||||
@JvmOverloads
|
|
||||||
fun <T : View?> update(
|
|
||||||
view: T,
|
|
||||||
shouldActivateCriteria: ((T) -> Boolean) = { true },
|
|
||||||
vararg additionalViews: View? = emptyArray()
|
|
||||||
) {
|
|
||||||
if (darkModeConfig.isDarkModeActive()) {
|
|
||||||
if (shouldActivateCriteria(view)) {
|
|
||||||
activateDarkMode(view, *additionalViews)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
deactivateDarkMode(view, *additionalViews)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deactivateDarkMode(vararg additionalViews: View?) {
|
|
||||||
additionalViews.filterNotNull()
|
|
||||||
.forEach { it.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun activateDarkMode(vararg additionalViews: View?) {
|
|
||||||
additionalViews.filterNotNull()
|
|
||||||
.forEach { it.setLayerType(View.LAYER_TYPE_HARDWARE, invertedPaint) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -188,15 +188,4 @@ open class KiwixWebView @SuppressLint("SetJavaScriptEnabled") constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
val DARK_MODE_COLORS =
|
|
||||||
floatArrayOf(
|
|
||||||
-1.0f, 0f, 0f, 0f,
|
|
||||||
255f, 0f, -1.0f, 0f,
|
|
||||||
0f, 255f, 0f, 0f,
|
|
||||||
-1.0f, 0f, 255f, 0f,
|
|
||||||
0f, 0f, 1.0f, 0f
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,6 @@ import org.kiwix.kiwixmobile.core.main.CompatFindActionModeCallback
|
|||||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreSearchWidget
|
import org.kiwix.kiwixmobile.core.main.CoreSearchWidget
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreWebViewClient
|
import org.kiwix.kiwixmobile.core.main.CoreWebViewClient
|
||||||
import org.kiwix.kiwixmobile.core.main.DarkModeViewPainter
|
|
||||||
import org.kiwix.kiwixmobile.core.main.DocumentParser
|
import org.kiwix.kiwixmobile.core.main.DocumentParser
|
||||||
import org.kiwix.kiwixmobile.core.main.DocumentParser.SectionsListener
|
import org.kiwix.kiwixmobile.core.main.DocumentParser.SectionsListener
|
||||||
import org.kiwix.kiwixmobile.core.main.FIND_IN_PAGE_SEARCH_STRING
|
import org.kiwix.kiwixmobile.core.main.FIND_IN_PAGE_SEARCH_STRING
|
||||||
@ -218,10 +217,6 @@ abstract class CoreReaderFragment :
|
|||||||
@JvmField
|
@JvmField
|
||||||
@Inject
|
@Inject
|
||||||
var donationDialogHandler: DonationDialogHandler? = null
|
var donationDialogHandler: DonationDialogHandler? = null
|
||||||
|
|
||||||
@JvmField
|
|
||||||
@Inject
|
|
||||||
var painter: DarkModeViewPainter? = null
|
|
||||||
protected var currentWebViewIndex by mutableStateOf(0)
|
protected var currentWebViewIndex by mutableStateOf(0)
|
||||||
private var currentTtsWebViewIndex = 0
|
private var currentTtsWebViewIndex = 0
|
||||||
private var isFirstTimeMainPageLoaded = true
|
private var isFirstTimeMainPageLoaded = true
|
||||||
@ -301,7 +296,6 @@ abstract class CoreReaderFragment :
|
|||||||
selectedWebView = null,
|
selectedWebView = null,
|
||||||
readerScreenTitle = "",
|
readerScreenTitle = "",
|
||||||
showTabSwitcher = false,
|
showTabSwitcher = false,
|
||||||
darkModeViewPainter = null,
|
|
||||||
currentWebViewPosition = ZERO,
|
currentWebViewPosition = ZERO,
|
||||||
onTabClickListener = object : TabClickListener {
|
onTabClickListener = object : TabClickListener {
|
||||||
override fun onSelectTab(position: Int) {
|
override fun onSelectTab(position: Int) {
|
||||||
@ -444,7 +438,6 @@ abstract class CoreReaderFragment :
|
|||||||
readerScreenState.update {
|
readerScreenState.update {
|
||||||
copy(
|
copy(
|
||||||
readerScreenTitle = context.getString(string.reader),
|
readerScreenTitle = context.getString(string.reader),
|
||||||
darkModeViewPainter = darkModeViewPainter,
|
|
||||||
tocButtonItem = getTocButtonStateAndAction(),
|
tocButtonItem = getTocButtonStateAndAction(),
|
||||||
appName = (requireActivity() as CoreMainActivity).appName,
|
appName = (requireActivity() as CoreMainActivity).appName,
|
||||||
donateButtonClick = {
|
donateButtonClick = {
|
||||||
@ -1803,7 +1796,6 @@ abstract class CoreReaderFragment :
|
|||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
updateBottomToolbarVisibility()
|
updateBottomToolbarVisibility()
|
||||||
updateNightMode()
|
|
||||||
if (tts == null) {
|
if (tts == null) {
|
||||||
setUpTTS()
|
setUpTTS()
|
||||||
}
|
}
|
||||||
@ -2108,23 +2100,12 @@ abstract class CoreReaderFragment :
|
|||||||
getCurrentWebView()?.url?.let { webUrlsFlow.value = it }
|
getCurrentWebView()?.url?.let { webUrlsFlow.value = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateNightMode() {
|
|
||||||
painter?.update(
|
|
||||||
getCurrentWebView(),
|
|
||||||
::shouldActivateNightMode,
|
|
||||||
readerScreenState.value.fullScreenItem.second
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldActivateNightMode(kiwixWebView: KiwixWebView?): Boolean = kiwixWebView != null
|
|
||||||
|
|
||||||
private fun loadPrefs() {
|
private fun loadPrefs() {
|
||||||
isBackToTopEnabled = sharedPreferenceUtil?.prefBackToTop == true
|
isBackToTopEnabled = sharedPreferenceUtil?.prefBackToTop == true
|
||||||
isOpenNewTabInBackground = sharedPreferenceUtil?.prefNewTabBackground == true
|
isOpenNewTabInBackground = sharedPreferenceUtil?.prefNewTabBackground == true
|
||||||
if (!isBackToTopEnabled) {
|
if (!isBackToTopEnabled) {
|
||||||
hideBackToTopButton()
|
hideBackToTopButton()
|
||||||
}
|
}
|
||||||
updateNightMode()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showBackToTopButton() {
|
private fun showBackToTopButton() {
|
||||||
@ -2307,7 +2288,6 @@ abstract class CoreReaderFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateBottomToolbarVisibility()
|
updateBottomToolbarVisibility()
|
||||||
updateNightMode()
|
|
||||||
if (!isWebViewHistoryRestoring) {
|
if (!isWebViewHistoryRestoring) {
|
||||||
saveTabStates()
|
saveTabStates()
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,6 @@ import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions
|
|||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED
|
||||||
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
|
||||||
import org.kiwix.kiwixmobile.core.extensions.update
|
import org.kiwix.kiwixmobile.core.extensions.update
|
||||||
import org.kiwix.kiwixmobile.core.main.DarkModeViewPainter
|
|
||||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
import org.kiwix.kiwixmobile.core.ui.components.ContentLoadingProgressBar
|
||||||
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
import org.kiwix.kiwixmobile.core.ui.components.KiwixAppBar
|
||||||
@ -458,8 +457,7 @@ private fun TabSwitcherAnimated(state: ReaderScreenState) {
|
|||||||
state.kiwixWebViewList,
|
state.kiwixWebViewList,
|
||||||
state.currentWebViewPosition,
|
state.currentWebViewPosition,
|
||||||
state.onTabClickListener,
|
state.onTabClickListener,
|
||||||
state.onCloseAllTabs,
|
state.onCloseAllTabs
|
||||||
state.darkModeViewPainter
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -776,8 +774,7 @@ fun TabSwitcherView(
|
|||||||
webViews: List<KiwixWebView>,
|
webViews: List<KiwixWebView>,
|
||||||
selectedIndex: Int,
|
selectedIndex: Int,
|
||||||
onTabClickListener: TabClickListener,
|
onTabClickListener: TabClickListener,
|
||||||
onCloseAllTabs: () -> Unit,
|
onCloseAllTabs: () -> Unit
|
||||||
painter: DarkModeViewPainter?
|
|
||||||
) {
|
) {
|
||||||
val state = rememberLazyListState()
|
val state = rememberLazyListState()
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
@ -797,12 +794,6 @@ fun TabSwitcherView(
|
|||||||
?: context.getString(R.string.menu_home)
|
?: context.getString(R.string.menu_home)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(webView) {
|
|
||||||
if (title != context.getString(R.string.menu_home)) {
|
|
||||||
painter?.update(webView)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TabItemView(
|
TabItemView(
|
||||||
index = index,
|
index = index,
|
||||||
title = title,
|
title = title,
|
||||||
|
@ -20,7 +20,6 @@ package org.kiwix.kiwixmobile.core.main.reader
|
|||||||
|
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import org.kiwix.kiwixmobile.core.main.DarkModeViewPainter
|
|
||||||
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
import org.kiwix.kiwixmobile.core.main.KiwixWebView
|
||||||
import org.kiwix.kiwixmobile.core.ui.models.IconItem.Drawable
|
import org.kiwix.kiwixmobile.core.ui.models.IconItem.Drawable
|
||||||
|
|
||||||
@ -139,7 +138,6 @@ data class ReaderScreenState(
|
|||||||
*/
|
*/
|
||||||
val shouldShowBottomAppBar: Boolean,
|
val shouldShowBottomAppBar: Boolean,
|
||||||
val readerScreenTitle: String,
|
val readerScreenTitle: String,
|
||||||
val darkModeViewPainter: DarkModeViewPainter?,
|
|
||||||
/**
|
/**
|
||||||
* Manages the click event on tabs.
|
* Manages the click event on tabs.
|
||||||
*/
|
*/
|
||||||
|
@ -341,12 +341,7 @@ class ZimFileReader constructor(
|
|||||||
val output = ByteArrayOutputStream()
|
val output = ByteArrayOutputStream()
|
||||||
when {
|
when {
|
||||||
uri.endsWith(UNINITIALISER_ADDRESS) -> output.write(UNINITIALISE_HTML.toByteArray())
|
uri.endsWith(UNINITIALISER_ADDRESS) -> output.write(UNINITIALISE_HTML.toByteArray())
|
||||||
item != null -> {
|
item != null -> output.write(item.data.data)
|
||||||
if ("text/css" == item.mimetype && darkModeConfig.isDarkModeActive()) {
|
|
||||||
output.write(INVERT_IMAGES_VIDEO.toByteArray())
|
|
||||||
}
|
|
||||||
output.write(item.data.data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayInputStream(output.toByteArray())
|
ByteArrayInputStream(output.toByteArray())
|
||||||
@ -415,21 +410,6 @@ class ZimFileReader constructor(
|
|||||||
val UI_URI: Uri? = "content://org.kiwix.ui/".toUri()
|
val UI_URI: Uri? = "content://org.kiwix.ui/".toUri()
|
||||||
|
|
||||||
const val CONTENT_PREFIX = "https://kiwix.app/"
|
const val CONTENT_PREFIX = "https://kiwix.app/"
|
||||||
|
|
||||||
private val INVERT_IMAGES_VIDEO =
|
|
||||||
"""
|
|
||||||
img, video, div[poster] {
|
|
||||||
-webkit-filter: invert(1);
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
div[poster] img, div[poster] video {
|
|
||||||
-webkit-filter: invert(0);
|
|
||||||
filter: invert(0);
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
background-color: white !important;
|
|
||||||
}
|
|
||||||
""".trimIndent()
|
|
||||||
private val assetExtensions =
|
private val assetExtensions =
|
||||||
listOf("3gp", "mp4", "m4a", "webm", "mkv", "ogg", "ogv", "svg", "warc")
|
listOf("3gp", "mp4", "m4a", "webm", "mkv", "ogg", "ogv", "svg", "warc")
|
||||||
private val compressedExtensions =
|
private val compressedExtensions =
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Kiwix Android
|
|
||||||
* Copyright (c) 2024 Kiwix <android.kiwix.org>
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.kiwix.kiwixmobile.core.main
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import io.mockk.every
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.verify
|
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.kiwix.kiwixmobile.core.DarkModeConfig
|
|
||||||
|
|
||||||
class DarkModeViewPainterTest {
|
|
||||||
private lateinit var darkModeConfig: DarkModeConfig
|
|
||||||
private lateinit var darkModeViewPainter: DarkModeViewPainter
|
|
||||||
private lateinit var view: View
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun setUp() {
|
|
||||||
darkModeConfig = mockk()
|
|
||||||
view = mockk(relaxed = true)
|
|
||||||
darkModeViewPainter = DarkModeViewPainter(darkModeConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should activate dark mode when dark mode is active and criteria is true`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
val shouldActivateCriteria: (View) -> Boolean = { true }
|
|
||||||
darkModeViewPainter.update(view, shouldActivateCriteria)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should not activate dark mode when dark mode is active but criteria is false`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
val shouldActivateCriteria: (View) -> Boolean = { false }
|
|
||||||
darkModeViewPainter.update(view, shouldActivateCriteria)
|
|
||||||
verify(exactly = 0) { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should deactivate dark mode when dark mode is inactive`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns false
|
|
||||||
darkModeViewPainter.update(view)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should handle null views without crashing`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
darkModeViewPainter.update(null)
|
|
||||||
assertTrue(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should activate dark mode for multiple additional views when dark mode is active`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
val additionalView1 = mockk<View>(relaxed = true)
|
|
||||||
val additionalView2 = mockk<View>(relaxed = true)
|
|
||||||
darkModeViewPainter.update(view, { true }, additionalView1, additionalView2)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
verify { additionalView1.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
verify { additionalView2.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should deactivate dark mode for multiple additional views when dark mode is inactive`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns false
|
|
||||||
val additionalView1 = mockk<View>(relaxed = true)
|
|
||||||
val additionalView2 = mockk<View>(relaxed = true)
|
|
||||||
darkModeViewPainter.update(view, { true }, additionalView1, additionalView2)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
verify { additionalView1.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
verify { additionalView2.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should handle null additional views without crashing when dark mode is active`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
darkModeViewPainter.update(view, { true }, null, null)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should handle null additional views without crashing when dark mode is inactive`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns false
|
|
||||||
darkModeViewPainter.update(view, { true }, null, null)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should only update main view when no additional views are passed and dark mode is active`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
darkModeViewPainter.update(view)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun shouldOnlyUpdateMainViewWhenNoAdditionalViewsArePassedAndDarkModeIsInactive() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns false
|
|
||||||
darkModeViewPainter.update(view)
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_NONE, null) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `should handle empty additional views array without crashing`() {
|
|
||||||
every { darkModeConfig.isDarkModeActive() } returns true
|
|
||||||
darkModeViewPainter.update(view, { true }, *arrayOf())
|
|
||||||
verify { view.setLayerType(View.LAYER_TYPE_HARDWARE, any()) }
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user