Resolved conflicts

This commit is contained in:
s-ayush2903 2020-11-29 20:40:59 +05:30
commit eaf6b77664
No known key found for this signature in database
GPG Key ID: B4341DD08B2371CB
35 changed files with 419 additions and 134 deletions

View File

@ -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: |

View File

@ -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: |

View File

@ -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

View File

@ -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).

View File

@ -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<T : Activity> {
abstract class BaseActivityTest {
@get:Rule
abstract var activityRule: ActivityTestRule<T>
open var activityRule = ActivityTestRule(KiwixMainActivity::class.java)
@get:Rule
var readPermissionRule: GrantPermissionRule =

View File

@ -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<KiwixMainActivity>() {
@get:Rule
override var activityRule: ActivityTestRule<KiwixMainActivity> =
ActivityTestRule(KiwixMainActivity::class.java)
class HelpFragmentTest : BaseActivityTest() {
@Test
fun verifyHelpActivity() {

View File

@ -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<KiwixMainActivity>() {
override var activityRule = activityTestRule<KiwixMainActivity>()
class IntroFragmentTest : BaseActivityTest() {
@Test
fun viewIsSwipeableAndNavigatesToMain() {

View File

@ -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<KiwixMainActivity> = activityTestRule {
PreferenceManager.getDefaultSharedPreferences(context).edit {
putBoolean(SharedPreferenceUtil.PREF_SHOW_INTRO, false)
}
}
@Test
fun testTopLevelDestination() {

View File

@ -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?
}

View File

@ -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

View File

@ -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),

View File

@ -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<FileItem>) {
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()
}

View File

@ -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

View File

@ -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;

View File

@ -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, NetworkState, Unit> { _, _ -> Unit }
BiFunction<Unit, NetworkState, Unit> { _, _ -> }
)
.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() })
}

View File

@ -6,4 +6,6 @@
<string name="file_system_does_not_support_4gb">\'U file system tune non ge supporte le file cchiù granne de 4GB</string>
<string name="detecting_file_system">Stoche a condrolle ce \'u file system tune pò ccrejà le file cchiù granne de 4GB</string>
<string name="cannot_open_file">Aprture du fail sciute a male\nPe piacere pruève arrete a cercà stu fail jndrà Schede d\'u despositive d\'a libbreria toje.</string>
<string name="send_files_title">Manne le file</string>
<string name="receive_files_title">Pigghie le file</string>
</resources>

View File

@ -6,4 +6,6 @@
<string name="file_system_does_not_support_4gb">Su sistema de documentos (file system) tuo non suportat documentos prus mannos de 4GB</string>
<string name="detecting_file_system">Verifichende si su sistema de documentos podet creare documentos de 4GB</string>
<string name="cannot_open_file">Abertura de su documentu fallida\nPro praghere proa a chircare custu documentu in s\'Ischeda de sos Dispositivos de sa Biblioteca tua</string>
<string name="send_files_title">Imbia documentos</string>
<string name="receive_files_title">Retzi documentos</string>
</resources>

View File

@ -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

View File

@ -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"
}
/**

View File

@ -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)

View File

@ -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
})

View File

@ -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)

View File

@ -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(

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -0,0 +1,85 @@
/*
* 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.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 = """
<html>
<head>
<script type="text/javascript">
function do_unregister() {
if (!navigator.serviceWorker) {
$UNINITIALISER_INTERFACE.onUninitialised();
return;
}
navigator.serviceWorker.getRegistrations().then(async function (registrations) {
if (registrations.length) {
console.debug('we do have ' + registrations.length + ' registration(s)');
var registration = registrations[0];
registration.unregister()
.then(function (success) { $UNINITIALISER_INTERFACE.onUninitialised();})
.catch(function (e) {alert("ERR:" + e)});
}
else {
$UNINITIALISER_INTERFACE.onUninitialised();
}
});
}
do_unregister();
</script>
</head>
<body>
<div id="loading" style="width: 100%; text-align: center">
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<path d="M36 18c0-9.94-8.06-18-18-18" stroke="gray">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>
</div>
</body>
</html>
"""
class ServiceWorkerUninitialiser(val onUninitialisedAction: () -> Unit) {
fun initInterface(webView: WebView) {
webView.addJavascriptInterface(this, UNINITIALISER_INTERFACE)
}
@JavascriptInterface
fun onUninitialised() {
Handler(Looper.getMainLooper()).post { onUninitialisedAction() }
}
}

View File

@ -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 =
"""

View File

@ -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()

View File

@ -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()
}
}

View File

@ -29,6 +29,7 @@
<string name="open_in_new_tab">Gıre xıldayışo newe de abo?</string>
<string name="hotspot_service_channel_name">Kanalê xızmeti Hotspot</string>
<string name="hotspot_failed_title">Serkewtışê hotspoti nêbiyo</string>
<string name="hotspot_failed_message">Hotspotê şıma xora akerde aseno. Dewma kerdışi rê kerem kerê nuqtay resayışê Wi-Fi dewre ra vecê.</string>
<string name="go_to_wifi_settings_label">Ravêrê eyaranê Wi-Fi</string>
<string name="connection_refused">Gırebiyayış biyo red</string>
<string name="hotspot_running">Hotspoto gureyneyino</string>
@ -43,12 +44,14 @@
<string name="progress_dialog_starting_server">Server gureyneyino</string>
<string name="hotspot_dialog_title">Telimatê meymandariya kıtaban</string>
<string name="wifi_dialog_title">Gırey Wi-fi tesbit biya</string>
<string name="wifi_dialog_body">Kıtabanê cihazanê binan mocnayışi rê gani cihazi pêro wa eyni torra Wi-Fi ya gıre bı</string>
<string name="hotspot_dialog_message">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ê.</string>
<string name="hotspot_dialog_neutral_button">RAVÊR Şİ</string>
<string name="hotspot_channel_description">Heqa Hotspot/server eleqeyın rocaney .</string>
<string name="hotspot_notification_content_title">Kiwix Hotspot</string>
<string name="start_server_label">Serveri serkewtış</string>
<string name="stop_server_label">Serveri vındardış</string>
<string name="server_started_message">Seba resayışê serverê %s re browseri rê ena adresê ip cı kerê</string>
<string name="error_file_not_found">Xeta: Dosyaya ZIMia weçinıtiye nêvêniye.</string>
<string name="zim_not_opened">Dosyay Zimi nêabiyena</string>
<string name="error_file_invalid">Xeta: Dosyaya weçinıtiye yew dosyaya ZIMia vêrdiye niya.</string>
@ -80,6 +83,7 @@
<string name="delete">Bestere</string>
<string name="cancel">Bıtexelne</string>
<string name="delete_specific_search_toast">Cıgeyrayışo peyên wedariya</string>
<string name="hint_contents_drawer_message">Zerrey nê meqaley vinayışi rê peta hetê çepiya xuz kerê</string>
<string name="got_it">Mı fehm kerd</string>
<string name="did_you_know">Şıma zanenê?</string>
<string name="undo">Peyser biya</string>
@ -99,6 +103,7 @@
<string name="new_tab_snack_bar">Meqale tabê neweyi de bi a</string>
<string name="search_widget_text">Kiwix\'i cıgeyre</string>
<string name="speech_prompt_text">Serva cıgeyrayışi %s vacê</string>
<string name="speech_not_supported">Malesef, cihazê şımayo dekerderê qısekerdışi rê desteg nêdano</string>
<string name="local_zims">Cihaz</string>
<string name="remote_zims">Online</string>
<string name="library">Kıtıbxane</string>
@ -113,10 +118,18 @@
<string name="zim_no_vid">Videoyi çıniyê</string>
<string name="no_network_connection">Gıreyê torre çıniyo</string>
<string name="help_2">Kiwix se keno ?</string>
<string name="help_3">Kiwix offline wanayoğê zerrekiyo. Eyni zey browserê torro lakin pelanê webi vera online resayışi, zerrekê dosyayan formatê ZIMi de waneno.</string>
<string name="help_4">Kiwix normalde Wikipedia offline wanayışi rê dizayn biya lakin zerrekê online zi şeno bıwano.</string>
<string name="help_5">Zerrek kam ca de yo?</string>
<string name="help_6">Zerrekê ma pela websita Kiwixi de yo.</string>
<string name="help_7">Zey dosyayanê ZIMi benê. İnan ra zeder estê :</string>
<string name="help_8">• Wikipedia seba herg zıwani weziyetê gureynayışi dera.</string>
<string name="help_9">• Çımey zey Wikileaks yana Wikiçıme enewke weziyetê gureynayışi derê.</string>
<string name="help_10">Weçinyayey dosyay ZIMi zerrey aplikasyoni de roniyenê yana waştenanê ho verê transferê SD kart kerdışi şenê komputeri ra desktopi ra ronê</string>
<string name="help_11">Zerrey aplikasyon miyan de roniyaye dosyay ZIM dosyaları cihazê depoy teberi de be namey klasorê sernamey Kiwix dero</string>
<string name="pref_storage">Depo kerdış</string>
<string name="pref_current_folder">Klasoro Mewcud</string>
<string name="delete_zim_failed">Malesef ma nêşa tay dosyayan esterê. Belka şıma şenê yew idarekari ra peşti bıgêrê.</string>
<string name="tts_pause">bıvındarne</string>
<string name="tts_resume">devam kerê</string>
<string name="stop">bıvındarne</string>
@ -127,8 +140,13 @@
<string name="confirm_stop_download_title">Wa ronayış vındero?</string>
<string name="confirm_stop_download_msg">Şıma qayılê nê ronayışi vındarne?</string>
<string name="download_change_storage">Weçinoğê cihazê depokerdışi</string>
<string name="tts_not_enabled">Seba na dosyay ZIM tetbiqiya wanayışê metini hewl niya</string>
<string name="texttospeech_initialization_failed">Metin ra wanayıi sernêkewto. Reyna bıcerrebnê</string>
<string name="texttospeech_error">Metin ra wanayışi de xeta. Reyna bıcerrebnê</string>
<string name="next">Bahdoyên</string>
<string name="previous">Verên</string>
<string name="wifi_only_title">Zerrek wa torra mobiliya gureynayışiya roneyo?</string>
<string name="wifi_only_msg">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ê</string>
<string name="pref_wifi_only">Zerreki teyna pê Wifi ya rone</string>
<string name="time_day">roce</string>
<string name="time_hour">sa</string>
@ -138,12 +156,15 @@
<string name="time_today">Ewro</string>
<string name="time_yesterday">Vızêr</string>
<string name="pref_external_link_popup_title">Gırey teberi cıkerdış de iqaz bıde</string>
<string name="pref_external_link_popup_summary">Ekstra ucret ya zi gırey offline nêgureyê se akerde teqa mocnayışiya iqaz bıdê.</string>
<string name="external_link_popup_dialog_title">Gıreyê teberi beno cı!</string>
<string name="external_link_popup_dialog_message">Şı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ê?</string>
<string name="do_not_ask_anymore">Endi meperse</string>
<string name="your_languages">Weçinaye zıwan :</string>
<string name="other_languages">Zıwano bin:</string>
<string name="no_items_msg">Karneyaye obce çıniyo</string>
<string name="crash_title">Ey… No teneyê ariyeya</string>
<string name="crash_description">Ze ke ma kewte.\n\nMelumatê cêri rışiyayışa nê problemi baş kerdışi rê şenê peşti bıdê?</string>
<string name="crash_checkbox_language">Eyarê zıwanê şıma</string>
<string name="crash_checkbox_zimfiles">Lista Dosyayanê Zıme Şıma</string>
<string name="crash_checkbox_exception">Detayê Rızyayışi</string>
@ -186,6 +207,7 @@
<string name="note">Note</string>
<string name="wiki_article_title">Serekê Meqaley Wiki</string>
<string name="ext_storage_permission_rationale_add_note">Serva nota resayışê depoyê ganşyoı</string>
<string name="ext_storage_write_permission_denied_add_note">Noti mısadey resayışê depoy nêbo se nêgureniyeno</string>
<string name="note_save_unsuccessful">Qeyd kerdışê noti nêbiyo</string>
<string name="note_delete_successful">Not esteriyaya</string>
<string name="note_delete_unsuccessful">Not nêesteriyê</string>
@ -203,22 +225,37 @@
<string name="discovery_failed">Kaşır nêşayo</string>
<string name="severe_loss_error">Xetaya gıran! WiFi P2P\'yi Dewre ra vec/Retnanaltiv kerê bıcerrebnê</string>
<string name="connection_failed">Gıreyin nêbiya</string>
<string name="permission_rationale_location">Cihazê takêşan ra ferq bıyayışi rê terefê Androidi ra mısadey mehali ganiyo.</string>
<string name="permission_rationale_location_on_host_zim_file">Dosyayanê ZIMi darênayışê aplikasyoni rê terefê Androidi ra mısadey mehali ganiyo.</string>
<string name="permission_refused_location">Bêmısadey mehali cihazanê takêşi nêvineyênê</string>
<string name="permission_refused_storage">Bêmısadey depo kerdışi nêresiyeno dosyayanê ZIMi</string>
<string name="request_enable_location">Taypêyan his kerdışi rê seba mısade dayışi mehali aktiv kerê</string>
<string name="discovery_needs_location">Servisê mehali taypêyi nêvineyênê</string>
<string name="request_enable_wifi">WiFi P2P\'yi eyaranê sistemi ra aktiv ke</string>
<string name="discovery_needs_wifi">WiFi AKERDE nêbo se tekê cı keşf nêbeno</string>
<string name="transfer_to">%s ya wa dosya transfer vo?</string>
<string name="device_not_cooperating">Weçineyaye cihazo seba transferi piya nêguriyeno</string>
<string name="file_transfer_complete">Transferê dosya biyo temam</string>
<string name="error_during_transfer">Çerğa transferi de yew xeta veciyê</string>
<string name="error_transferring">Dosyay %s transfer kerdış de xeta veciyê</string>
<string name="get_content_from_nearby_device">Cihazê nezdiy ra zerrek bıgêrê</string>
<string name="search_for_peers">Zey pêyan cıgeyre</string>
<string name="your_device">Cihazê Şıma:</string>
<string name="nearby_devices">NEZDI CİHAZİ</string>
<string name="no_devices_found">Cihaz nêvineya. Reyna cerbnayışi rê maka cıgeyrayışi bıploğne</string>
<string name="files_for_transfer">TRANSFERÊ DOSYAYAN</string>
<string name="preparing_files">Keno ke dosyaya transfer kero…</string>
<string name="performing_handshake">Dest dano destan…</string>
<string name="status">Weziyet</string>
<string name="pref_clear_all_notes_summary">Meqaleya pêroyın de nota pêroyın pak ke</string>
<string name="pref_clear_all_notes_title">Nota pêroyın pak ke</string>
<string name="pref_text_zoom_summary">Ebatê metin %25 zeydnayışana bıvurnê</string>
<string name="tag_pic">Resım</string>
<string name="tag_vid">Video</string>
<string name="tag_text_only">Teyna metin</string>
<string name="tag_short_text">Metino kılm</string>
<string name="storage_permission_denied">İcazetê depoy red biyo</string>
<string name="grant_read_storage_permission">Aplikasyoni seba gurenayışê depoy rê hunerê wanayışi icab keno</string>
<string name="go_to_settings">Şo eyaranê Hotspoti</string>
<string name="no_results">Neticeyi çıniyê</string>
<string name="no_bookmarks">Nişani çıniyê</string>
@ -234,6 +271,7 @@
<string name="send_report">Rapora teşhisi bırışê</string>
<string name="crash_checkbox_file_system">Detayê Sistemê Dosya</string>
<string name="diagnostic_report">Rapora Teşhisi</string>
<string name="diagnostic_report_message">Problemi fahm kerdışi rê detayanê cêrêna pêroyın kontrol kerê</string>
<string name="percentage">%d%%</string>
<string name="pref_text_zoom_title">Nazdiyiya metini</string>
<string name="search_open_in_new_tab">Taba newiye de ake</string>
@ -244,4 +282,5 @@
<string name="open_drawer">Antergey akerê</string>
<string name="close_drawer">Antergey bıqefelne</string>
<string name="how_to_update_content">Zerrek seni rocane beno?</string>
<string name="update_content_description">Seba rocane kerdışê zerreki (yu dosyay zimi), etni zerrekiya versiyonê tewr peyêni ronayış ganiyo. Ney kışta ronayışi ra şenê bıkerê.</string>
</resources>

View File

@ -27,6 +27,7 @@
<string name="hotspot_failed_title">Aviamentu de s\'hotspot fallidu</string>
<string name="hotspot_failed_message">Paret chi s\'hotspot tuo siat allutu. Pro praghere disabìlita s\'hotspot wifi tuo pro sighire.</string>
<string name="go_to_wifi_settings_label">Bae a sas impostatziones de su WIFI</string>
<string name="connection_refused">Connessione negada.</string>
<string name="hotspot_running">Hotspot ativu</string>
<string name="no_books_selected_toast_message">In antis ischerta libros</string>
<string name="server_failed_message">Aviamentu de su servidore fallidu. Pro praghere allughe s\'hotspot tuo</string>
@ -221,6 +222,7 @@
<string name="severe_loss_error">Faddina manna! Proa a Disabilitare/Torrare a abilitare su P2P WiFi</string>
<string name="connection_failed">Connessione fallida</string>
<string name="permission_rationale_location">Android tenet bisòngiu de su permissu de localizatzione pro rilevare dispositivos pares (peers)</string>
<string name="permission_rationale_location_on_host_zim_file">Android tenet bisòngiu de su permissu de localizatzione pro permìtere a s\'aplicatzione de istrangiare documentos Zim</string>
<string name="permission_refused_location">Impossìbile localizare dispositivos pares (peers) chene sos permissos de localizatzione</string>
<string name="permission_refused_storage">Impossìbile tènnere atzessu a sos documentos zim chene su permissu de archiviatzione</string>
<string name="request_enable_location">Abìlita sa localizatzione pro permìtere su rilevamentu de pares (peers)</string>
@ -243,6 +245,7 @@
<string name="status">Istadu</string>
<string name="pref_clear_all_notes_summary">Iscantzella totu sas notas in totu sos artìculos</string>
<string name="pref_clear_all_notes_title">Iscantzella totu sas notas</string>
<string name="pref_text_zoom_summary">Càmbia sa mannària de su testu cun ismanniamentos de su 25%.</string>
<string name="tag_pic">Immàgine</string>
<string name="tag_vid">Vìdeu</string>
<string name="tag_text_only">Testu ebbia</string>
@ -267,4 +270,13 @@
<string name="diagnostic_report_message">Pro praghere imbia totu sos detàllios chi sighent, in manera chi amus a pòdere diagnosticare su problema</string>
<string name="percentage">%d%%</string>
<string name="pref_text_zoom_title">Ismanniamentu de su testu</string>
<string name="search_open_in_new_tab">Aberi in un\'ischeda noa</string>
<string name="reader">Leghidore</string>
<string name="no_open_book">Perunu libru abertu</string>
<string name="open_library">Aberi sa biblioteca</string>
<string name="tab_restored">Ischeda ripristinada</string>
<string name="open_drawer">Aberi su pannellu</string>
<string name="close_drawer">Serra su pannellu</string>
<string name="how_to_update_content">Comente agiornare su cuntenutu?</string>
<string name="update_content_description">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.</string>
</resources>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Authors:
* Saraiki
-->
<resources>
<string name="menu_help">مدد</string>
<string name="menu_home">گھر</string>
<string name="menu_settings">ترتیباں</string>
<string name="menu_search_in_text">ورقے وچ لبھو</string>
<string name="bookmarks">بک مارک</string>
<string name="menu_random_article">کُݨے نال چوݨواں مضمون</string>
<string name="menu_full_screen">پوری سکرین</string>
<string name="menu_exit_full_screen">پوری سکرین توں نکلو</string>
<string name="menu_read_aloud">اُچی آواز نال پڑھو</string>
<string name="save_media">میڈیا بچاؤ</string>
<string name="search_label">ڳولو</string>
<string name="pref_display_title">ڈسپلے</string>
<string name="pref_info_title">معلومات</string>
<string name="pref_info_version">ورژن</string>
<string name="pref_night_mode">رات آلا مزاج</string>
<string name="pref_back_to_top">واپس اُتے ون٘ڄو</string>
<string name="pref_language_title">زبان</string>
<string name="pref_language_chooser">زبان چݨو</string>
<string name="delete_recent_search_item">ایہ ائٹم مٹاؤں؟</string>
<string name="pref_clear_all_history_title">تاریخچہ مٹاؤ</string>
<string name="clear_all_history_dialog_title">ساری تاریخ صاف کروں؟</string>
<string name="share">شیئر</string>
<string name="delete">مٹاؤ</string>
<string name="cancel">منسوخ</string>
<string name="got_it">گھن گھندا</string>
<string name="did_you_know">بھلا تساں ڄاݨدے ہو؟</string>
<string name="undo">واپس</string>
<string name="tab_closed">ٹیب بند تھی ڳئی</string>
<string name="bookmark_added">بک مارک شامل تھی ڳیا</string>
<string name="no_thanks">کو، شکریہ</string>
<string name="rate_dialog_neutral">بعد وچ</string>
<string name="open">کھولو</string>
<string name="pref_extras">فالتو</string>
<string name="search_widget_text">کیوکس وچ ڳولو</string>
<string name="local_zims">مشین، ڈیوائس</string>
<string name="remote_zims">آن لائن</string>
<string name="library">لائبریری</string>
<string name="no_files_here">اتھ کوئی فائلاں کائنی</string>
<string name="download">ڈاؤن لوڈ</string>
<string name="zim_simple">سادہ</string>
<string name="zim_no_vid">ویڈیو کائنی</string>
<string name="help_2">کِوِکس کیا کریندے؟</string>
<string name="pref_storage">ذخیرہ</string>
<string name="pref_current_folder">حالیہ فولڈر</string>
<string name="tts_pause">جمبو، اجھکو</string>
<string name="tts_resume">ولدا شروع کرو</string>
<string name="stop">اختتام</string>
<string name="internal_storage">اندرونی</string>
<string name="external_storage">ٻاہر آلا</string>
<string name="yes">ڄیا</string>
<string name="no">کو</string>
<string name="confirm_stop_download_title">ڈاؤن لوڈ روکوں؟</string>
<string name="next">اڳلا</string>
<string name="previous">پچھلا</string>
<string name="time_day">ݙینہ</string>
<string name="time_hour">گھ</string>
<string name="time_minute">منٹ</string>
<string name="time_second">سیک</string>
<string name="time_left">باقی</string>
<string name="time_today">اڄ</string>
<string name="time_yesterday">کل</string>
<string name="your_languages">چُݨیاں ہویاں زباناں:</string>
<string name="other_languages">ٻیاں زباناں:</string>
<string name="new_tab_shortcut_label">نویں ٹیب</string>
<string name="get_started">شروع کرو</string>
<string name="expand">ودھاؤ</string>
<string name="history">تاریخ</string>
<string name="pending_state">وچار ہیٹھ</string>
<string name="running_state">تھیندا پئے</string>
<string name="complete">مکمل</string>
<string name="paused_state">جمب ڳیا</string>
<string name="save">بچاؤ</string>
<string name="note">نوٹ</string>
<string name="status">حیثیت</string>
<string name="tag_pic">تصویر</string>
<string name="tag_vid">وڈیو</string>
<string name="tag_text_only">صرف عبارت</string>
<string name="no_bookmarks">بک مارک کائنی</string>
<string name="on">آن</string>
<string name="off">بند</string>
<string name="auto">خود بخود</string>
<string name="open_library">مفت لائبریری</string>
<string name="open_drawer">دراز کھولو</string>
<string name="close_drawer">دراز بند کرو</string>
</resources>

View File

@ -31,6 +31,7 @@
<string name="hotspot_failed_title">Misslyckades att starta surfpunkt</string>
<string name="hotspot_failed_message">Det verkar som att din surfpunkt redan är aktiverad. Var god inaktivera din WiFi-surfpunkt för att fortsätta.</string>
<string name="go_to_wifi_settings_label">Gå till WiFi-inställningar</string>
<string name="connection_refused">Anslutning vägrades.</string>
<string name="hotspot_running">Aktiv surfpunkt</string>
<string name="no_books_selected_toast_message">Välj böcker först</string>
<string name="server_failed_message">Kunde inte starta server. Var god aktivera din surfpunkt</string>
@ -220,15 +221,25 @@
<string name="notes_deletion_successful">Raderade hela anteckningsmappen</string>
<string name="notes_deletion_unsuccessful">Vissa filer raderades inte</string>
<string name="books_count">%d bok/böcker</string>
<string name="discovery_initiated">Inleder upptäckt</string>
<string name="discovery_failed">Upptäckt misslyckades</string>
<string name="severe_loss_error">Allvarligt fel! Testa att starta om WiFi P2P</string>
<string name="connection_failed">Anslutning misslyckades</string>
<string name="permission_rationale_location">Platsåtkomst krävs från Android för att låta appen söka efter närliggande enheter.</string>
<string name="permission_rationale_location_on_host_zim_file">Platsåtkomst krävs från Android för att låta appen hantera Host Zim-filer.</string>
<string name="permission_refused_location">Kan inte hitta närliggande enheter utan platsåtkomst.</string>
<string name="permission_refused_storage">Kan inte komma åt zim-filer utan lagringsbehörighet</string>
<string name="request_enable_location">Aktivera plats för att tillåta sökning efter närliggande enheter</string>
<string name="discovery_needs_location">Kan inte hitta närliggande enheter utan platstjänster</string>
<string name="request_enable_wifi">Aktivera WiFi P2P i systeminställningar</string>
<string name="discovery_needs_wifi">Kan inte hitta närliggande enheter utan WiFi</string>
<string name="transfer_to">Överför filer till %s?</string>
<string name="device_not_cooperating">Valda enheter samarbetar inte för överföring</string>
<string name="file_transfer_complete">Filöverföring slutfördes</string>
<string name="error_during_transfer">Ett fel uppstod under överförning</string>
<string name="error_transferring">Fel uppstod när filen %s överfördes</string>
<string name="get_content_from_nearby_device">Hämta innehåll från enheter i närheten</string>
<string name="search_for_peers">Sök efter enheter</string>
<string name="your_device">Din enhet:</string>
<string name="nearby_devices">ENHETER I NÄRHETEN</string>
<string name="no_devices_found">Inga enheter hittades. Tryck på sökknappen för att söka igen.</string>
@ -238,6 +249,7 @@
<string name="status">Status</string>
<string name="pref_clear_all_notes_summary">Rensar alla anteckningar på alla artiklar</string>
<string name="pref_clear_all_notes_title">Rensa alla anteckningar</string>
<string name="pref_text_zoom_summary">Ändra textstorlek med steg på 25%.</string>
<string name="tag_pic">Bild</string>
<string name="tag_vid">Video</string>
<string name="tag_text_only">Endast text</string>

View File

@ -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("")) }
}

View File

@ -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