Compose UI State With Sealed Classes

노준혁·2023년 5월 22일

https://betterprogramming.pub/managing-jetpack-compose-ui-state-with-sealed-classes-d864c1609279

https://github.com/nohjunh/Compose_SP/tree/main/UiState_Sealed_Classes


이미지 Album Demo


MainActivity

+class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            UistatewithsealedclassesTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    UiStateApp()
                }
            }
        }
    }
}

@Composable
fun UiStateApp() {
    Surface(
        color = MaterialTheme.colors.background,
        modifier = Modifier.fillMaxSize()
    ) {
        Column(
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            ContentScreen()
        }
    }
}

Album (data class)


data class Album(
    @DrawableRes val imageId: Int,
    val title: String,
    val description: String,
)

AlbumState (sealed class)

sealed class AlbumState {
    object Loading : AlbumState()
    data class Success(
        val album: List<Album>
    ) : AlbumState()
    object Error : AlbumState()
}

ContentScreen

@Composable
fun ContentScreen(
    viewModel: ContentViewModel = hiltViewModel()
) {
    val albumState by viewModel.uiState.collectAsState()

    Content(albumState)
}

@Composable
fun Content(
    state: AlbumState
) {
    Scaffold(
        topBar = {
            TopAppBar(
                backgroundColor = Color.Transparent,
                elevation = 0.dp,
            ) {
                IconButton(onClick = { /*TODO*/ }) {
                    Icon(
                        imageVector = Icons.Default.ArrowBack,
                        contentDescription = "뒤로 가기"
                    )
                }
            }
        }
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(it)
        ) {
            when (state) {
                is AlbumState.Loading -> LoadingScreen()
                is AlbumState.Success -> ReadyScreen(albumList = state.album)
                is AlbumState.Error -> ErrorScreen()
            }
        }
    }
}

ContentViewModel

@HiltViewModel
class ContentViewModel @Inject constructor(

) : ViewModel(){
    private val _uiState = MutableStateFlow<AlbumState>(AlbumState.Loading) // uiState의 처음은 Loading으로 시작 -> LoadingScreen이 보여짐.
    val uiState = _uiState.asStateFlow()

    init {
        viewModelScope.launch {
            delay(2000)
            _uiState.value = AlbumState.Success(MockData) // uiState를 Success로 바꿔줌 -> ReadyScreen이 보여짐.
        }
    }
}

val MockData = listOf(
    Album(
        imageId = R.drawable.img1,
        title = "테스트 이미지 1",
        description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor in venilamco laboris nisi ut aliquip ex ea commodo consequat. "
    ),
    Album(
        imageId = R.drawable.img2,
        title = "테스트 이미지 2",
        description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magn "
    ),
    Album(
        imageId = R.drawable.img3,
        title = "테스트 이미지 3",
        description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed diqua. Ut enim ad minim veniam, quis consequat. "
    )
)

Error Screen

@Composable
fun ErrorScreen(

) {

}

Loading Screen

@Composable
fun LoadingScreen(

) {
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Top
    ) {
        Spacer(modifier = Modifier.weight(.2f))
        Text("Loading Screen")
        Spacer(modifier = Modifier.weight(.3f))
        CircularProgressIndicator(
            color = Color.Gray,
            modifier = Modifier
                .size(50.dp)
                .padding(10.dp)
        )
        Spacer(modifier = Modifier.weight(.5f))
    }
}

ReadyScreen

@Composable
fun ReadyScreen(
    albumList: List<Album>
) {
    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        LazyColumn {
            item {
                Text(text = "Ready Screen")
            }
            items(albumList) { item ->
                AlbumItem(item = item)
            }
        }
    }
}

@Composable
fun AlbumItem(item: Album) {
    Card(
        elevation = 8.dp,
        modifier = Modifier.padding(16.dp)
    ) {
        Column(
            modifier = Modifier.padding(5.dp)
        ) {
            Image(painter = painterResource(id = item.imageId), contentDescription = "image")
            Spacer(modifier = Modifier.padding(10.dp))
            Text(
                text = item.title,
                style = MaterialTheme.typography.h4
            )
            Text(
                text = item.description
            )
        }
    }
}
profile
https://github.com/nohjunh

0개의 댓글