mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
64 Custom apps should validate their expansion files and re-download if corrupt/missing - add Custom Download flow
This commit is contained in:
parent
fed540a390
commit
c05742d02a
@ -19,40 +19,17 @@
|
||||
package org.kiwix.kiwixmobile;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import org.kiwix.kiwixmobile.core.ViewModelFactory;
|
||||
import org.kiwix.kiwixmobile.di.KiwixScope;
|
||||
|
||||
@KiwixScope
|
||||
public class KiwixViewModelFactory implements ViewModelProvider.Factory {
|
||||
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
|
||||
public class KiwixViewModelFactory extends ViewModelFactory {
|
||||
|
||||
@Inject
|
||||
public KiwixViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
|
||||
this.creators = creators;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends ViewModel> T create(Class<T> modelClass) {
|
||||
Provider<? extends ViewModel> creator = creators.get(modelClass);
|
||||
if (creator == null) {
|
||||
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
|
||||
if (modelClass.isAssignableFrom(entry.getKey())) {
|
||||
creator = entry.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (creator == null) {
|
||||
throw new IllegalArgumentException("unknown model class " + modelClass);
|
||||
}
|
||||
try {
|
||||
return (T) creator.get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
super(creators);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
||||
import org.kiwix.kiwixmobile.language.adapter.LanguageListItem.LanguageItem
|
||||
import org.kiwix.kiwixmobile.language.viewmodel.Action.Filter
|
||||
@ -31,7 +32,6 @@ import org.kiwix.kiwixmobile.language.viewmodel.Action.UpdateLanguages
|
||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Content
|
||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Loading
|
||||
import org.kiwix.kiwixmobile.language.viewmodel.State.Saving
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.SideEffect
|
||||
import javax.inject.Inject
|
||||
|
||||
class LanguageViewModel @Inject constructor(
|
||||
|
@ -22,7 +22,7 @@ import io.reactivex.Flowable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.Language
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
|
||||
data class SaveLanguagesAndFinish(
|
||||
val languages: List<Language>,
|
||||
|
@ -66,7 +66,7 @@ import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.DeleteFiles
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.None
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.OpenFile
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.ShareFiles
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects.StartMultiSelection
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.BookItem
|
||||
|
@ -17,7 +17,6 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.zim_manager.download_view
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
@ -29,12 +28,6 @@ import kotlinx.android.synthetic.main.download_item.favicon
|
||||
import kotlinx.android.synthetic.main.download_item.stop
|
||||
import kotlinx.android.synthetic.main.download_item.title
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Failed
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Paused
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Pending
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Running
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState.Successful
|
||||
import org.kiwix.kiwixmobile.core.extensions.setBitmap
|
||||
|
||||
class DownloadViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
|
||||
@ -50,21 +43,7 @@ class DownloadViewHolder(override val containerView: View) : RecyclerView.ViewHo
|
||||
stop.setOnClickListener {
|
||||
itemClickListener.invoke(downloadItem)
|
||||
}
|
||||
downloadState.text = toReadableState(downloadItem.downloadState, containerView.context)
|
||||
eta.text = downloadItem.eta.takeIf { it.seconds > 0L }?.toHumanReadableTime() ?: ""
|
||||
}
|
||||
|
||||
private fun toReadableState(
|
||||
downloadState: DownloadState,
|
||||
context: Context
|
||||
) = when (downloadState) {
|
||||
is Failed -> context.getString(
|
||||
downloadState.stringId,
|
||||
downloadState.reason.name
|
||||
)
|
||||
Pending,
|
||||
Running,
|
||||
Paused,
|
||||
Successful -> context.getString(downloadState.stringId)
|
||||
downloadState.text = downloadItem.downloadState.toReadableState(containerView.context)
|
||||
eta.text = downloadItem.readableEta
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects
|
||||
|
||||
import android.app.Activity
|
||||
import org.kiwix.kiwixmobile.R
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.dao.NewBookDao
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects
|
||||
|
||||
import android.app.Activity
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
|
||||
object None : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: Activity) {
|
||||
|
@ -20,12 +20,14 @@ package org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects
|
||||
import android.app.Activity
|
||||
import androidx.core.net.toUri
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.extensions.start
|
||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
||||
import org.kiwix.kiwixmobile.main.KiwixMainActivity
|
||||
|
||||
class OpenFile(private val bookOnDisk: BookOnDisk) : SideEffect<Unit> {
|
||||
class OpenFile(private val bookOnDisk: BookOnDisk) :
|
||||
SideEffect<Unit> {
|
||||
|
||||
override fun invokeWith(activity: Activity) {
|
||||
val file = bookOnDisk.file
|
||||
|
@ -24,9 +24,11 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.content.FileProvider
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem.BookOnDisk
|
||||
|
||||
class ShareFiles(private val selectedBooks: List<BookOnDisk>) : SideEffect<Unit> {
|
||||
class ShareFiles(private val selectedBooks: List<BookOnDisk>) :
|
||||
SideEffect<Unit> {
|
||||
override fun invokeWith(activity: Activity) {
|
||||
val selectedFileShareIntent = Intent()
|
||||
selectedFileShareIntent.action = Intent.ACTION_SEND_MULTIPLE
|
||||
|
@ -22,6 +22,7 @@ import android.app.Activity
|
||||
import android.view.ActionMode
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.extensions.startActionMode
|
||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
||||
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions
|
||||
|
@ -143,6 +143,7 @@ class AllProjectConfigurer {
|
||||
implementation(Libs.kotlin_stdlib_jdk7)
|
||||
implementation(Libs.appcompat)
|
||||
implementation(Libs.material)
|
||||
implementation(Libs.constraintlayout)
|
||||
implementation(Libs.androidx_multidex_multidex)
|
||||
implementation(Libs.okhttp)
|
||||
implementation(Libs.logging_interceptor)
|
||||
|
@ -46,8 +46,6 @@ dependencies {
|
||||
|
||||
// Android Support
|
||||
implementation(Libs.cardview)
|
||||
implementation(Libs.constraintlayout)
|
||||
|
||||
|
||||
// Tab indicator
|
||||
implementation(Libs.ink_page_indicator)
|
||||
|
@ -21,10 +21,10 @@
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/kiwix_icon"
|
||||
android:label="@string/app_name"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:roundIcon="@mipmap/kiwix_icon_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="m">
|
||||
|
||||
<activity
|
||||
@ -35,6 +35,7 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.MONKEY" />
|
||||
</intent-filter>
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import java.util.Map;
|
||||
import javax.inject.Provider;
|
||||
|
||||
public class ViewModelFactory implements ViewModelProvider.Factory {
|
||||
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;
|
||||
|
||||
public ViewModelFactory(
|
||||
Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
|
||||
this.creators = creators;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends ViewModel> T create(Class<T> modelClass) {
|
||||
Provider<? extends ViewModel> creator = creators.get(modelClass);
|
||||
if (creator == null) {
|
||||
for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
|
||||
if (modelClass.isAssignableFrom(entry.getKey())) {
|
||||
creator = entry.getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (creator == null) {
|
||||
throw new IllegalArgumentException("unknown model class " + modelClass);
|
||||
}
|
||||
try {
|
||||
return (T) creator.get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.zim_manager.fileselect_view.effects
|
||||
package org.kiwix.kiwixmobile.core.base
|
||||
|
||||
import android.app.Activity
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.kiwix.kiwixmobile.core.downloader.model
|
||||
|
||||
import android.content.Context
|
||||
import com.tonyodev.fetch2.Error
|
||||
import com.tonyodev.fetch2.Status
|
||||
import com.tonyodev.fetch2.Status.ADDED
|
||||
@ -43,6 +44,8 @@ data class DownloadItem(
|
||||
val downloadState: DownloadState
|
||||
) {
|
||||
|
||||
val readableEta: CharSequence = eta.takeIf { it.seconds > 0L }?.toHumanReadableTime() ?: ""
|
||||
|
||||
constructor(downloadModel: DownloadModel) : this(
|
||||
downloadModel.downloadId,
|
||||
Base64String(downloadModel.book.favicon),
|
||||
@ -84,4 +87,12 @@ sealed class DownloadState(val stringId: Int) {
|
||||
data class Failed(val reason: Error) : DownloadState(R.string.failed_state)
|
||||
|
||||
override fun toString(): String = javaClass.simpleName
|
||||
|
||||
fun toReadableState(context: Context): CharSequence = when (this) {
|
||||
is Failed -> context.getString(stringId, reason.name)
|
||||
Pending,
|
||||
Running,
|
||||
Paused,
|
||||
Successful -> context.getString(stringId)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.core.extensions
|
||||
|
||||
import android.widget.ViewAnimator
|
||||
|
||||
fun ViewAnimator.setDistinctDisplayedChild(index: Int) {
|
||||
if (displayedChild != index) {
|
||||
displayedChild = index
|
||||
}
|
||||
}
|
@ -1091,8 +1091,7 @@ public abstract class CoreMainActivity extends BaseActivity implements WebViewCa
|
||||
@NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_STORAGE_PERMISSION: {
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PERMISSION_GRANTED) {
|
||||
if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
finish();
|
||||
Intent newZimFile = Intents.internal(CoreMainActivity.class);
|
||||
newZimFile.setData(Uri.fromFile(file));
|
||||
@ -1222,7 +1221,6 @@ public abstract class CoreMainActivity extends BaseActivity implements WebViewCa
|
||||
}, 300);
|
||||
}
|
||||
|
||||
|
||||
@OnClick(R2.id.bottom_toolbar_bookmark)
|
||||
public void toggleBookmark() {
|
||||
//Check maybe need refresh
|
||||
@ -1605,7 +1603,7 @@ public abstract class CoreMainActivity extends BaseActivity implements WebViewCa
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean urlIsInvalid(){
|
||||
protected boolean urlIsInvalid() {
|
||||
return getCurrentWebView().getUrl() == null;
|
||||
}
|
||||
|
||||
@ -1827,14 +1825,10 @@ public abstract class CoreMainActivity extends BaseActivity implements WebViewCa
|
||||
}
|
||||
|
||||
private void searchFiles() {
|
||||
if (Build.VERSION.SDK_INT >= VERSION_CODES.M && ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
|
||||
REQUEST_READ_STORAGE_PERMISSION);
|
||||
} else {
|
||||
if (hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
scanStorageForZims();
|
||||
} else {
|
||||
requestExternalStoragePermission();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
<item name="android:textColorSecondary">@color/textDarkSecondary</item>
|
||||
<item name="android:textColorTertiary">@color/textDarkTertiary</item>
|
||||
<item name="colorControlNormal">@color/accent</item>
|
||||
<item name="buttonStyle">@style/KiwixButtonStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Night" parent="AppTheme.Base">
|
||||
@ -162,4 +163,8 @@
|
||||
<item name="layout_constraintBottom_toBottomOf">parent</item>
|
||||
</style>
|
||||
|
||||
<style name="KiwixButtonStyle" parent="Widget.MaterialComponents.Button">
|
||||
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Medium</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -109,6 +109,7 @@ android {
|
||||
buildConfigField "int", "CONTENT_VERSION_CODE", "$parsedJson.version_code"
|
||||
}
|
||||
buildConfigField "String", "ENFORCED_LANG", "\"$parsedJson.enforced_lang\""
|
||||
buildConfigField "String", "ZIM_URL", "\"$parsedJson.zim_url\""
|
||||
resValue "string", "app_name", "$parsedJson.app_name"
|
||||
resValue "string", "app_search_string", "Search " + "$parsedJson.app_name"
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission
|
||||
android:name="android.permission.INTERNET"
|
||||
tools:node="remove" />
|
||||
</manifest>
|
@ -3,7 +3,8 @@
|
||||
"package": "org.kiwix.kiwixcustomexample",
|
||||
"version_name": "2017-07",
|
||||
"version_code": "1",
|
||||
"zim_file": "wikipedia_fr_test_2017-07.zim",
|
||||
"zim_file": "kiwix.granbluefantasy_en_all_all.zim",
|
||||
"zim_url": "http://download.kiwix.org/zim/other/granbluefantasy_en_all_nopic_2018-10.zim.meta4",
|
||||
"embed_zim": false,
|
||||
"ic_launcher": "icon.png",
|
||||
"enforced_lang": "en"
|
||||
|
@ -39,5 +39,6 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".download.CustomDownloadActivity" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import org.kiwix.kiwixmobile.core.ViewModelFactory;
|
||||
import org.kiwix.kiwixmobile.custom.di.CustomScope;
|
||||
|
||||
@CustomScope
|
||||
public class CustomViewModelFactory extends ViewModelFactory {
|
||||
|
||||
@Inject
|
||||
public CustomViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
|
||||
super(creators);
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@ import android.app.Activity
|
||||
import dagger.BindsInstance
|
||||
import dagger.Subcomponent
|
||||
import org.kiwix.kiwixmobile.core.di.ActivityScope
|
||||
import org.kiwix.kiwixmobile.custom.download.CustomDownloadActivity
|
||||
import org.kiwix.kiwixmobile.custom.main.CustomMainActivity
|
||||
import org.kiwix.kiwixmobile.custom.settings.CustomSettingsActivity
|
||||
|
||||
@ -30,6 +31,7 @@ import org.kiwix.kiwixmobile.custom.settings.CustomSettingsActivity
|
||||
interface CustomActivityComponent {
|
||||
fun inject(customMainActivity: CustomMainActivity)
|
||||
fun inject(customSettingsActivity: CustomSettingsActivity)
|
||||
fun inject(customDownloadActivity: CustomDownloadActivity)
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
@ -21,7 +21,7 @@ package org.kiwix.kiwixmobile.custom.di
|
||||
import dagger.Component
|
||||
import org.kiwix.kiwixmobile.core.di.components.CoreComponent
|
||||
|
||||
@Component(dependencies = [CoreComponent::class])
|
||||
@Component(dependencies = [CoreComponent::class], modules = [CustomViewModelModule::class])
|
||||
@CustomScope
|
||||
interface CustomComponent {
|
||||
fun activityComponentBuilder(): CustomActivityComponent.Builder
|
||||
|
@ -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.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
import org.kiwix.kiwixmobile.custom.CustomViewModelFactory
|
||||
import org.kiwix.kiwixmobile.custom.download.CustomDownloadViewModel
|
||||
import org.kiwix.kiwixmobile.di.ViewModelKey
|
||||
|
||||
@Module
|
||||
abstract class CustomViewModelModule {
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(CustomDownloadViewModel::class)
|
||||
abstract fun bindCustomDownloadViewModel(zimManageViewModel: CustomDownloadViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
abstract fun bindViewModelFactory(factory: CustomViewModelFactory):
|
||||
ViewModelProvider.Factory
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||
|
||||
sealed class Action {
|
||||
data class DatabaseEmission(val downloads: List<DownloadItem>) : Action()
|
||||
object ClickedDownload : Action()
|
||||
object ClickedRetry : Action()
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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 android.os.Bundle
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.activity_custom_download.cd_view_animator
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_error.cd_error_text
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_error.cd_retry_button
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_in_progress.cd_download_state
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_in_progress.cd_eta
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_in_progress.cd_progress
|
||||
import kotlinx.android.synthetic.main.layout_custom_download_required.cd_download_button
|
||||
import org.kiwix.kiwixmobile.core.base.BaseActivity
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||
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.customActivityComponent
|
||||
import org.kiwix.kiwixmobile.custom.download.Action.ClickedDownload
|
||||
import org.kiwix.kiwixmobile.custom.download.Action.ClickedRetry
|
||||
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 javax.inject.Inject
|
||||
|
||||
class CustomDownloadActivity : BaseActivity() {
|
||||
|
||||
private val downloadViewModel by lazy {
|
||||
viewModel<CustomDownloadViewModel>(viewModelFactory)
|
||||
}
|
||||
|
||||
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun injection() {
|
||||
customActivityComponent.inject(this)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_custom_download)
|
||||
downloadViewModel.state.observe(this, Observer(::render))
|
||||
compositeDisposable.add(
|
||||
downloadViewModel.effects.subscribe(
|
||||
{ it.invokeWith(this) },
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
)
|
||||
cd_download_button.setOnClickListener { downloadViewModel.actions.offer(ClickedDownload) }
|
||||
cd_retry_button.setOnClickListener { downloadViewModel.actions.offer(ClickedRetry) }
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
private fun render(state: State) {
|
||||
return when (state) {
|
||||
DownloadRequired -> cd_view_animator.setDistinctDisplayedChild(0)
|
||||
is DownloadInProgress -> {
|
||||
cd_view_animator.setDistinctDisplayedChild(1)
|
||||
render(state.downloads[0])
|
||||
}
|
||||
is DownloadFailed -> {
|
||||
cd_view_animator.setDistinctDisplayedChild(2)
|
||||
cd_error_text.text = state.downloadState.toReadableState(this)
|
||||
}
|
||||
DownloadComplete -> cd_view_animator.setDistinctDisplayedChild(3)
|
||||
}
|
||||
}
|
||||
|
||||
private fun render(downloadItem: DownloadItem) {
|
||||
cd_progress.progress = downloadItem.progress
|
||||
cd_eta.text = downloadItem.readableEta
|
||||
cd_download_state.text = downloadItem.downloadState.toReadableState(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.processors.PublishProcessor
|
||||
import org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.dao.FetchDownloadDao
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||
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 javax.inject.Inject
|
||||
|
||||
class CustomDownloadViewModel @Inject constructor(
|
||||
downloadDao: FetchDownloadDao,
|
||||
setPreferredStorageWithMostSpace: SetPreferredStorageWithMostSpace,
|
||||
private val downloadCustom: DownloadCustom
|
||||
) : ViewModel() {
|
||||
|
||||
val state = MutableLiveData<State>().apply { value = DownloadRequired }
|
||||
val actions = PublishProcessor.create<Action>()
|
||||
private val _effects = PublishProcessor.create<SideEffect<*>>()
|
||||
val effects = _effects.startWith(setPreferredStorageWithMostSpace)
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
compositeDisposable.addAll(
|
||||
reducer(),
|
||||
downloadsAsActions(downloadDao)
|
||||
)
|
||||
}
|
||||
|
||||
private fun reducer() = actions.map { reduce(it, state.value!!) }
|
||||
.distinctUntilChanged()
|
||||
.subscribe(state::postValue, Throwable::printStackTrace)
|
||||
|
||||
private fun downloadsAsActions(downloadDao: FetchDownloadDao) =
|
||||
downloadDao.downloads()
|
||||
.map { it.map(::DownloadItem) }
|
||||
.subscribe(
|
||||
{ actions.offer(DatabaseEmission(it)) },
|
||||
Throwable::printStackTrace
|
||||
)
|
||||
|
||||
private fun reduce(action: Action, state: State): State {
|
||||
return when (action) {
|
||||
is DatabaseEmission -> reduceDatabaseEmission(state, action)
|
||||
ClickedRetry,
|
||||
ClickedDownload -> state.also { _effects.offer(downloadCustom) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun reduceDatabaseEmission(state: State, action: DatabaseEmission) = when (state) {
|
||||
is DownloadFailed,
|
||||
DownloadRequired ->
|
||||
if (action.downloads.isNotEmpty()) DownloadInProgress(action.downloads)
|
||||
else state
|
||||
is DownloadInProgress ->
|
||||
if (action.downloads.isNotEmpty())
|
||||
if (action.downloads[0].downloadState is Failed)
|
||||
DownloadFailed(action.downloads[0].downloadState)
|
||||
else
|
||||
DownloadInProgress(action.downloads)
|
||||
else
|
||||
DownloadComplete.also { _effects.offer(FinishAndStartMain()) }
|
||||
DownloadComplete -> state
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 org.kiwix.kiwixmobile.core.downloader.model.DownloadItem
|
||||
import org.kiwix.kiwixmobile.core.downloader.model.DownloadState
|
||||
|
||||
sealed class State {
|
||||
object DownloadRequired : State()
|
||||
data class DownloadInProgress(val downloads: List<DownloadItem>) : State()
|
||||
data class DownloadFailed(val downloadState: DownloadState) : State()
|
||||
object DownloadComplete : State()
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.downloader.Downloader
|
||||
import org.kiwix.kiwixmobile.core.entity.LibraryNetworkEntity.Book
|
||||
import org.kiwix.kiwixmobile.custom.BuildConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
data class DownloadCustom @Inject constructor(val downloader: Downloader) : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: Activity) {
|
||||
downloader.download(emptyBook(id = "custom", url = BuildConfig.ZIM_URL))
|
||||
}
|
||||
|
||||
private fun emptyBook(
|
||||
id: String = "",
|
||||
title: String = "",
|
||||
description: String = "",
|
||||
language: String = "",
|
||||
creator: String = "",
|
||||
publisher: String = "",
|
||||
date: String = "",
|
||||
url: String = "",
|
||||
articleCount: String = "",
|
||||
mediaCount: String = "",
|
||||
size: String = "",
|
||||
name: String = "",
|
||||
favIcon: String = ""
|
||||
) =
|
||||
Book().apply {
|
||||
this.id = id
|
||||
this.title = title
|
||||
this.description = description
|
||||
this.language = language
|
||||
this.creator = creator
|
||||
this.publisher = publisher
|
||||
this.date = date
|
||||
this.url = url
|
||||
this.articleCount = articleCount
|
||||
this.mediaCount = mediaCount
|
||||
this.size = size
|
||||
bookName = name
|
||||
favicon = favIcon
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.extensions.start
|
||||
import org.kiwix.kiwixmobile.custom.main.CustomMainActivity
|
||||
|
||||
class FinishAndStartMain() : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: Activity) {
|
||||
activity.finish()
|
||||
activity.start<CustomMainActivity>()
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 org.kiwix.kiwixmobile.core.base.SideEffect
|
||||
import org.kiwix.kiwixmobile.core.settings.StorageCalculator
|
||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
class SetPreferredStorageWithMostSpace @Inject constructor(
|
||||
private val storageCalculator: StorageCalculator,
|
||||
private val sharedPreferenceUtil: SharedPreferenceUtil
|
||||
) : SideEffect<Unit> {
|
||||
override fun invokeWith(activity: Activity) {
|
||||
ContextCompat.getExternalFilesDirs(activity, null)
|
||||
.filterNotNull()
|
||||
.maxBy(storageCalculator::availableBytes)
|
||||
?.let { sharedPreferenceUtil.putPrefStorage(it.path) }
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.main
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasBothFiles
|
||||
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasFile
|
||||
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasNothing
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class CustomFileValidator @Inject constructor(private val context: Context) {
|
||||
|
||||
fun validate(onFilesFound: (ValidationState) -> Unit, onNoFilesFound: () -> Unit) =
|
||||
when (val installationState = detectInstallationState()) {
|
||||
is HasBothFiles,
|
||||
is HasFile -> onFilesFound(installationState)
|
||||
HasNothing -> onNoFilesFound()
|
||||
}
|
||||
|
||||
private fun detectInstallationState(
|
||||
obbFiles: List<File> = obbFiles(),
|
||||
zimFiles: List<File> = zimFiles()
|
||||
): ValidationState {
|
||||
return when {
|
||||
obbFiles.isNotEmpty() && zimFiles().isNotEmpty() -> HasBothFiles(obbFiles[0], zimFiles[0])
|
||||
obbFiles.isNotEmpty() -> HasFile(obbFiles[0])
|
||||
zimFiles.isNotEmpty() -> HasFile(zimFiles[0])
|
||||
else -> HasNothing
|
||||
}
|
||||
}
|
||||
|
||||
private fun obbFiles() = scanDirs(ContextCompat.getObbDirs(context), "obb")
|
||||
|
||||
private fun zimFiles() =
|
||||
scanDirs(ContextCompat.getExternalFilesDirs(context, null), "zim")
|
||||
|
||||
private fun scanDirs(dirs: Array<out File>, extensionToMatch: String): List<File> =
|
||||
dirs.fold(listOf()) { acc, dir ->
|
||||
acc + dir.walk().filter { it.extension.startsWith(extensionToMatch) }.toList()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ValidationState {
|
||||
data class HasBothFiles(val obbFile: File, val zimFile: File) : ValidationState()
|
||||
data class HasFile(val file: File) : ValidationState()
|
||||
object HasNothing : ValidationState()
|
||||
}
|
@ -22,23 +22,24 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.net.toUri
|
||||
import org.kiwix.kiwixmobile.core.CoreApp
|
||||
import org.kiwix.kiwixmobile.core.R
|
||||
import org.kiwix.kiwixmobile.core.extensions.start
|
||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||
import org.kiwix.kiwixmobile.core.main.WebViewCallback
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
|
||||
import org.kiwix.kiwixmobile.core.utils.Constants.TAG_KIWIX
|
||||
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
|
||||
import org.kiwix.kiwixmobile.core.utils.StyleUtils.dialogStyle
|
||||
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
||||
import org.kiwix.kiwixmobile.custom.BuildConfig
|
||||
import org.kiwix.kiwixmobile.custom.customActivityComponent
|
||||
import org.kiwix.kiwixmobile.custom.download.CustomDownloadActivity
|
||||
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasBothFiles
|
||||
import org.kiwix.kiwixmobile.custom.main.ValidationState.HasFile
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
class CustomMainActivity : CoreMainActivity() {
|
||||
@Inject lateinit var customFileValidator: CustomFileValidator
|
||||
|
||||
override fun showHomePage() {
|
||||
Log.e("CustomMain", "tried to show home page")
|
||||
@ -54,17 +55,22 @@ class CustomMainActivity : CoreMainActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
Log.d(TAG_KIWIX, "This is a custom app:$packageName")
|
||||
if (loadCustomAppContent()) {
|
||||
Log.d(TAG_KIWIX, "Found custom content, continuing...")
|
||||
// Continue
|
||||
} else {
|
||||
Log.e(TAG_KIWIX, "Problem finding the content, no more OnCreate() code")
|
||||
// What should we do here? exit? I'll investigate empirically.
|
||||
// It seems unpredictable behaviour if the code returns at this point as yesterday
|
||||
// it didn't crash yet today the app crashes because it tries to load books
|
||||
// in onResume();
|
||||
}
|
||||
requireEnforcedLanguage()
|
||||
customFileValidator.validate(
|
||||
{
|
||||
when (it) {
|
||||
is HasFile -> openZimFile(it.file)
|
||||
is HasBothFiles -> {
|
||||
it.zimFile.delete()
|
||||
openZimFile(it.obbFile)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
finish()
|
||||
start<CustomDownloadActivity>()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
@ -79,74 +85,15 @@ class CustomMainActivity : CoreMainActivity() {
|
||||
zimReaderContainer: ZimReaderContainer
|
||||
) = CustomWebViewClient(webViewCallback, zimReaderContainer)
|
||||
|
||||
/**
|
||||
* loadCustomAppContent Return true if all's well, else false.
|
||||
*/
|
||||
private fun loadCustomAppContent(): Boolean {
|
||||
Log.d(
|
||||
TAG_KIWIX,
|
||||
"Kiwix Custom App starting for the first time. Checking Companion ZIM: " +
|
||||
BuildConfig.ZIM_FILE_NAME
|
||||
)
|
||||
|
||||
private fun requireEnforcedLanguage(): Boolean {
|
||||
val currentLocaleCode = Locale.getDefault().toString()
|
||||
// Custom App recommends to start off a specific language
|
||||
if (BuildConfig.ENFORCED_LANG.length > 0 && BuildConfig.ENFORCED_LANG != currentLocaleCode) {
|
||||
|
||||
// change the locale machinery
|
||||
if (BuildConfig.ENFORCED_LANG.isNotEmpty() && BuildConfig.ENFORCED_LANG != currentLocaleCode) {
|
||||
LanguageUtils.handleLocaleChange(this, BuildConfig.ENFORCED_LANG)
|
||||
|
||||
// save new locale into preferences for next startup
|
||||
sharedPreferenceUtil.putPrefLanguage(BuildConfig.ENFORCED_LANG)
|
||||
|
||||
// restart activity for new locale to take effect
|
||||
this.setResult(1236)
|
||||
this.finish()
|
||||
this.startActivity(Intent(this, this.javaClass))
|
||||
return false
|
||||
}
|
||||
|
||||
var filePath = ""
|
||||
if (BuildConfig.HAS_EMBEDDED_ZIM) {
|
||||
val appPath = packageResourcePath
|
||||
val libDir = File(appPath.substring(0, appPath.lastIndexOf("/")) + "/lib/")
|
||||
if (libDir.exists() && libDir.listFiles().size > 0) {
|
||||
filePath = libDir.listFiles()[0].path + "/" + BuildConfig.ZIM_FILE_NAME
|
||||
}
|
||||
if (filePath.isEmpty() || !File(filePath).exists()) {
|
||||
filePath = String.format(
|
||||
"/data/data/%s/lib/%s", packageName,
|
||||
BuildConfig.ZIM_FILE_NAME
|
||||
)
|
||||
}
|
||||
} else {
|
||||
filePath = generateExpansionFilePath()
|
||||
}
|
||||
|
||||
Log.d(TAG_KIWIX, "BuildConfig.ZIM_FILE_SIZE = " + BuildConfig.ZIM_FILE_SIZE)
|
||||
if (!FileUtils.doesFileExist(filePath, BuildConfig.ZIM_FILE_SIZE, false)) {
|
||||
|
||||
val zimFileMissingBuilder = AlertDialog.Builder(this, dialogStyle())
|
||||
zimFileMissingBuilder.setTitle(R.string.app_name)
|
||||
zimFileMissingBuilder.setMessage(R.string.custom_app_missing_content)
|
||||
zimFileMissingBuilder.setIcon(R.mipmap.kiwix_icon)
|
||||
val activity = this
|
||||
zimFileMissingBuilder.setPositiveButton(
|
||||
getString(R.string.go_to_play_store)
|
||||
) { dialog, which ->
|
||||
startActivity(Intent(Intent.ACTION_VIEW).apply {
|
||||
data = "market://details?id=$packageName".toUri()
|
||||
})
|
||||
activity.finish()
|
||||
}
|
||||
zimFileMissingBuilder.setCancelable(false)
|
||||
val zimFileMissingDialog = zimFileMissingBuilder.create()
|
||||
zimFileMissingDialog.show()
|
||||
return false
|
||||
} else {
|
||||
openZimFile(File(filePath))
|
||||
startActivity(Intent(this, this.javaClass))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun manageZimFiles(tab: Int) {
|
||||
|
38
custom/src/main/res/layout/activity_custom_download.xml
Normal file
38
custom/src/main/res/layout/activity_custom_download.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cd_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_vertical_margin"
|
||||
android:src="@drawable/kiwix_icon_with_title"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ViewAnimator
|
||||
android:id="@+id/cd_view_animator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:inAnimation="@anim/fade_in"
|
||||
android:outAnimation="@anim/fade_out"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cd_icon">
|
||||
|
||||
<include layout="@layout/layout_custom_download_required" />
|
||||
|
||||
<include layout="@layout/layout_custom_download_in_progress" />
|
||||
|
||||
<include layout="@layout/layout_custom_download_error" />
|
||||
|
||||
<include layout="@layout/layout_custom_download_complete" />
|
||||
</ViewAnimator>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:showIn="@layout/activity_custom_download">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/complete"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias=".3" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
30
custom/src/main/res/layout/layout_custom_download_error.xml
Normal file
30
custom/src/main/res/layout/layout_custom_download_error.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:showIn="@layout/activity_custom_download">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cd_error_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias=".3" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cd_retry_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/retry"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cd_error_text" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cd_download_state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/cd_progress"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/cd_progress"
|
||||
app:layout_constraintRight_toRightOf="@+id/cd_progress" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/cd_progress"
|
||||
style="?android:progressBarStyleHorizontal"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="100"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias=".3" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cd_eta"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/cd_progress"
|
||||
app:layout_constraintStart_toEndOf="@id/cd_progress"
|
||||
app:layout_constraintTop_toTopOf="@id/cd_progress" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:showIn="@layout/activity_custom_download">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cd_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/invalid_installation"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias=".3" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/cd_download_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/download"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/cd_text" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
8
custom/src/main/res/values/strings.xml
Normal file
8
custom/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<string name="retry">Retry</string>
|
||||
<string name="download">Download</string>
|
||||
<string name="invalid_installation">Invalid Install. Please Download Zim.\n Ensure WiFi is on and you have enough storage</string>
|
||||
<string name="complete">Complete</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user