ui: make generic fragment viewmodels abstract

Turns out hilt doesn't like generic fragments. Move out all required
viewmodels to other places.
This commit is contained in:
Alexander Capehart 2023-01-29 19:44:21 -07:00
parent 7b0e502761
commit 09d4dfc990
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
12 changed files with 62 additions and 7 deletions

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.detail.recycler.AlbumDetailAdapter
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.adapter.BasicListInstructions import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
@ -39,6 +40,8 @@ import org.oxycblt.auxio.music.MusicMode
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.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
/** /**
@ -48,6 +51,9 @@ import org.oxycblt.auxio.util.*
class AlbumDetailFragment : class AlbumDetailFragment :
ListFragment<Song, FragmentDetailBinding>(), AlbumDetailAdapter.Listener { ListFragment<Song, FragmentDetailBinding>(), AlbumDetailAdapter.Listener {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what album to display is initially within the navigation arguments // Information about what album to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an album. // as a UID, as that is the only safe way to parcel an album.
private val args: AlbumDetailFragmentArgs by navArgs() private val args: AlbumDetailFragmentArgs by navArgs()

View file

@ -32,12 +32,16 @@ import org.oxycblt.auxio.detail.recycler.DetailAdapter
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.adapter.BasicListInstructions import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
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.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
@ -51,6 +55,9 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
class ArtistDetailFragment : class ArtistDetailFragment :
ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> { ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what artist to display is initially within the navigation arguments // Information about what artist to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an artist. // as a UID, as that is the only safe way to parcel an artist.
private val args: ArtistDetailFragmentArgs by navArgs() private val args: ArtistDetailFragmentArgs by navArgs()

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.detail.recycler.GenreDetailAdapter
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.adapter.BasicListInstructions import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
@ -39,6 +40,9 @@ import org.oxycblt.auxio.music.Music
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.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logD
@ -52,6 +56,9 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
class GenreDetailFragment : class GenreDetailFragment :
ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> { ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> {
private val detailModel: DetailViewModel by activityViewModels() private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what genre to display is initially within the navigation arguments // Information about what genre to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an genre. // as a UID, as that is the only safe way to parcel an genre.
private val args: GenreDetailFragmentArgs by navArgs() private val args: GenreDetailFragmentArgs by navArgs()

View file

@ -49,10 +49,12 @@ import org.oxycblt.auxio.home.list.GenreListFragment
import org.oxycblt.auxio.home.list.SongListFragment import org.oxycblt.auxio.home.list.SongListFragment
import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy
import org.oxycblt.auxio.list.selection.SelectionFragment import org.oxycblt.auxio.list.selection.SelectionFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
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.music.library.Sort
import org.oxycblt.auxio.music.system.Indexer import org.oxycblt.auxio.music.system.Indexer
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.MainNavigationAction
import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
@ -67,6 +69,8 @@ class HomeFragment :
private val homeModel: HomeViewModel by androidActivityViewModels() private val homeModel: HomeViewModel by androidActivityViewModels()
private val musicModel: MusicViewModel by activityViewModels() private val musicModel: MusicViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels() private val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private var storagePermissionLauncher: ActivityResultLauncher<String>? = null private var storagePermissionLauncher: ActivityResultLauncher<String>? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -34,10 +34,14 @@ import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.adapter.ListDiffer import org.oxycblt.auxio.list.adapter.ListDiffer
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.AlbumViewHolder import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
/** /**
@ -49,6 +53,9 @@ class AlbumListFragment :
FastScrollRecyclerView.Listener, FastScrollRecyclerView.Listener,
FastScrollRecyclerView.PopupProvider { FastScrollRecyclerView.PopupProvider {
private val homeModel: HomeViewModel by activityViewModels() private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val albumAdapter = AlbumAdapter(this) private val albumAdapter = AlbumAdapter(this)
// Save memory by re-using the same formatter and string builder when creating popup text // Save memory by re-using the same formatter and string builder when creating popup text
private val formatterSb = StringBuilder(64) private val formatterSb = StringBuilder(64)

View file

@ -32,12 +32,16 @@ import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.adapter.ListDiffer import org.oxycblt.auxio.list.adapter.ListDiffer
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.ArtistViewHolder import org.oxycblt.auxio.list.recycler.ArtistViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.nonZeroOrNull import org.oxycblt.auxio.util.nonZeroOrNull
@ -50,6 +54,9 @@ class ArtistListFragment :
FastScrollRecyclerView.PopupProvider, FastScrollRecyclerView.PopupProvider,
FastScrollRecyclerView.Listener { FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels() private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val artistAdapter = ArtistAdapter(this) private val artistAdapter = ArtistAdapter(this)
override fun onCreateBinding(inflater: LayoutInflater) = override fun onCreateBinding(inflater: LayoutInflater) =

View file

@ -32,12 +32,16 @@ import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.adapter.ListDiffer import org.oxycblt.auxio.list.adapter.ListDiffer
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.GenreViewHolder import org.oxycblt.auxio.list.recycler.GenreViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
/** /**
@ -49,6 +53,9 @@ class GenreListFragment :
FastScrollRecyclerView.PopupProvider, FastScrollRecyclerView.PopupProvider,
FastScrollRecyclerView.Listener { FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels() private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val genreAdapter = GenreAdapter(this) private val genreAdapter = GenreAdapter(this)
override fun onCreateBinding(inflater: LayoutInflater) = override fun onCreateBinding(inflater: LayoutInflater) =

View file

@ -34,13 +34,17 @@ import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.adapter.ListDiffer import org.oxycblt.auxio.list.adapter.ListDiffer
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicMode
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.music.library.Sort import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
/** /**
@ -52,6 +56,9 @@ class SongListFragment :
FastScrollRecyclerView.PopupProvider, FastScrollRecyclerView.PopupProvider,
FastScrollRecyclerView.Listener { FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels() private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val songAdapter = SongAdapter(this) private val songAdapter = SongAdapter(this)
// Save memory by re-using the same formatter and string builder when creating popup text // Save memory by re-using the same formatter and string builder when creating popup text
private val formatterSb = StringBuilder(64) private val formatterSb = StringBuilder(64)

View file

@ -21,7 +21,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.activityViewModels
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.MainFragmentDirections import org.oxycblt.auxio.MainFragmentDirections
@ -39,7 +38,7 @@ import org.oxycblt.auxio.util.showToast
*/ */
abstract class ListFragment<in T : Music, VB : ViewBinding> : abstract class ListFragment<in T : Music, VB : ViewBinding> :
SelectionFragment<VB>(), SelectableListListener<T> { SelectionFragment<VB>(), SelectableListListener<T> {
protected val navModel: NavigationViewModel by activityViewModels() protected abstract val navModel: NavigationViewModel
private var currentMenu: PopupMenu? = null private var currentMenu: PopupMenu? = null
override fun onDestroyBinding(binding: VB) { override fun onDestroyBinding(binding: VB) {

View file

@ -20,12 +20,10 @@ package org.oxycblt.auxio.list.selection
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.activityViewModels
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.showToast import org.oxycblt.auxio.util.showToast
/** /**
@ -34,8 +32,8 @@ import org.oxycblt.auxio.util.showToast
*/ */
abstract class SelectionFragment<VB : ViewBinding> : abstract class SelectionFragment<VB : ViewBinding> :
ViewBindingFragment<VB>(), Toolbar.OnMenuItemClickListener { ViewBindingFragment<VB>(), Toolbar.OnMenuItemClickListener {
protected val selectionModel: SelectionViewModel by activityViewModels() protected abstract val selectionModel: SelectionViewModel
protected val playbackModel: PlaybackViewModel by androidActivityViewModels() protected abstract val playbackModel: PlaybackViewModel
/** /**
* Get the [SelectionToolbarOverlay] of the concrete Fragment to be automatically managed by * Get the [SelectionToolbarOverlay] of the concrete Fragment to be automatically managed by

View file

@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.* import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.library.Library import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.util.logD
/** /**
* A [ViewModel] that manages the current selection. * A [ViewModel] that manages the current selection.

View file

@ -25,6 +25,7 @@ import android.view.inputmethod.InputMethodManager
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.postDelayed import androidx.core.view.postDelayed
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -32,12 +33,15 @@ import org.oxycblt.auxio.databinding.FragmentSearchBinding
import org.oxycblt.auxio.list.Item import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.adapter.BasicListInstructions import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Music
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.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.* import org.oxycblt.auxio.util.*
/** /**
@ -51,6 +55,9 @@ import org.oxycblt.auxio.util.*
*/ */
class SearchFragment : ListFragment<Music, FragmentSearchBinding>() { class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
private val searchModel: SearchViewModel by androidViewModels() private val searchModel: SearchViewModel by androidViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val searchAdapter = SearchAdapter(this) private val searchAdapter = SearchAdapter(this)
private var imm: InputMethodManager? = null private var imm: InputMethodManager? = null
private var launchedKeyboard = false private var launchedKeyboard = false