Git Product home page Git Product logo

octometer's Introduction

Hi 👋, I'm Ryan

I make Android Apps, and more... through Kotlin Multiplatform

ryanw-mobile

ryanw-mobile ryanw-mobile

About Me

  • 🌍 UK Resident | Open To Work in Senior Android Developer roles
  • 🌱 Focused on Jetpack Compose, Coroutines, Kotlin Multiplatform, and Compose Multiplatform
  • 📚 Check out my blogs on Medium

 

My Android Journey

Transforming ideas into engaging apps since 2010.

  • 📱 13 Apps on Google Play with RW Android Labs / RW MobiMedia
  • 📈 Privately-owned apps exceeding 1,600,000+ downloads
  • 🔄 14+ years of comprehensive experience in Android development, from concept to deployment

 

Recent Highlights

OctoMeter Kotlin Multiplatform Demo     compose pager demo     Giphy Trending         

 

Skills and Tools

  • 🛠️ Skilled in Kotlin, Java, and various other languages
  • 🎓 Previously proficient in Java (1999-2021); primary programming language during my Computer Science undergrad with multiple certifications
  • 🔄 All major public repositories automated with Github Actions and Renovate

ryanw-mobile

 

Connect & Explore

 

Some other unpinned repositories

  • dvd-multiplatform - A Simple Kotlin Multiplatform tutorial targeting Android, iOS, Web, Desktop.
  • Fused User Preferences - Template data source for both SharedPreferences and DataStore implementation
  • nd940-cap-advanced-android-programming-project - An Android-Kotlin-MVVM application that provides civic data intended to provide educational opportunities to the U.S. electorate using data provided by the Google Civic Information API.
  • JRNL - Journaling iphone/iPad/VisionOS demo App with widget support, built by following tutorials

octometer's People

Contributors

renovate[bot] avatar rwmobi avatar ryanw-mobile avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

octometer's Issues

Change project namespace to codename

It is easier to detach the project namespace from the user-facing App names - so we can have plenty of time to think about it while not causing a massive refactoring due to namespace change.

The project codename (thus the namespace) will be. com.rwmobi.kunigami

Account Screen: Minor milestore touchups

Making the Account screen a bit better before we provide the preferences library.

Account screen:

  • Add background icon
  • Add button: Update API Key
  • Make Selected / SELECT button work
  • Make sense of error messages
  • Extract String resources
  • See any quick way to format date

Improve account screen

should be able to show the existing/latest tariff including standing charge on one single screen.

The logout / change config feature will be dealt with later when we have the secured preference implemented.

FakeRepository for demo mode

At the near-release stage, it will be useful to build a Fake Repository so it only fires real API requests that do not need authentication. Fake data will be returned for all the rest of the requests so that the App can be assessed by people who are not the customer or who do not want to provide an API Key.

Fake/ ChatGPT scrambled data will be provided.

API - Account Endpoint

/v1/accounts/<account-number>/

Deliverables:

  1. Ktor endpoint and DTO
  2. Repository for making basic reqeust
  3. Basic domain model (we don't know what to keep yet)
  4. Unit test
  5. Scrambled sample json data for unit test

UIState refactoring - adaptive layout

Small changes to enable viewmodel as the source to render the layout template according to the window size class, so composables will have no code accessing to the real device resolutions.

This covers usages and agile.

Agile screen enhancements

  1. pull real current tariff rates and standing charges
  2. display selected agile standing charges & current agile rate
  3. LaunchedEffect set to auto refresh at the nearest 30 minutes to show the updated agile rate

Android Splash Screen setup

It shouldn't be a thing even we don't have the launcher icon ready yet.
The code is there and we can just update the reference (or even the color) when the real one is ready.

Basic UI connectivity - Android

Given the repository and domain model is available, have the basic Compose Multiplatform UI ready which can be used to build the Android app

Showing dual rates tariffs

ElectricityTariffDto has placeholder added for dual rates

// @SerialName("day_unit_rate_exc_vat") val dayUnitRateExcVat: Double? = null,
// @SerialName("day_unit_rate_inc_vat") val dayUnitRateIncVat: Double? = null,
// @SerialName("night_unit_rate_exc_vat") val nightUnitRateExcVat: Double? = null,
// @SerialName("night_unit_rate_inc_vat") val nightUnitRateIncVat: Double? = null,

Some refactoring work is needed so that we have to show an alternative layout when there are day unit rates and night unit rates.

This can be simulated by hardcoding a tariff code in the viewmodel (started with E-2R)
Example Tariff: E-2R-OE-FIX-12M-24-04-11-H

API - Consumption endpoints

The most useful API end-point.
Authentication needed.

/v1/electricity-meter-points/< MPAN >/meters/< meter serial number >/consumption/?page_size=100&period_from=2023-03-29T00:00Z&period_to=2023-03-29T01:29Z&order_by=period

Deliverables:

  1. Ktor endpoint and DTO
  2. Repository for making basic reqeust
  3. Basic domain model (we don't know what to keep yet)
  4. Unit test
  5. Scrambled sample json data for unit test
  6. Domain function:
    "Electricity consumption data is returned to the nearest 0.001kwh. For billing, consumption is rounded to the nearest 0.01kwh before multiplying by the price. The rounding method used is rounding half to even, where numbers ending in 5 are rounded up or down, towards the nearest even hundredth decimal place. As a result, 0.015 would be rounded up to 0.02, while 0.025 is rounded down to 0.02."

update provideSettings.android.kt deprecated methods

w: ProvideSettings.android.kt:12:33 'MasterKeys' is deprecated. Deprecated in Java
w: ProvideSettings.android.kt:17:26 'MasterKeys' is deprecated. Deprecated in Java
w: ProvideSettings.android.kt:17:49 'MasterKeys' is deprecated. Deprecated in Java
w: ProvideSettings.android.kt:18:56 'create(String, String, Context, 
EncryptedSharedPreferences.PrefKeyEncryptionScheme, 
EncryptedSharedPreferences.PrefValueEncryptionScheme): SharedPreferences' is deprecated. Deprecated in Java

Use case should handle lazy load due to the API design

Currently, the data source and repository are discarding paging data.
It is ok both of them do not automatically resume, but the use case should check and fire follow-up requests since we are supposed to plot the graph using a complete set of data.

User Preference repository

Need to connect the viewmodel to database
so that we can provide the API key, MPAN and meter serial number to API

Tariff details screen

  1. check the exact endpoint to use
  2. add additional DTOs if needed
  3. add new domain models
  4. decide the presentation - bottomsheet or new window? - responsive layout concerns here.

We don't have to show all available tariffes (especially not export/gas/ non-octopus) as this part is purely for demo purpose.

Adaptive rate cards

A composable that takes a parameter columns:Int

will split the given list into equally-wide columns with the list items distributed among these columns.

So that when viewmodel when being notified the screen size, it will calculate how many columns is required, and sending an Int to UIState.

Composable just take that integer and pass it on to this composable, which will then split the list according to the integer without knowing the actual screen size.

Onboarding screen

While there are things like the Product & Agile are free to browse,
certain features required API key to proceed,
we can create a simple onboarding screen asking for the API key
(and instruction pointing to the portal to get the key)
during first launch.

This can be simply some instructions,
then a CTA like "enter API key" to navigate to the settings screen
or "i'll do that later" to enter the main screen without a API key.

API - Price endpoints (agile)

This contains a set of endpoints

Deliverables:

  1. Ktor endpoint and DTO
  2. Repository for making basic reqeust
  3. Basic domain model (we don't know what to keep yet)
  4. Unit test
  5. Scrambled sample json data for unit test

Basic UI connectivity - iOS

Given the Android UI is done, the iOS basic xcode project should be able to load the compose multiplatform components - at least to run it and show some data, even if they are not formatted.

API - Products Endpoint

/v1/products/

This endpoint doesn't require authentication.

Deliverables:

  1. Ktor endpoint and DTO
  2. Repository for making basic reqeust
  3. Basic domain model (we don't know what to keep yet)
  4. Unit test
  5. Scrambled sample json data for unit test

Change chart type

Obviously there should have another bar chart type rather than the XYGraph that we are using.
It's better to get this sorted before we customise the chart.

Basic UI connectivity - Desktop

After Android and iOS, the desktop (JVM) app should also be able to show some unformatted data.
The UI design for desktop has to be different so this is placed after Android and iOS - probably as a first start if it looks like Android Tablet UI might be good.

The point is we need to have all three platforms up and building before we construct the subsequent UI, navigation, and everything..

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

cocoapods
iosApp/Podfile
github-actions
.github/workflows/create_artifact_release.yml
  • timheuer/base64-to-file v1.2
  • actions/checkout v4
  • actions/setup-java v4
  • actions/upload-artifact v4
  • actions/upload-artifact v4
  • actions/upload-artifact v4
.github/workflows/dependency_submission.yml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v4
.github/workflows/main_build.yml
  • timheuer/base64-to-file v1.2
  • actions/checkout v4
  • actions/setup-java v4
  • actions/upload-artifact v4
  • codecov/codecov-action v4
  • codacy/codacy-coverage-reporter-action v1.3.0
.github/workflows/renovate_check.yml
  • timheuer/base64-to-file v1.2
  • actions/checkout v4
  • actions/setup-java v4
  • actions/upload-artifact v4
.github/workflows/tag_create_release.yml
  • timheuer/base64-to-file v1.2
  • actions/checkout v4
  • actions/setup-java v4
  • actions/create-release v1
  • actions/upload-release-asset v1
  • actions/upload-release-asset v1
  • actions/upload-release-asset v1
  • actions/checkout v4
  • actions/github-script v7
  • actions/setup-java v4
  • actions/upload-release-asset v1
  • actions/upload-release-asset v1
gradle
gradle.properties
settings.gradle.kts
build.gradle.kts
baselineprofile/build.gradle.kts
composeApp/build.gradle.kts
gradle/libs.versions.toml
  • androidx.compose:compose-bom 2024.06.00
  • co.touchlab:kermit 2.0.4
  • co.touchlab:kermit-koin 2.0.4
  • io.github.koalaplot:koalaplot-core 0.6.3
  • androidx.activity:activity-compose 1.9.1
  • androidx.core:core-splashscreen 1.0.1
  • androidx.security:security-crypto 1.1.0-alpha06
  • androidx.compose.ui:ui-tooling 1.7.0-beta07
  • androidx.compose.ui:ui-tooling-preview 1.7.0-beta07
  • androidx.test:core-ktx 1.6.1
  • androidx.room:room-compiler 2.7.0-alpha06
  • androidx.room:room-runtime 2.7.0-alpha06
  • androidx.sqlite:sqlite-bundled 2.5.0-alpha06
  • org.robolectric:robolectric 4.13
  • io.ktor:ktor-client-core 2.3.12
  • io.ktor:ktor-client-cio 2.3.12
  • io.ktor:ktor-client-okhttp 2.3.12
  • io.ktor:ktor-serialization-kotlinx-json 2.3.12
  • io.ktor:ktor-client-content-negotiation 2.3.12
  • io.ktor:ktor-client-darwin 2.3.12
  • io.ktor:ktor-client-mock 2.3.12
  • org.jetbrains.kotlinx:kotlinx-datetime 0.6.0
  • org.jetbrains.kotlinx:kotlinx-coroutines-android 1.8.1
  • org.jetbrains.kotlinx:kotlinx-coroutines-core 1.8.1
  • org.jetbrains.kotlinx:kotlinx-coroutines-swing 1.8.1
  • org.jetbrains.kotlinx:kotlinx-coroutines-test 1.8.1
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.7.1
  • dev.chrisbanes.material3:material3-window-size-class-multiplatform 0.5.0
  • io.insert-koin:koin-core 3.5.6
  • io.insert-koin:koin-test 3.5.6
  • io.insert-koin:koin-android 3.5.6
  • io.insert-koin:koin-core-jvm 3.5.6
  • io.insert-koin:koin-compose 1.1.5
  • com.squareup.leakcanary:leakcanary-android 2.14
  • com.russhwolf:multiplatform-settings 1.1.1
  • org.jetbrains.androidx.navigation:navigation-compose 2.8.0-alpha08
  • androidx.lifecycle:lifecycle-runtime-compose 2.8.4
  • com.github.Dansoftowner:jSystemThemeDetector 3.9.1
  • androidx.test.ext:junit 1.2.1
  • androidx.test.espresso:espresso-core 3.6.1
  • androidx.test.uiautomator:uiautomator 2.3.0
  • androidx.benchmark:benchmark-macro-junit4 1.2.4
  • androidx.profileinstaller:profileinstaller 1.3.1
  • org.slf4j:slf4j-simple 2.0.16
  • com.apollographql.apollo:apollo-runtime 4.0.0
  • com.apollographql.apollo:apollo-testing-support 4.0.0
  • com.apollographql.mockserver:apollo-mockserver 0.0.3
  • androidx.test:rules 1.6.1
  • org.jetbrains.skiko:skiko-awt-runtime-macos-arm64 0.8.11
  • org.jetbrains.skiko:skiko-awt-runtime-windows-x64 0.8.11
  • org.jetbrains.skiko:skiko-awt-runtime-linux-x64 0.8.11
  • com.android.application 8.5.2
  • com.android.library 8.5.2
  • com.google.devtools.ksp 2.0.10-1.0.24
  • com.android.test 8.5.2
  • androidx.room 2.7.0-alpha06
  • org.jetbrains.kotlin.multiplatform 2.0.10
  • org.jetbrains.kotlin.native.cocoapods 2.0.10
  • org.jetbrains.kotlin.plugin.power-assert 2.0.10
  • org.jetbrains.kotlin.plugin.compose 2.0.10
  • org.jetbrains.kotlin.plugin.serialization 2.0.10
  • org.jetbrains.kotlin.android 2.0.10
  • org.jetbrains.kotlin.jvm 2.0.10
  • org.jetbrains.compose 1.7.0-alpha02
  • org.jetbrains.kotlinx.kover 0.8.3
  • org.jlleitschuh.gradle.ktlint 12.1.1
  • com.github.gmazzo.buildconfig 5.4.0
  • androidx.baselineprofile 1.2.4
  • com.apollographql.apollo 4.0.0
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.10

  • Check this box to trigger a request for Renovate to run again on this repository

Set up Ktor

This includes how we define the endpoints, and the basic infrastructure to keep our API keys safe - locally and on CI.

Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers

A very strange error showing in the log.
This affects Usage, Agile and tariffs, but not Account. Error logged whenever the screen is scrolled.

It is interesting because basically all four screens have the same root LazyColumn with Scrollbar.
Tariffs doesn't come with any charts but still getting the same error when scrolled.

Not a high priority but for record purpose.

2024-05-20 20:39:46.874 2376-2376 ImageReader_JNI com.rwmobi.kunigami.debug W Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers
2024-05-20 20:39:46.875 2376-2402 FrameEvents com.rwmobi.kunigami.debug E updateAcquireFence: Did not find frame.

Tariffs follow up

Inspect the returned DTO to see how much we want to show.
It might also be useful to add helper functions in the Mapper to parse the additional details link so we can programmatically determine if any extra navigation is available.

The first milestone is to present all we want to show without too much polishing the UI.
Optionally, in later stages, we could filter or even search - all without a database. Still, we focus on getting the first level right to stabilise the domain models for this ticket.

Add data export function

This has a low priority.

Probably port from another project after its completion.

To allow exporting smart meter data to .csv or some other format.
Would be nice if google sheets could open it.

This involves access to device dependent APIs on iOS and Desktop, which I have no idea how iOS could be done yet.

Repository and domain models - basic

We need a very basic non-caching repository connecting all the data sources, and domain models holding only the data we are interested at the first stage.

This ticket should cover the unit tests where a draft should have been done when crafting the data sources.

Mark data classes stable

I don't have a way to scientifically prove any substantial difference, but let's give it a try my annotating UIState classes @Stable as an experiment

iOS Launch Screen set up

Yes, it is normal for the default Kotlin Multiplatform iOS app generated using a template to show a blank white screen during startup. By default, there's no splash screen set up. However, you can customize this to include a splash screen for a better user experience.

Setting Up a Splash Screen in a Kotlin Multiplatform iOS App

Here's a step-by-step guide on how to set up a splash screen for your iOS app:

  1. Add a Launch Screen Storyboard
  2. Configure the Info.plist
  3. Customize the Launch Screen

Step 1: Add a Launch Screen Storyboard

  1. Open Xcode: Open your iOS project in Xcode.
  2. Add a New Storyboard:
    • Right-click on your project in the Project Navigator.
    • Select New File.
    • Choose Storyboard under the User Interface section.
    • Name the file LaunchScreen.storyboard.

Step 2: Configure the Info.plist

  1. Open Info.plist: In Xcode, open the Info.plist file of your iOS project.
  2. Add Launch Screen Key:
    • Add a new key called UILaunchStoryboardName.
    • Set its value to LaunchScreen.

Step 3: Customize the Launch Screen

  1. Open LaunchScreen.storyboard: Open the LaunchScreen.storyboard file in Xcode.
  2. Design Your Splash Screen:
    • Drag and drop UI elements (e.g., UIImageView, UILabel) to design your splash screen.
    • Customize it as needed (e.g., set a logo image, add app name, etc.).

Here's an example to show a logo image centered on the screen:

  1. Add an Image View:

    • Drag an UIImageView to the center of the storyboard.
    • Set constraints to center it both horizontally and vertically.
  2. Set Image:

    • In the Attributes Inspector, set the image to your logo (ensure the image is added to your Xcode project's asset catalog).

Example Configuration in Info.plist

<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>

Example LaunchScreen.storyboard

Design your storyboard as shown in the steps above.

Additional Tips

  • Splash Screen Duration: The splash screen duration is determined by the app loading time. To keep it visible for a longer period, you need to handle it programmatically within the app's lifecycle, which is generally not recommended. Instead, ensure that your main app UI loads promptly.
  • Asset Management: Make sure all images used in the splash screen are added to the asset catalog in Xcode for proper referencing and optimization.

Final Thoughts

Setting up a splash screen in a Kotlin Multiplatform iOS app is primarily done through Xcode and storyboard configuration. By following the steps above, you can ensure your app has a visually appealing splash screen during startup, providing a better user experience.


Yes, you can design your splash screen to support different themes, including dark mode, in your iOS app. This involves setting up different UI elements for light and dark modes within your LaunchScreen.storyboard and making sure your images and colors adapt to the theme.

Step-by-Step Guide to Support Dark Mode for Splash Screen

  1. Add Dark Mode Assets
  2. Configure Colors for Dark Mode
  3. Set Up the Launch Screen Storyboard

Step 1: Add Dark Mode Assets

  1. Open Xcode: Open your iOS project in Xcode.

  2. Add Image Assets:

    • Go to the Assets catalog in Xcode.
    • Add your image assets (e.g., logo) and configure them for both light and dark modes.

    To add dark mode support for an image:

    • Select your image asset in the Assets catalog.
    • Click on the "Appearances" dropdown and select "Any, Dark".
    • Add separate images for "Any Appearance" and "Dark".

Step 2: Configure Colors for Dark Mode

  1. Add Color Assets:

    • In the Assets catalog, create new color sets for the colors you want to use in your splash screen.
    • Configure the color sets to support both light and dark modes.

    To add dark mode support for a color:

    • Select your color set in the Assets catalog.
    • Click on the "Appearances" dropdown and select "Any, Dark".
    • Set colors for both "Any Appearance" and "Dark".

Step 3: Set Up the Launch Screen Storyboard

  1. Open LaunchScreen.storyboard: Open the LaunchScreen.storyboard file in Xcode.

  2. Add UI Elements:

    • Add UIImageView for logos or images and configure their constraints.
    • Add other UI elements like UILabel if needed.
  3. Configure UI Elements for Dark Mode:

    • For UIImageView, ensure the images are set from the asset catalog which supports both light and dark modes.
    • For labels and other elements, set the colors using the color sets configured for both light and dark modes.

Example Configuration in Xcode

Adding an Image Asset with Dark Mode

  1. Add Image to Asset Catalog:

    • Click the "+" button in the Assets catalog.
    • Select "New Image Set".
    • Name it, for example, logo.
  2. Configure Appearances:

    • Select logo in the Assets catalog.
    • Click "Appearances" and select "Any, Dark".
    • Add images for both "Any Appearance" and "Dark".

Adding a Color Set with Dark Mode

  1. Add Color to Asset Catalog:

    • Click the "+" button in the Assets catalog.
    • Select "New Color Set".
    • Name it, for example, backgroundColor.
  2. Configure Appearances:

    • Select backgroundColor in the Assets catalog.
    • Click "Appearances" and select "Any, Dark".
    • Set colors for both "Any Appearance" and "Dark".

Example LaunchScreen.storyboard

  1. Set Background Color:

    • Select the main view in the storyboard.
    • In the Attributes Inspector, set the background color to the color set backgroundColor.
  2. Set ImageView:

    • Add an UIImageView to the center of the storyboard.
    • Set the image to logo (which supports both light and dark modes).
    • Add constraints to center it both horizontally and vertically.
  3. Set Label Color:

    • Add a UILabel if needed.
    • In the Attributes Inspector, set the text color to a color set that supports both light and dark modes.

Final Thoughts

By configuring your assets and storyboard as described, your splash screen will adapt to the system's light and dark modes, providing a seamless user experience. This ensures that your app looks good regardless of the user's theme preference.

App level error handling review

One example is when no network - have to check on each platform the App is showing something sane.
Otherwise individual API errors should have been handled in the relevant usecase/viewmodel.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.