Wansuko-cmd / Passon

3 stars 0 forks source link

編集画面のView層を作成 #21

Closed Wansuko-cmd closed 2 years ago

Wansuko-cmd commented 2 years ago

image

概要

編集画面のうち、XML等のView、ViewModel等のView層部分を作成しました

実装したところ

XML Fragment ViewModel Flow同士を組み合わせてアップデートできるような関数

懸念点

入力された文字をViewModelに反映させる方法が本当にこれでいいのかでかなり悩んでいます

現状は、LayoutTextWithIcon(custom view)からafterTextChangedを生やして、ここにリスナーを渡して対応しています。 ただ、もう少しイカした方法があるのではないかと考えています(例えば双方向データバインディング使うとか)

EpoxyのControllerで、二つ以上の引数を取るとき、片方のみ更新する方法が分かりません

例えば

class SomeClass: Typed2EpoxyController<String, Int>()

の時に

someClass.setData("Foo")

みたいに片方のみ更新したいです。

これが分からないため、現状Stateの分岐処理がEpoxyControllerの方に行ってしまっています

UiStateの管理の仕方が怪しいです 現状は以下のような感じです


//編集している部分を表す
data class EditContentsUiState(
val title: State<String, ErrorEditUiState> = State.Loading,
val passwords: State<List<PasswordEditUiState>, ErrorEditUiState> = State.Loading,
)

//全体の状態を表す data class EditUiState( //ActionBarのタイトル名 val titleState: State<String, ErrorEditUiState> = State.Loading, //編集中の部分 val contents: EditContentsUiState = EditContentsUiState(), )


編集しているときは、編集があるたびにEditUiStateのcontentsを更新して、データベースに保存するときはこのcontentsの中身を使う感じです

他にもいろいろありましたら遠慮なくいってくださるとうれしいです!
Index197511 commented 2 years ago

EpoxyのControllerで、二つ以上の引数を取るとき、片方のみ更新する方法が分かりません

ユースケースがあまりよく理解できていないので的確な答えが出せないんですが、知っている限りではできなさそうです... 例えばどのファイルのどの部分のことを危惧している感じでしょうか:eyes:

Index197511 commented 2 years ago

入力された文字をViewModelに反映させる方法が本当にこれでいいのかでかなり悩んでいます

個人的にはこれでよいと思っています! テキストが変更されたときに発火したい関数を渡すだけで、View側が関数の詳細な実装を知らないことを実現できていれば問題ないと思います!

Wansuko-cmd commented 2 years ago

https://github.com/Wansuko-cmd/Passon/pull/21#issuecomment-1041549801

例えば今までのコードだと、FragmentでStateの状態の確認、それに合わせて処理を変更・・・ということを行ってましたと思います(Fragmentで書く方がContextとかも使えて何かと都合がいいからです) こんな感じです

        launchInLifecycleScope(Lifecycle.State.STARTED) {
            indexViewModel.uiState.collect { indexUiState ->

                indexUiState.passwordGroupsState.consume(
                    success = { indexEpoxyController.setData(it) },
                    failure = {
                        Toast.makeText(
                            context,
                            it.message,
                            Toast.LENGTH_LONG,
                        ).show()
                    },
                    loading = {},
                )
            }
        }
    }

そこで今回もそんな感じで書こうと思ったのですが、それができなくて・・・

理想郷

        launchInLifecycleScope(Lifecycle.State.STARTED) {
            editViewModel.uiState.collect { editUiState ->
                editUiState.contents.title.consume(
                    success = { editEpoxyController.setFirstData(it) },
                    failure = { /*Error処理*/ },
                    loading = {},
                )

                editUiState.contents.passwords.consume(
                    success = { editEpoxyController.setSecondData(it) },
                    failure = { /*Error処理*/ },
                    loading = {},
                )
            }
        }

現実

EditFragment.kt

        launchInLifecycleScope(Lifecycle.State.STARTED) {
            editViewModel.uiState.collect { editUiState ->
               editEpoxyController.setData(editUiState.contents)
            }
        }

EditEpoxyController.kt

    override fun buildModels(contents: EditContentsUiState) {

        contents.title.consume(
            success = {
                editTitleRow {
                    TODO()
                }
            },
            failure = {},
            loading = {},
        )

        contents.passwords.consume(
            success = { list ->
                list.forEach { password ->
                    editPasswordRow {
                        TODO()
                    }
                }
            },
            failure = {},
            loading = {},
        )
    }

これだとEpoxyControllerでStateの状態を確かめる必要が出てくるため、リスナーをこっちに持ってくる必要があります Fragmentにまとめたいのですが、何かしら手はあるのでしょうか?

Typed2EpoxyControllerを継承してそういう関数を生やしてみようとしたのですが、dataがprivateだったためできませんでした・・・

Wansuko-cmd commented 2 years ago

上のやつですが、よく考えると

abstract class MyTyped2EpoxyController<T, U> : Typed2EpoxyController<T, U>() {
    private var data1: T? = null
    private var data2: U? = null

    fun setFirstData(newData: T) {
        data1 = newData
        if(data2 != null) setData(data1, data2)
    }
    fun setSecondData(newData: U) {
        data2 = newData
        if(data1 != null) setData(data1, data2)
    }
}

という感じに継承してやるとできそうです!すみません!

Wansuko-cmd commented 2 years ago

大丈夫そうですので、DBにUpdateする流れを追加したいのですが、別のPRに分けた方がいいですか?

Index197511 commented 2 years ago

別PRのほうがよいかもです!