Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
2c0953f
chore: update gradle.properties and pubspec.lock file
NewtonMutugi Jul 15, 2026
d69641c
feat: update app branding with new theme colors and design system ref…
NewtonMutugi Jul 15, 2026
da5a25a
feat: update authentication navigation to use pushNamed and add back …
NewtonMutugi Jul 15, 2026
741750e
feat: update fluttecon logo and implement responsive theme-aware SVG …
NewtonMutugi Jul 15, 2026
e7916c7
style: update switch track color to flutterconBlue in sessions screen
NewtonMutugi Jul 15, 2026
46a0a17
feat: replace android icon with flutter dash and add new flutter icon…
NewtonMutugi Jul 15, 2026
b89edf9
refactor: clean up imports, format UI components, and remove unused t…
NewtonMutugi Jul 15, 2026
d7dba9d
chore(android): upgrade Gradle wrapper to 9.5.1 for JDK 25 support
NewtonMutugi Sep 10, 2026
2c3170b
Merge pull request #250 from droidconKE/chore/gradle-9-java25-support
NewtonMutugi Sep 11, 2026
c14612b
chore: upgrade Flutter SDK to 3.47.3 and unpin isar_community to stab…
NewtonMutugi Sep 11, 2026
4b2e317
Merge pull request #251 from droidconKE/chore/flutter-upgrade
NewtonMutugi Sep 11, 2026
d95404e
chore(android): upgrade AGP to 9.4.0, Kotlin to 2.4.20, Gradle to 9.7.1
NewtonMutugi Sep 11, 2026
89a956a
Merge pull request #252 from droidconKE/chore/agp-kotlin-upgrade
NewtonMutugi Sep 11, 2026
9fedb00
fix(auth): resolve unawaited_return_in_try_block analyzer warning
NewtonMutugi Sep 11, 2026
0cb43b6
Merge pull request #253 from droidconKE/fix/analyze-fatal-warning
NewtonMutugi Sep 11, 2026
b0d2630
docs: add CLAUDE.md and AI-agent architecture docs
NewtonMutugi Sep 11, 2026
8774384
docs: make keeping docs/ current an explicit, non-optional instruction
NewtonMutugi Sep 11, 2026
175c51e
Merge pull request #254 from droidconKE/docs/ai-agent-architecture-docs
NewtonMutugi Sep 11, 2026
e319b51
docs: add 2026 rebrand migration plan (flutterconKEApp#243)
NewtonMutugi Sep 11, 2026
e8c11c8
Merge pull request #255 from droidconKE/docs/rebrand-migration-plan
NewtonMutugi Sep 11, 2026
46e84ed
feat(theme): rebrand Phase 0 — design tokens (closes flutterconKEApp#…
NewtonMutugi Sep 11, 2026
07edeba
Merge pull request #263 from droidconKE/feat/rebrand-phase0-design-to…
NewtonMutugi Sep 14, 2026
16615f7
feat(theme): rebrand Phase 1 — global chrome (closes flutterconKEApp#…
NewtonMutugi Sep 15, 2026
f68b4b4
docs: rebrand Phase 0b — decide against porting Rauschen B (closes fl…
NewtonMutugi Sep 16, 2026
a7eb107
Merge pull request #265 from droidconKE/docs/rebrand-phase0b-font-dec…
NewtonMutugi Sep 16, 2026
467411b
feat(about): rebrand Phase 2 — home/about stat panel (#267)
NewtonMutugi Sep 17, 2026
c7f2d3a
feat(sessions,speakers): rebrand Phase 3 — session & speaker cards (c…
NewtonMutugi Oct 9, 2026
31e4759
Merge pull request #268 from droidconKE/feat/rebrand-phase3-sessions-…
NewtonMutugi Oct 10, 2026
e44812b
feat(sponsors,feed,feedback): rebrand Phase 4 — remaining screens (cl…
NewtonMutugi Oct 12, 2026
a237e52
fix(a11y): rebrand Phase 5 — polish, contrast fixes, cleanup (closes …
NewtonMutugi Oct 12, 2026
237a6e4
fix(app-bar): prevent RenderFlex overflow on narrower real devices
NewtonMutugi Oct 12, 2026
366270b
fix(app-bar): make logo size consistent across tabs instead of dynami…
NewtonMutugi Oct 12, 2026
94ccb91
refactor(sessions): move view-toggle/filter controls out of the app bar
NewtonMutugi Oct 12, 2026
e59108c
feat(feed): replace bare error/empty text with a proper status view
NewtonMutugi Oct 12, 2026
5b2ff87
fix(network): stop spinning forever on a failed fetch
NewtonMutugi Oct 13, 2026
24bcf6e
fix(home): stop SponsorsCard crashing when no sponsor is tier 'gold'
NewtonMutugi Oct 13, 2026
c7fd92c
fix(sessions): stop schedule fetch crashing on string room ids
NewtonMutugi Oct 13, 2026
aa22a42
feat(home): redesign Sponsors/Organised-by cards to match the web app
NewtonMutugi Oct 13, 2026
a2eb4b2
feat(home): add blue duotone speaker/organiser tint, Conf Essentials …
NewtonMutugi Oct 13, 2026
e577ac4
fix(assets): resolve CSS-class fills in Conf Essentials tech-stack SVGs
NewtonMutugi Oct 13, 2026
97ecd6f
fix(config): update eventSlug for FlutterCon 2026
NewtonMutugi Oct 13, 2026
86bbd6a
Merge pull request #270 from droidconKE/feat/rebrand-phase5-polish
NewtonMutugi Oct 13, 2026
6ffd49f
feat(organising-team): enhance PersonnelWidget with maxWidth for bett…
NewtonMutugi Oct 14, 2026
b84774a
fix(organising-team): streamline padding definition in SliverPadding
NewtonMutugi Oct 14, 2026
62d8c0b
fix(config): update eventSlug for FlutterCon 2026 in production and s…
NewtonMutugi Oct 15, 2026
a9eed01
feat(ci): add release-internal.yml for manual internal testing AAB bu…
NewtonMutugi Oct 16, 2026
d8501a9
fix(version): update app version to 1.21.00+12100
NewtonMutugi Oct 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/release-internal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Release Internal Testing AAB

on:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'adopt'

- name: 📚 Git Checkout
uses: actions/checkout@v5

- name: 🐦 Setup Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: 3

- name: 📦 Install Dependencies
run: flutter packages get

- name: ✨ Check Formatting
run: dart format --set-exit-if-changed lib test

- name: ⚙️ Code Generation
run: dart run build_runner build --delete-conflicting-outputs

- name: 🕵️ Analyze
run: flutter analyze lib

- name: ⚙️ Download Android keystore
id: android_keystore
uses: timheuer/base64-to-file@v1.2
with:
fileName: key.jks
encodedString: ${{ secrets.PROD_KEYSTORE }}

- name: 🔐 Create key.properties
run: |
echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > android/key.properties
echo "storePassword=${{ secrets.PROD_KEYSTORE_PASSPHRASE }}" >> android/key.properties
echo "keyPassword=${{ secrets.PROD_KEYSTORE_PASSWORD }}" >> android/key.properties
echo "keyAlias=${{ secrets.PROD_KEYSTORE_ALIAS }}" >> android/key.properties

- name: ⚙️ Build AAB
run: flutter build appbundle --flavor production --target lib/main_production.dart -v

- name: ⚙️ Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.0"
bundler-cache: true

- name: ⚙️ Cache bundle dependencies
uses: actions/cache@v4
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: ${{ runner.os }}-gems-

- name: ⚙️ Download bundle dependencies
run: |
gem install bundler:2.0.2
bundle install

- name: 🚀 Release to Google Play (Internal testing)
env:
SUPPLY_PACKAGE_NAME: ${{ secrets.ANDROID_PACKAGE_NAME }}
SUPPLY_JSON_KEY_DATA: ${{ secrets.PLAY_STORE_CREDENTIALS }}
run: |
bundle exec fastlane supply \
--aab build/app/outputs/bundle/productionRelease/app-production-release.aab \
--track internal
70 changes: 70 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Keep `docs/` current — this is required, not optional

This repo has a `docs/` directory (see `docs/README.md` for the index) written for AI agents:
architecture, data layer, features, routing, auth, networking, notifications, and CI/build details,
each with file:line citations. **Any change you make that invalidates something described there must
update the relevant doc file in the same commit/PR** — a new repository or Cubit, a changed fetch or
auth pattern, a new/removed route, a CI workflow edit, a new feature module, a dependency-injection
change, and so on. Treat a stale doc as a bug in your own change, not a separate follow-up task.

Before finishing any non-trivial change, ask: "does anything in `docs/` now describe this incorrectly?"
If yes, fix it as part of the same change. If you notice a doc is already stale for an unrelated reason
while working on something else, fix that opportunistically too rather than leaving it.

## Commands

```bash
flutter packages get # install dependencies
dart run build_runner build --delete-conflicting-outputs # regenerate freezed/json_serializable/isar/hive_ce/injectable code (required after touching any model, repository, or DI annotation)
dart format --set-exit-if-changed lib test # format check (CI-enforced)
flutter analyze lib # static analysis — CI treats ANY warning as fatal (exit 1), not just errors
flutter run --flavor development --target lib/main_development.dart # run dev flavor
flutter run --flavor staging --target lib/main_staging.dart # run staging flavor
flutter run --flavor production --target lib/main_production.dart # run production flavor
flutter build apk --flavor <flavor> --target lib/main_<flavor>.dart # build APK for a flavor
```

There is no `test/` directory with any test files yet — `flutter test` has nothing to run. CI (`pr-check.yml`) only gates on format + codegen + `flutter analyze`, run against PRs targeting `main` (not against `feat/*` branches directly — see Architecture below for why that matters).

`android/key.properties` is required locally to build (points at a shared public dev keystore for Firebase social-auth SHA1 matching) — see README.md "APK Signing" for the exact contents to create.

Gradle/AGP/Kotlin versions are pinned tightly together (`android/gradle/wrapper/gradle-wrapper.properties`, `android/settings.gradle`): AGP's minimum-supported Gradle version has been the recurring blocker when bumping either — check AGP's release notes for its Gradle floor before bumping one without the other.

## Architecture

### CI targets `main`, not the working branch

`.github/workflows/pr-check.yml`, `release-apk.yml`, and `release.yml` only trigger on `pull_request`/`release` events aimed at **`main`**. If active development happens on a long-lived branch (e.g. `feat/2026_rebrand`) with PRs stacked on top of *that* branch instead of `main`, none of those PRs get CI-checked — only the eventual PR from that branch into `main` does. When diagnosing "CI is failing," first confirm which PR the check actually ran on.

### Dependency injection: `injectable` + `get_it`, singletons only

`lib/core/di/injectable.dart` calls a generated `getIt.initGetIt()` (`@InjectableInit`). Every `@singleton`-annotated repository/service (`ApiRepository`, `AuthRepository`, `DBRepository`, `FirebaseRepository`, `HiveRepository`, `ShareRepository`, `NotificationService`, `FlutterConRouter`) is eagerly constructed with no injected constructor args — each wires its own dependencies internally. There are no `@injectable` (factory) registrations. **Cubits are not part of the DI graph at all** — they're constructed by hand in `lib/bootstrap.dart` (pulling repositories via `getIt()`) and provided app-wide through one large `MultiBlocProvider`. Adding a new Cubit means adding it to that list, not annotating it.

### Two local persistence stores with different jobs

- **Isar** (`isar_community`, `lib/common/repository/db_repository.dart`, models in `lib/common/data/models/local/*.dart`) is the queryable offline content cache: feed entries, speakers, sessions, sponsors, organisers. Used because it supports `.filter()` queries for search/browsing.
- **Hive** (`hive_ce`, `lib/common/repository/hive_repository.dart`, `lib/common/data/models/adapters.dart`) is the small key-value store: auth token, user profile, theme mode preference. Keyed to a per-flavor box name (`FlutterConValues.hiveBox`, e.g. `fluttercon-dev`).

Logout (`LogOutCubit`) wipes both: all Isar tables via `DBRepository.clearAllTables()`, and the token/profile/sessions keys via `HiveRepository.clearPrefs()`.

### Fetch pattern: cache-first, silent background refresh

Cubits that load list data (sessions, speakers, sponsors, organisers, feed) follow the same shape: if Isar already has data, emit `Loaded` from it immediately and kick off a network refresh in the background *without re-emitting* — the UI won't show newly-fetched data until the next explicit fetch. If Isar is empty (or `forceRefresh: true`), fetch from `ApiRepository` first, persist to `DBRepository`, then read back and emit. `SearchCubit` never touches the network — it's pure Isar filter queries. This means "data looks stale" bugs are usually about this silent-refresh path, not a caching bug per se.

### Routing has no auth guard

`lib/common/utils/router.dart` (go_router) declares routes but no `redirect:` logic. `lib/features/splash/splash_screen.dart` unconditionally navigates to the dashboard (its own comment notes auth-redirect was intentionally bypassed) — sign-in is reached manually, not enforced. Auth state lives in Hive and is only consulted by things that need a token (e.g. `NetworkUtil` attaching `Authorization: Bearer`, `BookmarkSessionCubit` gating on `HiveRepository.retrieveToken()`), not by routing.

The dashboard's bottom-nav (Home/Feed/Sessions/About) is a plain `PageView` inside `DashboardScreen`, not a go_router `ShellRoute` — tab switches don't change the URL/route stack.

### Flavors

Three entrypoints (`lib/main_development.dart`, `lib/main_staging.dart`, `lib/main_production.dart`) each construct a `FlutterConConfig` singleton (`lib/common/utils/env/flavor_config.dart`) with flavor-specific `baseDomain`, `hiveBox`, `eventSlug`, `organiserSlug` before calling `bootstrap()`. `NetworkUtil` reads the active config for its base URL. All three CI/release workflows only ever build the `production` flavor — `staging`/`development` are local-only.

### Networking accepts any TLS certificate

`lib/common/utils/network.dart`'s `badCertificateCallback` always returns `true`. Be aware of this if working on anything network-security-adjacent; it's an existing behavior, not something to silently "fix" as a drive-by in an unrelated change.
4 changes: 4 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ analyzer:
- lib/generated_plugin_registrant.dart
- lib/**/*.g.dart
- lib/**/*.freezed.dart
- build/**
- android/**
- ios/**
- macos/**
errors:
invalid_annotation_target: ignore

Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ android {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt')
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
}
debug {
signingConfig signingConfigs.release
Expand Down
6 changes: 5 additions & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ org.gradle.jvmargs=-Xmx4g
android.useAndroidX=true
android.enableJetifier=true
android.enableAapt2Daemon=false
kotlin.daemon.jvm.options=-Xmx2g
kotlin.daemon.jvm.options=-Xmx2g
# This builtInKotlin flag was added automatically by Flutter migrator
android.builtInKotlin=false
# This newDsl flag was added automatically by Flutter migrator
android.newDsl=false
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-all.zip
4 changes: 2 additions & 2 deletions android/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ pluginManagement {

plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id 'com.android.application' version '8.13.0' apply false
id 'com.android.application' version '9.4.0' apply false
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.4.3" apply false
id "com.google.firebase.crashlytics" version "3.0.6" apply false
// END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "2.2.20" apply false
id "org.jetbrains.kotlin.android" version "2.4.20" apply false
}

include ":app"
10 changes: 10 additions & 0 deletions assets/images/SVG/AI.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions assets/images/SVG/DroidCon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading