Kotlin Weekly

Kotlin Weekly # -373 "Compose Settings library"

베블렌 2023. 9. 25. 02:39

9월 4주차에는 제목에 낚여서 들어갔지만 실망하고 다시 관심이 갔던 주제입니다.
https://github.com/alorma/Compose-Settings

 

GitHub - alorma/Compose-Settings: Android #JetpackCompose Settings library

Android #JetpackCompose Settings library. Contribute to alorma/Compose-Settings development by creating an account on GitHub.

github.com

 

소개

 

저의경우 compose를 쓰다 보면 항상 가장 힘들고 시간이 걸리는게 라이브러리 세팅입니다. 최근에 그래프를 그려보려고 세상 모든 compose의 그래프 라이브러리를 찾다가 모든기능이 적용 안 되는 것을 확인하고 MPAndroidChart를 사용했습니다. sdk,kotlin 버전 안 맞고, 기능 안 되고 그래서 이번 글 제목을 보자마자 호다닥 들어갔지만
앱 설정 화면 구성 간소화, 보일러플레이트 코드를 줄이기 위한 라이브러리였습니다....

 

내용

 

몇 가지 지원되는 건 없는데 코드의 간소화가 눈에 띄어서 작성합니다.

기능은

  1. Menu Link: 다른 설정 화면을 열거나, 링크를 열거나, 대화 상자를 표시하는데 사용됩니다.
  2. Switch & Checkboxes: 기능을 활성화하거나 비활성화하는 데 사용됩니다.
  3. State: 설정의 기본값을 제공하고 상태가 변경될 때 리컴포즈(다시 그리기)하기 위해 사용됩니다. 또한 이 라이브러리는 상태가 변경될 때 값이 환경설정(preferences)에 지속되도록 하는 환경설정 버전의 상태를 제공합니다.
  4. DataStore: 상태가 변경될 때 값이 DataStore 환경설정에 지속되도록 합니다. 이를 위해 PreferenceDataStore 버전과 ProtoDatastore 버전이 있습니다.

 

# 우선 메뉴링크, 스위치, 체크박스를 비교하면

라이브러리 미사용

@Composable
fun SettingsScreenWithoutLibrary() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Text(text = "Wifi", fontWeight = FontWeight.Bold, modifier = Modifier.clickable {
            // Handle click event
        })

        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(text = "Bluetooth")
            Switch(checked = true, onCheckedChange = { /* Handle switch event */ })
        }

        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(text = "Notifications")
            Checkbox(checked = true, onCheckedChange = { /* Handle checkbox event */ })
        }
    }
}

라이브러리 사용

@Composable
fun SettingsScreen() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        SettingsMenuLink(
            icon = { Icon(imageVector = Icons.Default.Wifi, contentDescription = "Wifi") },
            title = { Text(text = "Wifi") },
            onClick = {}
        )

        SettingsSwitchbox(
            icon = { Icon(imageVector = Icons.Default.Bluetooth, contentDescription = "Bluetooth") },
            title = { Text(text = "Bluetooth") },
            onCheckedChange = { /* Handle checkbox event */ }
        )

        SettingsCheckbox(
            icon = { Icon(imageVector = Icons.Default.Notifications, contentDescription = "Notifications") },
            title = { Text(text = "Notifications") },
            onCheckedChange = { /* Handle checkbox event */ }
        )
    }
}

(라이브러리에서는 checkbox를 같은코드로 두번보여주는데 오타가 아닐까싶습니다.)
간결과 일관성에서 꽤나 유의미한 차이를 보입니다.

# 다음으로 State와 DataStore를 비교하면

 

라이브러리 미사용

@Composable
fun SettingsScreenWithStateAndDataStore(viewModel: SettingsViewModel) {
    val wifiEnabled by viewModel.wifiState.collectAsState()
    val bluetoothEnabled by viewModel.bluetoothState.collectAsState()

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(text = "Wifi")
            Switch(checked = wifiEnabled, onCheckedChange = viewModel::setWifiEnabled)
        }

        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Text(text = "Bluetooth")
            Checkbox(checked = bluetoothEnabled, onCheckedChange = viewModel::setBluetoothEnabled)
        }
    }
}

 

라이브러리 사용

 

@Composable
fun SettingsScreenWithLibrary() {
    val wifiState = rememberPreferenceBooleanSettingState(key = "wifi_key", defaultValue = false)
    val bluetoothState = rememberPreferenceBooleanSettingState(key = "bluetooth_key", defaultValue = true)

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        SettingsCheckbox(
            icon = { Icon(imageVector = Icons.Default.Wifi, contentDescription = "Wifi") },
            title = { Text(text = "Wifi") },
            state = wifiState
        )

        SettingsCheckbox(
            icon = { Icon(imageVector = Icons.Default.Bluetooth, contentDescription = "Bluetooth") },
            title = { Text(text = "Bluetooth") },
            state = bluetoothState
        )
    }
}

 

이런식으로 viewmodel이 아니라 preference또는 Datastore에 저장하여 불러오는 방식이 차이가 있습니다.

 

 

정리

 

State와 Data의 경우 특히 지금이미 잘되고있는 라이브러리가 있지만 ui의 박스부분같은경우에는 특히 이러한 변화들이 모여서 더 편한 ui방식이 만들어져 디자인 구성 난이도를 xml 수준까지 올리면 정말 좋을것 같습니다. 굉장히 눈에 잘 들어옵니다.
그리고 제목에 낚여서 들어왔지만, 정말 compose를 세팅하는 폼같은 라이브러리가 나왔으면 좋겠습니다...


http://kotlinweekly.net/

 

** Kotlin Weekly **

 

kotlinweekly.net