list: add update instructions framework
Add the basic framework that should allow for different types of list updates in different situations.
This commit is contained in:
parent
5988908b56
commit
176f0cc465
14 changed files with 100 additions and 88 deletions
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
## dev
|
## dev
|
||||||
|
|
||||||
|
#### What's New
|
||||||
|
- Added ability to play/shuffle selections
|
||||||
|
|
||||||
#### What's Improved
|
#### What's Improved
|
||||||
- Added ability to edit previously played or currently playing items in the queue
|
- Added ability to edit previously played or currently playing items in the queue
|
||||||
- Added support for date values formatted as "YYYYMMDD"
|
- Added support for date values formatted as "YYYYMMDD"
|
||||||
|
|
|
@ -343,10 +343,8 @@ class MainFragment :
|
||||||
if (playbackSheetBehavior.state == NeoBottomSheetBehavior.STATE_HIDDEN) {
|
if (playbackSheetBehavior.state == NeoBottomSheetBehavior.STATE_HIDDEN) {
|
||||||
val queueSheetBehavior =
|
val queueSheetBehavior =
|
||||||
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
|
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
|
||||||
|
|
||||||
// Queue sheet behavior is either collapsed or expanded, no hiding needed
|
// Queue sheet behavior is either collapsed or expanded, no hiding needed
|
||||||
queueSheetBehavior?.isDraggable = true
|
queueSheetBehavior?.isDraggable = true
|
||||||
|
|
||||||
playbackSheetBehavior.apply {
|
playbackSheetBehavior.apply {
|
||||||
// Make sure the view is draggable, at least until the draw checks kick in.
|
// Make sure the view is draggable, at least until the draw checks kick in.
|
||||||
isDraggable = true
|
isDraggable = true
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.oxycblt.auxio.list
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the specific way to update a list of items.
|
||||||
|
* @author Alexander Capehart (OxygenCobalt)
|
||||||
|
*/
|
||||||
|
enum class UpdateInstructions {
|
||||||
|
/**
|
||||||
|
* (A)synchronously diff the list. This should be used for small diffs with little item
|
||||||
|
* movement.
|
||||||
|
*/
|
||||||
|
DIFF,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously remove the current list and replace it with a new one. This should be used
|
||||||
|
* for large diffs with that would cause erratic scroll behavior or in-efficiency.
|
||||||
|
*/
|
||||||
|
REPLACE
|
||||||
|
}
|
|
@ -242,7 +242,7 @@ class PlaybackViewModel(application: Application) :
|
||||||
* @param selection The selection to play.
|
* @param selection The selection to play.
|
||||||
*/
|
*/
|
||||||
fun play(selection: List<Music>) =
|
fun play(selection: List<Music>) =
|
||||||
playbackManager.play(null, selectionToSongs(selection), false)
|
playbackManager.play(null, null, selectionToSongs(selection), false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuffle an [Album].
|
* Shuffle an [Album].
|
||||||
|
@ -267,7 +267,7 @@ class PlaybackViewModel(application: Application) :
|
||||||
* @param selection The selection to shuffle.
|
* @param selection The selection to shuffle.
|
||||||
*/
|
*/
|
||||||
fun shuffle(selection: List<Music>) =
|
fun shuffle(selection: List<Music>) =
|
||||||
playbackManager.play(null, selectionToSongs(selection), true)
|
playbackManager.play(null, null, selectionToSongs(selection), true)
|
||||||
|
|
||||||
private fun playImpl(
|
private fun playImpl(
|
||||||
song: Song?,
|
song: Song?,
|
||||||
|
@ -286,7 +286,7 @@ class PlaybackViewModel(application: Application) :
|
||||||
null -> musicSettings.songSort
|
null -> musicSettings.songSort
|
||||||
}
|
}
|
||||||
val queue = sort.songs(parent?.songs ?: library.songs)
|
val queue = sort.songs(parent?.songs ?: library.songs)
|
||||||
playbackManager.play(song, queue, shuffled)
|
playbackManager.play(song, parent, queue, shuffled)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
import org.oxycblt.auxio.databinding.FragmentQueueBinding
|
||||||
import org.oxycblt.auxio.list.EditableListListener
|
import org.oxycblt.auxio.list.EditableListListener
|
||||||
|
import org.oxycblt.auxio.list.UpdateInstructions
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||||
import org.oxycblt.auxio.ui.ViewBindingFragment
|
import org.oxycblt.auxio.ui.ViewBindingFragment
|
||||||
|
@ -100,18 +101,19 @@ class QueueFragment : ViewBindingFragment<FragmentQueueBinding>(), EditableListL
|
||||||
val binding = requireBinding()
|
val binding = requireBinding()
|
||||||
|
|
||||||
// Replace or diff the queue depending on the type of change it is.
|
// Replace or diff the queue depending on the type of change it is.
|
||||||
// TODO: Extend this to the whole app.
|
val instructions = queueModel.instructions
|
||||||
if (queueModel.replaceQueue == true) {
|
if (instructions?.update == UpdateInstructions.REPLACE) {
|
||||||
logD("Replacing queue")
|
logD("Replacing queue")
|
||||||
queueAdapter.replaceList(queue)
|
queueAdapter.replaceList(queue)
|
||||||
} else {
|
} else {
|
||||||
logD("Diffing queue")
|
logD("Diffing queue")
|
||||||
queueAdapter.submitList(queue)
|
queueAdapter.submitList(queue)
|
||||||
}
|
}
|
||||||
queueModel.finishReplace()
|
// Update position in list (and thus past/future items)
|
||||||
|
queueAdapter.setPosition(index, isPlaying)
|
||||||
|
|
||||||
// If requested, scroll to a new item (occurs when the index moves)
|
// If requested, scroll to a new item (occurs when the index moves)
|
||||||
val scrollTo = queueModel.scrollTo
|
val scrollTo = instructions?.scrollTo
|
||||||
if (scrollTo != null) {
|
if (scrollTo != null) {
|
||||||
val lmm = binding.queueRecycler.layoutManager as LinearLayoutManager
|
val lmm = binding.queueRecycler.layoutManager as LinearLayoutManager
|
||||||
val start = lmm.findFirstCompletelyVisibleItemPosition()
|
val start = lmm.findFirstCompletelyVisibleItemPosition()
|
||||||
|
@ -132,9 +134,7 @@ class QueueFragment : ViewBindingFragment<FragmentQueueBinding>(), EditableListL
|
||||||
min(queue.lastIndex, scrollTo + (end - start)))
|
min(queue.lastIndex, scrollTo + (end - start)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queueModel.finishScrollTo()
|
|
||||||
|
|
||||||
// Update position in list (and thus past/future items)
|
queueModel.finishInstructions()
|
||||||
queueAdapter.setPosition(index, isPlaying)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.playback.queue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import org.oxycblt.auxio.list.UpdateInstructions
|
||||||
import org.oxycblt.auxio.music.MusicParent
|
import org.oxycblt.auxio.music.MusicParent
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||||
|
@ -42,15 +43,47 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
|
||||||
val index: StateFlow<Int>
|
val index: StateFlow<Int>
|
||||||
get() = _index
|
get() = _index
|
||||||
|
|
||||||
/** Whether to replace or diff the queue list when updating it. Is null if not specified. */
|
/** Specifies how to update the list when the queue changes. */
|
||||||
var replaceQueue: Boolean? = null
|
var instructions: Instructions? = null
|
||||||
/** Flag to scroll to a particular queue item. Is null if no command has been specified. */
|
|
||||||
var scrollTo: Int? = null
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
playbackManager.addListener(this)
|
playbackManager.addListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onIndexMoved(queue: Queue) {
|
||||||
|
instructions = Instructions(null, queue.index)
|
||||||
|
_index.value = queue.index
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueueChanged(queue: Queue, change: Queue.ChangeResult) {
|
||||||
|
// Queue changed trivially due to item mo -> Diff queue, stay at current index.
|
||||||
|
instructions = Instructions(UpdateInstructions.DIFF, null)
|
||||||
|
_queue.value = queue.resolve()
|
||||||
|
if (change != Queue.ChangeResult.MAPPING) {
|
||||||
|
// Index changed, make sure it remains updated without actually scrolling to it.
|
||||||
|
_index.value = queue.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueueReordered(queue: Queue) {
|
||||||
|
// Queue changed completely -> Replace queue, update index
|
||||||
|
instructions = Instructions(UpdateInstructions.REPLACE, null)
|
||||||
|
_queue.value = queue.resolve()
|
||||||
|
_index.value = queue.index
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewPlayback(queue: Queue, parent: MusicParent?) {
|
||||||
|
// Entirely new queue -> Replace queue, update index
|
||||||
|
instructions = Instructions(UpdateInstructions.REPLACE, null)
|
||||||
|
_queue.value = queue.resolve()
|
||||||
|
_index.value = queue.index
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
playbackManager.removeListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start playing the the queue item at the given index.
|
* Start playing the the queue item at the given index.
|
||||||
* @param adapterIndex The index of the queue item to play. Does nothing if the index is out of
|
* @param adapterIndex The index of the queue item to play. Does nothing if the index is out of
|
||||||
|
@ -86,52 +119,10 @@ class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finish a replace flag specified by [replaceQueue]. */
|
/** Signal that the specified [Instructions] in [instructions] were performed. */
|
||||||
fun finishReplace() {
|
fun finishInstructions() {
|
||||||
replaceQueue = null
|
instructions = null
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Finish a scroll operation started by [scrollTo]. */
|
class Instructions(val update: UpdateInstructions?, val scrollTo: Int?)
|
||||||
fun finishScrollTo() {
|
|
||||||
scrollTo = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onIndexMoved(queue: Queue) {
|
|
||||||
// Index moved -> Scroll to new index
|
|
||||||
replaceQueue = null
|
|
||||||
scrollTo = queue.index
|
|
||||||
_index.value = queue.index
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueueChanged(queue: Queue, change: Queue.ChangeResult) {
|
|
||||||
// Queue changed trivially due to item mo -> Diff queue, stay at current index.
|
|
||||||
replaceQueue = false
|
|
||||||
scrollTo = null
|
|
||||||
_queue.value = queue.resolve()
|
|
||||||
if (change != Queue.ChangeResult.MAPPING) {
|
|
||||||
// Index changed, make sure it remains updated without actually scrolling to it.
|
|
||||||
_index.value = queue.index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueueReordered(queue: Queue) {
|
|
||||||
// Queue changed completely -> Replace queue, update index
|
|
||||||
replaceQueue = true
|
|
||||||
scrollTo = queue.index
|
|
||||||
_queue.value = queue.resolve()
|
|
||||||
_index.value = queue.index
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewPlayback(queue: Queue, parent: MusicParent?) {
|
|
||||||
// Entirely new queue -> Replace queue, update index
|
|
||||||
replaceQueue = true
|
|
||||||
scrollTo = queue.index
|
|
||||||
_queue.value = queue.resolve()
|
|
||||||
_index.value = queue.index
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCleared() {
|
|
||||||
super.onCleared()
|
|
||||||
playbackManager.removeListener(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.oxycblt.auxio.BuildConfig
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.MusicStore
|
import org.oxycblt.auxio.music.MusicStore
|
||||||
import org.oxycblt.auxio.music.library.Library
|
import org.oxycblt.auxio.music.library.Library
|
||||||
import org.oxycblt.auxio.music.library.Sort
|
|
||||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager.Listener
|
import org.oxycblt.auxio.playback.state.PlaybackStateManager.Listener
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
import org.oxycblt.auxio.util.logE
|
import org.oxycblt.auxio.util.logE
|
||||||
|
@ -60,7 +59,7 @@ class PlaybackStateManager private constructor() {
|
||||||
val queue = Queue()
|
val queue = Queue()
|
||||||
/** The [MusicParent] currently being played. Null if playback is occurring from all songs. */
|
/** The [MusicParent] currently being played. Null if playback is occurring from all songs. */
|
||||||
@Volatile
|
@Volatile
|
||||||
var parent: MusicParent? = null
|
var parent: MusicParent? = null // TODO: Parent is interpreted wrong when nothing is playing.
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/** The current [InternalPlayer] state. */
|
/** The current [InternalPlayer] state. */
|
||||||
|
@ -98,7 +97,7 @@ class PlaybackStateManager private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a [Listener] from this instance, preventing it from recieving any further updates.
|
* Remove a [Listener] from this instance, preventing it from receiving any further updates.
|
||||||
* @param listener The [Listener] to remove. Does nothing if the [Listener] was never added in
|
* @param listener The [Listener] to remove. Does nothing if the [Listener] was never added in
|
||||||
* the first place.
|
* the first place.
|
||||||
* @see Listener
|
* @see Listener
|
||||||
|
@ -156,14 +155,13 @@ class PlaybackStateManager private constructor() {
|
||||||
* Start new playback.
|
* Start new playback.
|
||||||
* @param song A particular [Song] to play, or null to play the first [Song] in the new queue.
|
* @param song A particular [Song] to play, or null to play the first [Song] in the new queue.
|
||||||
* @param queue The queue of [Song]s to play from.
|
* @param queue The queue of [Song]s to play from.
|
||||||
* @param parent The [MusicParent] to play from, or null if to play from the entire [Library].
|
* @param parent The [MusicParent] to play from, or null if to play from an non-specific
|
||||||
* @param sort [Sort] to initially sort an ordered queue with.
|
* collection of "All [Song]s".
|
||||||
* @param shuffled Whether to shuffle or not.
|
* @param shuffled Whether to shuffle or not.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun play(song: Song?, queue: List<Song>, shuffled: Boolean) {
|
fun play(song: Song?, parent: MusicParent?, queue: List<Song>, shuffled: Boolean) {
|
||||||
val internalPlayer = internalPlayer ?: return
|
val internalPlayer = internalPlayer ?: return
|
||||||
val library = musicStore.library ?: return
|
|
||||||
// Set up parent and queue
|
// Set up parent and queue
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
this.queue.start(song, queue, shuffled)
|
this.queue.start(song, queue, shuffled)
|
||||||
|
|
|
@ -208,8 +208,9 @@ class Queue {
|
||||||
// We have moved an song from in front of the playing song to behind, shift forward.
|
// We have moved an song from in front of the playing song to behind, shift forward.
|
||||||
in dst until src -> index += 1
|
in dst until src -> index += 1
|
||||||
else -> {
|
else -> {
|
||||||
|
// Nothing to do.
|
||||||
check()
|
check()
|
||||||
ChangeResult.MAPPING
|
return ChangeResult.MAPPING
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
check()
|
check()
|
||||||
|
|
|
@ -355,13 +355,14 @@ class PlaybackService :
|
||||||
}
|
}
|
||||||
// Shuffle all -> Start new playback from all songs
|
// Shuffle all -> Start new playback from all songs
|
||||||
is InternalPlayer.Action.ShuffleAll -> {
|
is InternalPlayer.Action.ShuffleAll -> {
|
||||||
playbackManager.play(null, musicSettings.songSort.songs(library.songs), true)
|
playbackManager.play(null, null, musicSettings.songSort.songs(library.songs), true)
|
||||||
}
|
}
|
||||||
// Open -> Try to find the Song for the given file and then play it from all songs
|
// Open -> Try to find the Song for the given file and then play it from all songs
|
||||||
is InternalPlayer.Action.Open -> {
|
is InternalPlayer.Action.Open -> {
|
||||||
library.findSongForUri(application, action.uri)?.let { song ->
|
library.findSongForUri(application, action.uri)?.let { song ->
|
||||||
playbackManager.play(
|
playbackManager.play(
|
||||||
song,
|
song,
|
||||||
|
null,
|
||||||
musicSettings.songSort.songs(library.songs),
|
musicSettings.songSort.songs(library.songs),
|
||||||
playbackManager.queue.isShuffled && playbackSettings.keepShuffle)
|
playbackManager.queue.isShuffled && playbackSettings.keepShuffle)
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,8 +123,7 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
|
||||||
if (pkgName == "android") {
|
if (pkgName == "android") {
|
||||||
// No default browser [Must open app chooser, may not be supported]
|
// No default browser [Must open app chooser, may not be supported]
|
||||||
openAppChooser(browserIntent)
|
openAppChooser(browserIntent)
|
||||||
} else {
|
} else try {
|
||||||
try {
|
|
||||||
browserIntent.setPackage(pkgName)
|
browserIntent.setPackage(pkgName)
|
||||||
startActivity(browserIntent)
|
startActivity(browserIntent)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
@ -132,7 +131,6 @@ class AboutFragment : ViewBindingFragment<FragmentAboutBinding>() {
|
||||||
browserIntent.setPackage(null)
|
browserIntent.setPackage(null)
|
||||||
openAppChooser(browserIntent)
|
openAppChooser(browserIntent)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// No app installed to open the link
|
// No app installed to open the link
|
||||||
context.showToast(R.string.err_no_app)
|
context.showToast(R.string.err_no_app)
|
||||||
|
|
|
@ -88,6 +88,11 @@ interface Settings<L> {
|
||||||
onSettingChanged(key, unlikelyToBeNull(listener))
|
onSettingChanged(key, unlikelyToBeNull(listener))
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun onSettingChanged(key: String, listener: L) {}
|
/**
|
||||||
|
* Called when a setting entry with the given [key] has changed.
|
||||||
|
* @param key The key of the changed setting.
|
||||||
|
* @param listener The implementation's listener that updates should be applied to.
|
||||||
|
*/
|
||||||
|
protected open fun onSettingChanged(key: String, listener: L) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ abstract class BaseBottomSheetBehavior<V : View>(context: Context, attributeSet:
|
||||||
/**
|
/**
|
||||||
* Called when window insets are being applied to the [View] this [BaseBottomSheetBehavior] is
|
* Called when window insets are being applied to the [View] this [BaseBottomSheetBehavior] is
|
||||||
* linked to.
|
* linked to.
|
||||||
* @param child The child view recieving the [WindowInsets].
|
* @param child The child view receiving the [WindowInsets].
|
||||||
* @param insets The [WindowInsets] to apply.
|
* @param insets The [WindowInsets] to apply.
|
||||||
* @return The (possibly modified) [WindowInsets].
|
* @return The (possibly modified) [WindowInsets].
|
||||||
* @see View.onApplyWindowInsets
|
* @see View.onApplyWindowInsets
|
||||||
|
|
|
@ -74,12 +74,11 @@ abstract class ViewBindingDialogFragment<VB : ViewBinding> : DialogFragment() {
|
||||||
* @return The currently-inflated [ViewBinding].
|
* @return The currently-inflated [ViewBinding].
|
||||||
* @throws IllegalStateException if the [ViewBinding] is not inflated.
|
* @throws IllegalStateException if the [ViewBinding] is not inflated.
|
||||||
*/
|
*/
|
||||||
protected fun requireBinding(): VB {
|
protected fun requireBinding() =
|
||||||
return requireNotNull(_binding) {
|
requireNotNull(_binding) {
|
||||||
"ViewBinding was available. Fragment should be a valid state " +
|
"ViewBinding was available. Fragment should be a valid state " +
|
||||||
"right now, but instead it was ${lifecycle.currentState}"
|
"right now, but instead it was ${lifecycle.currentState}"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final override fun onCreateView(
|
final override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
|
|
@ -65,12 +65,11 @@ abstract class ViewBindingFragment<VB : ViewBinding> : Fragment() {
|
||||||
* @return The currently-inflated [ViewBinding].
|
* @return The currently-inflated [ViewBinding].
|
||||||
* @throws IllegalStateException if the [ViewBinding] is not inflated.
|
* @throws IllegalStateException if the [ViewBinding] is not inflated.
|
||||||
*/
|
*/
|
||||||
protected fun requireBinding(): VB {
|
protected fun requireBinding() =
|
||||||
return requireNotNull(_binding) {
|
requireNotNull(_binding) {
|
||||||
"ViewBinding was available. Fragment should be a valid state " +
|
"ViewBinding was available. Fragment should be a valid state " +
|
||||||
"right now, but instead it was ${lifecycle.currentState}"
|
"right now, but instead it was ${lifecycle.currentState}"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final override fun onCreateView(
|
final override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
|
|
Loading…
Reference in a new issue