Skip to content

Feat 2026 Rebrand - #244

Open
NewtonMutugi wants to merge 47 commits into
mainfrom
feat/2026_rebrand
Open

NewtonMutugi wants to merge 47 commits into
mainfrom
feat/2026_rebrand

Conversation

@NewtonMutugi

@NewtonMutugi NewtonMutugi commented Jul 15, 2026 •

Copy link
Copy Markdown
Member

Description

This pull request introduces a major visual and branding update across the application, shifting the color palette and assets from the previous Droidcon theme to the new Fluttercon branding. It also updates some dependencies and improves navigation and asset handling. Below are the most important changes:

Branding and Visual Redesign:

  • Replaced Droidcon-related colors (blueDroidconColor, orangeDroidconColor, etc.) with new Fluttercon colors (flutterconBlue, flutterconMagenta) throughout the codebase, affecting app bars, buttons, icons, backgrounds, and text styles. (lib/core/theme/theme_colors.dart [1] lib/core/theme/theme_data.dart [2] [3] lib/common/widgets/app_bar/app_bar.dart [4] [5] [6] lib/common/widgets/app_bar/feedback_button.dart [7] [8] lib/common/widgets/app_bar/user_profile_icon.dart [9] lib/common/widgets/bottom_nav/bottom_nav_bar.dart [10] lib/common/widgets/personnel_widget.dart [11] lib/features/about/ui/organising_team_details.dart [12] lib/features/home/ui/speaker_details/speaker_details.dart [13] lib/features/home/widgets/search_bar.dart [14] [15] lib/features/home/widgets/sessions_card.dart [16]
  • Updated asset references: removed flutterConKeLogo and replaced with new SVG assets flutterConLogoLight and flutterConLogoDark for light/dark theme support. Updated all logo usages to use these SVGs. (lib/common/utils/constants/app_assets.dart [1] lib/common/widgets/app_bar/app_bar.dart [2] lib/features/auth/ui/sign_in.dart [3]
  • Updated various widget backgrounds and surfaces to use scaffoldBackgroundColor from the theme for better consistency. (lib/common/widgets/app_bar/app_bar.dart [1] lib/common/widgets/bottom_nav/bottom_nav_bar.dart [2] lib/features/about/ui/about_screen.dart [3] lib/features/auth/ui/sign_in.dart [4]

Navigation Improvements:

  • Changed navigation to use pushNamed instead of goNamed for sign-in routes, ensuring proper navigation stack behavior. (lib/common/widgets/app_bar/feedback_button.dart [1] lib/common/widgets/app_bar/user_profile_icon.dart [2]
  • Added a custom back button to the sign-in screen for improved user experience. (lib/features/auth/ui/sign_in.dart lib/features/auth/ui/sign_in.dartL48-R60)

Dependency and Build System Updates:

Code and Dependency Injection Maintenance:

  • Removed the generateForDir: ['lib'] argument from the @InjectableInit annotation in the dependency injection setup. (lib/core/di/injectable.dart lib/core/di/injectable.dartL9-R9)

These changes collectively modernize the app’s appearance and branding, improve navigation, and keep dependencies up to date

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore

Issues

Test Changes on Device

You can download your APK from Firebase App Distribution once this PR builds successfully via the following link: https://appdistribution.firebase.dev/i/c796669942f8a811

Screenshots

Light mode

Home (top) Home (Conf. Essentials/Highlights) Sessions About Feed (error state) About (Organising Team)

Dark mode

Home dark Sessions dark About dark Feed dark

NewtonMutugi and others added 30 commits July 15, 2026 13:55
Android Studio now bundles JDK 25, which Gradle 8.14 cannot run
(it failed with 'Error resolving plugin dev.flutter.flutter-plugin-loader
> 25.0.3'). Gradle 9.1+ supports Java 25; pinned to 9.5.1 because
AGP 8.13.0 relies on a Gradle internal API removed in 9.6.0.

Verified: flutter build apk --flavor development succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
chore(android): upgrade Gradle wrapper to 9.5.1 for JDK 25 support
…le 3.3.2

- flutter upgrade: 3.44.6 -> 3.47.3 (Dart 3.12.2 -> 3.13.3)
- Moved isar_community/isar_community_flutter_libs/isar_community_generator
  off the 3.3.0-dev.3 prerelease pin onto stable 3.3.2. That prerelease
  transitively capped analyzer at <9.0.0, which crashed
  'dart run build_runner build' on Dart 3.13's dot-shorthand syntax
  (Exception: Missing implementation of visitDotShorthandPropertyAccess).
  Stable 3.3.2 allows analyzer <11.0.0, letting freezed resolve to 3.2.5
  and analyzer to 10.2.0, which understands the new syntax. This is the
  actual fix for the pr-check/release-apk 'build_runner' CI failures.
- Regenerated pubspec.lock, analysis_options.yaml, and
  macos/Flutter/GeneratedPluginRegistrant.swift via flutter pub get /
  code generation under the new SDK.

Verified:
- dart run build_runner build --delete-conflicting-outputs: succeeds
  (was crashing before)
- dart format --set-exit-if-changed lib test: clean
- flutter analyze lib: 1 pre-existing warning, no errors
- flutter build apk --flavor development --debug: succeeds

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
chore: upgrade Flutter SDK to 3.47.3, fix build_runner CI crash
- AGP 8.13.0 -> 9.4.0 and Kotlin Gradle plugin 2.2.20 -> 2.4.20, per
  Flutter's deprecation warning that support for the old versions will
  soon be dropped.
- AGP 9.4.0 requires Gradle >=9.6.0, so the wrapper is bumped
  8.13.0-era 9.5.1 -> 9.7.1 to match (9.5.1 was previously the ceiling
  because it was the last version AGP 8.13.0 tolerated).
- AGP 9.4.0 also removes support for getDefaultProguardFile('proguard-android.txt')
  (it hardcodes -dontoptimize, which blocks R8 optimizations); switched
  the release buildType to the '...-optimize.txt' variant it now requires.

Verified:
- flutter build apk --flavor development --debug: succeeds
- dart format --set-exit-if-changed lib test: clean
- flutter analyze lib: 1 pre-existing warning, no errors

Not included: migrating to Flutter's Built-in Kotlin (still warns that
several plugins - firebase_analytics, firebase_auth, firebase_core,
firebase_crashlytics, firebase_remote_config, share_plus - apply their
own Kotlin Gradle Plugin). That depends on upstream plugin releases,
not something this repo controls alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
chore(android): upgrade AGP to 9.4.0, Kotlin to 2.4.20, Gradle to 9.7.1
flutter analyze treats warnings as fatal by default, so this warning
was failing CI. It was previously masked by a build_runner crash (see
#251) that aborted the pipeline before the analyze step's exit code
mattered; once that crash was fixed, this became the new blocker.

signInWithGoogle() returned Future.value(authResult.credential?.accessToken)
from inside a try block without awaiting it, tripping
unawaited_return_in_try_block. Removing the unneeded Future.value
wrapper exposed a real, pre-existing type mismatch: the method's
declared return type is Future<String> (non-nullable) but
accessToken can be null. Fixed by throwing a Failure in that case,
consistent with how the rest of the method already handles invalid
auth states.

Verified:
- flutter analyze lib: no issues found (was 1 fatal warning)
- dart format --set-exit-if-changed lib test: clean
- No existing tests cover this method; project has no test/ files yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fix(auth): resolve unawaited_return_in_try_block analyzer warning breaking CI
Initializes Claude Code project guidance (CLAUDE.md) and a docs/
directory aimed at AI coding agents: deeper reference material with
file:line citations covering DI/state management, the Isar+Hive data
layer and cache-first fetch pattern, per-feature breakdown, routing
(including the missing auth guard and a stale globalNavigatorKey
getter), the full auth flow (including the reviewer-bypass ghost
sign-in), networking/error-mapping/flavor config (including a
60000-second Dio timeout typo and the fact all three flavors hit the
same API domain), notifications, and exactly what each GitHub Actions
workflow triggers on and does.

docs/README.md asks agents to keep these files updated as the code
they describe changes, rather than letting them go stale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs/README.md already asked for this, but CLAUDE.md is the file
guaranteed to load into every Claude Code session's context, so the
instruction needed to live there too, stated as a requirement rather
than a suggestion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs: add CLAUDE.md and AI-agent architecture docs
Analyzed the flutterconKE web redesign (flutterconKE2024Web#23, and
its dev branch design tokens/components) to ground a phased plan for
porting the same rebrand to this app. Documents what's already
aligned (primary/accent colors, the app-bar logo, bottom-nav accents
all already match the web's tokens) versus the real gap (color ramps,
rounded-card system, pill badges, stat-card color inversion, the
licensed Rauschen B display font, halftone/duotone imagery, pill
button language), plus the phase breakdown that will become GitHub
sub-issues under #243.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…256)

Foundation tokens for the 2026 flutterconKE rebrand
(docs/design/REBRAND-PLAN.md), ported from the flutterconKE web
repo's tailwind.config.js / globals.css on its dev branch. Nothing
here is wired into an existing screen yet — this is deliberately
inert until Phase 1+ adopts it.

- AppColorRamps: full blue50-900/magenta50-900 ramps, matching the
  web's Figma-export values exactly.
- Corners: extended with the rebrand's rounded-card scale
  (s16/s24/s32/s40) plus a pill/pillBorder/pillRadius trio for
  pill buttons and badges.
- PillBadge: level (magenta) / format (blue) chip widget, matching
  SessionListCard.tsx's levelPill/formatPill exactly.
- AppButtonStyles: primary/accent/outline pill ButtonStyle builders,
  matching .btn-primary/.btn-accent/.btn-outline. Opt-in — not wired
  into ThemeData's elevatedButtonTheme/outlinedButtonTheme defaults,
  since that would restyle every existing button as a side effect.
- AppTextStyles.display: Montserrat Black stand-in for the licensed
  Rauschen B display font, pending the Phase 0b decision
  (flutterconKEApp#257).
- InvertedPanelColors: a ThemeExtension encoding the two documented
  light/dark color-inversion panels (e.g. the About stat block),
  registered on both AppTheme.lightTheme()/darkTheme().

Verified: flutter analyze (clean), dart format (clean), full debug
APK build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…kens

feat(theme): rebrand Phase 0 — design tokens
…258) (#264)

Confirmed the app-bar/sign-in logo assets already pixel-match the web
repo's new rebrand mark (rendered both to PNG and compared directly,
light and dark variants) and that there are no stray pre-rebrand
hardcoded colors anywhere in lib/ — every color reference already
goes through ThemeColors. No asset or color-usage changes needed.

sign_in.dart's only visible button is the auth_buttons package's
GoogleAuthButton, which shouldn't be restyled (Google's own brand
guidelines govern its shape); the ghost sign-in path is a hidden
long-press gesture, not a visible button. So there was no real
apply-pill-styles work available on that screen specifically.

Applied Phase 0's pill language where a real opportunity existed
instead:
- FeedbackButton (app bar, visible on most screens): fixed 10px
  radius -> Corners.pillBorder
- LogOutDialog: confirm button -> Corners.pillBorder (kept red;
  that's destructive-action semantics, not a rebrand color); cancel
  button -> AppButtonStyles.outline

Left session_filter.dart's SegmentedButton/filter-panel buttons
alone — that's session-filtering UI, not global chrome, and belongs
with Phase 3's more thorough Sessions pass.

Verified: flutter analyze (clean), dart format (clean), full debug
APK build succeeds.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…utterconKEApp#257)

Checked the droidconKE/private-fonts repo's own README for the actual
license terms rather than assuming the web's build-time-fetch pattern
would transfer cleanly. It doesn't: the license explicitly permits
serving Rauschen B as a web font from droidcon's own infrastructure,
and explicitly forbids committing it to a public repo or sharing it
externally — but says nothing about bundling the file inside a
distributed app binary. A compiled mobile app ships the font file
inside every installed APK/IPA, trivially extractable by unzipping —
a materially different distribution than serving over HTTPS from a
server droidcon controls, and not something covered by the existing
grant.

Decision (confirmed with the repo owner): don't port this. Montserrat
Black (AppTextStyles.display, shipped in Phase 0) is the permanent
display font for this app, not a placeholder pending resolution.
Revisiting this would need an explicit confirmation from whoever
actually holds the Rauschen B license/usage rights (Out of the Dark
or droidcon's brand team) that app-binary embedding is covered — not
an inference from the web's existing, web-scoped grant.

Updated docs/design/REBRAND-PLAN.md and the AppTextStyles doc comment
accordingly; no functional code change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ision

docs: rebrand Phase 0b — decide against porting Rauschen B
* feat(about): rebrand Phase 2 — home/about stat panel (closes flutterconKEApp#259)

Ported the web's About-section 2x2 stat block
(components/home/About.tsx on flutterconKE2024Web's dev branch) —
same four values (3RD Fluttercon edition, 7th Droidcon edition, 230+
sessions delivered, 3,000+ attendees since 2018), same deliberate
light/dark color inversion (black+magenta figures in light, magenta+
white figures in dark).

Placement decision: the About screen, not Home. about_screen.dart
already had an About headline + description paragraph structurally
identical to the web's About section intro, so the stat block reads
as a natural continuation of that content rather than a dashboard
summary that fits Home. Left Home's hero-style header treatment out
of scope — that's a distinct, larger visual question from the web's
own Hero component, better handled on its own rather than folded
into this stat-panel port.

AboutStatsPanel (lib/features/about/widgets/about_stats_panel.dart)
reads Phase 0's InvertedPanelColors extension and AppTextStyles.display
rather than hardcoding the light/dark swap. Wired into about_screen.dart
right after the existing intro text, before Organising Team.

Verified visually, not just via analyze/build: ran the app on an
emulator, navigated to the About screen, and confirmed both
color-inversion states directly (toggled via
adb shell cmd uimode night yes/no) — matches the web's design
exactly in both modes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* feat(localization): update aboutFluttercon description for rebranding

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…loses flutterconKEApp#260)

Ported the web's SessionListCard.tsx / SpeakerCard.tsx pattern
(flutterconKE2024Web, dev branch, from PR #32) to both session card
variants and the speaker grid/detail screens.

- SessionTimeBadge (lib/features/sessions/ui/widgets/session_time_badge.dart):
  the rounded time-badge box, shared by both session card variants.
- CompactViewCard: rebuilt from a ListTile to a custom layout matching
  SessionListCard.tsx exactly - rounded-4xl bordered card,
  SessionTimeBadge, level/format PillBadges (skipped for service
  sessions, matching the web's !is_serviceSession check), speaker
  names in primary color.
- ScheduleViewCard: same rounded-4xl border + SessionTimeBadge + pill
  badges, added alongside its existing image banner and speaker-
  avatar row (kept - the web has no direct equivalent of this
  image-forward variant).
- SpeakerDuotoneAvatar (lib/features/home/widgets/speaker_duotone_avatar.dart):
  grayscale+contrast ColorFiltered, then a second ColorFiltered with
  BlendMode.screen against blue (Flutter's equivalent of the web's
  mix-blend-screen over a bg-blue-600 backdrop), plus a CustomPainter
  dot overlay. Wired into SpeakerGridTile and SpeakerDetailsPage, NOT
  into the shared PersonnelWidget (also used for About-screen
  organisers, which don't get this speaker-specific treatment on the
  web either).
- SpeakerGridTile also picked up the rounded-4xl bordered card shape.

Verified: flutter analyze (clean), dart format (clean), full debug
build succeeds. The session-card redesign (both view variants, light
+ dark mode) was confirmed visually on an emulator. The speaker
duotone avatar is verified by code review + clean analyze/build only
- the emulator's touch input stopped registering taps partway through
this phase's verification pass (swipes still worked; recovery
attempts didn't resolve it) - flagged in the plan doc as worth a
manual look on a real device or fresh emulator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…speakers

feat(sessions,speakers): rebrand Phase 3 — session & speaker cards
…oses flutterconKEApp#261) (#269)

Applied Phase 0's rounded-card/pill tokens across the remaining
screens so nothing looks pre-rebrand next to the Sessions/Speakers
screens from Phase 3.

- SponsorsCard/OrganizersCard: outer card radius -> Corners.s24Border,
  inner logo tiles -> Corners.s16Border, border changed from
  dark-mode-only (transparent in light, primary in dark) to always-on,
  matching every other rebrand card. Added missing item spacing to
  SponsorsCard's horizontal tile list - it previously relied on the
  light-mode border being invisible to hide the lack of a gap; with
  an always-on border that would have made adjacent tiles look fused.
- feed_screen.dart: each post wrapped in a Corners.s32Border-bordered
  card (replacing a bare divider-separated list); feed images moved
  from a Container with a borderRadius that was never actually
  clipping its child (BoxDecoration.borderRadius doesn't clip content
  - a pre-existing no-op) to a proper ClipRRect with Corners.s16Border.
- feedback_screen.dart: submit button now uses AppButtonStyles.primary
  instead of a hand-rolled ElevatedButton.styleFrom. Also fixed its
  label color, previously colorScheme.surface (near-black in dark
  mode - dark text on a blue button background, a pre-existing
  low-contrast bug), to plain white matching the button style.
- EmojiContainer: radius bumped to Corners.s16Border to match the
  rest of the card scale.
- About/organiser cards: no change needed - organising_team.dart
  uses the shared PersonnelWidget (deliberately excluded from the
  speaker-only duotone treatment per Phase 3), and
  organising_team_details.dart has no card chrome to restyle.

Verified: flutter analyze (clean), dart format (clean), full debug
build succeeds. SponsorsCard/OrganizersCard confirmed visually on an
emulator in both light and dark mode. The feed card restyle could
not be visually confirmed - the test event's feed endpoint returned
no data on this build, unrelated to this phase. The feedback button
swap is verified by code review and clean analyze/build only, since
it reuses the already-proven AppButtonStyles.primary.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…flutterconKEApp#262)

Ran a full accessibility/contrast pass over every color pairing
introduced by the rebrand (WCAG relative-luminance contrast ratio,
not eyeballed) rather than just checking it looked fine.

Fixed two real findings that were ours to fix without deviating from
the web's shipped design:
- PillBadge's format variant and SessionTimeBadge's light-mode text
  used flutterconBlue (blue700) text on blue50 background - 3.2:1,
  below the 4.5:1 AA threshold for this text size. Neither is a
  literal copy of one specific shipped web value for this exact
  pairing (they're independent component choices informed by the
  same palette), so swapped to blue800 from the same ramp - 5.1:1,
  passes AA, visually indistinguishable at a glance.

Found and documented, but deliberately NOT changed, three contrast
findings that are inherited from the shared design system and already
shipped identically on the public website:
- AppButtonStyles.primary (white on flutterconBlue, 3.4:1) - a direct
  copy of the web's .btn-primary.
- InvertedPanelColors.dark (white on magenta, 3.1:1) - the explicit,
  documented color-inversion decision from the web.
- Bottom-nav selected-item magenta on white (3.1:1) - predates this
  rebrand entirely.
All three clear AA for large text (>=3:1) but not small/normal text.
Fixing them would mean diverging from the web or from an explicit
design decision, which defeats this migration's purpose - flagged
for a design-system-level conversation instead of a unilateral patch.

Also:
- Dark-mode QA re-confirmed across Phase 2-4 deliverables (About
  stats inversion, session cards, sponsors/organisers cards) -  all
  correct in both themes.
- Responsive check: reasoned AboutStatsPanel's fixed-aspect-ratio
  grid (the component most likely to be fragile) through a 320dp
  device width budget - clears with margin even with its longest
  label wrapping to two lines. Not re-verified on an actual
  small-width emulator.
- Removed ThemeColors.greyDarkThemeBackground (zero usages) and
  assets/images/flutterconke_logo.png (the pre-rebrand logo bitmap,
  unreferenced anywhere once the Flutter-blue SVG mark replaced it).
  Left unrelated pre-existing unused Corners scale entries alone -
  they predate this rebrand and aren't unused because of anything
  this migration did.
- Checked docs/architecture.md and docs/data-layer.md against the
  current code - both still accurate, no updates needed.

This closes out the 2026 flutterconKE rebrand migration (#243) - all
phases shipped.

Verified: flutter analyze (clean), dart format (clean), full debug
build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
NewtonMutugi and others added 12 commits October 12, 2026 13:16
Reported by the user: a Flutter debug overflow banner appeared
pinned to the right edge of CustomAppBar on their physical device
(1080x2400) across Home, Feed, and Sessions.

Root cause: the fluttercon wordmark SVG has an intrinsic aspect
ratio of ~5.8:1 (87x15 viewBox). At the app bar's fixed height: 32,
it renders ~186dp wide - combined with FeedbackButton (127dp) +
spacing (15dp) + UserProfileIcon (30dp), the title Row's fixed-width
children sum to ~358dp before any padding, which is too tight on a
device logical width in the ~400dp range. This was never visible on
the large tablet-class emulator used throughout this rebrand's
verification passes.

Fix: wrap the logo in Flexible + FittedBox(fit: BoxFit.scaleDown),
so it shrinks gracefully under space pressure instead of forcing its
full intrinsic width and overflowing. No visual change on screens
with enough room (which is every device tested so far, including
the previous emulator) - this only kicks in when space is actually
tight.

Verified on the reporting user's own physical device (confirmed by
matching screen resolution): rebuilt, reinstalled, and reproduced
the fix working on Home, Feed, and Sessions - no overflow banner,
logo scales down cleanly, Feedback pill and avatar unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…cally scaling

The previous fix (Flexible + FittedBox) stopped the overflow but
introduced a new problem, caught by the user: FeedbackButton renders
as a zero-size SizedBox() on Home (selectedIndex == 0) but a real
127dp pill everywhere else, so the available width for the logo
differed per tab - FittedBox shrank it more on Feed/About/Sessions
than on Home, making the brand mark visibly different sizes
depending which tab you were on.

Replaced with a single fixed height: 24 (down from 32) on every tab.
At this size the logo (~140dp wide at its 5.8:1 intrinsic aspect
ratio) comfortably fits even the tightest case - Feed/About, with
the full Feedback pill (127dp) + spacing (15dp) + avatar (30dp) - on
the user's exact device (360dp logical width, confirmed via adb).

Verified on the user's own physical device: rebuilt, reinstalled,
confirmed the logo is now the same size on Home and Feed (the
tightest tab) with no overflow banner on either.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Sessions tab's app bar crowded the logo together with the
compact/schedule view-toggle icons and the Filter button, all
squeezed into one toolbar-height row with no room to breathe -
flagged by the user as looking crowded.

- New SessionViewToolbar (lib/features/sessions/ui/widgets/session_view_toolbar.dart):
  a dedicated secondary toolbar living below the app bar, as the
  first header sliver in SessionsScreen's NestedScrollView. Holds the
  view toggle (now a proper pill-shaped segmented control using
  Corners.pillBorder, matching the rebrand's button language) and the
  Filter trigger (now an outlined pill button instead of bare grey
  text+icon).
- CustomAppBar: removed the selectedIndex==2 special case entirely
  (onCompactTapped/onScheduleTapped/selectedScheduleIndex params
  gone) along with the now-unused SessionFilter/WoltModalSheet
  wiring that moved to SessionViewToolbar. The app bar is back to
  just logo + feedback + avatar on every tab, including Sessions -
  it had been the only tab hiding those to make room for the icons
  that just moved out, so this also makes all four tabs' app bars
  consistent with each other.

Verified on the user's own device: app bar is no longer crowded,
view toggle and filter both still function (confirmed switching to
schedule view), no overflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Feed screen's error state just rendered the raw API error
message (e.g. literally 'Not found') as bare bold text pinned to the
top-left of the screen, with no icon, heading, context, or way to
retry - flagged by the user as a bad experience. The empty-posts
state had the same problem, just plain centered text.

New FeedStatusView (lib/features/feed/widgets/feed_status_view.dart):
a centered icon in a soft brand-blue circle + bold title + muted
message, with an optional retry button (AppButtonStyles.primary).
Used for both cases:
- Empty (no posts): dynamic_feed icon, 'No posts found' /
  'Check back later for updates from the team.', no retry (nothing
  to retry - there's just nothing there yet).
- Error: wifi_off icon, 'Couldn't load the feed' as the heading with
  the actual API error message underneath for context, and a
  'Try again' button wired to fetchFeeds(forceRefresh: true).

Added noPostsMessage/feedErrorTitle/tryAgain l10n strings.

Verified on device: confirmed the error state renders correctly
(this test event's feed endpoint genuinely has no data, so the error
case was reproducible) and that Try Again correctly re-triggers the
fetch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reported by the user with a logcat trace showing a 404 on the
sessions schedule endpoint: the Sessions screen's BlocBuilder used
state.maybeWhen(orElse: ..., loaded: ...) with no explicit error
case, so a failed FetchGroupedSessionsCubit fetch fell into orElse
and just showed the loading spinner forever instead of ever
surfacing the failure.

Audited every maybeWhen a fetch cubit's BlocBuilder uses and found
two more instances of the identical bug (no error: branch at all,
not even unstyled text) beyond the one reported:
- SessionsScreen (full-page spinner, the one reported)
- Home's SessionsCard (both the horizontal session-preview list and
  its small '+N' count badge)
- About's OrganisingTeamView (the individual-organisers grid)

All three now use the shared StatusView (promoted from Feed's
feed_status_view.dart, since Sessions needed the identical icon +
title + message + retry pattern - see the previous commit) in their
error branch, each wired to that screen's own forceRefresh retry
call. The '+N' badge is small/inline enough that a full StatusView
would be visually heavy there, so it just hides instead of spinning
forever - the main list below it already surfaces the error properly.

Added sessionsErrorTitle/organisersErrorTitle l10n strings
(feedErrorTitle/tryAgain already existed from the Feed fix).

Verified: flutter analyze (clean), dart format (clean), full debug
build succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reported by the user as 'No element issues' appearing on Home after
switching the dev event slug to fluttercon-ke-2026-222: that event's
sponsors are tiered platinum/bronze only, and SponsorsCard
unconditionally called sponsors.firstWhere((s) => s.sponsorType ==
SponsorType.gold) with no orElse - a Dart StateError ('Bad state: No
element') whenever no sponsor happens to be tier gold specifically.

Fixed by picking the featured sponsor dynamically: walk a tier
priority list (platinum > gold > silver > bronze > swag > startup >
venue) and feature whichever tier the event's sponsors actually have
the highest-ranking match for, instead of hardcoding 'gold'. Also
guards the now-empty-list edge case (renders nothing rather than
crashing) and renamed the confusingly-named nonPlatinumSponsors
variable (it filtered by gold, not platinum) to remainingSponsors.

Audited the rest of the codebase for the same unguarded
.firstWhere()/.first pattern - this was the only unsafe instance;
the others are either already guarded with orElse or operate on
collections Flutter guarantees are non-empty (e.g. SegmentedButton's
onSelectionChanged).

Verified on an emulator with the real fluttercon-ke-2026-222 event
data: Sponsors section now renders Flutter (platinum) as the
featured sponsor with Typesense below, no crash.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The new event's schedule API returns room ids as strings (e.g.
"room-a") instead of numbers, which crashed the fromJson cast with
"type 'String' is not a subtype of type 'num'" on both the Room model
and its Isar-backed LocalRoom mirror.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace SponsorsCard's single-featured-logo-plus-scroll-row layout with
the web's tiered sections (dashed divider + tier label + logo card per
tier, matching flutterconKE2024Web's SponsorsList.tsx). Replace
OrganizersCard's bordered horizontal scroll strip with the web's pink
"Organised by" banner and white logo tile grid ("Our Community
Partners" on the web). Both now use StatusView for error states
instead of raw error text, for consistency with the rest of the app.

ResolvedImage gains optional height/width so callers can size logos
per-tier instead of relying on its screen-proportional default.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…& Highlights sections

Apply the web's blue-duotone photo treatment (SpeakerDuotoneAvatar) to
the shared PersonnelWidget, which the Home speaker preview and the
About screen's organising team grid both use — previously only the
full speaker list page had it, leaving speakers/organisers elsewhere
with plain photos. Centers and bolds the name/designation labels to
match.

Add two new Home sections mirroring the web homepage
(flutterconKE2024Web `dev` branch): "2026 Conf. Essentials" (a
gradient card with Panels/Workshops/Networking/Exhibitions icons plus
a "More Stacks. All Mobile." tech-logo strip) and "Conf. Highlights"
("Beyond the Sessions" / "Developer Days" cards), built from the SVGs
and images added for this.

Also includes the flutterConBanner asset swap (new 2026 banner image)
that was already staged for this same home_screen.dart/app_assets.dart
area.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kotlin/Swift/AI/Flutter/DroidCon/React/FlutterCon.svg defined colors
via <defs><style>.cls-N{fill:#...}</style></defs> + class="cls-N",
which flutter_svg doesn't support (it only resolves presentation
attributes, not CSS class selectors) — every shape silently fell back
to black. Inlined each class's fill as a direct attribute and dropped
the now-unused <style> block, so the icons render in their actual
brand colors instead of black silhouettes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fix(a11y): rebrand Phase 5 — polish, contrast fixes, cleanup
@NewtonMutugi
NewtonMutugi marked this pull request as ready for review October 13, 2026 22:31
@NewtonMutugi

NewtonMutugi commented Oct 13, 2026 •

Copy link
Copy Markdown
Member Author

@wangerekaharun @KendiJ
I believe all the new design updates have been fully handled. You can test and check whether everything is working as expected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flutter app redesign / 2026 rebrand — design language + implementation plan

1 participant