Skip to content

About

A standalone Flutter app (Android + iOS) demonstrating our mobile engineering: Clean Architecture, BLoC/Cubit, GetIt + injectable, Freezed and fpdart. Recreates the Showcase.NextJS/Android/iOS hero and portfolio — splash screen, animated logo, auto-advancing pager. No backend, no credentials.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Artificialss Showcase — Flutter

License: MIT CI Flutter Platforms: Android · iOS

A small, standalone cross-platform app demonstrating our mobile engineering: Flutter + Dart, Clean Architecture, BLoC / Cubit, GetIt + injectable for dependency injection, and Freezed + fpdart for immutable state and explicit error handling — the Flutter counterpart of Showcase.Android and Showcase.iOS.

It recreates the same Hero and Portfolio content shown on Showcase.NextJS, rebuilt for phones with a bottom navigation bar and an auto-advancing portfolio pager — no backend, no credentials.

Screenshots

Android (Pixel 9)

Splash Home Portfolio
Splash Home Portfolio

iOS (iPhone 16 Pro)

Splash Home Portfolio
Splash Home Portfolio

Demo

Android iOS
Android demo iOS demo

Click a preview for the full-quality video.

What's in here

  • Splash — fades in the brand logo and tagline on the brand-green background, then auto-navigates to Home.
  • Home — logo with an animated "Powered by AI" sign, headline, subtitle, and a CTA that opens artificialss.ai/portfolio in the browser.
  • Portfolio — a starry black-sky background with a PageView that auto-advances every 2 seconds through 7 projects (including this repo), each with an illustrated CustomPainter mockup and a tap-through link.

Architecture

Clean Architecture in three layers; BLoC/Cubit on top:

lib/
├── core/
│   ├── di/              # GetIt + injectable (injection.dart, app_module.dart, generated config)
│   ├── error/           # Failure — Freezed union, the Left side of Either<Failure, T>
│   ├── usecase/         # UseCase<T, Params> contract
│   ├── services/        # UrlLauncherService → Either<Failure, Unit>
│   ├── theme/           # Brand color tokens ported from the Next.js design system
│   └── widgets/         # Logo (+ animated sign), SpaceBackground
└── features/
    ├── splash/presentation/     # SplashCubit + SplashPage
    ├── home/presentation/       # HomeCubit + HomePage
    ├── main/presentation/       # NavigationCubit + bottom-nav shell
    └── portfolio/
        ├── domain/              # PortfolioItem (Equatable), repository interface, GetPortfolioItems use case
        ├── data/                # Mock data source + PortfolioRepositoryImpl (TaskEither.tryCatch)
        └── presentation/        # PortfolioBloc (+ Freezed state), page, pager, card, mockups
  • Domain is pure Dart — no Flutter imports. Use cases and repositories return Future<Either<Failure, T>> (fpdart), so errors are values, not thrown exceptions.
  • State is immutable. PortfolioBloc (event-driven) emits a Freezed union — loading | success | failure — and the UI switches over it exhaustively. Simpler flows (splash, home, tab navigation) use Cubits.
  • DI is injectable annotations on top of GetIt; build_runner generates the wiring.
  • Animation timing (the 2-second auto-advance) lives in the widget — PageController is a UI concern, not business logic.
  • The 4k-path logo is pre-compiled to a .vec asset (vector_graphics_compiler), so it isn't parsed at runtime.

Tech Stack

Layer Technology
Framework Flutter 3.47 / Dart
State flutter_bloc (Bloc + Cubit), equatable
DI get_it + injectable
Immutability / errors freezed, fpdart (Either, TaskEither)
Tests bloc_test, mocktail, integration_test

What's deliberately left out

No environment variables, API keys, analytics, or backend of any kind — the portfolio list is a static, deterministic mock data source, matching the other Showcase.* repos. External links open in the system browser.

Run it locally

flutter pub get
dart run build_runner build   # generates injectable + freezed code
flutter run                   # on any Android emulator or iOS simulator
flutter test                  # unit + bloc tests

How the demos were recorded (fully autonomous)

Every screenshot and video in docs/screenshots/ was captured with no human touching a device. The app drives itself (iOS) or is driven over adb (Android) while the platform's own screen recorder runs, and the raw footage is then trimmed and encoded by script. The whole pipeline is in tool/.

The walkthrough: splash → Home → tap Portfolio → pager auto-advances through all 7 projects → tap Home.

Step iOS Android
Device iPhone 16 Pro simulator Pixel 9 emulator (API 36)
Driver integration_test/demo_test.dart taps the nav bar and waits on the real clock (LiveTestWidgetsFlutterBindingFramePolicy.fullyLive) adb shell input tap against the installed release build
Recorder xcrun simctl io <device> recordVideo adb shell screenrecord
Script tool/record_ios.sh tool/record_android.sh

Then tool/process_video.sh turns the raw footage into the final assets with ffmpeg: it trims to the first frame of the splash, scales to 540 px wide, and exports demo.mp4 (H.264) plus a palette-optimised demo.gif. Screenshots are single full-resolution frames pulled from the same raw video.

# iOS — boot ONE simulator first
xcrun simctl boot <udid>
tool/record_ios.sh <udid> /tmp/ios_raw.mov
tool/process_video.sh /tmp/ios_raw.mov <start-s> <duration-s> docs/screenshots/ios

# Android — boot ONE emulator first
tool/record_android.sh emulator-5554 /tmp/android_raw.mp4
tool/process_video.sh /tmp/android_raw.mp4 <start-s> <duration-s> docs/screenshots/android

Things learned along the way (so the next re-record is quick):

  • Run one emulator/simulator at a time. Two at once exhausts memory; Android's low-memory killer then drops the test connection mid-run and the emulator can render a black screen.
  • Trim with filters, not -ss. Simulator and emulator recordings are variable-frame-rate, so seeking by timestamp lands on the wrong frame; fps=30,trim=… keeps the timeline consistent.
  • Record Android from a release build. A debug build sits on the native launch screen for 20 s+ on a cold emulator; release starts in about a second.
  • A widget test can't wait with Future.delayed (fake clock) — the iOS driver pumps frames in a loop with tester.runAsync so animations play at true speed.
  • The recording scripts reproduce the exact commands used to produce the committed assets; they have not been re-run end-to-end as scripts, so expect to adjust the <start-s> trim point and, on Android, the tap coordinates for other screen sizes.

License

MIT — see LICENSE. Free to use, modify, and distribute.


Built with Flutter by Artificialss

About

A standalone Flutter app (Android + iOS) demonstrating our mobile engineering: Clean Architecture, BLoC/Cubit, GetIt + injectable, Freezed and fpdart. Recreates the Showcase.NextJS/Android/iOS hero and portfolio — splash screen, animated logo, auto-advancing pager. No backend, no credentials.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages