Inspiration

The idea for WayBefore came from a personal frustration: trip planning is scattered. You end up with flights in one app, stays in another, packing lists on a notes app, and itineraries on a spreadsheet. I wanted one place where everything lives together — not just logistics, but the feeling of anticipation. The name "WayBefore" captures that: the exciting phase way before you actually board the plane, when the trip is still a dream taking shape.

I was also drawn to the idea that planning a trip is an emotional journey in itself. Choosing where to stay, deciding what to pack, writing a letter to your future self about why you're going, these aren't just tasks, they're moments of reflection. I wanted the app to honour that, not just check boxes.

When I came across Revenuecat's Shipyard Creator contest, Gabby's dream app really aligned well with what I had in mind and it felt like the universe was telling me to start developing

What I Learned

Flutter in landscape-first is a different beast. Most Flutter resources assume portrait. Building every screen as a two-panel landscape layout; left panel for navigation and context, right panel for content forced me to think about information hierarchy differently. Adding portrait support later via a custom OrientationMixin taught me about orientation listeners, animation controllers, and how to persist per screen state so the rotation hint overlay only appears once.

State management choices compound. I chose Provider with a StorageService backed by SharedPreferences. It's simple and it works, but as the app grew to 7+ screens with CRUD operations, I learned the value of keeping a consistent model pattern (immutable classes, copyWith, toJson/fromJson, enum serialization by .index). That consistency made adding new features like packing lists and transport decisions almost formulaic.

Monetization should feel like a natural next step, not a gate. Integrating RevenueCat for subscriptions taught me about entitlement checking, customer info listeners, and the importance of separating the purchase flow from the entitlement state. I initially hardcoded premium access for testing and later had to carefully wire it to real subscription checks. A reminder that testing shortcuts need clean removal paths.

Animation is about timing, not complexity. Adding Lottie celebrations (confetti on purchase, rocket on template apply, sunrise on first letter) and flutter_animate micro-interactions (staggered fade-ins during onboarding) transformed how the app feels. The technical lesson: .lottie files require both the dotlottie_loader and lottie packages, and AnimatedBuilder doesn't exist in Flutter despite what autocomplete might suggest.

How I Built It

The project started as "Becoming" a broader personal growth app and narrowed into WayBefore, a travel planning tool focused on a single destination (Hawaii) as the MVP.

Architecture: Every screen follows the same two-panel landscape layout pattern. A left panel (~300px) holds headings, navigation, or summary info. The right panel is an expanded scrollable area for the main content. Bottom sheets handle forms and overlays. This consistency meant I could build new screens quickly once the pattern was established.

Core stack:

  • Flutter (Dart 3.8.1) with landscape orientation locked in main.dart
  • Provider for dependency injection (StorageService, EntitlementProvider)
  • SharedPreferences for all persistence — itineraries, transport decisions, stays, packing lists, future letters
  • Google Fonts (Playfair Display + Lato) and a warm colour palette (cream, mustard, brown) for a travel-journal feel
  • RevenueCat (purchases_flutter) for subscription management
  • Lottie + dotlottie_loader for celebration animations
  • flutter_animate for entrance/transition micro-animations

Build order:

  1. Onboarding flow (welcome → profile → destination → date → loading)
  2. Home dashboard with 6 feature tiles and a readiness tracker
  3. Itinerary builder (full CRUD, day management, reorderable activities, premium templates)
  4. Transport mode selection with timeline impact
  5. Stays screen with free and premium locations loaded from a JSON asset
  6. Packing list with categories, progress tracking, and filters
  7. Reflections/Future Letters with prompt-driven decision memory and scheduled unlock notifications
  8. Premium paywall with RevenueCat integration
  9. Animations pass Lottie celebrations and flutter_animate micro-interactions across all screens
  10. Polish — orientation overlay persistence, premium entitlement wiring, deprecated API cleanup

Challenges I Faced

The rename from "Becoming" to "WayBefore" touched almost everything; package name, Android namespace, bundle identifiers, window titles, Gradle files (which also needed converting from .kts to .gradle), and CMakeLists. It was a tedious but necessary refactor that taught me how deep a name goes in a Flutter project.

Deprecated APIs kept appearing. Flutter deprecated withOpacity() in favour of withValues(alpha:), which meant updating colour calls across dozens of files. The timezone package needed to be an explicit dependency rather than transitive. zonedSchedule() for local notifications required a uiLocalNotificationDateInterpretation parameter that isn't obvious from the docs.

Celebration animations needed "only once" logic. Confetti on 100% packing completion should fire when you pack the last item, not every time you revisit the screen. This required tracking wasDone state before each toggle and using boolean flags (_completionCelebrated, _firstActivityCelebrated) to prevent repeats. For the home screen, the confetti trigger is computed during build(), so it needed addPostFrameCallback to avoid calling showGeneralDialog during the build phase.

The orientation overlay was annoying users. The landscape-to-portrait rotation hint appeared every single time a user visited any screen that supported it. Fixing this meant adding persistence to StorageService (a StringList of seen screen IDs), modifying the OrientationMixin to accept a screenId parameter, and updating all 6 screen call sites a small change in concept but touching many files.

Premium gating needed to be reactive. When a user buys a subscription, every screen needs to update immediately; Locked stays should unlock, intelligence panels should appear, template previews should expand. Using context.watch<EntitlementProvider>() with ChangeNotifier solved this, but it required careful placement to avoid unnecessary rebuilds and making sure checkSub() is called after both purchase and restore flows.

What's Next

WayBefore currently ships with Hawaii as the sole destination; A deliberate MVP choice to get the full planning experience right before scaling. Here's what's on the roadmap:

More destinations. Disneyland and Las Vegas are already teased in the destination picker as "Coming Soon." The next step is building out their location-specific data — curated itinerary templates, stay areas, transport options, and packing suggestions tailored to each destination. The architecture is destination-agnostic, so this is mostly a content effort.

User-created destinations. Beyond the curated options, users should be able to create their own destination from scratch: Enter a city, set up their own days, stays, and packing lists without relying on pre-built data. This opens the app up from "pick from our list" to "plan any trip you want."

Explore page. The home screen has a tile reserved for discovery. The vision is a browsable feed of destination highlights, travel tips, and community-contributed itineraries giving users inspiration before they commit to a destination.

Notifications. The notification service is built and letter unlock scheduling works, but there's more to do: daily planning reminders, countdown alerts as the travel date approaches, packing deadline nudges, and trip-day notifications. The flutter_local_notifications and permission_handler packages are already integrated, it's a matter of wiring up the trigger points.

Richer premium features. The premium paywall promises five feature groups (curated itineraries, transport intelligence, insider stays, smart packing, and decision recall). The gating logic and UI teasers are in place, but the actual premium content; Real template data, weather-aware packing suggestions, forgotten-item warnings, and past-letter insights still needs to be fleshed out with meaningful data and logic.

Portrait-first rethink. The app was built landscape-first with portrait as an afterthought via OrientationMixin. As the user base grows, a proper responsive layout that feels native in both orientations rather than just "supported" would make the experience smoother on phones held naturally.

Cloud sync and multi-device. Everything currently lives in SharedPreferences on a single device. Moving to a cloud backend would let users plan on their tablet and check their packing list on their phone a natural expectation for a travel app.

Built With

Share this project:

Updates