QuoteVault is a modern Android application for discovering, saving, and sharing quotes, built with Jetpack Compose and Supabase.
- Authentication: Email/password sign up, login, logout, password reset
- Quote Browsing: Infinite scroll feed, category filtering (Motivation, Love, Success, Wisdom, Humor, Life)
- Search: Full-text search by quote content or author
- Favorites: Save quotes with cloud sync across devices
- Collections: Create custom collections to organize quotes
- Daily Quote Widget: Home screen widget with daily inspiration
- Push Notifications: Configurable daily quote notifications
- Share quotes as text via system share sheet
- Generate beautiful quote cards with 3 template styles (Minimal, Bold, Artistic)
- Save quote cards as images to device
- Dark/Light mode with system default option
- Multiple accent color themes
- Adjustable quote text size
- All settings sync to user profile
Dark Theme Light Theme
Black Theme Light Theme
Black Theme Light Theme
Black Theme Light Theme
Black Theme Light Theme
- Android Studio: Koala (2024.1.1) or newer
- JDK: 17 or higher
- Minimum SDK: Android 10 (API 29)
- Supabase Account: Free tier works
git clone https://github.com/gawwr4v/QuoteVault.git
cd QuoteVault
# Open in Android StudioThis project uses BuildConfig to secure sensitive API keys. Do not commit your real keys to version control.
- Open
local.propertiesin the project root (git-ignored by default) - Add your Supabase credentials:
SUPABASE_URL="https://<YOUR_PROJECT_ID>.supabase.co" SUPABASE_KEY="<YOUR_ANON_KEY>"
- Click "Sync Project with Gradle Files" in Android Studio
# Build debug APK
./gradlew assembleDebug
# Install on connected device
./gradlew installDebug
# Run all tests
./gradlew testOr simply press
Run this SQL script in the Supabase SQL Editor to set up your database:
-- 1. Enable UUID Extension
create extension if not exists "uuid-ossp";
-- 2. Categories Table
create table public.categories (
id uuid primary key default uuid_generate_v4(),
name text not null unique
);
-- 3. Quotes Table
create table public.quotes (
id uuid primary key default uuid_generate_v4(),
text text not null,
author text not null,
category_id uuid references public.categories(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 4. Lists Table (User Collections)
create table public.lists (
id uuid primary key default uuid_generate_v4(),
name text not null,
user_id uuid not null references auth.users(id) on delete cascade
);
-- 5. Favorites Table
create table public.favorites (
id uuid primary key default uuid_generate_v4(),
quote_id uuid not null references public.quotes(id) on delete cascade,
user_id uuid not null references auth.users(id) on delete cascade,
unique (quote_id, user_id)
);
-- 6. List Quotes Junction Table (Many-to-Many)
create table public.list_quotes (
id uuid primary key default uuid_generate_v4(),
list_id uuid not null references public.lists(id) on delete cascade,
quote_id uuid not null references public.quotes(id) on delete cascade,
unique (list_id, quote_id)
);
-- === Row Level Security (RLS) Policies ===
alter table favorites enable row level security;
alter table lists enable row level security;
alter table list_quotes enable row level security;
create policy "favorites_select" on favorites for select using (auth.uid() = user_id);
create policy "favorites_insert" on favorites for insert with check (auth.uid() = user_id);
create policy "favorites_delete" on favorites for delete using (auth.uid() = user_id);
create policy "lists_all" on lists for all
using (auth.uid() = user_id)
with check (auth.uid() = user_id);
create policy "list_quotes_all" on list_quotes for all
using (
exists (
select 1 from lists
where lists.id = list_quotes.list_id
and lists.user_id = auth.uid()
)
);
-- === Initial Data ===
insert into categories (name) values
('Motivation'), ('Love'), ('Success'), ('Wisdom'), ('Humor'), ('Life');Seed your database with 100+ quotes across categories. You can use any public quote API or dataset.
- MVVM: Clear separation between UI and business logic
- Clean Architecture: Three distinct layers:
- Data Layer: Repositories, Supabase Data Source, DataStore
- Domain Layer: Use cases and data models
- UI Layer: Jetpack Compose screens and ViewModels
- Dependency Injection: Hilt (Dagger)
app/src/main/java/com/quotevault/
├── data/ # Repositories, data sources
├── di/ # Hilt modules
├── domain/ # Models, repository interfaces
├── ui/
│ ├── components/ # Reusable Compose components
│ ├── navigation/ # NavGraph, Screen routes
│ ├── screens/ # Feature screens (auth, home, search, etc.)
│ └── theme/ # Colors, Typography, Theme
├── widget/ # Home screen Glance widget
├── worker/ # WorkManager for notifications
└── MainActivity.kt
- Language: Kotlin 100%
- UI Framework: Jetpack Compose (Material 3)
- Dependency Injection: Hilt
- Backend & Auth: Supabase (GoTrue, Postgrest)
- Network: Ktor Client
- Image Loading: Coil
- Local Storage: DataStore Preferences
- Background Tasks: WorkManager
- Widgets: Jetpack Glance
- Architecture: Clean Architecture + MVVM
INTERNET- API calls to SupabasePOST_NOTIFICATIONS- Daily quote notifications (Android 13+)VIBRATE- Haptic feedback for radial menuSCHEDULE_EXACT_ALARM- Precise notification scheduling
- Offline Mode: App requires internet for initial data load
- Widget Sync: Updates via WorkManager or immediately on app launch
- Auth Rate Limits (Development): On Supabase's free tier, email delivery (signups/password resets) is strictly rate-limited to 2 emails per hour to prevent spam.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
See the LICENSE file for details.
Network Use Clause:
If you run a modified version of this software as a network service, you must make the complete source code available to users, as required by the AGPL-3.0.









