Merge pull request #2854 from kiwix/Issue#2851

Upgrading gradle plugin version to 7.1.0
This commit is contained in:
Kelson 2022-06-20 12:03:01 +02:00 committed by GitHub
commit 9defd1eba8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 438 additions and 366 deletions

View File

@ -24,6 +24,11 @@ jobs:
with:
fetch-depth: 1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: create instrumentation coverage
uses: ReactiveCircus/android-emulator-runner@v2.23.0
env:
@ -34,7 +39,6 @@ jobs:
ndk: 21.4.7075529
script: bash contrib/instrumentation.sh
- name: Upload screenshot result
uses: actions/upload-artifact@v1
if: failure()
@ -48,8 +52,7 @@ jobs:
- name: Upload coverage to Codecov
if: ${{ matrix.api-level==21 }}
run: |
bash <(curl -s https://codecov.io/bash)
uses: codecov/codecov-action@v2
- name: Upload Coverage to GH-Actions
uses: actions/upload-artifact@v2.2.0

View File

@ -44,6 +44,11 @@ jobs:
with:
fetch-depth: 1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Install NDK
run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;22.0.7026061" --sdk_root=${ANDROID_SDK_ROOT}
@ -70,4 +75,3 @@ jobs:
mkdir $DATE
cp $UNIVERSAL_DEBUG_APK $DATE
scp -P 30022 -vrp -i ssh_key -o StrictHostKeyChecking=no $DATE ci@master.download.kiwix.org:/data/download/nightly/

View File

@ -13,6 +13,11 @@ jobs:
with:
fetch-depth: 1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Static Analysis
run: ./gradlew ktlintCheck detekt app:lintDebug custom:lintCustomexampleDebug
@ -34,6 +39,11 @@ jobs:
with:
fetch-depth: 1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Install NDK
run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;22.0.7026061" --sdk_root=${ANDROID_SDK_ROOT}

View File

@ -17,6 +17,11 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Decrypt files
env:
keystore: ${{ secrets.keystore }}

View File

@ -30,8 +30,8 @@ fun generateVersionName() = "${ext["versionMajor"]}.${ext["versionMinor"]}.${ext
fun generateVersionCode() =
20 * 10000 +
((ext["versionMajor"] as Int) * 10000) +
((ext["versionMinor"] as Int) * 100) +
ext["versionMajor"] as Int * 10000 +
ext["versionMinor"] as Int * 100 +
ext["versionPatch"] as Int
val apkPrefix get() = System.getenv("TAG") ?: "dev"
@ -45,7 +45,6 @@ android {
versionCode = generateVersionCode()
versionName = generateVersionName()
}
lintOptions {
isCheckDependencies = true
}
@ -78,11 +77,11 @@ android {
}
play {
isEnabled = true
serviceAccountCredentials = file("../google.json")
track = "alpha"
releaseStatus = "draft"
resolutionStrategy = "fail"
enabled.set(true)
serviceAccountCredentials.set(file("../google.json"))
track.set("alpha")
releaseStatus.set(com.github.triplet.gradle.androidpublisher.ReleaseStatus.DRAFT)
resolutionStrategy.set(com.github.triplet.gradle.androidpublisher.ResolutionStrategy.FAIL)
}
dependencies {

View File

@ -1,19 +1,19 @@
<?xml version="1.0" ?>
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<Blacklist></Blacklist>
<Whitelist>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>EmptyFunctionBlock:None.kt$None${ }</ID>
<ID>EmptyFunctionBlock:SimplePageChangeListener.kt$SimplePageChangeListener${ }</ID>
<ID>LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( booksOnFileSystem: List&lt;BookOnDisk&gt;, activeDownloads: List&lt;DownloadModel&gt;, allLanguages: List&lt;Language&gt;, libraryNetworkEntity: LibraryNetworkEntity, filter: String, fileSystemState: FileSystemState )</ID>
<ID>LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( booksOnFileSystem: List&lt;BookOnDisk>, activeDownloads: List&lt;DownloadModel>, allLanguages: List&lt;Language>, libraryNetworkEntity: LibraryNetworkEntity, filter: String, fileSystemState: FileSystemState )</ID>
<ID>LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( private val downloadDao: FetchDownloadDao, private val bookDao: NewBookDao, private val languageDao: NewLanguagesDao, private val storageObserver: StorageObserver, private val kiwixService: KiwixService, private val context: Application, private val connectivityBroadcastReceiver: ConnectivityBroadcastReceiver, private val bookUtils: BookUtils, private val fat32Checker: Fat32Checker, private val defaultLanguageProvider: DefaultLanguageProvider, private val dataSource: DataSource, private val connectivityManager: ConnectivityManager, private val sharedPreferenceUtil: SharedPreferenceUtil )</ID>
<ID>MagicNumber:LibraryListItem.kt$LibraryListItem.LibraryDownloadItem$1000L</ID>
<ID>MagicNumber:PeerGroupHandshake.kt$PeerGroupHandshake$15000</ID>
<ID>MagicNumber:ShareFiles.kt$ShareFiles$24</ID>
<ID>MagicNumber:ZimManageViewModel.kt$ZimManageViewModel$5</ID>
<ID>MagicNumber:ZimManageViewModel.kt$ZimManageViewModel$500</ID>
<ID>NestedBlockDepth:LocalLibraryFragment.kt$LocalLibraryFragment$checkPermissions</ID>
<ID>NestedBlockDepth:PeerGroupHandshake.kt$PeerGroupHandshake$readHandshakeAndExchangeMetaData</ID>
<ID>NestedBlockDepth:ReceiverHandShake.kt$ReceiverHandShake$exchangeFileTransferMetadata</ID>
<ID>NestedBlockDepth:LocalLibraryFragment.kt$LocalLibraryFragment$private fun checkPermissions()</ID>
<ID>NestedBlockDepth:PeerGroupHandshake.kt$PeerGroupHandshake$private fun readHandshakeAndExchangeMetaData(): InetAddress?</ID>
<ID>NestedBlockDepth:ReceiverHandShake.kt$ReceiverHandShake$override fun exchangeFileTransferMetadata(inputStream: InputStream, outputStream: OutputStream)</ID>
<ID>PackageNaming:AvailableSpaceCalculator.kt$package org.kiwix.kiwixmobile.zim_manager.library_view</ID>
<ID>PackageNaming:ConnectivityBroadcastReceiver.kt$package org.kiwix.kiwixmobile.zim_manager</ID>
<ID>PackageNaming:DefaultLanguageProvider.kt$package org.kiwix.kiwixmobile.zim_manager</ID>
@ -46,5 +46,5 @@
<ID>TooGenericExceptionThrown:LibraryViewHolder.kt$LibraryViewHolder.LibraryBookViewHolder$throw RuntimeException("impossible invalid state: ${item.fileSystemState}")</ID>
<ID>TooGenericExceptionThrown:ZimManageViewModel.kt$ZimManageViewModel$throw RuntimeException("Impossible state")</ID>
<ID>VariableNaming:PeerGroupHandshake.kt$PeerGroupHandshake$private val HANDSHAKE_MESSAGE = "Request Kiwix File Sharing"</ID>
</Whitelist>
</CurrentIssues>
</SmellBaseline>

View File

@ -108,4 +108,4 @@ private fun resourceId(view: View) =
if (view.id > 0 && view.resources != null) " id:${view.resources.getResourceName(view.id)}"
else ""
private fun numSpaces(marginOffset: Int) = (0..marginOffset).fold("", { acc, _ -> "$acc-" })
private fun numSpaces(marginOffset: Int) = (0..marginOffset).fold("") { acc, _ -> "$acc-" }

View File

@ -48,7 +48,7 @@ abstract class BaseActivityTest {
getInstrumentation().targetContext.applicationContext
}
inline fun <reified T : Activity> activityTestRule(
protected inline fun <reified T : Activity> activityTestRule(
noinline beforeActivityAction: (() -> Unit)? = null
) =
object : ActivityTestRule<T>(T::class.java) {

View File

@ -40,8 +40,8 @@ class Matcher {
public override fun matchesSafely(view: View): Boolean {
val parent = view.parent
return parent is ViewGroup && parentMatcher.matches(parent) && view == parent.getChildAt(
position
)
position
)
}
}
}

View File

@ -32,7 +32,8 @@
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@style/KiwixTheme.Launcher"
android:windowSoftInputMode="adjustPan">
android:windowSoftInputMode="adjustPan"
android:exported="true">
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
@ -145,7 +146,8 @@
<service android:name=".webserver.wifi_hotspot.HotspotService" />
<receiver android:name=".main.KiwixSearchWidget">
<receiver android:name=".main.KiwixSearchWidget"
android:exported="true">
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/kiwix_widget_provider_info" />

View File

@ -72,14 +72,18 @@ class IntroFragment : BaseFragment(), IntroContract.View, FragmentActivityExtens
addOnPageChangeListener(SimplePageChangeListener(::updateView, ::handleDraggingState))
}
tab_indicator.setViewPager(view_pager)
timer?.schedule(object : TimerTask() {
override fun run() {
handler.post {
if (currentPage == views.size) currentPage = 0
view_pager.setCurrentItem(currentPage++, true)
timer?.schedule(
object : TimerTask() {
override fun run() {
handler.post {
if (currentPage == views.size) currentPage = 0
view_pager.setCurrentItem(currentPage++, true)
}
}
}
}, timerDelay, timerPeriod)
},
timerDelay,
timerPeriod
)
views.forEach {
it.setOnClickListener { dismissAutoRotate() }
}

View File

@ -125,9 +125,11 @@ class LanguageFragment : BaseFragment() {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_language, menu)
val search = menu.findItem(R.id.menu_language_search)
(search.actionView as SearchView).setOnQueryTextListener(SimpleTextListener {
languageViewModel.actions.offer(Filter(it))
})
(search.actionView as SearchView).setOnQueryTextListener(
SimpleTextListener {
languageViewModel.actions.offer(Filter(it))
}
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {

View File

@ -82,7 +82,8 @@ import javax.inject.Inject
const val URIS_KEY = "uris"
@SuppressLint("GoogleAppIndexingApiWarning", "Registered")
class LocalFileTransferFragment : BaseFragment(),
class LocalFileTransferFragment :
BaseFragment(),
WifiDirectManager.Callbacks {
@Inject
lateinit var alertDialogShower: AlertDialogShower

View File

@ -66,7 +66,8 @@ abstract class PeerGroupHandshake(private var groupInfo: WifiP2pInfo) {
InetSocketAddress(
groupInfo.groupOwnerAddress.hostAddress,
PEER_HANDSHAKE_PORT
), 15000
),
15000
)
val objectOutputStream = ObjectOutputStream(client.getOutputStream())
// Send message for the peer device to verify

View File

@ -112,16 +112,19 @@ class WifiDirectManager @Inject constructor(
private fun unregisterWifiDirectBroadcastReceiver() = context.unregisterReceiver(receiver)
fun discoverPeerDevices() {
manager?.discoverPeers(channel, object : ActionListener {
override fun onSuccess() {
context.toast(R.string.discovery_initiated, Toast.LENGTH_SHORT)
}
manager?.discoverPeers(
channel,
object : ActionListener {
override fun onSuccess() {
context.toast(R.string.discovery_initiated, Toast.LENGTH_SHORT)
}
override fun onFailure(reason: Int) {
Log.d(TAG, "${context.getString(R.string.discovery_failed)}: ${getErrorMessage(reason)}")
context.toast(R.string.discovery_failed, Toast.LENGTH_SHORT)
override fun onFailure(reason: Int) {
Log.d(TAG, "${context.getString(R.string.discovery_failed)}: ${getErrorMessage(reason)}")
context.toast(R.string.discovery_failed, Toast.LENGTH_SHORT)
}
}
})
)
}
/* From KiwixWifiP2pBroadcastReceiver.P2pEventListener callback-interface*/
@ -188,7 +191,8 @@ class WifiDirectManager @Inject constructor(
hasSenderStartedConnection = true
connect(senderSelectedPeerDevice)
context.toast(R.string.performing_handshake, Toast.LENGTH_LONG)
})
}
)
}
}
@ -197,17 +201,21 @@ class WifiDirectManager @Inject constructor(
deviceAddress = senderSelectedPeerDevice.deviceAddress
wps.setup = WpsInfo.PBC
}
manager?.connect(channel, config, object : ActionListener {
override fun onSuccess() {
// UI updated from broadcast receiver
}
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, context.getString(R.string.connection_failed) + ": " + errorMessage)
context.toast(R.string.connection_failed, Toast.LENGTH_LONG)
override fun onFailure(reason: Int) {
val errorMessage = getErrorMessage(reason)
Log.d(TAG, context.getString(R.string.connection_failed) + ": " + errorMessage)
context.toast(R.string.connection_failed, Toast.LENGTH_LONG)
}
}
})
)
}
private fun performHandshakeWith(groupInfo: WifiP2pInfo) {
@ -291,17 +299,20 @@ class WifiDirectManager @Inject constructor(
}
private fun disconnect() {
manager?.removeGroup(channel, object : ActionListener {
override fun onFailure(reasonCode: Int) {
Log.d(TAG, "Disconnect failed. Reason: $reasonCode")
closeChannel()
}
manager?.removeGroup(
channel,
object : ActionListener {
override fun onFailure(reasonCode: Int) {
Log.d(TAG, "Disconnect failed. Reason: $reasonCode")
closeChannel()
}
override fun onSuccess() {
Log.d(TAG, "Disconnect successful")
closeChannel()
override fun onSuccess() {
Log.d(TAG, "Disconnect successful")
closeChannel()
}
}
})
)
}
private fun closeChannel() {

View File

@ -94,10 +94,12 @@ class LocalLibraryFragment : BaseFragment() {
}
private val bookDelegate: BookOnDiskDelegate.BookDelegate by lazy {
BookOnDiskDelegate.BookDelegate(sharedPreferenceUtil,
BookOnDiskDelegate.BookDelegate(
sharedPreferenceUtil,
{ offerAction(RequestNavigateTo(it)) },
{ offerAction(RequestMultiSelection(it)) },
{ offerAction(RequestSelect(it)) })
{ offerAction(RequestSelect(it)) }
)
}
private val booksOnDiskAdapter: BooksOnDiskAdapter by lazy {
BooksOnDiskAdapter(bookDelegate, BookOnDiskDelegate.LanguageDelegate)
@ -138,9 +140,9 @@ class LocalLibraryFragment : BaseFragment() {
}
zimManageViewModel.fileSelectListStates.observe(viewLifecycleOwner, Observer(::render))
disposable.add(sideEffects())
zimManageViewModel.deviceListIsRefreshing.observe(viewLifecycleOwner, Observer {
zimManageViewModel.deviceListIsRefreshing.observe(viewLifecycleOwner) {
zim_swiperefresh.isRefreshing = it!!
})
}
if (savedInstanceState != null && savedInstanceState.getBoolean(WAS_IN_ACTION_MODE)) {
zimManageViewModel.fileSelectActions.offer(FileSelectActions.RestartActionMode)
}

View File

@ -43,6 +43,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.observe
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import eu.mhutti1.utils.storage.StorageDevice
@ -107,7 +108,8 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
LibraryDelegate.DownloadDelegate {
dialogShower.show(
KiwixDialog.YesNoDialog.StopDownload,
{ downloader.cancelDownload(it.downloadId) })
{ downloader.cancelDownload(it.downloadId) }
)
},
LibraryDelegate.DividerDelegate
)
@ -153,18 +155,22 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
viewLifecycleOwner, Observer(::onRefreshStateChange)
)
zimManageViewModel.networkStates.observe(viewLifecycleOwner, Observer(::onNetworkStateChange))
zimManageViewModel.shouldShowWifiOnlyDialog.observe(viewLifecycleOwner, Observer {
zimManageViewModel.shouldShowWifiOnlyDialog.observe(
viewLifecycleOwner
) {
if (it) {
showInternetPermissionDialog()
}
})
}
// hides keyboard when scrolled
libraryList.addOnScrollListener(SimpleRecyclerViewScrollListener { _, newState ->
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
libraryList.closeKeyboard()
libraryList.addOnScrollListener(
SimpleRecyclerViewScrollListener { _, newState ->
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
libraryList.closeKeyboard()
}
}
})
)
allowInternetPermissionButton.setOnClickListener {
showInternetPermissionDialog()
@ -405,7 +411,8 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
})
return
}
else -> availableSpaceCalculator.hasAvailableSpaceFor(item,
else -> availableSpaceCalculator.hasAvailableSpaceFor(
item,
{ downloadFile(item.book) },
{
libraryList.snack(
@ -415,7 +422,8 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
R.string.download_change_storage,
::showStorageSelectDialog
)
})
}
)
}
}
}

View File

@ -41,8 +41,9 @@ class KiwixPrefsFragment : CorePrefsFragment() {
override fun setStorage() {
findPreference<Preference>(PREF_STORAGE)?.title = getString(
if (sharedPreferenceUtil.prefStorage == internalStorage()?.let
(sharedPreferenceUtil::getPublicDirectoryPath)
if (sharedPreferenceUtil.prefStorage == internalStorage()?.let(
sharedPreferenceUtil::getPublicDirectoryPath
)
) R.string.internal_storage
else R.string.external_storage
)

View File

@ -17,6 +17,7 @@
*/
package org.kiwix.kiwixmobile.webserver.wifi_hotspot
import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
@ -38,18 +39,20 @@ class HotspotNotificationManager @Inject constructor(
private fun hotspotNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.createNotificationChannel(NotificationChannel(
HOTSPOT_SERVICE_CHANNEL_ID,
context.getString(R.string.hotspot_service_channel_name),
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = context.getString(R.string.hotspot_channel_description)
setSound(null, null)
})
notificationManager.createNotificationChannel(
NotificationChannel(
HOTSPOT_SERVICE_CHANNEL_ID,
context.getString(R.string.hotspot_service_channel_name),
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = context.getString(R.string.hotspot_channel_description)
setSound(null, null)
}
)
}
}
fun buildForegroundNotification(): Notification {
@SuppressLint("UnspecifiedImmutableFlag") fun buildForegroundNotification(): Notification {
val contentIntent = NavDeepLinkBuilder(context).setComponentName(
KiwixMainActivity::class.java
)

View File

@ -483,6 +483,7 @@ class ZimManageViewModel @Inject constructor(
oldBookOnDisk.id == newBookOnDisk.id
}
newBookOnDisk.apply { isSelected = firstOrNull?.isSelected ?: false }
})
}
)
}
}

View File

@ -61,7 +61,8 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.45" />
app:layout_constraintVertical_bias="0.45"
tools:ignore="RequiredSize" />
<Button
android:id="@+id/allowInternetPermissionButton"

View File

@ -64,6 +64,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="RequiredSize"
app:layout_constraintVertical_bias="0.45" />
<Button

View File

@ -12,12 +12,13 @@ repositories {
}
dependencies {
implementation("com.android.tools.build:gradle:4.0.1")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72")
implementation("com.hiya:jacoco-android:0.2")
implementation("org.jlleitschuh.gradle:ktlint-gradle:9.2.1")
implementation("com.android.tools.build:gradle:7.1.0")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.21")
implementation("com.dicedmelon.gradle:jacoco-android:0.1.5")
implementation("org.jlleitschuh.gradle:ktlint-gradle:10.3.0")
implementation("com.google.apis:google-api-services-androidpublisher:v3-rev129-1.25.0")
implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.9.1")
implementation("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.20.0")
implementation("com.googlecode.json-simple:json-simple:1.1")
implementation(gradleApi())
implementation(localGroovy())

View File

@ -22,7 +22,7 @@ object Versions {
const val com_squareup_okhttp3: String = "4.9.0"
const val org_jetbrains_kotlin: String = "1.4.20"
const val org_jetbrains_kotlin: String = "1.4.21"
const val androidx_navigation: String = "2.3.1"
@ -42,11 +42,11 @@ object Versions {
const val android_arch_lifecycle_extensions: String = "1.1.1"
const val com_android_tools_build_gradle: String = "4.0.1" // available: "4.1.1"
const val com_android_tools_build_gradle: String = "7.1.0"
const val de_fayard_buildsrcversions_gradle_plugin: String = "0.7.0"
const val com_github_triplet_play_gradle_plugin: String = "2.8.0" // available: "3.0.0"
const val com_github_triplet_play_gradle_plugin: String = "3.7.0"
const val javax_annotation_api: String = "1.3.2"

View File

@ -23,8 +23,6 @@ import Libs
import com.android.build.gradle.BaseExtension
import io.gitlab.arturbosch.detekt.extensions.DetektExtension
import org.gradle.api.Project
import org.gradle.api.tasks.testing.Test
import org.gradle.kotlin.dsl.KotlinClosure1
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
@ -39,7 +37,7 @@ class AllProjectConfigurer {
target.plugins.apply("kotlin-android")
target.plugins.apply("kotlin-android-extensions")
target.plugins.apply("kotlin-kapt")
target.plugins.apply("com.hiya.jacoco-android")
target.plugins.apply("com.dicedmelon.gradle.jacoco-android")
target.plugins.apply("org.jlleitschuh.gradle.ktlint")
target.plugins.apply("io.gitlab.arturbosch.detekt")
target.plugins.apply("androidx.navigation.safeargs")
@ -75,19 +73,21 @@ class AllProjectConfigurer {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
unitTests.apply {
isReturnDefaultValues = true
all(KotlinClosure1<Any, Test>({
(this as Test).also { testTask ->
all {
it.also { testTask ->
testTask.useJUnitPlatform()
testTask.testLogging {
setEvents(setOf("passed", "skipped", "failed", "standardOut", "standardError"))
outputs.upToDateWhen { false }
testTask.outputs.upToDateWhen { false }
showStandardStreams = true
}
testTask.extensions
.getByType(JacocoTaskExtension::class.java)
.isIncludeNoLocationClasses = true
.getByType(JacocoTaskExtension::class.java).apply {
isIncludeNoLocationClasses = true
excludes = listOf("jdk.internal.*")
}
}
}, this))
}
}
}
@ -104,16 +104,18 @@ class AllProjectConfigurer {
"CheckResult",
"LabelFor",
"LogConditional",
"ConvertToWebp"
)
warning(
"ConvertToWebp",
//TODO remove this when we remove jcenter from gradle
"JcenterRepositoryObsolete",
"UnknownNullness",
"SelectableText",
"MissingTranslation",
"IconDensities",
"ContentDescription",
"IconDipSize"
"IconDipSize",
"UnusedResources",
"NonConstantResourceId",
"NotifyDataSetChanged"
)
lintConfig = target.rootProject.file("lintConfig.xml")
}
@ -144,9 +146,11 @@ class AllProjectConfigurer {
configureExtension<JacocoPluginExtension> { toolVersion = "0.8.7" }
configureExtension<KtlintExtension> { android.set(true) }
configureExtension<DetektExtension> {
buildUponDefaultConfig = true
allRules = false
config = target.files("${target.rootDir}/config/detekt/detekt.yml")
baseline = project.file("detekt_baseline.xml")
}
}
}

View File

@ -2,10 +2,10 @@ build:
maxIssues: 0
excludeCorrectable: false
weights:
# complexity: 2
# LongParameterList: 1
# style: 1
# comments: 1
# complexity: 2
# LongParameterList: 1
# style: 1
# comments: 1
config:
validation: true
@ -25,11 +25,11 @@ processors:
console-reports:
active: true
exclude:
- 'ProjectStatisticsReport'
- 'ComplexityReport'
- 'NotificationReport'
# - 'FindingsReport'
- 'FileBasedFindingsReport'
- 'ProjectStatisticsReport'
- 'ComplexityReport'
- 'NotificationReport'
# - 'FindingsReport'
- 'FileBasedFindingsReport'
comments:
active: true
@ -180,130 +180,22 @@ exceptions:
active: true
excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt"
exceptionNames:
- ArrayIndexOutOfBoundsException
- Error
- Exception
- IllegalMonitorStateException
- NullPointerException
- IndexOutOfBoundsException
- RuntimeException
- Throwable
- ArrayIndexOutOfBoundsException
- Error
- Exception
- IllegalMonitorStateException
- NullPointerException
- IndexOutOfBoundsException
- RuntimeException
- Throwable
allowedExceptionNameRegex: "^(_|(ignore|expected).*)"
TooGenericExceptionThrown:
active: true
exceptionNames:
- Error
- Exception
- Throwable
- RuntimeException
formatting:
active: true
android: false
autoCorrect: true
AnnotationOnSeparateLine:
active: false
autoCorrect: true
ChainWrapping:
active: true
autoCorrect: true
CommentSpacing:
active: true
autoCorrect: true
EnumEntryNameCase:
active: false
autoCorrect: true
Filename:
active: true
FinalNewline:
active: true
autoCorrect: true
ImportOrdering:
active: false
autoCorrect: true
Indentation:
active: false
autoCorrect: true
indentSize: 4
continuationIndentSize: 4
MaximumLineLength:
active: true
maxLineLength: 120
ModifierOrdering:
active: true
autoCorrect: true
MultiLineIfElse:
active: true
autoCorrect: true
NoBlankLineBeforeRbrace:
active: true
autoCorrect: true
NoConsecutiveBlankLines:
active: true
autoCorrect: true
NoEmptyClassBody:
active: true
autoCorrect: true
NoEmptyFirstLineInMethodBlock:
active: false
autoCorrect: true
NoLineBreakAfterElse:
active: true
autoCorrect: true
NoLineBreakBeforeAssignment:
active: true
autoCorrect: true
NoMultipleSpaces:
active: true
autoCorrect: true
NoSemicolons:
active: true
autoCorrect: true
NoTrailingSpaces:
active: true
autoCorrect: true
NoUnitReturn:
active: true
autoCorrect: true
NoUnusedImports:
active: true
autoCorrect: true
NoWildcardImports:
active: true
PackageName:
active: true
autoCorrect: true
ParameterListWrapping:
active: true
autoCorrect: true
indentSize: 4
SpacingAroundColon:
active: true
autoCorrect: true
SpacingAroundComma:
active: true
autoCorrect: true
SpacingAroundCurly:
active: true
autoCorrect: true
SpacingAroundDot:
active: true
autoCorrect: true
SpacingAroundKeyword:
active: true
autoCorrect: true
SpacingAroundOperators:
active: true
autoCorrect: true
SpacingAroundParens:
active: true
autoCorrect: true
SpacingAroundRangeOperator:
active: true
autoCorrect: true
StringTemplate:
active: true
autoCorrect: true
- Error
- Exception
- Throwable
- RuntimeException
naming:
active: true

View File

@ -19,8 +19,34 @@ plugins {
plugins.apply(KiwixConfigurationPlugin::class)
apply(plugin = "io.objectbox")
apply(plugin = "com.jakewharton.butterknife")
ext {
set("versionMajor", 3)
set("versionMinor", 5)
set("versionPatch", 0)
}
/*
* max version code: 21-0-0-00-00-00
* our template : UU-D-A-ZZ-YY-XX
* where:
* X = patch version
* Y = minor version
* Z = major version (+ 20 to distinguish from previous, non semantic, versions of the app)
* A = number representing ABI split
* D = number representing density split
* U = unused
*/
fun generateVersionCode() =
20 * 10000 +
ext["versionMajor"] as Int * 10000 +
ext["versionMinor"] as Int * 100 +
ext["versionPatch"] as Int
android {
defaultConfig {
buildConfigField("long", "VERSION_CODE", "${generateVersionCode()}")
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
@ -31,7 +57,6 @@ android {
fun shouldUseLocalVersion() = File(projectDir, "libs").exists()
dependencies {
// use jdk8 java.time backport, as long app < Build.VERSION_CODES.O
implementation(Libs.threetenabp)

View File

@ -1,18 +1,20 @@
<?xml version="1.0" ?>
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<Blacklist></Blacklist>
<Whitelist>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>EmptyFunctionBlock:BooksOnDiskViewHolder.kt$BookOnDiskViewHolder.BookViewHolder${ }</ID>
<ID>EmptyFunctionBlock:FetchDownloadMonitor.kt$FetchDownloadMonitor.&lt;no name provided&gt;${}</ID>
<ID>EmptyFunctionBlock:FetchDownloadMonitor.kt$FetchDownloadMonitor.&lt;no name provided>${}</ID>
<ID>EmptyFunctionBlock:OnSwipeTouchListener.kt$OnSwipeTouchListener${}</ID>
<ID>ForbiddenComment:JNIInitialiser.kt$JNIInitialiser$// TODO: Consider surfacing to user</ID>
<ID>LongMethod:TabsAdapter.kt$TabsAdapter$onCreateViewHolder</ID>
<ID>LongParameterList:KiwixDialog.kt$KiwixDialog$( val title: Int?, val message: Int?, val positiveMessage: Int, val negativeMessage: Int?, val cancelable: Boolean = true, val icon: Int? = null, val neutralMessage: Int? = null, val getView: (() -&gt; View)? = null )</ID>
<ID>LongParameterList:MainMenu.kt$MainMenu$( private val activity: Activity, zimFileReader: ZimFileReader?, menu: Menu, webViews: MutableList&lt;KiwixWebView&gt;, urlIsValid: Boolean, disableReadAloud: Boolean = false, disableTabs: Boolean = false, private val menuClickListener: MenuClickListener )</ID>
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList&lt;KiwixWebView&gt;, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
<ID>ForbiddenComment:NetworkUtilsTest.kt$NetworkUtilsTest$// TODO: find a way to assert regex matching via JUnit and rewrite the test</ID>
<ID>LongMethod:ChunkUtilsTest.kt$ChunkUtilsTest$@Test fun testGetChunks()</ID>
<ID>LongMethod:TabsAdapter.kt$TabsAdapter$@SuppressLint("ResourceType") override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): ViewHolder</ID>
<ID>LongParameterList:KiwixDialog.kt$KiwixDialog$( val title: Int?, val message: Int?, val positiveMessage: Int, val negativeMessage: Int?, val cancelable: Boolean = true, val icon: Int? = null, val neutralMessage: Int? = null, val getView: (() -> View)? = null )</ID>
<ID>LongParameterList:MainMenu.kt$MainMenu$( private val activity: Activity, zimFileReader: ZimFileReader?, menu: Menu, webViews: MutableList&lt;KiwixWebView>, urlIsValid: Boolean, disableReadAloud: Boolean = false, disableTabs: Boolean = false, private val menuClickListener: MenuClickListener )</ID>
<ID>LongParameterList:MainMenu.kt$MainMenu.Factory$( menu: Menu, webViews: MutableList&lt;KiwixWebView>, urlIsValid: Boolean, menuClickListener: MenuClickListener, disableReadAloud: Boolean, disableTabs: Boolean )</ID>
<ID>LongParameterList:PageTestHelpers.kt$( bookmarkTitle: String = "bookmarkTitle", isSelected: Boolean = false, id: Long = 2, zimId: String = "zimId", zimName: String = "zimName", zimFilePath: String = "zimFilePath", bookmarkUrl: String = "bookmarkUrl", favicon: String = "favicon" )</ID>
<ID>LongParameterList:Repository.kt$Repository$( @param:IO private val io: Scheduler, @param:MainThread private val mainThread: Scheduler, private val bookDao: NewBookDao, private val bookmarksDao: NewBookmarksDao, private val historyDao: HistoryDao, private val languageDao: NewLanguagesDao, private val recentSearchDao: NewRecentSearchDao, private val zimReaderContainer: ZimReaderContainer )</ID>
<ID>LongParameterList:ToolbarScrollingKiwixWebView.kt$ToolbarScrollingKiwixWebView$( context: Context, callback: WebViewCallback, attrs: AttributeSet, nonVideoView: ViewGroup, videoView: ViewGroup, webViewClient: CoreWebViewClient, private val toolbarView: View, private val bottomBarView: View, sharedPreferenceUtil: SharedPreferenceUtil, private val parentNavigationBar: View? = null )</ID>
<ID>MagicNumber:ArticleCount.kt$ArticleCount$1000.0</ID>
<ID>MagicNumber:ArticleCount.kt$ArticleCount$3</ID>
<ID>MagicNumber:CompatFindActionModeCallback.kt$CompatFindActionModeCallback$100</ID>
<ID>MagicNumber:DownloadItem.kt$DownloadItem$1000L</ID>
@ -29,11 +31,15 @@
<ID>MagicNumber:Seconds.kt$Seconds$60</ID>
<ID>MagicNumber:Seconds.kt$Seconds$60.0</ID>
<ID>MagicNumber:TabsAdapter.kt$TabsAdapter$8</ID>
<ID>NestedBlockDepth:FileUtils.kt$FileUtils$deleteZimFile</ID>
<ID>NestedBlockDepth:ImageUtils.kt$ImageUtils$getBitmapFromView</ID>
<ID>NestedBlockDepth:JNIInitialiser.kt$JNIInitialiser$loadICUData</ID>
<ID>NestedBlockDepth:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$onFling</ID>
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$canWrite</ID>
<ID>MatchingDeclarationName:PageTestHelpers.kt$PageImpl : Page</ID>
<ID>MaxLineLength:BookUtilsTest.kt$BookUtilsTest$// this case uses the result from the container nested class inside LanguageUtils. It will be tested in LanguageUtilsTest</ID>
<ID>MaxLineLength:MetaLinkNetworkEntityTest.kt$MetaLinkNetworkEntityTest$"http://www.mirrorservice.org/sites/download.kiwix.org/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim"</ID>
<ID>MaxLineLength:NetworkUtilsTest.kt$NetworkUtilsTest$// Here the Method should return the substring between the first '?' character and the nearest '/' character preceeding it</ID>
<ID>NestedBlockDepth:FileUtils.kt$FileUtils$@JvmStatic @Synchronized fun deleteZimFile(path: String)</ID>
<ID>NestedBlockDepth:ImageUtils.kt$ImageUtils$private fun getBitmapFromView(width: Int, height: Int, viewToDrawFrom: View): Bitmap?</ID>
<ID>NestedBlockDepth:JNIInitialiser.kt$JNIInitialiser$private fun loadICUData(context: Context): String?</ID>
<ID>NestedBlockDepth:OnSwipeTouchListener.kt$OnSwipeTouchListener.GestureListener$override fun onFling( e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float ): Boolean</ID>
<ID>NestedBlockDepth:StorageDeviceUtils.kt$StorageDeviceUtils$// Amazingly file.canWrite() does not always return the correct value private fun canWrite(file: File): Boolean</ID>
<ID>PackageNaming:ArticleCount.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
<ID>PackageNaming:BookOnDiskDelegate.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter</ID>
<ID>PackageNaming:BooksOnDiskAdapter.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter</ID>
@ -45,7 +51,7 @@
<ID>PackageNaming:MountPointProducer.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
<ID>PackageNaming:SelectionMode.kt$package org.kiwix.kiwixmobile.core.zim_manager.fileselect_view</ID>
<ID>PackageNaming:TagsView.kt$package org.kiwix.kiwixmobile.core.zim_manager</ID>
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun getAllZimParts(book: Book): List&lt;File&gt;</ID>
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun getAllZimParts(book: Book): List&lt;File></ID>
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun getLocalFilePathByUri( context: Context, uri: Uri ): String?</ID>
<ID>ReturnCount:FileUtils.kt$FileUtils$@JvmStatic fun hasPart(file: File): Boolean</ID>
<ID>ReturnCount:FileUtils.kt$FileUtils$@Synchronized private fun deleteZimFileParts(path: String): Boolean</ID>
@ -68,5 +74,5 @@
<ID>TopLevelPropertyNaming:Bytes.kt$const val Mb = Kb * 1024</ID>
<ID>TopLevelPropertyNaming:Bytes.kt$const val Pb = Tb * 1024</ID>
<ID>TopLevelPropertyNaming:Bytes.kt$const val Tb = Gb * 1024</ID>
</Whitelist>
</CurrentIssues>
</SmellBaseline>

View File

@ -4,7 +4,8 @@
android:installLocation="auto">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

View File

@ -22,8 +22,10 @@ import android.view.View
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import kotlinx.android.extensions.LayoutContainer
abstract class BaseViewHolder<in ITEM>(override val containerView: View) : ViewHolder(
containerView
), LayoutContainer {
abstract class BaseViewHolder<in ITEM>(override val containerView: View) :
ViewHolder(
containerView
),
LayoutContainer {
abstract fun bind(item: ITEM)
}

View File

@ -30,9 +30,11 @@ import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import javax.inject.Inject
class NewBookmarksDao @Inject constructor(val box: Box<BookmarkEntity>) : PageDao {
fun bookmarks(): Flowable<List<Page>> = box.asFlowable(box.query {
order(BookmarkEntity_.bookmarkTitle)
}).map { it.map(::BookmarkItem) }
fun bookmarks(): Flowable<List<Page>> = box.asFlowable(
box.query {
order(BookmarkEntity_.bookmarkTitle)
}
).map { it.map(::BookmarkItem) }
override fun pages(): Flowable<List<Page>> = bookmarks()
override fun deletePages(pagesToDelete: List<Page>) =
@ -55,7 +57,8 @@ class NewBookmarksDao @Inject constructor(val box: Box<BookmarkEntity>) : PageDa
.or()
.equal(BookmarkEntity_.zimName, zimFileReader?.name ?: "")
order(BookmarkEntity_.bookmarkTitle)
}).map { it.map(BookmarkEntity::bookmarkUrl) }
}
).map { it.map(BookmarkEntity::bookmarkUrl) }
.subscribeOn(Schedulers.io())
fun saveBookmark(bookmarkItem: BookmarkItem) {

View File

@ -68,7 +68,8 @@ class Repository @Inject internal constructor(
.map {
HeaderizableList<BooksOnDiskListItem, BookOnDisk, LanguageItem>(it).foldOverAddingHeaders(
{ bookOnDisk -> LanguageItem(bookOnDisk.locale) },
{ current, next -> current.locale.displayName != next.locale.displayName })
{ current, next -> current.locale.displayName != next.locale.displayName }
)
}
.map { it.toList() }

View File

@ -45,9 +45,11 @@ class NetworkModule {
.connectTimeout(CONNECTION_TIMEOUT, SECONDS)
.readTimeout(READ_TIMEOUT, SECONDS)
.callTimeout(CALL_TIMEOUT, SECONDS)
.addNetworkInterceptor(HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) BASIC else NONE
})
.addNetworkInterceptor(
HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) BASIC else NONE
}
)
.addNetworkInterceptor(UserAgentInterceptor(USER_AGENT))
.build()
}

View File

@ -17,6 +17,7 @@
*/
package org.kiwix.kiwixmobile.core.downloader.fetch
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
@ -107,6 +108,7 @@ class FetchDownloadNotificationManager(context: Context) :
notificationCustomisation(downloadNotification, notificationBuilder, context)
}
@SuppressLint("UnspecifiedImmutableFlag")
private fun notificationCustomisation(
downloadNotification: DownloadNotification,
notificationBuilder: NotificationCompat.Builder,

View File

@ -17,6 +17,7 @@
*/
package org.kiwix.kiwixmobile.core.error
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Build
import android.os.Bundle
@ -139,7 +140,7 @@ open class ErrorActivity : BaseActivity() {
All Zim Files in DB:
$allZimFiles
""".trimIndent()
""".trimIndent()
}
private fun languageLocale(): String = """
@ -184,13 +185,15 @@ open class ErrorActivity : BaseActivity() {
get() = """
Hi Kiwix Developers!
The Android app crashed, here are some details to help fix it:
""".trimIndent()
""".trimIndent()
private val versionCode: Int
@SuppressLint("WrongConstant")
get() = packageManager
.getPackageInfo(packageName, ZERO).versionCode
private val versionName: String
@SuppressLint("WrongConstant")
get() = packageManager
.getPackageInfo(packageName, ZERO).versionName

View File

@ -29,11 +29,13 @@ fun Book.calculateSearchMatches(
) {
val searchableText = buildSearchableText(bookUtils)
searchMatches = filter.split("\\s+")
.foldRight(0,
.foldRight(
0,
{ filterWord, acc ->
if (searchableText.contains(filterWord, true)) acc + 1
else acc
})
}
)
}
fun Book.buildSearchableText(bookUtils: BookUtils): String =

View File

@ -85,10 +85,14 @@ abstract class HelpFragment : BaseFragment() {
private fun sendFeedback() {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = ("mailto:${Uri.encode(CONTACT_EMAIL_ADDRESS)}" +
"?subject=${
Uri.encode("Feedback in ${getCurrentLocale(requireActivity()).displayLanguage}")
}").toUri()
intent.data = (
"mailto:${Uri.encode(CONTACT_EMAIL_ADDRESS)}" +
"?subject=" +
Uri.encode(
"Feedback in " +
getCurrentLocale(requireActivity()).displayLanguage
)
).toUri()
startActivity(Intent.createChooser(intent, "Send Feedback via Email"))
}
}

View File

@ -243,11 +243,13 @@ class AddNoteDialog : DialogFragment() {
// Show the previously saved note if it exists
displayNote()
add_note_edit_text.addTextChangedListener(SimpleTextWatcher { _, _, _, _ ->
noteEdited = true
enableSaveNoteMenuItem()
enableShareNoteMenuItem()
})
add_note_edit_text.addTextChangedListener(
SimpleTextWatcher { _, _, _, _ ->
noteEdited = true
enableSaveNoteMenuItem()
enableShareNoteMenuItem()
}
)
if (!noteFileExists) {
// Prepare for input in case of empty/new note
add_note_edit_text.requestFocus()

View File

@ -17,6 +17,7 @@
*/
package org.kiwix.kiwixmobile.core.main
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
@ -46,6 +47,7 @@ abstract class CoreSearchWidget : AppWidgetProvider() {
}
}
@SuppressLint("UnspecifiedImmutableFlag")
private fun pendingIntent(context: Context, action: String) = PendingIntent.getActivity(
context,
(System.currentTimeMillis() % Int.MAX_VALUE).toInt(),

View File

@ -58,16 +58,19 @@ class KiwixTextToSpeech internal constructor(
private val focusLock: Any = Any()
private val am: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
@JvmField var currentTTSTask: TTSTask? = null
private val tts: TextToSpeech = TextToSpeech(instance, OnInitListener { status: Int ->
if (status == SUCCESS) {
Log.d(TAG_KIWIX, "TextToSpeech was initialized successfully.")
this.isInitialized = true
onInitSucceedListener.onInitSucceed()
} else {
Log.e(TAG_KIWIX, "Initialization of TextToSpeech Failed!")
context.toast(R.string.texttospeech_initialization_failed, Toast.LENGTH_SHORT)
private val tts: TextToSpeech = TextToSpeech(
instance,
OnInitListener { status: Int ->
if (status == SUCCESS) {
Log.d(TAG_KIWIX, "TextToSpeech was initialized successfully.")
this.isInitialized = true
onInitSucceedListener.onInitSucceed()
} else {
Log.e(TAG_KIWIX, "Initialization of TextToSpeech Failed!")
context.toast(R.string.texttospeech_initialization_failed, Toast.LENGTH_SHORT)
}
}
})
)
/**
* Returns whether the TTS is initialized.
@ -139,7 +142,7 @@ class KiwixTextToSpeech internal constructor(
Array.prototype.forEach.call(toRemove, function(elem) {
elem.parentElement.removeChild(elem);});
tts.speakAloud(body.innerText);
""".trimIndent()
""".trimIndent()
)
}

View File

@ -166,9 +166,11 @@ open class KiwixWebView @SuppressLint("SetJavaScriptEnabled") constructor(
}
val fileToSave = sequence {
yield(File(root, fileName))
yieldAll(generateSequence(1) { it + 1 }.map {
File(root, fileName.replace(".", "_$it."))
})
yieldAll(
generateSequence(1) { it + 1 }.map {
File(root, fileName.replace(".", "_$it."))
}
)
}.first { !it.exists() }
val source = Uri.parse(src)
try {

View File

@ -102,9 +102,11 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
inflater.inflate(R.menu.menu_page, menu)
val search = menu.findItem(R.id.menu_page_search).actionView as SearchView
search.queryHint = searchQueryHint
search.setOnQueryTextListener(SimpleTextListener {
pageViewModel.actions.offer(Action.Filter(it))
})
search.setOnQueryTextListener(
SimpleTextListener {
pageViewModel.actions.offer(Action.Filter(it))
}
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -139,11 +141,13 @@ abstract class PageFragment : OnItemClickListener, BaseFragment(), FragmentActiv
pageViewModel.state.observe(viewLifecycleOwner, Observer(::render))
// hides keyboard when scrolled
recycler_view.addOnScrollListener(SimpleRecyclerViewScrollListener { _, newState ->
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
recycler_view.closeKeyboard()
recycler_view.addOnScrollListener(
SimpleRecyclerViewScrollListener { _, newState ->
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
recycler_view.closeKeyboard()
}
}
})
)
}
override fun onCreateView(

View File

@ -39,7 +39,9 @@ data class ShowDeleteBookmarksDialog(
@Inject lateinit var dialogShower: DialogShower
override fun invokeWith(activity: AppCompatActivity) {
activity.cachedComponent.inject(this)
dialogShower.show(if (state.isInSelectionState) DeleteSelectedBookmarks else DeleteAllBookmarks,
{ effects.offer(DeletePageItems(state, pageDao)) })
dialogShower.show(
if (state.isInSelectionState) DeleteSelectedBookmarks else DeleteAllBookmarks,
{ effects.offer(DeletePageItems(state, pageDao)) }
)
}
}

View File

@ -32,8 +32,10 @@ data class HistoryState(
) : PageState<HistoryItem>() {
override val visiblePageItems: List<HistoryListItem> =
HeaderizableList<HistoryListItem, HistoryItem, DateItem>(filteredPageItems)
.foldOverAddingHeaders({ historyItem -> DateItem(historyItem.dateString) },
{ current, next -> current.dateString != next.dateString })
.foldOverAddingHeaders(
{ historyItem -> DateItem(historyItem.dateString) },
{ current, next -> current.dateString != next.dateString }
)
override fun copyWithNewItems(newItems: List<HistoryItem>): PageState<HistoryItem> =
copy(pageItems = (newItems))

View File

@ -119,7 +119,8 @@ class SearchFragment : BaseFragment() {
override fun handleOnBackPressed() {
goBack()
}
})
}
)
}
private fun setupToolbar(view: View) {
@ -149,11 +150,13 @@ class SearchFragment : BaseFragment() {
val searchMenuItem = menu.findItem(R.id.menu_search)
searchMenuItem.expandActionView()
searchView = searchMenuItem.actionView as SearchView
searchView.setOnQueryTextListener(SimpleTextListener {
if (it.isNotEmpty()) {
searchViewModel.actions.offer(Filter(it))
searchView.setOnQueryTextListener(
SimpleTextListener {
if (it.isNotEmpty()) {
searchViewModel.actions.offer(Filter(it))
}
}
})
)
searchMenuItem.setOnActionExpandListener(object : OnActionExpandListener {
override fun onMenuItemActionExpand(item: MenuItem) = false

View File

@ -25,9 +25,11 @@ import androidx.appcompat.R
object DimenUtils {
@JvmStatic fun Context.getToolbarHeight(): Int {
return resources.getDimensionPixelSize(TypedValue().apply {
theme.resolveAttribute(R.attr.actionBarSize, this, true)
}.resourceId)
return resources.getDimensionPixelSize(
TypedValue().apply {
theme.resolveAttribute(R.attr.actionBarSize, this, true)
}.resourceId
)
}
@JvmStatic fun Activity.getWindowHeight(): Int =

View File

@ -58,6 +58,7 @@ class ExternalLinkOpener @Inject constructor(
{
sharedPreferenceUtil.putPrefExternalLinkPopup(false)
openLink(intent)
})
}
)
}
}

View File

@ -18,6 +18,7 @@
package org.kiwix.kiwixmobile.core.utils
import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.graphics.Typeface
@ -54,12 +55,14 @@ class LanguageUtils(private val context: Context) {
MutableList<LanguageContainer> {
val localeCollator =
Collator.getInstance(context.locale).apply { strength = Collator.SECONDARY }
languageCodesFromAssets.sortWith(Comparator { o1, o2 ->
localeCollator.compare(
o1.languageName,
o2.languageName
)
})
languageCodesFromAssets.sortWith(
Comparator { o1, o2 ->
localeCollator.compare(
o1.languageName,
o2.languageName
)
}
)
return languageCodesFromAssets
}
@ -80,7 +83,10 @@ class LanguageUtils(private val context: Context) {
// which also sets a Factory on the LayoutInflator, we have to access the private field of the
// LayoutInflater, that handles this restriction via Java's reflection API
// and make it accessible set it to false again.
fun changeFont(layoutInflater: LayoutInflater, sharedPreferenceUtil: SharedPreferenceUtil) {
@SuppressLint("SoonBlockedPrivateApi") fun changeFont(
layoutInflater: LayoutInflater,
sharedPreferenceUtil: SharedPreferenceUtil
) {
if (!haveToChangeFont(sharedPreferenceUtil)) {
return
@ -187,6 +193,7 @@ class LanguageUtils(private val context: Context) {
}
}
@SuppressLint("AppBundleLocaleChanges")
@JvmStatic
fun handleLocaleChange(context: Context, language: String) {
val locale =

View File

@ -34,9 +34,11 @@ sealed class KiwixDialog(
val getView: (() -> View)? = null
) {
data class DeleteZims(override val args: List<Any>) : KiwixDialog(
null, R.string.delete_zim_body, R.string.delete, R.string.no
), HasBodyFormatArgs {
data class DeleteZims(override val args: List<Any>) :
KiwixDialog(
null, R.string.delete_zim_body, R.string.delete, R.string.no
),
HasBodyFormatArgs {
constructor(zimNameList: String) : this(listOf(zimNameList))
}
@ -99,12 +101,14 @@ sealed class KiwixDialog(
cancelable = false
)
data class ShowHotspotDetails(override val args: List<Any>) : KiwixDialog(
R.string.hotspot_turned_on,
R.string.hotspot_details_message,
android.R.string.ok,
null
), HasBodyFormatArgs {
data class ShowHotspotDetails(override val args: List<Any>) :
KiwixDialog(
R.string.hotspot_turned_on,
R.string.hotspot_details_message,
android.R.string.ok,
null
),
HasBodyFormatArgs {
constructor(wifiConfiguration: WifiConfiguration) : this(
listOf(wifiConfiguration.SSID, wifiConfiguration.preSharedKey)
)
@ -125,9 +129,11 @@ sealed class KiwixDialog(
neutralMessage = R.string.hotspot_dialog_neutral_button
)
data class FileTransferConfirmation(override val args: List<Any>) : KiwixDialog(
null, R.string.transfer_to, R.string.yes, android.R.string.cancel
), HasBodyFormatArgs {
data class FileTransferConfirmation(override val args: List<Any>) :
KiwixDialog(
null, R.string.transfer_to, R.string.yes, android.R.string.cancel
),
HasBodyFormatArgs {
constructor(selectedPeerDeviceName: String) : this(listOf(selectedPeerDeviceName))
}

View File

@ -36,8 +36,6 @@ import org.kiwix.kiwixmobile.core.extensions.toast
import java.io.BufferedReader
import java.io.File
import java.io.IOException
import java.lang.Exception
import java.util.ArrayList
object FileUtils {
@ -252,8 +250,10 @@ object FileUtils {
@SuppressLint("WrongConstant")
@JvmStatic fun getPathFromUri(activity: Activity, data: Intent): String? {
val uri: Uri? = data.data
val takeFlags: Int = data.flags and (Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
val takeFlags: Int = data.flags and (
Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
uri?.let {
activity.grantUriPermission(
activity.packageName, it,

View File

@ -27,9 +27,11 @@ inline class KiloByte(private val kilobyteString: String?) {
get() = kilobyteString?.toLongOrNull()?.let {
val units = arrayOf("KB", "MB", "GB", "TB")
val conversion = (log10(it.toDouble()) / log10(1024.0)).toInt()
(DecimalFormat("#,##0.#")
.format(it / 1024.0.pow(conversion.toDouble())) +
" " +
units[conversion])
(
DecimalFormat("#,##0.#")
.format(it / 1024.0.pow(conversion.toDouble())) +
" " +
units[conversion]
)
} ?: ""
}

View File

@ -34,7 +34,8 @@ inline class ArticleCount(val articleCount: String) {
val units = arrayOf("", "K", "M", "B", "T")
val conversion = (log10(size.toDouble()) / 3).toInt()
context.getString(
R.string.articleCount, DecimalFormat("#,##0.#")
R.string.articleCount,
DecimalFormat("#,##0.#")
.format(size / 1000.0.pow(conversion.toDouble())) + units[conversion]
)
}

View File

@ -82,7 +82,8 @@ class ChunkUtilsTest {
assertEquals(
"verify that the same notificationID is passed on to each chunk",
true, listReturned[0].url == url &&
true,
listReturned[0].url == url &&
listReturned[1].url == url &&
listReturned[2].url == url &&
listReturned[3].url == url &&
@ -92,7 +93,8 @@ class ChunkUtilsTest {
assertEquals(
"verify that the same URL is passed on to each chunk",
true, listReturned[0].notificationID == 56 &&
true,
listReturned[0].notificationID == 56 &&
listReturned[1].notificationID == 56 &&
listReturned[2].notificationID == 56 &&
listReturned[3].notificationID == 56 &&

View File

@ -200,32 +200,37 @@ class NetworkUtilsTest {
// Using the standard Kiwix Download URLs
assertEquals(
"URL Parsing", "No Pictures", NetworkUtils.parseURL(
"URL Parsing", "No Pictures",
NetworkUtils.parseURL(
context,
"http://ftpmirror.your.org/pub/kiwix/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim"
)
)
assertEquals(
"URL Parsing", "No Videos", NetworkUtils.parseURL(
"URL Parsing", "No Videos",
NetworkUtils.parseURL(
context,
"http://www.mirrorservice.org/sites/download.kiwix.org/zim/wikipedia/" +
"wikipedia_af_all_novid_2016-05.zim"
)
)
assertEquals(
"URL Parsing", "Simple", NetworkUtils.parseURL(
"URL Parsing", "Simple",
NetworkUtils.parseURL(
context,
"http://download.wikimedia.org/kiwix/zim/wikipedia/wikipedia_af_all_simple_2016-05.zim"
)
)
assertEquals(
"URL Parsing", "No Pictures", NetworkUtils.parseURL(
"URL Parsing", "No Pictures",
NetworkUtils.parseURL(
context,
"http://mirror.netcologne.de/kiwix/zim/wikipedia/wikipedia_af_all_nopic_2016-05.zim"
)
)
assertEquals(
"URL Parsing", "Simple", NetworkUtils.parseURL(
"URL Parsing", "Simple",
NetworkUtils.parseURL(
context,
"http://mirror3.kiwix.org/zim/wikipedia/wikipedia_af_all_simple_2016-05.zim"
)

View File

@ -34,7 +34,7 @@ internal class ServerUtilsTest {
fec0::d8d1:9ff:fe42:160c
fec0::8d6e:2327:6d9f:ce75
192.168.200.2
""".trimIndent()
""".trimIndent()
)
).isEqualTo(
"192.168.232.2"

View File

@ -105,7 +105,8 @@ class FileSearchTest {
val zimFile = File.createTempFile(
"fileToFind",
".zim",
File("$tempRoot${File.separator}dir").apply { mkdirs() })
File("$tempRoot${File.separator}dir").apply(File::mkdirs)
)
every { contentResolver.query(any(), any(), any(), any(), any()) } returns null
every { storageDevice.name } returns zimFile.parentFile.parent
val fileList = fileSearch.scan()

View File

@ -20,7 +20,7 @@ android {
}
flavorDimensions("default")
productFlavors {
productFlavors.apply {
CustomApps.createDynamically(project.file("src"), this)
all {
File("$projectDir/src", "$name/$name.zim").let {

View File

@ -17,7 +17,8 @@
android:configChanges="orientation|keyboardHidden|screenSize|locale"
android:theme="@style/KiwixTheme.Launcher"
android:label="@string/app_name"
android:windowSoftInputMode="adjustPan">
android:windowSoftInputMode="adjustPan"
android:exported="true">
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
@ -53,7 +54,8 @@
</intent-filter>
</activity>
<receiver android:name=".main.CustomSearchWidget">
<receiver android:name=".main.CustomSearchWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="KiwixSearchWidget.TEXT_CLICKED" />

View File

@ -183,9 +183,11 @@ class CustomReaderFragment : CoreReaderFragment() {
}
private fun goToSettings() {
startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", activity?.packageName, null)
})
startActivity(
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", activity?.packageName, null)
}
)
}
private fun readStorageHasBeenPermanentlyDenied(grantResults: IntArray) =

View File

@ -1,6 +1,6 @@
#Tue Feb 25 11:46:45 IST 2020
#Wed Jun 01 10:28:35 IST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip
zipStoreBase=GRADLE_USER_HOME

View File

@ -4,7 +4,20 @@
<ignore path="**-qq/**.xml" />
<ignore path="**-iw/**.xml" />
</issue>
<issue id="LintError">
<ignore regexp=".*BookmarksRobot.kt.*"/>
<ignore regexp=".*DebugFunctions.kt.*"/>
<ignore regexp=".*HistoryRobot.kt.*"/>
<ignore regexp=".*IntroRobot.kt.*"/>
<ignore regexp=".*LanguageRobot.kt.*"/>
<ignore regexp=".*LibraryRobot.kt.*"/>
<ignore regexp=".*LocalFileTransferRobot.kt.*"/>
<ignore regexp=".*OnlineLibraryRobot.kt.*"/>
<ignore regexp=".*ReaderRobot.kt.*"/>
<ignore regexp=".*SettingsRobot.kt.*"/>
<ignore regexp=".*TopLevelDestinationRobot.kt.*"/>
<ignore regexp=".*ZimHostRobot.kt.*"/>
</issue>
<issue id="TypographyEllipsis">
<ignore path="**-iw/**.xml" />
</issue>
@ -19,10 +32,11 @@
<issue id="InvalidPackage">
<ignore path="**simple-xml-2.7.1.jar" />
<ignore path="**/squidb*.jar" />
<ignore path="**/org.jacoco.agent-0.8.3-runtime.jar" />
</issue>
<issue id="IconLocation">
<ignore path="src/main/res/drawable/kiwix_icon_with_title.png" />
<ignore path="src/main/res/drawable/search_widget_preview.png" />
<ignore path="core/src/main/res/drawable/search_widget_preview.png" />
</issue>
<issue id="ConvertToWebp">
<ignore path="src/main/res/drawable/search_widget_preview.png" />