Denwee: Daily Trivia
Discover short, easy-to-understand, memorable facts every day!
> Denwee is an open-source mobile application built with Flutter. It delivers personalized daily facts based on user-selected interests and supports push notifications, localization, and a modular, scalable architecture inspired by SOLID principles.
## π₯ Onboarding
Click to watch full app onboarding (30s):
[](https://www.denwee.com/media/onboarding.mp4)
## π¨ Features
- Daily facts delivery with [Supabase](https://supabase.com) and [ChatGPT Batch API](https://platform.openai.com/docs/guides/batch)
- Push notifications using [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging)
- Synced user accounts via [Supabase Auth](https://supabase.com/docs/guides/auth)
- Analytics and crash reporting with [Firebase Analytics](https://firebase.google.com/products/analytics) and [Crashlytics](https://firebase.google.com/products/crashlytics)
- Multi-language support with [Easy Localization](https://pub.dev/packages/easy_localization)
## π Tech Stack
| Layer | Technologies | Description |
|----------- |--------------|-------------|
| **Frontend (Open Source)** | Flutter, Dart, Firebase Cloud Messaging, Localizations | Client app, responsible for UI, notifications, localization, and user interactions |
| **Backend (Closed Source)** | Supabase, PostgreSQL, Supabase Edge Functions, ChatGPT API (Batch), Cron/Scheduled Jobs | Handles authentication, facts generation, data storage, multi-device token management, and notification scheduling |
| **Infrastructure** | Supabase (Database, Auth, API)
Firebase (Push Notifications, Analytics, Crashlytics) | Manages user accounts, data, push notifications, analytics, and crash reporting |
## π¦ Primary Packages
| Package | Purpose |
|---------|---------|
| [flutter_bloc](https://pub.dev/packages/flutter_bloc) | State management |
| [get_it](https://pub.dev/packages/get_it) | Dependency injection |
| [app_links](https://pub.dev/packages/app_links) | Deep links |
| [drift](https://pub.dev/packages/drift) | Local database |
| [dio](https://pub.dev/packages/dio) | Network requests |
| [easy_localization](https://pub.dev/packages/easy_localization) | Multi-language support |
| [animate_do](https://pub.dev/packages/animate_do) | Animations |
## π§© Architecture
> This section describes the architectural structure of the application and its internal dependency model.
> The design follows principles inspired by Clean Architecture, with emphasis on separation of concerns, modularity, and long-term maintainability.
### Folder Structure
The project is organized using a feature-based structure with explicit separation between domain, data, and presentation layers.
The following diagram illustrates the base structure of the project:
```mermaid
flowchart TB
subgraph Presentation[" "]
direction TB
page
bloc
widget
shared
end
subgraph Feature[" "]
direction TB
data --> model_m[model]
data --> repo_m[repo]
data --> source_m[source]
domain --> entity_d[entity]
domain --> repo_d[repo]
domain --> source_d[source]
domain --> use_case_d[use_case]
end
lib --> core
core --> feature
feature --> Feature
lib --> presentation
presentation --> Presentation
```
> The `presentation/` folder is kept outside of the `core/` directory to enforce strict separation between application logic and UI components.
> Below is what each layer is responsible for using the **Profile** feature as an example for typical files β¬οΈ
### Domain Layer
| Folder | Responsibility | Typical Files |
|-------------|----------------|---------------|
| `entity/` | Business models | `profile.dart`
`profile_failure.dart` |
| `use_case/` | Business operations | `get_profile_use_case.dart` |
| `repo/` | Repository contracts | `profile_repo.dart` |
| `source/` | Data source contracts | `profile_local_source.dart`
`profile_remote_source.dart` |
> The domain layer contains pure business logic and application rules for implementing feature behavior in the application.
> It defines core use cases and entities and remains independent of external frameworks and data sources.
### Data Layer
| Folder | Responsibility | Typical Files |
|------------|----------------|---------------|
| `model/` | Data transfer objects (DTOs) | `profile_dto.dart`
`profile_response_dto.dart` |
| `repo/` | Repository implementations | `profile_repo_impl.dart` |
| `source/` | Local / Remote data source implementations | `profile_local_source_impl.dart`
`profile_remote_source_impl.dart` |
> The data layer is used for retrieving, storing, and transforming external data for application features.
> It implements domain contracts and performs DTO-to-entity mapping.
### Presentation Layer
- `pages/` contains all application screens
- `bloc/` contains Cubits and Blocs for state management
- `widget/` contains reusable UI components
- `shared/` contains routing, theming, constants, utilities, etc...
> The presentation layer is separated from core feature modules as a deliberate design choice.
> This structure reflects a personal preference for improved screen discoverability and centralized UI infrastructure.
### Dependency Injection
The application uses annotation-based dependency injection with `injectable` and `get_it` to connect layers and enable controlled execution flows.
Dependencies are registered automatically through code generation.
Example objects injection:
``` dart
@LazySingleton()
class ProfileCubit extends Cubit {
final GetProfileUseCase _getProfileUseCase;
ProfileCubit(this._getProfileUseCase) : super(ProfileState.initial());
}
@LazySingleton()
class GetProfileUseCase {
final ProfileRepo _profileRepo;
const GetProfileUseCase(this._profileRepo);
}
```
Example resolution hierarchy:
```text
ProfilePage
β ProfileCubit
β GetProfileUseCase
β ProfileRepository
β ProfileRemoteSource / ProfileLocalSource
β API
```
## ποΈ Assets
- **Static icons** from [Iconsax](https://iconsax.io)
- **Animated emojis** from [Noto Animated Emojis](https://googlefonts.github.io/noto-emoji-animation/) β licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode)
- **Fonts:** [Quicksand](https://fonts.google.com/specimen/Quicksand) (Primary), [Manrope](https://fonts.google.com/specimen/Manrope) (Secondary)
## π How To Run
To run this application, you'll need [Flutter](https://flutter.dev) of version `3.35.5` or higher:
```bash
# Get all packages
flutter pub get
# Generate localization files
flutter pub run easy_localization:generate -S "assets/translations" -O "lib/presentation/shared/localization"
# Generate localization keys
flutter pub run easy_localization:generate -S "assets/translations" -O "lib/presentation/shared/localization" -o "locale_keys.g.dart" -f keys
# Build runner
dart run build_runner build --delete-conflicting-outputs
# Run dev environment
flutter run --flavor dev -t lib/main_dev.dart
# Run prod environment
flutter run --flavor prod -t lib/main_prod.dart
```
## π€ How To Contribute
Denwee projects are crafted by a solo enthusiastic developer across Mobile, Web, and Backend technologies. Your contributions, no matter how big or small, are always welcome! Hereβs how you can help:
* **Open PR's** β fix bugs, add features, or improve existing code.
* **Submit Issues** β report bugs, request features, or suggest improvements.
## π You May Also Like
Explore the **Denwee App landing page**, built with Flutter Web. This simple landing page is also open-source π₯ [Check it out](https://github.com/denweeLabs/factlyapp-landing)
## π Credits
Some design elements and animations were inspired by [Reflectly App](https://reflectlyapp.com), adapted and implemented originally for Denwee. Definitely check out their awesome product!
## β€οΈ Support
If this project helped you, a quick review on the App Store or Google Play would really mean a lot!
For any questions or support, please reach out to support@denwee.com π«Ά
## π License
[](https://opensource.org/licenses/MIT)