Add manga grouping in library!! This was inspired by J2ks version of the feature
This commit is contained in:
parent
0e43234c23
commit
e945de74f2
@ -282,4 +282,6 @@ object PreferenceKeys {
|
||||
const val webtoonEnableZoomOut = "webtoon_enable_zoom_out"
|
||||
|
||||
const val startReadingButton = "start_reading_button"
|
||||
|
||||
const val groupLibraryBy = "group_library_by"
|
||||
}
|
||||
|
@ -386,4 +386,6 @@ class PreferencesHelper(val context: Context) {
|
||||
fun webtoonEnableZoomOut() = flowPrefs.getBoolean(Keys.webtoonEnableZoomOut, false)
|
||||
|
||||
fun startReadingButton() = flowPrefs.getBoolean(Keys.startReadingButton, true)
|
||||
|
||||
fun groupLibraryBy() = flowPrefs.getInt(Keys.groupLibraryBy, 0)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
|
||||
@ -44,6 +45,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
|
||||
private var lastFilterJob: Job? = null
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val trackManager: TrackManager by injectLazy()
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
private val hasLoggedServices by lazy {
|
||||
trackManager.hasLoggedServices()
|
||||
}
|
||||
@ -86,7 +88,7 @@ class LibraryCategoryAdapter(view: LibraryCategoryView, val controller: LibraryC
|
||||
return currentItems.indexOfFirst { it.manga.id == manga.id }
|
||||
}
|
||||
|
||||
fun canDrag() = (mode != Mode.MULTI || (mode == Mode.MULTI && selectedItemCount == 1)) && searchText.isBlank()
|
||||
fun canDrag() = (mode != Mode.MULTI || (mode == Mode.MULTI && selectedItemCount == 1)) && searchText.isBlank() && preferences.groupLibraryBy().get() == LibraryGroup.BY_DEFAULT
|
||||
|
||||
// EXH -->
|
||||
// Note that we cannot use FlexibleAdapter's built in filtering system as we cannot cancel it
|
||||
|
@ -213,7 +213,13 @@ class LibraryController(
|
||||
is LibrarySettingsSheet.Sort.SortGroup -> onSortChanged()
|
||||
is LibrarySettingsSheet.Display.DisplayGroup -> reattachAdapter()
|
||||
is LibrarySettingsSheet.Display.BadgeGroup -> onBadgeSettingChanged()
|
||||
// SY -->
|
||||
is LibrarySettingsSheet.Display.ButtonsGroup -> onButtonSettingChanged()
|
||||
// SY <--
|
||||
is LibrarySettingsSheet.Display.TabsGroup -> onTabsSettingsChanged()
|
||||
// SY -->
|
||||
is LibrarySettingsSheet.Grouping.InternalGroup -> onGroupSettingChanged()
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,6 +342,16 @@ class LibraryController(
|
||||
presenter.requestBadgesUpdate()
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun onButtonSettingChanged() {
|
||||
presenter.requestButtonsUpdate()
|
||||
}
|
||||
|
||||
private fun onGroupSettingChanged() {
|
||||
presenter.requestGroupsUpdate()
|
||||
}
|
||||
// SY <--
|
||||
|
||||
private fun onTabsSettingsChanged() {
|
||||
tabsVisibilityRelay.call(preferences.categoryTabs().get() && adapter?.categories?.size ?: 0 > 1)
|
||||
updateTitle()
|
||||
|
@ -0,0 +1,32 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
object LibraryGroup {
|
||||
|
||||
const val BY_DEFAULT = 0
|
||||
const val BY_SOURCE = 1
|
||||
const val BY_STATUS = 2
|
||||
const val BY_TRACK_STATUS = 3
|
||||
const val UNGROUPED = 4
|
||||
|
||||
fun groupTypeStringRes(type: Int, hasCategories: Boolean = true): Int {
|
||||
return when (type) {
|
||||
BY_STATUS -> R.string.status
|
||||
BY_SOURCE -> R.string.label_sources
|
||||
BY_TRACK_STATUS -> R.string.tracking_status
|
||||
UNGROUPED -> R.string.ungrouped
|
||||
else -> if (hasCategories) R.string.categories else R.string.ungrouped
|
||||
}
|
||||
}
|
||||
|
||||
fun groupTypeDrawableRes(type: Int): Int {
|
||||
return when (type) {
|
||||
BY_STATUS -> R.drawable.ic_progress_clock_24dp
|
||||
BY_TRACK_STATUS -> R.drawable.ic_sync_24dp
|
||||
BY_SOURCE -> R.drawable.ic_explore_24dp
|
||||
UNGROUPED -> R.drawable.ic_ungroup_24dp
|
||||
else -> R.drawable.ic_label_24dp
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
@ -11,6 +12,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.Filter.TriState.Companion.STATE_EXCLUDE
|
||||
import eu.kanade.tachiyomi.source.model.Filter.TriState.Companion.STATE_IGNORE
|
||||
@ -89,9 +91,26 @@ class LibraryPresenter(
|
||||
*/
|
||||
private var librarySubscription: Subscription? = null
|
||||
|
||||
// --> EXH
|
||||
// SY -->
|
||||
val favoritesSync = FavoritesSyncHelper(context)
|
||||
// <-- EXH
|
||||
|
||||
private var groupType = preferences.groupLibraryBy().get()
|
||||
|
||||
private val libraryIsGrouped
|
||||
get() = groupType != LibraryGroup.UNGROUPED
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||
|
||||
/**
|
||||
* Relay used to apply the UI update to the last emission of the library.
|
||||
*/
|
||||
private val buttonTriggerRelay = BehaviorRelay.create(Unit)
|
||||
|
||||
/**
|
||||
* Relay used to apply the UI update to the last emission of the library.
|
||||
*/
|
||||
private val groupingTriggerRelay = BehaviorRelay.create(Unit)
|
||||
// SY <--
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
@ -107,6 +126,15 @@ class LibraryPresenter(
|
||||
.combineLatest(badgeTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
||||
lib.apply { setBadges(mangaMap) }
|
||||
}
|
||||
// SY -->
|
||||
.combineLatest(buttonTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
||||
lib.apply { setButtons(mangaMap) }
|
||||
}
|
||||
.combineLatest(groupingTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
||||
val (map, categories) = applyGrouping(lib.mangaMap, lib.categories)
|
||||
lib.copy(mangaMap = map, categories = categories)
|
||||
}
|
||||
// SY <--
|
||||
.combineLatest(filterTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
||||
lib.copy(mangaMap = applyFilters(lib.mangaMap))
|
||||
}
|
||||
@ -172,6 +200,21 @@ class LibraryPresenter(
|
||||
|
||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the button on each manga.
|
||||
*
|
||||
* @param map the map of manga.
|
||||
*/
|
||||
private fun setButtons(map: LibraryMap) {
|
||||
val startReadingButton = preferences.startReadingButton().get()
|
||||
|
||||
for ((_, itemList) in map) {
|
||||
for (item in itemList) {
|
||||
item.startReadingButton = startReadingButton
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
@ -182,7 +225,6 @@ class LibraryPresenter(
|
||||
private fun setBadges(map: LibraryMap) {
|
||||
val showDownloadBadges = preferences.downloadBadge().get()
|
||||
val showUnreadBadges = preferences.unreadBadge().get()
|
||||
val startReadingButton = preferences.startReadingButton().get()
|
||||
|
||||
for ((_, itemList) in map) {
|
||||
for (item in itemList) {
|
||||
@ -199,10 +241,6 @@ class LibraryPresenter(
|
||||
// Unset unread count if not enabled
|
||||
-1
|
||||
}
|
||||
|
||||
// SY -->
|
||||
item.startReadingButton = startReadingButton
|
||||
// SY <--
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -294,6 +332,27 @@ class LibraryPresenter(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
private fun applyGrouping(map: LibraryMap, categories: List<Category>): Pair<LibraryMap, List<Category>> {
|
||||
groupType = preferences.groupLibraryBy().get()
|
||||
var editedCategories: List<Category> = categories
|
||||
val libraryMangaAsList = map.flatMap { it.value }.distinctBy { it.manga.id }
|
||||
val items = if (groupType == LibraryGroup.BY_DEFAULT) {
|
||||
map
|
||||
} else if (!libraryIsGrouped) {
|
||||
editedCategories = listOf(Category.create("All").apply { this.id = 0 })
|
||||
libraryMangaAsList
|
||||
.groupBy { 0 }
|
||||
} else {
|
||||
val (items, customCategories) = getGroupedMangaItems(libraryMangaAsList)
|
||||
editedCategories = customCategories
|
||||
items
|
||||
}
|
||||
|
||||
return items to editedCategories
|
||||
}
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Get the categories from the database.
|
||||
*
|
||||
@ -331,6 +390,23 @@ class LibraryPresenter(
|
||||
badgeTriggerRelay.call(Unit)
|
||||
}
|
||||
|
||||
// SY -->
|
||||
/**
|
||||
* Requests the library to have buttons toggled.
|
||||
*/
|
||||
fun requestButtonsUpdate() {
|
||||
buttonTriggerRelay.call(Unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the library to have groups refreshed.
|
||||
*/
|
||||
fun requestGroupsUpdate() {
|
||||
groupingTriggerRelay.call(Unit)
|
||||
}
|
||||
|
||||
// SY <--
|
||||
|
||||
/**
|
||||
* Requests the library to be sorted.
|
||||
*/
|
||||
@ -491,5 +567,109 @@ class LibraryPresenter(
|
||||
chapters.sortedByDescending { it.source_order }.find { !it.read }
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGroupedMangaItems(libraryManga: List<LibraryItem>): Pair<LibraryMap, List<Category>> {
|
||||
val grouping: MutableList<Triple<String, Int, String>> = mutableListOf()
|
||||
when (groupType) {
|
||||
LibraryGroup.BY_STATUS -> libraryManga.distinctBy { it.manga.status }.map { it.manga.status }.forEachIndexed { index, status ->
|
||||
grouping += Triple(status.toString(), index, mapStatus(status))
|
||||
}
|
||||
LibraryGroup.BY_SOURCE -> libraryManga.distinctBy { it.manga.source }.map { it.manga.source }.forEachIndexed { index, sourceLong ->
|
||||
grouping += Triple(sourceLong.toString(), index, sourceManager.getOrStub(sourceLong).name)
|
||||
}
|
||||
LibraryGroup.BY_TRACK_STATUS -> {
|
||||
grouping += Triple("1", 1, context.getString(R.string.reading))
|
||||
grouping += Triple("2", 2, context.getString(R.string.repeating))
|
||||
grouping += Triple("3", 3, context.getString(R.string.plan_to_read))
|
||||
grouping += Triple("4", 4, context.getString(R.string.on_hold))
|
||||
grouping += Triple("5", 5, context.getString(R.string.completed))
|
||||
grouping += Triple("6", 6, context.getString(R.string.dropped))
|
||||
grouping += Triple("7", 7, context.getString(R.string.not_tracked))
|
||||
}
|
||||
}
|
||||
val map: MutableMap<Int, MutableList<LibraryItem>> = mutableMapOf()
|
||||
|
||||
libraryManga.forEach { libraryItem ->
|
||||
when (groupType) {
|
||||
LibraryGroup.BY_TRACK_STATUS -> {
|
||||
val status: String = {
|
||||
val tracks = db.getTracks(libraryItem.manga).executeAsBlocking()
|
||||
val track = tracks.find { track ->
|
||||
loggedServices.any { it.id == track?.sync_id }
|
||||
}
|
||||
val service = loggedServices.find { it.id == track?.sync_id }
|
||||
if (track != null && service != null) {
|
||||
service.getStatus(track.status)
|
||||
} else {
|
||||
"not tracked"
|
||||
}
|
||||
}()
|
||||
val group = grouping.find { it.first == mapTrackingOrder(status) }
|
||||
if (group != null) {
|
||||
map[group.second]?.plusAssign(libraryItem) ?: map.put(group.second, mutableListOf(libraryItem))
|
||||
} else {
|
||||
map[7]?.plusAssign(libraryItem) ?: map.put(7, mutableListOf(libraryItem))
|
||||
}
|
||||
}
|
||||
LibraryGroup.BY_SOURCE -> {
|
||||
val group = grouping.find { it.first.toLongOrNull() == libraryItem.manga.source }
|
||||
if (group != null) {
|
||||
map[group.second]?.plusAssign(libraryItem) ?: map.put(group.second, mutableListOf(libraryItem))
|
||||
} else {
|
||||
if (grouping.all { it.second != Int.MAX_VALUE }) grouping += Triple(Int.MAX_VALUE.toString(), Int.MAX_VALUE, context.getString(R.string.unknown))
|
||||
map[Int.MAX_VALUE]?.plusAssign(libraryItem) ?: map.put(Int.MAX_VALUE, mutableListOf(libraryItem))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val group = grouping.find { it.first == libraryItem.manga.status.toString() }
|
||||
if (group != null) {
|
||||
map[group.second]?.plusAssign(libraryItem) ?: map.put(group.second, mutableListOf(libraryItem))
|
||||
} else {
|
||||
if (grouping.all { it.second != Int.MAX_VALUE }) grouping += Triple(Int.MAX_VALUE.toString(), Int.MAX_VALUE, context.getString(R.string.unknown))
|
||||
map[Int.MAX_VALUE]?.plusAssign(libraryItem) ?: map.put(Int.MAX_VALUE, mutableListOf(libraryItem))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val categories = (
|
||||
when (groupType) {
|
||||
LibraryGroup.BY_SOURCE -> grouping.sortedBy { it.third.toLowerCase() }
|
||||
LibraryGroup.BY_TRACK_STATUS -> grouping.filter { it.second in map.keys }
|
||||
else -> grouping
|
||||
}
|
||||
).map {
|
||||
val category = Category.create(it.third)
|
||||
category.id = it.second
|
||||
category
|
||||
}
|
||||
|
||||
return map to categories
|
||||
}
|
||||
|
||||
private fun mapTrackingOrder(status: String): String {
|
||||
with(context) {
|
||||
return when (status) {
|
||||
getString(R.string.reading), getString(R.string.currently_reading) -> "1"
|
||||
getString(R.string.repeating) -> "2"
|
||||
getString(R.string.plan_to_read), getString(R.string.want_to_read) -> "3"
|
||||
getString(R.string.on_hold), getString(R.string.paused) -> "4"
|
||||
getString(R.string.completed) -> "5"
|
||||
getString(R.string.dropped) -> "6"
|
||||
else -> "7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun mapStatus(status: Int): String {
|
||||
return context.getString(
|
||||
when (status) {
|
||||
SManga.LICENSED -> R.string.licensed
|
||||
SManga.ONGOING -> R.string.ongoing
|
||||
SManga.COMPLETED -> R.string.completed
|
||||
else -> R.string.unknown
|
||||
}
|
||||
)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
@ -25,6 +26,7 @@ class LibrarySettingsSheet(
|
||||
val filters: Filter
|
||||
private val sort: Sort
|
||||
private val display: Display
|
||||
private val grouping: Grouping
|
||||
|
||||
init {
|
||||
filters = Filter(activity)
|
||||
@ -35,6 +37,9 @@ class LibrarySettingsSheet(
|
||||
|
||||
display = Display(activity)
|
||||
display.onGroupClicked = onGroupClickListener
|
||||
|
||||
grouping = Grouping(activity)
|
||||
grouping.onGroupClicked = onGroupClickListener
|
||||
}
|
||||
|
||||
fun refreshSort() {
|
||||
@ -44,13 +49,15 @@ class LibrarySettingsSheet(
|
||||
override fun getTabViews(): List<View> = listOf(
|
||||
filters,
|
||||
sort,
|
||||
display
|
||||
display,
|
||||
grouping
|
||||
)
|
||||
|
||||
override fun getTabTitles(): List<Int> = listOf(
|
||||
R.string.action_filter,
|
||||
R.string.action_sort,
|
||||
R.string.action_display
|
||||
R.string.action_display,
|
||||
R.string.group
|
||||
)
|
||||
|
||||
/**
|
||||
@ -198,6 +205,9 @@ class LibrarySettingsSheet(
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
item as Item.MultiStateGroup
|
||||
// SY -->
|
||||
if (item == dragAndDrop && preferences.groupLibraryBy().get() != LibraryGroup.BY_DEFAULT) return
|
||||
// SY <--
|
||||
val prevState = item.state
|
||||
|
||||
item.group.items.forEach {
|
||||
@ -355,6 +365,80 @@ class LibrarySettingsSheet(
|
||||
}
|
||||
}
|
||||
|
||||
// SY -->
|
||||
inner class Grouping @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||
Settings(context, attrs) {
|
||||
|
||||
init {
|
||||
setGroups(listOf(InternalGroup()))
|
||||
}
|
||||
|
||||
inner class InternalGroup : Group {
|
||||
private val groupItems = mutableListOf<Item.DrawableSelection>()
|
||||
private val db: DatabaseHelper = Injekt.get()
|
||||
private val trackManager: TrackManager = Injekt.get()
|
||||
private val hasCategories = db.getCategories().executeAsBlocking().size != 0
|
||||
|
||||
init {
|
||||
val groupingItems = mutableListOf(
|
||||
LibraryGroup.BY_DEFAULT,
|
||||
LibraryGroup.BY_SOURCE,
|
||||
LibraryGroup.BY_STATUS
|
||||
)
|
||||
if (trackManager.hasLoggedServices()) {
|
||||
groupingItems.add(LibraryGroup.BY_TRACK_STATUS)
|
||||
}
|
||||
if (hasCategories) {
|
||||
groupingItems.add(LibraryGroup.UNGROUPED)
|
||||
}
|
||||
groupItems += groupingItems.map { id ->
|
||||
Item.DrawableSelection(
|
||||
id,
|
||||
this,
|
||||
LibraryGroup.groupTypeStringRes(id, hasCategories),
|
||||
LibraryGroup.groupTypeDrawableRes(id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override val header = null
|
||||
override val items = groupItems
|
||||
override val footer = null
|
||||
|
||||
override fun initModels() {
|
||||
val groupType = preferences.groupLibraryBy().get()
|
||||
|
||||
items.forEach {
|
||||
it.state = if (it.id == groupType) {
|
||||
Item.DrawableSelection.SELECTED
|
||||
} else {
|
||||
Item.DrawableSelection.NOT_SELECTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClicked(item: Item) {
|
||||
item as Item.DrawableSelection
|
||||
if (item.id != LibraryGroup.BY_DEFAULT && preferences.librarySortingMode().get() == LibrarySort.DRAG_AND_DROP) {
|
||||
preferences.librarySortingMode().set(LibrarySort.ALPHA)
|
||||
preferences.librarySortingAscending().set(true)
|
||||
refreshSort()
|
||||
}
|
||||
|
||||
item.group.items.forEach {
|
||||
(it as Item.DrawableSelection).state =
|
||||
Item.DrawableSelection.NOT_SELECTED
|
||||
}
|
||||
item.state = Item.DrawableSelection.SELECTED
|
||||
|
||||
preferences.groupLibraryBy().set(item.id)
|
||||
|
||||
item.group.items.forEach { adapter.notifyItemChanged(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
||||
open inner class Settings(context: Context, attrs: AttributeSet?) :
|
||||
ExtendedNavigationView(context, attrs) {
|
||||
|
||||
|
@ -109,6 +109,22 @@ open class ExtendedNavigationView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
// SY -->
|
||||
class DrawableSelection(val id: Int, group: Group, stringResId: Int, val drawable: Int) : MultiStateGroup(stringResId, group) {
|
||||
|
||||
companion object {
|
||||
const val NOT_SELECTED = 0
|
||||
const val SELECTED = 1
|
||||
}
|
||||
|
||||
override fun getStateDrawable(context: Context): Drawable? {
|
||||
return when (state) {
|
||||
SELECTED -> tintVector(context, drawable, R.attr.colorAccent)
|
||||
NOT_SELECTED -> tintVector(context, drawable, R.attr.colorOnSurface)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TriStateGroup(resId: Int, group: Group) : MultiStateGroup(resId, group) {
|
||||
|
||||
companion object {
|
||||
|
10
app/src/main/res/drawable/ic_progress_clock_24dp.xml
Normal file
10
app/src/main/res/drawable/ic_progress_clock_24dp.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<!-- drawable/progress_clock.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M13,2.03V2.05L13,4.05C17.39,4.59 20.5,8.58 19.96,12.97C19.5,16.61 16.64,19.5 13,19.93V21.93C18.5,21.38 22.5,16.5 21.95,11C21.5,6.25 17.73,2.5 13,2.03M11,2.06C9.05,2.25 7.19,3 5.67,4.26L7.1,5.74C8.22,4.84 9.57,4.26 11,4.06V2.06M4.26,5.67C3,7.19 2.25,9.04 2.05,11H4.05C4.24,9.58 4.8,8.23 5.69,7.1L4.26,5.67M2.06,13C2.26,14.96 3.03,16.81 4.27,18.33L5.69,16.9C4.81,15.77 4.24,14.42 4.06,13H2.06M7.1,18.37L5.67,19.74C7.18,21 9.04,21.79 11,22V20C9.58,19.82 8.23,19.25 7.1,18.37M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z" />
|
||||
</vector>
|
8
app/src/main/res/drawable/ic_ungroup_24dp.xml
Normal file
8
app/src/main/res/drawable/ic_ungroup_24dp.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- drawable/ungroup.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M2,2H6V3H13V2H17V6H16V9H18V8H22V12H21V18H22V22H18V21H12V22H8V18H9V16H6V17H2V13H3V6H2V2M18,12V11H16V13H17V17H13V16H11V18H12V19H18V18H19V12H18M13,6V5H6V6H5V13H6V14H9V12H8V8H12V9H14V6H13M12,12H11V14H13V13H14V11H12V12Z" />
|
||||
</vector>
|
@ -286,6 +286,11 @@
|
||||
<string name="tracked">Tracked</string>
|
||||
<string name="lewd">Lewd</string>
|
||||
|
||||
<!-- Library Grouping -->
|
||||
<string name="tracking_status">Tracking status</string>
|
||||
<string name="ungrouped">Ungrouped</string>
|
||||
<string name="not_tracked">Not tracked</string>
|
||||
|
||||
<!-- Favorites Sync -->
|
||||
<string name="sync_favorites">Sync favorites</string>
|
||||
<string name="favorites_sync_error">Favorites sync error</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user