mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-09-08 06:42:21 -04:00
Improved the design of showing the downloading progress of online library.
* Also, disabled the refresh layout so avoid unnecessary calls when a request is already in progress.
This commit is contained in:
parent
90f711b244
commit
c5d0d8aeea
@ -41,6 +41,7 @@ import androidx.core.app.ActivityCompat
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.MenuHost
|
import androidx.core.view.MenuHost
|
||||||
import androidx.core.view.MenuProvider
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
@ -86,6 +87,7 @@ import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
|||||||
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.YesNoDialog.WifiOnly
|
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog.YesNoDialog.WifiOnly
|
||||||
import org.kiwix.kiwixmobile.databinding.FragmentDestinationDownloadBinding
|
import org.kiwix.kiwixmobile.databinding.FragmentDestinationDownloadBinding
|
||||||
import org.kiwix.kiwixmobile.zimManager.NetworkState
|
import org.kiwix.kiwixmobile.zimManager.NetworkState
|
||||||
|
import org.kiwix.kiwixmobile.zimManager.OnlineLibraryStatus
|
||||||
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
import org.kiwix.kiwixmobile.zimManager.ZimManageViewModel
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.AvailableSpaceCalculator
|
import org.kiwix.kiwixmobile.zimManager.libraryView.AvailableSpaceCalculator
|
||||||
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryAdapter
|
import org.kiwix.kiwixmobile.zimManager.libraryView.adapter.LibraryAdapter
|
||||||
@ -192,16 +194,11 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) {
|
) {
|
||||||
if (it && !NetworkUtils.isWiFi(requireContext())) {
|
if (it && !NetworkUtils.isWiFi(requireContext())) {
|
||||||
|
hideProgressBarOfFetchingOnlineLibrary()
|
||||||
showInternetAccessViaMobileNetworkDialog()
|
showInternetAccessViaMobileNetworkDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zimManageViewModel.downloadProgress.observe(viewLifecycleOwner) { progress ->
|
zimManageViewModel.downloadProgress.observe(viewLifecycleOwner, ::onLibraryStatusChanged)
|
||||||
fragmentDestinationDownloadBinding?.onlineLibraryProgressBar?.progress = progress
|
|
||||||
}
|
|
||||||
|
|
||||||
zimManageViewModel.downloadStatus.observe(viewLifecycleOwner) { status ->
|
|
||||||
fragmentDestinationDownloadBinding?.libraryErrorText?.text = status
|
|
||||||
}
|
|
||||||
setupMenu()
|
setupMenu()
|
||||||
|
|
||||||
// hides keyboard when scrolled
|
// hides keyboard when scrolled
|
||||||
@ -254,13 +251,11 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
dialogShower.show(
|
dialogShower.show(
|
||||||
WifiOnly,
|
WifiOnly,
|
||||||
{
|
{
|
||||||
onRefreshStateChange(true)
|
|
||||||
showRecyclerviewAndHideSwipeDownForLibraryErrorText()
|
showRecyclerviewAndHideSwipeDownForLibraryErrorText()
|
||||||
sharedPreferenceUtil.putPrefWifiOnly(false)
|
sharedPreferenceUtil.putPrefWifiOnly(false)
|
||||||
zimManageViewModel.shouldShowWifiOnlyDialog.value = false
|
zimManageViewModel.shouldShowWifiOnlyDialog.value = false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
onRefreshStateChange(false)
|
|
||||||
context.toast(
|
context.toast(
|
||||||
resources.getString(string.denied_internet_permission_message),
|
resources.getString(string.denied_internet_permission_message),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
@ -285,17 +280,32 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
)
|
)
|
||||||
libraryErrorText.visibility = View.VISIBLE
|
libraryErrorText.visibility = View.VISIBLE
|
||||||
libraryList.visibility = View.GONE
|
libraryList.visibility = View.GONE
|
||||||
onlineLibraryProgressBar.visibility = View.GONE
|
|
||||||
}
|
}
|
||||||
|
hideProgressBarOfFetchingOnlineLibrary()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showProgressBarOfFetchingOnlineLibrary() {
|
private fun showProgressBarOfFetchingOnlineLibrary() {
|
||||||
|
onRefreshStateChange(false)
|
||||||
fragmentDestinationDownloadBinding?.apply {
|
fragmentDestinationDownloadBinding?.apply {
|
||||||
onlineLibraryProgressBar.visibility = View.VISIBLE
|
librarySwipeRefresh.isEnabled = false
|
||||||
libraryErrorText.apply {
|
onlineLibraryProgressLayout.visibility = View.VISIBLE
|
||||||
visibility = View.VISIBLE
|
onlineLibraryProgressStatusText.setText(string.reaching_remote_library)
|
||||||
setText(string.reaching_remote_library)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun hideProgressBarOfFetchingOnlineLibrary() {
|
||||||
|
onRefreshStateChange(false)
|
||||||
|
fragmentDestinationDownloadBinding?.apply {
|
||||||
|
librarySwipeRefresh.isEnabled = true
|
||||||
|
onlineLibraryProgressLayout.visibility = View.GONE
|
||||||
|
onlineLibraryProgressStatusText.setText(string.reaching_remote_library)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onLibraryStatusChanged(onlineLibraryStatus: OnlineLibraryStatus) {
|
||||||
|
fragmentDestinationDownloadBinding?.apply {
|
||||||
|
onlineLibraryProgressBar.progress = onlineLibraryStatus.progress
|
||||||
|
onlineLibraryProgressStatusText.text = onlineLibraryStatus.status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,17 +322,20 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onRefreshStateChange(isRefreshing: Boolean?) {
|
private fun onRefreshStateChange(isRefreshing: Boolean?) {
|
||||||
fragmentDestinationDownloadBinding?.librarySwipeRefresh?.isRefreshing = isRefreshing == true
|
var refreshing = isRefreshing == true
|
||||||
|
// do not show the refreshing when the online library is downloading
|
||||||
|
if (fragmentDestinationDownloadBinding?.onlineLibraryProgressLayout?.isVisible == true) {
|
||||||
|
refreshing = false
|
||||||
|
}
|
||||||
|
fragmentDestinationDownloadBinding?.librarySwipeRefresh?.isRefreshing = refreshing
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onNetworkStateChange(networkState: NetworkState?) {
|
private fun onNetworkStateChange(networkState: NetworkState?) {
|
||||||
when (networkState) {
|
when (networkState) {
|
||||||
NetworkState.CONNECTED -> {
|
NetworkState.CONNECTED -> {
|
||||||
if (NetworkUtils.isWiFi(requireContext())) {
|
if (NetworkUtils.isWiFi(requireContext())) {
|
||||||
onRefreshStateChange(true)
|
|
||||||
refreshFragment()
|
refreshFragment()
|
||||||
} else if (noWifiWithWifiOnlyPreferenceSet) {
|
} else if (noWifiWithWifiOnlyPreferenceSet) {
|
||||||
onRefreshStateChange(false)
|
|
||||||
hideRecyclerviewAndShowSwipeDownForLibraryErrorText()
|
hideRecyclerviewAndShowSwipeDownForLibraryErrorText()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,7 +357,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
)
|
)
|
||||||
fragmentDestinationDownloadBinding?.libraryErrorText?.visibility = View.VISIBLE
|
fragmentDestinationDownloadBinding?.libraryErrorText?.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
fragmentDestinationDownloadBinding?.librarySwipeRefresh?.isRefreshing = false
|
hideProgressBarOfFetchingOnlineLibrary()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun noInternetSnackbar() {
|
private fun noInternetSnackbar() {
|
||||||
@ -364,7 +377,7 @@ class OnlineLibraryFragment : BaseFragment(), FragmentActivityExtensions {
|
|||||||
if (it != null) {
|
if (it != null) {
|
||||||
libraryAdapter.items = it
|
libraryAdapter.items = it
|
||||||
}
|
}
|
||||||
fragmentDestinationDownloadBinding?.onlineLibraryProgressBar?.visibility = View.GONE
|
hideProgressBarOfFetchingOnlineLibrary()
|
||||||
if (it?.isEmpty() == true) {
|
if (it?.isEmpty() == true) {
|
||||||
fragmentDestinationDownloadBinding?.libraryErrorText?.setText(
|
fragmentDestinationDownloadBinding?.libraryErrorText?.setText(
|
||||||
if (isNotConnected) string.no_network_connection
|
if (isNotConnected) string.no_network_connection
|
||||||
|
@ -26,6 +26,11 @@ class AppProgressListenerProvider(
|
|||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override fun onProgress(bytesRead: Long, contentLength: Long, done: Boolean) {
|
override fun onProgress(bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||||
val progress = if (contentLength == -1L) 0 else (bytesRead * 100 / contentLength).toInt()
|
val progress = if (contentLength == -1L) 0 else (bytesRead * 100 / contentLength).toInt()
|
||||||
zimManageViewModel.downloadProgress.postValue(progress)
|
zimManageViewModel.downloadProgress.postValue(
|
||||||
|
OnlineLibraryStatus(
|
||||||
|
progress,
|
||||||
|
"Downloading online content"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
@ -140,8 +140,7 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
val requestFiltering = BehaviorProcessor.createDefault("")
|
val requestFiltering = BehaviorProcessor.createDefault("")
|
||||||
|
|
||||||
private var compositeDisposable: CompositeDisposable? = CompositeDisposable()
|
private var compositeDisposable: CompositeDisposable? = CompositeDisposable()
|
||||||
val downloadProgress = MutableLiveData<Int>()
|
val downloadProgress = MutableLiveData<OnlineLibraryStatus>()
|
||||||
val downloadStatus = MutableLiveData<String>()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// add listener to retrofit to get updates of downloading online library
|
// add listener to retrofit to get updates of downloading online library
|
||||||
@ -299,14 +298,6 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
.map { }
|
.map { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.doOnEach {
|
|
||||||
downloadStatus.postValue("Reaching remote library")
|
|
||||||
}
|
|
||||||
.switchMap {
|
|
||||||
Flowable.fromCallable {
|
|
||||||
downloadStatus.postValue("Starting download of the online library")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.flatMap {
|
.flatMap {
|
||||||
@ -314,18 +305,32 @@ class ZimManageViewModel @Inject constructor(
|
|||||||
.toFlowable()
|
.toFlowable()
|
||||||
.retry(5)
|
.retry(5)
|
||||||
.doOnSubscribe {
|
.doOnSubscribe {
|
||||||
downloadStatus.postValue("Downloading library 0%")
|
downloadProgress.postValue(OnlineLibraryStatus(0, "Downloading library 0%"))
|
||||||
}
|
}
|
||||||
.map { response ->
|
.map { response ->
|
||||||
downloadStatus.postValue("Downloading library... parsing response")
|
downloadProgress.postValue(
|
||||||
|
OnlineLibraryStatus(
|
||||||
|
0,
|
||||||
|
"Downloading library... parsing response"
|
||||||
|
)
|
||||||
|
)
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
.doFinally {
|
.doFinally {
|
||||||
downloadStatus.postValue("Remote library downloaded, parsing data")
|
downloadProgress.postValue(
|
||||||
|
OnlineLibraryStatus(
|
||||||
|
0,
|
||||||
|
"Remote library downloaded, parsing data"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.onErrorReturn {
|
.onErrorReturn {
|
||||||
it.printStackTrace()
|
it.printStackTrace()
|
||||||
downloadStatus.postValue("Failed to download the library")
|
downloadProgress.postValue(
|
||||||
|
OnlineLibraryStatus(
|
||||||
|
0, "Failed to download the library"
|
||||||
|
)
|
||||||
|
)
|
||||||
LibraryNetworkEntity().apply { book = LinkedList() }
|
LibraryNetworkEntity().apply { book = LinkedList() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@
|
|||||||
android:id="@+id/libraryList"
|
android:id="@+id/libraryList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:scrollbars="vertical"
|
|
||||||
android:contentDescription="@string/library"
|
android:contentDescription="@string/library"
|
||||||
|
android:scrollbars="vertical"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
tools:listitem="@layout/item_download" />
|
tools:listitem="@layout/item_download" />
|
||||||
|
|
||||||
@ -66,13 +66,44 @@
|
|||||||
app:layout_constraintVertical_bias="0.45"
|
app:layout_constraintVertical_bias="0.45"
|
||||||
tools:ignore="RequiredSize" />
|
tools:ignore="RequiredSize" />
|
||||||
|
|
||||||
<ProgressBar
|
<androidx.cardview.widget.CardView
|
||||||
android:id="@+id/onlineLibraryProgressBar"
|
android:id="@+id/progressCardView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:layout_margin="16dp"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:visibility="gone"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/libraryErrorText" />
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/onlineLibraryProgressLayout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="@dimen/activity_horizontal_margin"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/onlineLibraryProgressBar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_horizontal_margin" />
|
||||||
|
|
||||||
|
<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" />
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -32,18 +32,17 @@ class ProgressResponseBody(
|
|||||||
private val progressListener: OnlineLibraryProgressListener
|
private val progressListener: OnlineLibraryProgressListener
|
||||||
) : ResponseBody() {
|
) : ResponseBody() {
|
||||||
|
|
||||||
private var bufferedSource: BufferedSource? = null
|
private lateinit var bufferedSource: BufferedSource
|
||||||
|
|
||||||
override fun contentType(): MediaType? = responseBody.contentType()
|
override fun contentType(): MediaType? = responseBody.contentType()
|
||||||
|
|
||||||
override fun contentLength(): Long = responseBody.contentLength()
|
override fun contentLength(): Long = responseBody.contentLength()
|
||||||
|
|
||||||
@Suppress("UnsafeCallOnNullableType")
|
|
||||||
override fun source(): BufferedSource {
|
override fun source(): BufferedSource {
|
||||||
if (bufferedSource == null) {
|
if (!::bufferedSource.isInitialized) {
|
||||||
bufferedSource = source(responseBody.source()).buffer()
|
bufferedSource = source(responseBody.source()).buffer()
|
||||||
}
|
}
|
||||||
return bufferedSource!!
|
return bufferedSource
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun source(source: Source): Source {
|
private fun source(source: Source): Source {
|
||||||
@ -57,14 +56,15 @@ class ProgressResponseBody(
|
|||||||
totalBytesRead,
|
totalBytesRead,
|
||||||
responseBody.contentLength(),
|
responseBody.contentLength(),
|
||||||
isDone
|
isDone
|
||||||
).also {
|
)
|
||||||
Log.e(
|
.also {
|
||||||
"PROGRESS",
|
Log.e(
|
||||||
"onProgress: ${contentLength()} and byteRead = $totalBytesRead\n" +
|
"PROGRESS",
|
||||||
" sink ${bytesRead == -1L} \n byteRead = $bytesRead " +
|
"onProgress: ${contentLength()} and byteRead = $totalBytesRead\n" +
|
||||||
"\n bufferedSource = ${bufferedSource?.isOpen}"
|
" sink ${bytesRead == -1L} \n byteRead = $bytesRead " +
|
||||||
)
|
"\n bufferedSource = ${bufferedSource.isOpen}"
|
||||||
}
|
)
|
||||||
|
}
|
||||||
return bytesRead
|
return bytesRead
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user