Serein
Rust로 만든 가볍고 성능 좋은 Discord 전용 네이티브 클라이언트
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
A modern, privacy-respecting Mastodon client for Android, built with Jetpack Compose
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Tootsie is a modern, high-performance, and privacy-respecting Mastodon client for Android. Built from the ground up with Jetpack Compose and Kotlin, it follows Clean Architecture principles to provide a smooth experience for the Fediverse.
Google requires a closed test with at least 12 testers for 14 days before Tootsie can be published on Google Play. You can help:
Bugs and ideas are welcome as issues. Without the Play Store, install the APK from the latest release.
RemoteMediator) and stay fully scrollable without a network connection.Some features depend on the server version: quote posts and fetching remote replies need Mastodon 4.5 or newer, decrypting push notifications needs Mastodon 4.4 or newer. On older servers Tootsie falls back to the previous behaviour (e.g. the boost button boosts directly).
gradle/libs.versions.toml)MigrationTestHelperClone the repository:
git clone https://github.com/pfitzer/tootsie.git
cd tootsie
Open in Android Studio: Import the project and let Gradle sync.
Build & Run:
Select the app configuration and run it on your device or emulator.
./gradlew assembleDebug./gradlew assembleRelease./gradlew testDebugUnitTest./gradlew connectedDebugAndroidTest./gradlew :app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.pfitzer.tootsie.data.local.TootsieDatabaseMigrationTest
Instrumented test runs uninstall the app afterwards, which deletes its data (including logins). Add -Pandroid.injected.androidTest.leaveApksInstalledAfterRun=true to keep it installed.
CI (GitHub Actions) runs the unit tests and builds debug and release APKs; instrumented tests are not part of CI.
app/
├── schemas/ # Exported Room schemas (one JSON per database version)
└── src/main/java/com/pfitzer/tootsie/
├── TootsieApplication.kt # Hilt application, UnifiedPush callbacks
├── MainActivity.kt # Single activity hosting Compose
├── di/ # Dependency injection modules
├── data/ # Data layer
│ ├── local/ # Room (DAOs, entities, database), DataStore, credential encryption
│ ├── remote/ # Retrofit API, DTOs, interceptors, account-scoped credentials
│ ├── repository/ # Repository implementations
│ ├── mapper/ # DTO / entity ↔ domain mappers
│ └── paging/ # Paging sources, keyword filter matching
├── domain/ # Domain layer (pure Kotlin)
│ ├── model/ # Domain models
│ ├── repository/ # Repository interfaces
│ └── usecase/ # Use cases
├── presentation/ # Presentation layer
│ ├── screens/ # Screen composables & ViewModels
│ ├── components/ # Reusable UI components
│ ├── navigation/ # Navigation graph and destinations
│ ├── theme/ # Material 3 theme
│ └── util/ # UI helpers (HTML rendering, UiText, …)
├── push/ # UnifiedPush service, Web Push decryption, notifications
├── worker/ # WorkManager workers (notification polling)
└── util/ # Cross-cutting utilities
Contributions are welcome, see CONTRIBUTING.md and the Code of Conduct.
When contributing to Tootsie, please adhere to these architectural guardrails (details in CLAUDE.md):
.collect {} on DataStore.data for one-time reads as it is a hot flow and will block infinitely. Always use .first().runBlocking or suspend functions inside interceptors. Use the Provider Pattern with AtomicReference for thread-safe, synchronous access to tokens and the instance URL.init blocks or during Hilt construction. Every entry point that calls the API (splash screen, workers, push callbacks) must call AuthRepositoryImpl.ensureInitialized() first.Dispatchers.IO.strings.xml (English and German). ViewModels expose messages as UiText, never as hardcoded strings.app/schemas/ and a migration test.CredentialCipher). Requests on behalf of a specific account (push, polling) pass that account's credentials explicitly instead of using the active account.Planned features and known issues are tracked in GitHub Issues, for example:
Please report vulnerabilities privately, see SECURITY.md.
This project is licensed under the MIT License - see the LICENSE file for details.