Alphabitz — Project B

Sal Aldana
21 min readJun 22, 2023

The second entry in the Alphabitz series is going to be a simple app for keeping track of books you own, or want to get. This will require connecting to an API that will provide the information on books and a way to store books locally. As with every app in this series, the goal for this tutorial is to create the same app across multiple platforms to be used as a starting point for your own project 🏗.

Note: This tutorial assumes you have some basic understanding of MVVM design patterns and data visualization methods . If this is your first trip in app development you may want to check out some intro-level tutorials and articles for Swift, SwiftUI, Kotlin, Jetpack Compose, and Svelte on Ray Wenderlich or Stack Overflow .

All the source code for all projects can be downloaded here: Bookz

Research Stage 🔎

As usual the research for this project can be broken down into two parts, the backend logic and the frontend UI. There isn’t really a lot of “logic” that is needed for this kind of app, we just need to find an API we can use for book information and what kind of storage we want to use for the data. For the UI it’s better to keep it simple again and just use simple built in layouts to show a list of available books, books that a person owns and a wishlist of books a person would want to get.

  1. For the backend side I’ll need to setup a some kind of storage system for books people own and ones they want to get. I’ll go for some of the built in options that are available, so Core Data for iOS, Room for Android and a simple Svelte-Store for Web.
  2. The second piece for the backend is find an API that can provide the data that I need. I found Google has a BooksAPI that should suffice for what I need, so following the directions at https://developers.google.com/books/docs/overview I setup an API Key for this project.
  3. For the frontend side it’s not too complicated, I would need some basic list, tables and tab layouts for all the screens. I’ll use some basic templates for each platform again just to help speed things up.

Considering there’s tons of these kind of apps available on all markets, I know the project is feasible, so really it’s more of making sure my version makes sense and works the way I intend it to. Also, like before, I found a name to use during research for this app, Bookz

Project Setup 🚧

Before I start working on the designs I’ll setup my project folder both online and offline. I’ll use GitHub for hosting my project, so I create an initial project folder locally, add a simple README file to get started and sync the folder online. I use the following folder structure for these types of projects since I can also sync up Timemator to create time trackers for each folder while working.

-- bookz 
---- README
---- android
---- design
---- ios
---- web

Design Stage 🎨

I sort of follow the Atomic Design process mixed with the Agile Development practice to iterate through each stage until I get a product that I’m happy with. For this project I’m going to use Figma for my design tool, since I’ve been wanting to give it a try. Just like Sketch, there’s plenty of system templates to use so I’ll start out with the iOS template to create the mobile UI outline and can skip the wireframe part of the design stage.

Mobile Mockup

For the mobile design I’ll use the iOS design template to start out setting up my TabBar on the bottom with the potential views I plan on showing; Home, Library, and Wishlist.

For the Home View the main idea is to show a carousel viewer for the different types of genres that are available to choose from and then below the genre image a list of books matching this genre should be shown.

Example of Home Screen layout

The Library and Wishlist screens will have a lot of the same elements; a TableView listing books, a SearchBar and some buttons to Filter/Sort the list and using the swipe actions to save a book to either local list.

Example of Library and Wishlist screens

The last screen to work on is the Detail screen, which can be called when a book it selected from any screen. Again, to keep things simple the Book cover and title can be used for the top of the view and then a TextView can be used to display all the books details.

Sample Book Details layout

Web Mockup

Switching over to the web design, I’ll try to keep the smaller screens layout similar to the mobile layouts, so I really only need to work on the larger screen layout when I have a lot more space to work with. I’ll go with a Admin style design so my tabs will all be in a sidebar and then each screen can use larger elements to fill up the space. Based on the few templates I’ve seen, I can add a few card style elements for selecting specific genres and a table that will display all the data based on the other selections. I’m sure I’ll have to tweak this more in code, but this gives me a good idea of what libraries I’ll need to look for when I start coding it.

Sample of Web style layout

Design Handoff 🤝

Once I have enough “design” items in the mockups that I can use to start coding I’ll wrap up the design process with some little extras that are sometimes overlooked. First is the app icon, if you have enough to create it now then it’s a good idea to generate all the assets for the different applications. I’m not doing anything super fancy for these projects, all of the icons will include a simple icon from the Symbolicons library and the colors from my companies brand. There are all kinds of apps and kits available for generating app icons so there’s no need to list where to go to do this, what I would suggest is make sure you are generating the right types of assets for each platform (I like to use templates from just in case you wanted to know, Apply Pixels 😄 )

  1. iOS uses various sizes inside the Asset Catalog, some tools will generate all the sizes or just a few sizes and you will have to find/match the different sizes (since some are the same as others just with different names)
  2. Android uses an Adaptive icon so it can be dynamic for the different device types. Most tools will generate the two layers and using the Asset Studio inside Android Studio allows you to assign the layers to the App Icon.
  3. Web will need a favicon, as well as images needed for mobile browsers. Again most tools will generate all these sizes for you, just make sure to add them in the correct folder when ready.

Development Stage 🏗

Similar to the design stage, I’ll use an Atomic Design mixed with Agile Development to iterate through the development of each app. I’ll also start with the iOS App, again since it’s my stronger area and works as a blueprint for the other apps.

iOS App 📱

Minimum Requirements: Xcode 14.1 & Swift 5

Setting up the project is fairly simple, no need to go into details here, just make sure to choose Swift and SwiftUI as the language and framework options. I use the simulator to test frequently, so although not mentioned I would suggest building frequently to validate changes are working on a device and not just the preview windows.

Once the project is opened, one of the first things I like to do is setup my preview window to show both light and dark modes of the app. This can be done with a small tweak to the PreviewProvider on your SwiftUI view using a ForEach loop and adding the .preferredColorScheme() modifier.

Show Dark & Light Preview windows

One of the first items I want to setup for this app is the network layer that will interact with the Google Books API. I’ll use the Swift Package Manager for this project and add Alamofire for my networking framework and then start setting up my network class.

To get a better understanding of how the API works it’s a good idea to use an API tool that will let you play with the request formats to ensure you get the correct response from the server. I like to use RapidAPI , but there are numerous other tools available, and from here I can also get my response JSON to build the response models in Swift. After a few rounds of playing with various parameters I did see that some of my initial design will have to change based on how the API works, but nothing too drastic. So now the scrollable card area on the top of the page will be used to filter by genre and the switch between Newest and Popular will be removed.

RapidAPI test query for Adventure Books

Jumping back into Xcode I’ll get started on setting up a network layer that will handle building the various queries that could be used. To get started I’ll setup a base function that will be responsible for building the queries with options to change various parameters if you wanted to

Network Layer with initial Query builder

After the network layer is setup, the next piece is to setup the decodable structs that can be used to parse the response into Swift usable data. There are tons of tools available to do this (I like to use QuickType), or you can do it manually as well looking at the response JSON structure, but this shouldn’t take a long time to do with the data responses we get from RapidAPI. With the decodable struct setup, the API can be called, and parsed with just a few simple lines.

Using responseDecodable to quickly parse API response

With everything setup to fetch books from the API, the next step is to setup the Card view that can be used to carousel through different genres. I’ll use some free illustrations from ManyPixels and also added another package for handling colors; DynamicColor. Setting up a paging style of view just requires a modifier to be added to a TabView making it a PageTabViewStyle .

TabView with paging style

To make the Card style view just requires adding a cornerRadius modifier and set the background to a gradient color.

Card View with Preview

With the CardView done the next piece to setup is the Cell for the Books that will show up on each ListView. How you want to setup the list item is totally dependent on what information you want to show, for me I decided to just go with some minimal information like the Book name, authors, published date and rating. There’s a few ways to enable row selection in a list, but one of the easier ways is to just use the onTapGesture modifier and set the selected book as a @State variable so it can be used in the sheet modifier for showing the Book detail popup.

Using a sheet to show the Book Detail View

Running the app right now will give you the top 5 books from different genres and the ability to tap on any row to view more details about that book. What we need next is a way to store the books and populate the Library and Wishlist views, so for that I’ll use Core Data. Core Data has come a long way since it was first introduced, and using it with SwiftUI is very similar to the ViewModel we have setup using the environment modifier. I’ll start with creating my Data Model and adding my entities to it.

Xcode tries to make this process fairly simple, first step is to setup the data model and then you can create all the entities you need and setup the attributes for each. I’m not planning on saving the entire Book JSON response model, but just some key fields that can be used to identify the book again in the Books API.

Simple Core Data setup for Bookz

Once all the entities are setup we can start setting our code to load the database and keep it open while the app is alive. First thing to do is setup the NSPersistentContainer that loads the database. This is also a good place to add the preview version that can be used during development with pre-loaded data.

Core Data controller class

To use this object in SwiftUI we can pass it as an Environment object from within the main entry of the app by adding it to my ContentView modifier

Adding Core Data controller to SwiftUI views

Now we’re all setup to start using our Core Data models within the app. To fetch objects from the SwiftUI side we use the @FetchRequest to build a variable populated with items from the database. For example to fetch all books with no sorting can be done with just@FetchRequest(entity: SavedBooks.entity(), sortDescriptors: []) var books: FetchedResults<SavedBooks> . When used outside of SwiftUI a FetchRequest is built by first using the Entity you want to search against ( SavedBooks.fetchRequest() ) and then using a NSPredicate to add filters/sort operations.

Now for the Library view, which will also contain a Search bar to filter books based on title and swipe actions to Delete/Move books. SwiftUI has been making some of these steps easier with each version, and right now searching is done by simply adding a searchable modifier on the NavigationStack . To make it easy to filter items a separate variable can be used that will show all items when the searchText is empty and return the filtered array when searching. In the List we need to use a ForEach loop instead of adding the objects to the List initializer so we can add the swipeActions modifier for handling the delete and move actions.

Library view with ViewModel fetch method

Setting up the WishlistView is as simple as copying the LibraryView and just updating the variables used in each area. At this point the app is ready to use, until I realized the only books I can add to either list are just from the Top 5 list on each genre. Adding a generic search would be the final piece needed to make this app more useful, and it’s a simple process using the same sheet modifier to open a new screen that uses the searchable modifier as well. The one extra piece is to add the onSubmit(of: .search) modifier to the view to initiate the search after the user hits enter on the keyboard. Everything else is the same as the Library/Wishlist view with a List and ForEach to show the Book cell and the onTap to handle showing the detail screen.

Search View for finding more book

With the final piece in place this app can be considered done now 👏. Last steps are to add a few Unit Tests, drop in the App Icon and get the build ready for production. Before we push this app, it’s time to do it all again in Android

I have to do this again?

Android App 🤖

Minimum Requirements: Android Studio 2022 (Electric Eel) & Kotlin 1.5. At the time of writing most of these features were marked Experimental and may change over time.

Using my iOS app as a blueprint, I already know what I need to get started with the Android side of things as well. To get started choose an Empty Compose Activity(Material 3) and choose Kotlin with minimum of API 24 (Nouget). As with the iOS app, I use a simulator to verify and will build often while working through each step.

One of the differences for the Android platform is how the Colors and Themes are used. In order to get the colors I need I use the Material Theme Builder and export using the Jetpack Compose Theme. After dropping this into the app, I can now setup my Dark & Light Preview light previews, which is done by creating different Preview Composable and setting the useDarkTheme variable. I like to use the showBackground and showSystemUi on the Preview windows as well just to get the full preview on each type.

Android Light & Dark Mode Previews

To get started with this app, I’ll use the Accompanist library for some of the UI components and Fuel for the HTTP requests with the Gson library for handling the JSON conversions.

implementation "com.google.accompanist:accompanist-pager:0.19.0" //Pager 
implementation 'com.github.kittinunf.fuel:fuel:2.3.1' //Fuel
implementation 'com.github.kittinunf.fuel:fuel-gson:2.3.1' //Fuel Gson
implementation 'com.google.code.gson:gson:2.8.9' //Gson
implementation "androidx.navigation:navigation-compose:2.5.3" // Navigation
implementation "androidx.compose.runtime:runtime-livedata:1.3.3" // LiveData

With my iOS app as a blueprint, there are a few items I can get setup to start testing the Google API, including the HorizontalPager and the snapshotFlow to call the API when the user swipes between genres. A Text view is used for now since I’m more concerned with getting the network layer setup.

Pager view setup with Genre Cards

The Fuel library is very easy to use, just add .httpGet() to a url string to get a response. Adding the .responseObject() allows you to use Gson to parse the json response into a data class . It’s all very similar to the iOS side, just some variations in the code format and a lot of that is handled by Android Studio automatically.

Fuel example to search Google Books API

Now the Homepage can be updated to show the Genre cards and a LazyColumn for the results from the API call. To make the book item clickable in the LazyColumn the Book view needs to be wrapped in a Row so the .clickable modifier can be added. Later this can be used to show the popup.

Homepage View with Pager and Table

Showing the detail view in Jetpack Compose is similar to SwiftUI, you need an observable boolean that can be used to trigger showing the popup view. Setting up the layout is pretty straightforward if I follow the same layout as on the iOS side and now with those pieces setup the next part to work on is the Room database.

Showing a Dialog in Jetpack Compose

Setting up a Room database requires a few steps, first you need an Entity class that defines the object, the Database class, a DAO (data access object) that provides the interaction point between the database and the last piece, the repository that will work with the ViewModel. First you need to add a few more libraries to the project.

implementation("io.coil-kt:coil-compose:2.2.2") // Image processing
implementation "androidx.room:room-runtime:$room_version" //Room
implementation "androidx.room:room-ktx:$room_version" // Room Kotlin Support
annotationProcessor "androidx.room:room-compiler:$room_version" // Annotations
ksp "androidx.room:room-compiler:$room_version" // Compiler

The Room entities are easy to setup, just use the ColumnInfo attribute to identify the column name and then the Query annotations will work in the DAO class to write out the SQL statements. The Database can then be setup with the DAO class and now you have a working Room database for the app 👏.

Room setup

Adding this database repository to the ViewModel is done by calling the database Instance and then adding the DAO class from the instance to a repository and now the view model can respond in real time to changes made to the database objects.

Adding Room Database to the ViewModel

Now with the Network and Database layers all setup, the only part needed now is setting up the UI to handle the different MutableLiveData arrays. Jetpack Compose is setup in a way where you can get files with lots of nested components so I like to break up my components a little more on Android. For the navigation I’ll use a BottomNavigation to setup the different tab bars and then for each view I use CenterAlignedTopBar with a TextField when needed for the search option.

Setting up TopBars in Android

Since I had the option to setup other types of TopBars, I decided to use a Drawer component for the home page to open the search view. This gives the Android app some more OS specific functionality that stills provides the same functionality for a user if they happen to use each device.

Using a Drawer view for the Search View

Finally I need to setup a list item for showing each book, and make it swipe able in the Library/Wishlist views. The SwipeToDismiss Composable can be used to add swipe gestures to any view, and by using a DismissState to remember the direction being swiped we can perform the same actions as in iOS by swiping left to delete and right to move the book to the other view.

Adding the Swipe gesture to the Table Cells

So that should wrap up the Android version of the app, using the iOS version as a blueprint speeds up the development process and Jetpack Compose keeps adding more components that are easy to integrate into an app. Next step is to add some Unit Tests and update the app icon, but before pushing this app it’s time to do this for a third time for the web app.

I really have to do this again? 😆

Web App 🕸

Minimum Requirements: Vite, Svelte, TypeScript and TailwindCSS.

The Web App is definitely a more “open” playground to use compared to mobile apps since there is far more variety in the frameworks that can be used. While there are some frameworks that are more widely used than others, I chose a stack that I felt worked best for my style of development coming from a mobile only background. For testing, I like to use Sizzy as a development browser since I can see both small and large screens.

  1. Vite — A newer build tool that is extremely fast and provides Hot Reloading (Live Updates), also works well with Svelte
  2. Svelte — A front end framework for building reactive components
  3. TypeScript — For the backend logic to add type safety, something I’m used to as a mobile developer
  4. TailwindCSS — A CSS Framework to make responsive classes easier to write and read.

To get started I’ll use the Vite CLI to setup a project using npm create vite@latest and follow the commands to create an empty project and select the option to use Svelte and TypeScript. Once the project is done, adding TailwindCSS can be done with a simple command npx svelte-add@latest tailwindcss and now the only item needed is FontAwesome for icons. For FontAwesome I like to use the local option, downloading the assets and adding the CSS link to the index.html file and now the web app base is ready to go.

To build the UI I’m going to use the Notus Svelte template to take some of the work out of building an entire UI from scratch. I drop all the files from the template into my project and then start working out what pieces I will need for each screen. The Admin template ended up having all the components I would need to make the app work with a sidebar for selecting each view and multiple table layouts to use. I get started with the sidebar piece first and update my main App.svelte page to handle switching between views based on the selection made in the Sidebar.svelte component.

Tweaking the template for my needs

Next step is to get the enum interface setup so I can work on the View Model, don’t really need a network layer for the web app since it will be online already 😃.

Setting up the Genre object in TypeScript

In the view model I can use the built in fetch ,Promise and await libraries to perform the API requests and make all of this perform asynchronous for performance. If you use a tool like QuickType to generate the interface from the JSON then the conversion is as simple as just doing let data = json as BooksModel; , or you can use other libraries to work with the JSON data however you prefer.

ViewModel with storing/fetching methods

Svelte is also setup to work with the Promise library already and uses a easy #await block that will update once the data is downloaded. Combined with the #each loop the book tables can be populated with the results from the queries and that is all I need to get all 3 views tables setup.

Dashboard View example with Svelte Await

This makes the entire setup finished, it’s just adding the on:click actions to the buttons for adding and removing books as well as moving them between the saved library and wishlist views.

Sample screenshot of Dashboard View

The last item was to add a modal popup window for showing the details of each book. I found this handy little class, svelte-simple-modal that just needs a wrapper around the main area in App.svelte and then just pass the name of the view to open as a modal window when the button is clicked with on:click={() => open(BookDetailView, { book: book })} .

Sample of the book Detail Modal Window

This will pretty much wrap up the Web App functionality with the mobile apps, but there are a few more items needed for a web app to be complete. Basically it’s just wrapping all this content with a Navigation Bar and Footer area that contains basic data. After these basic items are added the last piece to add is some Unit Tests for the web app, and for this I’ll use the Vitest framework. The Vitest framework uses a very easy to understand format, using describe to setup a test class and it and expect functions to explain what kind of test is being executed in each it function.

With the Unit Tests completed we now have 3 apps ready to be published and pushed out to the public.

Finally finished 🎉

Deployment Stage 🚀

Following the same pattern as before, I’ll go through the deployment options for each app, starting with the iOS App first.

iOS App Package 📦

Publishing an iOS App requires the App Store, regardless of the type of distribution that you want to use. For this app I’ll use the Ad Hoc distribution option so I can install the app on just my own specific devices. Open Xcode and go to the Product menu and choose the Archive option to start the build process. In the Archive window choose the Ad Hoc option and follow the instructions to end up with a .ipa file that can be installed to a device using the Apple Configurator app.

Android App Package 📦

Publishing an Android App is a little bit more open than the iOS side and doesn’t require having to use the Google Play store to build a Ad Hoc version of the app. To get started open Android Studio and use the Build menu to go to Generate Signed APK and then choose the App Bundle option. The next screen will ask you to setup a keystore for the app that is needed for future updates to the package so make sure this is safely stored somewhere. Last step is to choose where to save the APK file and which version to use for the build (use the release build) and that’s it for the Android side. The app can be installed on a device manually or uploaded to the Google Play store for public distribution.

Web Package 📦

For the web app, Vite comes with scripts already setup for generating a build and to preview the build as well. Once the build script is finished the final step is to find a host for the web app. There are quite a few options available from free to commercial, depending on the needs of the project and the resources available. For this project, a simple free hosting option can be used with Vercel and using the CLI option all you need to do is run the vercel command from the project dist folder and follow the prompts to launch the app. The live preview can be found here: Bookz Preview

Wrapping it up 🤔

Even with just a high level overview of each app, this was quite a bit to take in if you followed along for all three apps. The nice thing is this project is small enough that it can be taken in any direction now if you want to add more features to this app. Here’s a few ideas of areas that can be expanded on:

  1. The Web app doesn’t have the search methods setup for other books.
  2. Other/More genres can be added
  3. More interactive options can be added (like filters or sorting options on the tables).

Whatever you do, I just hope this was a good starting point to help visualize some ideas you might have. I’ll continue the series with C, which is currently in pre-design stage. Stay tuned for more 😄.

--

--