mirror of
https://github.com/usetrmnl/trmnl-android.git
synced 2026-04-29 13:35:26 -07:00
Merge pull request #278 from usetrmnl/metro-migration-MAIN
feat: migrate from Dagger/Anvil/KAPT to Metro DI framework
This commit is contained in:
@@ -4,7 +4,7 @@ This directory contains the development container configuration for TRMNL Androi
|
||||
|
||||
## Features
|
||||
|
||||
- **Base Image**: Java 17 (Bookworm)
|
||||
- **Base Image**: Java 21 (Bookworm)
|
||||
- **Android SDK**: Manually installed via post-create script
|
||||
- **Android Command Line Tools**: Version 11076708
|
||||
- **Platform Tools**: Latest version
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "TRMNL Android",
|
||||
"image": "mcr.microsoft.com/devcontainers/java:1-17-bookworm",
|
||||
"image": "mcr.microsoft.com/devcontainers/java:1-21-bookworm",
|
||||
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/git:1": {},
|
||||
|
||||
@@ -11,7 +11,7 @@ This document provides essential information for GitHub Copilot agents working o
|
||||
- Build System: Gradle 8.13
|
||||
- Min SDK: 28 (Android 9.0 Pie)
|
||||
- Target SDK: 36 (Android 16.0)
|
||||
- Architecture: Modern Android with Jetpack Compose, Circuit UDF, Dagger DI
|
||||
- Architecture: Modern Android with Jetpack Compose, Circuit UDF, Metro DI
|
||||
|
||||
## Critical Build & Test Commands
|
||||
|
||||
@@ -55,7 +55,7 @@ This document provides essential information for GitHub Copilot agents working o
|
||||
|
||||
## Environment Requirements
|
||||
|
||||
- **JDK Version:** 17 (OpenJDK 17 - Temurin distribution recommended)
|
||||
- **JDK Version:** 21 (OpenJDK 21 - Temurin distribution recommended)
|
||||
- **Gradle:** 8.13 (via wrapper, do NOT install manually)
|
||||
- **Android SDK:** Compile SDK 36
|
||||
- **Build Tools:** Managed by Gradle plugin (AGP 8.9.2)
|
||||
@@ -70,7 +70,7 @@ app/src/main/java/ink/trmnl/android/
|
||||
├── MainActivity.kt # App entry point (138 lines)
|
||||
├── TrmnlDisplayMirrorApp.kt # Application class (51 lines)
|
||||
├── data/ # Repositories, DataStore implementations
|
||||
├── di/ # Dagger dependency injection modules
|
||||
├── di/ # Metro dependency injection modules
|
||||
├── model/ # Data models (TrmnlDeviceConfig, etc.)
|
||||
├── network/ # Retrofit API service, response models
|
||||
├── ui/ # Jetpack Compose screens (Circuit UDF)
|
||||
@@ -89,7 +89,7 @@ app/src/main/java/ink/trmnl/android/
|
||||
|
||||
### Key Architectural Patterns
|
||||
- **UI Framework:** Jetpack Compose with Circuit (Slack's UDF architecture)
|
||||
- **DI:** Dagger with Anvil for code generation
|
||||
- **DI:** Metro (dev.zacsweers.metro) for compile-time code generation
|
||||
- **Background Work:** WorkManager (15 min minimum interval)
|
||||
- **Networking:** Retrofit + OkHttp + Moshi for JSON parsing
|
||||
- **Data Storage:** DataStore (preferences) for settings/tokens
|
||||
@@ -134,7 +134,7 @@ All workflows are in `.github/workflows/`:
|
||||
**Solution:** This is informational only. The file is optional for local dev (used for release keystores). Debug builds work without it.
|
||||
|
||||
### Issue: First Build Takes 2-3 Minutes
|
||||
**Solution:** Expected behavior. Gradle downloads dependencies and builds annotation processors (KSP, KAPT). Subsequent builds are much faster (~1 minute) due to caching.
|
||||
**Solution:** Expected behavior. Gradle downloads dependencies and runs Metro compiler plugin + KSP. Subsequent builds are much faster (~1 minute) due to caching.
|
||||
|
||||
### Issue: Test Warning "Sharing is only supported for boot loader classes"
|
||||
**Solution:** Harmless warning from Robolectric tests. Can be ignored. Tests still pass.
|
||||
@@ -199,7 +199,7 @@ See `RELEASE_CHECKLIST.md` for complete release process.
|
||||
## Trust These Instructions
|
||||
|
||||
These instructions have been validated by running all commands in a clean repository clone. If you encounter issues not documented here:
|
||||
1. First verify you're using JDK 17 and the Gradle wrapper (`./gradlew`)
|
||||
1. First verify you're using JDK 21 and the Gradle wrapper (`./gradlew`)
|
||||
2. Try `./gradlew clean` then retry the command
|
||||
3. Check if similar issues exist in closed GitHub issues
|
||||
4. Only search the codebase if these instructions prove incomplete or incorrect
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
cache: gradle
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Create test directory
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17' # Using a stable JDK version
|
||||
java-version: '21' # Using a stable JDK version
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Verify Java and Keytool Installation
|
||||
|
||||
@@ -37,3 +37,4 @@ app/release/
|
||||
*.salive
|
||||
app*.aab
|
||||
secret.properties
|
||||
metro-main*
|
||||
|
||||
@@ -11,7 +11,7 @@ TRMNL Android is a native Android app that displays TRMNL e-ink device content o
|
||||
- Build: Gradle 8.13 with AGP 8.9.2
|
||||
- Min SDK: 28 (Android 9.0 Pie), Target SDK: 36 (Android 16.0)
|
||||
- UI: Jetpack Compose with Circuit UDF architecture (Slack's unidirectional data flow)
|
||||
- DI: Dagger 2.56.2 with Anvil 0.4.1 for code generation
|
||||
- DI: Metro 0.12.1 (dev.zacsweers.metro) with MetroX Android for compile-time DI
|
||||
- Background Work: WorkManager 2.10.1 (15-minute minimum interval limitation)
|
||||
- Networking: Retrofit 2.11.0 + OkHttp 4.12.0 + Moshi 1.15.2
|
||||
- Image Loading: Coil 3.2.0 with OkHttp integration
|
||||
@@ -25,14 +25,14 @@ TRMNL Android is a native Android app that displays TRMNL e-ink device content o
|
||||
**CRITICAL: On a fresh clone, you MUST build first to generate code:**
|
||||
|
||||
```bash
|
||||
# 1. Build debug APK (generates Dagger/Circuit code via KSP/KAPT)
|
||||
# 1. Build debug APK (generates Metro/Circuit code via compiler plugin + KSP)
|
||||
./gradlew assembleDebug --parallel --daemon
|
||||
|
||||
# 2. Now you can run tests
|
||||
./gradlew testDebugUnitTest --parallel --daemon
|
||||
```
|
||||
|
||||
**Why?** Running tests before building will fail with Dagger errors about missing generated modules. The build step generates necessary code via KSP (Circuit) and KAPT (Dagger).
|
||||
**Why?** Running tests before building will fail with Metro errors about missing generated modules. The build step generates necessary code via Metro compiler plugin (DI) and KSP (Circuit).
|
||||
|
||||
### Regular Development (After Initial Build)
|
||||
|
||||
@@ -53,7 +53,7 @@ TRMNL Android is a native Android app that displays TRMNL e-ink device content o
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- JDK: Minimum JDK 17, but JDK 21+ works (backward compatible)
|
||||
- JDK: Minimum JDK 21 (required by Metro gradle plugin)
|
||||
- ALWAYS use `./gradlew` wrapper, NEVER system gradle
|
||||
- First build: ~1-2 minutes (optimized with G1GC, parallel execution, configuration cache)
|
||||
- Subsequent builds: ~2-8 seconds with Gradle cache and configuration cache
|
||||
@@ -72,8 +72,8 @@ app/src/main/java/ink/trmnl/android/
|
||||
│ ├── TrmnlDeviceConfigDataStore.kt # Device config (token, server)
|
||||
│ ├── ImageMetadataStore.kt # Image state management
|
||||
│ ├── log/ # Refresh log management
|
||||
├── di/ # Dagger modules
|
||||
│ ├── AppComponent.kt # Main app component
|
||||
├── di/ # Metro DI modules
|
||||
│ ├── AppGraph.kt # Main app dependency graph
|
||||
│ ├── NetworkModule.kt # Retrofit, OkHttp, Moshi
|
||||
│ ├── CircuitModule.kt # Circuit UI setup
|
||||
├── model/ # Data models
|
||||
@@ -98,15 +98,16 @@ app/src/main/java/ink/trmnl/android/
|
||||
### Key Architectural Patterns
|
||||
|
||||
**Circuit UDF (Unidirectional Data Flow):**
|
||||
- All screens use `@CircuitInject` annotation for DI with Anvil
|
||||
- All screens use `@CircuitInject` annotation for DI with Metro
|
||||
- Presenter pattern: State + Event → Presenter → Updated State
|
||||
- Example: `TrmnlMirrorDisplayScreen` with presenter handling events
|
||||
|
||||
**Dependency Injection:**
|
||||
- Dagger with Anvil for compile-time code generation
|
||||
- Metro for compile-time code generation via Kotlin compiler plugin (no KAPT)
|
||||
- `@ContributesTo(AppScope::class)` for module contribution
|
||||
- `@SingleIn(AppScope::class)` for app-scoped singletons
|
||||
- Circuit integration: `arg("anvil-ksp-extraContributingAnnotations", "com.slack.circuit.codegen.annotations.CircuitInject")`
|
||||
- `@DependencyGraph(AppScope::class)` on `AppGraph` as the root component
|
||||
- Circuit integration: `arg("circuit.codegen.mode", "metro")`
|
||||
|
||||
**Background Work:**
|
||||
- WorkManager with 15-minute minimum interval (Android OS limitation)
|
||||
@@ -198,13 +199,13 @@ The project uses optimized Gradle settings based on best practices from the [Now
|
||||
|
||||
## Common Issues
|
||||
|
||||
- **Tests fail on fresh checkout**: Must run `./gradlew assembleDebug` first to generate Dagger/Circuit code
|
||||
- **Tests fail on fresh checkout**: Must run `./gradlew assembleDebug` first to generate Metro/Circuit code
|
||||
- **"secret.properties not found"**: Informational only, debug builds work without it
|
||||
- **First build slow**: Expected for clean builds, ~1-2 minutes with optimized Gradle settings
|
||||
- **"Sharing is only supported for boot loader classes"**: Harmless Robolectric warning, tests still pass
|
||||
- **"INVISIBLE_REFERENCE" in NetworkingTools.kt:56**: Expected, uses internal Kotlin API (documented warning)
|
||||
- **WorkManager 15-min minimum**: Android OS limitation, not a bug
|
||||
- **Dagger KAPT errors about missing modules**: Run `assembleDebug` first to generate code
|
||||
- **Metro codegen errors about missing modules**: Run `assembleDebug` first to generate code
|
||||
|
||||
## Code Style
|
||||
|
||||
@@ -243,7 +244,7 @@ The project uses optimized Gradle settings based on best practices from the [Now
|
||||
- **Authentication**: Token-based auth required (TRMNL access token or device ID/MAC address)
|
||||
- **BYOS Support**: Supports custom server URLs for BYOS installations
|
||||
- **Screen Wake Lock**: `FLAG_KEEP_SCREEN_ON` doesn't work reliably on e-Ink tablets due to aggressive battery optimization
|
||||
- **Kotlin Version**: Capped at 2.1.10 due to Dagger 2.56.2 compatibility (see libs.versions.toml comment)
|
||||
- **Kotlin Version**: 2.3.20+ (Metro removed the Dagger/KAPT compatibility constraint)
|
||||
- **No Product Flavors**: Only debug/release build types exist
|
||||
|
||||
## Copilot Instructions Context
|
||||
@@ -253,5 +254,5 @@ From `.github/copilot-instructions.md`:
|
||||
- Use Circuit's `@CircuitInject` for UI components
|
||||
- WorkManager periodic work has 15-min minimum interval
|
||||
- Image loading handles HTTP 403 auto-refresh for expired URLs
|
||||
- Dagger KSP support is in Alpha - using KAPT for now
|
||||
- Metro uses a Kotlin compiler plugin — no KAPT, no KSP for DI itself
|
||||
- Trust the documented build commands - they're CI-validated
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ The app uses a modern Android architecture with the following components:
|
||||
- **UI**: Jetpack Compose with Circuit UDF architecture
|
||||
- **Background Processing**: WorkManager for scheduled image (re)loading
|
||||
- **Networking**: Retrofit and OkHttp for API communication
|
||||
- **DI**: Dagger with Anvil for dependency injection
|
||||
- **DI**: Metro for dependency injection
|
||||
- **Data Storage**: DataStore for preferences and token storage
|
||||
|
||||
#### Key Features/Screens
|
||||
|
||||
+11
-19
@@ -5,10 +5,9 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
alias(libs.plugins.kotlin.kapt)
|
||||
alias(libs.plugins.kotlinter)
|
||||
alias(libs.plugins.ksp)
|
||||
alias(libs.plugins.anvil)
|
||||
id("dev.zacsweers.metro")
|
||||
}
|
||||
|
||||
// Load secret.properties file for local development
|
||||
@@ -99,12 +98,8 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@@ -122,6 +117,12 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.activity.compose)
|
||||
@@ -147,13 +148,7 @@ dependencies {
|
||||
implementation(libs.core.ktx)
|
||||
ksp(libs.circuit.codegen)
|
||||
|
||||
implementation(libs.dagger)
|
||||
// Dagger KSP support is in Alpha, not available yet. Using KAPT for now.
|
||||
// https://dagger.dev/dev-guide/ksp.html
|
||||
kapt(libs.dagger.compiler)
|
||||
|
||||
implementation(libs.anvil.annotations)
|
||||
implementation(libs.anvil.annotations.optional)
|
||||
implementation(libs.metrox.android)
|
||||
|
||||
// Timber
|
||||
implementation(libs.timber)
|
||||
@@ -198,10 +193,7 @@ dependencies {
|
||||
}
|
||||
|
||||
ksp {
|
||||
// Anvil-KSP
|
||||
arg("anvil-ksp-extraContributingAnnotations", "com.slack.circuit.codegen.annotations.CircuitInject")
|
||||
// kotlin-inject-anvil (requires 0.0.3+)
|
||||
arg("kotlin-inject-anvil-contributing-annotations", "com.slack.circuit.codegen.annotations.CircuitInject")
|
||||
arg("circuit.codegen.mode", "metro")
|
||||
}
|
||||
|
||||
// Enable dynamic agent loading for tests needed by MockK
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
<application
|
||||
android:name=".TrmnlDisplayMirrorApp"
|
||||
android:appComponentFactory=".di.TrmnlAppComponentFactory"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
@@ -17,12 +16,12 @@
|
||||
android:theme="@style/Theme.App"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
tools:targetApi="36"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
tools:replace="android:appComponentFactory">
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.App">
|
||||
android:theme="@style/Theme.App"
|
||||
tools:ignore="Instantiatable">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ import com.slack.circuit.foundation.rememberCircuitNavigator
|
||||
import com.slack.circuit.overlay.ContentWithOverlays
|
||||
import com.slack.circuit.sharedelements.SharedElementTransitionLayout
|
||||
import com.slack.circuitx.gesturenavigation.GestureNavigationDecorationFactory
|
||||
import com.squareup.anvil.annotations.ContributesMultibinding
|
||||
import ink.trmnl.android.di.ActivityKey
|
||||
import dev.zacsweers.metro.ContributesIntoMap
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.binding
|
||||
import dev.zacsweers.metrox.android.ActivityKey
|
||||
import ink.trmnl.android.di.AppScope
|
||||
import ink.trmnl.android.di.ApplicationContext
|
||||
import ink.trmnl.android.ui.display.TrmnlMirrorDisplayScreen
|
||||
@@ -30,7 +32,6 @@ import ink.trmnl.android.work.TrmnlImageUpdateManager
|
||||
import ink.trmnl.android.work.TrmnlWorkScheduler.Companion.IMAGE_REFRESH_ONETIME_WORK_NAME
|
||||
import ink.trmnl.android.work.TrmnlWorkScheduler.Companion.IMAGE_REFRESH_PERIODIC_WORK_NAME
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Main activity for the TRMNL app.
|
||||
@@ -39,7 +40,7 @@ import javax.inject.Inject
|
||||
* It can function as either a mirror for existing TRMNL devices or as a
|
||||
* standalone TRMNL display connected directly to BYOS servers.
|
||||
*/
|
||||
@ContributesMultibinding(AppScope::class, boundType = Activity::class)
|
||||
@ContributesIntoMap(AppScope::class, binding = binding<Activity>())
|
||||
@ActivityKey(MainActivity::class)
|
||||
class MainActivity
|
||||
@Inject
|
||||
|
||||
@@ -3,23 +3,23 @@ package ink.trmnl.android
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.work.Configuration
|
||||
import ink.trmnl.android.di.AppComponent
|
||||
import ink.trmnl.android.work.TrmnlWorkerFactory
|
||||
import dev.zacsweers.metro.createGraphFactory
|
||||
import dev.zacsweers.metrox.android.MetroAppComponentProviders
|
||||
import dev.zacsweers.metrox.android.MetroApplication
|
||||
import ink.trmnl.android.di.AppGraph
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Application class for the app with key initializations.
|
||||
*/
|
||||
class TrmnlDisplayMirrorApp :
|
||||
Application(),
|
||||
MetroApplication,
|
||||
Configuration.Provider {
|
||||
private val appComponent: AppComponent by lazy { AppComponent.create(this) }
|
||||
private val appGraph by lazy { createGraphFactory<AppGraph.Factory>().create(this) }
|
||||
|
||||
fun appComponent(): AppComponent = appComponent
|
||||
|
||||
@Inject
|
||||
lateinit var workerFactory: TrmnlWorkerFactory
|
||||
override val appComponentProviders: MetroAppComponentProviders
|
||||
get() = appGraph
|
||||
|
||||
override val workManagerConfiguration: Configuration
|
||||
get() {
|
||||
@@ -27,14 +27,13 @@ class TrmnlDisplayMirrorApp :
|
||||
return Configuration
|
||||
.Builder()
|
||||
.setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.DEBUG else Log.WARN)
|
||||
.setWorkerFactory(workerFactory)
|
||||
.setWorkerFactory(appGraph.workerFactory)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
installLoggingTree()
|
||||
appComponent.inject(this)
|
||||
}
|
||||
|
||||
private fun installLoggingTree() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import dev.zacsweers.metro.Inject
|
||||
import ink.trmnl.android.di.ApplicationContext
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -15,7 +16,6 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import java.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
private val Context.imageDataStore: DataStore<Preferences> by preferencesDataStore(
|
||||
name = "trmnl_image_metadata",
|
||||
|
||||
@@ -8,9 +8,10 @@ import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.longPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.squareup.anvil.annotations.optional.SingleIn
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.Types
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import ink.trmnl.android.data.AppConfig.DEFAULT_REFRESH_INTERVAL_SEC
|
||||
import ink.trmnl.android.data.AppConfig.TRMNL_API_SERVER_BASE_URL
|
||||
import ink.trmnl.android.di.AppScope
|
||||
@@ -24,7 +25,6 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* DataStore for managing TRMNL device configuration.
|
||||
@@ -377,7 +377,7 @@ class TrmnlDeviceConfigDataStore
|
||||
*/
|
||||
suspend fun saveAccessToken(token: String) {
|
||||
context.deviceConfigStore.edit { preferences ->
|
||||
preferences[ACCESS_TOKEN_KEY] = token
|
||||
preferences[ACCESS_TOKEN_KEY] = token.trim()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ package ink.trmnl.android.data
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.exceptionOrNull
|
||||
import com.squareup.anvil.annotations.optional.SingleIn
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import ink.trmnl.android.di.AppScope
|
||||
import ink.trmnl.android.model.SupportedDeviceModel
|
||||
import ink.trmnl.android.model.TrmnlDeviceConfig
|
||||
@@ -20,7 +21,6 @@ import ink.trmnl.android.util.AndroidDeviceInfoProvider
|
||||
import ink.trmnl.android.util.HTTP_500
|
||||
import ink.trmnl.android.util.isHttpOk
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Repository class responsible for fetching and mapping display data.
|
||||
|
||||
@@ -2,7 +2,8 @@ package ink.trmnl.android.data
|
||||
|
||||
import com.slack.eithernet.ApiResult
|
||||
import com.slack.eithernet.exceptionOrNull
|
||||
import com.squareup.anvil.annotations.optional.SingleIn
|
||||
import dev.zacsweers.metro.Inject
|
||||
import dev.zacsweers.metro.SingleIn
|
||||
import ink.trmnl.android.di.AppScope
|
||||
import ink.trmnl.android.model.TrmnlDeviceConfig
|
||||
import ink.trmnl.android.network.TrmnlUserApiService
|
||||
@@ -11,7 +12,6 @@ import ink.trmnl.android.network.model.TrmnlUser
|
||||
import ink.trmnl.android.network.util.constructApiUrl
|
||||
import ink.trmnl.android.util.AndroidDeviceInfoProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Repository class for user-level TRMNL API operations.
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.FileProvider
|
||||
import com.squareup.moshi.Moshi
|
||||
import dev.zacsweers.metro.Inject
|
||||
import ink.trmnl.android.di.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -13,7 +14,6 @@ import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.Instant
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Handles exporting refresh logs to a JSON file and sharing it via Android's share intent.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user