스팀 앱 개발기 #37 - 지갑 화면 구현: WalletViewModel과 WalletFragment를 바인딩
WalletViewModel 클래스에서 스팀 지갑 정보를 로딩을 구현하였습니다. 이제 이 클래스와 WalletFragment를 바인딩하여 지갑 화면을 구현해보겠습니다.
스크린샷
지갑 화면은 아래 스크린샷과 같습니다. Wallet 탭 클릭하고요. 스팀잇 계정 입력 후, SEARCH 버튼을 클릭하면 지갑 내용이 화면으로 보입니다. 테스트로 스팀잇의 메인 큐레이터 중 하나인 @steemcurator01로 검색해 보았습니다.
작업 개요
지갑 화면 구현을 위해 작업한 사항들은 다음과 같습니다.
- 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_balance | viewModel.steemitWallet.steemBalance |
text_sbd_balance | viewModel.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_amount | viewModel.steemitWallet.steemPowerVest |
text_effetive_sp_amount | viewModel.steemitWallet.effectiveSteemPowerVest |
text_delegating_amount | viewModel.steemitWallet.delegatedSteemPowerVest |
text_delegated_amount | viewModel.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)으로 저장된 스팀, 스팀 달러도 보여줘야 합니다. 그리고 스팀, 스팀 달러를 보내고 받은 거래 내역 보여주기도 구현해야 합니다. 블로그, 포스트 보여주는 기능도 앞으로 만들어야죠. 앞으로 해야 할 게 참 많습니다. 쉽지 않지만, 꾸준히 개발하여 사용자들이 찾는 앱으로 완성하고 싶습니다.
지난 스팀 앱 개발기
- #36 - 유닛 테스트로 구현한 WalletViewModelTest 클래스에서 공통 부분 추출하여 CommonPartOfViewModelTest 클래스 만들기
- #35 - 유닛 테스트용 WalletViewModelTest 클래스 구현 후 보이는 문제점
- #34 - WalletViewModel 클래스에 스팀 지갑 정보 읽는 코드 작성
- #33 - 추가 리팩토링: 데이터 모듈의 데이터 클래스의 필드들에 nullable 적용
- #32 - 리팩토링: 데이터 클래스 이름 변경
- #31 - 도메인 모듈에서 정의하는 데이터 클래스들이 DTO 패턴을 따르는 것이 맞는가?
- #30 - 진도를 더 나가기 전에 리팩토링 고려 중
- #29 - 뷰모델, Repository 패턴 그리고 Use Case 패턴의 관계
- #28 - Use Case 패턴 적용
- #27 - Repository 패턴 적용
- #26 - condenser_api.get_accounts API로 받은 계정 자료를 SteemitWalletDTO 타입으로 변환하기
- #25 - SteemClient, SteemService 잘 작동하는지 유닛 테스트
- #24 - API 실행을 담당할 SteemService 인터페이스 정의
- #23 - condenser_api.get_accounts API 연동에 필요한 데이터 클래스 정의
- #22 - API 연동에 필요한 라이브러리 추가
- #21 - 사용자 지갑 정보를 담을 SteemitWallet 클래스 정의
- #20 - 클린 아키텍처를 위한 모듈 구성 (2)
- #19 - 클린 아키텍처를 위한 모듈 구성 (1)
- #18 - VEST로부터 STEEM POWER를 계산하는 방법
- #17 - VEST를 STEEM POWER로 변환하기 위해 필요한 get_dynamic_global_properties API
- #16 - 지갑 내용을 읽기 위해 필요한 API
- #15 - 지갑 서브화면(WalletFragment) 레이아웃 구성해 보기
- #14 - 지갑 서브화면(WalletFragment)에서 계정 인식하기
- #13 - 프로파일 서브화면(ProfileFragment)에서 계정 인식하기
- #12 - 태그 서브화면에서 태그 인식하기
- #11 - 검색 레이아웃을 메인 화면에 적용
- #10 - 태그 및 계정 검색 레이아웃 만들기
- #9 - BaseActivity 클래스 정의 그리고 MainActivity 클래스에 적용
- #8 - BaseFragment 클래스 정의 그리고 기존 프래그먼트들에 적용
- #7 - ProfileFragment 그리고 WalletFragment에 데이터 바인딩 적용
- #6 - 태그별 검색 내용을 보여줄 TagsFragment에 데이터 바인딩 적용
- #5 - GitHub에 소스 올리기
- #4 - 하단 내비게이션의 탭 관련 클래스 이름 수정
- #3 - 하단 내비게이션 바의 아이콘, 텍스트 수정
- #2 - 프로젝트 생성
- #1 - 시작하며...
[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Upvoted! Thank you for supporting witness @jswit.