mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-09-10 20:43:14 +02:00
Reorder downloads + Fixes to extensions autochecker
This commit is contained in:
parent
65ca7ab476
commit
53f7b3a762
@ -5,13 +5,11 @@ import com.hippo.unifile.UniFile
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.util.launchNow
|
||||
import eu.kanade.tachiyomi.util.launchUI
|
||||
import kotlinx.coroutines.delay
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
@ -95,6 +93,19 @@ class DownloadManager(context: Context) {
|
||||
downloader.clearQueue(isNotification)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders the download queue.
|
||||
*
|
||||
* @param downloads value to set the download queue to
|
||||
*/
|
||||
fun reorderQueue(downloads: List<Download>) {
|
||||
downloader.pause()
|
||||
downloader.queue.clear()
|
||||
downloader.queue.addAll(downloads)
|
||||
downloader.start()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tells the downloader to enqueue the given list of chapters.
|
||||
*
|
||||
|
@ -13,7 +13,12 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.fetchAllImageUrlsFromPageList
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import eu.kanade.tachiyomi.util.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.RetryWithDelay
|
||||
import eu.kanade.tachiyomi.util.launchNow
|
||||
import eu.kanade.tachiyomi.util.launchUI
|
||||
import eu.kanade.tachiyomi.util.plusAssign
|
||||
import eu.kanade.tachiyomi.util.saveTo
|
||||
import kotlinx.coroutines.async
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
@ -94,7 +99,7 @@ class Downloader(
|
||||
fun start(): Boolean {
|
||||
if (isRunning || queue.isEmpty())
|
||||
return false
|
||||
|
||||
notifier.paused = false
|
||||
if (!subscriptions.hasSubscriptions())
|
||||
initializeSubscriptions()
|
||||
|
||||
@ -184,7 +189,6 @@ class Downloader(
|
||||
if (isRunning) return
|
||||
isRunning = true
|
||||
runningRelay.call(true)
|
||||
|
||||
subscriptions.clear()
|
||||
|
||||
subscriptions += downloadsRelay.concatMapIterable { it }
|
||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.notification
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
@ -19,47 +20,16 @@ import java.util.concurrent.TimeUnit
|
||||
|
||||
class ExtensionUpdateJob : Job() {
|
||||
|
||||
var subscription:Subscription? = null
|
||||
|
||||
override fun onRunJob(params: Params): Result {
|
||||
val extensionManager: ExtensionManager = Injekt.get()
|
||||
extensionManager.findAvailableExtensions()
|
||||
/*return extensionManager.getInstalledExtensionsObservable()
|
||||
.map { list ->
|
||||
val pendingUpdates = list.filter { it.hasUpdate }
|
||||
if (pendingUpdates.isNotEmpty()) {
|
||||
val names = pendingUpdates.map { it.name }
|
||||
|
||||
NotificationManagerCompat.from(context).apply {
|
||||
notify(Notifications.ID_UPDATES_TO_EXTS,
|
||||
context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
|
||||
setContentTitle(
|
||||
context.getString(
|
||||
R.string.update_check_notification_ext_updates, names.size
|
||||
)
|
||||
)
|
||||
val extNames = if (names.size > 5) {
|
||||
"${names.take(4).joinToString(", ")}, " + context.getString(
|
||||
R.string.notification_and_n_more, (names.size - 4)
|
||||
)
|
||||
} else names.joinToString(", ")
|
||||
setContentText(extNames)
|
||||
setSmallIcon(R.drawable.ic_extension_update)
|
||||
color = ContextCompat.getColor(context, R.color.colorAccentLight)
|
||||
setContentIntent(
|
||||
NotificationReceiver.openExtensionsPendingActivity(
|
||||
context
|
||||
)
|
||||
)
|
||||
setAutoCancel(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
Result.SUCCESS
|
||||
}
|
||||
.onErrorReturn { Result.FAILURE }
|
||||
// Sadly, the task needs to be synchronous.
|
||||
.toBlocking()
|
||||
.single()*/
|
||||
Observable.defer {
|
||||
subscription?.unsubscribe()
|
||||
|
||||
// Update favorite manga. Destroy service when completed or in case of an error.
|
||||
subscription = Observable.defer {
|
||||
extensionManager.getInstalledExtensionsObservable().map { list ->
|
||||
val pendingUpdates = list.filter { it.hasUpdate }
|
||||
if (pendingUpdates.isNotEmpty()) {
|
||||
@ -89,8 +59,9 @@ class ExtensionUpdateJob : Job() {
|
||||
})
|
||||
}
|
||||
}
|
||||
subscription?.unsubscribe()
|
||||
Result.SUCCESS
|
||||
}.onErrorReturn { Result.FAILURE }
|
||||
}
|
||||
}.subscribeOn(Schedulers.io())
|
||||
.subscribe({
|
||||
}, {
|
||||
@ -100,51 +71,6 @@ class ExtensionUpdateJob : Job() {
|
||||
return Result.SUCCESS
|
||||
}
|
||||
|
||||
/*fun runStuff(context: Context) {
|
||||
val extensionManager: ExtensionManager = Injekt.get()
|
||||
extensionManager.findAvailableExtensions()
|
||||
Observable.defer {
|
||||
extensionManager.getInstalledExtensionsObservable().map { list ->
|
||||
val pendingUpdates = list.filter { it.hasUpdate }
|
||||
if (pendingUpdates.isNotEmpty()) {
|
||||
val names = pendingUpdates.map { it.name }
|
||||
NotificationManagerCompat.from(context).apply {
|
||||
notify(Notifications.ID_UPDATES_TO_EXTS,
|
||||
context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
|
||||
setContentTitle(
|
||||
context.getString(
|
||||
R.string.update_check_notification_ext_updates, names.size
|
||||
)
|
||||
)
|
||||
val extNames = if (names.size > 5) {
|
||||
"${names.take(4).joinToString(", ")}, " + context.getString(
|
||||
R.string.notification_and_n_more, (names.size - 4)
|
||||
)
|
||||
} else names.joinToString(", ")
|
||||
setContentText(extNames)
|
||||
setSmallIcon(R.drawable.ic_extension_update)
|
||||
color = ContextCompat.getColor(context, R.color.colorAccentLight)
|
||||
setContentIntent(
|
||||
NotificationReceiver.openExtensionsPendingActivity(
|
||||
context
|
||||
)
|
||||
)
|
||||
setAutoCancel(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
Result.SUCCESS
|
||||
}.onErrorReturn { Result.FAILURE }
|
||||
}.subscribeOn(Schedulers.io())
|
||||
.subscribe({
|
||||
}, {
|
||||
Timber.e(it)
|
||||
}, {
|
||||
})
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
companion object {
|
||||
const val TAG = "ExtensionUpdate"
|
||||
|
||||
|
@ -1,72 +1,24 @@
|
||||
package eu.kanade.tachiyomi.ui.download
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
|
||||
/**
|
||||
* Adapter storing a list of downloads.
|
||||
*
|
||||
* @param context the context of the fragment containing this adapter.
|
||||
*/
|
||||
class DownloadAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<DownloadHolder>() {
|
||||
|
||||
private var items = emptyList<Download>()
|
||||
|
||||
init {
|
||||
setHasStableIds(true)
|
||||
}
|
||||
class DownloadAdapter(controller: DownloadController) : FlexibleAdapter<DownloadItem>(null, controller,
|
||||
true) {
|
||||
|
||||
/**
|
||||
* Sets a list of downloads in the adapter.
|
||||
*
|
||||
* @param downloads the list to set.
|
||||
* Listener called when an item of the list is released.
|
||||
*/
|
||||
fun setItems(downloads: List<Download>) {
|
||||
items = downloads
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
val onItemReleaseListener: OnItemReleaseListener = controller
|
||||
|
||||
/**
|
||||
* Returns the number of downloads in the adapter
|
||||
*/
|
||||
override fun getItemCount(): Int {
|
||||
return items.size
|
||||
interface OnItemReleaseListener {
|
||||
/**
|
||||
* Called when an item of the list is released.
|
||||
*/
|
||||
fun onItemReleased(position: Int)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier for a download.
|
||||
*
|
||||
* @param position the position in the adapter.
|
||||
* @return an identifier for the item.
|
||||
*/
|
||||
override fun getItemId(position: Int): Long {
|
||||
return items[position].chapter.id!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new view holder.
|
||||
*
|
||||
* @param parent the parent view.
|
||||
* @param viewType the type of the holder.
|
||||
* @return a new view holder for a manga.
|
||||
*/
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadHolder {
|
||||
val view = parent.inflate(R.layout.download_item)
|
||||
return DownloadHolder(view)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds a holder with a new position.
|
||||
*
|
||||
* @param holder the holder to bind.
|
||||
* @param position the position to bind.
|
||||
*/
|
||||
override fun onBindViewHolder(holder: DownloadHolder, position: Int) {
|
||||
val download = items[position]
|
||||
holder.onSetValues(download)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
package eu.kanade.tachiyomi.ui.download
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import android.view.*
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
@ -12,14 +17,15 @@ import kotlinx.android.synthetic.main.download_controller.*
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.util.*
|
||||
import java.util.HashMap
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
||||
* Controller that shows the currently active downloads.
|
||||
* Uses R.layout.fragment_download_queue.
|
||||
*/
|
||||
class DownloadController : NucleusController<DownloadPresenter>() {
|
||||
class DownloadController : NucleusController<DownloadPresenter>(),
|
||||
DownloadAdapter.OnItemReleaseListener {
|
||||
|
||||
/**
|
||||
* Adapter containing the active downloads.
|
||||
@ -59,11 +65,12 @@ class DownloadController : NucleusController<DownloadPresenter>() {
|
||||
setInformationView()
|
||||
|
||||
// Initialize adapter.
|
||||
adapter = DownloadAdapter()
|
||||
adapter = DownloadAdapter(this@DownloadController)
|
||||
recycler.adapter = adapter
|
||||
adapter?.isHandleDragEnabled = true
|
||||
|
||||
// Set the layout manager for the recycler and fixed size.
|
||||
recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(view.context)
|
||||
recycler.layoutManager = LinearLayoutManager(view.context)
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
|
||||
|
||||
@ -170,7 +177,7 @@ class DownloadController : NucleusController<DownloadPresenter>() {
|
||||
// Avoid leaking subscriptions
|
||||
progressSubscriptions.remove(download)?.unsubscribe()
|
||||
|
||||
progressSubscriptions.put(download, subscription)
|
||||
progressSubscriptions[download] = subscription
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,10 +207,10 @@ class DownloadController : NucleusController<DownloadPresenter>() {
|
||||
*
|
||||
* @param downloads the downloads from the queue.
|
||||
*/
|
||||
fun onNextDownloads(downloads: List<Download>) {
|
||||
fun onNextDownloads(downloads: List<DownloadItem>) {
|
||||
activity?.invalidateOptionsMenu()
|
||||
setInformationView()
|
||||
adapter?.setItems(downloads)
|
||||
adapter?.updateDataSet(downloads)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,4 +253,15 @@ class DownloadController : NucleusController<DownloadPresenter>() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an item is released from a drag.
|
||||
*
|
||||
* @param position The position of the released item.
|
||||
*/
|
||||
override fun onItemReleased(position: Int) {
|
||||
val adapter = adapter ?: return
|
||||
val downloads = (0 until adapter.itemCount).mapNotNull { adapter.getItem(it)?.download }
|
||||
presenter.reorder(downloads)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.ui.download
|
||||
|
||||
import android.view.View
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseViewHolder
|
||||
import kotlinx.android.synthetic.main.download_item.view.*
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import kotlinx.android.synthetic.main.download_item.*
|
||||
|
||||
/**
|
||||
* Class used to hold the data of a download.
|
||||
@ -12,47 +12,50 @@ import kotlinx.android.synthetic.main.download_item.view.*
|
||||
* @param view the inflated view for this holder.
|
||||
* @constructor creates a new download holder.
|
||||
*/
|
||||
class DownloadHolder(private val view: View) : BaseViewHolder(view) {
|
||||
class DownloadHolder(view: View, val adapter: DownloadAdapter) : BaseFlexibleViewHolder(view, adapter) {
|
||||
|
||||
init {
|
||||
setDragHandleView(reorder)
|
||||
}
|
||||
|
||||
private lateinit var download: Download
|
||||
|
||||
/**
|
||||
* Method called from [DownloadAdapter.onBindViewHolder]. It updates the data for this
|
||||
* holder with the given download.
|
||||
* Binds this holder with the given category.
|
||||
*
|
||||
* @param download the download to bind.
|
||||
* @param category The category to bind.
|
||||
*/
|
||||
fun onSetValues(download: Download) {
|
||||
fun bind(download: Download) {
|
||||
this.download = download
|
||||
|
||||
// Update the chapter name.
|
||||
view.chapter_title.text = download.chapter.name
|
||||
chapter_title.text = download.chapter.name
|
||||
|
||||
// Update the manga title
|
||||
view.manga_title.text = download.manga.title
|
||||
manga_title.text = download.manga.title
|
||||
|
||||
// Update the progress bar and the number of downloaded pages
|
||||
val pages = download.pages
|
||||
if (pages == null) {
|
||||
view.download_progress.progress = 0
|
||||
view.download_progress.max = 1
|
||||
view.download_progress_text.text = ""
|
||||
download_progress.progress = 0
|
||||
download_progress.max = 1
|
||||
download_progress_text.text = ""
|
||||
} else {
|
||||
view.download_progress.max = pages.size * 100
|
||||
download_progress.max = pages.size * 100
|
||||
notifyProgress()
|
||||
notifyDownloadedPages()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the progress bar of the download.
|
||||
*/
|
||||
fun notifyProgress() {
|
||||
val pages = download.pages ?: return
|
||||
if (view.download_progress.max == 1) {
|
||||
view.download_progress.max = pages.size * 100
|
||||
if (download_progress.max == 1) {
|
||||
download_progress.max = pages.size * 100
|
||||
}
|
||||
view.download_progress.progress = download.totalProgress
|
||||
download_progress.progress = download.totalProgress
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,7 +63,12 @@ class DownloadHolder(private val view: View) : BaseViewHolder(view) {
|
||||
*/
|
||||
fun notifyDownloadedPages() {
|
||||
val pages = download.pages ?: return
|
||||
view.download_progress_text.text = "${download.downloadedImages}/${pages.size}"
|
||||
download_progress_text.text = "${download.downloadedImages}/${pages.size}"
|
||||
}
|
||||
|
||||
override fun onItemReleased(position: Int) {
|
||||
super.onItemReleased(position)
|
||||
adapter.onItemReleaseListener.onItemReleased(position)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package eu.kanade.tachiyomi.ui.download
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
|
||||
class DownloadItem(val download: Download) : AbstractFlexibleItem<DownloadHolder>() {
|
||||
|
||||
/**
|
||||
* Whether this item is currently selected.
|
||||
*/
|
||||
var isSelected = false
|
||||
|
||||
/**
|
||||
* Returns the layout resource for this item.
|
||||
*/
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.download_item
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new view holder for this item.
|
||||
*
|
||||
* @param view The view of this item.
|
||||
* @param adapter The adapter of this item.
|
||||
*/
|
||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView
|
||||
.ViewHolder>>): DownloadHolder {
|
||||
return DownloadHolder(view, adapter as DownloadAdapter)
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the given view holder with this item.
|
||||
*
|
||||
* @param adapter The adapter of this item.
|
||||
* @param holder The holder to bind.
|
||||
* @param position The position of this item in the adapter.
|
||||
* @param payloads List of partial changes.
|
||||
*/
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
||||
holder: DownloadHolder, position: Int, payloads: MutableList<Any>) {
|
||||
holder.bind(download)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this item is draggable.
|
||||
*/
|
||||
override fun isDraggable(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is DownloadItem) {
|
||||
return download.chapter.id == other.download.chapter.id
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return download.chapter.id!!.toInt()
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,6 @@ import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Presenter of [DownloadController].
|
||||
@ -32,10 +31,10 @@ class DownloadPresenter : BasePresenter<DownloadController>() {
|
||||
|
||||
downloadQueue.getUpdatedObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map { ArrayList(it) }
|
||||
.subscribeLatestCache(DownloadController::onNextDownloads, { _, error ->
|
||||
.map { it.map(::DownloadItem) }
|
||||
.subscribeLatestCache(DownloadController::onNextDownloads) { _, error ->
|
||||
Timber.e(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun getDownloadStatusObservable(): Observable<Download> {
|
||||
@ -62,4 +61,8 @@ class DownloadPresenter : BasePresenter<DownloadController>() {
|
||||
downloadManager.clearQueue()
|
||||
}
|
||||
|
||||
fun reorder(downloads: List<Download>) {
|
||||
downloadManager.reorderQueue(downloads)
|
||||
}
|
||||
|
||||
}
|
@ -2,9 +2,9 @@
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/material_layout_keylines_screen_edge_margin"
|
||||
android:paddingRight="@dimen/material_layout_keylines_screen_edge_margin"
|
||||
android:paddingTop="@dimen/material_component_lists_padding_above_list">
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
android:layout_alignParentLeft="true"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
|
||||
android:textAppearance="@style/TextAppearance.Regular.Body1"
|
||||
tools:text="Manga title"/>
|
||||
|
||||
@ -36,6 +37,7 @@
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="Chapter Title"
|
||||
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
|
||||
android:textAppearance="@style/TextAppearance.Regular.Caption"/>
|
||||
|
||||
<ProgressBar
|
||||
@ -43,6 +45,16 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/chapter_title"
|
||||
android:layout_marginStart="@dimen/material_component_lists_single_line_with_avatar_height"
|
||||
style="?android:attr/progressBarStyleHorizontal"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reorder"
|
||||
android:layout_width="@dimen/material_component_lists_single_line_with_avatar_height"
|
||||
android:layout_height="@dimen/material_component_lists_single_line_with_avatar_height"
|
||||
android:layout_gravity="start"
|
||||
android:scaleType="center"
|
||||
android:tint="?android:attr/textColorPrimary"
|
||||
app:srcCompat="@drawable/ic_reorder_grey_24dp" />
|
||||
|
||||
</RelativeLayout>
|
Loading…
Reference in New Issue
Block a user