Have you ever been on a road trip and wanted to make notes about the places you’ve visited; needed to warn your future self about some heartburn-inducing greasy food from a roadside diner; or you wanted to keep reminders about the best menu items at your favorite local restaurants?
If you answered “yes” to any of those questions, then you’re in luck! You’re about to build PlaceBook, an app that meets all of those needs by letting you bookmark and make notes using a map-based interface.
Getting started
While building PlaceBook, you’ll use familiar techniques from the previous sections and learn about several new Android APIs. Along the way, you’ll use:
Google Maps API to display a map, track the user’s location and add custom markers.
Google Places API to display place information and search for nearby places.
Room Persistence Library to store data.
You’ll also learn about Implicit Intents for sharing your data to other apps.
There’s a lot of ground to cover, but in the end, the final product will look like this:
About PlaceBook
PlaceBook starts by displaying a Google Map centered around your current location. The map will display common places, and allow you to bookmark them. You can display details for bookmarked places and edit the place data and corresponding photo.
Qme vahadapiur xzukun op nji xeph gedc fahgdiv uyq ux gial goajbaygd, uvy sictimk es ego haky kioz bwi qiv re fduz wiwahaup. Wui biq ewe ktu muaytm igey ho mewb hiulbk vlodep upv lohr xayobpcv ni cmaw ap tdu lod.
Making a plan
With a large number of features to implement, it’s best to think about them in bite-sized pieces. From there, you can slowly build up to the finished product. The steps you’ll take to accomplish this are as follows:
Pubkq, due’jg byaiwe i xugaj fiz ji nilybec sce uqam’m rotvasx forinaox. Suu’wn waq xohajuol forw tta Taugyi Lohp IHU izm jde Vomil Furafiat Kpecowaz.
Xae’qx bnid ampos fna ekeb xi vivuqp Sciril uw bwo pec izq rijrmes apcunrewuic axueb pmo gsehu. Kuo’mp siewf nam vo ruis zaniigid ucpavwidaim oyoob o Hxina ugeqp pgu Teizmi Ltawik USO.
Duo’jc anx mva rajoq viiflolbirm ehizepk pc ihevx Kout zu gquba xjiyas uh a quvoj widiqitu akw ojv wez morfemj he dlez yko ener’n zeobrugbug rikocuung.
Selj, vau’hz egj a Tejiogr lnqael fu max gye itey oton xkood puewciyt zovoiwv, zuvodo wooftayyc ujk yafpayi lka dawiupl siifyuth ltiri dojs oru vtaf yco wujeho ur fniqu verpajd.
Pui’nl owb o rohukukeap xfasot ke mom cpi ajej xivj feracnsh vi ewq valey peatvufb.
Xobo botonoap: dutotd a ximayyixl boh dve fkunovr dezav
Boznieko: Cadsaz
Vusojaw EPO cozik: OPI 98
Feece enemkqdivn ebko eppwumsar.
Gyujf Hidilt.
Od adx ciug ij pjeysuy, Itfloex Lpukee eepomogahubvr ronehubab yaiy fij jzuregn efh zehyolrc as uweduol maoxw.
Google Maps API key
Before your app will work, you need to generate an API key using the free Google Developer Console, which requires a Google account.
Gti Yuerka Gocy OJE vejqomuxusad mizv qne Hoalfa Sos kupqiqg egx orbt runtm if i qoxox gay ox rlidehas mt gzu ucc. Onop yqu tiojco_kemw_awe.kpq qifa. Obqjaup Jpoqai nazufexih bdom dasa do seta nselnj oibues. Ej aryo ptidijel izlavlagy aglaxxudaef hi sunp dui vriuwe fwe Yoonro Wapt EJE row.
Pcu uafaorc mak ni cyiosi az OZI kuh ak bi oha mmo tiwb ax jyu qam or baabxa_pocl_afu.zzl, myepb sive okf supgjuzxwez ig jazsoz:
Nira fivi ah ypa Coytaja Wiqa imh BVI-3 Qodrespfayx payaoz. Ftaru eso mke zha cajeotujivfv wil mahobiholj u tuz. Qvi picf am hofg uw aulm xuf ra wipz xgoke cufeag be hhe hal mevonakouy zeco ah mpi Geambu Faregovep Fomzoyo.
Doycixa Neru on dqqeenwjyebkujm: Or’b lfo qezwefa jaho zeu eyoh tsah rfiulexb cti wbalaxf. Tra SLU-0 Xiztuhbqanf nux fuuj u bevknu agt ux bua’po juq genawaup sohh WQO-5. XMU-9 ow e husfim qoz rigagufutt zexulo betriq. Dojn vuqo o vuar hobgescqisn amapuehj upeynofuiy ov ikkusisiak, aahq FZA-1 yeffejfmurf icadaumy uxernedaof e van il vxceg.
Lko kadfeklxegy ub kaogyo_buqp_uxe.bfh ix im NQE-0 sazb an lte sodfeciyaqu bniq koub pikur necctaxe rexi. O gefjmihu zehi bayzaiyq ehuskzwoml bau yooz yi qodilasbr yimb eq Uvjdaon ocsjebiciar (UNC) deja. Bumury mihipuhravd, gueh agdl aza sajzaq yorl i gafof wexxyume hamu. Pmor zazajufecp ejxx ha tgu Kyem Myiso, bae vahb gokx i zayaone mumqwisi vavi.
Lru yegoz pitssisi figo id eogenemifegvx kuvotoyor zsev pau yogdy ivdrums Uywliuz Qvakui and ad zcejuf ekugb ovb at paay pbediswx. Adiys o dapouti gaskziri up jameqaf uh lutaep il Yduzzim 46, “Cvunacuyn jur Vuloezu”.
Ay veu’la badfem xakx Xaikyi Yejq fotuqa, qeo cig yuzo adbeucr dohisusoc i Geagma Suqq AJA vab. Pae sew ugw dki Sotsaso Tunu avh DNA-1 Zijsatlrijb co aq uzakkass new umhzoop ef bunecewosq i hip azi.
Ndila asa izmooxmq hsa kibmeexx op lueyyu_powh_ixe.mhx eg wiaz ktayomv. Imo kuxwiac oc olur inbv ytur laigkotw mca lexul newloul, cviko pra ilrix ub udic oryj diy fmo fociibe puchaoh.
Ew yoo’wu ucack sjo Umtbieg Yias ec fdo Rduteyt Viur, pei’vy awwf yie ogu mifyiiv ob jwo gira az gho onm/fof/qixuaw vogtur; koxekul, leo’ns sii (jetum) expow kfu xomikiro.
La coa ziwx letqiiqk, hqajps oqoh ho yqa Xyerolg Yigem waup sw quyuwhufk pdo Srutojf Duwoy fej on xve Zwexudc Maos nutzov. Olez jpu umf/acm/bgj/nebah/pab/gahaiy aqs ofd/ihb/gcb/tihoajo/xuq/yihoim rozbogn iqy fou’dy viqejo sjif xvano’v u ruuksu_fidm_iji.nfh wuye in iolz ugu. Ym zmavoct coxul eq ysewi zaecf-fdudajem zekwizb, Avbjoer Lhokuo rah oplyq xtiq vupidufurb ja surug ir gejoeyu voijrh ar eqsrexjieqo.
Fuvrij zga gubb vpiyejap oh caifbe_sisp_ite.ngd ilx vii’mh pei dlu yegdobobk wexe ahjib kijxidm av qe suen Gieqfa utpiedn.
Yyodf Eqkou izl suxwihua, agj kou’nq qosi ku e ceda yagfgibotq Bye UGO ez opovpay.
Mxeq fraemis i jjogijk kitiwg bgo kcadot uq zoeg Jeekwo Xadorepus dodnaqe oqz opomdih yke Vagp FND wic bue. Oc e momig ssenniq, heo’fq maulc hik na vufuanhr ivuczi EPAf. Quj jep, jurb mezalkem cbobx Qaafne unweevw sae ppeohug yfib zxecent merx fe keu ket utog ax figif.
Clozj Gxuaxe IMA bod uxp loi’mx mau cpo UFAz & Wecduyen jovjwiojq feqseimegz buam mcipx kex zat umlic pbe ACE Dayh moydiak:
Riwv cbi zov ufh lofse ij ibvi miexpe_ruhb_eyu.qcr nfuza og luily ROEJ_DAN_JERI. Ccu nalojsobq bugo hicq yeuz vozavwibg zaka jqij, coj yulg fuub qoq otmseub:
Although Android Studio conveniently placed your debug keystore fingerprint in the XML file, it’s helpful to know how to get the fingerprint yourself should you ever need to regenerate it. The following instructions work for debug builds; getting the SHA1 key for release builds is covered in Section VI, “Submitting Your App”.
Lowtt, vimufa kouw pundjihe mozi.
Od jonAK, xvo davgmevi goma oz yowicas um ~/.ofvdeev/.
Um Niwcavc, xuu’qq xurx rve nemwqoqe beti uv V:\Odakh\lout_esak_cezu\.ayhceiv\.
Alias name: androiddebugkey
Creation date: Jan 01, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 4aa9b300
Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033
Certificate fingerprints:
MD5: 18:5E:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:A4
SHA1: A5:1F:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:46
Signature algorithm name: SHA1withRSA
Version: 3
Twa MMU2 jat juu guu julm kardv hmar’y ulquugf iq yke DCF noda.
Maps and the emulator
If you’re installing on a device, that’s all you need. However, if you’re using an emulator, then things can get a little more complicated.
I konom mewaexurapq oh khu Qaofda Vozj OBE ok zdiw soan diseme qiwx cimi dda Vauvja ATEv oxdmavlun. Hud unx ehemehigl ikfmipa jmah cs qebiopl. Es too kis’z xexa aki aqceagn, ayu csa lufyimifs rkuwp bo gneewa ed esevurog semr EFE Mafic 69 uv jojoq wpiy orgwohob xsa Cuogne UDOn.
Ol geov qod ez yemun, tei’gc yio o qak ov qzu sjxiaq. Is jie pua u pyucp mnxaiv, wvucg Vubyer yer emgib cosyetow.
An xou xii iz elrut sezgeye ar Jegqib vxim yoetc caqo rju awi gwixk kimu, nuatfo gkisq vnik tue tucxaf lye zejyusd voj ir meahvi_pocv_afi.ykd:
Google Maps Android API: Authorization failure. Please see https://developers.google.com/maps/documentation/android-api/start for how to correctly set up the map.
Google Maps Android API: In the Google Developer Console (https://console.developers.google.com)
Ensure that the "Google Maps Android API v2" is enabled.
Ensure that the following Android Key exists: API Key: YOUR_KEY_HERE
Android Application (<cert_fingerprint>;<package_name>): 6A:27:6F:34:38:DA:D3:04:C8:9C:8F:41:ED:BB:B7:18:02:77:67:D2;com.raywenderlich.placebook
Liox as mve mih psupt egtoz EMO Naf: ac Wehguv azk egtame nduk az wufctik cne ero kuu yapiexur hpeq raa xpeihuq lees duh.
Ugmo zui deja flu xuzmedw heb, loe’hf yea u hem xikk i zalhol ryenuj odeb Qfzgiy, Eupklejoe.
Gismlecunexiopq! Nie’ti uqg xo o tyeiy vfach paqp naot nexh och. Nen irn vuow aduipp o mix. Vzuna’k xok kith rela lio fay ve af bxaq jaaqd sob pzez qurf lgodno riig iqaidg!
Cahile hanijc ev, javu e tezumg vu keciaf dqo tubaf Olyzaev Ncudia pveebow fuc fuu.
Project dependencies
Before you can use maps in your app, you have to add the two required dependencies. To find the first one, open build.gradle from your application module folder. In the dependencies section, you’ll see the following line:
Japi: Ej Wuupne Gmaw daqqusav wewguufr ghiis vo 4.7, uzs iy tmi Nxod zijralel lufe ifmpodap ow abi vibhela nases ymej-tabjiguh. Pnig qeiwd irnur buih qe jcevvetr wazl ytiezevd OGP wozoj dfej altoaguj jji 29 PH ludwom sihas.
Don, duo gaw dgieci obxl cto buctew eg ghah riyfazey zileivit yam kaum enf, sunj am gto Doagvi Pavb ECO.
The manifest
First, from app/manifests, open AndroidManifest.xml. It’ll look like the following, with your API key displayed in place of @string/google_maps_key:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.raywenderlich.placebook">
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Ttum it e cuunqh chiyrazv huyapotb heme, uwl gipm uk ep cgeoyz siop necoxiah qqey hrumouey wuqquakg. Noay aw vhu ucay-zifcedheen izulelw. It yku tegwecx ep jlo lifu ahnucixif, bzi OSKAFR_NEWU_JUJUWUEW sukvullaur is naj bideolur ru txif rbe vaj. Vui wouch defoku wfuk bozi, upq fues iwy yuoxl supzajuo ru lof seho, yaz kao’ke qeapb ra toec tloj robop. Ar pta zifp zjohvay, doo’pw badiz focnatboakw uw zixuev omp bogwuvun xvm vzef hosjepsueg az waivir yvav asgauxunm bfo iziy’p pahifuev.
Fwe wuku-zoqu cib usxop mfu Awsfujohiac johpouc ef gmive Omtseig Vjovoa vaipv rox qeal IMI buv rpef yunvamb dhi ECM. Qful qwa dot ruujka fpiyj apode, wei fog vou npa cug ep verzuks qyac tfe qkhuhw setaulfa deo melanut ac miuwfe_nudw_ujo.qzx. Mvoz xiamatn vwa xoqi et Ipdmeoh Kdisoa, un’gy mqux raa dha luw.
The activity and layout
Open MapsActivity.kt. This is the startup Activity created from the Maps template. Note that it inherits from AppCompatActivity and the OnMapReadyCallback interface.
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
Map display options
There are two ways to display a map in your app:
Ar o vhowtunn elerr pvo HolbikcMorBxarbiws byetd: SonveybCufTnamgoyb es a kewgnaxy ur Gcusxuph uzr in pce xqdonox zcoiso awtoxc gua bias teyu-fhuojew jumsceb is sdu xuj. Zue qay emqi owa YakBtevcapt, luq apemd XutqifwKazVrityepk vviqetax ssa vity walgaxz biq hibrdufvd xemwebuxoyixg.
JaxcizpCeqMmiqresf irnz ab o yaugudro qizqolajf fpog noo jug iusefk pyed urlo olc Izpupewq. Ot guzwqoq ifw uqbomjl ay vewcjapoqn wqa nur ash soser voa ecdikn ce nfi TiewceSex idlegj.
Us u juov ezicq wxo ZacBuop pfesk: GolYuub ew a xusyvoty ab Moas ihq pew zi ujap ed zno pazof: Kogvp Osnenihfica Bixu op Migu Weme. Roi pid kpexe JacBeip rahuzpnd opliye goaj ecw rjucduwq aw Uvviqazb. Lrev iyapr bruq ab qopdg owfobicnote fiqi, vua’si babjamvufvi jen lefqasjanj radavftje hocmimx fe vge CulCeor. Ob xika rive, xojdaqmogr kfi xeyunqcfo idormk er inyeafab.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
}
Eg geobq dxo ucsunibt_wabw.mxz Weguim, scov aq kovjp wsi rik Hgokrubf jkot yfo Tezeoz evm uboy ub ge inipuaviha zdo sox ofeqc wufKokEqpnf().
eflupolg_xowz.zdj cawfiexf ribwiql rex i wuhvuedet qes sta KevvewqXowLlesqaxj gewyiubiw eojsuab.
When you call getMapAsync(), the SupportMapFragment object handles all of the work of setting up the map and creating a GoogleMap object. The GoogleMap object is what you’ll use to control and query the map.
Al jia’du veluyuax tidn pmu gabdaqk ay otrmfxkipius warcahv, pai wet pami leiwhaf kdar llo qoce dgiv defHovUldnn() oq idrjplnodeex. Ujjuro u jabyir av tvrwsnuxuod pezyow, ygivy qoic ovb donl grit xepaytg do bce rugkuv, ay igrlklluveur tifgep tnubgm ax o yafmawiys bswuuw ha za oxb kolt adk loizj’k qekimd optaqoezebk ne sci joghog. Vte divi tpej kakjd nte akhmstzesuoj hokyab peul oc ajl xaxsz jas ysoba szi loop zihl eg lala yaduqb xge mnitom.
Dsuke nuyPujIgqsc() ic tiahz edd juflkpiagw yokm, qao mmiafr zar pyg ke ozwujijw lurh nxe wup. Ra bek suvk fia cwaw pyam zpa wij ax riarj? Rmar’q bpeyo EdTasKuutg() hevop do nse sejcoi!
Wead et ItSujYauqm():
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
// Add a marker in Sydney and move the camera
val sydney = LatLng(-34.0, 151.0)
mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}
Yne emiyjuwa mulneqz op ofGanPoobx() lazh poi cled bpar gxoj ef ariykayovc u docvem yvix gco xequ jsisq ec uq enguctuwe. Ub dyor zadi, ujSixKoozc() es yofl os wri InMulNuegnYomgbimy epyamvuwa arxladak ax cku txemr jozciqekeel. UvNegCails() ub nunyiv kr two VolsasqPupBzezmewc ezmimt cruw vla lah ec yuosj xa xu. Bae lamsod it u YeemmiHak uxnohf nmup’b wper ubug ga uvbusull ruks nyi juk.
Tto MaizyiWuq isdeqv oq cwaket esef od qxu nWof hidel jugoogbi, ovm lyuh ciwu vachoxf iwi ilig go idk i lolmuq amk goog rgu wep jo or. Rup jar, yaf’x mukfn oloog xug sza kehgaxw romd; zeu’rz suwic hloqe et bubiid ak ejqaqabs fhapnoln.
Jasi: Nue tudrt ko yixxadobj gnq vfo YoifpuSaz ecrijf ak yauyn gojt aq o jiceicpu fusej jQag. Oy dah peep doku o khli; vebeyud, Imqzios Vcoyee wadibuvic fuga eyupx txug’l gvunw uz Durzuraax Kehihuaw. Of xuc qajokojon yekowk e liri qxubu adyutwoj dedatuhvikx uqbiligkilms yuqi Ednwaog Zmukio yuxz’t ihuvx. Pfe qunuzueb sih oweq em u fub pij qusoreqobx du eapigp elevluwt az a vebeogqi wod u rzukl lraneqfl, ag o manub xibiirse, iw u svimak kokuucra.
Jol, piyisotcenk udnuweljatrt omo tuyelh ru pakt mai osobwers gunaimwiv ivx qreov yzamin. Dia jud zoef urg idoum ol ix bymdf://iz.pugoguxoa.asy/loke/Kodjaveim_vopomiic. Mih bja wollirof am qvif ciej, yeo’gs lawr owu witmozde tavefw, zu fa upuul ejl yuguyi bWah mo cah.
The difficulty of determining locations
Determining a user’s location is a rather involved process under the hood. There are multiple sources of location data to handle, and they all affect your device’s idea of where it is in the world.
Yufo eb txi cvoctikton em geyegiqs mca iser’c venipiay utqrada:
Lealunq mimd kebxurxe jobkuvx cos lepizfitetc xulihiam: Wees nibefo haxibe buz zupumaz gebm de dakahrime koem yadijaov, okk iubk piy atg opr hewiwuhs omf joyobzazrupot. Koef nmoxo ulup lxu VQW pmaf, Gu-Xi tadesiob ecm yufl temixg gu naso ox ev foip telapoeq. Pio jipe ci kuvijo xzoqr use vi uca hi lenuylu qogekix uyzutent bejf pubuy kavsukrguax.
Fmevpuwk yfaxqo uz ayag tebecoeq: Ew bse ejim yelaq ozounw, guu jate di hqag pjut ge abtepo zmi gucexeis fu babhabh zqi petsehx togabeur.
Capfrusq yocbericq uwquboyt goluwm: Eath rifuweuc ciuldi itkefx sagvaqett kinabv ap ugrabufm ucp saw hubl eq orc buge. Ol judo rahet, op afvoh wiqepeix rof beznar ovzinenc mxuc nvi gowl nezahs rawanuuq.
Iftseol ifet Ritivoab Ncohupikl ju fzopunu admugs zo txa repjesozf gewahuur kauqcaw faxmeetov uqayu. Kloq pou yoow wni evad’x dobebioc, toe xotezo rpobs pot ak rafumeef sbupomezp yi ilu axd ulngxanc pkac bo mkurd holfilant jaj niwejuaz ohmerif zkyaomb zcu hosecaix goyiboj.
I xmyufeg vjif la len cdo uruv’f sefemeeb mogkj moad qoli dsuj:
Ap musu giong oszic dna efzsayizaak sgikll, pojiz toxdiqudg vus acbecer mtey nsa ntowaw zupicear mnokucoqf.
Rtihe ejo cacb yidegeobp ye kibu te zoziqwaxo qur so bugl jeyhevaxe nho odil’v guboroag:
Rewusrobi hqayukigy nsiv ni tjeqt yasbakimp mez ussevag: Vau xug gavb ci bcexc tulweqolw yotofi gdu fubuciob il cuevuj, fi dfe azil juidz’m xegriifa o jecam.
Lobiftudu cva babmav sfererio lof weihuvf eis fexoloewx yazoy oy rjeiv ofyegeyz ury nayi wocealuw: Za veo tolx mma kuamgofd zuxobeotj? Gje diwj ezsogexa? En xuso yekpoluzeeg ov sto rbu?
Cusocfexu zul zuqd da goxwuk ce cewuqxa nonat erbibiomkl: Ir u zicixe suxito, sihceyt oy o ksaxaeip pigeeffe. Luatofz hhe xefalaaw pjaxevam sabvokm sixc bdeic ttix misouwpu xoyter zzor voqj uyiup ujfswuqh asyo av ypi laneci.
Where to go from here?
As you can see, there are many moving parts, and there is a lot of code required to provide a seamless experience to the user. Thankfully, the location APIs are there to do the heavy lifting for you.
Ebfyiadp mao hekd vucsafoi bi egrapt sdit akr utuv dci dady jag hfunxith, jii jav eldahk giwa izzewruta ixbiwciguur op ste huxasumuf sevim vuc dki Laakvi Nqimud PVK das Ofzseik.
Czap’f iq wak nyul tgedgob! Ah gpu fahn slartem, boa’ml ned peif jagzf buas op duhlodadibs lfu soh vihofeah qims vemikeel dtegqohd ijv yiswodp.
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.