Esta é uma pergunta complementar a esta . Então, pelo que entendi, posso acessar o Gerenciador de Senhas do Google, encontrar o e-mail/senha salvos naquele aplicativo e excluí-los manualmente. Mas como posso excluí-los programaticamente? Por exemplo, quando clico em um botão de exclusão dentro do meu aplicativo Android, quero que essa conta NÃO seja exibida novamente no seletor na próxima vez que eu fizer login. Algo semelhante a excluir uma Conta do Google usando GoogleSignInClient#revokeAccess()
. Como resolver isso?
Joan P.'s questions
Estou implementando o login com o Gerenciador de Credenciais. Se eu fizer login com várias contas com e-mail e senha e essas contas ficarem indisponíveis, elas permanecerão no seletor. Se eu tentar fazer login usando uma das contas indisponíveis, recebo:
A credencial de autenticação fornecida está incorreta, malformada ou expirou.
Como remover contas do seletor BottomSheet de login do Google ao usar o Gerenciador de Credenciais para evitar a exibição de contas expiradas? Como remover essas contas do sistema?
Preciso exibir uma mensagem somente quando a operação de adicionar um item no Firebase for concluída. Esta é a função na interface:
suspend fun addItem(item: Item): Response<String>
Esta é a implementação:
override suspend fun addItem(item: Item) = try {
val itemId = itemsRef.add(item).await().id
Response.Success(itemId)
} catch (ex: Exception) {
Response.Failure(ex)
}
No ViewModel eu chamo addItem
assim:
class ItemViewModel @Inject constructor(
private val repo: ItemRepository
): ViewModel() {
private val _addItemResponse = MutableStateFlow<Response<String>>(Response.Success(""))
val addItemResponse: StateFlow<Response<String>> = _addItemResponse.asStateFlow()
fun addItem(item: Item) = viewModelScope.launch {
_addItemResponse.value = Response.Loading
_addItemResponse.value = repo.addItem(item)
}
}
E dentro da IU eu uso:
when(val addItemResponse = viewModel.addItemResponse.collectAsStateWithLifecycle().value) {
is Response.Loading -> CircularProgressIndicator()
is Response.Success -> Toast.makeText(context, addItemResponse.itemId, Toast.LENGTH_LONG).show()
is Response.Failure -> Text(addItemResponse.ex)
}
O problema é que toda vez que inicio o aplicativo, recebo um Toast vazio. Se eu adicionar um item, recebo uma mensagem Toast com o ID do item, que está correto. Mas como mostrar a mensagem Toast somente quando recebo Succes, ou seja, quando os dados são adicionados ao Firebase?
Eu tenho um aplicativo onde injeto um ViewModel
objeto diretamente no MainScreen
:
@Composable
fun MainScreen(
viewModel: ItemsViewModel = hiltViewModel()
) {
Scaffold(
topBar = {
TopBar(
onClick = {
viewModel.signOut()
}
)
},
content = {
ItemsContent(
items = viewModel.getItems()
)
},
floatingActionButton = {
FAB(
onClick = {
viewModel.addItem("ABC")
}
)
}
)
}
É recomendado injetar o ViewModel
objeto apenas uma vez na MainScreen
tela ou posso injetar o mesmo ViewModel
objeto dentro de cada função que pode ser composta, TopBar
, ItemsContent
e FAB
?
Eu tenho um aplicativo muito simples:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyTheme {
Navigation(
navController = rememberNavController()
)
}
}
}
}
Com duas telas:
sealed class Screen(val route: String){
data object MainScreen : Screen("main_screen")
data object DetailScreen : Screen("detail_screen")
fun withArgs(vararg args: String) = buildString {
append(route)
args.forEach { arg ->
append("/$arg")
}
}
}
O que eu quero é passar um texto de uma tela para outra usando navegação:
@Composable
fun Navigation(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = MainScreen.route
) {
composable(
route = MainScreen.route
) {
MainScreen(
navigateToDetailScreen = { text ->
navController.navigate(DetailScreen.withArgs(text))
}
)
}
composable(
route = DetailScreen.route + "/{text}",
arguments = listOf(
navArgument("text") {
type = NavType.StringType
}
)
) { entry ->
DetailScreen(
text = entry.arguments?.getString("text")!!
)
}
}
}
E aqui estão minhas duas telas:
@Composable
fun MainScreen(
navigateToDetailScreen: (text: String) -> Unit
) {
Log.d("MyTag", "MainScreen")
var text by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize()
) {
TextField(
value = text,
onValueChange = {
text = it
}
)
Button(
onClick = {
navigateToDetailScreen(text)
}
) {
Text(
text = "Navigate"
)
}
}
}
@Composable
fun DetailScreen(text: String) {
Log.d("MyTag", "DetailScreen")
Column(
modifier = Modifier.fillMaxSize()
) {
Text(
text = text
)
}
}
Os dois problemas que estou enfrentando são:
Cada vez que escrevo um novo personagem dentro do
TextField
, aMainScreen
diversão dispara continuamente.Quando pressiono
Navigate
, aMainScreen
diversão dispara novamente,DetailScreen
dispara uma vez e aMainScreen
diversão dispara novamente, resultando na exibição:MainScreen //when the app starts MainScreen //when adding the first character MainScreen //when adding the second character MainScreen //when clicking the "Navigate" button DetailScreen //when the second screen is displayed MainScreen //For no reason
Como impedir que isso aconteça?
Na minha MainActivity eu crio esta tela:
setContent {
MyTheme {
Surface(
modifier = Modifier.fillMaxSize()
) {
MainScreen()
}
}
}
É assim:
Scaffold(
topBar = {/* ... */},
content = { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding).fillMaxSize()
) {
Column() {
Text("Info1")
Text("Info2")
}
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
items(users) { user ->
Text(user.ane)
}
}
}
}
)
O problema é que quando tenho vários nomes de usuário exibidos no LazyColumn, recebo uma rolagem. O que eu quero é, quando tiver vários nomes de usuário, expandir a lista para poder rolar todo o conteúdo MainScreen
e não apenas o conteúdo do arquivo LazyColumn
. Como resolver isso?