This site is driven by two keys, like the machine it came from. Reading: j and k scroll, d and u move half a page, gg goes to the top, G to the bottom, H and L switch windows, ? opens the help. Space is the Neovim leader and handles content: Space then h home, r research, p projects, g gear, a about, / tags, or Space then a digit to jump to that window. Home is the tmux prefix and handles windows: Home then c opens a terminal, Home then & closes a window, Home then space goes to the next one. While focus is on the keyboard, h j k l move between keys and Enter opens one.

ResearchR AboutA Gear — G for gear — keyboard, terminal, editor, homelab.G
    ProjectsP Tags — / as in vim: search./
    ×
    Menu

    busgo: A Bus Ticket Booking Flow in Flutter

    A UI prototype for booking bus tickets — search, pick a bus, pick a seat, enter passenger details, pay, ticket. Flutter with Riverpod and go_router, no backend.

    busgo is a bus-ticket booking flow I built to practise one specific thing: a multi-step flow in Flutter without every screen knowing what comes next.

    That flow is genuinely all there is — there’s no HTTP client in pubspec.yaml, so all the data is local. What’s being exercised here is the navigation and the shape of the state, not integration.

    The flow

    login → home (search form)
          → select_bus_page
          → select_seat_sheet
          → passengger_form_sheet
          → waiting_payment
          → ticket → list_booking

    The three middle steps aren’t full pages but bottom sheets (select_seat_sheet, passengger_form_sheet, plus the shared bottom_sheet_selector and bottom_sheet_date_selector). The reason is practical: picking a seat and then changing your mind is normal, and dismissing a sheet feels far cheaper than hitting back on a full page.

    Routes and state

    Navigation goes through go_router in a single lib/router/app_router.dart, so every route is readable in one place and no screen pushes directly to another. State is Riverpod (flutter_riverpod + hooks_riverpod), with ProviderScope wrapped in a three-line main.dart:

    void main() {
      runApp(const ProviderScope(child: BusGoApp()));
    }

    The folder layout is by feature, not by file type:

    lib/features/{auth,home,booking,payment,profile}
    lib/shared/widgets      # bottom navigation + sheets used across features
    lib/router/app_router.dart

    Status

    A UI prototype. No backend, no real payment — waiting_payment just holds the screen. If it ever gets wired to an API, the layer to add is a repository under the providers; the screens shouldn’t have to know.

    id en
    rss gh in