Implemented Source Selector
This commit is contained in:
@@ -42,6 +42,7 @@ import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.pupil.sources.initSources
|
||||
import xyz.quaver.pupil.types.Tag
|
||||
import xyz.quaver.pupil.util.*
|
||||
import xyz.quaver.setClient
|
||||
@@ -89,6 +90,8 @@ class Pupil : Application() {
|
||||
firebaseAnalytics = Firebase.analytics
|
||||
FirebaseCrashlytics.getInstance().setUserId(userID)
|
||||
|
||||
initSources(this)
|
||||
|
||||
val proxyInfo = getProxyInfo()
|
||||
|
||||
clientBuilder = OkHttpClient.Builder()
|
||||
|
||||
59
app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt
Normal file
59
app/src/main/java/xyz/quaver/pupil/adapters/SourceAdapter.kt
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* 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 xyz.quaver.pupil.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.graphics.drawable.DrawableCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding
|
||||
import xyz.quaver.pupil.sources.Source
|
||||
import xyz.quaver.pupil.sources.sourceIcons
|
||||
|
||||
class SourceAdapter(private val sources: List<Source<*>>) : RecyclerView.Adapter<SourceAdapter.ViewHolder>() {
|
||||
|
||||
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
|
||||
|
||||
inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
lateinit var source: Source<*>
|
||||
|
||||
init {
|
||||
binding.go.setOnClickListener {
|
||||
onSourceSelectedListener?.invoke(source)
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(source: Source<*>) {
|
||||
this.source = source
|
||||
|
||||
binding.icon.setImageDrawable(sourceIcons[source.name])
|
||||
binding.name.text = source.name
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(SourceSelectDialogItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.bind(sources[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = sources.size
|
||||
}
|
||||
@@ -18,9 +18,13 @@
|
||||
|
||||
package xyz.quaver.pupil.sources
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import xyz.quaver.pupil.R
|
||||
import kotlin.reflect.KClass
|
||||
import xyz.quaver.pupil.sources.hitomi.Hitomi
|
||||
import xyz.quaver.pupil.sources.hitomi.Hiyobi
|
||||
|
||||
data class SearchResult(
|
||||
val id: String,
|
||||
@@ -49,8 +53,28 @@ data class SearchResult(
|
||||
}
|
||||
}
|
||||
|
||||
interface Source<Query_SortMode: Enum<*>> {
|
||||
val querySortModeClass: KClass<Query_SortMode>?
|
||||
enum class DefaultSortMode {
|
||||
DEFAULT
|
||||
}
|
||||
interface Source<Query_SortMode : Enum<Query_SortMode>> {
|
||||
val name: String
|
||||
val iconResID: Int
|
||||
val availableSortMode: Array<Query_SortMode>
|
||||
|
||||
suspend fun query(query: String, range: IntRange, sortMode: Query_SortMode? = null) : Pair<Channel<SearchResult>, Int>
|
||||
suspend fun query(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
|
||||
}
|
||||
|
||||
val sources = mutableMapOf<String, Source<*>>()
|
||||
val sourceIcons = mutableMapOf<String, Drawable?>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun initSources(context: Context) {
|
||||
// Add Default Sources
|
||||
listOf(
|
||||
Hitomi(),
|
||||
Hiyobi()
|
||||
).forEach {
|
||||
sources[it.name] = it
|
||||
sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID)
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ package xyz.quaver.pupil.sources.hitomi
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import xyz.quaver.hitomi.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.sources.SearchResult
|
||||
import xyz.quaver.pupil.sources.SearchResult.ExtraType
|
||||
import xyz.quaver.pupil.sources.Source
|
||||
@@ -30,18 +31,20 @@ import kotlin.math.min
|
||||
|
||||
class Hitomi : Source<Hitomi.SortMode> {
|
||||
|
||||
override val querySortModeClass = SortMode::class
|
||||
|
||||
enum class SortMode {
|
||||
NEWEST,
|
||||
POPULAR
|
||||
}
|
||||
|
||||
override val name: String = "hitomi.la"
|
||||
override val iconResID: Int = R.drawable.hitomi
|
||||
override val availableSortMode: Array<SortMode> = SortMode.values()
|
||||
|
||||
var cachedQuery: String? = null
|
||||
var cachedSortMode: SortMode? = null
|
||||
val cache = mutableListOf<Int>()
|
||||
|
||||
override suspend fun query(query: String, range: IntRange, sortMode: SortMode?): Pair<Channel<SearchResult>, Int> {
|
||||
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
|
||||
cachedQuery = null
|
||||
cache.clear()
|
||||
|
||||
@@ -23,14 +23,19 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import xyz.quaver.hiyobi.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.sources.DefaultSortMode
|
||||
import xyz.quaver.pupil.sources.SearchResult
|
||||
import xyz.quaver.pupil.sources.Source
|
||||
import xyz.quaver.pupil.util.wordCapitalize
|
||||
|
||||
class Hiyobi : Source<Enum<*>> {
|
||||
override val querySortModeClass = null
|
||||
class Hiyobi : Source<DefaultSortMode> {
|
||||
|
||||
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>?): Pair<Channel<SearchResult>, Int> {
|
||||
override val name: String = "hiyobi.me"
|
||||
override val iconResID: Int = R.drawable.ic_hiyobi
|
||||
override val availableSortMode: Array<DefaultSortMode> = DefaultSortMode.values()
|
||||
|
||||
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||
val channel = Channel<SearchResult>()
|
||||
|
||||
val (results, total) = if (query.isEmpty())
|
||||
@@ -59,7 +64,7 @@ class Hiyobi : Source<Enum<*>> {
|
||||
mapOf(
|
||||
SearchResult.ExtraType.CHARACTER to { galleryBlock.characters.joinToString { it.value.wordCapitalize() } },
|
||||
SearchResult.ExtraType.SERIES to { galleryBlock.parodys.joinToString { it.value.wordCapitalize() } },
|
||||
SearchResult.ExtraType.TYPE to { galleryBlock.type.name.wordCapitalize() },
|
||||
SearchResult.ExtraType.TYPE to { galleryBlock.type.name.replace('_', ' ').wordCapitalize() },
|
||||
SearchResult.ExtraType.PAGECOUNT to { getGalleryInfo(galleryBlock.id).files.size.toString() }
|
||||
),
|
||||
galleryBlock.tags.map { it.value }
|
||||
|
||||
@@ -25,23 +25,27 @@ import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.text.util.Linkify
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.children
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import xyz.quaver.floatingsearchview.FloatingSearchView
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.floatingsearchview.util.view.MenuView
|
||||
import xyz.quaver.floatingsearchview.util.view.SearchInputView
|
||||
import xyz.quaver.hitomi.getSuggestionsForQuery
|
||||
import xyz.quaver.pupil.*
|
||||
@@ -50,18 +54,16 @@ import xyz.quaver.pupil.databinding.MainActivityBinding
|
||||
import xyz.quaver.pupil.services.DownloadService
|
||||
import xyz.quaver.pupil.sources.SearchResult
|
||||
import xyz.quaver.pupil.sources.Source
|
||||
import xyz.quaver.pupil.sources.hitomi.Hitomi
|
||||
import xyz.quaver.pupil.sources.hitomi.Hiyobi
|
||||
import xyz.quaver.pupil.sources.sourceIcons
|
||||
import xyz.quaver.pupil.sources.sources
|
||||
import xyz.quaver.pupil.types.*
|
||||
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
|
||||
import xyz.quaver.pupil.ui.dialog.GalleryDialog
|
||||
import xyz.quaver.pupil.ui.dialog.SourceSelectDialog
|
||||
import xyz.quaver.pupil.ui.view.ProgressCardView
|
||||
import xyz.quaver.pupil.ui.view.SwipePageTurnView
|
||||
import xyz.quaver.pupil.util.ItemClickSupport
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.checkUpdate
|
||||
import xyz.quaver.pupil.util.*
|
||||
import xyz.quaver.pupil.util.downloader.DownloadManager
|
||||
import xyz.quaver.pupil.util.restore
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.math.*
|
||||
import kotlin.random.Random
|
||||
@@ -82,9 +84,8 @@ class MainActivity :
|
||||
}
|
||||
private var queryStack = mutableListOf<String>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private var source: Source<Enum<*>> = Hiyobi() as Source<Enum<*>>
|
||||
private var sortMode = Hitomi.SortMode.NEWEST
|
||||
private lateinit var source: Source<*>
|
||||
private lateinit var sortMode: Enum<*>
|
||||
|
||||
private var searchJob: Deferred<Pair<Channel<SearchResult>, Int>>? = null
|
||||
private var totalItems = 0
|
||||
@@ -97,6 +98,8 @@ class MainActivity :
|
||||
binding = MainActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
setSource(sources.values.first())
|
||||
|
||||
if (intent.action == Intent.ACTION_VIEW) {
|
||||
intent.dataString?.let { url ->
|
||||
restore(url,
|
||||
@@ -167,6 +170,34 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
private fun setSource(source: Source<*>) {
|
||||
this.source = source
|
||||
sortMode = source.availableSortMode.first()
|
||||
|
||||
query = ""
|
||||
currentPage = 1
|
||||
|
||||
with (binding.contents.searchview.binding.querySection.menuView) {
|
||||
post {
|
||||
menuItems.findMenu(R.id.sort).subMenu.apply {
|
||||
clear()
|
||||
|
||||
source.availableSortMode.forEach {
|
||||
add(R.id.sort_mode_group_id, it.ordinal, Menu.NONE, it.name)
|
||||
}
|
||||
|
||||
setGroupCheckable(R.id.sort_mode_group_id, true, true)
|
||||
|
||||
children.first().isChecked = true
|
||||
}
|
||||
with (getChildAt(1) as ImageView) {
|
||||
ImageViewCompat.setImageTintList(this, null)
|
||||
setImageDrawable(sourceIcons[source.name])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initView() {
|
||||
binding.contents.recyclerview.addOnScrollListener(object: RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
@@ -175,7 +206,7 @@ class MainActivity :
|
||||
min(
|
||||
max(
|
||||
binding.contents.searchview.translationY - dy,
|
||||
-binding.contents.searchview.findViewById<CardView>(R.id.search_query_section).height.toFloat()
|
||||
-binding.contents.searchview.binding.querySection.root.height.toFloat()
|
||||
), 0F)
|
||||
|
||||
if (dy > 0)
|
||||
@@ -224,6 +255,7 @@ class MainActivity :
|
||||
with(binding.contents.randomFab) {
|
||||
setImageResource(R.drawable.shuffle_variant)
|
||||
setOnClickListener {
|
||||
setImageDrawable(CircularProgressDrawable(context))
|
||||
if (totalItems > 0)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val random = Random.Default.nextInt(totalItems)
|
||||
@@ -236,6 +268,7 @@ class MainActivity :
|
||||
).first.receive()
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
setImageResource(R.drawable.shuffle_variant)
|
||||
GalleryDialog(this@MainActivity, randomResult.id).apply {
|
||||
onChipClickedHandler.add {
|
||||
query = it.toQuery()
|
||||
@@ -394,7 +427,7 @@ class MainActivity :
|
||||
with(binding.contents.searchview) {
|
||||
onMenuStatusChangeListener = object: FloatingSearchView.OnMenuStatusChangeListener {
|
||||
override fun onMenuOpened() {
|
||||
(binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems()
|
||||
(this@MainActivity.binding.contents.recyclerview.adapter as SearchResultsAdapter).closeAllItems()
|
||||
}
|
||||
|
||||
override fun onMenuClosed() {
|
||||
@@ -402,14 +435,6 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
findViewById<MenuView>(R.id.menu_view).menuItems.firstOrNull {
|
||||
(it as MenuItem).itemId == R.id.main_menu_thin
|
||||
}?.let {
|
||||
(it as MenuItem).isChecked = Preferences["thin"]
|
||||
}
|
||||
}
|
||||
|
||||
onHistoryDeleteClickedListener = {
|
||||
searchHistory.remove(it)
|
||||
swapSuggestions(defaultSuggestions)
|
||||
@@ -473,37 +498,32 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
|
||||
attachNavigationDrawerToMenuButton(binding.drawer)
|
||||
attachNavigationDrawerToMenuButton(this@MainActivity.binding.drawer)
|
||||
}
|
||||
}
|
||||
|
||||
fun onActionMenuItemSelected(item: MenuItem?) {
|
||||
when(item?.itemId) {
|
||||
R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
|
||||
R.id.main_menu_thin -> {
|
||||
// TODO
|
||||
private fun onActionMenuItemSelected(item: MenuItem?) {
|
||||
if (item?.groupId == R.id.sort_mode_group_id) {
|
||||
currentPage = 1
|
||||
sortMode = source.availableSortMode.let { availableSortMode ->
|
||||
availableSortMode.getOrElse(item.itemId) { availableSortMode.first() }
|
||||
}
|
||||
R.id.main_menu_sort_newest -> {
|
||||
sortMode = Hitomi.SortMode.NEWEST
|
||||
item.isChecked = true
|
||||
|
||||
runOnUiThread {
|
||||
currentPage = 1
|
||||
|
||||
query()
|
||||
}
|
||||
}
|
||||
R.id.main_menu_sort_popular -> {
|
||||
sortMode = Hitomi.SortMode.POPULAR
|
||||
item.isChecked = true
|
||||
|
||||
runOnUiThread {
|
||||
currentPage = 1
|
||||
|
||||
query()
|
||||
}
|
||||
}
|
||||
query()
|
||||
}
|
||||
else
|
||||
when(item?.itemId) {
|
||||
R.id.main_menu_settings -> startActivity(Intent(this@MainActivity, SettingsActivity::class.java))
|
||||
R.id.source -> SourceSelectDialog().apply {
|
||||
onSourceSelectedListener = {
|
||||
setSource(it)
|
||||
|
||||
query()
|
||||
|
||||
dismiss()
|
||||
}
|
||||
}.show(supportFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
@@ -539,6 +559,7 @@ class MainActivity :
|
||||
private fun clearGalleries() = CoroutineScope(Dispatchers.Main).launch {
|
||||
searchResults.clear()
|
||||
|
||||
(binding.contents.recyclerview.adapter as RecyclerSwipeAdapter).mItemManger.closeAllItems()
|
||||
binding.contents.recyclerview.adapter?.notifyDataSetChanged()
|
||||
|
||||
binding.contents.noresult.visibility = View.INVISIBLE
|
||||
|
||||
@@ -64,12 +64,7 @@ class GalleryDialog(context: Context, private val galleryID: String) : AlertDial
|
||||
binding = GalleryDialogBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
window?.attributes.apply {
|
||||
this ?: return@apply
|
||||
|
||||
width = LayoutParams.MATCH_PARENT
|
||||
height = LayoutParams.MATCH_PARENT
|
||||
}
|
||||
window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
||||
|
||||
with(binding.fab) {
|
||||
setImageDrawable(ContextCompat.getDrawable(context, R.drawable.arrow_right))
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* 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 xyz.quaver.pupil.ui.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import android.view.Window
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import xyz.quaver.pupil.adapters.SourceAdapter
|
||||
import xyz.quaver.pupil.sources.Source
|
||||
import xyz.quaver.pupil.sources.sources
|
||||
|
||||
class SourceSelectDialog : DialogFragment() {
|
||||
|
||||
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return Dialog(requireContext()).apply {
|
||||
window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||
window?.setLayout(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
|
||||
|
||||
setContentView(RecyclerView(context).apply {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
adapter = SourceAdapter(sources.values.toList()).apply {
|
||||
onSourceSelectedListener = this@SourceSelectDialog.onSourceSelectedListener
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -407,6 +407,16 @@ public class SwipePageTurnView extends ViewGroup implements NestedScrollingChild
|
||||
stopNestedScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
|
||||
return dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
||||
return dispatchNestedFling(velocityX, velocityY, consumed);
|
||||
}
|
||||
|
||||
// NestedScrollingChild
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.view.MenuItem
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.serialization.json.*
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -142,4 +143,8 @@ operator fun JsonElement.get(tag: String) =
|
||||
this.jsonObject[tag]
|
||||
|
||||
val JsonElement.content
|
||||
get() = this.jsonPrimitive.contentOrNull
|
||||
get() = this.jsonPrimitive.contentOrNull
|
||||
|
||||
fun List<MenuItem>.findMenu(itemID: Int): MenuItem {
|
||||
return first { it.itemId == itemID }
|
||||
}
|
||||
Reference in New Issue
Block a user