🌄

[Android] ViewModelに依存したComposeのPreviewを表示する

2022/06/03に公開

やりたかったこと

ComposeのPreviewにAPIレスポンスのモックを表示したかった。
画像のLoginをタップ後APIから token が返却され、下部にあるtoken=以降に値を表示するのをPreviewで再現したかった。
※tokenを表示するのはエンジニアとしてどうなのかというのはある

実装

Screen

@Composable
fun LoginScreen(viewModel: LoginViewModel) {
    val scope = rememberCoroutineScope()
    val state = viewModel.state.collectAsState() // Flow
    
    Column {
        ... 
        // Text Fieldの実装
        ...
	
	Button(onClick = {
	    scope.launch {
	        viewModel.login(email, password)
	    }.invokeOnCompletion {
	        ....
	    }
	}) {
	    Text(text = "Login")
	}
	
	Text(text = "token = ${state.value.token}") // ここをモックで表示したい
}

ViewModel

abstruct classViewModel()を Implement しておき、「実際にStateを管理するクラス」と「Preview表示用のモッククラス」それぞれを作成し、共通部分(今回は state)を使いまわすことで解決した。

abstruct class LoginViewModel : ViewModel() {
    sealed class State {
        data class Login(val token: String) : State()
    }
    
    abstract val state: MutableStateFlow<State>
}

@HiltViewModel
class LoginViewModelImpl @Inject constructor(
    private val loginUseCase: LoginUseCase
) : LoginViewModel() {
    
    private val _state = MutableStateFlow<State>(State.Login("")
    override val state: MutableStateFlow<State>
        get() = _state
	
    suspend fun login(email: String, password: String) {
        loginUseCase.login(email, password)
	    ...
	    .onEach { response ->
	        _state.value = UiState.Login(response.token)
	    }
	    ...
    }
}

// Previewに表示するためのモッククラス
class FakeLoginViewModel : LoginViewModel() {
    override val state: MutableStateFlow<State>
        get() = MutableStateFlow(
	    State.Login("Fake Success! UseCase will return login token.")
	)
}

Preview

@Preview
@Composable
fun PreviewLogin() {
    LoginScreen(viewModel = FakeLoginViewModel())
}

Previewの表示結果

FakeLoginViewModel で記述したテキストがPreviewに表示されている!

補足

今回は abstruct class で実装しましたが、場合によっては interface でも良いと思います。

Discussion