A Flutter application for the PLC community.
- Flutter SDK 3.35.5 or higher
- Dart SDK 3.6.2 or higher
- Android Studio / Xcode (for mobile development)
- Google Sheets API service account credentials
git clone <repository-url>
cd plcflutter pub getThe app uses envied for secure, obfuscated environment variables. You have several options to set this up:
Run the interactive setup script:
./setup_credentials.shThe script will guide you through:
- Importing from an existing
service_account.jsonfile - Pasting the JSON content directly
- Creating from template for manual editing
-
Copy the template file:
cp .env.template .env
-
Edit
.envand replace the placeholder JSON with your actual Google service account credentials -
Save the file
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google Sheets API
- Go to "IAM & Admin" > "Service Accounts"
- Create a new service account
- Generate and download the JSON key
- Share your Google Sheets with the service account email address
After creating your .env file, generate the obfuscated environment code:
dart run build_runner build --delete-conflicting-outputsThis creates lib/core/config/env.g.dart with your encrypted credentials.
flutter runDebug Build:
flutter build apk --debugRelease Build:
flutter build apk --releaseAndroid App Bundle (for Play Store):
flutter build appbundle --releaseflutter testNada é publicado automaticamente. O bump de versão roda na sua máquina e o
build é disparado à mão: o workflow Release é workflow_dispatch puro, sem
gatilho por push ou por tag.
-
Deixe a
mainatualizada, com tudo mergeado e o working tree limpo. O lane aborta emensure_git_status_cleanse houver qualquer alteração pendente. -
Rode o bump informando o nome da nova versão. O build number é incrementado sozinho (
1.3.0+12→1.4.0+13):cd fastlane && bundle exec fastlane bump_version version:1.4.0
O lane escreve a versão em
pubspec.yaml, gerafastlane/metadata/android/pt-BR/changelogs/<build number>.txtcom os commits desde a última tag, commitaBump version to 1.4.0+13e cria a tag1.4.0+13. Ele não faz push. -
Revise o changelog gerado. Esse arquivo é o texto que aparece na Play Store.
-
Publique o commit e a tag:
git push --follow-tags
-
Dispare o build:
gh workflow run release.yaml
Ou em Actions > Release > Run workflow.
O workflow compila o appbundle, publica na track beta e, depois que o
environment android-production for aprovado, promove para produção.
generate_changelog (em fastlane/actions/) pega os commits entre a última
tag e o HEAD e mantém só os tipos feat:, fix:, perf: e security:,
agrupados sob "Funcionalidades", "Correções de problemas", "Melhorias de
Performance" e "Correções de Segurança".
O título do commit vira o item da lista. Quando o commit tem corpo, o corpo é
publicado logo abaixo do título. Escreva esses commits para quem usa o app:
nada de nome de arquivo, de função ou de decisão de implementação. O que for
técnico vai em chore:, refactor:, test: ou docs:, que o gerador ignora.
- Flutter: o CI usa
flutter-version-file: pubspec.yaml, ou seja, o valor deenvironment.flutter. Rodarflutter pub getcom outra versão reescreve opubspec.locke gera diff desnecessário. - Ruby: o CI usa 3.1 (
release.yaml), enquantofastlane/mise.tomlusa olatestda máquina. OGemfile.lockversionado precisa continuar instalável nas duas versões.
- Daily Reading (Liturgia Diária): View today's liturgical readings with liturgical color indicator
- Preachers: Browse community preachers and their information
- Secretary Documents: Access official documents and materials
- Parishes: Discover parishes with PLC presence
- About PLC: Learn about the Peregrinação de Leigos Cristãos movement
lib/
├── core/
│ ├── features/ # Generic features library
│ │ ├── data/
│ │ │ ├── datasources/ # Generic data source implementations
│ │ │ ├── models/ # Base model interfaces
│ │ │ └── repositories/ # Generic repository implementations
│ │ ├── domain/
│ │ │ ├── repositories/ # Repository interfaces
│ │ │ └── usecases/ # Generic use cases
│ │ ├── presentation/
│ │ │ └── bloc/ # Generic BLoC components
│ │ ├── core_features.dart # Library exports
│ │ └── USAGE_EXAMPLE.md # Detailed usage guide
│ └── storage/
│ ├── gsheets_storage_service.dart # Google Sheets integration
│ └── local_storage_service.dart # Local caching
├── features/ # Feature modules
│ ├── preachers/ # Preachers feature (old pattern)
│ └── secretary/ # Secretary feature (new pattern)
└── main.dart # App entry point
This project includes a powerful Generic Features Library (lib/core/features/) that drastically reduces boilerplate when creating new read-only features.
- ~70% less code per feature
- Automatic caching with 1-day sync by default
- Built-in search and filter support
- Type-safe generic implementations
- Google Sheets integration out of the box
Creating a new feature only requires:
- Define Entity (domain/entities/your_entity.dart)
- Define Model that extends
EntityModel(data/models/your_model.dart) - Configure DI in
injection_container.dart - Create UI using
GenericListBloc
See lib/core/features/USAGE_EXAMPLE.md for detailed examples.
The Secretary feature demonstrates the generic library usage. It was created with only:
- 3 files: Entity, Model, and UI page (~200 lines total)
- DI configuration: ~40 lines in injection_container.dart
- Full functionality: Caching, error handling, empty states, document opening
Compare this to the older Preachers feature which required ~15 files and ~800 lines of code!
The project uses GitHub Actions for continuous deployment:
- Builds are automatically created on workflow dispatch
- Deployment to Google Play Console (alpha, beta, production tracks)
- Credentials are injected securely via GitHub Secrets
GOOGLE_SERVICE_ACCOUNT: Google service account JSON (as a JSON string)ANDROID_KEYSTORE_BASE64: Base64-encoded Android keystoreANDROID_KEYSTORE_PASSWORD: Android keystore passwordGOOGLE_SERVICE_ACCOUNT_KEY: Google Play Console service account key
- Never commit
.env- it's already in.gitignore - Never commit
service_account.json- keep credentials secure - The app uses
enviedto obfuscate credentials at compile time - Credentials are encrypted in the compiled binary (much more secure than
--dart-define) - The hardcoded credentials have been removed from the source code
envied provides compile-time obfuscation and encryption of environment variables:
- Compile-time encryption: When you run
build_runner, envied encrypts your credentials - Obfuscated output: The generated
env.g.dartcontains encrypted values - Runtime decryption: The app decrypts values at runtime (very fast)
- Binary protection: Much harder to extract credentials from the compiled app compared to
--dart-define
This means the app couldn't find the credentials. Make sure:
- You've created the
.envfile - You've run
dart run build_runner build --delete-conflicting-outputs - The
env.g.dartfile was generated successfully
This means you need to run build_runner:
dart run build_runner build --delete-conflicting-outputsEnsure your .env follows this structure:
GOOGLE_SERVICE_ACCOUNT={"type":"service_account","project_id":"..."}
Note: The service account JSON should be on a single line without quotes around it.