Migrate from Dagger to kotlin-inject

This commit is contained in:
Alinson S. Xavier 2026-04-05 14:54:04 -05:00
parent 0544166124
commit 110f594d09
72 changed files with 434 additions and 584 deletions

View File

@ -6,13 +6,12 @@ appintro = "6.3.1"
commonsCodec = "1.16.0"
commonsIo = "1.3.2"
commonsLang3 = "3.14.0"
dagger = "2.55"
kotlin-inject = "0.9.0"
desugar = "2.1.4"
dexmaker = "2.28.3"
espresso = "3.6.1"
guava = "33.2.1-android"
hamcrest = "2.2"
jsr250 = "1.0"
jsr305 = "3.0.2"
junit = "1.2.1"
junitJupiter = "5.10.1"
@ -41,15 +40,14 @@ appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "a
commons-codec = { module = "commons-codec:commons-codec", version.ref = "commonsCodec" }
commons-io = { module = "org.apache.commons:commons-io", version.ref = "commonsIo" }
commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang3" }
dagger = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" }
dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" }
kotlin-inject-runtime = { group = "me.tatarka.inject", name = "kotlin-inject-runtime", version.ref = "kotlin-inject" }
kotlin-inject-compiler = { group = "me.tatarka.inject", name = "kotlin-inject-compiler-ksp", version.ref = "kotlin-inject" }
desugar_jdk_libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugar" }
dexmaker-mockito = { group = "com.linkedin.dexmaker", name = "dexmaker-mockito", version.ref = "dexmaker" }
espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
jsr250-api = { group = "javax.annotation", name = "jsr250-api", version.ref = "jsr250" }
jsr305 = { group = "com.google.code.findbugs", name = "jsr305", version.ref = "jsr305" }
junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" }
junit-junit = { module = "junit:junit", version.ref = "junitVersion" }
@ -79,7 +77,7 @@ documentfile = { group = "androidx.documentfile", name = "documentfile", version
[bundles]
androidTest = [
"annotation",
"dagger",
"kotlin-inject-runtime",
"dexmaker-mockito",
"espresso-contrib",
"espresso-core",
@ -91,7 +89,7 @@ androidTest = [
"uiautomator"
]
test = [
"dagger",
"kotlin-inject-runtime",
"junit-junit",
"mockito-kotlin",
]

View File

@ -89,11 +89,10 @@ android {
}
dependencies {
compileOnly(libs.jsr250.api)
coreLibraryDesugaring(libs.desugar.jdk.libs)
implementation(libs.appIntro)
implementation(libs.jsr305)
implementation(libs.dagger)
implementation(libs.kotlin.inject.runtime)
implementation(libs.guava)
implementation(libs.ktor.client.android)
implementation(libs.ktor.client.core)
@ -110,7 +109,7 @@ dependencies {
implementation(libs.opencsv)
implementation(libs.konfetti.xml)
implementation(project(":uhabits-core"))
ksp(libs.dagger.compiler)
ksp(libs.kotlin.inject.compiler)
androidTestImplementation(libs.bundles.androidTest)
testImplementation(libs.bundles.test)

View File

@ -37,9 +37,7 @@ import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.inject.ActivityContextModule
import org.isoron.uhabits.inject.AppContextModule
import org.isoron.uhabits.inject.HabitsModule
import org.isoron.uhabits.inject.create
import org.isoron.uhabits.utils.DatabaseUtils.getDatabaseFile
import org.isoron.uhabits.utils.InterfaceUtils.setFixedResolution
import org.isoron.uhabits.utils.StyledResources.Companion.setFixedTheme
@ -81,11 +79,10 @@ abstract class BaseAndroidTest : TestCase() {
latch = CountDownLatch(1)
val context = targetContext.applicationContext
val dbFile = getDatabaseFile(context)
appComponent = DaggerHabitsApplicationTestComponent
.builder()
.appContextModule(AppContextModule(context))
.habitsModule(HabitsModule(dbFile))
.build()
appComponent = HabitsApplicationTestComponent::class.create(
appContext = context,
dbFile = dbFile
)
HabitsApplication.component = appComponent
prefs = appComponent.preferences
habitList = appComponent.habitList
@ -96,11 +93,10 @@ abstract class BaseAndroidTest : TestCase() {
fixtures = HabitFixtures(modelFactory, habitList)
fixtures.purgeHabits(appComponent.habitList)
fixtures.createEmptyHabit()
component = DaggerHabitsActivityTestComponent
.builder()
.activityContextModule(ActivityContextModule(targetContext))
.habitsApplicationComponent(appComponent)
.build()
component = HabitsActivityTestComponent::class.create(
parent = appComponent,
activityContext = targetContext
)
}
protected fun assertWidgetProviderIsInstalled(componentClass: Class<out BaseWidgetProvider?>?) {

View File

@ -19,38 +19,60 @@
package org.isoron.uhabits
import dagger.Component
import dagger.Module
import dagger.Provides
import android.content.Context
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.isoron.uhabits.activities.HabitsDirFinder
import org.isoron.uhabits.activities.habits.list.ListHabitsModule
import org.isoron.uhabits.activities.habits.list.ListHabitsScreen
import org.isoron.uhabits.activities.habits.list.views.CheckmarkButtonViewFactory
import org.isoron.uhabits.activities.habits.list.views.CheckmarkPanelViewFactory
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
import org.isoron.uhabits.activities.habits.list.views.HabitCardViewFactory
import org.isoron.uhabits.activities.habits.list.views.NumberButtonViewFactory
import org.isoron.uhabits.activities.habits.list.views.NumberPanelViewFactory
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.inject.ActivityContextModule
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsMenuBehavior
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBehavior
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
import org.isoron.uhabits.inject.HabitModule
import org.isoron.uhabits.inject.HabitsActivityModule
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.mockito.kotlin.mock
@Module
class TestModule {
@Provides
fun listHabitsBehavior(): ListHabitsBehavior = mock()
}
@ActivityScope
@Component(
modules = [ActivityContextModule::class, HabitsActivityModule::class, ListHabitsModule::class, HabitModule::class, TestModule::class],
dependencies = [HabitsApplicationComponent::class]
)
interface HabitsActivityTestComponent {
fun getCheckmarkPanelViewFactory(): CheckmarkPanelViewFactory
fun getHabitCardViewFactory(): HabitCardViewFactory
fun getEntryButtonViewFactory(): CheckmarkButtonViewFactory
fun getNumberButtonViewFactory(): NumberButtonViewFactory
fun getNumberPanelViewFactory(): NumberPanelViewFactory
@Component
abstract class HabitsActivityTestComponent(
@Component val parent: HabitsApplicationComponent,
@get:Provides @get:ActivityContext
val activityContext: Context
) {
abstract fun getCheckmarkPanelViewFactory(): CheckmarkPanelViewFactory
abstract fun getHabitCardViewFactory(): HabitCardViewFactory
abstract fun getEntryButtonViewFactory(): CheckmarkButtonViewFactory
abstract fun getNumberButtonViewFactory(): NumberButtonViewFactory
abstract fun getNumberPanelViewFactory(): NumberPanelViewFactory
@Provides
open fun listHabitsBehavior(): ListHabitsBehavior = mock()
open val HabitCardListAdapter.bindAdapter: ListHabitsMenuBehavior.Adapter
@Provides get() = this
open val ListHabitsModule.bindBugReporter: ListHabitsBehavior.BugReporter
@Provides get() = this
open val ListHabitsScreen.bindMenuScreen: ListHabitsMenuBehavior.Screen
@Provides get() = this
open val ListHabitsScreen.bindScreen: ListHabitsBehavior.Screen
@Provides get() = this
open val HabitCardListAdapter.bindSelMenuAdapter: ListHabitsSelectionMenuBehavior.Adapter
@Provides get() = this
open val ListHabitsScreen.bindSelMenuScreen: ListHabitsSelectionMenuBehavior.Screen
@Provides get() = this
open val HabitsDirFinder.bindDirFinder: ListHabitsBehavior.DirFinder
@Provides get() = this
}

View File

@ -18,15 +18,28 @@
*/
package org.isoron.uhabits
import dagger.Component
import android.content.Context
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.inject.AppContextModule
import org.isoron.uhabits.core.tasks.SingleThreadTaskRunner
import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.inject.AppContext
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.isoron.uhabits.inject.HabitsModule
import org.isoron.uhabits.intents.IntentScheduler
import java.io.File
@AppScope
@Component(modules = [AppContextModule::class, HabitsModule::class, SingleThreadModule::class])
interface HabitsApplicationTestComponent : HabitsApplicationComponent {
val intentScheduler: IntentScheduler?
@Component
abstract class HabitsApplicationTestComponent(
@get:Provides @get:AppContext
appContext: Context,
@get:Provides dbFile: File
) : HabitsApplicationComponent(appContext, dbFile) {
abstract val intentScheduler: IntentScheduler?
@AppScope
@Provides
override fun taskRunner(): TaskRunner = SingleThreadTaskRunner()
}

View File

@ -1,17 +0,0 @@
package org.isoron.uhabits
import dagger.Module
import dagger.Provides
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.tasks.SingleThreadTaskRunner
import org.isoron.uhabits.core.tasks.TaskRunner
@Module
internal object SingleThreadModule {
@JvmStatic
@Provides
@AppScope
fun provideTaskRunner(): TaskRunner {
return SingleThreadTaskRunner()
}
}

View File

@ -22,6 +22,7 @@ import android.content.Context
import android.os.Build
import android.os.Environment
import android.view.WindowManager
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.inject.AppContext
import java.io.BufferedReader
import java.io.File
@ -32,9 +33,9 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.LinkedList
import java.util.Locale
import javax.inject.Inject
open class AndroidBugReporter @Inject constructor(@AppContext private val context: Context) {
@Inject
open class AndroidBugReporter(@AppContext private val context: Context) {
/**
* Captures and returns a bug report. The bug report contains some device

View File

@ -20,12 +20,13 @@ package org.isoron.uhabits
import android.content.Context
import androidx.core.content.ContextCompat
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.inject.AppContext
import org.isoron.uhabits.utils.FileUtils
import java.io.File
import javax.inject.Inject
class AndroidDirFinder @Inject constructor(@param:AppContext private val context: Context) {
@Inject
class AndroidDirFinder(@param:AppContext private val context: Context) {
fun getFilesDir(relativePath: String): File? {
return FileUtils.getDir(
ContextCompat.getExternalFilesDirs(context, null),

View File

@ -26,10 +26,8 @@ import org.isoron.platform.time.setToday
import org.isoron.uhabits.core.database.UnsupportedDatabaseVersionException
import org.isoron.uhabits.core.reminders.ReminderScheduler
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.inject.AppContextModule
import org.isoron.uhabits.inject.DaggerHabitsApplicationComponent
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.isoron.uhabits.inject.HabitsModule
import org.isoron.uhabits.inject.create
import org.isoron.uhabits.utils.DatabaseUtils
import org.isoron.uhabits.widgets.WidgetUpdater
import java.io.File
@ -62,11 +60,10 @@ class HabitsApplication : Application() {
}
val db = DatabaseUtils.getDatabaseFile(this)
HabitsApplication.component = DaggerHabitsApplicationComponent
.builder()
.appContextModule(AppContextModule(context))
.habitsModule(HabitsModule(db))
.build()
HabitsApplication.component = HabitsApplicationComponent::class.create(
appContext = context,
dbFile = db
)
val prefs = component.preferences
prefs.lastAppVersion = BuildConfig.VERSION_CODE

View File

@ -18,14 +18,14 @@
*/
package org.isoron.uhabits.activities
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.AndroidDirFinder
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuPresenter
import java.io.File
import javax.inject.Inject
class HabitsDirFinder @Inject
constructor(
@Inject
class HabitsDirFinder(
private val androidDirFinder: AndroidDirFinder
) : ShowHabitMenuPresenter.System, ListHabitsBehavior.DirFinder {

View File

@ -20,6 +20,7 @@ package org.isoron.uhabits.activities.common.dialogs
import android.content.Context
import com.android.colorpicker.ColorPickerDialog.SIZE_SMALL
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.PaletteColor
@ -27,10 +28,10 @@ import org.isoron.uhabits.core.ui.views.Theme
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
import org.isoron.uhabits.utils.StyledResources
import javax.inject.Inject
@Inject
@ActivityScope
class ColorPickerDialogFactory @Inject constructor(@param:ActivityContext private val context: Context) {
class ColorPickerDialogFactory(@param:ActivityContext private val context: Context) {
fun create(color: PaletteColor, theme: Theme): ColorPickerDialog {
val dialog = ColorPickerDialog()
val res = StyledResources(context)

View File

@ -41,10 +41,9 @@ import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.core.ui.ThemeSwitcher.Companion.THEME_DARK
import org.isoron.uhabits.core.utils.MidnightTimer
import org.isoron.uhabits.database.AutoBackup
import org.isoron.uhabits.inject.ActivityContextModule
import org.isoron.uhabits.inject.DaggerHabitsActivityComponent
import org.isoron.uhabits.inject.HabitsActivityComponent
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.isoron.uhabits.inject.create
import org.isoron.uhabits.utils.applyRootViewInsets
import org.isoron.uhabits.utils.dismissCurrentDialog
import org.isoron.uhabits.utils.restartWithFade
@ -83,11 +82,10 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
super.onCreate(savedInstanceState)
appComponent = (applicationContext as HabitsApplication).component
component = DaggerHabitsActivityComponent
.builder()
.activityContextModule(ActivityContextModule(this))
.habitsApplicationComponent(appComponent)
.build()
component = HabitsActivityComponent::class.create(
parent = appComponent,
activityContext = this
)
component.themeSwitcher.apply()
prefs = appComponent.preferences

View File

@ -24,6 +24,7 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.preferences.Preferences
@ -32,10 +33,10 @@ import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsMenuBehavior
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
import org.isoron.uhabits.utils.StyledResources
import javax.inject.Inject
@Inject
@ActivityScope
class ListHabitsMenu @Inject constructor(
class ListHabitsMenu(
@ActivityContext context: Context,
private val preferences: Preferences,
private val themeSwitcher: ThemeSwitcher,

View File

@ -20,43 +20,12 @@
package org.isoron.uhabits.activities.habits.list
import android.content.Context
import dagger.Binds
import dagger.Module
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.AndroidBugReporter
import org.isoron.uhabits.activities.HabitsDirFinder
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsMenuBehavior
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBehavior
import org.isoron.uhabits.inject.AppContext
import javax.inject.Inject
class BugReporterProxy
@Inject constructor(
@Inject
class ListHabitsModule(
@AppContext context: Context
) : AndroidBugReporter(context), ListHabitsBehavior.BugReporter
@Module
abstract class ListHabitsModule {
@Binds
abstract fun getAdapter(adapter: HabitCardListAdapter): ListHabitsMenuBehavior.Adapter
@Binds
abstract fun getBugReporter(proxy: BugReporterProxy): ListHabitsBehavior.BugReporter
@Binds
abstract fun getMenuScreen(screen: ListHabitsScreen): ListHabitsMenuBehavior.Screen
@Binds
abstract fun getScreen(screen: ListHabitsScreen): ListHabitsBehavior.Screen
@Binds
abstract fun getSelMenuAdapter(adapter: HabitCardListAdapter): ListHabitsSelectionMenuBehavior.Adapter
@Binds
abstract fun getSelMenuScreen(screen: ListHabitsScreen): ListHabitsSelectionMenuBehavior.Screen
@Binds
abstract fun getSystem(system: HabitsDirFinder): ListHabitsBehavior.DirFinder
}

View File

@ -23,6 +23,7 @@ import android.content.Context
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import android.widget.RelativeLayout
import me.tatarka.inject.annotations.Inject
import nl.dionsegijn.konfetti.xml.KonfettiView
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.common.views.ScrollableChart
@ -50,14 +51,14 @@ import org.isoron.uhabits.utils.dim
import org.isoron.uhabits.utils.dp
import org.isoron.uhabits.utils.setupToolbar
import org.isoron.uhabits.utils.sres
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
const val MAX_CHECKMARK_COUNT = 60
@Inject
@ActivityScope
class ListHabitsRootView @Inject constructor(
class ListHabitsRootView(
@ActivityContext context: Context,
hintListFactory: HintListFactory,
preferences: Preferences,

View File

@ -25,7 +25,7 @@ import android.content.Intent
import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AppCompatActivity
import dagger.Lazy
import me.tatarka.inject.annotations.Inject
import nl.dionsegijn.konfetti.core.Party
import nl.dionsegijn.konfetti.core.Position
import nl.dionsegijn.konfetti.core.emitter.Emitter
@ -78,7 +78,6 @@ import org.isoron.uhabits.utils.showSendFileScreen
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
const val RESULT_IMPORT_DATA = 101
const val RESULT_EXPORT_CSV = 102
@ -88,9 +87,9 @@ const val RESULT_REPAIR_DB = 105
const val REQUEST_OPEN_DOCUMENT = 106
const val REQUEST_SETTINGS = 107
@Inject
@ActivityScope
class ListHabitsScreen
@Inject constructor(
class ListHabitsScreen(
@ActivityContext val context: Context,
private val commandRunner: CommandRunner,
private val intentFactory: IntentFactory,
@ -148,10 +147,10 @@ class ListHabitsScreen
private fun onSettingsResult(resultCode: Int) {
when (resultCode) {
RESULT_IMPORT_DATA -> showImportScreen()
RESULT_EXPORT_CSV -> behavior.get().onExportCSV()
RESULT_EXPORT_CSV -> behavior.value.onExportCSV()
RESULT_EXPORT_DB -> onExportDB()
RESULT_BUG_REPORT -> behavior.get().onSendBugReport()
RESULT_REPAIR_DB -> behavior.get().onRepairDB()
RESULT_BUG_REPORT -> behavior.value.onSendBugReport()
RESULT_REPAIR_DB -> behavior.value.onRepairDB()
}
}
@ -236,7 +235,7 @@ class ListHabitsScreen
return
}
val baseColor = themeSwitcher.currentTheme!!.color(color).toInt()
rootView.get().konfettiView.start(
rootView.value.konfettiView.start(
Party(
speed = 0f,
maxSpeed = 16f,
@ -288,7 +287,7 @@ class ListHabitsScreen
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback
) {
val theme = rootView.get().currentTheme()
val theme = rootView.value.currentTheme()
val fm = (context as AppCompatActivity).supportFragmentManager
val dialog = CheckmarkDialog()
dialog.arguments = Bundle().apply {

View File

@ -24,7 +24,7 @@ import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import dagger.Lazy
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.getToday
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
@ -35,10 +35,10 @@ import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBehavior
import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.inject.ActivityScope
import javax.inject.Inject
@Inject
@ActivityScope
class ListHabitsSelectionMenu @Inject constructor(
class ListHabitsSelectionMenu(
@ActivityContext context: Context,
private val listAdapter: HabitCardListAdapter,
var commandRunner: CommandRunner,
@ -86,7 +86,7 @@ class ListHabitsSelectionMenu @Inject constructor(
return true
}
override fun onDestroyActionMode(mode: ActionMode?) {
listController.get().onSelectionFinished()
listController.value.onSelectionFinished()
}
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {

View File

@ -28,6 +28,7 @@ import android.text.TextPaint
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.View.MeasureSpec.EXACTLY
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Entry.Companion.NO
@ -42,10 +43,9 @@ import org.isoron.uhabits.utils.getFontAwesome
import org.isoron.uhabits.utils.sp
import org.isoron.uhabits.utils.sres
import org.isoron.uhabits.utils.toMeasureSpec
import javax.inject.Inject
class CheckmarkButtonViewFactory
@Inject constructor(
@Inject
class CheckmarkButtonViewFactory(
@ActivityContext val context: Context,
val preferences: Preferences
) {

View File

@ -20,15 +20,15 @@
package org.isoron.uhabits.activities.habits.list.views
import android.content.Context
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.inject.ActivityContext
import javax.inject.Inject
class CheckmarkPanelViewFactory
@Inject constructor(
@Inject
class CheckmarkPanelViewFactory(
@ActivityContext val context: Context,
val preferences: Preferences,
private val buttonFactory: CheckmarkButtonViewFactory

View File

@ -20,6 +20,7 @@ package org.isoron.uhabits.activities.habits.list.views
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.activities.habits.list.MAX_CHECKMARK_COUNT
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
@ -32,7 +33,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBeh
import org.isoron.uhabits.core.utils.MidnightTimer
import org.isoron.uhabits.inject.ActivityScope
import java.util.LinkedList
import javax.inject.Inject
/**
* Provides data that backs a [HabitCardListView].
@ -41,8 +41,9 @@ import javax.inject.Inject
* The data if fetched and cached by a [HabitCardListCache]. This adapter
* also holds a list of items that have been selected.
*/
@Inject
@ActivityScope
class HabitCardListAdapter @Inject constructor(
class HabitCardListAdapter(
private val cache: HabitCardListCache,
private val preferences: Preferences,
private val midnightTimer: MidnightTimer

View File

@ -19,21 +19,21 @@
package org.isoron.uhabits.activities.habits.list.views
import dagger.Lazy
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.activities.habits.list.ListHabitsSelectionMenu
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.ModelObservable
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.inject.ActivityScope
import javax.inject.Inject
/**
* Controller responsible for receiving and processing the events generated by a
* HabitListView. These include selecting and reordering items, toggling
* checkmarks and clicking habits.
*/
@Inject
@ActivityScope
class HabitCardListController @Inject constructor(
class HabitCardListController(
private val adapter: HabitCardListAdapter,
private val behavior: ListHabitsBehavior,
private val selectionMenu: Lazy<ListHabitsSelectionMenu>
@ -69,7 +69,7 @@ class HabitCardListController @Inject constructor(
override fun onModelChange() {
if (adapter.isSelectionEmpty) {
activeMode = NormalMode()
selectionMenu.get().onSelectionFinish()
selectionMenu.value.onSelectionFinish()
}
}
@ -89,7 +89,7 @@ class HabitCardListController @Inject constructor(
private fun cancelSelection() {
adapter.clearSelection()
activeMode = NormalMode()
selectionMenu.get().onSelectionFinish()
selectionMenu.value.onSelectionFinish()
}
interface HabitListener {
@ -130,7 +130,7 @@ class HabitCardListController @Inject constructor(
private fun startSelection(position: Int) {
toggleSelection(position)
activeMode = SelectionMode()
selectionMenu.get().onSelectionStart()
selectionMenu.value.onSelectionStart()
}
}
@ -157,9 +157,9 @@ class HabitCardListController @Inject constructor(
private fun notifyListener() {
if (activeMode is SelectionMode) {
selectionMenu.get().onSelectionChange()
selectionMenu.value.onSelectionChange()
} else {
selectionMenu.get().onSelectionFinish()
selectionMenu.value.onSelectionFinish()
}
}
}

View File

@ -35,15 +35,14 @@ import androidx.recyclerview.widget.ItemTouchHelper.START
import androidx.recyclerview.widget.ItemTouchHelper.UP
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.Lazy
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.common.views.BundleSavedState
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.inject.ActivityContext
import javax.inject.Inject
class HabitCardListViewFactory
@Inject constructor(
@Inject
class HabitCardListViewFactory(
@ActivityContext val context: Context,
val adapter: HabitCardListAdapter,
val cardViewFactory: HabitCardViewFactory,
@ -186,13 +185,13 @@ class HabitCardListView(
override fun onLongPress(e: MotionEvent) {
val position = holder.adapterPosition
controller.get().onItemLongClick(position)
controller.value.onItemLongClick(position)
if (adapter.isSortable) touchHelper.startDrag(holder)
}
override fun onSingleTapUp(e: MotionEvent): Boolean {
val position = holder.adapterPosition
controller.get().onItemClick(position)
controller.value.onItemClick(position)
return true
}
}
@ -210,7 +209,7 @@ class HabitCardListView(
from: ViewHolder,
to: ViewHolder
): Boolean {
controller.get().drop(from.adapterPosition, to.adapterPosition)
controller.value.drop(from.adapterPosition, to.adapterPosition)
return true
}

View File

@ -34,6 +34,7 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.gui.toInt
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
@ -46,10 +47,9 @@ import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.utils.currentTheme
import org.isoron.uhabits.utils.dp
import org.isoron.uhabits.utils.sres
import javax.inject.Inject
class HabitCardViewFactory
@Inject constructor(
@Inject
class HabitCardViewFactory(
@ActivityContext val context: Context,
private val checkmarkPanelFactory: CheckmarkPanelViewFactory,
private val numberPanelFactory: NumberPanelViewFactory,

View File

@ -28,6 +28,7 @@ import android.text.TextPaint
import android.view.View
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST
@ -40,7 +41,6 @@ import org.isoron.uhabits.utils.drawNotesIndicator
import org.isoron.uhabits.utils.getFontAwesome
import org.isoron.uhabits.utils.sres
import java.text.DecimalFormat
import javax.inject.Inject
private val BOLD_TYPEFACE = Typeface.create("sans-serif-condensed", Typeface.BOLD)
private val NORMAL_TYPEFACE = Typeface.create("sans-serif-condensed", Typeface.NORMAL)
@ -58,8 +58,8 @@ fun Double.toShortString(): String = when {
else -> DecimalFormat("#.##").format(this)
}
class NumberButtonViewFactory
@Inject constructor(
@Inject
class NumberButtonViewFactory(
@ActivityContext val context: Context,
val preferences: Preferences
) {

View File

@ -20,15 +20,15 @@
package org.isoron.uhabits.activities.habits.list.views
import android.content.Context
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.models.NumericalHabitType
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.inject.ActivityContext
import javax.inject.Inject
class NumberPanelViewFactory
@Inject constructor(
@Inject
class NumberPanelViewFactory(
@ActivityContext val context: Context,
val preferences: Preferences,
val buttonFactory: NumberButtonViewFactory

View File

@ -22,7 +22,7 @@ package org.isoron.uhabits.automation
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import dagger.Component
import me.tatarka.inject.annotations.Component
import org.isoron.platform.time.getToday
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.core.models.HabitList
@ -39,16 +39,21 @@ const val ACTION_DECREMENT = 4
const val EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"
const val EXTRA_STRING_BLURB = "com.twofortyfouram.locale.intent.extra.BLURB"
@ReceiverScope
@Component
internal abstract class FireSettingReceiverComponent(
@Component val parent: HabitsApplicationComponent
) {
abstract val widgetController: WidgetBehavior
}
class FireSettingReceiver : BroadcastReceiver() {
private lateinit var allHabits: HabitList
override fun onReceive(context: Context, intent: Intent) {
val app = context.applicationContext as HabitsApplication
val component = DaggerFireSettingReceiver_ReceiverComponent
.builder()
.habitsApplicationComponent(app.component)
.build()
val component = FireSettingReceiverComponent::class.create(app.component)
allHabits = app.component.habitList
val args = SettingUtils.parseIntent(intent, allHabits) ?: return
val today = getToday()
@ -62,10 +67,4 @@ class FireSettingReceiver : BroadcastReceiver() {
ACTION_DECREMENT -> controller.onDecrement(args.habit, today, 1000)
}
}
@ReceiverScope
@Component(dependencies = [HabitsApplicationComponent::class])
internal interface ReceiverComponent {
val widgetController: WidgetBehavior
}
}

View File

@ -20,11 +20,12 @@
package org.isoron.uhabits.database
import android.database.sqlite.SQLiteDatabase
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.database.DatabaseOpener
import java.io.File
import javax.inject.Inject
class AndroidDatabaseOpener @Inject constructor() : DatabaseOpener {
@Inject
class AndroidDatabaseOpener() : DatabaseOpener {
override fun open(file: File): AndroidDatabase {
return AndroidDatabase(
db = SQLiteDatabase.openDatabase(

View File

@ -18,9 +18,13 @@
*/
package org.isoron.uhabits.inject
import javax.inject.Qualifier
import me.tatarka.inject.annotations.Qualifier
@Qualifier
@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE
)
annotation class ActivityContext

View File

@ -1,30 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.inject
import android.content.Context
import dagger.Module
import dagger.Provides
@Module
class ActivityContextModule(
@get:Provides
@get:ActivityContext
val context: Context
)

View File

@ -18,7 +18,7 @@
*/
package org.isoron.uhabits.inject
import javax.inject.Scope
import me.tatarka.inject.annotations.Scope
/**
* Scope used by objects that live as long as the activity is alive.

View File

@ -18,9 +18,13 @@
*/
package org.isoron.uhabits.inject
import javax.inject.Qualifier
import me.tatarka.inject.annotations.Qualifier
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Target(
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE
)
annotation class AppContext

View File

@ -1,31 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.inject
import android.content.Context
import dagger.Module
import dagger.Provides
@Module
class AppContextModule(
@get:Provides
@get:AppContext
@param:AppContext
val context: Context
)

View File

@ -1,29 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.inject
import dagger.Module
import dagger.Provides
import org.isoron.uhabits.core.models.Habit
@Module
class HabitModule(private val habit: Habit) {
@Provides fun getHabit() = habit
}

View File

@ -19,7 +19,11 @@
package org.isoron.uhabits.inject
import dagger.Component
import android.content.Context
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.activities.HabitsDirFinder
import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory
import org.isoron.uhabits.activities.habits.list.ListHabitsMenu
import org.isoron.uhabits.activities.habits.list.ListHabitsModule
@ -27,21 +31,53 @@ import org.isoron.uhabits.activities.habits.list.ListHabitsRootView
import org.isoron.uhabits.activities.habits.list.ListHabitsScreen
import org.isoron.uhabits.activities.habits.list.ListHabitsSelectionMenu
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.ThemeSwitcher
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsMenuBehavior
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsSelectionMenuBehavior
@ActivityScope
@Component(
modules = [ActivityContextModule::class, HabitsActivityModule::class, ListHabitsModule::class, HabitModule::class],
dependencies = [HabitsApplicationComponent::class]
)
interface HabitsActivityComponent {
val colorPickerDialogFactory: ColorPickerDialogFactory
val habitCardListAdapter: HabitCardListAdapter
val listHabitsBehavior: ListHabitsBehavior
val listHabitsMenu: ListHabitsMenu
val listHabitsRootView: ListHabitsRootView
val listHabitsScreen: ListHabitsScreen
val listHabitsSelectionMenu: ListHabitsSelectionMenu
val themeSwitcher: ThemeSwitcher
@Component
abstract class HabitsActivityComponent(
@Component val parent: HabitsApplicationComponent,
@get:Provides @get:ActivityContext
val activityContext: Context
) {
abstract val colorPickerDialogFactory: ColorPickerDialogFactory
abstract val habitCardListAdapter: HabitCardListAdapter
abstract val listHabitsBehavior: ListHabitsBehavior
abstract val listHabitsMenu: ListHabitsMenu
abstract val listHabitsRootView: ListHabitsRootView
abstract val listHabitsScreen: ListHabitsScreen
abstract val listHabitsSelectionMenu: ListHabitsSelectionMenu
abstract val themeSwitcher: ThemeSwitcher
@ActivityScope
@Provides
open fun themeSwitcher(
@ActivityContext context: Context,
prefs: Preferences
): ThemeSwitcher = AndroidThemeSwitcher(context, prefs)
open val HabitCardListAdapter.bindAdapter: ListHabitsMenuBehavior.Adapter
@Provides get() = this
open val ListHabitsModule.bindBugReporter: ListHabitsBehavior.BugReporter
@Provides get() = this
open val ListHabitsScreen.bindMenuScreen: ListHabitsMenuBehavior.Screen
@Provides get() = this
open val ListHabitsScreen.bindScreen: ListHabitsBehavior.Screen
@Provides get() = this
open val HabitCardListAdapter.bindSelMenuAdapter: ListHabitsSelectionMenuBehavior.Adapter
@Provides get() = this
open val ListHabitsScreen.bindSelMenuScreen: ListHabitsSelectionMenuBehavior.Screen
@Provides get() = this
open val HabitsDirFinder.bindDirFinder: ListHabitsBehavior.DirFinder
@Provides get() = this
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.inject
import android.content.Context
import dagger.Module
import dagger.Provides
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.ThemeSwitcher
@Module
class HabitsActivityModule {
@Provides
@ActivityScope
fun getThemeSwitcher(
@ActivityContext context: Context,
prefs: Preferences
): ThemeSwitcher {
return AndroidThemeSwitcher(context, prefs)
}
}

View File

@ -19,13 +19,18 @@
package org.isoron.uhabits.inject
import android.content.Context
import dagger.Component
import me.tatarka.inject.annotations.Component
import me.tatarka.inject.annotations.Provides
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.DatabaseOpener
import org.isoron.uhabits.core.io.GenericImporter
import org.isoron.uhabits.core.io.Logging
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.sqlite.SQLModelFactory
import org.isoron.uhabits.core.models.sqlite.SQLiteHabitList
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.isoron.uhabits.core.reminders.ReminderScheduler
@ -33,34 +38,107 @@ import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.core.ui.screens.habits.list.HabitCardListCache
import org.isoron.uhabits.core.utils.MidnightTimer
import org.isoron.uhabits.database.AndroidDatabase
import org.isoron.uhabits.database.AndroidDatabaseOpener
import org.isoron.uhabits.intents.IntentFactory
import org.isoron.uhabits.intents.IntentParser
import org.isoron.uhabits.intents.IntentScheduler
import org.isoron.uhabits.intents.PendingIntentFactory
import org.isoron.uhabits.io.AndroidLogging
import org.isoron.uhabits.notifications.AndroidNotificationTray
import org.isoron.uhabits.preferences.SharedPreferencesStorage
import org.isoron.uhabits.receivers.ReminderController
import org.isoron.uhabits.tasks.AndroidTaskRunner
import org.isoron.uhabits.utils.DatabaseUtils
import org.isoron.uhabits.widgets.WidgetUpdater
import java.io.File
@AppScope
@Component(modules = [AppContextModule::class, HabitsModule::class, AndroidTaskRunner::class])
interface HabitsApplicationComponent {
val commandRunner: CommandRunner
@Component
abstract class HabitsApplicationComponent(
@get:Provides @get:AppContext
val appContext: Context,
@get:Provides val dbFile: File
) {
abstract val commandRunner: CommandRunner
@get:AppContext
val context: Context
val genericImporter: GenericImporter
val habitCardListCache: HabitCardListCache
val habitList: HabitList
val intentFactory: IntentFactory
val intentParser: IntentParser
val logging: Logging
val midnightTimer: MidnightTimer
val modelFactory: ModelFactory
val notificationTray: NotificationTray
val pendingIntentFactory: PendingIntentFactory
val preferences: Preferences
val reminderScheduler: ReminderScheduler
val reminderController: ReminderController
val taskRunner: TaskRunner
val widgetPreferences: WidgetPreferences
val widgetUpdater: WidgetUpdater
abstract val context: Context
abstract val genericImporter: GenericImporter
abstract val habitCardListCache: HabitCardListCache
abstract val habitList: HabitList
abstract val intentFactory: IntentFactory
abstract val intentParser: IntentParser
abstract val logging: Logging
abstract val midnightTimer: MidnightTimer
abstract val modelFactory: ModelFactory
abstract val notificationTray: NotificationTray
abstract val pendingIntentFactory: PendingIntentFactory
abstract val preferences: Preferences
abstract val reminderScheduler: ReminderScheduler
abstract val reminderController: ReminderController
abstract val taskRunner: TaskRunner
abstract val widgetPreferences: WidgetPreferences
abstract val widgetUpdater: WidgetUpdater
val db: Database
get() = providedDb
private val providedDb: Database by lazy {
AndroidDatabase(DatabaseUtils.openDatabase(), dbFile)
}
@AppScope
@Provides
open fun database(): Database = providedDb
@AppScope
@Provides
open fun preferences(storage: SharedPreferencesStorage): Preferences =
Preferences(storage)
@AppScope
@Provides
open fun reminderScheduler(
sys: IntentScheduler,
commandRunner: CommandRunner,
habitList: HabitList,
widgetPreferences: WidgetPreferences
): ReminderScheduler =
ReminderScheduler(commandRunner, habitList, sys, widgetPreferences)
@AppScope
@Provides
open fun notificationTray(
taskRunner: TaskRunner,
commandRunner: CommandRunner,
preferences: Preferences,
screen: AndroidNotificationTray
): NotificationTray =
NotificationTray(taskRunner, commandRunner, preferences, screen)
@AppScope
@Provides
open fun widgetPreferences(storage: SharedPreferencesStorage): WidgetPreferences =
WidgetPreferences(storage)
@AppScope
@Provides
open fun modelFactory(): ModelFactory = SQLModelFactory(providedDb)
@AppScope
@Provides
open fun habitList(list: SQLiteHabitList): HabitList = list
@AppScope
@Provides
open fun databaseOpener(opener: AndroidDatabaseOpener): DatabaseOpener = opener
@AppScope
@Provides
open fun logging(): Logging = AndroidLogging()
@AppScope
@Provides
open fun taskRunner(): TaskRunner = AndroidTaskRunner()
}

View File

@ -1,117 +0,0 @@
/*
* Copyright (C) 2016-2025 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.inject
import dagger.Module
import dagger.Provides
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.DatabaseOpener
import org.isoron.uhabits.core.io.Logging
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.sqlite.SQLModelFactory
import org.isoron.uhabits.core.models.sqlite.SQLiteHabitList
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.isoron.uhabits.core.reminders.ReminderScheduler
import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.database.AndroidDatabase
import org.isoron.uhabits.database.AndroidDatabaseOpener
import org.isoron.uhabits.intents.IntentScheduler
import org.isoron.uhabits.io.AndroidLogging
import org.isoron.uhabits.notifications.AndroidNotificationTray
import org.isoron.uhabits.preferences.SharedPreferencesStorage
import org.isoron.uhabits.utils.DatabaseUtils
import java.io.File
@Module
class HabitsModule(dbFile: File) {
val db: Database = AndroidDatabase(DatabaseUtils.openDatabase(), dbFile)
@Provides
@AppScope
fun getPreferences(storage: SharedPreferencesStorage): Preferences {
return Preferences(storage)
}
@Provides
@AppScope
fun getReminderScheduler(
sys: IntentScheduler,
commandRunner: CommandRunner,
habitList: HabitList,
widgetPreferences: WidgetPreferences
): ReminderScheduler {
return ReminderScheduler(commandRunner, habitList, sys, widgetPreferences)
}
@Provides
@AppScope
fun getTray(
taskRunner: TaskRunner,
commandRunner: CommandRunner,
preferences: Preferences,
screen: AndroidNotificationTray
): NotificationTray {
return NotificationTray(taskRunner, commandRunner, preferences, screen)
}
@Provides
@AppScope
fun getWidgetPreferences(
storage: SharedPreferencesStorage
): WidgetPreferences {
return WidgetPreferences(storage)
}
@Provides
@AppScope
fun getModelFactory(): ModelFactory {
return SQLModelFactory(db)
}
@Provides
@AppScope
fun getHabitList(list: SQLiteHabitList): HabitList {
return list
}
@Provides
@AppScope
fun getDatabaseOpener(opener: AndroidDatabaseOpener): DatabaseOpener {
return opener
}
@Provides
@AppScope
fun getLogging(): Logging {
return AndroidLogging()
}
@Provides
@AppScope
fun getDatabase(): Database {
return db
}
}

View File

@ -22,6 +22,7 @@ package org.isoron.uhabits.intents
import android.content.Context
import android.content.Intent
import android.net.Uri
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.about.AboutActivity
import org.isoron.uhabits.activities.habits.edit.EditHabitActivity
@ -29,10 +30,9 @@ import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
import org.isoron.uhabits.activities.intro.IntroActivity
import org.isoron.uhabits.activities.settings.SettingsActivity
import org.isoron.uhabits.core.models.Habit
import javax.inject.Inject
class IntentFactory
@Inject constructor() {
@Inject
class IntentFactory() {
fun helpTranslate(context: Context) =
buildViewIntent(context.getString(R.string.translateURL))

View File

@ -22,16 +22,16 @@ package org.isoron.uhabits.intents
import android.content.ContentUris.parseId
import android.content.Intent
import android.net.Uri
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import javax.inject.Inject
@Inject
@AppScope
class IntentParser
@Inject constructor(
class IntentParser(
private val habits: HabitList
) {

View File

@ -27,6 +27,7 @@ import android.content.Context
import android.content.Context.ALARM_SERVICE
import android.os.Build
import android.util.Log
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.reminders.ReminderScheduler.SchedulerResult
@ -34,12 +35,11 @@ import org.isoron.uhabits.core.reminders.ReminderScheduler.SystemScheduler
import org.isoron.uhabits.core.utils.DateFormats
import org.isoron.uhabits.inject.AppContext
import java.util.Date
import javax.inject.Inject
import kotlin.math.min
@Inject
@AppScope
class IntentScheduler
@Inject constructor(
class IntentScheduler(
@AppContext context: Context,
private val pendingIntents: PendingIntentFactory
) : SystemScheduler {

View File

@ -29,6 +29,7 @@ import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.activities.habits.list.ListHabitsActivity
import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
@ -37,11 +38,10 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.inject.AppContext
import org.isoron.uhabits.receivers.ReminderReceiver
import org.isoron.uhabits.receivers.WidgetReceiver
import javax.inject.Inject
@Inject
@AppScope
class PendingIntentFactory
@Inject constructor(
class PendingIntentFactory(
@AppContext private val context: Context,
private val intentFactory: IntentFactory
) {

View File

@ -32,6 +32,7 @@ import androidx.core.app.NotificationCompat.Action
import androidx.core.app.NotificationCompat.Builder
import androidx.core.app.NotificationCompat.WearableExtender
import androidx.core.app.NotificationManagerCompat
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.R
import org.isoron.uhabits.core.AppScope
@ -40,11 +41,10 @@ import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.inject.AppContext
import org.isoron.uhabits.intents.PendingIntentFactory
import javax.inject.Inject
@Inject
@AppScope
class AndroidNotificationTray
@Inject constructor(
class AndroidNotificationTray(
@AppContext private val context: Context,
private val pendingIntents: PendingIntentFactory,
private val preferences: Preferences,

View File

@ -27,14 +27,14 @@ import android.media.RingtoneManager.getRingtone
import android.net.Uri
import android.preference.PreferenceManager
import android.provider.Settings
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.inject.AppContext
import javax.inject.Inject
@Inject
@AppScope
class RingtoneManager
@Inject constructor(@AppContext private val context: Context) {
class RingtoneManager(@AppContext private val context: Context) {
val prefs: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context)

View File

@ -22,15 +22,15 @@ package org.isoron.uhabits.preferences
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.R
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.inject.AppContext
import javax.inject.Inject
@Inject
@AppScope
class SharedPreferencesStorage
@Inject constructor(
class SharedPreferencesStorage(
@AppContext context: Context
) : SharedPreferences.OnSharedPreferenceChangeListener, Preferences.Storage {

View File

@ -18,7 +18,7 @@
*/
package org.isoron.uhabits.receivers
import javax.inject.Scope
import me.tatarka.inject.annotations.Scope
@Scope
annotation class ReceiverScope

View File

@ -21,6 +21,7 @@ package org.isoron.uhabits.receivers
import android.content.Context
import android.content.Intent
import android.net.Uri
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.models.Habit
@ -29,10 +30,10 @@ import org.isoron.uhabits.core.reminders.ReminderScheduler
import org.isoron.uhabits.core.ui.NotificationTray
import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.notifications.SnoozeDelayPickerActivity
import javax.inject.Inject
@Inject
@AppScope
class ReminderController @Inject constructor(
class ReminderController(
private val reminderScheduler: ReminderScheduler,
private val notificationTray: NotificationTray,
private val preferences: Preferences

View File

@ -22,7 +22,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import dagger.Component
import me.tatarka.inject.annotations.Component
import org.isoron.platform.time.computeToday
import org.isoron.platform.time.setToday
import org.isoron.uhabits.HabitsApplication
@ -30,6 +30,14 @@ import org.isoron.uhabits.core.ui.widgets.WidgetBehavior
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.isoron.uhabits.intents.IntentParser.CheckmarkIntentData
@ReceiverScope
@Component
internal abstract class WidgetComponent(
@Component val parent: HabitsApplicationComponent
) {
abstract val widgetController: WidgetBehavior
}
/**
* The Android BroadcastReceiver for Loop Habit Tracker.
*
@ -39,10 +47,7 @@ import org.isoron.uhabits.intents.IntentParser.CheckmarkIntentData
class WidgetReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val app = context.applicationContext as HabitsApplication
val component = DaggerWidgetReceiver_WidgetComponent
.builder()
.habitsApplicationComponent(app.component)
.build()
val component = WidgetComponent::class.create(app.component)
val parser = app.component.intentParser
val controller = component.widgetController
val prefs = app.component.preferences
@ -108,12 +113,6 @@ class WidgetReceiver : BroadcastReceiver() {
}
}
@ReceiverScope
@Component(dependencies = [HabitsApplicationComponent::class])
internal interface WidgetComponent {
val widgetController: WidgetBehavior
}
companion object {
const val ACTION_ADD_REPETITION = "org.isoron.uhabits.ACTION_ADD_REPETITION"
const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER"

View File

@ -19,16 +19,11 @@
package org.isoron.uhabits.tasks
import android.os.AsyncTask
import dagger.Module
import dagger.Provides
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.tasks.Task
import org.isoron.uhabits.core.tasks.TaskRunner
import java.util.HashMap
import java.util.LinkedList
// TODO: @Module not needed?
@Module
class AndroidTaskRunner : TaskRunner {
private val activeTasks: LinkedList<CustomAsyncTask> = LinkedList()
private val taskToAsyncTask: HashMap<Task, CustomAsyncTask> = HashMap()
@ -90,14 +85,4 @@ class AndroidTaskRunner : TaskRunner {
values[0]?.let { task.onProgressUpdate(it) }
}
}
@Module
companion object {
@JvmStatic
@Provides
@AppScope
fun provideTaskRunner(): TaskRunner {
return AndroidTaskRunner()
}
}
}

View File

@ -20,12 +20,12 @@
package org.isoron.uhabits.tasks
import android.content.Context
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.AndroidDirFinder
import org.isoron.uhabits.inject.AppContext
import javax.inject.Inject
class ExportDBTaskFactory
@Inject constructor(
@Inject
class ExportDBTaskFactory(
@AppContext private val context: Context,
private val system: AndroidDirFinder
) {

View File

@ -19,13 +19,13 @@
package org.isoron.uhabits.tasks
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.io.GenericImporter
import org.isoron.uhabits.core.models.ModelFactory
import java.io.File
import javax.inject.Inject
class ImportDataTaskFactory
@Inject constructor(
@Inject
class ImportDataTaskFactory(
private val importer: GenericImporter,
private val modelFactory: ModelFactory
) {

View File

@ -23,6 +23,7 @@ import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.commands.Command
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
@ -32,14 +33,13 @@ import org.isoron.uhabits.core.tasks.TaskRunner
import org.isoron.uhabits.core.utils.DateUtils
import org.isoron.uhabits.inject.AppContext
import org.isoron.uhabits.intents.IntentScheduler
import javax.inject.Inject
/**
* A WidgetUpdater listens to the commands being executed by the application and
* updates the home-screen widgets accordingly.
*/
class WidgetUpdater
@Inject constructor(
@Inject
class WidgetUpdater(
@AppContext private val context: Context,
private val commandRunner: CommandRunner,
private val taskRunner: TaskRunner,

View File

@ -44,7 +44,7 @@ kotlin {
val jvmMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
compileOnly(libs.dagger)
compileOnly(libs.kotlin.inject.runtime)
implementation(libs.guava)
implementation(libs.kotlinx.coroutines.core.jvm)
implementation(libs.annotation)

View File

@ -18,7 +18,7 @@
*/
package org.isoron.uhabits.core
import javax.inject.Scope
import me.tatarka.inject.annotations.Scope
@Scope
annotation class AppScope

View File

@ -18,15 +18,15 @@
*/
package org.isoron.uhabits.core.commands
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.tasks.Task
import org.isoron.uhabits.core.tasks.TaskRunner
import java.util.LinkedList
import javax.inject.Inject
@AppScope
open class CommandRunner
@Inject constructor(
@Inject
open class CommandRunner(
private val taskRunner: TaskRunner
) {
private val listeners: LinkedList<Listener> = LinkedList()

View File

@ -18,15 +18,15 @@
*/
package org.isoron.uhabits.core.io
import me.tatarka.inject.annotations.Inject
import java.io.File
import javax.inject.Inject
/**
* A GenericImporter decides which implementation of AbstractImporter is able to
* handle a given file and delegates to it the task of importing the data.
*/
class GenericImporter
@Inject constructor(
@Inject
class GenericImporter(
loopDBImporter: LoopDBImporter,
rewireDBImporter: RewireDBImporter,
tickmateDBImporter: TickmateDBImporter,

View File

@ -19,6 +19,7 @@
package org.isoron.uhabits.core.io
import com.opencsv.CSVReader
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Frequency
@ -29,13 +30,12 @@ import org.isoron.uhabits.core.models.ModelFactory
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
import javax.inject.Inject
/**
* Class that imports data from HabitBull CSV files.
*/
class HabitBullCSVImporter
@Inject constructor(
@Inject
class HabitBullCSVImporter(
private val habitList: HabitList,
private val modelFactory: ModelFactory,
logging: Logging

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.io
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.DATABASE_VERSION
@ -34,13 +35,12 @@ import org.isoron.uhabits.core.models.sqlite.records.EntryRecord
import org.isoron.uhabits.core.models.sqlite.records.HabitRecord
import org.isoron.uhabits.core.utils.isSQLite3File
import java.io.File
import javax.inject.Inject
/**
* Class that imports data from database files exported by Loop Habit Tracker.
*/
class LoopDBImporter
@Inject constructor(
@Inject
class LoopDBImporter(
@AppScope val habitList: HabitList,
@AppScope val modelFactory: ModelFactory,
@AppScope val opener: DatabaseOpener,

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.io
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.database.Cursor
import org.isoron.uhabits.core.database.Database
@ -31,13 +32,12 @@ import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.isoron.uhabits.core.utils.isSQLite3File
import java.io.File
import javax.inject.Inject
/**
* Class that imports database files exported by Rewire.
*/
class RewireDBImporter
@Inject constructor(
@Inject
class RewireDBImporter(
private val habitList: HabitList,
private val modelFactory: ModelFactory,
private val opener: DatabaseOpener

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.io
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.database.Cursor
import org.isoron.uhabits.core.database.Database
@ -29,12 +30,12 @@ import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.utils.isSQLite3File
import java.io.File
import javax.inject.Inject
/**
* Class that imports data from database files exported by Tickmate.
*/
class TickmateDBImporter @Inject constructor(
@Inject
class TickmateDBImporter(
private val habitList: HabitList,
private val modelFactory: ModelFactory,
private val opener: DatabaseOpener

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.models.sqlite
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.database.Database
import org.isoron.uhabits.core.database.Repository
import org.isoron.uhabits.core.models.EntryList
@ -26,13 +27,12 @@ import org.isoron.uhabits.core.models.ScoreList
import org.isoron.uhabits.core.models.StreakList
import org.isoron.uhabits.core.models.sqlite.records.EntryRecord
import org.isoron.uhabits.core.models.sqlite.records.HabitRecord
import javax.inject.Inject
/**
* Factory that provides models backed by an SQLite database.
*/
class SQLModelFactory
@Inject constructor(
@Inject
class SQLModelFactory(
val database: Database
) : ModelFactory {
override fun buildOriginalEntries() = SQLiteEntryList(database)

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.models.sqlite
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.database.Repository
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
@ -25,12 +26,12 @@ import org.isoron.uhabits.core.models.HabitMatcher
import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.memory.MemoryHabitList
import org.isoron.uhabits.core.models.sqlite.records.HabitRecord
import javax.inject.Inject
/**
* Implementation of a [HabitList] that is backed by SQLite.
*/
class SQLiteHabitList @Inject constructor(private val modelFactory: ModelFactory) : HabitList() {
@Inject
class SQLiteHabitList(private val modelFactory: ModelFactory) : HabitList() {
private val repository: Repository<HabitRecord> = modelFactory.buildHabitListRepository()
private val list: MemoryHabitList = MemoryHabitList()
private var loaded = false

View File

@ -18,11 +18,12 @@
*/
package org.isoron.uhabits.core.preferences
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.AppScope
import javax.inject.Inject
@AppScope
class WidgetPreferences @Inject constructor(private val storage: Preferences.Storage) {
@Inject
class WidgetPreferences(private val storage: Preferences.Storage) {
fun addWidget(widgetId: Int, habitIds: LongArray) {
storage.putLongArray(getHabitIdKey(widgetId), habitIds)
}

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.reminders
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.commands.ChangeHabitColorCommand
import org.isoron.uhabits.core.commands.Command
@ -30,10 +31,10 @@ import org.isoron.uhabits.core.preferences.WidgetPreferences
import org.isoron.uhabits.core.utils.DateUtils
import java.util.Locale
import java.util.Objects
import javax.inject.Inject
@AppScope
class ReminderScheduler @Inject constructor(
@Inject
class ReminderScheduler(
private val commandRunner: CommandRunner,
private val habitList: HabitList,
private val sys: SystemScheduler,

View File

@ -19,13 +19,13 @@
package org.isoron.uhabits.core.tasks
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import java.io.File
import javax.inject.Inject
class ExportCSVTaskFactory
@Inject constructor(
@Inject
class ExportCSVTaskFactory(
val habitList: HabitList
) {
fun create(

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.ui
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.commands.Command
@ -32,10 +33,10 @@ import org.isoron.uhabits.core.tasks.TaskRunner
import java.util.HashMap
import java.util.Locale
import java.util.Objects
import javax.inject.Inject
@AppScope
class NotificationTray @Inject constructor(
@Inject
class NotificationTray(
private val taskRunner: TaskRunner,
private val commandRunner: CommandRunner,
private val preferences: Preferences,

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import me.tatarka.inject.annotations.Inject
import org.apache.commons.lang3.ArrayUtils
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.AppScope
@ -36,7 +37,6 @@ import java.util.Arrays
import java.util.HashMap
import java.util.LinkedList
import java.util.TreeSet
import javax.inject.Inject
/**
* A HabitCardListCache fetches and keeps a cache of all the data necessary to
@ -52,7 +52,8 @@ import javax.inject.Inject
* activities.
*/
@AppScope
class HabitCardListCache @Inject constructor(
@Inject
class HabitCardListCache(
private val allHabits: HabitList,
private val commandRunner: CommandRunner,
taskRunner: TaskRunner,

View File

@ -19,11 +19,11 @@
package org.isoron.uhabits.core.ui.screens.habits.list
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.preferences.Preferences
import javax.inject.Inject
class HintListFactory
@Inject constructor(
@Inject
class HintListFactory(
val preferences: Preferences
) {
fun create(hints: Array<String>) = HintList(preferences, hints)

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.getToday
import org.isoron.uhabits.core.commands.CommandRunner
@ -35,10 +36,10 @@ import org.isoron.uhabits.core.tasks.TaskRunner
import java.io.File
import java.io.IOException
import java.util.LinkedList
import javax.inject.Inject
import kotlin.math.roundToInt
open class ListHabitsBehavior @Inject constructor(
@Inject
open class ListHabitsBehavior(
private val habitList: HabitList,
private val dirFinder: DirFinder,
private val taskRunner: TaskRunner,

View File

@ -18,13 +18,14 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.HabitMatcher
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.ThemeSwitcher
import javax.inject.Inject
class ListHabitsMenuBehavior @Inject constructor(
@Inject
class ListHabitsMenuBehavior(
private val screen: Screen,
private val adapter: Adapter,
private val preferences: Preferences,

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.ui.screens.habits.list
import me.tatarka.inject.annotations.Inject
import org.isoron.uhabits.core.commands.ArchiveHabitsCommand
import org.isoron.uhabits.core.commands.ChangeHabitColorCommand
import org.isoron.uhabits.core.commands.CommandRunner
@ -28,9 +29,9 @@ import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.ui.callbacks.OnColorPickedCallback
import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback
import javax.inject.Inject
class ListHabitsSelectionMenuBehavior @Inject constructor(
@Inject
class ListHabitsSelectionMenuBehavior(
private val habitList: HabitList,
private val screen: Screen,
private val adapter: Adapter,

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.ui.widgets
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
@ -27,9 +28,9 @@ import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.NotificationTray
import javax.inject.Inject
class WidgetBehavior @Inject constructor(
@Inject
class WidgetBehavior(
private val habitList: HabitList,
private val commandRunner: CommandRunner,
private val notificationTray: NotificationTray,

View File

@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.core.utils
import me.tatarka.inject.annotations.Inject
import org.isoron.platform.time.computeToday
import org.isoron.platform.time.setToday
import org.isoron.uhabits.core.AppScope
@ -27,13 +28,13 @@ import java.util.LinkedList
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import javax.inject.Inject
/**
* A class that emits events when a new day starts.
*/
@AppScope
open class MidnightTimer @Inject constructor(
@Inject
open class MidnightTimer(
logging: Logging,
private val preferences: Preferences
) {