.NET MAUI for cars: Apple CarPlay Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys welcome back to the second part of the Maui Focus tutorial series we'll be finally covering Apple Core play in case you missed it in the first part I covered Android auto and set up an entire Maui project and added an Android auto project to that and this time we'll be extending that and adding the apple core play Port so I hope you're just as excited as I am so without any further Ado let's jump straight in and let me show you what we'll be building today so this is the app we'll be building today and as you can see it is running on my car I've hooked up a lot of these members to show an alert that you can easily override with your own functionality and I've implemented five different templates with the Tabor is the root template you've seen the grid and list templates now and this is the point of Interest template I mean any app just looks way cooler if it has a map on it I think we can all agree on that so as you tap on these members the icon enlarges in the map and you get some context info and lastly we have an information template with also some action buttons there that you can use to display information to a user there are more templates available but I figured these ones would provide you with the basic building blocks to get started and understand how.net Maui works with apple core play so let's get started so there are two important sets of documentation that we're going to be working from the first is the core play Apple developer documentation which I will also Link in the description below but you'll just also be able to find it by Googling Coldplay developer documentation and it's quite extensive it has quite a few categories that it covers just takes you through all the various sections of developing a core Play app so let's what a lot of this video is based on and then there's also a PDF document that Apple provides called Coldplay app programming guide which I'll also Link in the description below and this is this is basically what we're going to be following from start to end so the first thing that they mentioned here is getting your carplay app entitlement and this is probably one of the most difficult Parts about the entire process and can create a bit of a delay so you need to request entitlement from Apple before you'll be able to even run this in the simulator do you request an entitlement you can just go to this article on the Coldplay developer docs which I'll also Link in the description and then if you click on this call play contact us button they provide you with the form that you need to fill in where you have to provide a name email organization what app type you want to create so there's a couple of different options here the one that I am demonstrating in this tutorial is going to be a driving task and you have to give a brief description of your app and then tell them what specific Coldplay features do you plan to implement and then you can also provide an app store URL if it's already an app in production so if when it comes to the app type you have quite a couple of options and they explain them in a bit more detail in that PDF document that I showed you earlier which if you just scroll down a bit you will find an entire description of the various types of apps and the minimum iOS supported version so that's also something to take into consideration here that uses with all the iOS versions won't be able to launch your corplay app if you have for example a driving task app which requires iOS 16 but fortunately Apple do update the older phones as well so that helps at least and also this doesn't limit the your current user base only using the app on their phone they just won't be able to see the app pop-up on their core play system if they don't have IOS 16 but if they have for example iOS 14 you will still be able to run the mobile app so just something to take into consideration all right I've jumped over to my Mac and let's set up our environment to develop or Coldplay so the first thing that you will need is the latest visual studio for Mac so I'll just also add the link in the description below and then you'll also need additional tools for xcode which contains the Coldplay simulator so I'll also add the link in the description below but if you just Google it you'll land on this page and you'll see there's an additional tools page here once you tap on that you'll have to sign in I've already signed in so it's not going to ask me again so if you just scroll down you'll see there's a couple of different versions We like looking for the latest stable release so this is still the release candidate that's a beta version if we just go down a bit here we go this looks like the latest one currently additional tools for xcode 14.2 so you can just say view details and then you can click on the download once the download is done this is basically this dot DMG if you're not familiar with it it's basically a disk image file so it mounts a drive then if you open it up this window will pop up and we want to go to the hardware folder and there we have it there's the Coldplay simulator so you can just copy this to a location that's more convenient for you I've just added it to my Launchpad so that I can always launch it quickly from there connect your iPhone to your Mac it might present you with an alert when you launch the carplay simulator that you need to accept first but if all goes well it should launch into carplay and you should see all your call Play apps well done you've successfully set up your environment for Coldplay let's get started alright so launch visual studio for mac and if you followed the Android auto tutorial you can just continue on that project otherwise you can just create a new project if you're only interested in creating a carplay app so I'm gonna hit new here just to show you that process so on this dialog we just want to go to multi-platform app and then select a net Maui app and let's continue I'm going to select.net7 and continue let's just give our project a creative name so I'm just going to call this Maui car app demo and then you can just hit create and it should create our Maui base app all right now that we've created our project the first thing that we need to do is go to platforms iOS info plast we need to add a couple of things here to even be able to run the sample application so at this point I am assuming you have created your bundle ID and created the application on App Store connect so those are the first two steps there are a lot of resources online on how to set that up so I'm not going to go into all of that detail so I'm first just going to add my bundle display name that's a string and I'm just gonna call this Maui car app demo and then I am going to add my bundle identifier and this is typically com Dot and then your publisher name and Dot your app name and then I'm just going to add my bundle version here as well which is 1.0.0.1 and then also one last one is the bundle name which is just going to be the same as the bundle display name all right so that should work also just go to properties and make sure your bundle signing identifier and provisioning profile is selected correctly which should be related to your bundle identifier if you can't find your provisioning profile you set up just go to xcode and download the manual profiles from there all right let's launch the application and just make sure the sample app is indeed running and there we go it is launched correctly and if we tap on the click me button the counter does increment all right let's get started adding carplay to this Maui app let's get started with adding the necessary items to our info p list for the carplay if we have a look again at the core Play app programming guide and we go down to page 27. they provide us some information with what we need to specify in our info plist file so I'm just going to copy this and then right click on my info p list and say open with Visual Studio code and then paste it right before the last closing dictionary tag paste it in here and you will see the formatting is messed up so I'm just quickly going to fix that this spot is broken up into two sections the first one declares your iPhone's device scene delegate and then the second one declares the carplay scene delegate this is quite important otherwise the upon launch it won't know which class to redirect the system to to display the correct delegate so this is from the official Apple documentation but the way that Maui does it is slightly different and if we have a look at the Microsoft Docs This Is How They specify how you can provide multi-window support and Maui has something specific that they've added called Maui default scene configuration and this helps a lot because this used to be quite challenging to get right in xamarin so we just want to copy this UIC in configuration name and paste it into our UI scene configuration name where phone is currently specified and then also we can just specify the class that's going to be handling this scene delegate so I'm just going to call this device scene delegate and then on the carplay side we need to replace the parts of my app with the actual apps name so I'm just going to copy it from here and then the second one we just want to remove that completely it gives us some issues if we actually specify the app's name there so that's essentially it that you need to specify on your info p list for carplay so make sure you save this otherwise the changes won't reflect on visual studio so if we reload this info p list in Visual Studio you'll see we now have all of this information in here as well great so let's get started with adding our device scene delegate class this will be what the user will see when they launch the app from their phone if you don't create this class the app will just be a blank screen on your phone so I'm just going to say new class and call this device scene delegate dot CS and we're going to need a using here called foundation and you'll see that why in a second so this device scene delegate needs to inherit from Maui UI scene delegate and this is the powerful part that we didn't have in xamarin and I had to jump through hoops to try and get that to work and then we want to register this class for with a specific name so I've seen that Maui and xamarin sometimes assigns random grid names for classes in the background if you don't specify a explicit name so this is just so that info plist can find this class and there we go so if you don't have the foundation using it won't know what this attribute means so that is the device scene delegate and next we can create our core placing delegate but before we get to that we need to add an entitlements.p list to add the driving task entitlement so right click on the iOS folder and say new file and this is an XML file that we need to add and we're going to call it entitlements dot P list and just hit create and let's open this in vs code as well so if you go to the Microsoft documentation the iOS entitlements documentation they provide you with our entitlements.plist file should be set up so you just paste that in here and make sure you save this file and then if we reload this entitlements.plist at visual studio now knows what this is the entitlement we want to add is the driving task app so if we just quickly go back to the core app programming guide and just go back to the different types of core apps and we want to be adding this developer Apple Driving task so we want to add a new entry here and then in here just paste that entitlement the types should be a Boolean and the value should be yes great now that we've added our entitlement you also want to go right click on your project say go to properties under bundle signing make sure you navigate here to your entitlements.plist file so that it knows where to find the file all right great let's create our car placing delegate class so right click new class carplay scene delegate dot CS and hit create so we need to add a using for call play so just type using carplay and then you will be able to inherit from CP template application scene delegate again this is from the Apple Docs and we want to add a register for this class as well so add the using full Foundation and then register and just throw in the classes name in there okay great so if you have a look at the programming guide again and you go to the actual code that they give you there are two classes that we need to override for this to work the dead connect and the dead disconnect classes this code is in Swift but we're just going to translate that to C sharp so go in here start typing override and did connect and we want to choose the first option here we don't need the CP window and just let the autocomplete finish that for you and the same thing with the did disconnect class select the first one of the two now what we need from this is specifically is the interface controller so let's create a private member to keep or keep context of that member and then in the dead connect class we just want to assign it and in the did disconnect we want to dispose it okay great we are making really good progress but if you try and launch the app at this point it will crash because we not setting a root template yet in our Constructor we want to create our first root template so which is going to be a tab or template so let's create a private CP tab or template this is going to contain all our other templates and display them in a tab layout so let's just call this tab bar template and just going to say new CP tab or template in our Constructor it has a couple of overrides you usually don't want to use the NS code one that's usually the other one so it's the CP template array that we want to create here new CP template array and this is going to contain our other templates and then in our dead connect we want to set this as our root template so interface control Dot said root template all right then just specify the tab or template there and as the second parameter should it be animated yes because it looks prettier and there you have it but we still need to specify a template inside our tab or template so let's create a empty grid template so CP grid template I'm just going to new of it here as well and this is expecting a title and some grid buttons so the title is just going to be hello world since at this point this is our hello world message and then also just a empty grid button array you would expect hello world to display but if you don't set a tab image it won't show so you have to also specify a tab image and we are going to use the SF icons from Apple that's included when you create a iOS Maui project if you go to this website hotpot.ai free SF icons and you filter by Asif icons I'll also provide the link in the description below it gives you the entire list of Asif icons that you can use and we are looking for something that looks like a grid so let's just type in Grid and then let's just choose this one once you click on it it will copy the name for you so we can go back to visual studio and say UI kit dot UI image dot get system image and it's expecting a string so we can just paste our image in there great this is looking good and then we can just specify our grid template inside the list of CP templates for the Tabor template now you'll notice there's quite a lot of warnings going on here it's telling you that some of this code is reachable by for Mac Catalyst and some other things but this is actually a non-issue because it won't even show up on carplay if you're not on the right iOS version so but to get rid of some of these issues we can just add a using system dot runtime Dot versioning and then we can add some attributes so just say supported OS platform is iOS 16.0 and this needs to be in quotes because it's a string and we have unsupported OS platform which is Mac OS another unsupported so I'm just going to copy this which is my castle list and that got rid of some of the warnings that we soul but some of them will still remain but you can safely ignore these ones alright let's run this and see what it looks like remember to unlock your iPhone and launch your carplay simulator and there we go it looks like the app popped up on carplay let's see if we tap on it and there we go hello world fantastic that is very exciting I hope you're as excited as I was the first time I saw this working on carplay but well done you've come a long way and I think you can pat yourself on the back for getting this far already but let's extend this application a bit further and add some content to our template all right so let's start populating our grid template with grid buttons so let's create a private method to build our grid template and it's going to be returning a CP create template and we want to save this variable and then we can move all of this out of the Constructor and we want to return this and in the Constructor we want to use this private method to build that so our grid template is looking for some grid buttons in an array but I'm rather going to be using a list since I can then dynamically add them so let's create a list of CP grid buttons called created buttons and say new list of CP grid button and then in a for Loop I'm going to assign them I'm not going to use a 4 each so that I have access to the index and I'm gonna add eight of these so I'm just gonna go through them and say grid buttons dot add the same new CP grid button and if we have a look at the overload the first thing that it needs is title variants so title variance is essentially a list of strings from of varying lengths so depending on the screen space available carplay will decide which string to display but I am just going to specify one so a new string array and just going to say good item and let's just add that dollar sign and say I plus 1 since we're starting at zero then the next thing it's looking for is a UI image so I want to display our from our shape projects resources the dotnet bot SVG here so to do that I can just say UI kit dot UI image Dot from bundle and then specify a string year for the name without the file extension so just say dot net underscore bot and that should add our image and then the last thing it's expecting is a Handler that should be called when the button is pressed but for now I'm just gonna leave that blank so it's gonna say action it's expecting a action parameter and just use it empty Lambda for now and there we go so we've added our eight grid buttons now and then we can just add them here to the CP grid template all right it's throwing an error because it's expecting an array so just say dot to array and that should go away great let's quickly run this and just see what it looks like alright there we go so we have our grid items here currently they don't do anything if we tap on them but we'll later add that Handler so let's add our other three templates the list template the points of interest template and the information template okay before we create our list templates let's just rename this grid template title grid template that we can identify them easier and then let's create a private CP list template and then add that to our Tabor template and in here we are going to in the Constructor we are going to build it so let's just create another private method for that CP list template this is going to be build list template and so we want to have a VAR list template equals new CP list template and if we look at its Constructor it is looking for a title and some sections so the title I'm just going to say list template and then we can create some sections for it but before we get to that let's just also add its icon it's tab image so again UI kit dot UI image dot git system image and this time I'm going to use the list Dot Dash icon from the SF symbols Library and we want to return this list template we can now build up the sections so it is expecting an array of CP list sections so it's to say VAR list sections equals new CP list section so I'm just gonna create an array here and inside it I'm just going to say new CP list section and let's see what this needs so it needs some ICP list template items uh header text and a section index title so we are going to create the list items but first let's just add the header strings along so this is going to be section one and it's section index title I'm just gonna mix Section 1 index title and let's just copy that and create another section so basically this list is going to be broken up into two sections as you saw in the demo at the start so this is expecting items that implements an interface of ICP list template item so section one items section list items one equals new list of these guys and also the same thing for our second section then again I'm just going to build this in a for Loop so VAR I equals zero again not using four each so then I have the index parameter let's just create our list buttons here so the CP list item implements that interface so we can add that to that to this list and what it is expecting is some text let's just say list item I plus one because we're starting from zero and then it's looking for some detail text and I'm just going to say for the detail text section one list item and then lastly we can also specify a image for this list item so again I'm just gonna use that.net bot that we used in our grid template just going to copy it from here paste it in here just add the semicolon then we just need to add the list button to our actual list say dot add and throw in that list button there so we can do the same thing for the second section just updating the updating it's it's referencing the second sections items and then we can pass through these lists to the list sections and again this needs to be an array so just say.2 array and the same thing for the second one and then finally we can pass through the list sections to the list template so that's quite a helpful but I think it does make sense if you go through it slowly and we assign this there you go all right let's see what that looks like and there we go we can see our list template arrived there the first section is over here and the second section with each with their own four items currently if you tap on them some loading spinner will kick off and the app might crash because we have not implemented anything to handle the ontap handlers and if you look at the code there was there's no Constructor that allows us to provide a Handler but you can provide a Handler by saying list button this should not be plural list button dot Handler and then you can specify a Handler but we'll get to that after we've created all the templates and there you can see the exception happening okay now we can implement the point of Interest template so this is where it starts getting interesting so let's create a private CP point of Interest template say POI template and then let's add that one as the third template in our tab or template and here we are going to assign it in our Constructor so let's again create a private method to build that template gonna be a CP point of Interest template let's call this build POI template all right so let's say VAR Boi template equals new CP point of Interest template and let's see what it's looking for it's looking for a title some points of interest and a selected index so the title I'm just going to call it POI template then the points of interest we are going to specify still and then the selected index is an integer that keeps track all the selected index so I'm just gonna create a private keep track of that selected POI and then we can provide that guy over there so the point of Interest template basically provides you with a map and some points of interest so we're going to say VAR points interest and start building up that list so it's a new list CP point of Interest and then we can start creating that actually this doesn't need to be a list because we're not building it not gonna build it dynamically so let's just make this an array okay so new CP point of Interest and let's see what it's looking for so it's looking for quite a lot so the first thing it's looking for is a location create that new map kit Dot MK map item and then this in turn is looking for a map kit Dot MK placemark and then this is looking for a core location dot CL location coordinator 2D and then we finally have our latitude and longitude coordinates that we can provide so let's go to Google Maps and find a location to plot so there is this place in Nigeria called subscribe now so I'm going to be using this which is in no way supposed to be a subliminal message but in all seriousness if you are enjoying these videos please feel free to subscribe so if you right click on a place in Google Maps a little menu appears and you can just click on the GPS coordinates right on the top of the menu and then just paste it into where we need to provide the coordinates and it's already comma separated so that's nice so next thing we need to specify is a title for the point of Interest so I'm just going to call that subscribe now and the subtitle is for more great tutorials I get this feeling this place in Nigeria suddenly gonna get a lot of internet traffic and they're gonna wonder where this is coming from and for the summary I'm just gonna say hit the like if useful so it's a lot of info so all of these these top three ones are on the upper page and then once you've hit the the detail context view these are on the next one the detail title and subtitle and summary so then I'm just going to say thank you and I'm going to hope you find the videos helpful and then finally a detailed summary we can just say many more tutorials wow okay last thing we need to specify is our pin image I'm going to use a system image UI kit dot UI image dot get system image and just going to use the video icon on the SF icons library and then I think we're still looking for a closing bracket yes there we go so we have our first point of interest and we can now specify these points of interest in this list and then also return our POI template and use this method to build our point of Interest templates in our Constructor but let's just add two more points of interest to make it a little bit more interesting let's just search for another place nearby on Google Maps in Nigeria so next I am going to add maybe there's a school or something close by it's a high school so right click on that copy the coordinates paste the code and it's in here and this is just gonna be school I'm Gonna Leave the other text as is don't worry and then this one I'm just gonna use the book icon and let's just add one more point of Interest see if we can find a shop change the name to shop and let's just have a quick look here there's a market it seems you can use this one there we go and then just paste that in here and this time I'm going to use the cart icon for that all right let's launch this and see what it looks like and we never specified the icon for the tab so that always defaults the title to more and three dots so we just need to fix that but our point of Interest template is working and we can see our map with our three points of interest and just as we set it up if you hit the Subscribe now then it says thank you I hope you find the videos helpful many more tutorials coming so and as you tap on the others they enlarge on the map the icons and the same text is displayed because we didn't change the text for those ones okay great one more template to go and then we can add the action handlers okay before we get started with the information template let's just add that icon to our point of Interest template so that it displays the right title and icon the next time we run it so I just say tab image equals a UI kit dot UI image dot get system image and we're going to use the pen icon to symbolize our point of Interest template okay let's add our information template the last template on this application so it's going to be CP information template there's a lot of other templates available I just chose these five with the turbo template included so you can go and explore what else is available so it's info template and that equals and we're going to build our template there and we're gonna add it to our tab bar template as our fourth one and let's just create a private method to build that template so it's going to return a CP information template about info template and then we're just gonna save our info template equals new CP information template and let's have a look what we have available here so we have to specify title again so it's going to say info template then we can place a file layout we have the options between leading and two column so that's just each item will either be above each other or next to each other the title and the information so I'm just going to use two columns so you can see what that looks like then we have to build up our CP information item array and then lastly we can specify some actions I'm just going to leave these actions blank for now so it's also just going to be CP text button an empty array of this for now and before we forget let's add our tab image as well so this time it's going to use UI kit dot UI image dot get system image and this time I'm going to use the info dot Circle dot fill icon and then we can just return this info template and we can use this in our Constructor to build our info template accidentally Auto completed something wrong there we go much better alright so let's just build up our information items we're just going to say our info items equals new CP information item all right and then we can just create them here's a new CP information item and then let's have a look what we have title and detail so this is gonna say hi there and for the detail I'm gonna say here is your detail message and let's just add a couple more of these so say for example you have a grocery list App I'm just gonna make this title groceries and these are the groceries you need to remember to buy when you go to the store so it's gonna be milk some bread and some sugar and then we can just add these info items to our information template great let's run this and see what it looks like all right we're launching the app we can see our point of Interest template title and icon is now displayed correctly and then on our info template we can see the two column layout that we set up and we have our groceries that we need to remember awesome so we have our four templates inside our turbo template so let's add some actions to when we tap on the grid items or the list items and I'll also add some action buttons at the end of the info template all right so we want to display an alert every time we tap on one of those items and then you can easily hook up your own logic there that you want to do when a user Taps on one of your buttons so let's just create a private method to build our alert first so we're just going to say private CP alert template and just call this one build alert template all right and then we're just going to return a new CP alert template and let's have a look what we have available so again title variants for our alert and then we can have multiple actions action buttons on an alert so for the title I'm going to pass through a parameter so let's add a string message here so then we can pass that through as our title variant I'm just gonna this and then the CP alert action it's also going to be a new array and we're gonna add a new CP alert action all right let's see what we need to specify here we need a title so I'm just going to call this button this mess oh it just kind of dismissed the alert and then we can specify a CP alert action style so if you look at the autocomplete options we have a default a cancel and a destructive so I'm just going to use the default one here and then lastly we need to specify an action so you have to provide an action parameter and you can use a Lambda expression and then we can just say we can use our interface controller to dismiss this template again and we want this to be animated so it's just like a fancy pop-up and pop down yes I do want that and then we're just missing a semicolon there we go so we have a method that's building an alert it's gonna pop up with our message and have a button that says dismissing once you click on it it's going to dismiss this alert so let's add this to our grid template first so on the action here we want to use interface controller dot resent template so just something about presenting and pushing templates you'll see this two available options here pushing templates you can basically push any of the existing templates and it will display as a new page on top of whatever you're viewing and presenting template is seen more as like showing a modal on top of your current screen one thing to note you can only present one template at a time so if you're trying to display more than one template at a time it will crash your app so maybe just building some logic in there to always dismiss any existing templates before presenting new ones and then also remember your stack depth you only have a stack depth of like three or four so your turbo templates already taking up stack depth and then the template you're showing on that so you can only push one more template on top of your current stack and then if you try and push another one you'll get an exception but fortunately the exceptions are quite extensive so it you should know why it's crashing so we want to present our template so we're just going to call our method to build alert template and we can display a message here so it just say grid item was tapped and we want this to be animated yes and then finally we're missing a semicolon and there we go so let's add it to our list template as well we don't have a Handler in our Constructor but for the list button you can say list button dot Handler to this shift equal item and block is the two parameters we're given this is from the Apple documentation that I got somewhere and we're going to call this so you have to invoke your block so basically with the list items you have some special things that you can call async data and it shows that loading spinner while it's loading the data and then you can finish your block once that's done this is just something to take into consideration there and then we just want to call interfacecontroller again dot present template and use our method again build alert template and show our message section one list item was tapped we want this to be animated yes great and we can just add this to the second section as well see this is still plural let's just fix that and this is just going to be section two list item was tapped all right and then we can just add our text buttons with the same handlers to our info template so just so far text buttons equals new CP text button array and then we can create them in here CP text button and this is expecting a title so the first one is going to be accept gonna have accept and a cancel button so we can provide a text style I'm gonna make this one confirm and then a Handler so again let's just say action as the parameter and that calls Lambda function interface controller dot present template and we're gonna use our build alert template method and inside of that we're going to specify our message and say accept was tapped then we just want this to be animated oh true okay and then we can just copy this guy for our cancel button text is gonna be cancel and the style is gonna be cancel and then we can just say cancel was tapped and then we can just add these text buttons to our CP information template and there we have it let's run this oh wait there's a semicolon missing great let's run this and see what it looks like all right let's have a look launch our carplay app tap the grid item it's grid item was tapped when you press the dismiss it goes away go to the list template tap on one of the first sections items it says section one list item was tapped you can dismiss that guy go down here tap a second section list item and the correct alert is displayed dismiss that alert we didn't change anything on the point of Interest template so all of this is still the same and then on the info template we can see this is a little bit more squashed because we added our two buttons in here so if we tap the accept it says accept was Tab and the cancel cancel was tapped so there we go well done guys congrats for coming this far and thank you for watching all the way through and yeah I would love to see what you guys are building with carplay and Android auto on Maui so please drop a comment and let me know what apps you are building so maybe we can have a demo station where I just show a bunch of videos of you guys apps if you're keen on that and yeah I hope you found this tutorial helpful all the code will be on a GitHub repo called Maui for Cores which will be in the link description below so yeah please let me know if you have any issues as well add it into the comments and if you did find this helpful feel free to leave a like or subscribe I've heard it helps the algorithm until next time there are many more tutorials coming and I'm excited to see you guys all here next time
Info
Channel: Christian Strydom
Views: 2,448
Rating: undefined out of 5
Keywords: apple carplay, dotnet maui, xamarin forms, maui for cars, maui apple carplay, car app, cross platform car app, dotnet maui tutorial, .net maui tutorial, .net tutorial, full course, .net maui full course, .net maui app, apple carplay example, apple carplay apps, dotnet maui blazor, .net maui essentials, learn dotnet maui, maui carplay, dotnet carplay, .net carplay, iOS app, iOS car app, apple carplay 2023, .NET 7, .NET 7 tutorial, maui full course, develop for cars
Id: Yg2I6NbHZp8
Channel Id: undefined
Length: 55min 8sec (3308 seconds)
Published: Tue May 09 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.