스팀 앱 개발기 #37 - 지갑 화면 구현: WalletViewModel과 WalletFragment를 바인딩

WalletViewModel 클래스에서 스팀 지갑 정보를 로딩을 구현하였습니다. 이제 이 클래스와 WalletFragment를 바인딩하여 지갑 화면을 구현해보겠습니다.


스크린샷

지갑 화면은 아래 스크린샷과 같습니다. Wallet 탭 클릭하고요. 스팀잇 계정 입력 후, SEARCH 버튼을 클릭하면 지갑 내용이 화면으로 보입니다. 테스트로 스팀잇의 메인 큐레이터 중 하나인 @steemcurator01로 검색해 보았습니다.

IMAGE 2022-10-02 21:49:50.jpg


작업 개요

지갑 화면 구현을 위해 작업한 사항들은 다음과 같습니다.

  • AndroidManifest.xml 수정
  • String 클래스의 확장함수 추가
  • SteemitWallet 데이터 클래스 수정
  • 레이아웃 파일들에 데이터 바인딩 적용
  • WalletFragment 클래스에서 지갑 정보 읽기

AndroidManifest.xml 수정

앱과 서버를 연동하려면, android.permission.INTERNET 권한이 필요합니다. 이에 AndroidManifest.xml 파일에 아래 코드를 추가하였습니다.

<uses-permission android:name="android.permission.INTERNET" />

String 클래스의 확장함수 추가

서버로부터 받은 계정 정보 중에서 vesting share 값들은 " VESTS"로 끝납니다. 이들로부터 vest 값을 추출하기 위해 " VESTS"를 제거해야 하는데요. String 클래스의 replace 메소드를 사용해도 되지만, 가독성을 높이기 위해 removeSubstring 이라는 확장 함수를 추가해 보았습니다.

fun String.removeSubstring(substring: String): String = replace(substring, "")

SteemitWallet 데이터 클래스 수정

condenser_api.get_accounts API로부터 받은 계정 정보에서는 유효 스팀파워(보유 스파 + 임대받은 스파 - 임대준 스파)에 해당되는 vesting share 값을 주지 않습니다. 이것은 직접 계산해야 합니다. 이를 실행해주는 메소드를 SteemitWallet 클래스에 추가하였습니다.

이 외에 "0 STEEM", "0 SBD", "0 VESTS"인 디폴트 값들을 "0.000 STEEM", "0.000 SBD", "0.000000 VESTS"으로 수정하였습니다.

data class SteemitWallet(
    val account: String = "",
    val steemBalance: String = "0.000 STEEM",
    val sbdBalance: String = "0.000 SBD",
    val savingSteemBalance: String = "0.000 STEEM",
    val savingSbdBalance: String = "0.000 SBD",
    val steemPowerVest: String = "0.000000 VESTS",
    val delegatedSteemPowerVest: String = "0.000000 VESTS",
    val receivedSteemPowerVest: String = "0.000000 VESTS",
    val spWithdrawRate: String = "0.000000 VESTS",
    val spToBeWithdrawn: String = "0.000000 VESTS"
) {

    fun getEffectiveSteemPowerVest(): String {
        return try {
            val steemPowerVestDouble =
                steemPowerVest.removeSubstring(" VESTS").toDouble()
            val delegatedSteemPowerVestDouble =
                delegatedSteemPowerVest.removeSubstring(" VESTS").toDouble()
            val receivedSteemPowerVestDouble =
                receivedSteemPowerVest.removeSubstring(" VESTS").toDouble()
            val effectiveSteemPowerVestDouble =
                steemPowerVestDouble - delegatedSteemPowerVestDouble + receivedSteemPowerVestDouble
            String.format("%.6f VESTS", effectiveSteemPowerVestDouble)
        }
        catch (e: NumberFormatException) {
            e.printStackTrace()
            "0.000000 VESTS"
        }
    }

}

레이아웃 파일들에 데이터 바인딩 적용 - fragment_wallet.xml

지갑 화면을 구성하는 레이아웃들에 데이터 바인딩을 적용합니다. WalletFragment 객체가 생성한 WalletViewModel 객체가 FragmentWalletBinding 객체의 viewModel 객체로 지정했었지요. 이제 지갑 화면을 구성하는 layout_steem_balances 레이아웃과 layout_steem_staking 레이아웃에 이 viewModel 객체를 아래 코드와 같이 전달합니다. include 태그들의 app:viewModel 속성이 viewModel 객체로 지정됩니다.

<include
    android:id="@+id/include_steem_balances"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    layout="@layout/layout_steem_balances"
    app:viewModel="@{viewModel}"
    app:layout_constraintTop_toTopOf="parent" />

<include
    android:id="@+id/include_steem_staking"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="8dp"
    layout="@layout/layout_steem_staking"
    app:viewModel="@{viewModel}"
    app:layout_constraintTop_toBottomOf="@id/include_steem_balances" />

레이아웃 파일들에 데이터 바인딩 적용 - layout_steem_balances.xml

스팀, 스팀달러 값을 보여줄 텍스트뷰에 데이터 바인딩을 적용합니다. 적용 대상 뷰와 데이터는 다음과 같습니다.

데이터
text_steem_balanceviewModel.steemitWallet.steemBalance
text_sbd_balanceviewModel.steemitWallet.sbdBalance

코드로 표현하면, 다음과 같습니다.

text_steem_balance 뷰
<TextView
    android:id="@+id/text_steem_balance"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.steemBalance}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_steem"
    tools:text="0.000 STEEM" />
text_sbd_balance 뷰
<TextView
    android:id="@+id/text_sbd_balance"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.sbdBalance}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_sbd"
    tools:text="0.000 SBD" />

레이아웃 파일들에 데이터 바인딩 적용 - layout_steem_staking.xml

스팀 파워 값들을 보여줄 텍스트뷰들에 데이터 바인딩을 적용합니다. 적용 대상 뷰와 데이터는 다음과 같습니다.

데이터
text_sp_amountviewModel.steemitWallet.steemPowerVest
text_effetive_sp_amountviewModel.steemitWallet.effectiveSteemPowerVest
text_delegating_amountviewModel.steemitWallet.delegatedSteemPowerVest
text_delegated_amountviewModel.steemitWallet.receivedSteemPowerVest

코드로 표현하면, 다음과 같습니다.

text_sp_amount 뷰
<TextView
    android:id="@+id/text_sp_amount"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.steemPowerVest}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_sp"
    tools:text="0.000 SP" />
text_effetive_sp_amount 뷰
<TextView
    android:id="@+id/text_effetive_sp_amount"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.effectiveSteemPowerVest}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_effective_sp"
    tools:text="0.000 SP" />
text_delegating_amount 뷰
<TextView
    android:id="@+id/text_delegating_amount"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.delegatedSteemPowerVest}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_delegating"
    tools:text="0.000 SP" />
text_delegated_amount 뷰
<TextView
    android:id="@+id/text_delegated_amount"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{viewModel.steemitWallet.receivedSteemPowerVest}"
    android:textColor="@color/black"
    android:textSize="16sp"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="@id/text_delegated"
    tools:text="0.000 SP" />

WalletFragment 클래스에서 지갑 정보 읽기

MainViewModel 객체의 currentAcount 라이브 데이터를 WalletFragment 객체가 관찰(observe)하게 시켰지요. 스팀잇 계정이 바뀌면, 옵저버(observer)가 WalletViewModel 객체를 통해 지갑 정보를 불러 옵니다. 그러면 데이터 바인딩에 의해 자동으로 지갑 화면이 업데이트 되어 지갑 내용이 화면에 보입니다.

private val currentAccountObserver = Observer<String> {
    if (it.length > 2) {
        viewModel.readSteemitWallet(it).subscribe()
    }
}

GitHub Commit


마치며...

지갑 화면을 구현하기 위해 API 연동하고 클린 아키텍처 구축하며 리팩토링까지 하는 과정이 참 길었습니다. 이제야 뭔가 하나 해낸 듯한 느낌입니다. 그렇지만 지갑 화면이 아직 완성된 것은 아닙니다. 스팀 파워를 VEST가 아닌 SP로 바꿔서 보여줘야 하구요. 예금(savings)으로 저장된 스팀, 스팀 달러도 보여줘야 합니다. 그리고 스팀, 스팀 달러를 보내고 받은 거래 내역 보여주기도 구현해야 합니다. 블로그, 포스트 보여주는 기능도 앞으로 만들어야죠. 앞으로 해야 할 게 참 많습니다. 쉽지 않지만, 꾸준히 개발하여 사용자들이 찾는 앱으로 완성하고 싶습니다.


지난 스팀 앱 개발기

Sort:  
 2 years ago 

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.

Upvoted! Thank you for supporting witness @jswit.

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.029
BTC 57839.82
ETH 3132.70
USDT 1.00
SBD 2.43