https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
n

nrobi

09/03/2020, 9:26 AM
One of the issues we’re facing when migrating to KMP is that we have *VM*s loaded with 🤖 resource ids. While making a Resource abstraction seems okay at first, using
ApplicationContext
won’t work with all kinds of resources, while view specific
context
would probably cause leaks. How are you guys approaching this?
j

Javier

09/03/2020, 10:58 AM
I think you shouldn't use Int there because that concept is pure Android, maybe other platforms use String. And using context there can be a problem: https://medium.com/androiddevelopers/viewmodels-and-livedata-patterns-antipatterns-21efaef74a54
1
Shouldn't be easier just using domain in ViewModels and map to UI in the UI layer so you can share your VM in all platforms
n

nrobi

09/03/2020, 11:14 AM
Well it depends, I think it sounds reasonable to do the mapping to
UiModels
in the VM, which the View just “renders” (we currently do this directly from databinding or in the fragment/activity). At that point in order to make the VM platform agnostic you’d need some kind of ResourceMapper as I see it
a

alex009

09/03/2020, 11:17 AM
j

Javier

09/03/2020, 11:28 AM
@alex009 using moko resource in the ViewModel will have the same problem no?
@nrobi the problem is if you are using the context in the ViewModel and you exposes the string and not the ID, if the user change the language or rotates the screen (having differente string for landscape), it will not update the string
n

nrobi

09/03/2020, 11:32 AM
@Javier yepp, we’re using ids only, but that’s still android specific
j

Javier

09/03/2020, 11:33 AM
Yeah, but if you starts to expose Strings from the ViewModel, you can have problems if locale changes, I don't know if there is a solution to avoid this problem without moving the mapping to the UI layer
n

nrobi

09/03/2020, 11:33 AM
moko-resources look promising though, I guess if you plan on using it directly from databinding, you’ll have to write your own
BindingAdapters
, right @alex009?
j

Javier

09/03/2020, 11:34 AM
But it should have the same problem if you are using it inside
AndroidViewModel
👍 1
a

alex009

09/03/2020, 11:35 AM
In moko-mvvm already exists all required adapters :)
😍 1
n

nrobi

09/03/2020, 11:35 AM
Niice 🤩
s

streetsofboston

09/03/2020, 1:13 PM
We approach it something like this. Common Code: commonMain has these types:
Copy code
/**
 * Provides all the exposed resources as platform-specific values.
 */
interface ResourceProvider {
    /**
     * Provides all the exposed [StringResource]s.
     */
    val Strings: Strings

    /**
     * Provides all the exposed [PluralResource]s.
     */
    val Plurals: Plurals

    /**
     * Provides all the exposed [ColorResource]s.
     */
    val Colors: Colors

    /**
     * Provides all the exposed [ImageResource]s.
     */
    val Images: Images
}
Copy code
/**
 * Represents a string-resource
 */
expect class StringResource

/**
 * Wraps a [StringResource] around a plain [String].
 */
expect val String.asStringResource: StringResource

/**
 * Represents a plural-resource
 */
expect class PluralResource {
    internal val quantity: Int
}

/**
 * Represents a color-resource
 */
expect class ColorResource

/**
 * Represents an image-resource
 */
expect class ImageResource
Copy code
/**
 * Provides all the exposed resources for this shared common module.
 * E.g. val uiMsg = Resources.Strings.WelcomeMessage
 */
internal val Resources: ResourceProvider get() = Application.resourceProvider
commonMain then defines the actual Resources it needs for its common code: E.g.
Copy code
interface Strings {
    val WelcomeMessage: StringResource
    fun FullName(first: String, last: String): StringResource
    ...
}

interface Images {
    val AppIcon: DrawableResource
    ...
}
Common `actual`s: The androidMain and iosMain will the create the
actuals
for the
StringResource
,
DrawableResource
, etc. Android will wrap `Int`s as resource-ids; iOS will wrap `String`s as dict-keys. Platform Code: The actual Android
app
(Java/Kotlin) and iOS
iOS
(Swift) modules will provide and inject (Koin) the actual implementations of the
ResourceProvider
interface and assigns it to the
Application.resourceProvider
.
a

alex009

09/03/2020, 1:16 PM
Very close to moko-resources. But in moko all expect and actuals generated by gradle plugin
d

darkmoon_uk

09/04/2020, 3:00 AM
This touches on why I think MVP with Persistent state, may become preferable over MVVM. The distinction starts to get subtle; but ViewModels - by their nature - are very prescriptive about how something should be viewed. That's okay for iOS and Android, platforms that share the same form-factor with a touch interface... but becomes a barrier to fulfilling Kotlin Multiplatform's potential to reach across Desktop and Web. On those platforms you'll still have similar UI elements to support your user flows (Presentation), but the on-screen structuring of those elements and their resource demands may differ. Keeping resource definitions confined to platform specific View layer reduces the complexity here.. Enums of possible visual states in the Presenter which get optionally mapped to a resource in the View feels like the way to go. Completely understandable if a Mobile-only project doesn't care about any of this; but recent experience with Kotlin/JS has shown me that with some consideration to the above, it's possible to treat development for the browser like another rich Application client - an exciting prospect.
3 Views