Skip to main content
OAOlamilekan AdeyemiFlutter · React · Next.js · Full-Stack DeveloperHire Me
All projects

Electric vehicle charging · Mobile app

LumenCharge

Reworking an inherited EV charging app: a stronger UI, repaired navigation and state handling, and tighter payment and device safeguards across Android and iOS.

Improved an existing app
LumenCharge — actual App Store promotional screenshots
Charge smarter. Build better.
My roleFlutter DeveloperImproved an existing app
PlatformiOS / AndroidCross-platform mobile app
ScopeExisting app improvementReliability, features and interface
FocusCharging, wallet & recoveryImplementation and ongoing refinement

Security hardening

Payment, API and device safeguards on Android and iOS.

Navigation & state

Persistent tab journeys and corrected session/search state.

UI overhaul

Consistent screens, feedback and wallet/charging journeys.

Regression coverage

Tests for important business logic and failure states.

01 / The challenge

The problem to solve

I joined an existing development team and contributed to a shared product, rather than working as its sole developer. My focus was the Flutter mobile experience: understanding the inherited implementation, improving the areas I took responsibility for, and building on the work of other contributors.

I inherited an existing Flutter EV-charging app that needed substantial work on its UI, navigation, state management and security-sensitive flows. My role went beyond adding features: I reworked the interface, corrected disruptive navigation and state behaviour, and strengthened client-side safeguards for Android and iOS.

The supplied V1 already contained station discovery, QR scanning, charging sessions, wallet/Paystack flows, disputes, profiles, RFID requests and Riverpod. The challenge was to repair and improve that foundation—not claim it was built from scratch. Tabs needed stronger navigation continuity, shared search state affected separate views, and session handling needed to account for the complete charging lifecycle.

The problems crossed several layers: saved sessions could be restored without a startup expiry check; notification registration still used a placeholder; station list and map searches shared state; and device-specific storage or biometric failures needed bounded recovery. Wallet, receipt, verification and charging screens also needed clearer states and more complete interactions.

Payment and API boundaries also needed attention. The original checkout loaded its supplied URL directly and used prefix-based callback matching; API credential attachment lacked the later same-origin protection. I added stricter checkout navigation rules, external-request credential scoping and compromised-device checks, while improving authentication recovery and expanding regression coverage beyond the original smoke test.

02 / What I worked on

My approach & contributions

  • Overhauled inconsistent UI and feedback states with a shared visual system across the app’s core journeys.
  • Reworked tab navigation and corrected shared search state, session filtering and charging lifecycle handling.
  • Strengthened Android/iOS client-side safeguards with root/jailbreak checks, payment URL validation and API credential scoping.
  • Improved startup session recovery with proactive token refresh and more robust authentication handling.
  • Addressed Xiaomi/MIUI secure-storage hangs and added timeouts around biometric authentication.
  • Fixed duplicate notification handling and improved foreground alerts on iOS.
  • Refined transaction disputes, receipt options, status feedback and station-search behaviour.
  • Improved QR deep-link handling, OTP auto-submit and map lifecycle behaviour.
  • Expanded the shared UI system and self-service journeys for charging history, receipts, reviews and RFID cards.
  • Added regression coverage for authentication, wallet, QR and charging logic, alongside offline-state tests.
  • Built the GitHub Actions and Fastlane CI/CD workflow for automated checks, Google Play internal testing and iOS TestFlight delivery.

I worked within the existing Flutter, Riverpod and API structure. The detailed breakdown below distinguishes improvements to inherited features from new functionality I added.

Collaboration & ownership

Working as part of the team

LumenCharge was a team effort. I worked alongside other developers in an existing codebase, contributing mobile improvements while the wider product continued to evolve. My work connected the Flutter interface with shared API-driven journeys, including authentication, charging sessions, wallet transactions and notifications.

Individual ownership, shared delivery

I took responsibility for the mobile UI, navigation, state-handling and security improvements described here. Those contributions formed part of the team’s work—not a claim that I developed every part of LumenCharge.

Building on an existing foundation

I worked within the established Flutter, Riverpod and backend integration structure, improving existing journeys and adding functionality alongside other contributors’ changes.

This project demonstrates both sides of how I work: independently investigating and solving mobile problems, while contributing to a shared codebase and a broader team delivery.

Engineering beyond the app

CI/CD for the team’s Android & iOS releases

I also built the release workflow using GitHub Actions and Fastlane, connecting code validation with a repeatable beta-distribution process for both platforms.

Automated quality checks

Flutter analysis and tests run before dependent release jobs. Pull requests validate changes without triggering store distribution.

Controlled beta delivery

Fastlane lanes target Google Play internal testing and Apple TestFlight. Distribution is restricted to the dev branch with deployment enabled, and build artifacts are retained for the team.

03 / From the original version to the improved app

The fixes & improvements, in detail

A code-backed breakdown of my contributions within the team, comparing the supplied V1 with the current app and checking the relevant development history. Some entries describe later fixes made during the improvement process—not defects present in every version.

01

CI/CD for Android & iOS beta delivery

The starting point / issue
The team needed a repeatable route from code changes to checks and test builds, with clear separation between validating a pull request and distributing a beta release.
What I changed
I built a GitHub Actions workflow with Flutter analysis and tests, and Fastlane lanes for Google Play internal testing and Apple TestFlight. Release jobs depend on the checks and are gated to the dev branch with deployment explicitly enabled; pull requests do not trigger distribution. The workflow also retains Android AAB and iOS IPA build artifacts.
What this enabled
The team has a defined, automated path for checking mobile changes and preparing beta releases on both platforms. This describes the workflow I implemented, not a claim that every configured upload has completed successfully.
02

Repairing navigation & preserving each tab’s journey

The starting point / issue
The inherited navigation needed more than visual polish: tabs needed independent navigation state, charging deep links needed explicit route mapping, and session auto-opening needed to respect a user choosing to go back.
What I changed
I moved the main navigation to stateful shell branches, expanded routes for transaction details, receipts and reviews, and introduced a dismissed-session guard so backing out would not immediately reopen the same charging session. I also corrected charging QR/deep-link handling.
What this enabled
Tab navigation preserves separate journeys, detail screens have dedicated destinations, and charging navigation better respects user intent.
03

Correcting shared state & session lifecycle handling

The starting point / issue
V1 already used Riverpod, but some state boundaries and domain assumptions needed improvement. Station list/map search shared state; session history had one unfiltered provider; and live-session lookup only considered Active, excluding Finishing.
What I changed
I isolated list/map search, introduced filter-specific paginated session providers, merged failed/interrupted history into a correctly sorted cancelled view, and included finishing sessions in live-session lookup. I also strengthened map retention and notification-listener lifecycle handling.
What this enabled
State follows the relevant screen and filter, live charging ownership is represented more accurately, and repeated initialization is explicitly controlled. This was a targeted correction of state management—not a claim that Riverpod itself was the problem.
04

Android & iOS security hardening

The starting point / issue
The inherited application needed additional client-side checks around compromised devices and sensitive journeys, alongside stronger session and payment-navigation boundaries.
What I changed
I added Android root and iOS jailbreak indicator checks, a device-risk warning and checks on sensitive wallet/RFID actions. I strengthened biometric/session recovery and restricted where API authentication headers and hosted-checkout navigation could go.
What this enabled
The app gained layered client-side safeguards on both platforms. Root/jailbreak detection is heuristic and bypassed for development; these checks reduce specific risks but do not prove complete security or replace backend authorization and payment verification.
05

Charger availability reminders & balance checks

The starting point / issue
V1 had station information and charging actions, but no dedicated availability-reminder module or the newer charging-balance helper.
What I changed
I added charger availability reminders with persisted state, expanded availability handling and introduced a tariff-based minimum-balance/shortfall helper, with tests around these behaviours.
What this enabled
The app can retain reminder preferences and present charging balance requirements through explicit, testable logic.
06

Paystack checkout navigation safeguards

The starting point / issue
V1 already integrated Paystack, but loaded the supplied checkout URL directly and matched its callback using a string prefix.
What I changed
I added validation of the initial Paystack HTTPS destination, exact callback matching and checks for subsequent HTTPS navigation while allowing issuer-hosted payment authentication pages.
What this enabled
Checkout navigation has clearer boundaries without blocking the intended third-party payment authentication handoff. This is work on the existing Paystack integration, not the later OPay addition.
07

Reviews & RFID self-service screens

The starting point / issue
Reviews and RFID requests were already part of V1, but their screens and supporting models were substantially simpler than the improved version.
What I changed
I expanded review presentation with a dedicated location-reviews page and refined the review form, RFID card list, card-request and request-detail experiences, alongside their state and model handling.
What this enabled
Drivers can inspect station feedback and manage RFID-related journeys through more complete self-service interfaces.
08

Session recovery & token expiry

The starting point / issue
V1 restored a saved session as authenticated after biometric checks, without checking token expiry during startup. A returning user could therefore enter the app with credentials that needed refreshing.
What I changed
I added expiry-aware restoration, proactively refreshing tokens with less than 60 seconds remaining, bounded startup operations and explicit recovery paths when refresh fails.
What this enabled
Sign-in restoration now accounts for expired credentials instead of treating every saved session as ready to use.
09

Biometrics & Android secure-storage failures

The starting point / issue
V1 awaited secure-storage and biometric operations without the later startup timeouts. Device-specific Keystore failures could hold up the sign-in experience.
What I changed
I addressed the Xiaomi/MIUI failure path with secure-storage reset-on-error, guarded reads and cleanup, and timeouts around biometric resolution and session restoration.
What this enabled
Authentication can fall back gracefully when a device’s secure storage or biometric service fails to respond.
10

Real push notifications across iOS & Android

The starting point / issue
The supplied V1 registered a NoOpPushService—a placeholder integration rather than a working Firebase push implementation.
What I changed
I implemented Firebase Cloud Messaging registration, notification listeners, token refresh handling and navigation from notifications, with charging-session notification support.
What this enabled
The mobile client gained a real notification integration connected to the signed-in experience.
11

Duplicate alerts & missing foreground banners

The starting point / issue
During development, repeated listener initialization and overlapping notification presentation paths could create duplicate alerts. iOS foreground presentation also needed correction.
What I changed
I serialized notification initialization, cancelled existing subscriptions before replacement, added message deduplication and corrected iOS foreground presentation without also emitting duplicate local banners.
What this enabled
Notification delivery has explicit safeguards against duplicate listeners and repeated visible alerts.
12

Overhauling the UI & repairing inconsistent feedback

The starting point / issue
The inherited UI needed a substantial overhaul: simpler scaffold-based screens did not provide the later coherent visual hierarchy, branded journeys or consistent loading and feedback states. Light/dark themes existed, but the richer shared visual system and wallet privacy controls did not.
What I changed
I expanded the visual system with shared page styling, branded loading and splash experiences, signed-in headers, keyboard-safe layouts, consistent primary actions and light/dark artwork across onboarding, account, wallet and charging screens.
What this enabled
Core journeys share a more cohesive presentation and reusable UI foundation. This was an improvement to the existing app, not the invention of its original themes or architecture.
13

Station discovery, map state & search isolation

The starting point / issue
V1 used a shared search value across station list and map views. The later development history also records map lifecycle and camera-state issues.
What I changed
I separated search behaviour between views, preserved map state and camera position, refined location prompts, and reduced disruptive loading transitions while station data refreshes.
What this enabled
Drivers can move between station discovery views with better continuity and without carrying an unrelated search into the other view.
14

Station details & charging confirmation

The starting point / issue
The original app already supported station browsing and charging confirmation. The detail presentation and refresh behaviour needed further work to support a clearer decision before charging.
What I changed
I added parking-restriction information, refined compact station detail cards and header geometry, and fixed repeated EVSE loading skeletons in the charging confirmation flow.
What this enabled
Access information is easier to inspect, and confirmation avoids unnecessary loading disruption during data refreshes.
15

Charging progress, history & receipts

The starting point / issue
V1 had session tracking and history, but lacked the newer session-display helpers, progress model and dedicated in-app receipt page.
What I changed
I expanded the session presentation and confirmation flows, added dedicated display/progress models and an in-app receipt experience, and covered session states and stop-limit behaviour with regression tests.
What this enabled
Charging information and receipt access are presented through clearer, more focused components rather than only the original session screens.
16

Wallet visibility & transaction exploration

The starting point / issue
V1 had wallet balances, top-ups and transaction history. It did not include the later balance-privacy controller, transaction-filter helper or dedicated transaction-detail page.
What I changed
I developed the wallet presentation with balance visibility controls, transaction filtering and details, expandable transaction rows and more consistent transaction feedback.
What this enabled
Users have more control over what they expose on screen and can inspect individual transactions in greater detail.
17

Disputes, credit direction & transaction status

The starting point / issue
Disputes already existed in V1, but the later transaction-linked experience and credit/status formatting needed refinement. A failed transaction badge also used the wrong icon.
What I changed
I expanded transaction dispute flows, exposed full dispute identifiers, improved approved-status presentation, corrected dispute credit classification and fixed the failed-status badge icon.
What this enabled
Wallet and dispute screens communicate status and money movement more clearly. The work extends the existing dispute feature rather than claiming to have created it from nothing.
18

Receipt choices & safer external downloads

The starting point / issue
The supplied app had receipt-related functionality, but lacked the later dedicated wallet receipt downloader and explicit external URL policy.
What I changed
I added a choice to view a receipt in-app or download a PDF, dedicated download handling and API-origin header scoping so authentication and tenant headers are not forwarded to unrelated receipt hosts.
What this enabled
Receipt access is more flexible, with a clear boundary between authenticated API requests and external downloads.
19

Offline states, retry feedback & request safeguards

The starting point / issue
V1 had a basic error view but no shared offline guard or connectivity module. Later authentication and profile actions also needed protection against rapid repeated requests.
What I changed
I added connectivity-aware offline handling, richer retry/error states and consistent loading feedback, and extended client-side request throttling to sensitive authentication, wallet, verification and profile actions.
What this enabled
The interface explains connection failures more clearly and limits repeated client requests. Client-side throttling complements, but does not replace, server-side security controls.
20

Verification, account updates & tenant legal pages

The starting point / issue
V1 used simpler verification inputs and did not include a dedicated legal-page WebView. Email changes needed clearer pending-address and success states.
What I changed
I implemented six-digit OTP input and auto-submit, inline email switching, pending-email prefill, clearer success feedback, stronger change-email validation and tenant-specific terms/privacy links with fallback handling.
What this enabled
Account verification needs fewer manual steps and provides clearer feedback, while legal content follows the tenant configuration.
21

QR deep links & RFID request checks

The starting point / issue
The app already had QR scanning and RFID requests, but a charging deep-link format was not handled correctly and RFID request submission needed additional device checks.
What I changed
I corrected parsing for charging links such as lumencharge://charge/<evseId> and added root checks to the RFID request flow.
What this enabled
Supported QR links route into the intended charging journey, and RFID requests use the added device-safety checks.
22

Regression tests & release preparation

The starting point / issue
The V1 test directory contained one smoke test that only booted an empty MaterialApp—not meaningful coverage of the app’s charging, wallet or authentication behaviour.
What I changed
I added a dedicated test commit spanning 30 test files for authentication, biometrics, wallet filters, receipts, QR routing, station availability, charging sessions and other failure-prone logic. Later work added offline/error tests and Fastlane/GitHub Actions beta-release configuration.
What this enabled
The project gained repeatable checks around important behaviours and an automated release configuration. These are repository-backed deliverables, not a claim that every current test or release pipeline has been verified in this portfolio review.

04 / Key features

Solution highlights

Security hardening

Payment, API and device safeguards on Android and iOS.

Navigation & state

Persistent tab journeys and corrected session/search state.

UI overhaul

Consistent screens, feedback and wallet/charging journeys.

Regression coverage

Tests for important business logic and failure states.

05 / Outcome

What this work achieved

  • Expiry-aware session recovery and bounded handling of device-specific authentication failures.
  • A real Firebase notification integration with duplicate-listener and alert safeguards.
  • More complete station, wallet, dispute, receipt and verification journeys within the existing product.
  • Regression coverage expanded beyond V1’s single smoke test, with reusable UI and error-handling components supporting further development.

The result is a more complete implementation with explicit recovery paths and regression coverage. These are functional outcomes supported by the repository; no crash-rate, conversion or revenue improvements are claimed without production measurements.

Ready to build something great?

Let’s improve your existing product.

I’m available for freelance projects and remote development roles.

Let’s Work Together