mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-23 04:33:54 -04:00
Downloads now fully support states from a Query. Language handling improved. Guava & apache commons removed
This commit is contained in:
parent
f318da929c
commit
287d816304
@ -51,7 +51,7 @@ dependencies {
|
|||||||
implementation "com.android.support:cardview-v7:$supportLibraryVersion"
|
implementation "com.android.support:cardview-v7:$supportLibraryVersion"
|
||||||
implementation 'com.android.support:multidex:1.0.2'
|
implementation 'com.android.support:multidex:1.0.2'
|
||||||
|
|
||||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||||
|
|
||||||
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
|
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
|
||||||
|
|
||||||
@ -77,9 +77,6 @@ dependencies {
|
|||||||
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
androidTestImplementation 'com.android.support.test:runner:1.0.1'
|
||||||
androidTestImplementation 'com.android.support.test:rules:1.0.1'
|
androidTestImplementation 'com.android.support.test:rules:1.0.1'
|
||||||
|
|
||||||
// Guava
|
|
||||||
implementation group: 'com.google.guava', name: 'guava', version: '21.0'
|
|
||||||
|
|
||||||
// Dagger
|
// Dagger
|
||||||
compileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
|
compileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
|
||||||
androidTestCompileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
|
androidTestCompileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
|
||||||
@ -94,9 +91,6 @@ dependencies {
|
|||||||
implementation 'com.yahoo.squidb:squidb-annotations:2.0.0'
|
implementation 'com.yahoo.squidb:squidb-annotations:2.0.0'
|
||||||
annotationProcessor 'com.yahoo.squidb:squidb-processor:2.0.0'
|
annotationProcessor 'com.yahoo.squidb:squidb-processor:2.0.0'
|
||||||
|
|
||||||
// Apache
|
|
||||||
implementation 'commons-io:commons-io:2.5'
|
|
||||||
|
|
||||||
// Square
|
// Square
|
||||||
implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
|
implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
|
||||||
implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
|
implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
|
||||||
|
@ -75,6 +75,11 @@ public class KiwixApplication extends MultiDexApplication implements HasActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||||
|
// This process is dedicated to LeakCanary for heap analysis.
|
||||||
|
// You should not init your app in this process.
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (isExternalStorageWritable()) {
|
if (isExternalStorageWritable()) {
|
||||||
File appDirectory = new File(Environment.getExternalStorageDirectory() + "/Kiwix");
|
File appDirectory = new File(Environment.getExternalStorageDirectory() + "/Kiwix");
|
||||||
logFile = new File(appDirectory, "logcat.txt");
|
logFile = new File(appDirectory, "logcat.txt");
|
||||||
@ -105,13 +110,7 @@ public class KiwixApplication extends MultiDexApplication implements HasActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.d("KIWIX", "Started KiwixApplication");
|
Log.d("KIWIX", "Started KiwixApplication");
|
||||||
|
|
||||||
applicationComponent.inject(this);
|
applicationComponent.inject(this);
|
||||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
|
||||||
// This process is dedicated to LeakCanary for heap analysis.
|
|
||||||
// You should not init your app in this process.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LeakCanary.install(this);
|
LeakCanary.install(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ package org.kiwix.kiwixmobile.database;
|
|||||||
|
|
||||||
import com.yahoo.squidb.data.SquidCursor;
|
import com.yahoo.squidb.data.SquidCursor;
|
||||||
import com.yahoo.squidb.sql.Query;
|
import com.yahoo.squidb.sql.Query;
|
||||||
import com.yahoo.squidb.sql.Table;
|
|
||||||
import io.reactivex.Flowable;
|
import io.reactivex.Flowable;
|
||||||
import io.reactivex.processors.BehaviorProcessor;
|
import io.reactivex.processors.BehaviorProcessor;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -34,8 +33,6 @@ import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language;
|
|||||||
|
|
||||||
public class NetworkLanguageDao extends BaseDao {
|
public class NetworkLanguageDao extends BaseDao {
|
||||||
|
|
||||||
private final BehaviorProcessor<List<Language>> activeLanguageProcessor =
|
|
||||||
BehaviorProcessor.create();
|
|
||||||
private final BehaviorProcessor<List<Language>> allLanguageProcessor = BehaviorProcessor.create();
|
private final BehaviorProcessor<List<Language>> allLanguageProcessor = BehaviorProcessor.create();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -45,14 +42,9 @@ public class NetworkLanguageDao extends BaseDao {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onUpdateToTable() {
|
protected void onUpdateToTable() {
|
||||||
activeLanguageProcessor.onNext(fetchActiveLanguages());
|
|
||||||
allLanguageProcessor.onNext(fetchAllLanguages());
|
allLanguageProcessor.onNext(fetchAllLanguages());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Flowable<List<Language>> activeLanguages() {
|
|
||||||
return activeLanguageProcessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Flowable<List<Language>> allLanguages() {
|
public Flowable<List<Language>> allLanguages() {
|
||||||
return allLanguageProcessor;
|
return allLanguageProcessor;
|
||||||
}
|
}
|
||||||
@ -61,10 +53,6 @@ public class NetworkLanguageDao extends BaseDao {
|
|||||||
return fetchWith(Query.select());
|
return fetchWith(Query.select());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Language> fetchActiveLanguages() {
|
|
||||||
return fetchWith(Query.select().where(NetworkLanguageDatabaseEntity.ENABLED.eq(true)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull private List<Language> fetchWith(Query query) {
|
@NotNull private List<Language> fetchWith(Query query) {
|
||||||
ArrayList<Language> result = new ArrayList<>();
|
ArrayList<Language> result = new ArrayList<>();
|
||||||
final NetworkLanguageDatabaseEntity databaseEntity =
|
final NetworkLanguageDatabaseEntity databaseEntity =
|
||||||
|
@ -17,15 +17,24 @@
|
|||||||
*/
|
*/
|
||||||
package org.kiwix.kiwixmobile.downloader
|
package org.kiwix.kiwixmobile.downloader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.support.v7.widget.RecyclerView
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.download_item.description
|
import kotlinx.android.synthetic.main.download_item.description
|
||||||
import kotlinx.android.synthetic.main.download_item.downloadProgress
|
import kotlinx.android.synthetic.main.download_item.downloadProgress
|
||||||
|
import kotlinx.android.synthetic.main.download_item.downloadState
|
||||||
import kotlinx.android.synthetic.main.download_item.favicon
|
import kotlinx.android.synthetic.main.download_item.favicon
|
||||||
import kotlinx.android.synthetic.main.download_item.stop
|
import kotlinx.android.synthetic.main.download_item.stop
|
||||||
import kotlinx.android.synthetic.main.download_item.title
|
import kotlinx.android.synthetic.main.download_item.title
|
||||||
import org.kiwix.kiwixmobile.downloader.model.DownloadItem
|
import org.kiwix.kiwixmobile.downloader.model.DownloadItem
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Failed
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Paused
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Pending
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Running
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.DownloadState.Successful
|
||||||
|
import org.kiwix.kiwixmobile.downloader.model.FailureReason.Rfc2616HttpCode
|
||||||
import org.kiwix.kiwixmobile.extensions.setBitmap
|
import org.kiwix.kiwixmobile.extensions.setBitmap
|
||||||
|
|
||||||
class DownloadViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
|
class DownloadViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
|
||||||
@ -41,5 +50,36 @@ class DownloadViewHolder(override val containerView: View) : RecyclerView.ViewHo
|
|||||||
stop.setOnClickListener {
|
stop.setOnClickListener {
|
||||||
itemClickListener.invoke(downloadItem)
|
itemClickListener.invoke(downloadItem)
|
||||||
}
|
}
|
||||||
|
downloadState.text = toReadableState(
|
||||||
|
downloadItem.downloadState, containerView.context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toReadableState(
|
||||||
|
downloadState: DownloadState,
|
||||||
|
context: Context
|
||||||
|
) = when (downloadState) {
|
||||||
|
is Paused -> context.getString(
|
||||||
|
downloadState.stringId,
|
||||||
|
context.getString(downloadState.reason.stringId)
|
||||||
|
)
|
||||||
|
is Failed -> context.getString(
|
||||||
|
downloadState.stringId,
|
||||||
|
getTemplateString(downloadState, context)
|
||||||
|
)
|
||||||
|
Pending,
|
||||||
|
Running,
|
||||||
|
Successful -> context.getString(downloadState.stringId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTemplateString(
|
||||||
|
downloadState: Failed,
|
||||||
|
context: Context
|
||||||
|
) = when (downloadState.reason) {
|
||||||
|
is Rfc2616HttpCode -> context.getString(
|
||||||
|
downloadState.reason.stringId,
|
||||||
|
downloadState.reason.code
|
||||||
|
)
|
||||||
|
else -> context.getString(downloadState.reason.stringId)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,8 +24,7 @@ data class DownloadItem(
|
|||||||
val description: String,
|
val description: String,
|
||||||
val bytesDownloaded: Long,
|
val bytesDownloaded: Long,
|
||||||
val totalSizeBytes: Long,
|
val totalSizeBytes: Long,
|
||||||
val downloadState: DownloadState,
|
val downloadState: DownloadState
|
||||||
val reason: String
|
|
||||||
) {
|
) {
|
||||||
val progress get() = ((bytesDownloaded.toFloat() / totalSizeBytes) * 100).toInt()
|
val progress get() = ((bytesDownloaded.toFloat() / totalSizeBytes) * 100).toInt()
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ data class DownloadItem(
|
|||||||
downloadStatus.description,
|
downloadStatus.description,
|
||||||
downloadStatus.bytesDownloadedSoFar,
|
downloadStatus.bytesDownloadedSoFar,
|
||||||
downloadStatus.totalSizeBytes,
|
downloadStatus.totalSizeBytes,
|
||||||
downloadStatus.state,
|
downloadStatus.state
|
||||||
downloadStatus.reason
|
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -29,6 +29,19 @@ import android.app.DownloadManager.COLUMN_STATUS
|
|||||||
import android.app.DownloadManager.COLUMN_TITLE
|
import android.app.DownloadManager.COLUMN_TITLE
|
||||||
import android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES
|
import android.app.DownloadManager.COLUMN_TOTAL_SIZE_BYTES
|
||||||
import android.app.DownloadManager.COLUMN_URI
|
import android.app.DownloadManager.COLUMN_URI
|
||||||
|
import android.app.DownloadManager.ERROR_CANNOT_RESUME
|
||||||
|
import android.app.DownloadManager.ERROR_DEVICE_NOT_FOUND
|
||||||
|
import android.app.DownloadManager.ERROR_FILE_ALREADY_EXISTS
|
||||||
|
import android.app.DownloadManager.ERROR_FILE_ERROR
|
||||||
|
import android.app.DownloadManager.ERROR_HTTP_DATA_ERROR
|
||||||
|
import android.app.DownloadManager.ERROR_INSUFFICIENT_SPACE
|
||||||
|
import android.app.DownloadManager.ERROR_TOO_MANY_REDIRECTS
|
||||||
|
import android.app.DownloadManager.ERROR_UNHANDLED_HTTP_CODE
|
||||||
|
import android.app.DownloadManager.ERROR_UNKNOWN
|
||||||
|
import android.app.DownloadManager.PAUSED_QUEUED_FOR_WIFI
|
||||||
|
import android.app.DownloadManager.PAUSED_UNKNOWN
|
||||||
|
import android.app.DownloadManager.PAUSED_WAITING_FOR_NETWORK
|
||||||
|
import android.app.DownloadManager.PAUSED_WAITING_TO_RETRY
|
||||||
import android.app.DownloadManager.STATUS_FAILED
|
import android.app.DownloadManager.STATUS_FAILED
|
||||||
import android.app.DownloadManager.STATUS_PAUSED
|
import android.app.DownloadManager.STATUS_PAUSED
|
||||||
import android.app.DownloadManager.STATUS_PENDING
|
import android.app.DownloadManager.STATUS_PENDING
|
||||||
@ -36,6 +49,7 @@ import android.app.DownloadManager.STATUS_RUNNING
|
|||||||
import android.app.DownloadManager.STATUS_SUCCESSFUL
|
import android.app.DownloadManager.STATUS_SUCCESSFUL
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import org.kiwix.kiwixmobile.R
|
||||||
import org.kiwix.kiwixmobile.extensions.get
|
import org.kiwix.kiwixmobile.extensions.get
|
||||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -45,7 +59,6 @@ class DownloadStatus(
|
|||||||
val title: String,
|
val title: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
val state: DownloadState,
|
val state: DownloadState,
|
||||||
val reason: String,
|
|
||||||
val bytesDownloadedSoFar: Long,
|
val bytesDownloadedSoFar: Long,
|
||||||
val totalSizeBytes: Long,
|
val totalSizeBytes: Long,
|
||||||
val lastModified: String,
|
val lastModified: String,
|
||||||
@ -66,8 +79,7 @@ class DownloadStatus(
|
|||||||
cursor[COLUMN_ID],
|
cursor[COLUMN_ID],
|
||||||
cursor[COLUMN_TITLE],
|
cursor[COLUMN_TITLE],
|
||||||
cursor[COLUMN_DESCRIPTION],
|
cursor[COLUMN_DESCRIPTION],
|
||||||
DownloadState.from(cursor[COLUMN_STATUS]),
|
DownloadState.from(cursor[COLUMN_STATUS], cursor[COLUMN_REASON]),
|
||||||
cursor[COLUMN_REASON],
|
|
||||||
cursor[COLUMN_BYTES_DOWNLOADED_SO_FAR],
|
cursor[COLUMN_BYTES_DOWNLOADED_SO_FAR],
|
||||||
cursor[COLUMN_TOTAL_SIZE_BYTES],
|
cursor[COLUMN_TOTAL_SIZE_BYTES],
|
||||||
cursor[COLUMN_LAST_MODIFIED_TIMESTAMP],
|
cursor[COLUMN_LAST_MODIFIED_TIMESTAMP],
|
||||||
@ -79,11 +91,14 @@ class DownloadStatus(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class DownloadState {
|
sealed class DownloadState(val stringId: Int) {
|
||||||
companion object {
|
companion object {
|
||||||
fun from(status: Int) = when (status) {
|
fun from(
|
||||||
STATUS_FAILED -> Failed
|
status: Int,
|
||||||
STATUS_PAUSED -> Paused
|
reason: Int
|
||||||
|
) = when (status) {
|
||||||
|
STATUS_PAUSED -> Paused(PausedReason.from(reason))
|
||||||
|
STATUS_FAILED -> Failed(FailureReason.from(reason))
|
||||||
STATUS_PENDING -> Pending
|
STATUS_PENDING -> Pending
|
||||||
STATUS_RUNNING -> Running
|
STATUS_RUNNING -> Running
|
||||||
STATUS_SUCCESSFUL -> Successful
|
STATUS_SUCCESSFUL -> Successful
|
||||||
@ -91,13 +106,59 @@ sealed class DownloadState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Paused : DownloadState()
|
data class Paused(val reason: PausedReason) : DownloadState(R.string.paused_state)
|
||||||
object Failed : DownloadState()
|
data class Failed(val reason: FailureReason) : DownloadState(R.string.failed_state)
|
||||||
object Pending : DownloadState()
|
object Pending : DownloadState(R.string.pending_state)
|
||||||
object Running : DownloadState()
|
object Running : DownloadState(R.string.running_state)
|
||||||
object Successful : DownloadState()
|
object Successful : DownloadState(R.string.successful_state)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return javaClass.simpleName
|
return javaClass.simpleName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class FailureReason(val stringId: Int) {
|
||||||
|
companion object {
|
||||||
|
fun from(reason: Int) = when (reason) {
|
||||||
|
in 100..505 -> Rfc2616HttpCode(reason)
|
||||||
|
ERROR_CANNOT_RESUME -> CannotResume
|
||||||
|
ERROR_DEVICE_NOT_FOUND -> StorageNotFound
|
||||||
|
ERROR_FILE_ALREADY_EXISTS -> FileAlreadyExists
|
||||||
|
ERROR_FILE_ERROR -> UnknownFileError
|
||||||
|
ERROR_HTTP_DATA_ERROR -> HttpError
|
||||||
|
ERROR_INSUFFICIENT_SPACE -> InsufficientSpace
|
||||||
|
ERROR_TOO_MANY_REDIRECTS -> TooManyRedirects
|
||||||
|
ERROR_UNHANDLED_HTTP_CODE -> UnhandledHttpCode
|
||||||
|
ERROR_UNKNOWN -> Unknown
|
||||||
|
else -> Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CannotResume : FailureReason(R.string.failed_cannot_resume)
|
||||||
|
object StorageNotFound : FailureReason(R.string.failed_storage_not_found)
|
||||||
|
object FileAlreadyExists : FailureReason(R.string.failed_file_already_exists)
|
||||||
|
object UnknownFileError : FailureReason(R.string.failed_unknown_file_error)
|
||||||
|
object HttpError : FailureReason(R.string.failed_http_error)
|
||||||
|
object InsufficientSpace : FailureReason(R.string.failed_insufficient_space)
|
||||||
|
object TooManyRedirects : FailureReason(R.string.failed_too_many_redirects)
|
||||||
|
object UnhandledHttpCode : FailureReason(R.string.failed_unhandled_http_code)
|
||||||
|
object Unknown : FailureReason(R.string.failed_unknown)
|
||||||
|
data class Rfc2616HttpCode(val code: Int) : FailureReason(R.string.failed_http_code)
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class PausedReason(val stringId: Int) {
|
||||||
|
companion object {
|
||||||
|
fun from(reason: Int) = when (reason) {
|
||||||
|
PAUSED_QUEUED_FOR_WIFI -> WaitingForWifi
|
||||||
|
PAUSED_WAITING_FOR_NETWORK -> WaitingForConnectivity
|
||||||
|
PAUSED_WAITING_TO_RETRY -> WaitingForRetry
|
||||||
|
PAUSED_UNKNOWN -> Unknown
|
||||||
|
else -> Unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WaitingForWifi : PausedReason(R.string.paused_wifi)
|
||||||
|
object WaitingForConnectivity : PausedReason(R.string.paused_connectivity)
|
||||||
|
object WaitingForRetry : PausedReason(R.string.paused_retry)
|
||||||
|
object Unknown : PausedReason(R.string.paused_unknown)
|
||||||
|
}
|
@ -29,7 +29,6 @@ import io.reactivex.functions.Function5
|
|||||||
import io.reactivex.processors.BehaviorProcessor
|
import io.reactivex.processors.BehaviorProcessor
|
||||||
import io.reactivex.processors.PublishProcessor
|
import io.reactivex.processors.PublishProcessor
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.kiwix.kiwixmobile.KiwixApplication
|
|
||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
import org.kiwix.kiwixmobile.database.BookDao
|
import org.kiwix.kiwixmobile.database.BookDao
|
||||||
import org.kiwix.kiwixmobile.database.DownloadDao
|
import org.kiwix.kiwixmobile.database.DownloadDao
|
||||||
@ -45,7 +44,6 @@ import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity
|
|||||||
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity.Book
|
||||||
import org.kiwix.kiwixmobile.network.KiwixService
|
import org.kiwix.kiwixmobile.network.KiwixService
|
||||||
import org.kiwix.kiwixmobile.utils.BookUtils
|
import org.kiwix.kiwixmobile.utils.BookUtils
|
||||||
import org.kiwix.kiwixmobile.utils.NetworkUtils
|
|
||||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.StorageObserver
|
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.StorageObserver
|
||||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language
|
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.Language
|
||||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
|
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem
|
||||||
@ -53,6 +51,7 @@ import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.Bo
|
|||||||
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
|
import org.kiwix.kiwixmobile.zim_manager.library_view.adapter.LibraryListItem.DividerItem
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||||
import java.util.concurrent.TimeUnit.SECONDS
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -105,7 +104,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
updateBookItems(booksFromDao),
|
updateBookItems(booksFromDao),
|
||||||
checkFileSystemForBooksOnRequest(booksFromDao),
|
checkFileSystemForBooksOnRequest(booksFromDao),
|
||||||
updateLibraryItems(booksFromDao, downloads, library),
|
updateLibraryItems(booksFromDao, downloads, library),
|
||||||
updateActiveLanguages(library),
|
updateLanguagesInDao(library),
|
||||||
updateNetworkStates(),
|
updateNetworkStates(),
|
||||||
updateLanguageItemsForDialog()
|
updateLanguageItemsForDialog()
|
||||||
)
|
)
|
||||||
@ -127,14 +126,16 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
private fun libraryFromNetwork() =
|
private fun libraryFromNetwork() =
|
||||||
Flowable.combineLatest(
|
Flowable.combineLatest(
|
||||||
requestDownloadLibrary,
|
requestDownloadLibrary,
|
||||||
connectivityBroadcastReceiver.networkStates.distinctUntilChanged().filter(NetworkState.CONNECTED::equals),
|
connectivityBroadcastReceiver.networkStates.distinctUntilChanged().filter(
|
||||||
|
NetworkState.CONNECTED::equals
|
||||||
|
),
|
||||||
BiFunction<Unit, NetworkState, Unit> { _, _ -> Unit }
|
BiFunction<Unit, NetworkState, Unit> { _, _ -> Unit }
|
||||||
)
|
)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.doOnNext { libraryListIsRefreshing.postValue(true) }
|
.doOnNext { libraryListIsRefreshing.postValue(true) }
|
||||||
.switchMap { kiwixService.library }
|
.switchMap { kiwixService.library }
|
||||||
.onErrorResumeNext(Flowable.just(LibraryNetworkEntity().apply { book = LinkedList() }))
|
|
||||||
.doOnError(Throwable::printStackTrace)
|
.doOnError(Throwable::printStackTrace)
|
||||||
|
.onErrorResumeNext(Flowable.just(LibraryNetworkEntity().apply { book = LinkedList() }))
|
||||||
|
|
||||||
private fun updateLibraryItems(
|
private fun updateLibraryItems(
|
||||||
booksFromDao: Flowable<List<Book>>,
|
booksFromDao: Flowable<List<Book>>,
|
||||||
@ -143,7 +144,9 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
) = Flowable.combineLatest(
|
) = Flowable.combineLatest(
|
||||||
booksFromDao,
|
booksFromDao,
|
||||||
downloads,
|
downloads,
|
||||||
languageDao.activeLanguages().filter { it.isNotEmpty() },
|
languageDao.allLanguages()
|
||||||
|
.debounce(100, MILLISECONDS)
|
||||||
|
.filter { it.isNotEmpty() },
|
||||||
library,
|
library,
|
||||||
requestFiltering
|
requestFiltering
|
||||||
.doOnNext { libraryListIsRefreshing.postValue(true) }
|
.doOnNext { libraryListIsRefreshing.postValue(true) }
|
||||||
@ -158,11 +161,13 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
Throwable::printStackTrace
|
Throwable::printStackTrace
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun updateActiveLanguages(library: Flowable<LibraryNetworkEntity>) = library
|
private fun updateLanguagesInDao(
|
||||||
|
library: Flowable<LibraryNetworkEntity>
|
||||||
|
) = library
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.map { it.books }
|
.map { it.books }
|
||||||
.withLatestFrom(
|
.withLatestFrom(
|
||||||
languageDao.activeLanguages(),
|
languageDao.allLanguages(),
|
||||||
BiFunction(this::combineToLanguageList)
|
BiFunction(this::combineToLanguageList)
|
||||||
)
|
)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
@ -172,47 +177,68 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
|
|
||||||
private fun combineToLanguageList(
|
private fun combineToLanguageList(
|
||||||
booksFromNetwork: List<Book>,
|
booksFromNetwork: List<Book>,
|
||||||
activeLanguages: List<Language>
|
allLanguages: List<Language>
|
||||||
): List<Language> {
|
): List<Language> {
|
||||||
val languageCounts = booksFromNetwork.mapNotNull { it.language }
|
val networkLanguageCounts = booksFromNetwork.mapNotNull { it.language }
|
||||||
.fold(
|
.fold(
|
||||||
mutableMapOf<String, Int>(),
|
mutableMapOf<String, Int>(),
|
||||||
{ acc, language ->
|
{ acc, language -> acc.increment(language) }
|
||||||
acc[language] = acc.getOrElse(language, { 0 }) + 1
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
return when {
|
||||||
|
booksFromNetwork.isEmpty() && allLanguages.isEmpty() -> defaultLanguage()
|
||||||
|
booksFromNetwork.isEmpty() && allLanguages.isNotEmpty() -> allLanguages
|
||||||
|
booksFromNetwork.isNotEmpty() && allLanguages.isEmpty() ->
|
||||||
|
fromLocalesWithNetworkMatchesSetActiveBy(networkLanguageCounts, defaultLanguage())
|
||||||
|
booksFromNetwork.isNotEmpty() && allLanguages.isNotEmpty() ->
|
||||||
|
fromLocalesWithNetworkMatchesSetActiveBy(networkLanguageCounts, allLanguages)
|
||||||
|
else -> throw RuntimeException("Impossible state")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <K> MutableMap<K, Int>.increment(key: K) =
|
||||||
|
apply { set(key, getOrElse(key, { 0 }) + 1) }
|
||||||
|
|
||||||
|
private fun fromLocalesWithNetworkMatchesSetActiveBy(
|
||||||
|
networkLanguageCounts: MutableMap<String, Int>,
|
||||||
|
listToActivateBy: List<Language>
|
||||||
|
): List<Language> {
|
||||||
return Locale.getISOLanguages()
|
return Locale.getISOLanguages()
|
||||||
.map { Locale(it) }
|
.map { Locale(it) }
|
||||||
.filter { languageCounts.containsKey(it.isO3Language) }
|
.filter { networkLanguageCounts.containsKey(it.isO3Language) }
|
||||||
.map { locale ->
|
.map { locale ->
|
||||||
Language(
|
Language(
|
||||||
locale.isO3Language,
|
locale.isO3Language,
|
||||||
languageWasPreviouslyActiveOrIsPrimaryLanguage(activeLanguages, locale),
|
languageIsActive(listToActivateBy, locale),
|
||||||
languageCounts.getOrElse(locale.isO3Language, { 0 })
|
networkLanguageCounts.getOrElse(locale.isO3Language, { 0 })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun languageWasPreviouslyActiveOrIsPrimaryLanguage(
|
private fun defaultLanguage() =
|
||||||
activeLanguages: List<Language>,
|
listOf(
|
||||||
locale: Locale
|
Language(
|
||||||
) = activeLanguages.firstOrNull { it.languageCode == locale.isO3Language }?.let { true }
|
context.resources.configuration.locale.isO3Language,
|
||||||
?: isPrimaryLocale(locale)
|
true,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private fun isPrimaryLocale(locale: Locale) =
|
private fun languageIsActive(
|
||||||
context.resources.configuration.locale.isO3Language == locale.isO3Language
|
allLanguages: List<Language>,
|
||||||
|
locale: Locale
|
||||||
|
) = allLanguages.firstOrNull { it.languageCode == locale.isO3Language }?.active == true
|
||||||
|
|
||||||
private fun combineLibrarySources(
|
private fun combineLibrarySources(
|
||||||
booksOnFileSystem: List<Book>,
|
booksOnFileSystem: List<Book>,
|
||||||
activeDownloads: List<DownloadModel>,
|
activeDownloads: List<DownloadModel>,
|
||||||
activeLanguages: List<Language>,
|
allLanguages: List<Language>,
|
||||||
libraryNetworkEntity: LibraryNetworkEntity,
|
libraryNetworkEntity: LibraryNetworkEntity,
|
||||||
filter: String
|
filter: String
|
||||||
): List<LibraryListItem> {
|
): List<LibraryListItem> {
|
||||||
val downloadedBooksIds = booksOnFileSystem.map { it.id }
|
val downloadedBooksIds = booksOnFileSystem.map { it.id }
|
||||||
val downloadingBookIds = activeDownloads.map { it.book.id }
|
val downloadingBookIds = activeDownloads.map { it.book.id }
|
||||||
val activeLanguageCodes = activeLanguages.map { it.languageCode }
|
val activeLanguageCodes = allLanguages.filter(Language::active)
|
||||||
|
.map { it.languageCode }
|
||||||
val booksUnfilteredByLanguage =
|
val booksUnfilteredByLanguage =
|
||||||
applyUserFilter(
|
applyUserFilter(
|
||||||
libraryNetworkEntity.books
|
libraryNetworkEntity.books
|
||||||
@ -341,3 +367,5 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/time_remaining"
|
android:id="@+id/downloadState"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="start"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
tools:text="3hrs 45 mins"
|
tools:text="In Progress"
|
||||||
/>
|
/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -181,4 +181,23 @@
|
|||||||
<string name="crash_checkbox_device">Device Details</string>
|
<string name="crash_checkbox_device">Device Details</string>
|
||||||
<string name="crash_button_confirm">SEND DETAILS</string>
|
<string name="crash_button_confirm">SEND DETAILS</string>
|
||||||
<string name="crash_button_decline">NO THANKS</string>
|
<string name="crash_button_decline">NO THANKS</string>
|
||||||
|
<string name="pending_state">Pending</string>
|
||||||
|
<string name="running_state">In Progress</string>
|
||||||
|
<string name="successful_state">Complete</string>
|
||||||
|
<string name="paused_state">Paused: %s</string>
|
||||||
|
<string name="failed_state">Failed: %s</string>
|
||||||
|
<string name="paused_wifi">Waiting for Wifi</string>
|
||||||
|
<string name="paused_connectivity">Waiting to connect to a network</string>
|
||||||
|
<string name="paused_retry">Waiting to retry</string>
|
||||||
|
<string name="paused_unknown">Unknown</string>
|
||||||
|
<string name="failed_cannot_resume">Cannot resume due to unknown reason</string>
|
||||||
|
<string name="failed_storage_not_found">Could not find storage</string>
|
||||||
|
<string name="failed_file_already_exists">File already exists</string>
|
||||||
|
<string name="failed_unknown_file_error">Unknown file system error</string>
|
||||||
|
<string name="failed_http_error">HTTP data error</string>
|
||||||
|
<string name="failed_insufficient_space">Not enough space on storage</string>
|
||||||
|
<string name="failed_too_many_redirects">Too many redirects</string>
|
||||||
|
<string name="failed_unhandled_http_code">Unknown HTTP code received</string>
|
||||||
|
<string name="failed_unknown">Unknown</string>
|
||||||
|
<string name="failed_http_code">HTTP code %s</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user