mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 16:11:20 +02:00
Fix focusing before loading on recommended pages (#220)
Basically now will wait until a row is loaded before sending the focus request
This commit is contained in:
parent
b7cb6efc4f
commit
c5a5345f6c
3 changed files with 83 additions and 39 deletions
|
|
@ -12,7 +12,7 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||||
import com.github.damontecres.wholphin.services.NavigationManager
|
import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||||
import com.github.damontecres.wholphin.ui.data.RowColumn
|
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||||
|
|
@ -26,6 +26,8 @@ import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -95,8 +97,8 @@ class RecommendedMovieViewModel
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
if (resumeItems.isNotEmpty()) {
|
||||||
loading.value = LoadingState.Success
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex, "Exception fetching movie recommendations")
|
Timber.e(ex, "Exception fetching movie recommendations")
|
||||||
|
|
@ -159,9 +161,9 @@ class RecommendedMovieViewModel
|
||||||
R.string.suggestions to suggestedItems,
|
R.string.suggestions to suggestedItems,
|
||||||
R.string.top_unwatched to unwatchedTopRatedItems,
|
R.string.top_unwatched to unwatchedTopRatedItems,
|
||||||
)
|
)
|
||||||
|
rows
|
||||||
rows.forEachIndexed { index, (title, pager) ->
|
.mapIndexed { index, (title, pager) ->
|
||||||
viewModelScope.launchIO {
|
viewModelScope.async(Dispatchers.IO + ExceptionHandler()) {
|
||||||
val title = context.getString(title)
|
val title = context.getString(title)
|
||||||
val result =
|
val result =
|
||||||
try {
|
try {
|
||||||
|
|
@ -175,8 +177,16 @@ class RecommendedMovieViewModel
|
||||||
HomeRowLoadingState.Error(title, null, ex)
|
HomeRowLoadingState.Error(title, null, ex)
|
||||||
}
|
}
|
||||||
update(index + 1, result)
|
update(index + 1, result)
|
||||||
|
if (result is HomeRowLoadingState.Success && result.items.isNotEmpty() &&
|
||||||
|
(loading.value == LoadingState.Loading || loading.value == LoadingState.Pending)
|
||||||
|
) {
|
||||||
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.awaitAll()
|
||||||
|
if (loading.value == LoadingState.Loading || loading.value == LoadingState.Pending) {
|
||||||
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
|
||||||
import com.github.damontecres.wholphin.services.NavigationManager
|
import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.ui.SlimItemFields
|
import com.github.damontecres.wholphin.ui.SlimItemFields
|
||||||
import com.github.damontecres.wholphin.ui.data.RowColumn
|
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
|
||||||
|
|
@ -27,6 +27,8 @@ import dagger.assisted.AssistedInject
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -123,8 +125,8 @@ class RecommendedTvShowViewModel
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
if (resumeItems.isNotEmpty() || nextUpItems.isNotEmpty()) {
|
||||||
loading.value = LoadingState.Success
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex, "Exception fetching tv recommendations")
|
Timber.e(ex, "Exception fetching tv recommendations")
|
||||||
|
|
@ -188,20 +190,32 @@ class RecommendedTvShowViewModel
|
||||||
R.string.top_unwatched to unwatchedTopRatedItems,
|
R.string.top_unwatched to unwatchedTopRatedItems,
|
||||||
)
|
)
|
||||||
|
|
||||||
rows.forEachIndexed { index, (title, pager) ->
|
rows
|
||||||
viewModelScope.launchIO {
|
.mapIndexed { index, (title, pager) ->
|
||||||
|
viewModelScope.async(Dispatchers.IO + ExceptionHandler()) {
|
||||||
val title = context.getString(title)
|
val title = context.getString(title)
|
||||||
val result =
|
val result =
|
||||||
try {
|
try {
|
||||||
pager.init()
|
pager.init()
|
||||||
|
if (pager.isNotEmpty()) {
|
||||||
|
pager.getBlocking(0)
|
||||||
|
}
|
||||||
HomeRowLoadingState.Success(title, pager)
|
HomeRowLoadingState.Success(title, pager)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Timber.e(ex, "Error fetching %s", title)
|
Timber.e(ex, "Error fetching %s", title)
|
||||||
HomeRowLoadingState.Error(title, null, ex)
|
HomeRowLoadingState.Error(title, null, ex)
|
||||||
}
|
}
|
||||||
update(index + 2, result)
|
update(index + 2, result)
|
||||||
|
if (result is HomeRowLoadingState.Success && result.items.isNotEmpty() &&
|
||||||
|
(loading.value == LoadingState.Loading || loading.value == LoadingState.Pending)
|
||||||
|
) {
|
||||||
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.awaitAll()
|
||||||
|
if (loading.value == LoadingState.Loading || loading.value == LoadingState.Pending) {
|
||||||
|
loading.setValueOnMain(LoadingState.Success)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -197,8 +197,20 @@ fun HomePageContent(
|
||||||
loadingState: LoadingState? = null,
|
loadingState: LoadingState? = null,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
val firstRow =
|
||||||
|
remember {
|
||||||
|
homeRows
|
||||||
|
.indexOfFirst {
|
||||||
|
when (it) {
|
||||||
|
is HomeRowLoadingState.Error -> false
|
||||||
|
is HomeRowLoadingState.Loading -> true
|
||||||
|
is HomeRowLoadingState.Pending -> true
|
||||||
|
is HomeRowLoadingState.Success -> it.items.isNotEmpty()
|
||||||
|
}
|
||||||
|
}.coerceAtLeast(0)
|
||||||
|
}
|
||||||
var position by rememberSaveable(stateSaver = RowColumnSaver) {
|
var position by rememberSaveable(stateSaver = RowColumnSaver) {
|
||||||
mutableStateOf(RowColumn(0, 0))
|
mutableStateOf(RowColumn(firstRow, 0))
|
||||||
}
|
}
|
||||||
var focusedItem =
|
var focusedItem =
|
||||||
position.let {
|
position.let {
|
||||||
|
|
@ -208,11 +220,19 @@ fun HomePageContent(
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
val positionFocusRequester = remember { FocusRequester() }
|
val positionFocusRequester = remember { FocusRequester() }
|
||||||
LaunchedEffect(Unit) {
|
var focused by remember { mutableStateOf(false) }
|
||||||
|
LaunchedEffect(homeRows) {
|
||||||
|
if (!focused) {
|
||||||
|
homeRows
|
||||||
|
.indexOfFirst { it is HomeRowLoadingState.Success && it.items.isNotEmpty() }
|
||||||
|
.takeIf { it >= 0 }
|
||||||
|
?.let {
|
||||||
positionFocusRequester.tryRequestFocus()
|
positionFocusRequester.tryRequestFocus()
|
||||||
// Hacky, but mostly works
|
|
||||||
delay(50)
|
delay(50)
|
||||||
listState.animateScrollToItem(position.row)
|
listState.animateScrollToItem(position.row)
|
||||||
|
focused = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LaunchedEffect(position) {
|
LaunchedEffect(position) {
|
||||||
listState.animateScrollToItem(position.row)
|
listState.animateScrollToItem(position.row)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue