Skip to content
burakJsPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

47 Commits

Folders and files

Repository files navigation

Lokaly πŸ“

Drop yourself into TΓΌrkiye's most famous places with AI, then share it.

Lokaly is a social photo app. You upload a photo of yourself, pick a city and a landmark, and AI realistically places you at that spot β€” keeping your face and appearance intact. The generated image lands in a social feed where it can be liked, commented on, and shared.


Screenshots

Auth

Login Google Sign-In
Login Google Sign-In

Create Flow

1 Β· Select City 2 Β· Select Place 3 Β· Select Photo
Select City Select Place Select Photo
Generating Result Native Share
Generating Result Share

Social

Feed Comments Profile
Feed Comments Profile

Account & Settings

Edit Profile Settings (EN) Settings (TR)
Edit Profile Settings English Settings Turkish

Features

  • πŸ“Έ AI placement β€” upload your photo and get realistically placed at a famous Turkish landmark
  • πŸ™οΈ 81 cities β€” landmark suggestions are fetched live per city via Gemini
  • πŸ€– Person-preserving generation β€” your face and appearance stay identical to the reference
  • 🧭 Guided 4-step create flow β€” City β†’ Place β†’ Photo β†’ Result with a progress bar
  • ❀️ Social feed β€” like, comment, and follow other users
  • πŸ“€ Share β€” share generated photos through the native share sheet
  • πŸ‘€ Profiles β€” stats, post grid, editable username / bio / avatar
  • πŸŒ— Theme β€” Light / Dark / System
  • 🌍 Localization β€” Turkish & English (easy_localization)
  • πŸ” Auth β€” email/password and Google Sign-In via Firebase

Tech Stack

Layer Technology
Framework Flutter (Dart SDK ^3.12)
Page state flutter_bloc (Cubit)
Global state provider (AppState)
Navigation go_router
Extensions kartal
Auth firebase_auth + google_sign_in
Database cloud_firestore
Storage firebase_storage
AI (landmarks) firebase_ai β€” Gemini 2.5 Flash
AI (image) firebase_ai β€” Gemini 2.5 Flash Image
Images image_picker, cached_network_image, flutter_image_compress
Sharing share_plus
Localization easy_localization
Fonts google_fonts (Manrope)
Env flutter_dotenv
Models freezed + json_serializable
Unit tests flutter_test, mockito, bloc_test
Integration tests patrol

Getting Started

Prerequisites

  • Flutter SDK (latest stable, Dart ^3.12)
  • A Firebase project with Authentication (Email + Google), Firestore, and Storage enabled
  • Firebase AI (Gemini) enabled on the project
  • flutterfire_cli installed

Setup

git clone https://github.com/burakJs/Lokaly.git
cd lokaly
flutter pub get

Configure Firebase (generates firebase_options.dart and platform config):

dart pub global activate flutterfire_cli
flutterfire configure

Create a .env file in the project root (it is referenced as an asset in pubspec.yaml):

# Optional β€” only needed for Google Sign-In on Android.
# The Google "Web client" OAuth ID (serverClientId). Leave empty to rely on
# platform config (google-services.json / Info.plist).
GOOGLE_SERVER_CLIENT_ID=

# Gemini access is provided through the Firebase project (firebase_ai),
# so no separate Gemini API key is required at runtime.

The app loads .env on startup, so the file must exist (it can be empty).

Run code generation (freezed / json_serializable / mockito):

dart run build_runner build --delete-conflicting-outputs

Run the app:

flutter run

Running Tests

# Unit & widget tests
flutter test

# With coverage
flutter test --coverage

# Patrol integration / E2E tests (Android)
patrol test

# Patrol integration / E2E tests (iOS)
patrol test --ios

Project Structure

The codebase follows a core / feature / product layering convention.

lib/
β”œβ”€β”€ main.dart          # App bootstrap: init + global providers + runApp
β”œβ”€β”€ app/               # LokalyApp (MaterialApp) + go_router config
β”œβ”€β”€ core/              # Infrastructure: theme, init, constants (UI-agnostic)
β”‚   β”œβ”€β”€ theme/         #   AppColors, text styles, ThemeData (light/dark)
β”‚   β”œβ”€β”€ constants/     #   App constants + Turkey cities
β”‚   └── init/          #   dotenv + Firebase initialization
β”œβ”€β”€ feature/           # One folder per screen: cubit/ (state) + view/ (UI)
β”‚   β”œβ”€β”€ splash/        #   auth-state redirect
β”‚   β”œβ”€β”€ auth/          #   login + register
β”‚   β”œβ”€β”€ feed/          #   home feed
β”‚   β”œβ”€β”€ create/        #   city β†’ landmark β†’ photo β†’ generating β†’ result
β”‚   β”œβ”€β”€ comments/      #   realtime comments sheet
β”‚   β”œβ”€β”€ profile/       #   profile + edit profile
β”‚   β”œβ”€β”€ post_detail/   #   single post view
β”‚   └── settings/      #   theme + language + account
└── product/           # Cross-feature shared code
    β”œβ”€β”€ state/         #   AppState (global ChangeNotifier)
    β”œβ”€β”€ models/        #   user / post / comment models
    β”œβ”€β”€ services/      #   auth, firestore, gemini, image gen, share, etc.
    β”œβ”€β”€ widgets/       #   shared widgets (logo, post card, badges...)
    └── navigation/    #   route paths

test/                  # Unit + widget + cubit tests (flutter_test)
integration_test/      # Patrol E2E tests
screenshots/           # Images used in this README

Architecture

Two-layer state management:

  • Page state β†’ each screen owns a Cubit (flutter_bloc) under feature/<x>/cubit/. Holds screen-local concerns: form, loading, error, lists, selection.
  • Global state β†’ AppState (provider / ChangeNotifier) under product/state/. Holds app-wide concerns: theme mode, current user, locale.
View (feature/<x>/view)
        ↓  (BlocBuilder / BlocProvider)
Cubit (feature/<x>/cubit)  ←→  AppState (global, via provider)
        ↓  (constructor injection)
Services (product/services: Auth, Firestore, Gemini, Image, Share)
        ↓
Firebase  Β·  Gemini (firebase_ai)

Rule: service calls happen inside Cubits, never in the view. Cubits receive their services via constructor injection so they can be mocked in tests.


Firestore Data Model

users/{uid}                                  β†’ username, email, photoURL, bio,
                                               followersCount, followingCount, createdAt
posts/{postId}                               β†’ userId, userUsername, userPhotoURL,
                                               imageURL, city, landmark,
                                               likesCount, commentsCount, createdAt
posts/{postId}/likes/{uid}                   β†’ createdAt
posts/{postId}/comments/{commentId}          β†’ userId, userUsername, text, createdAt
following/{uid}/userFollowing/{targetUid}    β†’ createdAt
followers/{uid}/userFollowers/{targetUid}    β†’ createdAt

Likes and follows are written via Firestore transactions so the denormalized counters stay consistent.


Built with Flutter Β· Firebase Β· Gemini.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages