feat(di): Hilt modules for the database, repositories and clocks
The database and its DAOs, the four repository bindings, and the Android implementations of the two clocks — so nothing constructs a Room database or reads a system clock by hand. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,8 +21,8 @@ import java.io.File
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Clockula's storage bindings. M1 wires the preference half only; the Room
|
||||
* database and its DAOs join this module in M2.
|
||||
* The DataStore half of Clockula's storage. The Room database and its DAOs live
|
||||
* next door in `DatabaseModule`.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package de.jeanlucmakiola.clockula.data.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import de.jeanlucmakiola.clockula.data.alarms.AlarmDao
|
||||
import de.jeanlucmakiola.clockula.data.db.ClockulaDatabase
|
||||
import de.jeanlucmakiola.clockula.data.stopwatch.LapDao
|
||||
import de.jeanlucmakiola.clockula.data.timers.TimerDao
|
||||
import de.jeanlucmakiola.clockula.data.worldclocks.WorldClockDao
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* The database and its four DAOs. No destructive-migration fallback: docs/PLAN.md
|
||||
* §12 wants every schema change to arrive with a tested migration, and a fallback
|
||||
* would quietly drop a user's alarms instead of failing loudly in review.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DatabaseModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDatabase(@ApplicationContext context: Context): ClockulaDatabase =
|
||||
Room.databaseBuilder(context, ClockulaDatabase::class.java, ClockulaDatabase.NAME).build()
|
||||
|
||||
@Provides
|
||||
fun provideAlarmDao(database: ClockulaDatabase): AlarmDao = database.alarmDao()
|
||||
|
||||
@Provides
|
||||
fun provideTimerDao(database: ClockulaDatabase): TimerDao = database.timerDao()
|
||||
|
||||
@Provides
|
||||
fun provideWorldClockDao(database: ClockulaDatabase): WorldClockDao = database.worldClockDao()
|
||||
|
||||
@Provides
|
||||
fun provideLapDao(database: ClockulaDatabase): LapDao = database.lapDao()
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package de.jeanlucmakiola.clockula.data.di
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import de.jeanlucmakiola.clockula.data.alarms.AlarmRepository
|
||||
import de.jeanlucmakiola.clockula.data.alarms.AlarmRepositoryImpl
|
||||
import de.jeanlucmakiola.clockula.data.stopwatch.StopwatchRepository
|
||||
import de.jeanlucmakiola.clockula.data.stopwatch.StopwatchRepositoryImpl
|
||||
import de.jeanlucmakiola.clockula.data.timers.TimerRepository
|
||||
import de.jeanlucmakiola.clockula.data.timers.TimerRepositoryImpl
|
||||
import de.jeanlucmakiola.clockula.data.worldclocks.WorldClockRepository
|
||||
import de.jeanlucmakiola.clockula.data.worldclocks.WorldClockRepositoryImpl
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** The four interfaces the rest of the app sees — and the only ones it may see. */
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class RepositoryModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindAlarmRepository(impl: AlarmRepositoryImpl): AlarmRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindTimerRepository(impl: TimerRepositoryImpl): TimerRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindWorldClockRepository(impl: WorldClockRepositoryImpl): WorldClockRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun bindStopwatchRepository(impl: StopwatchRepositoryImpl): StopwatchRepository
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package de.jeanlucmakiola.clockula.data.di
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import de.jeanlucmakiola.clockula.data.time.SystemElapsedRealtimeClock
|
||||
import de.jeanlucmakiola.clockula.data.time.SystemWallClock
|
||||
import de.jeanlucmakiola.clockula.domain.time.ElapsedRealtimeClock
|
||||
import de.jeanlucmakiola.clockula.domain.time.WallClock
|
||||
|
||||
/**
|
||||
* Both clocks are injected, never called statically, so the wall-clock /
|
||||
* elapsed-realtime distinction can be tested from both sides.
|
||||
*/
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
abstract class TimeModule {
|
||||
|
||||
@Binds
|
||||
abstract fun bindWallClock(impl: SystemWallClock): WallClock
|
||||
|
||||
@Binds
|
||||
abstract fun bindElapsedRealtimeClock(impl: SystemElapsedRealtimeClock): ElapsedRealtimeClock
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package de.jeanlucmakiola.clockula.data.time
|
||||
|
||||
import android.os.SystemClock
|
||||
import de.jeanlucmakiola.clockula.domain.time.ElapsedRealtimeClock
|
||||
import de.jeanlucmakiola.clockula.domain.time.WallClock
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Instant
|
||||
import javax.inject.Inject
|
||||
|
||||
/** The device's calendar time. Moves with the user, the network and DST. */
|
||||
class SystemWallClock @Inject constructor() : WallClock {
|
||||
override fun now(): Instant = Instant.fromEpochMilliseconds(System.currentTimeMillis())
|
||||
}
|
||||
|
||||
/**
|
||||
* Milliseconds since boot, including deep sleep. Never decreases within a boot
|
||||
* and no setting can move it — which is exactly why a running timer and the
|
||||
* stopwatch anchor on it.
|
||||
*/
|
||||
class SystemElapsedRealtimeClock @Inject constructor() : ElapsedRealtimeClock {
|
||||
override fun elapsedRealtime(): Duration = SystemClock.elapsedRealtime().milliseconds
|
||||
}
|
||||
Reference in New Issue
Block a user