diff --git a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthFormScreen.kt b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthFormScreen.kt index 6dbb84c9fc..4a6503b3bd 100644 --- a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthFormScreen.kt +++ b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthFormScreen.kt @@ -1,19 +1,41 @@ package net.pantasystem.milktea.auth import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.* +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedButton +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Scaffold +import androidx.compose.material.Switch +import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Search import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -22,10 +44,12 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import kotlinx.coroutines.flow.distinctUntilChanged import net.pantasystem.milktea.auth.viewmodel.app.AuthUiState import net.pantasystem.milktea.auth.viewmodel.app.AuthUserInputState import net.pantasystem.milktea.common.ResultState import net.pantasystem.milktea.common.StateContent +import net.pantasystem.milktea.common.ui.isScrolledToTheEnd import net.pantasystem.milktea.data.infrastructure.auth.Authorization @Composable @@ -43,6 +67,7 @@ fun AuthFormScreen( onToggleTermsOfServiceAgreement: (Boolean) -> Unit, onToggleAcceptMastodonAlphaTest: (Boolean) -> Unit, onSignUpButtonClicked: () -> Unit, + onBottomReached: () -> Unit, ) { Column( @@ -112,6 +137,7 @@ fun AuthFormScreen( uiState = uiState, instanceDomain = instanceDomain, onInputInstanceDomain = onInputInstanceDomain, + onBottomReached = onBottomReached ) Column( @@ -235,14 +261,26 @@ private fun FilteredInstances( uiState: AuthUiState, instanceDomain: String, onInputInstanceDomain: (String) -> Unit, + onBottomReached: () -> Unit, ) { + val listState = rememberLazyListState() + LaunchedEffect(Unit) { + snapshotFlow { + listState.isScrolledToTheEnd() + }.distinctUntilChanged().collect { + if (it) { + onBottomReached() + } + } + } val instances = remember(uiState.misskeyInstanceInfosResponse, uiState.formState) { uiState.misskeyInstanceInfosResponse.filter { it.meta.uri.contains(instanceDomain) || it.name.contains(instanceDomain) - } ?: emptyList() + } } LazyColumn( - modifier + modifier, + state = listState, ) { items(instances) { instance -> Box( @@ -296,7 +334,8 @@ fun Preview_AuthFormScreen() { onTogglePrivacyPolicyAgreement = {}, onToggleTermsOfServiceAgreement = {}, onToggleAcceptMastodonAlphaTest = {}, - onSignUpButtonClicked = {} + onSignUpButtonClicked = {}, + onBottomReached = {} ) } } diff --git a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthScreen.kt b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthScreen.kt index 4378e63219..0ed13be980 100644 --- a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthScreen.kt +++ b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/AuthScreen.kt @@ -84,7 +84,8 @@ fun AuthScreen( onShowTermsOfService = onShowTermsOfService, onShowPrivacyPolicy = onShowPrivacyPolicy, onToggleAcceptMastodonAlphaTest = authViewModel::onToggleAcceptMastodonAlphaTest, - onSignUpButtonClicked = onSignUpButtonClicked + onSignUpButtonClicked = onSignUpButtonClicked, + onBottomReached = authViewModel::onBottomReached ) } is Authorization.Waiting4UserAuthorization -> { diff --git a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/suggestions/InstanceSuggestionsPagingModel.kt b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/suggestions/InstanceSuggestionsPagingModel.kt index 8497482aad..fbadb8d3a4 100644 --- a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/suggestions/InstanceSuggestionsPagingModel.kt +++ b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/suggestions/InstanceSuggestionsPagingModel.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import net.pantasystem.milktea.api.misskey.InstanceInfoAPIBuilder import net.pantasystem.milktea.api.misskey.infos.InstanceInfosResponse +import net.pantasystem.milktea.common.Logger import net.pantasystem.milktea.common.PageableState import net.pantasystem.milktea.common.paginator.EntityConverter import net.pantasystem.milktea.common.paginator.PaginationState @@ -21,11 +22,15 @@ import javax.inject.Inject class InstanceSuggestionsPagingModel @Inject constructor( private val instancesInfoAPIBuilder: InstanceInfoAPIBuilder, + private val loggerFactory: Logger.Factory, ) : StateLocker, PaginationState, PreviousLoader, EntityConverter { + private val logger by lazy { + loggerFactory.create("InstanceSuggestionsPagingModel") + } private var _offset = 0 private var _name: String = "" private val _state = @@ -62,7 +67,7 @@ class InstanceSuggestionsPagingModel @Inject constructor( _job?.cancel() mutex.withLock { _name = name - + _offset = 0 } setState(PageableState.Loading.Init()) } @@ -79,7 +84,9 @@ class InstanceSuggestionsPagingModel @Inject constructor( fun onLoadNext(scope: CoroutineScope) { _job?.cancel() _job = scope.launch { - previousPagingController.loadPrevious() + previousPagingController.loadPrevious().onFailure { + logger.error("Failed to load previous", it) + } } } diff --git a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/viewmodel/app/AppAuthViewModel.kt b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/viewmodel/app/AppAuthViewModel.kt index fb53b6c264..bac530f003 100644 --- a/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/viewmodel/app/AppAuthViewModel.kt +++ b/modules/features/auth/src/main/java/net/pantasystem/milktea/auth/viewmodel/app/AppAuthViewModel.kt @@ -88,26 +88,7 @@ class AppAuthViewModel @Inject constructor( StateContent.NotExist() ) ) -// -// private val instances = instanceInfoRepository.observeAll() -// .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList()) - -// @OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class) -// private val misskeyInstances = instanceDomain.flatMapLatest { name -> -// suspend { -// requireNotNull( -// instancesInfoAPIBuilder.build().getInstances( -// name = name -// ).throwIfHasError() -// .body() -// ).distinctBy { -// it.url -// } -// }.asFlow() -// }.catch { -// logger.error("インスタンス情報の取得に失敗", it) -// }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null) -// + private val misskeyInstances = instanceSuggestionsPagingModel.state.map { (it.content as? StateContent.Exist)?.rawContent ?: emptyList() }.stateIn( @@ -346,11 +327,6 @@ class AppAuthViewModel @Inject constructor( } }.launchIn(viewModelScope) -// viewModelScope.launch { -// instanceInfoRepository.sync().onFailure { -// logger.error("sync instance info error", it) -// } -// } } fun auth() { @@ -392,6 +368,9 @@ class AppAuthViewModel @Inject constructor( isAcceptMastodonAlphaTest.value = value } + fun onBottomReached() { + instanceSuggestionsPagingModel.onLoadNext(viewModelScope) + } }