diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 646a38241..51df46d36 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,7 +15,7 @@ jobs: coverageReport: strategy: matrix: - api-level: [21, 21] + api-level: [21, 21] fail-fast: false runs-on: macOS-latest steps: @@ -48,6 +48,7 @@ jobs: - name: Upload Coverage to GH-Actions uses: actions/upload-artifact@v2.2.0 + if: ${{ always() }} with: name: Tests Coverage Report path: | diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1f975420a..4e5ac2485 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -18,6 +18,7 @@ jobs: - name: Upload Static Analysis Report uses: actions/upload-artifact@v2.2.0 + if: ${{ always() }} with: name: Static Analysis Report path: | diff --git a/CHANGELOG b/CHANGELOG index 67bccb1d8..e5bb8b9c1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,7 @@ NEW: Overhauled navigation NEW: Updated translations NEW: Support resizing Kiwix -NEW: Open search in ne wtab +NEW: Open search in new tab BUGFIX: Search speed increased and loading state added BUGFIX: Memory leaks patched BUGFIX: More consistent labelling drives internal/external diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16bfe788b..e8caa7cb0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,7 +116,7 @@ To generate coverage reports for your automated tests run: Code coverage results can be seen under `[module]/build/reports/` -### Continous Integration +### Continuous Integration All PRs will have all these tests run and a combined coverage report will be attached, if coverage is to go down the PR will be marked failed. On Travis CI the automated tests are run on an emulator. To learn more about the commands run on the CI please refer to [.github/workflows](https://github.com/kiwix/kiwix-android/tree/develop/.github/workflows). diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/BaseActivityTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/BaseActivityTest.kt index 2a03e4d0b..6fdb17461 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/BaseActivityTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/BaseActivityTest.kt @@ -29,11 +29,12 @@ import org.junit.Rule import org.junit.runner.RunWith import org.kiwix.kiwixmobile.core.di.components.DaggerTestComponent import org.kiwix.kiwixmobile.core.di.components.TestComponent +import org.kiwix.kiwixmobile.main.KiwixMainActivity @RunWith(AndroidJUnit4::class) -abstract class BaseActivityTest { +abstract class BaseActivityTest { @get:Rule - abstract var activityRule: ActivityTestRule + open var activityRule = ActivityTestRule(KiwixMainActivity::class.java) @get:Rule var readPermissionRule: GrantPermissionRule = diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/help/HelpFragmentTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/help/HelpFragmentTest.kt index 9933b7d84..903077390 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/help/HelpFragmentTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/help/HelpFragmentTest.kt @@ -18,18 +18,11 @@ package org.kiwix.kiwixmobile.help import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread -import androidx.test.rule.ActivityTestRule -import org.junit.Rule import org.junit.Test import org.kiwix.kiwixmobile.BaseActivityTest import org.kiwix.kiwixmobile.R -import org.kiwix.kiwixmobile.main.KiwixMainActivity -class HelpFragmentTest : BaseActivityTest() { - - @get:Rule - override var activityRule: ActivityTestRule = - ActivityTestRule(KiwixMainActivity::class.java) +class HelpFragmentTest : BaseActivityTest() { @Test fun verifyHelpActivity() { diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/intro/IntroFragmentTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/intro/IntroFragmentTest.kt index 588734f53..65a2d06a6 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/intro/IntroFragmentTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/intro/IntroFragmentTest.kt @@ -21,11 +21,8 @@ import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiT import org.junit.Test import org.kiwix.kiwixmobile.BaseActivityTest import org.kiwix.kiwixmobile.R -import org.kiwix.kiwixmobile.main.KiwixMainActivity -class IntroFragmentTest : BaseActivityTest() { - - override var activityRule = activityTestRule() +class IntroFragmentTest : BaseActivityTest() { @Test fun viewIsSwipeableAndNavigatesToMain() { diff --git a/app/src/androidTest/java/org/kiwix/kiwixmobile/main/TopLevelDestinationTest.kt b/app/src/androidTest/java/org/kiwix/kiwixmobile/main/TopLevelDestinationTest.kt index 0964ec729..c13066352 100644 --- a/app/src/androidTest/java/org/kiwix/kiwixmobile/main/TopLevelDestinationTest.kt +++ b/app/src/androidTest/java/org/kiwix/kiwixmobile/main/TopLevelDestinationTest.kt @@ -17,14 +17,20 @@ */ package org.kiwix.kiwixmobile.main +import androidx.core.content.edit +import androidx.preference.PreferenceManager import androidx.test.rule.ActivityTestRule -import org.junit.Rule import org.junit.Test +import org.kiwix.kiwixmobile.BaseActivityTest +import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil -class TopLevelDestinationTest { - @Rule - @JvmField - var activityTestRule = ActivityTestRule(KiwixMainActivity::class.java) +class TopLevelDestinationTest : BaseActivityTest() { + + override var activityRule: ActivityTestRule = activityTestRule { + PreferenceManager.getDefaultSharedPreferences(context).edit { + putBoolean(SharedPreferenceUtil.PREF_SHOW_INTRO, false) + } + } @Test fun testTopLevelDestination() { diff --git a/app/src/main/java/org/kiwix/kiwixmobile/di/modules/KiwixModule.kt b/app/src/main/java/org/kiwix/kiwixmobile/di/modules/KiwixModule.kt index 98f7352c1..4741fcba1 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/di/modules/KiwixModule.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/di/modules/KiwixModule.kt @@ -21,14 +21,15 @@ package org.kiwix.kiwixmobile.di.modules import android.content.Context import android.location.LocationManager import android.net.wifi.WifiManager +import android.net.wifi.p2p.WifiP2pManager import dagger.Module import dagger.Provides import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil +import org.kiwix.kiwixmobile.core.zim_manager.MountPointProducer import org.kiwix.kiwixmobile.di.KiwixScope import org.kiwix.kiwixmobile.zim_manager.Fat32Checker import org.kiwix.kiwixmobile.zim_manager.FileWritingFileSystemChecker import org.kiwix.kiwixmobile.zim_manager.MountFileSystemChecker -import org.kiwix.kiwixmobile.core.zim_manager.MountPointProducer @Module object KiwixModule { @@ -52,4 +53,12 @@ object KiwixModule { sharedPreferenceUtil, listOf(MountFileSystemChecker(mountPointProducer), FileWritingFileSystemChecker()) ) + + @Provides + @KiwixScope + // We are forced to use the nullable type because of a + // crash on our nightly builds running on an emulator API 27 + // See: https://github.com/kiwix/kiwix-android/issues/2488 + fun providesWiFiP2pManager(context: Context): WifiP2pManager? = + context.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager? } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/di/modules/ServiceModule.kt b/app/src/main/java/org/kiwix/kiwixmobile/di/modules/ServiceModule.kt index 8f41eb771..a61810662 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/di/modules/ServiceModule.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/di/modules/ServiceModule.kt @@ -23,8 +23,8 @@ import android.app.Service import android.content.Context import dagger.Module import dagger.Provides -import org.kiwix.kiwixlib.Library import org.kiwix.kiwixlib.JNIKiwixServer +import org.kiwix.kiwixlib.Library import org.kiwix.kiwixmobile.di.ServiceScope import org.kiwix.kiwixmobile.webserver.WebServerHelper import org.kiwix.kiwixmobile.webserver.wifi_hotspot.HotspotNotificationManager diff --git a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/SenderDevice.kt b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/SenderDevice.kt index 9c013237c..ec30d95b9 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/SenderDevice.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/SenderDevice.kt @@ -17,7 +17,7 @@ */ package org.kiwix.kiwixmobile.localFileTransfer -import android.app.Activity +import android.content.Context import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -45,7 +45,7 @@ import java.net.Socket private const val TIME_OUT = 15000 internal class SenderDevice( - private val activity: Activity, + private val context: Context, private val wifiDirectManager: WifiDirectManager, private val fileReceiverDeviceAddress: InetAddress ) { @@ -59,7 +59,7 @@ internal class SenderDevice( .forEachIndexed { fileIndex, fileItem -> try { Socket().use { socket -> - activity.contentResolver.openInputStream(fileItem?.fileUri!!).use { fileInputStream -> + context.contentResolver.openInputStream(fileItem?.fileUri!!).use { fileInputStream -> socket.bind(null) socket.connect( InetSocketAddress(hostAddress, WifiDirectManager.FILE_TRANSFER_PORT), diff --git a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/WifiDirectManager.kt b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/WifiDirectManager.kt index b8aa67c09..f8342256f 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/WifiDirectManager.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/localFileTransfer/WifiDirectManager.kt @@ -17,7 +17,6 @@ */ package org.kiwix.kiwixmobile.localFileTransfer -import android.app.Activity import android.content.BroadcastReceiver import android.content.Context import android.content.IntentFilter @@ -35,7 +34,7 @@ import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener import android.net.wifi.p2p.WifiP2pManager.PeerListListener import android.os.Build.VERSION import android.os.Build.VERSION_CODES -import android.os.Looper +import android.os.Looper.getMainLooper import android.util.Log import android.widget.Toast import androidx.lifecycle.LifecycleCoroutineScope @@ -59,9 +58,10 @@ import javax.inject.Inject */ @SuppressWarnings("MissingPermission", "ProtectedMemberInFinalClass") class WifiDirectManager @Inject constructor( - private val activity: Activity, + private val context: Context, private val sharedPreferenceUtil: SharedPreferenceUtil, - private val alertDialogShower: AlertDialogShower + private val alertDialogShower: AlertDialogShower, + private val manager: WifiP2pManager? ) : ChannelListener, PeerListListener, ConnectionInfoListener, P2pEventListener { var callbacks: Callbacks? = null @@ -74,11 +74,8 @@ class WifiDirectManager @Inject constructor( // Whether channel has retried connecting previously private var shouldRetry = true - // Overall manager of Wifi p2p connections for the module - private lateinit var manager: WifiP2pManager - // Interface to the device's underlying wifi-p2p framework - private lateinit var channel: Channel + private var channel: Channel? = null // For receiving the broadcasts given by above filter private lateinit var receiver: BroadcastReceiver @@ -94,8 +91,7 @@ class WifiDirectManager @Inject constructor( fun startWifiDirectManager(filesForTransfer: List) { this.filesForTransfer = filesForTransfer isFileSender = filesForTransfer.isNotEmpty() - manager = activity.getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager - channel = manager.initialize(activity, Looper.getMainLooper(), null) + channel = manager?.initialize(context, getMainLooper(), null) registerWifiDirectBroadcastReceiver() } @@ -110,20 +106,20 @@ class WifiDirectManager @Inject constructor( addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION) } - activity.registerReceiver(receiver, intentFilter) + context.registerReceiver(receiver, intentFilter) } - private fun unregisterWifiDirectBroadcastReceiver() = activity.unregisterReceiver(receiver) + private fun unregisterWifiDirectBroadcastReceiver() = context.unregisterReceiver(receiver) fun discoverPeerDevices() { - manager.discoverPeers(channel, object : ActionListener { + manager?.discoverPeers(channel, object : ActionListener { override fun onSuccess() { - activity.toast(R.string.discovery_initiated, Toast.LENGTH_SHORT) + context.toast(R.string.discovery_initiated, Toast.LENGTH_SHORT) } override fun onFailure(reason: Int) { - Log.d(TAG, "${activity.getString(R.string.discovery_failed)}: ${getErrorMessage(reason)}") - activity.toast(R.string.discovery_failed, Toast.LENGTH_SHORT) + Log.d(TAG, "${context.getString(R.string.discovery_failed)}: ${getErrorMessage(reason)}") + context.toast(R.string.discovery_failed, Toast.LENGTH_SHORT) } }) } @@ -132,7 +128,7 @@ class WifiDirectManager @Inject constructor( override fun onWifiP2pStateChanged(isEnabled: Boolean) { isWifiP2pEnabled = isEnabled if (!isWifiP2pEnabled) { - activity.toast(R.string.discovery_needs_wifi, Toast.LENGTH_SHORT) + context.toast(R.string.discovery_needs_wifi, Toast.LENGTH_SHORT) callbacks?.onConnectionToPeersLost() } Log.d(TAG, "WiFi P2P state changed - $isWifiP2pEnabled") @@ -141,14 +137,14 @@ class WifiDirectManager @Inject constructor( override fun onPeersChanged() { /* List of available peers has changed, so request & use the new list through * PeerListListener.requestPeers() callback */ - manager.requestPeers(channel, this) + manager?.requestPeers(channel, this) Log.d(TAG, "P2P peers changed") } override fun onConnectionChanged(isConnected: Boolean) { if (isConnected) { // Request connection info about the wifi p2p group formed upon connection - manager.requestConnectionInfo(channel, this) + manager?.requestConnectionInfo(channel, this) } else { // Not connected after connection change -> Disconnected callbacks?.onConnectionToPeersLost() @@ -167,9 +163,9 @@ class WifiDirectManager @Inject constructor( Log.d(TAG, "Channel lost, trying again") callbacks?.onConnectionToPeersLost() shouldRetry = false - manager.initialize(activity, Looper.getMainLooper(), this) + manager?.initialize(context, getMainLooper(), this) } else { - activity.toast(R.string.severe_loss_error, Toast.LENGTH_LONG) + context.toast(R.string.severe_loss_error, Toast.LENGTH_LONG) } } @@ -191,7 +187,7 @@ class WifiDirectManager @Inject constructor( FileTransferConfirmation(senderSelectedPeerDevice.deviceName), { hasSenderStartedConnection = true connect(senderSelectedPeerDevice) - activity.toast(R.string.performing_handshake, Toast.LENGTH_LONG) + context.toast(R.string.performing_handshake, Toast.LENGTH_LONG) }) } } @@ -201,15 +197,15 @@ class WifiDirectManager @Inject constructor( deviceAddress = senderSelectedPeerDevice.deviceAddress wps.setup = WpsInfo.PBC } - manager.connect(channel, config, object : ActionListener { + manager?.connect(channel, config, object : ActionListener { override fun onSuccess() { // UI updated from broadcast receiver } override fun onFailure(reason: Int) { val errorMessage = getErrorMessage(reason) - Log.d(TAG, activity.getString(R.string.connection_failed) + ": " + errorMessage) - activity.toast(R.string.connection_failed, Toast.LENGTH_LONG) + Log.d(TAG, context.getString(R.string.connection_failed) + ": " + errorMessage) + context.toast(R.string.connection_failed, Toast.LENGTH_LONG) } }) } @@ -232,7 +228,7 @@ class WifiDirectManager @Inject constructor( Log.d(TAG, "InetAddress is null") } onFileTransferAsyncTaskComplete(false) - activity.toast(R.string.connection_refused) + context.toast(R.string.connection_refused) } } } @@ -254,8 +250,8 @@ class WifiDirectManager @Inject constructor( Log.d(LocalFileTransferFragment.TAG, "Starting file transfer") val fileReceiverDeviceAddress = if (groupInfo.isGroupOwner) inetAddress else groupInfo.groupOwnerAddress - activity.toast(R.string.preparing_files, Toast.LENGTH_LONG) - val senderDevice = SenderDevice(activity, this, fileReceiverDeviceAddress) + context.toast(R.string.preparing_files, Toast.LENGTH_LONG) + val senderDevice = SenderDevice(context, this, fileReceiverDeviceAddress) val isFileSendSuccessfully = senderDevice.send(filesForTransfer) onFileTransferAsyncTaskComplete(isFileSendSuccessfully) if (BuildConfig.DEBUG) { @@ -277,8 +273,8 @@ class WifiDirectManager @Inject constructor( filesForTransfer[itemIndex].fileStatus = status callbacks?.onFileStatusChanged(itemIndex) if (status == FileStatus.ERROR) { - activity.toast( - activity.getString( + context.toast( + context.getString( R.string.error_transferring, filesForTransfer[itemIndex].fileName ) ) @@ -295,7 +291,7 @@ class WifiDirectManager @Inject constructor( } private fun disconnect() { - manager.removeGroup(channel, object : ActionListener { + manager?.removeGroup(channel, object : ActionListener { override fun onFailure(reasonCode: Int) { Log.d(TAG, "Disconnect failed. Reason: $reasonCode") closeChannel() @@ -310,7 +306,7 @@ class WifiDirectManager @Inject constructor( private fun closeChannel() { if (VERSION.SDK_INT >= VERSION_CODES.O_MR1) { - channel.close() + channel?.close() } } @@ -325,9 +321,9 @@ class WifiDirectManager @Inject constructor( private fun onFileTransferAsyncTaskComplete(wereAllFilesTransferred: Boolean) { if (wereAllFilesTransferred) { - activity.toast(R.string.file_transfer_complete, Toast.LENGTH_LONG) + context.toast(R.string.file_transfer_complete, Toast.LENGTH_LONG) } else { - activity.toast(R.string.error_during_transfer, Toast.LENGTH_LONG) + context.toast(R.string.error_during_transfer, Toast.LENGTH_LONG) } callbacks?.onFileTransferComplete() } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt index 9c5f097c3..974851185 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/main/KiwixMainActivity.kt @@ -32,6 +32,7 @@ import com.google.android.material.navigation.NavigationView import kotlinx.android.synthetic.main.activity_kiwix_main.bottom_nav_view import kotlinx.android.synthetic.main.activity_kiwix_main.drawer_nav_view import kotlinx.android.synthetic.main.activity_kiwix_main.navigation_container +import kotlinx.android.synthetic.main.activity_kiwix_main.reader_drawer_nav_view import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions import org.kiwix.kiwixmobile.core.di.components.CoreComponent @@ -48,6 +49,7 @@ class KiwixMainActivity : CoreMainActivity() { override val navController by lazy { findNavController(R.id.nav_host_fragment) } override val drawerContainerLayout: DrawerLayout by lazy { navigation_container } override val drawerNavView: NavigationView by lazy { drawer_nav_view } + override val readerTableOfContentsDrawer: NavigationView by lazy { reader_drawer_nav_view } override val bookmarksFragmentResId: Int = R.id.bookmarksFragment override val settingsFragmentResId: Int = R.id.kiwixSettingsFragment override val historyFragmentResId: Int = R.id.historyFragment diff --git a/app/src/main/java/org/kiwix/kiwixmobile/webserver/WebServerHelper.java b/app/src/main/java/org/kiwix/kiwixmobile/webserver/WebServerHelper.java index 65b5178b3..e7a5e2463 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/webserver/WebServerHelper.java +++ b/app/src/main/java/org/kiwix/kiwixmobile/webserver/WebServerHelper.java @@ -26,8 +26,8 @@ import java.util.ArrayList; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import org.kiwix.kiwixlib.JNIKiwixException; -import org.kiwix.kiwixlib.Library; import org.kiwix.kiwixlib.JNIKiwixServer; +import org.kiwix.kiwixlib.Library; import org.kiwix.kiwixmobile.core.utils.ServerUtils; import org.kiwix.kiwixmobile.webserver.wifi_hotspot.IpAddressCallbacks; diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/ZimManageViewModel.kt b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/ZimManageViewModel.kt index 230a40d33..d62827fe2 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/ZimManageViewModel.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zim_manager/ZimManageViewModel.kt @@ -73,7 +73,6 @@ import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.Li import java.util.LinkedList import java.util.Locale import java.util.concurrent.TimeUnit.MILLISECONDS -import java.util.concurrent.TimeUnit.SECONDS import javax.inject.Inject class ZimManageViewModel @Inject constructor( @@ -218,18 +217,15 @@ class ZimManageViewModel @Inject constructor( connectivityBroadcastReceiver.networkStates.distinctUntilChanged().filter( CONNECTED::equals ), - BiFunction { _, _ -> Unit } + BiFunction { _, _ -> } ) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .subscribe( { kiwixService.library - .timeout(60, SECONDS) .retry(5) - .subscribe( - library::onNext - ) { + .subscribe(library::onNext) { it.printStackTrace() library.onNext(LibraryNetworkEntity().apply { book = LinkedList() }) } diff --git a/app/src/main/res/values-b+roa+tara/strings.xml b/app/src/main/res/values-b+roa+tara/strings.xml index acb28b141..83650607d 100644 --- a/app/src/main/res/values-b+roa+tara/strings.xml +++ b/app/src/main/res/values-b+roa+tara/strings.xml @@ -6,4 +6,6 @@ \'U file system tune non ge supporte le file cchiù granne de 4GB Stoche a condrolle ce \'u file system tune pò ccrejà le file cchiù granne de 4GB Aprture d‘u fail sciute a male\nPe piacere pruève arrete a cercà stu fail jndr’à Schede d\'u despositive d\'a libbreria toje. + Manne le file + Pigghie le file diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 14ff510e7..f16642d9a 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -6,4 +6,6 @@ Su sistema de documentos (file system) tuo non suportat documentos prus mannos de 4GB Verifichende si su sistema de documentos podet creare documentos de 4GB Abertura de su documentu fallida\nPro praghere proa a chircare custu documentu in s\'Ischeda de sos Dispositivos de sa Biblioteca tua + Imbia documentos + Retzi documentos diff --git a/buildSrc/src/main/kotlin/Libs.kt b/buildSrc/src/main/kotlin/Libs.kt index 083903f97..feae21060 100644 --- a/buildSrc/src/main/kotlin/Libs.kt +++ b/buildSrc/src/main/kotlin/Libs.kt @@ -326,7 +326,7 @@ object Libs { Versions.xfetch2okhttp /** - * http://assertj.org + * https://assertj.github.io/doc/ */ const val assertj_core: String = "org.assertj:assertj-core:" + Versions.assertj_core diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 54aca62e1..edbd9d1bb 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,4 +1,3 @@ -import kotlin.String import org.gradle.plugin.use.PluginDependenciesSpec import org.gradle.plugin.use.PluginDependencySpec @@ -12,35 +11,35 @@ import org.gradle.plugin.use.PluginDependencySpec * YOU are responsible for updating manually the dependency version. */ object Versions { - const val org_jetbrains_kotlinx_kotlinx_coroutines: String = "1.3.9" + const val org_jetbrains_kotlinx_kotlinx_coroutines: String = "1.4.1" - const val androidx_test_espresso: String = "3.2.0" // available: "3.3.0" + const val androidx_test_espresso: String = "3.3.0" const val com_squareup_retrofit2: String = "2.9.0" const val com_squareup_okhttp3: String = "4.9.0" - const val org_jetbrains_kotlin: String = "1.3.72" // available: "1.4.10" + const val org_jetbrains_kotlin: String = "1.4.20" - const val androidx_navigation: String = "2.3.0" + const val androidx_navigation: String = "2.3.1" - const val com_google_dagger: String = "2.28.3" // available: "2.29.1" + const val com_google_dagger: String = "2.29.1" const val com_yahoo_squidb: String = "2.0.0" // available: "3.2.3" - const val com_jakewharton: String = "10.2.2" // available: "10.2.3" + const val com_jakewharton: String = "10.2.3" - const val androidx_test: String = "1.2.0" // available: "1.3.0" + const val androidx_test: String = "1.3.0" - const val io_objectbox: String = "2.7.0" // available: "2.7.1" + const val io_objectbox: String = "2.8.1" const val org_jacoco: String = "0.7.9" - const val io_mockk: String = "1.10.0" // available: "1.10.2" + const val io_mockk: String = "1.10.2" const val android_arch_lifecycle_extensions: String = "1.1.1" - const val com_android_tools_build_gradle: String = "4.0.1" // available: "4.0.2" + const val com_android_tools_build_gradle: String = "4.0.1" // available: "4.1.1" const val de_fayard_buildsrcversions_gradle_plugin: String = "0.7.0" @@ -50,29 +49,29 @@ object Versions { const val ink_page_indicator: String = "1.3.0" - const val leakcanary_android: String = "2.4" // available: "2.5" + const val leakcanary_android: String = "2.5" - const val constraintlayout: String = "1.1.3" // available: "2.0.2" + const val constraintlayout: String = "2.0.4" const val collection_ktx: String = "1.1.0" const val preference_ktx: String = "1.1.1" - const val junit_jupiter: String = "5.6.2" // available: "5.7.0" + const val junit_jupiter: String = "5.7.0" const val xfetch2okhttp: String = "3.1.5" - const val assertj_core: String = "3.16.1" // available: "3.17.2" + const val assertj_core: String = "3.18.1" const val core_testing: String = "2.1.0" const val fragment_ktx: String = "1.2.5" - const val lint_gradle: String = "27.0.1" // available: "27.0.2" + const val lint_gradle: String = "27.1.1" const val testing_ktx: String = "1.1.2" - const val threetenabp: String = "1.2.4" + const val threetenabp: String = "1.3.0" const val uiautomator: String = "2.2.0" @@ -84,11 +83,11 @@ object Versions { const val rxandroid: String = "2.1.1" - const val core_ktx: String = "1.3.1" // available: "1.3.2" + const val core_ktx: String = "1.3.2" - const val kiwixlib: String = "9.4.0" + const val kiwixlib: String = "9.4.1" - const val material: String = "1.2.0" // available: "1.2.1" + const val material: String = "1.2.1" const val multidex: String = "2.0.1" @@ -98,22 +97,22 @@ object Versions { const val jsr305: String = "3.0.2" - const val ktlint: String = "0.36.0" // available: "0.39.0" + const val ktlint: String = "0.39.0" - const val rxjava: String = "2.2.19" // available: "2.2.20" + const val rxjava: String = "2.2.20" - const val webkit: String = "1.2.0" // available: "1.3.0" + const val webkit: String = "1.3.0" - const val aapt2: String = "4.0.1-6197926" // available: "4.0.2-6197926" + const val aapt2: String = "4.1.1-6503028" - const val junit: String = "1.1.1" // available: "1.1.2" + const val junit: String = "1.1.2" /** * Current version: "6.2" * See issue 19: How to update Gradle itself? * https://github.com/jmfayard/buildSrcVersions/issues/19 */ - const val gradleLatestVersion: String = "6.6.1" + const val gradleLatestVersion: String = "6.7.1" } /** diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/CoreApp.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/CoreApp.kt index 2143bbe91..c99a56df0 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/CoreApp.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/CoreApp.kt @@ -65,8 +65,8 @@ abstract class CoreApp : Application() { * The init of this class does the work of initializing, * simply injecting it is all that there is to be done */ - // @Inject - // lateinit var serviceWorkerInitialiser: ServiceWorkerInitialiser + @Inject + lateinit var serviceWorkerInitialiser: ServiceWorkerInitialiser override fun attachBaseContext(base: Context) { super.attachBaseContext(base) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt index 7feba240b..cc6b436ef 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/di/modules/NetworkModule.kt @@ -32,15 +32,19 @@ import javax.inject.Singleton private const val CONNECTION_TIMEOUT = 10L private const val READ_TIMEOUT = 60L +private const val CALL_TIMEOUT = 60L private const val USER_AGENT = "kiwix-android-version:${BuildConfig.VERSION_CODE}" private const val KIWIX_DOWNLOAD_URL = "http://mirror.download.kiwix.org/" @Module class NetworkModule { @Provides @Singleton fun provideOkHttpClient(): OkHttpClient { - return OkHttpClient().newBuilder().followRedirects(true).followSslRedirects(true) + return OkHttpClient().newBuilder() + .followRedirects(true) + .followSslRedirects(true) .connectTimeout(CONNECTION_TIMEOUT, SECONDS) .readTimeout(READ_TIMEOUT, SECONDS) + .callTimeout(CALL_TIMEOUT, SECONDS) .addNetworkInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) BASIC else NONE }) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/entity/LibraryNetworkEntity.java b/core/src/main/java/org/kiwix/kiwixmobile/core/entity/LibraryNetworkEntity.java index 5c6f93aa9..6953de8d1 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/entity/LibraryNetworkEntity.java +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/entity/LibraryNetworkEntity.java @@ -25,7 +25,7 @@ import org.simpleframework.xml.Attribute; import org.simpleframework.xml.ElementList; import org.simpleframework.xml.Root; -@Root(name = "library", strict = false) +@Root(name = "library") public class LibraryNetworkEntity { @ElementList(name = "book", inline = true, required = false) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt index 19c96942e..1696e0018 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreMainActivity.kt @@ -28,6 +28,8 @@ import androidx.appcompat.widget.Toolbar import androidx.core.net.toUri import androidx.core.os.bundleOf import androidx.drawerlayout.widget.DrawerLayout +import androidx.drawerlayout.widget.DrawerLayout.LOCK_MODE_LOCKED_CLOSED +import androidx.drawerlayout.widget.DrawerLayout.LOCK_MODE_UNLOCKED import androidx.fragment.app.Fragment import androidx.navigation.NavController import androidx.navigation.NavDestination @@ -66,6 +68,7 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { abstract val navController: NavController abstract val drawerContainerLayout: DrawerLayout abstract val drawerNavView: NavigationView + abstract val readerTableOfContentsDrawer: NavigationView abstract val bookmarksFragmentResId: Int abstract val settingsFragmentResId: Int abstract val historyFragmentResId: Int @@ -109,6 +112,14 @@ abstract class CoreMainActivity : BaseActivity(), WebViewProvider { if (destination.id !in topLevelDestinations) { handleDrawerOnNavigation() } + readerTableOfContentsDrawer.setLockMode( + if (destination.id == readerFragmentResId) LOCK_MODE_UNLOCKED + else LOCK_MODE_LOCKED_CLOSED + ) + } + + private fun NavigationView.setLockMode(lockMode: Int) { + drawerContainerLayout.setDrawerLockMode(lockMode, this) } override fun onRequestPermissionsResult( diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.java b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.java index d6d110ac9..9fab81278 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.java +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreReaderFragment.java @@ -123,6 +123,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldCall; import static org.kiwix.kiwixmobile.core.base.FragmentActivityExtensions.Super.ShouldNotCall; import static org.kiwix.kiwixmobile.core.downloader.fetch.FetchDownloadNotificationManagerKt.DOWNLOAD_NOTIFICATION_TITLE; +import static org.kiwix.kiwixmobile.core.main.ServiceWorkerUninitialiserKt.UNINITIALISER_ADDRESS; import static org.kiwix.kiwixmobile.core.page.history.adapter.HistoryListItem.HistoryItem; import static org.kiwix.kiwixmobile.core.utils.AnimationUtils.rotate; import static org.kiwix.kiwixmobile.core.utils.ConstantsKt.REQUEST_STORAGE_PERMISSION; @@ -743,6 +744,12 @@ public abstract class CoreReaderFragment extends BaseFragment AttributeSet attrs = StyleUtils.getAttributes(requireActivity(), R.xml.webview); KiwixWebView webView = createWebView(attrs); loadUrl(url, webView); + setUpWithTextToSpeech(webView); + documentParser.initInterface(webView); + new ServiceWorkerUninitialiser(() -> { + openMainPage(); + return Unit.INSTANCE; + }).initInterface(webView); return webView; } @@ -762,10 +769,20 @@ public abstract class CoreReaderFragment extends BaseFragment return newTab(contentUrl(zimReaderContainer.getMainPage())); } - protected KiwixWebView newTab(String url) { + private KiwixWebView newTab(String url) { + return newTab(url, true); + } + + private void newTabInBackground(String url) { + newTab(url, false); + } + + private KiwixWebView newTab(String url, boolean selectTab) { KiwixWebView webView = initalizeWebView(url); webViewList.add(webView); - selectTab(webViewList.size() - 1); + if(selectTab) { + selectTab(webViewList.size() - 1); + } tabsAdapter.notifyDataSetChanged(); setUpWebViewWithTextToSpeech(); if (webView != null) { @@ -774,14 +791,6 @@ public abstract class CoreReaderFragment extends BaseFragment return webView; } - private void newTabInBackground(String url) { - KiwixWebView webView = initalizeWebView(url); - webViewList.add(webView); - tabsAdapter.notifyDataSetChanged(); - setUpWebViewWithTextToSpeech(); - documentParser.initInterface(webView); - } - private void closeTab(int index) { tempZimFileForUndo = zimReaderContainer.getZimFile(); tempWebViewForUndo = webViewList.get(index); @@ -816,7 +825,7 @@ public abstract class CoreReaderFragment extends BaseFragment tabsAdapter.notifyDataSetChanged(); Snackbar.make(snackbarRoot, R.string.tab_restored, Snackbar.LENGTH_SHORT).show(); - setUpWebViewWithTextToSpeech(); + setUpWithTextToSpeech(tempWebViewForUndo); updateBottomToolbarVisibility(); contentFrame.addView(tempWebViewForUndo); } @@ -1048,7 +1057,7 @@ public abstract class CoreReaderFragment extends BaseFragment if (mainMenu != null) { mainMenu.onFileOpened(urlIsValid()); } - openMainPage(); + openArticle(UNINITIALISER_ADDRESS); safeDispose(); bookmarkingDisposable = Flowable.combineLatest( newBookmarksDao.bookmarkUrlsForCurrentBook(zimFileReader), @@ -1305,8 +1314,8 @@ public abstract class CoreReaderFragment extends BaseFragment openArticle(articleUrl); } - private void setUpWebViewWithTextToSpeech() { - if (tts != null) tts.initWebView(getCurrentWebView()); + private void setUpWithTextToSpeech(KiwixWebView kiwixWebView) { + tts.initWebView(kiwixWebView); } @OnClick(R2.id.activity_main_back_to_top_fab) diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreWebViewClient.java b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreWebViewClient.java index cb2762fee..ea42552fb 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreWebViewClient.java +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/CoreWebViewClient.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.net.Uri; import android.util.Log; import android.webkit.MimeTypeMap; +import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; @@ -42,6 +43,7 @@ public class CoreWebViewClient extends WebViewClient { protected final WebViewCallback callback; protected final ZimReaderContainer zimReaderContainer; private static String[] LEGACY_CONTENT_PREFIXES = new String[] { + "zim://content/", Uri.parse("content://" + CoreApp.getInstance().getPackageName() + ".zim.base/").toString() }; private String urlWithAnchor; @@ -67,10 +69,6 @@ public class CoreWebViewClient extends WebViewClient { if (url.startsWith(CONTENT_PREFIX)) { return handleEpubAndPdf(url); } - if (url.startsWith("file://")) { - // To handle home page (loaded from resources) - return true; - } if (url.startsWith("javascript:")) { // Allow javascript for HTML functions and code execution (EX: night mode) return true; @@ -116,8 +114,7 @@ public class CoreWebViewClient extends WebViewClient { @Override public void onPageFinished(WebView view, String url) { - boolean invalidUrl = - url.equals(CONTENT_PREFIX + "null"); + boolean invalidUrl = url.equals(CONTENT_PREFIX + "null"); Log.d(TAG_KIWIX, "invalidUrl = " + invalidUrl); @@ -142,12 +139,15 @@ public class CoreWebViewClient extends WebViewClient { @Nullable @Override - public WebResourceResponse shouldInterceptRequest(WebView view, String url) { - url = convertLegacyUrl(url); + public WebResourceResponse shouldInterceptRequest( + WebView view, + WebResourceRequest request) + { + String url = convertLegacyUrl(request.getUrl().toString()); if (url.startsWith(CONTENT_PREFIX)) { return zimReaderContainer.load(url); } else { - return super.shouldInterceptRequest(view, url); + return super.shouldInterceptRequest(view, request); } } } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/main/ServiceWorkerUninitialiser.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/main/ServiceWorkerUninitialiser.kt new file mode 100644 index 000000000..60785b942 --- /dev/null +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/main/ServiceWorkerUninitialiser.kt @@ -0,0 +1,85 @@ +/* + * Kiwix Android + * Copyright (c) 2020 Kiwix + * 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 . + * + */ + +package org.kiwix.kiwixmobile.core.main + +import android.os.Handler +import android.os.Looper +import android.webkit.JavascriptInterface +import android.webkit.WebView + +const val UNINITIALISER_ADDRESS = "A/remove_service_workers.html" +private const val UNINITIALISER_INTERFACE = "ServiceWorkerUninitialiser" +const val UNINITIALISE_HTML = """ + + + + + +
+ + + + + + + + + +
+ + +""" + +class ServiceWorkerUninitialiser(val onUninitialisedAction: () -> Unit) { + + fun initInterface(webView: WebView) { + webView.addJavascriptInterface(this, UNINITIALISER_INTERFACE) + } + + @JavascriptInterface + fun onUninitialised() { + Handler(Looper.getMainLooper()).post { onUninitialisedAction() } + } +} diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimFileReader.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimFileReader.kt index 656abd676..c6afb6923 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimFileReader.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimFileReader.kt @@ -33,6 +33,8 @@ import org.kiwix.kiwixlib.Pair import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.NightModeConfig import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book +import org.kiwix.kiwixmobile.core.main.UNINITIALISER_ADDRESS +import org.kiwix.kiwixmobile.core.main.UNINITIALISE_HTML import org.kiwix.kiwixmobile.core.reader.ZimFileReader.Companion.CONTENT_PREFIX import org.kiwix.kiwixmobile.core.search.SearchSuggestion import org.kiwix.kiwixmobile.core.utils.files.FileUtils @@ -136,7 +138,10 @@ class ZimFileReader constructor( fun getRedirect(url: String) = "${toRedirect(url)}" fun isRedirect(url: String) = - url.startsWith(CONTENT_PREFIX) && url != getRedirect(url) + when { + getRedirect(url).isEmpty() || url.endsWith(UNINITIALISER_ADDRESS) -> false + else -> url.startsWith(CONTENT_PREFIX) && url != getRedirect(url) + } private fun toRedirect(url: String) = "$CONTENT_PREFIX${jniKiwixReader.checkUrl(url.toUri().filePath)}".toUri() @@ -176,11 +181,15 @@ class ZimFileReader constructor( Completable.fromAction { try { outputStream.use { - getContentAndMimeType(uri).let { (content: ByteArray, mimeType: String) -> - if ("text/css" == mimeType && nightModeConfig.isNightModeActive()) { - it.write(INVERT_IMAGES_VIDEO.toByteArray(Charsets.UTF_8)) + if (uri.endsWith(UNINITIALISER_ADDRESS)) { + it.write(UNINITIALISE_HTML.toByteArray()) + } else { + getContentAndMimeType(uri).let { (content: ByteArray, mimeType: String) -> + if ("text/css" == mimeType && nightModeConfig.isNightModeActive()) { + it.write(INVERT_IMAGES_VIDEO.toByteArray()) + } + it.write(content) } - it.write(content) } } } catch (ioException: IOException) { @@ -236,7 +245,7 @@ class ZimFileReader constructor( @JvmField val UI_URI: Uri? = Uri.parse("content://org.kiwix.ui/") - const val CONTENT_PREFIX = "zim://content/" + const val CONTENT_PREFIX = "https://kiwix.app/" private val INVERT_IMAGES_VIDEO = """ diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimReaderContainer.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimReaderContainer.kt index 5b47c52a6..f03c616e8 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimReaderContainer.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/reader/ZimReaderContainer.kt @@ -24,9 +24,7 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class ZimReaderContainer @Inject constructor( - private val zimFileReaderFactory: Factory -) { +class ZimReaderContainer @Inject constructor(private val zimFileReaderFactory: Factory) { var zimFileReader: ZimFileReader? = null set(value) { field?.dispose() diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CoreSettingsFragment.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CoreSettingsFragment.kt index c3faaf935..9da75871d 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CoreSettingsFragment.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/settings/CoreSettingsFragment.kt @@ -28,11 +28,12 @@ import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.base.BaseFragment abstract class CoreSettingsFragment : BaseFragment() { - + private lateinit var prefsFragment: Fragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + prefsFragment = createPreferenceFragment() requireActivity().supportFragmentManager - .beginTransaction().replace(R.id.content_frame, createPreferenceFragment()) + .beginTransaction().replace(R.id.content_frame, prefsFragment) .commit() setUpToolbar() } @@ -52,4 +53,12 @@ abstract class CoreSettingsFragment : BaseFragment() { activity.supportActionBar!!.setHomeButtonEnabled(true) activity.supportActionBar!!.setDisplayHomeAsUpEnabled(true) } + + override fun onDestroyView() { + requireActivity().supportFragmentManager + .beginTransaction() + .remove(prefsFragment) + .commitNowAllowingStateLoss() + super.onDestroyView() + } } diff --git a/core/src/main/res/values-diq/strings.xml b/core/src/main/res/values-diq/strings.xml index a28aabdc5..57258631f 100644 --- a/core/src/main/res/values-diq/strings.xml +++ b/core/src/main/res/values-diq/strings.xml @@ -29,6 +29,7 @@ Gıre xıldayışo newe de abo? Kanalê xızmeti Hotspot Serkewtışê hotspoti nêbiyo + Hotspotê şıma xora akerde aseno. Dewma kerdışi rê kerem kerê nuqtay resayışê Wi-Fi dewre ra vecê. Ravêrê eyaranê Wi-Fi Gırebiyayış biyo red Hotspoto gureyneyino @@ -43,12 +44,14 @@ Server gureyneyino Telimatê meymandariya kıtaban Gırey Wi-fi tesbit biya + Kıtabanê cihazanê binan mocnayışi rê gani cihazi pêro wa eyni torra Wi-Fi ya gıre bıbê Seba ena xısusiyeti gureynayışi rê gani veri hotspotê WIFI peydeatana akerê ya zi esas cihaz u gırote cihazi eyni torra Wi-Fi gırebiyayışê cı kontrol kerê. RAVÊR Şİ Heqa Hotspot/server eleqeyın rocaney . Kiwix Hotspot Serveri serkewtış Serveri vındardış + Seba resayışê serverê %s re browseri rê ena adresê ip cı kerê Xeta: Dosyaya ZIMia weçinıtiye nêvêniye. Dosyay Zimi nêabiyena Xeta: Dosyaya weçinıtiye yew dosyaya ZIMia vêrdiye niya. @@ -80,6 +83,7 @@ Bestere Bıtexelne Cıgeyrayışo peyên wedariya + Zerrey nê meqaley vinayışi rê peta hetê çepiya xuz kerê Mı fehm kerd Şıma zanenê? Peyser biya @@ -99,6 +103,7 @@ Meqale tabê neweyi de bi a Kiwix\'i cıgeyre Serva cıgeyrayışi %s vacê + Malesef, cihazê şımayo dekerderê qısekerdışi rê desteg nêdano Cihaz Online Kıtıbxane @@ -113,10 +118,18 @@ Videoyi çıniyê Gıreyê torre çıniyo Kiwix se keno ? + Kiwix offline wanayoğê zerrekiyo. Eyni zey browserê torro lakin pelanê webi vera online resayışi, zerrekê dosyayan formatê ZIMi de waneno. + Kiwix normalde Wikipedia offline wanayışi rê dizayn biya lakin zerrekê online zi şeno bıwano. Zerrek kam ca de yo? Zerrekê ma pela websita Kiwixi de yo. + Zey dosyayanê ZIMi benê. İnan ra zeder estê : + • Wikipedia seba herg zıwani weziyetê gureynayışi dera. + • Çımey zey Wikileaks yana Wikiçıme enewke weziyetê gureynayışi derê. + Weçinyayey dosyay ZIMi zerrey aplikasyoni de roniyenê yana waştenanê ho verê transferê SD kart kerdışi şenê komputeri ra desktopi ra ronê + Zerrey aplikasyon miyan de roniyaye dosyay ZIM dosyaları cihazê depoy teberi de be namey klasorê sernamey Kiwix dero Depo kerdış Klasoro Mewcud + Malesef ma nêşa tay dosyayan esterê. Belka şıma şenê yew idarekari ra peşti bıgêrê. bıvındarne devam kerê bıvındarne @@ -127,8 +140,13 @@ Wa ronayış vındero? Şıma qayılê nê ronayışi vındarne? Weçinoğê cihazê depokerdışi + Seba na dosyay ZIM tetbiqiya wanayışê metini hewl niya + Metin ra wanayıi sernêkewto. Reyna bıcerrebnê + Metin ra wanayışi de xeta. Reyna bıcerrebnê Bahdoyên Verên + Zerrek wa torra mobiliya gureynayışiya roneyo? + Eger ke şıma “Eya”\'içy weçinê se şıma do bahdo iqaz nêvinê. Lakin Eyaran ra tım zi şıma şenê eney bıvurnê Zerreki teyna pê Wifi ya rone roce sa @@ -138,12 +156,15 @@ Ewro Vızêr Gırey teberi cıkerdış de iqaz bıde + Ekstra ucret ya zi gırey offline nêgureyê se akerde teqa mocnayışiya iqaz bıdê. Gıreyê teberi beno cı! + Şımayê kenê ke şırê gırey teberi. No seba transferê ekstra ucreta tabiyo yana weziyetê offline de nêgureniyeno. Şıma qayılê dewam bıkerê? Endi meperse Weçinaye zıwan : Zıwano bin: Karneyaye obce çıniyo Ey… No teneyê ariyeya + Ze ke ma kewte.\n\nMelumatê cêri rışiyayışa nê problemi baş kerdışi rê şenê peşti bıdê? Eyarê zıwanê şıma Lista Dosyayanê Zıme Şıma Detayê Rızyayışi @@ -186,6 +207,7 @@ Note Serekê Meqaley Wiki Serva nota resayışê depoyê ganşyoı + Noti mısadey resayışê depoy nêbo se nêgureniyeno Qeyd kerdışê noti nêbiyo Not esteriyaya Not nêesteriyê @@ -203,22 +225,37 @@ Kaşır nêşayo Xetaya gıran! WiFi P2P\'yi Dewre ra vec/Retnanaltiv kerê bıcerrebnê Gıreyin nêbiya + Cihazê takêşan ra ferq bıyayışi rê terefê Androidi ra mısadey mehali ganiyo. + Dosyayanê ZIMi darênayışê aplikasyoni rê terefê Androidi ra mısadey mehali ganiyo. + Bêmısadey mehali cihazanê takêşi nêvineyênê + Bêmısadey depo kerdışi nêresiyeno dosyayanê ZIMi + Taypêyan his kerdışi rê seba mısade dayışi mehali aktiv kerê + Servisê mehali taypêyi nêvineyênê + WiFi P2P\'yi eyaranê sistemi ra aktiv ke + WiFi AKERDE nêbo se tekê cı keşf nêbeno %s ya wa dosya transfer vo? + Weçineyaye cihazo seba transferi piya nêguriyeno Transferê dosya biyo temam + Çerğa transferi de yew xeta veciyê + Dosyay %s transfer kerdış de xeta veciyê + Cihazê nezdiy ra zerrek bıgêrê Zey pêyan cıgeyre Cihazê Şıma: NEZDI CİHAZİ + Cihaz nêvineya. Reyna cerbnayışi rê maka cıgeyrayışi bıploğne TRANSFERÊ DOSYAYAN Keno ke dosyaya transfer kero… Dest dano destan… Weziyet Meqaleya pêroyın de nota pêroyın pak ke Nota pêroyın pak ke + Ebatê metin %25 zeydnayışana bıvurnê Resım Video Teyna metin Metino kılm İcazetê depoy red biyo + Aplikasyoni seba gurenayışê depoy rê hunerê wanayışi icab keno Şo eyaranê Hotspoti Neticeyi çıniyê Nişani çıniyê @@ -234,6 +271,7 @@ Rapora teşhisi bırışê Detayê Sistemê Dosya Rapora Teşhisi + Problemi fahm kerdışi rê detayanê cêrêna pêroyın kontrol kerê %d%% Nazdiyiya metini Taba newiye de ake @@ -244,4 +282,5 @@ Antergey akerê Antergey bıqefelne Zerrek seni rocane beno? + Seba rocane kerdışê zerreki (yu dosyay zimi), etni zerrekiya versiyonê tewr peyêni ronayış ganiyo. Ney kışta ronayışi ra şenê bıkerê. diff --git a/core/src/main/res/values-sc/strings.xml b/core/src/main/res/values-sc/strings.xml index 27b13278a..ee81ce66c 100644 --- a/core/src/main/res/values-sc/strings.xml +++ b/core/src/main/res/values-sc/strings.xml @@ -27,6 +27,7 @@ Aviamentu de s\'hotspot fallidu Paret chi s\'hotspot tuo siat allutu. Pro praghere disabìlita s\'hotspot wifi tuo pro sighire. Bae a sas impostatziones de su WIFI + Connessione negada. Hotspot ativu In antis ischerta libros Aviamentu de su servidore fallidu. Pro praghere allughe s\'hotspot tuo @@ -221,6 +222,7 @@ Faddina manna! Proa a Disabilitare/Torrare a abilitare su P2P WiFi Connessione fallida Android tenet bisòngiu de su permissu de localizatzione pro rilevare dispositivos pares (peers) + Android tenet bisòngiu de su permissu de localizatzione pro permìtere a s\'aplicatzione de istrangiare documentos Zim Impossìbile localizare dispositivos pares (peers) chene sos permissos de localizatzione Impossìbile tènnere atzessu a sos documentos zim chene su permissu de archiviatzione Abìlita sa localizatzione pro permìtere su rilevamentu de pares (peers) @@ -243,6 +245,7 @@ Istadu Iscantzella totu sas notas in totu sos artìculos Iscantzella totu sas notas + Càmbia sa mannària de su testu cun ismanniamentos de su 25%. Immàgine Vìdeu Testu ebbia @@ -267,4 +270,13 @@ Pro praghere imbia totu sos detàllios chi sighent, in manera chi amus a pòdere diagnosticare su problema %d%% Ismanniamentu de su testu + Aberi in un\'ischeda noa + Leghidore + Perunu libru abertu + Aberi sa biblioteca + Ischeda ripristinada + Aberi su pannellu + Serra su pannellu + Comente agiornare su cuntenutu? + Pro agiornare su cuntenutu (unu documentu zim) tenes bisòngiu de iscarrigare s\'ùtrima versione intrea de su matessi cuntenutu. Lu podes fàghere pro mèdiu de sa setzione de iscarrigamentu. diff --git a/core/src/main/res/values-skr/strings.xml b/core/src/main/res/values-skr/strings.xml new file mode 100644 index 000000000..08425ccf8 --- /dev/null +++ b/core/src/main/res/values-skr/strings.xml @@ -0,0 +1,90 @@ + + + + مدد + گھر + ترتیباں + ورقے وچ لبھو + بک مارک + کُݨے نال چوݨواں مضمون + پوری سکرین + پوری سکرین توں نکلو + اُچی آواز نال پڑھو + میڈیا بچاؤ + ڳولو + ڈسپلے + معلومات + ورژن + رات آلا مزاج + واپس اُتے ون٘ڄو + زبان + زبان چݨو + ایہ ائٹم مٹاؤں؟ + تاریخچہ مٹاؤ + ساری تاریخ صاف کروں؟ + شیئر + مٹاؤ + منسوخ + گھن گھندا + بھلا تساں ڄاݨدے ہو؟ + واپس + ٹیب بند تھی ڳئی + بک مارک شامل تھی ڳیا + کو، شکریہ + بعد وچ + کھولو + فالتو + کیوکس وچ ڳولو + مشین، ڈیوائس + آن لائن + لائبریری + اتھ کوئی فائلاں کائنی + ڈاؤن لوڈ + سادہ + ویڈیو کائنی + کِوِکس کیا کریندے؟ + ذخیرہ + حالیہ فولڈر + جمبو، اجھکو + ولدا شروع کرو + اختتام + اندرونی + ٻاہر آلا + ڄیا + کو + ڈاؤن لوڈ روکوں؟ + اڳلا + پچھلا + ݙینہ + گھ + منٹ + سیک + باقی + اڄ + کل + چُݨیاں ہویاں زباناں: + ٻیاں زباناں: + نویں ٹیب + شروع کرو + ودھاؤ + تاریخ + وچار ہیٹھ + تھیندا پئے + مکمل + جمب ڳیا + بچاؤ + نوٹ + حیثیت + تصویر + وڈیو + صرف عبارت + بک مارک کائنی + آن + بند + خود بخود + مفت لائبریری + دراز کھولو + دراز بند کرو + diff --git a/core/src/main/res/values-sv/strings.xml b/core/src/main/res/values-sv/strings.xml index 9b2e4212c..e92faa056 100644 --- a/core/src/main/res/values-sv/strings.xml +++ b/core/src/main/res/values-sv/strings.xml @@ -31,6 +31,7 @@ Misslyckades att starta surfpunkt Det verkar som att din surfpunkt redan är aktiverad. Var god inaktivera din WiFi-surfpunkt för att fortsätta. Gå till WiFi-inställningar + Anslutning vägrades. Aktiv surfpunkt Välj böcker först Kunde inte starta server. Var god aktivera din surfpunkt @@ -220,15 +221,25 @@ Raderade hela anteckningsmappen Vissa filer raderades inte %d bok/böcker + Inleder upptäckt + Upptäckt misslyckades Allvarligt fel! Testa att starta om WiFi P2P Anslutning misslyckades + Platsåtkomst krävs från Android för att låta appen söka efter närliggande enheter. + Platsåtkomst krävs från Android för att låta appen hantera Host Zim-filer. + Kan inte hitta närliggande enheter utan platsåtkomst. Kan inte komma åt zim-filer utan lagringsbehörighet + Aktivera plats för att tillåta sökning efter närliggande enheter + Kan inte hitta närliggande enheter utan platstjänster Aktivera WiFi P2P i systeminställningar + Kan inte hitta närliggande enheter utan WiFi Överför filer till %s? + Valda enheter samarbetar inte för överföring Filöverföring slutfördes Ett fel uppstod under överförning Fel uppstod när filen %s överfördes Hämta innehåll från enheter i närheten + Sök efter enheter Din enhet: ENHETER I NÄRHETEN Inga enheter hittades. Tryck på sökknappen för att söka igen. @@ -238,6 +249,7 @@ Status Rensar alla anteckningar på alla artiklar Rensa alla anteckningar + Ändra textstorlek med steg på 25%. Bild Video Endast text diff --git a/core/src/test/java/org/kiwix/kiwixmobile/core/search/viewmodel/effects/ProcessActivityResultTest.kt b/core/src/test/java/org/kiwix/kiwixmobile/core/search/viewmodel/effects/ProcessActivityResultTest.kt index d59236509..ca8bce56d 100644 --- a/core/src/test/java/org/kiwix/kiwixmobile/core/search/viewmodel/effects/ProcessActivityResultTest.kt +++ b/core/src/test/java/org/kiwix/kiwixmobile/core/search/viewmodel/effects/ProcessActivityResultTest.kt @@ -70,7 +70,7 @@ internal class ProcessActivityResultTest { @Test fun `invoke with sends filter action with data`() { - every { data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)[0] } returns "" + every { data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) } returns arrayListOf("") successfulResult.invokeWith(activity) verify { actions.offer(Filter("")) } } diff --git a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt index d15c54f91..54da5d072 100644 --- a/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt +++ b/custom/src/main/java/org/kiwix/kiwixmobile/custom/main/CustomMainActivity.kt @@ -24,6 +24,7 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.navigation.NavController import androidx.navigation.findNavController import com.google.android.material.navigation.NavigationView +import kotlinx.android.synthetic.main.activity_custom_main.activity_main_nav_view import kotlinx.android.synthetic.main.activity_custom_main.custom_drawer_container import kotlinx.android.synthetic.main.activity_custom_main.drawer_nav_view import org.kiwix.kiwixmobile.core.di.components.CoreComponent @@ -40,6 +41,7 @@ class CustomMainActivity : CoreMainActivity() { } override val drawerContainerLayout: DrawerLayout by lazy { custom_drawer_container } override val drawerNavView: NavigationView by lazy { drawer_nav_view } + override val readerTableOfContentsDrawer: NavigationView by lazy { activity_main_nav_view } override val searchFragmentResId: Int = R.id.searchFragment override val bookmarksFragmentResId: Int = R.id.bookmarksFragment override val settingsFragmentResId: Int = R.id.customSettingsFragment