Where to hoist state in a reusable composable that needs domain/business logic?

I have a very complex composable that is about payment. It can have multiple states (NoPaymentMethodAvailable and Ready) and have different actions (OnSubTitleClicked, OnBuyClicked, OnPaymentMethodChangedClicked).

Here are a few screens that demonstrate that:

PaymentMethods available

Change PaymentMethods (Dialog open when click on the PaymentMethod itself)

No PaymentMethods available + a SubTitle-Action

To construct this composable, some business classes are involved. Like the StreamPaymentMethods (API call(s)), GetPreferredPaymentMethod (local DB), FormatPaymentMethod (local), you name it, class.

My question is basically, where do I hoist the state for this composable?

Note: The app architecture is right now based on each screen is a Fragment that creates a ViewModel and construct a ComposableView to display things.

If I would used this composable only once I would inject all the needed classes into my ViewModel, construct a State out of it, and lets that obvserve via viewModel.state.collectAsStateWithLifecycle() (assuming the State is a Flow<State>).

But since the composable is used in 6 different screens, I obviously don’t want to add all of the needed classes in each of those 6 ViewModel and basically dublicate code everywhere.

As a first step, I extracted a new PaymentBoxManager that encapsulated all of the needed classes and produces its own state (PaymentBoxState).

But now I struggling where to add this class.

To keep the “ViewModel is the source of truth and hoisting the state” argument, I could put in each ViewModel the PaymentBoxManager and using Kotlins delegate feature to observe the PaymentBoxState like that:

// ViewModel
class AViewModel(pmb: PaymentBoxManager) : ViewModel(), IPaymentBoxManager by pmb

// Fragment/Composable
val state by viewModel.paymentBoxState.collectAsStateWithLifecycle()
PaymentBox(state)

While having the benefit of hoisting it in a longer-loving Lifecycle (the Fragment) plus “having busniess logic in the ViewModel rather than the UI”, I would have the downside of a bit more (annoying) code. Not showed here in the example, but there is also a bit of Dagger stuff involved.

Comparing to another solution a colleague suggested.
Instead of putting the PaymentBoxState into the PaymentBox composable, I could also put the PaymentBoxManager into it. The PaymentBox would basically work on their own and there is no need to put anything into the ViewModel anymore. Screens that uses the PaymentBox can simply put it to the composable hierarchie and are ready to use it.

@Composable
fun PaymentBox(pbm: PaymentBoxManager = rememberPaymentBoxManager()) {
    val state by pbm.state.collectAsStateWithLifecycle()
    // Use the state to construct the UI
}

@Composable
fun rememberPaymentBoxManager() = remember { SomeDaggerComponent().paymentBoxManager }

The benfit is cleary that I can just add the PaymentBox composable and “it just works”.
Also, since the PaymentBoxManager is a plain Kotlin object, I can also test it Android-dependency free.

However, where I’m unsure with that is the following:

  1. The PaymentBoxManager is now scoped to the composable lifecycle. It lifes shorter than the Fragment lifecycle. Being said, if I would switch the composable hierarchie (removing PaymentBox and add it again (for whatever reasons)), I would get a new PaymentBoxManager.
  2. I moved some domain logic to the UI. (Did I?) Because the PaymentBoxManager uses the domain classes like StreamPaymentMethods that doing an API call or the GetPreferredPaymentMethod that doing some DB operations, but using it inside a composable, I feel a bit of “I doing it wrong”.

So back to my question:

My question is basically, where do I hoist the state for this composable?

In the ViewModel(s) and dublicate (a bit of) code or in the composables?
Benefits and downsides are mention in this question.
Maybe there are even more I haven’t discovered yet, but I guess these are the “main issues”.

I also read the official documentation about Where to hoist state, Stateholders#business-logic, and Stateholders#ui-logic.

If I get it right, they basically recommend to put these kind of things to the ViewModel (what I second), however, there is no single word about reusing composables that requires a lot of domain/business logic.

There might even not “the correct answer”, but just a bit of brainstorming from the community would be great.

Thank you and sorry for this wall of text :).

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật