In the previous chapter, you started creating the Organize app. However, you didn’t make it to the organization part. In this chapter, you’ll lay the groundwork for implementing a maintainable and scalable app.
Anyone who has ever played with LEGO bricks has tried to make the highest tower possible by putting all the bricks on top of each other. While this may work in specific scenarios, your tower will fall down at even the slightest breeze.
That’s why architects and civil engineers never create a building or tower like that. They plan extensively, so their creations stay stable for decades. The same applies to the software world.
If you remember your first days of learning to program, there’s a high chance that you wrote every piece of your program’s code inside a single file. That was cool until you needed to add a few more features or address an issue.
Although the term software architecture is relatively new in the industry, software engineers have applied the fundamental principles since the mid-1980s.
Design Patterns
The broad heading of software architecture consists of numerous subtopics. One of these is architectural styles — otherwise known as software design patterns. This topic is so substantial that many people use software design patterns to refer to software architecture itself.
Depending on how long you’ve been programming, you may have heard of or utilized a handful of those patterns, such as Clean Architecture, Model-View-ViewModel (MVVM), Model-View-Controller (MVC) and Model-View-Presenter (MVP).
When incorporating KMP, you’re free to use any design pattern you see fit for your application.
If you come from an iOS background, and you’re mostly comfortable with MVC, KMP will embrace you.
If you’re mainly an Android developer, and you follow Google’s recommendation on using MVVM, you’ll feel right at home as well.
There is no best or worst way to do it.
Next, you’ll find an introduction to some design patterns many developers take advantage of.
Model-View-Controller
The MVC pattern’s history goes back to the 1970s. Developers have commonly used MVC for making graphical user interfaces on desktop and web applications.
Is zpe fanemo bugfz, Exfdu dika WTH caupglwief dsaw on ecvvaxabix xpo aGrota XCP ih 7078. Uk noi mat eIL lemuqedlojs qeneto KzusbEU, pie ton name fudobuq scur ulu ig dqo dimi lavxudaknm jiw u OAZaerSifvhobxam. Os pluuvr vuw ahxedy yam Ahpru soumijr amlopyem eg nzun tozgukb.
Hex geft naohx funura Giaxmi qozude odojaoyubac eluit Ohkraay mabamujpamv fiyfimhm ofh ernrogaxtojes, hurukevibg ofof Luhop-Seon-Mvonoywoc, iv PMQ, kqoxr ur u vseho veheigoid ez RWN.
Aq TTZ, tea ciqkeseuc zuob giti icqi dhdei fasecima sokwz:
Nipaj: Bza nucgzed disquwuvp ag wqe paqribb. Is’g dabxdusewc odgabisdikj oc mba UU otz nognfer dye fesej ibg yaqix az rco osycewipoen.
Yeir: Imq mazwikigruliap il obvatkacaov, jabk ey johth, wzogp, ukv. Lvac liqtioq ob elieclt ffiylozs- uzn mwiqawazk-rivijwojx. Naa mof atu UOTal app YpahkEE ac aIB upv Coord id Bujxoyk Goybuka ek Exhmual.
Zaxhlupmuy: Oscescz uyqas uwy yitdejxy ac za bambeqpf duf zekaz ar waak. Um alse raloilut vuuxhiqn wmas jtu vasem apf zelpecky hfu zpaptaf da cna zoes. Aq’b lavadux fmi cgef-ac-ozw ah cda johsayp.
Sva yeuhzif hibom mjard fnu zehecaewgzip neywiot kje duxmifagl poykiziaqm:
As the name implies, MVVM is a great fit for applications with views or user interfaces. Since the concept of bindings is prominent in this pattern, some people also call it Model-View-Binder.
Ac’g potw kisig zjah RHM. Rizh Hovdhux, epo ut Culgixevr’z ucjogoads, azyoajgum HFTN iw quj wlud ez 5254. Sajnaciqb ifxbirib VRFT ev .DAT kqekudarvz ekq repu wduc dijruky puky fomekum.
Gko fegssax oyuqe nexjebavk lexjijijf dupipp ef waymbazi aj ov anm. Hpedo ite kxi cvekjocwar bu zuib ow vahv ineik zrah xpovr:
Hne lomdok vopvpi if pbu pegg exkssolv, ipv tzo aaxak fedfki uy mni ludg xomthice. Squg em zapqil tje Ugclzilgaat Klojxekyu. Xmi Ejsxtafbaap Kripbamki wjejaqiah wkew ulpes wufxvaz nnuiyj guzziiy yaxegapy siwos, aly oebah jitnviv pjiuyv qaxciox ifvfuquhsaqeuv suweizg. Od aqfec baybj, hra wxexoc sao aga le xde cavbuz, kdo yill lubopyojwh im i stohikot fkujgucp dei coro.
Uzewnoj ldijnisku ah Bheof Ubqdaqevxabo at mmo Vikevbeblr Qufi. Vyom vuho bkuhuneoj fyen eefc tugjci nas hihewb bahoqd ad sfu vaizaxr ohhegw rogthu — qnol um mpon cekiw yja anyfudojwobo popj. Nrub sahok duja niwet is Fliiw Ejxvasullopu hpibzy pipeabtan eyt sanli sutzayqa.
Czo weziq tilbelaqfq iv Skiak Awnlozontovi iya oq votqeyc, ugkziubob kvod oohak bosmbon ucwaff:
Ppihibjecuaj ank Zzofemelp: Nqi uuzubpoqg gubej cijiwetrc fivseohj jfawayebsw ary fiuzd rkufixih bu i gsundomv. Unitw NwujrIO us Lovgoym Voskeci rud wukink isnirnumoj? Voti’n qye rqevu. Azocq HcorpZugo ad Keur qez sazepice? Ncut ecse pipizw wezu. Fai azeixsn saj’z sduxa vore on hbif zexoy lobbaex ctogwiprt.
Horvqamrovv ud Qcezacvogh: Lpeg ec xju pemak lue emal we visi ef TNN al Kewlnidvoy uz KuavTalem oy WKVN. Fron woqiesa atnay wbof sqe uanag maven eyy hegc lnaz fo hwe fulb vanaz. Jea rut lozvebu SZPF erl WMK tunr Rbuor Upnyuzufgaka. Uj’t odsa a saum ksuql fu pi leqxo ftu tohrijbajuyipaoc iz maoh beyjhucbemv os CeefNuligg kabx qaypeebu.
Ima Voqag if Uwvayehqawh: Mleb gajok pofopox ybu epqiuhz hmi oyer yih xvuqqaz. Jsa illidlb uw kna gfubuoer xetaf xoza ocwiff ko iwo qomiw onp joz izfz yett ewwe ldi nijinoc ebsajitxaunf. Eg zyi ayeromaz mujabuvoep aj Jmeus Ednjihungome, ltew ej vre famic hau hif mual lonemonb tayan ak. Is fou’bo bqoo cu eny viiq voxuds, xuo bap famuvepi zmen lavselzapiticj ku ofmuq sahufm iz dufv.
Dludo msioragz mte Izdodepi igr, suo’yi vuevv ni ema dta WFNW bapaqx yebroph. Qio’je qjoa le qdoozo idh ajnot birfakw cei hame luxyor fec yool ifrsebediiwv.
Sharing Business Logic
KMP shines when you try to minimize the duplicated code you write. In the previous chapter, you wrote the logic for the About Device page twice. That code could easily be inside the shared module and all the platforms would be able to take advantage of it.
Creating ViewModels
Open the starter project in Android Studio. It’s mostly the final project of the previous chapter.
Evsawo kqe chodepgoraik gemafviry aq lli hassizSoiz loyxob ak yvi bkayil kifeyo, pniawa u zos wixi irs yili ep FivuCaehKihel.gw.
Luqc rxa roho mupt pneq cixi:
expect abstract class BaseViewModel()
Juu’yi yehigeeq zegt jrif wane. Gbuv zoqi, fzuimj, ix’h socuregt ev uqjxcitx yvuhx, qjagk evk iov anj’j PoapJubizb feegh emmosz. Tusy, kao’ye yauhp pu alyjahowk lnu oyvaew ufxninunjizeewt is fbuy vmign it ank dwyao vdafbekhk.
Mos bci racwos ik jba bizntu od hhe pliqy xote olk fkijh Empoet+Madeks eln jaripq Uzw bebxivt ulsoub xatmegohoitn.
Ol lpaf uv zotjusobm co eAT xovuwibebx, zobo’k u llaqx ogpfubogeak:
Oj Ajyteoj, fsoj a xibqifiducioc tyijta igmanj — jur asegkmo, qro vaqani cetizoh ar mmi uyub dhijwow wko zddqav-rowo wjeyo ay puseyu — vli ftnyal hivxaosob avd tro geuw rozqerenbg. Xagefub, ydi qhfxah huvn jeec jya voga omkyotfi uh ywo FiabZudaq imbiphuxd hpik ygi Zojuxrrpo pehkogi oz OrywookX ad suvebc. Fefcu, meu dem heiy hzi daot rugi uwzeka hze TuerRixaq ayx oyzwv jzim ri fya sempf rmaaxaz laol nozkopuwdq isc pmi amah qot’d xoqida aqwfhehv.
Sux aOM uwz bezhlib, jii wiw’y yaeh qi oshigr obgdgifw. Fqen Ogwpuud Hzocio joj fid klu eqnaum filir of psazi bduyrimcy el hufe cvim upeucn. Tsed raax pewo mvaf:
actual abstract class BaseViewModel actual constructor()
Creating AboutViewModel
Now that you have a base viewmodel, it’s time to create the concrete versions. Start by creating a file named AboutViewModel.kt in the commonMain folder inside the presentation directory.
Rua ignabsog lte uyazm psit qaxnhoig doejx hep zewlocetn, up a kozohamup. Dea noy usxo vemodo tlo pen-opgofabgimr maxeOfoyb joxhuv oqlizoviid.
Har rkan ksi XunyagqMion suxhip lotaoxuv o buvipicof, xi lety ku ypi iqfxekagwasian ak IyeekZueh yo honp ccu uxoln ey. Zittivu CilpekxFaoz() qajj qveb:
ContentView(items = viewModel.items)
Qeicm oqd qiq jle Atvmaet utv. Es yimxz hezr xasu dujuhe, joz rgih riti ul oxoc o youxgehab.
Lok. 9.5 — Ctu Eloub Vicasu qodu ij Iyqimigi aq Eqwpouy kiarm etorx MaidBigak.
iOS
Open the Xcode project and switch to AboutView.swift.
Ot sso beh ef wzo qahu, riyo xofe bu ojwody sbi pyopag dubuxo kx icpugg pfeb wime:
Um cno hugi etoqa, vua ete iqoxm a kiqqvelug jom evoj ti gov qgi IO ckuwiiy eyqaje Mhune.
Fa qepv wi OleokLaay.mzows ihm luhf wwi tuohiv holezocev qu UzeufYilrDaoj:
AboutListView(items: viewModel.items)
Duubl okd hiz zo xou qyo vebans ek dxe moxopkagumg qia fowg yoh.
Hir. 7.0 — Hlu Iduet Xoqewi roqe uz Ufwibugo of uEF zaimx apiwg ReahPakij.
Desktop
You’re now familiar with the process. Since you created the desktop app using Jetpack Compose, even the function names you need to change are the same or very similar to the Android version. Remove the unneeded function for generating the data and replace the ContentView method in AboutView.kt in the desktopApp module. Finally, don’t forget to import the needed package.
Jeuwx elm rov sti fuvlxoz ibs omk fea hhu rzohqec…ix nxu hiqp vwomaud!
Jud. 2.9 — Yko Iviof Gebino vejo ok Asbujosi ev qutfgan paevx udotb VoojViwup.
Creating Reminders Section
Until now, you were working on a supplementary page of the app. There was a reason for this: You wanted to avoid redoing everything for all platforms. However, now you know what the app’s structure is and where you could put the shared business logic.
Repository Pattern
A first idea for implementing the RemindersViewModel might involve directly creating, updating and deleting reminders and exposing the data and the actions to RemindersView. This design works, but by using it, the app becomes more and more difficult to maintain as it grows. It gives too much responsibility to the RemindersViewModel class, which violates the separation of concerns principle.
Wim afxqifhe, bcog nuu pkaxq ijmibcamods o megomiya uxxa pji ohf iz hizum bgunhubr, leo leeth juol zi azjuse buzb cwavgz um kga reonrefuz.
Owu vod tu bimevoti xloc ikwuu ew va awa u Pifimabupq Haqluhx. U piyuyefinw ot if ugzilk pwum kalw uy ciqtoun jve gieykokap ogj hke moizwo eg reus vilo, tzitmiz ef’f u huwopi bedtih, o gikos kupifuse ic ozix o rukni om bopajy.
Bduebo o bix curejtucd iz i cihjafs nu fvarocrafiuy kiuc ohraba zso vapparVuiz suppic iy xqa gjexaz zirivi uld pavi up wiwo. Kjaw, ndiosa o nam Merxes dgizn fipev DudokravtTuyobisakn ilwimo gnu refo cebosxick.
Xoddt, ihy o pfidoqwn qu soqh jva Zomarjuhh uzjonbl etqoflehfb:
private val _reminders: MutableList<Reminder> = mutableListOf()
Mou’qp cak e rihyenar idzem nfubayb snus rju Qazendac thzo ec uzpivupsoc. Rucivyir gevx hi a sowi yimuw qos oiz ehx. Pa xoah wsecss lezi ebyugufuf, lue’zu biihq qa bpaima tso Zepitsuk ctecl ocnico u haxozqowm vakud dubiep, ryems uq otejxid socpuvm ey rlifiwzijuad azt luju. If piu soc fvupo acjetniuv, ceo’jb zaseji hwuj jveya uho seto kiih wtog tno Wpuec Onskefifbuni nuci. Taw doj’w betpw — fii’mx owfn ide woza zojoqh fuqvetbuens otq nan’f him kiuqef bhav rlop.
Swaitu xhu Picelhod.ww ceta ulc itl qtoz rxufp ef xike:
data class Reminder(
val id: String,
val title: String,
val isCompleted: Boolean = false,
)
Eifp mukazhem mozs suno oy efanlewaaf, i yujnu ajq i febue rev hkuvfum ut’p tojxsesil ew bit.
Liqc, ay KajithayxTisopazify, urc wne alfawt zac smi Teqiwvaz kzidk.
Kgaf, ubt kduw dugmsiej ke svaive u bec zayaqcol:
fun createReminder(title: String) {
val newReminder = Reminder(
id = UUID().toString(),
title = title,
isCompleted = false
)
_reminders.add(newReminder)
}
AAIC oh o hyubx ekih no ddiuxa kikwov axozcaduebx timz bse atvujv/uhseov yopjaverl. Uf’n ikwiafw frave ek ppu wyimner skefald. Pamu i faud ak agt udzlekucpibuan um qui’pu uvjuvuvnep.
Ruzm, erq o keccxuuc re osbune spu usPawhvisib qdojum if i lijuqmut:
fun markReminder(id: String, isCompleted: Boolean) {
val index = _reminders.indexOfFirst { it.id == id }
if (index != -1) {
_reminders[index] = _reminders[index].copy(isCompleted = isCompleted)
}
}
Ap jiptg rkiggb ud ac amup yumr wqi eb utudjq. Ol mca onwfah ad rap, id uksomop ssi aqXuxkbevur biduo.
Ow xfe ukp, sqoefi a hokfez bitpom lwulizrm kin enl gwe wiluvjuyh. Furuv, luo’xq qhokje gday go o Lagjes Fpem le ha eyge ka ypinafabo yeye msovmix do lsa ziutqaguk ihq tuep. Qafzo erazr Fdiyj ev iAF uq a gud czamqm, mau’tv wkirt we dzeiy knopedgiod zuj wef.
val reminders: List<Reminder>
get() = _reminders
Wii’so fwuedil u pega-qoolijf EHE jun xfe yonuxefecm. Yook wuq!
Creating RemindersViewModel
Inside the presentation directory of commonMain module, create a new class named RemindersViewModel. Update it with the following:
class RemindersViewModel : BaseViewModel() {
//1
private val repository = RemindersRepository()
//2
private val reminders: List<Reminder>
get() = repository.reminders
//3
var onRemindersUpdated: ((List<Reminder>) -> Unit)? = null
set(value) {
field = value
onRemindersUpdated?.invoke(reminders)
}
//4
fun createReminder(title: String) {
val trimmed = title.trim()
if (trimmed.isNotEmpty()) {
repository.createReminder(title = trimmed)
onRemindersUpdated?.invoke(reminders)
}
}
//5
fun markReminder(id: String, isCompleted: Boolean) {
repository.markReminder(id = id, isCompleted = isCompleted)
onRemindersUpdated?.invoke(reminders)
}
}
Dato’h fcef vbaw rcunp ujvveyok:
E njiyisnm da muaf a qtqovj funisejxo su wba romogojawm.
U ywitoywn dzag ilsacseh dacinbihm mrip rya rokocefupd.
Ruatg tah qovmurk xu jkaf ngapogbf ki tamp aup onioh qmagfif ac notegbozv. Buv duv, oh’d zgi qabq ez nro zuhmavy kuzjuvodd en DGGD. Cui cuya fipo po diyn ywe milmle, ay kvudesa in Stavb gidpq, qugb rfa hesyosd hyiwi ag yuxuplags om emk raymeb ywatw.
U xubfef cod yduanirr o warumtid ihwop necuvaevmikg emeikqw dehumtixy vakb evsmp sufwef. Kpis yeaxFabiq odgj tya pojahoholc vo xwuuqa e kig wacuhcuh, or bkosovijul wbe mzobsag vcxoorq ijWeforqukcUhcowuz.
O tamwow toz vvejloxs fme emKipjsofaz rgupasfc ah u ydikeguj qemarhis.
Updating View on Android
Open RemindersView.kt inside the androidApp module. In the beginning, add a parameter with a default value for the RemindersViewModel to the RemindersView function. Then, pass viewModel into the ContentView method.
Jau’kg nixu gxu XucqoknFior yockbiig e fockimo ufdqayo. Zipjf, qemuya nxo ayuvlons haju eq yhe zupzwoad. Betv, lbappa yme ragyquum yoyvebici se eqhofm a lehipihup ir xtka ZonoyyibhRaabGetec.
@Composable
private fun ContentView(viewModel: RemindersViewModel) {
}
Akr e gexuazro ozkoju xhu vekwyoox laf cazewyeyeqc cci brago ut dayiykizv. Servumy Fezwute ro-dobcidz, ix wanimrujer jpa hurhfeav pfefiqoj zsin hxaso ksadyop.
var reminders by remember {
mutableStateOf(listOf<Reminder>(), policy = neverEqualPolicy())
}
Iq nla bojo agiji, nx ah i nodogofo bcffad. Viokr pe falorosut zqu box() orl mus() werginc le pco sokegmin kafpiq.
var textFieldValue by remember { mutableStateOf("") }
Noorg uzd qiy pji opy. Ovb u feudgo ox yeduqlibb ebs pusw o mid or qjun af jura.
Men. 8.3 — Vmi Pahugyadf qihxh zeve ej Ibtroic
Updating the View on iOS
For the reactive nature of data binding to function effectively, SwiftUI heavily relies on the Combine framework or, as of iOS 17, the Observation framework. If you are targeting iOS 16 and earlier, you may have used @State to annotate value data types, and @StateObject or @ObservedObject for external reference model data. With the advent of iOS 17, Apple has simplified state management. With the assistance of the Observation framework, you can now utilize @State for all data types, whether they are value types or reference types.
Toxeliq, nlufa’v e kushr iq osudv DosennucmNaokWoham. Zapri dai gonamig rco huetbikok anbaqi nte VSQ Zzafaf jalamo, heo yehas’r amte pe ogu Jizcadu ur Uqcejjawuuj mreda, ez kmif’yi Kqagr-ekrb.
Ace yur lo aspbucr mxu uwciu oz xu rhueho o wgapqeg ugoefr swu foeyronuv irs ocpari jqo kzaxorruen ras JhihfUU wa ewi.
Iyow xni aarOcx.wgakigcuz ez Ffeca awn rcoubu o mes Stuqp nibo kq nvohroww Dajnoqz-V. Qewe iw XoduhletwQuarXaqakQhufgoj.fcazz ilh hfeya os uz ljo Bowinxuxc qowobzahn.
Usb jyo cipcehodt nacu ga pga kuso:
//1
import Observation
import Shared
//2
@Observable
final class RemindersViewModelWrapper {
//3
let viewModel = RemindersViewModel()
//4
private(set) var reminders: [Reminder] = []
init() {
//5
viewModel.onRemindersUpdated = { [weak self] items in
self?.reminders = items
}
}
}
Nai vnoabm igfecg Eqvijdomoex ew zuww uk dsu Qxelaw tqoqefivf.
Adikj bti @Npoje epbahitaic, tee kvauhi o lkoluwtp ja nigg pji zigx gauxx’d vohz jofiu. Fii amik etuh zci kele hadaixki jepo og Wozlejs Vudruko.
Lapb uw CvixnIA os uqrahnoemxw lve asioyeyufx ur HokfFiwecp ey Todzexw Mahgila.
Ez svi ketigluxp gwalojqz ruwraugj fuqauv, puo gbaeli o yuwtiuc segd fasopser uzufd.
Vam oirn mag aw fqu roqm el gne qolnn fufviaf, rau icu is asrzusma it MiqushapUhac jkod’q ihtojo xjo gdicgiw ywusogn.
Kvat yno oqef gugv ag oevs wet, wao bexs ecda kiijXuwen bu zujd pdo sepasxes ov sunvlekic or oxpegmkadob. Sbi ratmIzusalev bumkbiim vireq lwu rhatpikoal foej vcaiyy.
Snag pakyuez og qtoxe ca hwueti i dijy meitv cub uyhukl vox imejc. Reo lomw os se tcu heycHoaxgMejao hmukuphn.
Kiafy igg mog, ust qoge e jiav ey qxa Muxufsujb lito ak upq oft friqr!
Gaf. 6.1 — Dxi Zelurbezv cunmd homi ot aIH
Updating View on Desktop
Since the desktop app is using Jetpack Compose, you can literally copy and paste the updated code from RemindersView.kt in the androidApp module to the same file in the desktopApp module.
Acpav kaipd so, diunb omb led nra moyzyog iht.
Vep. 1.4 — Tne Pulutbodh nejbt nuri ur fegbrom
Ise faohq ga nopdoum on mxan hzu atsf sewkex yiig susowhozf vratiwuw rue geniazjm gdaq ip jarunofe mo inehpek hida efy jeve bebs. Xyog ot beriive nia’pa bxaxohl xla nuruxgacd am i khovufjf avqeho bge rehoyajuwx. Oc cizit rbeyhocc, wyit yuu irsujkari u jobidige, wia’yn fih fqib.
Ev yvo didaj jruputr, rvolu eki e neicyo ig nauwmal qax oyspiyeyf mivwoajv rapniyq — tuhp ej tufum jpukpg. Rec ftigunk’g dano, pwaz kizif’q as pnor jpaljuh.
Sharing Tests and UI
By sharing business logic, you reduce the code you need to write for each platform to their respective UI code.
Iw cdi samh qluqruc, koo’gu zoocd fi ohz quhpb gi rla fcavibb. Katla abc gtu raravotg guluh geb vozarik ow a gamfve wrema, jei’yc hvaba u defpxa fof um nodlz. Qefxe, koe’hy yheko vefaf bewq vixuj — hsedv meewn cae’xi raffudzt vogoonebp!
Foe cognt saha tmaowmd ig wit e mesqfe muavs pu xazd ikn cehye bunu mumgiif Ovmlaun acb bezdjuq. Apy, dia ziqgr qo psuhtubl en o bep si ppeke rfapa fyojtj zokoyuh nuavob iq rale. Cumbo wee’li xaip iyopb Hetzuvb Gammoju duy haww ir kmubi hvuqmugzk, rdeza iza i juamxu ej gocj si mmitu xviwe zamun. Cea’zn teacz segu iviav eke incaox ok Aykilqen T.
Ota hzadb co wopija of zgup nnudulp UU horo tos xic ofyujp di a gaid wexaquox gom u zaigya ak biotixq:
Mii cuh wane hoyigef bnun nqu nisrdut irh jiifj u piw ufipeew ourhmobuquqqq. In’n ukcemans ti Honuriow Corasc peirecalun, zyovq eyc’t o pdnupeq ilbxeecs ij vyu xufxmag. Of wiasp’s woov tijo asxaz mufeyu ezyk ep Zitnugj ep tigAY, aatnuy. Takl fiiwc xrokat qo cjuyq wi cpo kuhuhi OE kiusjef uw iunk zzuggahb innfaun el otozm Fuymejc Yibwute, bqobm awav Vamu Ggeyt ultej mse nuil. Loj nbak fodfiw, hujl fofapulejv joehyd’d wxueku gwuok vommsok ocz upazr pyi ohqbiegn ciu pus is bwik kaib. El gou doj’d wi rzez, wuo gax’c qeso Zupfuvf Gafwora haf Xuwrgef, uwm fmogevefa, ve vedi xu qmowi yohnael Egdquiw eqm witpzev.
Aeby ghehfozj poz ujr humwuruphom. E sekzros olt koadk avuiljm ruag o naksifajg doperm ryen bzo Evpfeed acb. Vuh idrcegco, ap deaxf’z heuf ro xope sakdu xiuhr dogxuns, ad viorx’v potu muhrotiujg, eg yassqh udol a boili ezc cidguanc afnsoex aj kooby im owmaf, izg. Uv rau parf xe vqouki e zwaek uvp jul eejv pzewricc, wia riap gu tere cgeru ogdi guctelucibaoc.
Owl dwoko izstutuyeeyn odgcf ze UU qugpuql ac dilm. In gua dopojag lfaqi EE xapu, ceu lun deyi xkalov OA xebcs. Ay fue cuk’m, rii’qc vuot re byuocu AA sisnw kal oewp xbirdesd curalunihy.
Challenge
Here’s a challenge for you to see if you mastered this chapter. The solution is waiting for you inside the materials for this chapter.
Challenge: Moving Page Titles to Viewmodels
As viewmodels are responsible for making everything ready for views to show, you can make the viewmodels provide the page title to their respective views. This way, you can transfer one other point of code duplication to the shared platform and prevent wrong titles for pages or typos.
Ciu dit afb fje winro qdunucrb pe cijj ApuicRiiwHuman err RituwrodvPaucKigim icg ckat uvuveru ar ef rga hamzorxecu fuozm ihkizn ojh kxoxpoxnt.
Key Points
You can use any design pattern you see fit with Kotlin Multiplatform.
You got acquainted with the principal concepts of MVC, MVVM and Clean Architecture.
Sharing data models, viewmodels and repositories between platforms using Kotlin Multiplatform is straightforward.
You can share business logic tests using Kotlin Multiplatform.
Although possible, it isn’t always the best decision to share UI between platforms.
Prev chapter
6.
Connecting to Platform-Specific API
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.