mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 02:36:24 -04:00
Refactored our code to properly show the downloading online library progress.
* Added a head request to get the library length and showing the progress on behalf of that length. * Improved the library loading process: previously, fetching the online library involved making two requests, which not only took more time to get a response from the server but also used twice the bandwidth. To address this, we have refactored our code to ensure that only one request is made at a time. * Upgraded the retrofit, and interceptor dependencies to latest version.
This commit is contained in:
parent
8ebeb4e3e9
commit
10837aef76
@ -5,7 +5,7 @@
|
||||
<ID>EmptyFunctionBlock:None.kt$None${ }</ID>
|
||||
<ID>EmptyFunctionBlock:SimplePageChangeListener.kt$SimplePageChangeListener${ }</ID>
|
||||
<ID>LongParameterList:ZimManageViewModel.kt$ZimManageViewModel$( booksOnFileSystem: List<BookOnDisk>, activeDownloads: List<DownloadModel>, allLanguages: List<Language>, libraryNetworkEntity: LibraryNetworkEntity, filter: String, fileSystemState: FileSystemState )</ID>
|
||||
<ID>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 )</ID>
|
||||
<ID>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 )</ID>
|
||||
<ID>MagicNumber:LibraryListItem.kt$LibraryListItem.LibraryDownloadItem$1000L</ID>
|
||||
<ID>MagicNumber:PeerGroupHandshake.kt$PeerGroupHandshake$15000</ID>
|
||||
<ID>MagicNumber:ShareFiles.kt$ShareFiles$24</ID>
|
||||
|
@ -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<ZimManageViewModel>(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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Kiwix Android
|
||||
* Copyright (c) 2024 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.zimManager
|
||||
|
||||
data class OnlineLibraryStatus(val progress: Int, val status: String)
|
@ -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<OnlineLibraryStatus>()
|
||||
val downloadProgress = MutableLiveData<String>()
|
||||
|
||||
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() }
|
||||
}
|
||||
}
|
||||
|
@ -67,12 +67,12 @@
|
||||
tools:ignore="RequiredSize" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/progressCardView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/onlineLibraryProgressLayout"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_margin="16dp"
|
||||
android:visibility="visible"
|
||||
app:cardCornerRadius="4dp"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -80,30 +80,28 @@
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/onlineLibraryProgressLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/activity_horizontal_margin"
|
||||
android:visibility="gone">
|
||||
android:padding="@dimen/find_in_page_button_padding">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/onlineLibraryProgressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/activity_horizontal_margin" />
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/onlineLibraryProgressStatusText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="@dimen/activity_horizontal_margin"
|
||||
android:gravity="center"
|
||||
android:text="@string/reaching_remote_library"
|
||||
android:textColor="@color/mine_shaft_gray900"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -349,6 +349,9 @@
|
||||
<string name="allow">Allow</string>
|
||||
<string name="swipe_down_for_library">Swipe Down for Library</string>
|
||||
<string name="reaching_remote_library">Reaching remote library</string>
|
||||
<string name="parsing_remote_library">Parsing remote library</string>
|
||||
<string name="starting_downloading_remote_library">Starting download of the online library</string>
|
||||
<string name="downloading_library">Downloading library %s</string>
|
||||
<string-array name="pref_dark_modes_entries">
|
||||
<item>@string/on</item>
|
||||
<item>@string/off</item>
|
||||
|
Loading…
x
Reference in New Issue
Block a user