diff --git a/app/detekt_baseline.xml b/app/detekt_baseline.xml index 89953ee69..1c6340c34 100644 --- a/app/detekt_baseline.xml +++ b/app/detekt_baseline.xml @@ -5,7 +5,7 @@ EmptyFunctionBlock:None.kt$None${ } EmptyFunctionBlock:SimplePageChangeListener.kt$SimplePageChangeListener${ } LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( booksOnFileSystem: List<BookOnDisk>, activeDownloads: List<DownloadModel>, allLanguages: List<Language>, libraryNetworkEntity: LibraryNetworkEntity, filter: String, fileSystemState: FileSystemState ) - LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( private val downloadDao: DownloadRoomDao, private val bookDao: NewBookDao, private val languageDao: NewLanguagesDao, private val storageObserver: StorageObserver, private var 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 ) + LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( private val downloadDao: DownloadRoomDao, private val bookDao: NewBookDao, private val languageDao: NewLanguagesDao, private val storageObserver: StorageObserver, private var kiwixService: KiwixService, 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 ) MagicNumber:LibraryListItem.kt$LibraryListItem.LibraryDownloadItem$1000L MagicNumber:PeerGroupHandshake.kt$PeerGroupHandshake$15000 MagicNumber:ShareFiles.kt$ShareFiles$24 diff --git a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/OnlineLibraryFragment.kt b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/OnlineLibraryFragment.kt index 05fe1a31d..47592ffff 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/OnlineLibraryFragment.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/nav/destination/library/OnlineLibraryFragment.kt @@ -87,7 +87,6 @@ import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.YesNoDialog.WifiOnly import org.kiwix.kiwixmobile.databinding.FragmentDestinationDownloadBinding import org.kiwix.kiwixmobile.zimManager.NetworkState -import org.kiwix.kiwixmobile.zimManager.OnlineLibraryStatus import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel import org.kiwix.kiwixmobile.zimManager.libraryView.AvailableSpaceCalculator import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryAdapter @@ -106,7 +105,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions { @Inject lateinit var availableSpaceCalculator: AvailableSpaceCalculator @Inject lateinit var alertDialogShower: AlertDialogShower private var fragmentDestinationDownloadBinding: FragmentDestinationDownloadBinding? = null - + private val lock = Any() private var downloadBookItem: LibraryListItem.BookItem? = null private val zimManageViewModel by lazy { requireActivity().viewModel(viewModelFactory) @@ -302,10 +301,11 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions { } } - private fun onLibraryStatusChanged(onlineLibraryStatus: OnlineLibraryStatus) { - fragmentDestinationDownloadBinding?.apply { - onlineLibraryProgressBar.progress = onlineLibraryStatus.progress - onlineLibraryProgressStatusText.text = onlineLibraryStatus.status + private fun onLibraryStatusChanged(libraryStatus: String) { + synchronized(lock) { + fragmentDestinationDownloadBinding?.apply { + onlineLibraryProgressStatusText.text = libraryStatus + } } } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt index 6a51267c2..19dfb5653 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/AppProgressListenerProvider.kt @@ -18,18 +18,27 @@ package org.kiwix.kiwixmobile.zimManager +import org.kiwix.kiwixmobile.core.R import org.kiwix.kiwixmobile.core.data.remote.OnlineLibraryProgressListener +import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE +import org.kiwix.kiwixmobile.core.downloader.downloadManager.HUNDERED +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO class AppProgressListenerProvider( private val zimManageViewModel: ZimManageViewModel ) : OnlineLibraryProgressListener { @Suppress("MagicNumber") - override fun onProgress(bytesRead: Long, contentLength: Long, done: Boolean) { - val progress = if (contentLength == -1L) 0 else (bytesRead * 100 / contentLength).toInt() + override fun onProgress(bytesRead: Long, contentLength: Long) { + val progress = + if (contentLength == DEFAULT_INT_VALUE.toLong()) { + ZERO + } else { + (bytesRead * HUNDERED / contentLength).toInt() * 3 + } zimManageViewModel.downloadProgress.postValue( - OnlineLibraryStatus( - progress, - "Downloading online content" + zimManageViewModel.context.getString( + R.string.downloading_library, + zimManageViewModel.context.getString(R.string.percentage, progress) ) ) } diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/OnlineLibraryStatus.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/OnlineLibraryStatus.kt deleted file mode 100644 index 91c0f2c04..000000000 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/OnlineLibraryStatus.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Kiwix Android - * Copyright (c) 2024 Kiwix - * 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 . - * - */ - -package org.kiwix.kiwixmobile.zimManager - -data class OnlineLibraryStatus(val progress: Int, val status: String) diff --git a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt index 31715c981..89b114828 100644 --- a/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt +++ b/app/src/main/java/org/kiwix/kiwixmobile/zimManager/ZimManageViewModel.kt @@ -34,6 +34,7 @@ import io.reactivex.processors.BehaviorProcessor import io.reactivex.processors.PublishProcessor import io.reactivex.schedulers.Schedulers import okhttp3.OkHttpClient +import okhttp3.Request import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC import okhttp3.logging.HttpLoggingInterceptor.Level.NONE @@ -47,6 +48,7 @@ import org.kiwix.kiwixmobile.core.dao.NewBookDao import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao import org.kiwix.kiwixmobile.core.data.DataSource import org.kiwix.kiwixmobile.core.data.remote.KiwixService +import org.kiwix.kiwixmobile.core.data.remote.KiwixService.Companion.LIBRARY_NETWORK_PATH import org.kiwix.kiwixmobile.core.data.remote.ProgressResponseBody import org.kiwix.kiwixmobile.core.data.remote.UserAgentInterceptor import org.kiwix.kiwixmobile.core.di.modules.CALL_TIMEOUT @@ -106,7 +108,7 @@ class ZimManageViewModel @Inject constructor( private val languageDao: NewLanguagesDao, private val storageObserver: StorageObserver, private var kiwixService: KiwixService, - private val context: Application, + val context: Application, private val connectivityBroadcastReceiver: ConnectivityBroadcastReceiver, private val bookUtils: BookUtils, private val fat32Checker: Fat32Checker, @@ -140,7 +142,7 @@ class ZimManageViewModel @Inject constructor( val requestFiltering = BehaviorProcessor.createDefault("") private var compositeDisposable: CompositeDisposable? = CompositeDisposable() - val downloadProgress = MutableLiveData() + val downloadProgress = MutableLiveData() init { // add listener to retrofit to get updates of downloading online library @@ -150,6 +152,7 @@ class ZimManageViewModel @Inject constructor( } private fun createKiwixServiceWithProgressListener(): KiwixService { + val contentLength = getContentLengthOfLibraryXmlFile() val customOkHttpClient = OkHttpClient().newBuilder() .followRedirects(true) .followSslRedirects(true) @@ -168,7 +171,8 @@ class ZimManageViewModel @Inject constructor( .body( ProgressResponseBody( originalResponse.body!!, - AppProgressListenerProvider(this) + AppProgressListenerProvider(this), + contentLength ) ) .build() @@ -177,6 +181,29 @@ class ZimManageViewModel @Inject constructor( return KiwixService.ServiceCreator.newHackListService(customOkHttpClient, KIWIX_DOWNLOAD_URL) } + private fun getContentLengthOfLibraryXmlFile(): Long { + val headRequest = Request.Builder() + .url("$KIWIX_DOWNLOAD_URL$LIBRARY_NETWORK_PATH") + .head() + .header("Accept-Encoding", "identity") + .build() + val client = OkHttpClient().newBuilder() + .followRedirects(true) + .followSslRedirects(true) + .connectTimeout(CONNECTION_TIMEOUT, SECONDS) + .readTimeout(READ_TIMEOUT, SECONDS) + .callTimeout(CALL_TIMEOUT, SECONDS) + .addNetworkInterceptor(UserAgentInterceptor(USER_AGENT)) + .build() + client.newCall(headRequest).execute().use { response -> + if (response.isSuccessful) { + return@getContentLengthOfLibraryXmlFile response.header("content-length")?.toLongOrNull() + ?: -1L + } + } + return -1L + } + @VisibleForTesting fun onClearedExposed() { onCleared() @@ -300,37 +327,22 @@ class ZimManageViewModel @Inject constructor( } .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) - .flatMap { + .concatMap { kiwixService.library .toFlowable() .retry(5) .doOnSubscribe { - downloadProgress.postValue(OnlineLibraryStatus(0, "Downloading library 0%")) + downloadProgress.postValue(context.getString(R.string.start_server_label)) } .map { response -> - downloadProgress.postValue( - OnlineLibraryStatus( - 0, - "Downloading library... parsing response" - ) - ) + downloadProgress.postValue(context.getString(R.string.parsing_remote_library)) response } .doFinally { - downloadProgress.postValue( - OnlineLibraryStatus( - 0, - "Remote library downloaded, parsing data" - ) - ) + downloadProgress.postValue(context.getString(R.string.parsing_remote_library)) } .onErrorReturn { it.printStackTrace() - downloadProgress.postValue( - OnlineLibraryStatus( - 0, "Failed to download the library" - ) - ) LibraryNetworkEntity().apply { book = LinkedList() } } } diff --git a/app/src/main/res/layout/fragment_destination_download.xml b/app/src/main/res/layout/fragment_destination_download.xml index 137ae295c..1d8b7c9ae 100644 --- a/app/src/main/res/layout/fragment_destination_download.xml +++ b/app/src/main/res/layout/fragment_destination_download.xml @@ -67,12 +67,12 @@ tools:ignore="RequiredSize" /> + android:padding="@dimen/find_in_page_button_padding"> + android:layout_width="40dp" + android:layout_height="40dp" /> + android:textSize="10sp" + tools:ignore="SmallSp" /> diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 671c2986b..783340b5b 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -20,9 +20,9 @@ object Versions { const val tracing: String = "1.1.0" - const val com_squareup_retrofit2: String = "2.9.0" + const val com_squareup_retrofit2: String = "2.11.0" - const val com_squareup_okhttp3: String = "4.10.0" + const val com_squareup_okhttp3: String = "4.12.0" const val org_jetbrains_kotlin: String = "1.9.20" diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/OnlineLibraryProgressListener.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/OnlineLibraryProgressListener.kt index dd2301aec..742eea780 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/OnlineLibraryProgressListener.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/OnlineLibraryProgressListener.kt @@ -19,5 +19,5 @@ package org.kiwix.kiwixmobile.core.data.remote interface OnlineLibraryProgressListener { - fun onProgress(bytesRead: Long, contentLength: Long, done: Boolean) + fun onProgress(bytesRead: Long, contentLength: Long) } diff --git a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/ProgressResponseBody.kt b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/ProgressResponseBody.kt index e045d056a..503e8a512 100644 --- a/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/ProgressResponseBody.kt +++ b/core/src/main/java/org/kiwix/kiwixmobile/core/data/remote/ProgressResponseBody.kt @@ -25,11 +25,13 @@ import okio.BufferedSource import okio.ForwardingSource import okio.Source import okio.buffer -import org.kiwix.kiwixmobile.core.utils.files.Log +import org.kiwix.kiwixmobile.core.downloader.downloadManager.DEFAULT_INT_VALUE +import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO class ProgressResponseBody( private val responseBody: ResponseBody, - private val progressListener: OnlineLibraryProgressListener + private val progressListener: OnlineLibraryProgressListener, + private val contentLength: Long ) : ResponseBody() { private lateinit var bufferedSource: BufferedSource @@ -37,7 +39,6 @@ class ProgressResponseBody( override fun contentType(): MediaType? = responseBody.contentType() override fun contentLength(): Long = responseBody.contentLength() - override fun source(): BufferedSource { if (!::bufferedSource.isInitialized) { bufferedSource = source(responseBody.source()).buffer() @@ -47,24 +48,11 @@ class ProgressResponseBody( private fun source(source: Source): Source { return object : ForwardingSource(source) { - var totalBytesRead = 0L + var totalBytesRead = ZERO.toLong() override fun read(sink: Buffer, byteCount: Long): Long { val bytesRead = super.read(sink, byteCount) - totalBytesRead += if (bytesRead != -1L) bytesRead else 0 - val isDone = bytesRead == -1L - progressListener.onProgress( - totalBytesRead, - responseBody.contentLength(), - isDone - ) - .also { - Log.e( - "PROGRESS", - "onProgress: ${contentLength()} and byteRead = $totalBytesRead\n" + - " sink ${bytesRead == -1L} \n byteRead = $bytesRead " + - "\n bufferedSource = ${bufferedSource.isOpen}" - ) - } + totalBytesRead += if (bytesRead != DEFAULT_INT_VALUE.toLong()) bytesRead else ZERO.toLong() + progressListener.onProgress(totalBytesRead, contentLength) return bytesRead } } diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 3f856f264..5a8ee04b6 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -349,6 +349,9 @@ Allow Swipe Down for Library Reaching remote library + Parsing remote library + Starting download of the online library + Downloading library %s @string/on @string/off