ursus
02/18/2022, 1:27 PMLukasz Kalnik
02/18/2022, 2:02 PMursus
02/18/2022, 2:08 PMLukasz Kalnik
02/18/2022, 2:17 PMSong
, Author
and Podcast
be mixed together? I.e. are they displayed in the UI within one list in a mixed fashion?Podcast
for both apps. So what that the other app doesn't use it?Song
, Author
and Podcast
all from one data source (API call, database query)?ursus
02/18/2022, 2:21 PMwhen
etcLukasz Kalnik
02/18/2022, 2:21 PMViewModel1
and ViewModel2
where you inject CommonViewModel
(which is the part where UI logic is really identical, and not only similar)ursus
02/18/2022, 2:26 PMLukasz Kalnik
02/18/2022, 2:26 PMursus
02/18/2022, 2:27 PMLukasz Kalnik
02/18/2022, 2:27 PMursus
02/18/2022, 2:28 PMLukasz Kalnik
02/18/2022, 2:28 PMursus
02/18/2022, 2:29 PMLukasz Kalnik
02/18/2022, 2:29 PMSong
and Author
typesSong
and Author
Song
and Author
, and then a second call to get Podcast
.
Data is combined inside your domain layer.Song
, Author
and Podcast
. Then you cannot share anything.ursus
02/18/2022, 2:31 PMLukasz Kalnik
02/18/2022, 2:31 PMIf in reality the types don't go together, why should they belong to the same hierarchy?Reality = description of your business case
ursus
02/18/2022, 2:32 PMLukasz Kalnik
02/18/2022, 2:32 PMursus
02/18/2022, 2:33 PMLukasz Kalnik
02/18/2022, 2:33 PMursus
02/18/2022, 2:41 PMsealed class Item
data class DateItem(val timestamp: Long) : Item()
data class ActivatePushItem(val processing: Boolean) : Item()
object NonDefaultSubscriberItem : Item()
data class MessageItem(val message: BusinessMessage) : Item()
list looks like
ActivatePushItem
DateItem
MessageItem
MessageItem
MessageItem
DateItem
MessageItem
MessageItem
api usage
ViewModel.items: Flow<List<Item>>
fun ViewModel.messageClick(message: BusinessMessage) {
navigator.goToDetail(message.id)
}
--------
appB wants to add
data class PromotionItem(...)
list looks like
ActivatePushItem
PromotionItem
PromotionItem
DateItem
MessageItem
MessageItem
MessageItem
DateItem
MessageItem
MessageItem
Lukasz Kalnik
02/18/2022, 2:44 PMItem
is presentation (view) layer hierarchyItem1
and Item2
hierarchy for both appsursus
02/18/2022, 2:51 PMLukasz Kalnik
02/18/2022, 2:52 PMursus
02/18/2022, 2:53 PMLukasz Kalnik
02/18/2022, 2:53 PMPromotionItem
how do you deal with this in AppA?ursus
02/18/2022, 2:55 PMfun ItemMapper(
subscriber: LoadedSubscriber?,
messages: List<BusinessMessage>,
notificationMethod: BusinessNotificationMethod?,
pushActivating: Boolean
): List<Item> {
if (subscriber == null) return emptyList()
val showSettings = subscriber.default && notificationMethod == BusinessNotificationMethod.PUSH
val items = mutableListOf<Item>()
if (!subscriber.default) {
items += NonDefaultSubscriberItem
} else {
if (notificationMethod == BusinessNotificationMethod.SMS) {
items += ActivatePushItem(pushActivating)
}
var previousDate: LocalDate? = null
for (message in messages) {
val date = message.timestamp.toLocalDateTime().toLocalDate()
if (previousDate == null || !date.isEqual(previousDate)) {
items += DateItem(date.atStartOfDay(TIMEZONE_SLOVAKIA).toInstant().toEpochMilli())
}
items += MessageItem(message)
previousDate = date
}
}
return items
}
fun ItemMapper(
subscriber: LoadedSubscriber?,
messages: List<BusinessMessage>,
notificationMethod: BusinessNotificationMethod?,
pushActivating: Boolean,
promos: List<Promo> <------------------------------------------------
): Triple<List<Item>, Set<BusinessMessage.Category>, Boolean> {
if (subscriber == null) return tupleOf(emptyList(), emptySet(), false)
val showSettings = subscriber.default && notificationMethod == BusinessNotificationMethod.PUSH
val items = mutableListOf<Item>()
if (!subscriber.default) {
items += NonDefaultSubscriberItem
} else {
if (notificationMethod == BusinessNotificationMethod.SMS) {
items += ActivatePushItem(pushActivating)
}
for (promo in promos) { <------------------------------------------------
items += PromoItem(promo.id, promo.title etc) <------------------------------------------------
}
var previousDate: LocalDate? = null
for (message in messages) {
val date = message.timestamp.toLocalDateTime().toLocalDate()
if (previousDate == null || !date.isEqual(previousDate)) {
items += DateItem(date.atStartOfDay(TIMEZONE_SLOVAKIA).toInstant().toEpochMilli())
}
items += MessageItem(message)
previousDate = date
}
}
return items
}
Lukasz Kalnik
02/18/2022, 3:28 PMPromoItem
AppB -> with PromoItem
shared library for data access and conversion -> with PromoItemDto
.ItemDto
ItemDto
to its UiItem
hierarchyPromoItemDto
and converts ItemDto
to its own UiItem
hierarchy (without PromoItem
)ursus
02/18/2022, 3:32 PMLukasz Kalnik
02/18/2022, 3:35 PMursus
02/18/2022, 3:37 PMLukasz Kalnik
02/18/2022, 3:38 PMursus
02/18/2022, 3:38 PMLukasz Kalnik
02/18/2022, 3:38 PMList<BusinessMessage>
to List<Item>
appending to mutable Listmap
ursus
02/18/2022, 3:40 PMLukasz Kalnik
02/18/2022, 3:41 PMgetMessages()
in AppA and getMessages()
and getPromos()
in AppBursus
02/18/2022, 3:42 PMLukasz Kalnik
02/18/2022, 3:45 PMMessageOrPromo
ursus
02/18/2022, 3:45 PMLukasz Kalnik
02/18/2022, 3:45 PMItemDto
is not needed hereursus
02/18/2022, 3:46 PMLukasz Kalnik
02/18/2022, 3:48 PMursus
02/18/2022, 3:52 PMLukasz Kalnik
02/18/2022, 3:53 PMDateItem
, MessageItem
and PromoItem
) into separate convertersursus
02/18/2022, 3:53 PMLukasz Kalnik
02/18/2022, 3:54 PMUiItemA
and UiItemB
hierarchiesursus
02/18/2022, 3:55 PMLukasz Kalnik
02/18/2022, 3:55 PMMessageItem
doesn't have to be part of any sealed hierarchyursus
02/18/2022, 3:56 PMLukasz Kalnik
02/18/2022, 3:57 PMColumn
ursus
02/18/2022, 3:57 PMLukasz Kalnik
02/18/2022, 3:57 PMursus
02/18/2022, 3:58 PMLukasz Kalnik
02/18/2022, 3:58 PMursus
02/18/2022, 3:58 PMLukasz Kalnik
02/18/2022, 3:58 PMursus
02/18/2022, 3:59 PMLukasz Kalnik
02/18/2022, 3:59 PMursus
02/18/2022, 4:00 PMLukasz Kalnik
02/18/2022, 4:00 PMursus
02/18/2022, 4:02 PMLukasz Kalnik
02/18/2022, 4:02 PMursus
02/18/2022, 4:02 PMLukasz Kalnik
02/18/2022, 4:02 PMursus
02/18/2022, 4:02 PMLukasz Kalnik
02/18/2022, 4:03 PMursus
02/18/2022, 4:05 PMLukasz Kalnik
02/18/2022, 4:05 PMursus
02/18/2022, 4:05 PMLukasz Kalnik
02/18/2022, 4:06 PMursus
02/18/2022, 4:06 PMLukasz Kalnik
02/18/2022, 4:07 PMursus
02/18/2022, 4:08 PMLukasz Kalnik
02/18/2022, 4:08 PMursus
02/18/2022, 4:08 PMLukasz Kalnik
02/18/2022, 4:08 PMursus
02/18/2022, 4:09 PMLukasz Kalnik
02/18/2022, 4:09 PMursus
02/18/2022, 4:09 PMLukasz Kalnik
02/18/2022, 4:09 PMursus
02/18/2022, 4:10 PMLukasz Kalnik
02/18/2022, 4:10 PMursus
02/18/2022, 4:10 PMLukasz Kalnik
02/18/2022, 4:10 PMursus
02/18/2022, 4:10 PMLukasz Kalnik
02/18/2022, 4:10 PMursus
02/18/2022, 4:10 PMAnalyticsTracker.track(mesasge: Message)
Lukasz Kalnik
02/18/2022, 4:11 PMursus
02/18/2022, 4:11 PMLukasz Kalnik
02/18/2022, 4:12 PMMessageConverted
type, which is just independent typeursus
02/18/2022, 4:14 PMLukasz Kalnik
02/18/2022, 4:14 PMursus
02/18/2022, 4:18 PMLukasz Kalnik
02/18/2022, 4:19 PMAnalyticsTrackerAppA
and AnalyticsTrackerAppB
and skip the backwards mappingursus
02/18/2022, 4:24 PMLukasz Kalnik
02/18/2022, 4:26 PMursus
02/18/2022, 4:27 PMLukasz Kalnik
02/18/2022, 4:27 PMursus
02/18/2022, 4:31 PMLukasz Kalnik
02/18/2022, 4:32 PMursus
02/18/2022, 4:33 PMLukasz Kalnik
02/18/2022, 4:34 PMursus
02/18/2022, 4:35 PMColton Idle
02/18/2022, 5:10 PMWhat to do?I probably wouldn't let the two apps share a VM.
ursus
02/18/2022, 7:00 PM