64 Custom apps should validate their expansion files and re-download if corrupt/missing - unit test custom download

This commit is contained in:
Sean Mac Gillicuddy 2019-11-05 16:17:14 +00:00
parent c05742d02a
commit f92664ca5f
22 changed files with 478 additions and 203 deletions

View File

@ -32,7 +32,7 @@ import kotlinx.android.synthetic.main.activity_language.language_recycler_view
import kotlinx.android.synthetic.main.activity_language.toolbar import kotlinx.android.synthetic.main.activity_language.toolbar
import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.R
import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.extensions.viewModel import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.kiwixActivityComponent import org.kiwix.kiwixmobile.kiwixActivityComponent
import org.kiwix.kiwixmobile.language.adapter.LanguageAdapter import org.kiwix.kiwixmobile.language.adapter.LanguageAdapter
import org.kiwix.kiwixmobile.language.adapter.LanguageDelegate.HeaderDelegate import org.kiwix.kiwixmobile.language.adapter.LanguageDelegate.HeaderDelegate

View File

@ -27,7 +27,7 @@ import androidx.core.net.toFile
import androidx.core.net.toUri import androidx.core.net.toUri
import org.json.JSONArray import org.json.JSONArray
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.extensions.start import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.main.WebViewCallback import org.kiwix.kiwixmobile.core.main.WebViewCallback

View File

@ -17,12 +17,9 @@
*/ */
package org.kiwix.kiwixmobile.zim_manager package org.kiwix.kiwixmobile.zim_manager
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.Settings.System import android.provider.Settings.System
import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
@ -32,17 +29,15 @@ import kotlinx.android.synthetic.main.zim_manager.tabs
import kotlinx.android.synthetic.main.zim_manager.toolbar import kotlinx.android.synthetic.main.zim_manager.toolbar
import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.R
import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.extensions.start
import org.kiwix.kiwixmobile.core.extensions.startWithActionFrom
import org.kiwix.kiwixmobile.core.extensions.viewModel
import org.kiwix.kiwixmobile.language.LanguageActivity
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
import org.kiwix.kiwixmobile.core.utils.Constants.TAG_KIWIX import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.startWithActionFrom
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.utils.LanguageUtils import org.kiwix.kiwixmobile.core.utils.LanguageUtils
import org.kiwix.kiwixmobile.local_file_transfer.LocalFileTransferActivity
import org.kiwix.kiwixmobile.kiwixActivityComponent import org.kiwix.kiwixmobile.kiwixActivityComponent
import java.io.File import org.kiwix.kiwixmobile.language.LanguageActivity
import org.kiwix.kiwixmobile.local_file_transfer.LocalFileTransferActivity
import javax.inject.Inject import javax.inject.Inject
class ZimManageActivity : BaseActivity() { class ZimManageActivity : BaseActivity() {
@ -144,20 +139,6 @@ class ZimManageActivity : BaseActivity() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
// Set zim file and return
fun finishResult(path: String?) {
if (path != null) {
val file = File(path)
val uri = Uri.fromFile(file)
Log.i(TAG_KIWIX, "Opening Zim File: $uri")
setResult(Activity.RESULT_OK, Intent().setData(uri))
finish()
} else {
setResult(Activity.RESULT_CANCELED)
finish()
}
}
companion object { companion object {
const val TAB_EXTRA = "TAB" const val TAB_EXTRA = "TAB"
} }

View File

@ -32,7 +32,7 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.base.BaseFragment import org.kiwix.kiwixmobile.core.base.BaseFragment
import org.kiwix.kiwixmobile.core.downloader.Downloader import org.kiwix.kiwixmobile.core.downloader.Downloader
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
import org.kiwix.kiwixmobile.core.extensions.viewModel import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.core.utils.DialogShower import org.kiwix.kiwixmobile.core.utils.DialogShower
import org.kiwix.kiwixmobile.core.utils.KiwixDialog.YesNoDialog.StopDownload import org.kiwix.kiwixmobile.core.utils.KiwixDialog.YesNoDialog.StopDownload
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil

View File

@ -37,8 +37,8 @@ import kotlinx.android.synthetic.main.zim_list.zimfilelist
import org.kiwix.kiwixmobile.R import org.kiwix.kiwixmobile.R
import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.base.BaseFragment import org.kiwix.kiwixmobile.core.base.BaseFragment
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.extensions.viewModel
import org.kiwix.kiwixmobile.core.utils.Constants.REQUEST_STORAGE_PERMISSION import org.kiwix.kiwixmobile.core.utils.Constants.REQUEST_STORAGE_PERMISSION
import org.kiwix.kiwixmobile.core.utils.LanguageUtils import org.kiwix.kiwixmobile.core.utils.LanguageUtils
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil

View File

@ -21,7 +21,7 @@ import android.app.Activity
import androidx.core.net.toUri import androidx.core.net.toUri
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.start import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
import org.kiwix.kiwixmobile.main.KiwixMainActivity import org.kiwix.kiwixmobile.main.KiwixMainActivity

View File

@ -23,7 +23,7 @@ import android.view.ActionMode
import io.reactivex.processors.PublishProcessor import io.reactivex.processors.PublishProcessor
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.startActionMode import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.startActionMode
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestDeleteMultiSelection import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestDeleteMultiSelection

View File

@ -39,9 +39,9 @@ import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.base.BaseFragment import org.kiwix.kiwixmobile.core.base.BaseFragment
import org.kiwix.kiwixmobile.core.downloader.Downloader import org.kiwix.kiwixmobile.core.downloader.Downloader
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.core.extensions.snack import org.kiwix.kiwixmobile.core.extensions.snack
import org.kiwix.kiwixmobile.core.extensions.toast import org.kiwix.kiwixmobile.core.extensions.toast
import org.kiwix.kiwixmobile.core.extensions.viewModel
import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.settings.StorageCalculator import org.kiwix.kiwixmobile.core.settings.StorageCalculator
import org.kiwix.kiwixmobile.core.utils.BookUtils import org.kiwix.kiwixmobile.core.utils.BookUtils

View File

@ -1 +0,0 @@
relaxUnitFun=true

View File

@ -1 +0,0 @@
junit.jupiter.testinstance.lifecycle.default=per_class

View File

@ -1,104 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<metalink xmlns="urn:ietf:params:xml:ns:metalink">
<generator>MirrorBrain/2.18.1</generator>
<origin dynamic="true">http://download.kiwix.org/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim.meta4</origin>
<published>2016-06-08T08:59:18Z</published>
<publisher>
<name>Kiwix project</name>
<url>http://www.kiwix.org</url>
</publisher>
<file name="wikipedia_af_all_nopic_2016-05.zim">
<size>63973123</size>
<!-- <mtime>1462622396</mtime> -->
<!-- internal id: 756021 -->
<hash type="md5">6f06866b61c4a921b57f28cfd4307220</hash>
<hash type="sha-1">8aac4c7f89e3cdd45b245695e19ecde5aac59593</hash>
<hash type="sha-256">83126775538cf588a85edb10db04d6e012321a2025278a08a084b258849b3a5c</hash>
<pieces length="1048576" type="sha-1">
<hash>f36815d904d4fd563aaef4ee6ef2600fb1fd70b2</hash>
<hash>cd34a8a85ed1dd275417ce224ff0cd8d9893d101</hash>
<hash>7702114faf59441937c9075ad695fad61cdb13f3</hash>
<hash>532553bfb04c870375a53368b17838e50b169ab8</hash>
<hash>fcda3eba296502965015ef3f07b05adeb4d95dfc</hash>
<hash>97af1a7b1327a6f13dfc63524c63077c4aaa1278</hash>
<hash>4c02b16d3d0cb1acc5b0eb02a46e3047245ca65c</hash>
<hash>163927a9e7405b20c0544d06243baecfdf3c13d3</hash>
<hash>1d4ccf5570fecefc93793aa1ebb73d95eb46cf03</hash>
<hash>a0e5200bde74ba58c7318e15a34d5f891fb36841</hash>
<hash>e862a19ce5a4066efdcc15bf3c74462292251171</hash>
<hash>1c964b3029b6eda5ddff6815bf5298ca9a4c4196</hash>
<hash>29f52efd444b496fc55c99541de62823605bdce7</hash>
<hash>d5ae5e610f0b2f102bc16d7eeea55cacf259dda8</hash>
<hash>b7e0102f182a84d76c3a8ca02d0e9319a320eed6</hash>
<hash>bd63b665f1ac5620226481bacbe4dee1d31d48ba</hash>
<hash>54393351f78e24c4ebb4dbfd22fcdfff279f39fb</hash>
<hash>8845733b1da2876ad81aa1f7596dfd0e49bcc293</hash>
<hash>94c2bb5e297a1c61bd1e4a3b47a2ffa8457dc9aa</hash>
<hash>b2c1229eb3ffa88c71f0584c9714b7cf2d7df091</hash>
<hash>d0978cf7aaba0320442673fc47f400e43df84a99</hash>
<hash>5b8e68db7197089a78e92eb77f1c63859d098b1b</hash>
<hash>d4ff1f37c101735c81a06ebd98e1c3be465e0314</hash>
<hash>e9399f2c1f883816d3007765443cd38a1b4c6f9f</hash>
<hash>b6fa56a9dc6893bd67deebd14e9f2ccd42d63355</hash>
<hash>73efed5e8fd6480fece063826d62241783126b63</hash>
<hash>b24ec4bd6f1f6ad2de9724275ac141c92692edd2</hash>
<hash>3d35dee6ee7e1add3e8f30fe601f4f74ed11e704</hash>
<hash>9af07844246402bc6e28f37f8eb8c0329033a874</hash>
<hash>1be6178907a740670d8e61f72ebc8d47860015ce</hash>
<hash>6e954cc098392cf7f515e07f4d666d8b0a5fe329</hash>
<hash>e9f09f347f07585338073fea96f8d009a5aa3e0d</hash>
<hash>a48801add4c60733a023bdcce5e62aacb33becf0</hash>
<hash>90ca6abeeb08fbc136f1d0234741ca6b506869bc</hash>
<hash>7c426983069ea0556168f9e7343426f79d233bc1</hash>
<hash>18e893707d86bb778f9be3957e2645502ae1469d</hash>
<hash>c7a984439cb7e7fbbc805ea9eb77bebcfbaa25a5</hash>
<hash>9614ca49b5611494e4aaa0a3ffd3e23f5bfae86a</hash>
<hash>d344c4cd8db6c0859eb00ba90cdeb1e12b9922c4</hash>
<hash>ef777338b04c4b638721e1a043c3ae433a885c82</hash>
<hash>04504c63113f7719f5ac13c8e30f1feec4648268</hash>
<hash>1411ad174573f8c2a9a2d33c33f77f776db40f35</hash>
<hash>bc771262c4abf687b49321c83fd4613dbdcc1aa3</hash>
<hash>6762c76f99280283fa73037a0358efe5fd903eee</hash>
<hash>8ba56ea08fe4c2f9e76ee8273ce9dad4c4bd977a</hash>
<hash>97d8246b1db42afb9048109f920811fb5e723e71</hash>
<hash>6c59c23baeb706f6902f5a8dc822bcf932721cdc</hash>
<hash>1dff0732d971bc25af5afa9768493f435e5ab5d0</hash>
<hash>133ff15a2992b0d5337eeddc62da839f86cee1e0</hash>
<hash>0590bc490e4f12782849b8b36b87e1b68becdb83</hash>
<hash>705e5c62c96c6b41a9cfea97796ebdcc981145a6</hash>
<hash>e03ba6cf2deba1dfc8d781e4b8d0c602e033eea4</hash>
<hash>a5c46e2093d7c138df4553bfc92604de91b8fe89</hash>
<hash>035f0bd63b253c88a5ef7efaea96b3ee664e6f91</hash>
<hash>3b4732487b464d6164d9e460d990dcf8de8b499c</hash>
<hash>3453494c2188f5bee8a86a7b3626129e61a8bb21</hash>
<hash>47a062cdd2f7024f6f6ebffe6ade5ca9474932ea</hash>
<hash>5c30eee23b5b75680958760472c5c39aaaab108c</hash>
<hash>c93ae5c2faf3f3a898e01f5c9aef1d57f2969990</hash>
<hash>debf6ed9bbfbc9db4505d89dc74f871049d5c918</hash>
<hash>3d0c0800396e5305ff1ddabba2371f817ec4839c</hash>
<hash>8055e515aa6e78f2810bbb0e0cd07330838b8920</hash>
</pieces>
<!-- Found 7 mirrors: 0 in the same network prefix, 0 in the same autonomous system,
0 handling this country, 0 in the same region, 5 elsewhere -->
<!-- Mirrors in the same network (unknown): -->
<!-- Mirrors in the same AS (unknown): -->
<!-- Mirrors which handle this country (unknown): -->
<!-- Mirrors in the same continent (unknown): -->
<!-- Mirrors in the rest of the world: -->
<url location="us" priority="1">http://ftpmirror.your.org/pub/kiwix/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim</url>
<url location="gb" priority="2">http://www.mirrorservice.org/sites/download.kiwix.org/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim</url>
<url location="us" priority="3">http://download.wikimedia.org/kiwix/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim</url>
<url location="de" priority="4">http://mirror.netcologne.de/kiwix/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim</url>
<url location="fr" priority="5">http://mirror3.kiwix.org/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim</url>
</file>
</metalink>

View File

@ -87,7 +87,7 @@ class AllProjectConfigurer {
lintOptions { lintOptions {
isAbortOnError = true isAbortOnError = true
isCheckAllWarnings = true isCheckAllWarnings = true
isCheckAllWarnings = true isWarningsAsErrors = true
ignore( ignore(
"SyntheticAccessor", "SyntheticAccessor",
@ -102,7 +102,8 @@ class AllProjectConfigurer {
warning( warning(
"UnknownNullness", "UnknownNullness",
"SelectableText", "SelectableText",
"IconDensities" "IconDensities",
"ContentDescription"
) )
baseline("${path}/lint-baseline.xml") baseline("${path}/lint-baseline.xml")
} }
@ -121,6 +122,7 @@ class AllProjectConfigurer {
sourceSets { sourceSets {
getByName("test") { getByName("test") {
java.srcDir("${target.rootDir}/core/src/sharedTestFunctions/java") java.srcDir("${target.rootDir}/core/src/sharedTestFunctions/java")
resources.srcDir("${target.rootDir}/core/src/test/resources")
} }
} }
} }

View File

@ -30,11 +30,13 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import org.kiwix.kiwixmobile.core.Intents import org.kiwix.kiwixmobile.core.Intents
fun Activity.startActionMode( object ActivityExtensions {
fun Activity.startActionMode(
menuId: Int, menuId: Int,
idsToClickActions: Map<Int, () -> Any>, idsToClickActions: Map<Int, () -> Any>,
onDestroyAction: () -> Unit onDestroyAction: () -> Unit
): ActionMode? { ): ActionMode? {
return startActionMode(object : Callback { return startActionMode(object : Callback {
override fun onActionItemClicked( override fun onActionItemClicked(
mode: ActionMode, mode: ActionMode,
@ -63,22 +65,25 @@ fun Activity.startActionMode(
onDestroyAction() onDestroyAction()
} }
}) })
} }
inline fun <reified T : Activity> Activity.start(noinline intentFunc: (Intent.() -> Unit)? = null) { inline fun <reified T : Activity> Activity.start(
noinline intentFunc: (Intent.() -> Unit)? = null
) {
startActivity( startActivity(
Intent(this, T::class.java).apply { Intent(this, T::class.java).apply {
intentFunc?.invoke(this) intentFunc?.invoke(this)
} }
) )
} }
inline fun <reified T : Activity> Activity.startWithActionFrom() { inline fun <reified T : Activity> Activity.startWithActionFrom() {
startActivity(Intents.internal(T::class.java)) startActivity(Intents.internal(T::class.java))
} }
inline fun <reified T : ViewModel> FragmentActivity.viewModel( inline fun <reified T : ViewModel> FragmentActivity.viewModel(
viewModelFactory: ViewModelProvider.Factory viewModelFactory: ViewModelProvider.Factory
) = ) =
ViewModelProviders.of(this, viewModelFactory) ViewModelProviders.of(this, viewModelFactory)
.get(T::class.java) .get(T::class.java)
}

View File

@ -9,14 +9,12 @@
</issue> </issue>
<issue <issue
id="SdCardPath" id="ObsoleteLintCustomCheck"
message="Do not hardcode &quot;`/data/`&quot;; use `Context.getFilesDir().getPath()` instead" message="Lint found an issue registry (`butterknife.lint.LintRegistry`) which is older than the current API level; these checks may not work correctly.&#xA;&#xA;Recompile the checks against the latest version. Custom check API version is 2 (3.2), current lint API level is 5 (3.5+)"
errorLine1=" &quot;/data/data/%s/lib/%s&quot;, packageName," includedVariants="customexampleDebug"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> excludedVariants="customexampleRelease">
<location <location
file="src\main\java\org\kiwix\kiwixmobile\custom\main\CustomMainActivity.kt" file="..\..\..\.gradle\caches\transforms-2\files-2.1\6dca90c1110a5ba8556122fc8f89395f\butterknife-runtime-10.1.0\jars\lint.jar"/>
line="109"
column="12"/>
</issue> </issue>
<issue <issue
@ -58,9 +56,17 @@
<issue <issue
id="UnusedResources" id="UnusedResources"
message="The resource `R.drawable.kiwix_icon_with_title` appears to be unused"> message="The resource `R.mipmap.kiwix_icon` appears to be unused">
<location <location
file="src\customexample\res\drawable\kiwix_icon_with_title.png"/> file="src\customexample\res\mipmap-hdpi\kiwix_icon.png"/>
<location
file="src\customexample\res\mipmap-mdpi\kiwix_icon.png"/>
<location
file="src\customexample\res\mipmap-xhdpi\kiwix_icon.png"/>
<location
file="src\customexample\res\mipmap-xxhdpi\kiwix_icon.png"/>
<location
file="src\customexample\res\mipmap-xxxhdpi\kiwix_icon.png"/>
</issue> </issue>
<issue <issue
@ -74,6 +80,13 @@
column="11"/> column="11"/>
</issue> </issue>
<issue
id="UnusedResources"
message="The resource `R.raw.wikipedia_fr_test_2017_07` appears to be unused">
<location
file="src\customexample\res\raw\wikipedia_fr_test_2017_07.zim"/>
</issue>
<issue <issue
id="IconDipSize" id="IconDipSize"
message="The image `ic_kiwix_widget.png` varies significantly in its density-independent (dip) size across the various density versions: drawable-hdpi\\ic_kiwix_widget.png: 48x48 dp (72x72 px), drawable-mdpi\\ic_kiwix_widget.png: 72x72 dp (72x72 px), drawable-xhdpi\\ic_kiwix_widget.png: 48x48 dp (96x96 px), drawable-xxhdpi\\ic_kiwix_widget.png: 48x48 dp (144x144 px), drawable-xxxhdpi\\ic_kiwix_widget.png: 48x48 dp (192x192 px)"> message="The image `ic_kiwix_widget.png` varies significantly in its density-independent (dip) size across the various density versions: drawable-hdpi\\ic_kiwix_widget.png: 48x48 dp (72x72 px), drawable-mdpi\\ic_kiwix_widget.png: 72x72 dp (72x72 px), drawable-xhdpi\\ic_kiwix_widget.png: 48x48 dp (96x96 px), drawable-xxhdpi\\ic_kiwix_widget.png: 48x48 dp (144x144 px), drawable-xxxhdpi\\ic_kiwix_widget.png: 48x48 dp (192x192 px)">
@ -156,6 +169,39 @@
file="src\customexample\res\drawable-xxxhdpi\ic_kiwix_widget.png"/> file="src\customexample\res\drawable-xxxhdpi\ic_kiwix_widget.png"/>
</issue> </issue>
<issue
id="SelectableText"
message="Consider making the text value selectable by specifying `android:textIsSelectable=&quot;true&quot;`"
errorLine1=" &lt;TextView"
errorLine2=" ~~~~~~~~">
<location
file="src\main\res\layout\layout_custom_download_error.xml"
line="10"
column="4"/>
</issue>
<issue
id="SelectableText"
message="Consider making the text value selectable by specifying `android:textIsSelectable=&quot;true&quot;`"
errorLine1=" &lt;TextView"
errorLine2=" ~~~~~~~~">
<location
file="src\main\res\layout\layout_custom_download_in_progress.xml"
line="8"
column="4"/>
</issue>
<issue
id="SelectableText"
message="Consider making the text value selectable by specifying `android:textIsSelectable=&quot;true&quot;`"
errorLine1=" &lt;TextView"
errorLine2=" ~~~~~~~~">
<location
file="src\main\res\layout\layout_custom_download_in_progress.xml"
line="28"
column="4"/>
</issue>
<issue <issue
id="GoogleAppIndexingApiWarning" id="GoogleAppIndexingApiWarning"
message="Missing support for Firebase App Indexing API" message="Missing support for Firebase App Indexing API"
@ -167,4 +213,26 @@
column="7"/> column="7"/>
</issue> </issue>
<issue
id="ContentDescription"
message="Missing `contentDescription` attribute on image"
errorLine1=" &lt;ImageView"
errorLine2=" ~~~~~~~~~">
<location
file="src\main\res\layout\activity_custom_download.xml"
line="9"
column="4"/>
</issue>
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
errorLine1=" public CustomViewModelFactory(Map&lt;Class&lt;? extends ViewModel>, Provider&lt;ViewModel>> creators) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src\main\java\org\kiwix\kiwixmobile\custom\CustomViewModelFactory.java"
line="32"
column="33"/>
</issue>
</issues> </issues>

View File

@ -31,8 +31,8 @@ import kotlinx.android.synthetic.main.layout_custom_download_in_progress.cd_prog
import kotlinx.android.synthetic.main.layout_custom_download_required.cd_download_button import kotlinx.android.synthetic.main.layout_custom_download_required.cd_download_button
import org.kiwix.kiwixmobile.core.base.BaseActivity import org.kiwix.kiwixmobile.core.base.BaseActivity
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
import org.kiwix.kiwixmobile.core.extensions.setDistinctDisplayedChild import org.kiwix.kiwixmobile.core.extensions.setDistinctDisplayedChild
import org.kiwix.kiwixmobile.core.extensions.viewModel
import org.kiwix.kiwixmobile.custom.R import org.kiwix.kiwixmobile.custom.R
import org.kiwix.kiwixmobile.custom.customActivityComponent import org.kiwix.kiwixmobile.custom.customActivityComponent
import org.kiwix.kiwixmobile.custom.download.Action.ClickedDownload import org.kiwix.kiwixmobile.custom.download.Action.ClickedDownload

View File

@ -41,7 +41,8 @@ import javax.inject.Inject
class CustomDownloadViewModel @Inject constructor( class CustomDownloadViewModel @Inject constructor(
downloadDao: FetchDownloadDao, downloadDao: FetchDownloadDao,
setPreferredStorageWithMostSpace: SetPreferredStorageWithMostSpace, setPreferredStorageWithMostSpace: SetPreferredStorageWithMostSpace,
private val downloadCustom: DownloadCustom private val downloadCustom: DownloadCustom,
private val finishAndStartMain: FinishAndStartMain
) : ViewModel() { ) : ViewModel() {
val state = MutableLiveData<State>().apply { value = DownloadRequired } val state = MutableLiveData<State>().apply { value = DownloadRequired }
@ -90,7 +91,7 @@ class CustomDownloadViewModel @Inject constructor(
else else
DownloadInProgress(action.downloads) DownloadInProgress(action.downloads)
else else
DownloadComplete.also { _effects.offer(FinishAndStartMain()) } DownloadComplete.also { _effects.offer(finishAndStartMain) }
DownloadComplete -> state DownloadComplete -> state
} }
} }

View File

@ -20,10 +20,11 @@ package org.kiwix.kiwixmobile.custom.download.effects
import android.app.Activity import android.app.Activity
import org.kiwix.kiwixmobile.core.base.SideEffect import org.kiwix.kiwixmobile.core.base.SideEffect
import org.kiwix.kiwixmobile.core.extensions.start import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
import org.kiwix.kiwixmobile.custom.main.CustomMainActivity import org.kiwix.kiwixmobile.custom.main.CustomMainActivity
import javax.inject.Inject
class FinishAndStartMain() : SideEffect<Unit> { class FinishAndStartMain @Inject constructor() : SideEffect<Unit> {
override fun invokeWith(activity: Activity) { override fun invokeWith(activity: Activity) {
activity.finish() activity.finish()
activity.start<CustomMainActivity>() activity.start<CustomMainActivity>()

View File

@ -24,7 +24,7 @@ import android.util.Log
import android.view.Menu import android.view.Menu
import org.kiwix.kiwixmobile.core.CoreApp import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.R
import org.kiwix.kiwixmobile.core.extensions.start import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.start
import org.kiwix.kiwixmobile.core.main.CoreMainActivity import org.kiwix.kiwixmobile.core.main.CoreMainActivity
import org.kiwix.kiwixmobile.core.main.WebViewCallback import org.kiwix.kiwixmobile.core.main.WebViewCallback
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer

View File

@ -0,0 +1,176 @@
/*
* Kiwix Android
* Copyright (c) 2019 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.custom.download
import com.jraska.livedata.test
import com.tonyodev.fetch2.Error.NONE
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
import io.reactivex.processors.PublishProcessor
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao
import org.kiwix.kiwixmobile.core.downloader.model.DownloadModel
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Failed
import org.kiwix.kiwixmobile.custom.download.Action.ClickedDownload
import org.kiwix.kiwixmobile.custom.download.Action.ClickedRetry
import org.kiwix.kiwixmobile.custom.download.Action.DatabaseEmission
import org.kiwix.kiwixmobile.custom.download.State.DownloadComplete
import org.kiwix.kiwixmobile.custom.download.State.DownloadFailed
import org.kiwix.kiwixmobile.custom.download.State.DownloadInProgress
import org.kiwix.kiwixmobile.custom.download.State.DownloadRequired
import org.kiwix.kiwixmobile.custom.download.effects.DownloadCustom
import org.kiwix.kiwixmobile.custom.download.effects.FinishAndStartMain
import org.kiwix.kiwixmobile.custom.download.effects.SetPreferredStorageWithMostSpace
import org.kiwix.sharedFunctions.InstantExecutorExtension
import org.kiwix.sharedFunctions.downloadItem
@ExtendWith(InstantExecutorExtension::class)
internal class CustomDownloadViewModelTest {
private val fetchDownloadDao: FetchDownloadDao = mockk()
private val setPreferredStorageWithMostSpace: SetPreferredStorageWithMostSpace = mockk()
private val downloadCustom: DownloadCustom = mockk()
private val finishAndStartMain: FinishAndStartMain = mockk()
private val downloads: PublishProcessor<List<DownloadModel>> = PublishProcessor.create()
private lateinit var customDownloadViewModel: CustomDownloadViewModel
@BeforeEach
internal fun setUp() {
clearAllMocks()
every { fetchDownloadDao.downloads() } returns downloads
customDownloadViewModel = CustomDownloadViewModel(
fetchDownloadDao,
setPreferredStorageWithMostSpace,
downloadCustom,
finishAndStartMain
)
}
@Test
internal fun `effects emits SetPreferred on Subscribe`() {
customDownloadViewModel.effects.test().assertValue(setPreferredStorageWithMostSpace)
}
@Test
internal fun `initial State is DownloadRequired`() {
customDownloadViewModel.state.test().assertValue(State.DownloadRequired)
}
@Nested
inner class DownloadEmissions {
@Test
internal fun `Emission with data moves state from Required to InProgress`() {
assertStateTransition(
DownloadRequired,
DatabaseEmission(listOf(downloadItem())),
State.DownloadInProgress(listOf(downloadItem()))
)
}
@Test
internal fun `Emission without data moves state from Required to Required`() {
assertStateTransition(DownloadRequired, DatabaseEmission(listOf()), DownloadRequired)
}
@Test
internal fun `Emission with data moves state from Failed to InProgress`() {
assertStateTransition(
DownloadFailed(DownloadState.Pending),
DatabaseEmission(listOf(downloadItem())),
State.DownloadInProgress(listOf(downloadItem()))
)
}
@Test
internal fun `Emission without data moves state from Failed to Failed`() {
assertStateTransition(
DownloadFailed(DownloadState.Pending),
DatabaseEmission(listOf()),
DownloadFailed(DownloadState.Pending)
)
}
@Test
internal fun `Emission with data+failure moves state from InProgress to Failed`() {
assertStateTransition(
DownloadInProgress(listOf()),
DatabaseEmission(listOf(downloadItem(state = Failed(NONE)))),
DownloadFailed(Failed(NONE))
)
}
@Test
internal fun `Emission with data moves state from InProgress to InProgress`() {
assertStateTransition(
DownloadInProgress(listOf(downloadItem(downloadId = 1L))),
DatabaseEmission(listOf(downloadItem(downloadId = 2L))),
DownloadInProgress(listOf(downloadItem(downloadId = 2L)))
)
}
@Test
internal fun `Emission without data moves state from InProgress to Complete`() {
val sideEffects = customDownloadViewModel.effects.test()
assertStateTransition(
DownloadInProgress(listOf()),
DatabaseEmission(listOf()),
DownloadComplete
)
sideEffects.assertValues(setPreferredStorageWithMostSpace, finishAndStartMain)
}
@Test
internal fun `Any emission does not change state from Complete`() {
assertStateTransition(
DownloadComplete,
DatabaseEmission(listOf(downloadItem())),
DownloadComplete
)
}
private fun assertStateTransition(
initialState: State,
action: DatabaseEmission,
endState: State
) {
customDownloadViewModel.state.value = initialState
customDownloadViewModel.actions.offer(action)
customDownloadViewModel.state.test().assertValue(endState)
}
}
@Test
internal fun `clicking Retry triggers DownloadCustom`() {
val sideEffects = customDownloadViewModel.effects.test()
customDownloadViewModel.actions.offer(ClickedRetry)
sideEffects.assertValues(setPreferredStorageWithMostSpace, downloadCustom)
}
@Test
internal fun `clicking Download triggers DownloadCustom`() {
val sideEffects = customDownloadViewModel.effects.test()
customDownloadViewModel.actions.offer(ClickedDownload)
sideEffects.assertValues(setPreferredStorageWithMostSpace, downloadCustom)
}
}

View File

@ -0,0 +1,53 @@
/*
* Kiwix Android
* Copyright (c) 2019 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.custom.download.effects
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.downloader.Downloader
import org.kiwix.sharedFunctions.book
internal class DownloadCustomTest {
@Test
fun `invokeWith queues download with ZimUrl`() {
val downloader = mockk<Downloader>()
DownloadCustom(downloader).invokeWith(mockk())
verify {
downloader.download(expectedBook())
}
}
private fun expectedBook() = book(
"custom",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
)
}

View File

@ -0,0 +1,40 @@
/*
* Kiwix Android
* Copyright (c) 2019 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.custom.download.effects
import android.app.Activity
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Test
internal class FinishAndStartMainTest {
@Test
fun `invokeWith finishes activity and starts main`() {
val activity = mockk<Activity>()
// Inline functions cannot be mocked
// mockkObject(ActivityExtensions)
// every { start<CustomMainActivity>(null) } just Runs issues with inline extension functions
FinishAndStartMain().invokeWith(activity)
verify {
activity.finish()
activity.startActivity(any())
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Kiwix Android
* Copyright (c) 2019 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.custom.download.effects
import android.app.Activity
import androidx.core.content.ContextCompat
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import io.mockk.verify
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.settings.StorageCalculator
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import java.io.File
internal class SetPreferredStorageWithMostSpaceTest {
@Test
fun `invokeWith sets the storage with the most space as preferred`() {
val storageCalculator = mockk<StorageCalculator>()
val sharedPreferenceUtil = mockk<SharedPreferenceUtil>()
val activity = mockk<Activity>()
mockkStatic(ContextCompat::class)
val directoryWithMoreStorage = mockk<File>()
val directoryWithLessStorage = mockk<File>()
every { ContextCompat.getExternalFilesDirs(activity, null) } returns arrayOf(
directoryWithMoreStorage, null, directoryWithLessStorage
)
every { storageCalculator.availableBytes(directoryWithMoreStorage) } returns 1
every { storageCalculator.availableBytes(directoryWithLessStorage) } returns 0
val expectedStorage = "expectedStorage"
every { directoryWithMoreStorage.path } returns expectedStorage
SetPreferredStorageWithMostSpace(storageCalculator, sharedPreferenceUtil).invokeWith(activity)
verify {
sharedPreferenceUtil.putPrefStorage(expectedStorage)
}
}
}