Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ GEO=false E2E=true ./gradlew assembleDevRelease
E2E=true E2E_BACKEND=network ./gradlew assembleTnetRelease

# Lint using detekt
./gradlew detekt
./gradlew detekt --rerun-tasks

# Auto-format using detekt
./gradlew detekt --auto-correct
Expand Down Expand Up @@ -133,6 +133,13 @@ suspend fun getData() = withContext(Dispatchers.IO) { }

## Common Patterns

### Naming: Use Context, Avoid Redundant Prefixes
-
- Infer names from the surrounding context: file name, component/class name, enclosing function, module, and call site.
- Avoid repeating domain prefixes or suffixes that are already obvious from the context, especially for private, nested, local and file-local symbols, i.e., inner-scoped parts invisible outside their context.
- Only add a prefix/suffix when it resolves real ambiguity at the call site. Preserve existing concise names unless there is a concrete readability or correctness reason to rename them.
- Examples: `Numpad` or `formatAmount`, instead of `CalculatorNumpad` or `formatCalculatorAmount`.

### ViewModel State

```kotlin
Expand All @@ -141,7 +148,7 @@ val uiState: StateFlow<UiState> = _uiState.asStateFlow()

fun updateState(action: Action) {
viewModelScope.launch {
_uiState.update { it.copy(/* fields */) }
_uiState.update { it.copy(/**/) }
}
}
```
Expand All @@ -160,7 +167,6 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {

### Rules

- USE coding rules from `.cursor/default.rules.mdc`
- ALWAYS run `./gradlew compileDevDebugKotlin` after code changes to verify code compiles
- ALWAYS run `./gradlew testDevDebugUnitTest` after code changes to verify tests succeed and fix accordingly
- ALWAYS run `./gradlew detekt` after code changes to check for new lint issues and fix accordingly
Expand Down Expand Up @@ -201,7 +207,7 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
- ALWAYS add trailing commas in multi-line declarations, EXCEPT after a `modifier = ...` last argument — never add a trailing comma there, whether the modifier is a single call (`modifier = Modifier.weight(1f)`) or a chain (`modifier = Modifier.fillMaxWidth().testTag("foo")`)
- ALWAYS use `navController.navigateTo(route)` for simple navigation; NEVER use raw `navController.navigate(route)` — `navigateTo` prevents duplicate destinations
- ALWAYS prefer `VerticalSpacer`, `HorizontalSpacer`, `FillHeight` and `FillWidth` over `Spacer` when applicable
- PREFER declaring small dependant classes, constants, interfaces or top-level functions in the same file with the core class where these are used
- PREFER declaring small dependant classes, constants, interfaces, or top-level functions in the same file with the core class where these are used
- ALWAYS create data classes for state AFTER viewModel class in same file
- ALWAYS return early where applicable, PREFER guard-like `if` conditions like `if (condition) return`
- USE `docs/` as target dir of saved files when asked to create documentation for new features
Expand Down Expand Up @@ -278,3 +284,6 @@ suspend fun getData(): Result<Data> = withContext(Dispatchers.IO) {
- Use `WakeNodeWorker` to manage the handling of remote notifications received via cloud messages
- Use `*Services` to wrap rust library code exposed via bindings
- Use CQRS pattern of Command + Handler like it's done in the `NotifyPaymentReceived` + `NotifyPaymentReceivedHandler` setup

### Other Sources
- Use coding rules from `.cursor/default.rules.mdc`
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The following IDE plugins are recommended for development with Android Studio or

**Commands**
```sh
./gradlew detekt # run analysis + formatting check
./gradlew detekt --rerun-tasks # run analysis + formatting check (rerun flag ensures issues are always listed.)
./gradlew detekt --auto-correct # auto-fix formatting issues
```
Reports are generated in: `app/build/reports/detekt/`.
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,19 @@
android:resource="@xml/appwidget_info_weather" />
</receiver>

<!-- Calculator Widget -->
<receiver
android:name=".appwidget.ui.calculator.CalculatorGlanceReceiver"
android:exported="true"
android:label="@string/widgets__calculator__name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info_calculator" />
</receiver>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import to.bitkit.data.dto.WeatherDTO
import to.bitkit.data.dto.price.GraphPeriod
import to.bitkit.data.dto.price.PriceDTO
import to.bitkit.data.serializers.AppWidgetDataSerializer
import to.bitkit.repositories.CurrencyRepo
import to.bitkit.repositories.WidgetsRepo
import javax.inject.Inject
import javax.inject.Singleton

Expand All @@ -32,6 +34,8 @@ private val Context.appWidgetDataStore: DataStore<AppWidgetData> by dataStore(
interface AppWidgetEntryPoint {
fun appWidgetPreferencesStore(): AppWidgetPreferencesStore
fun appWidgetDataRepository(): AppWidgetDataRepository
fun widgetsRepo(): WidgetsRepo
fun currencyRepo(): CurrencyRepo
}

@Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import dagger.assisted.AssistedInject
import to.bitkit.appwidget.model.AppWidgetType
import to.bitkit.appwidget.ui.blocks.BlocksGlanceReceiver
import to.bitkit.appwidget.ui.blocks.BlocksGlanceWidget
import to.bitkit.appwidget.ui.calculator.CalculatorGlanceReceiver
import to.bitkit.appwidget.ui.calculator.CalculatorGlanceWidget
import to.bitkit.appwidget.ui.facts.FactsGlanceReceiver
import to.bitkit.appwidget.ui.facts.FactsGlanceWidget
import to.bitkit.appwidget.ui.headlines.HeadlinesGlanceReceiver
Expand Down Expand Up @@ -74,6 +76,7 @@ class AppWidgetRefreshWorker @AssistedInject constructor(
AppWidgetType.BLOCKS -> BlocksGlanceReceiver::class.java
AppWidgetType.FACTS -> FactsGlanceReceiver::class.java
AppWidgetType.WEATHER -> WeatherGlanceReceiver::class.java
AppWidgetType.CALCULATOR -> CalculatorGlanceReceiver::class.java
}
}

Expand Down Expand Up @@ -133,6 +136,10 @@ class AppWidgetRefreshWorker @AssistedInject constructor(
}
WeatherGlanceWidget().updateAll(appContext)
}

AppWidgetType.CALCULATOR -> {
CalculatorGlanceWidget().updateAll(appContext)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package to.bitkit.appwidget

import android.content.Context
import androidx.glance.appwidget.updateAll
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.first
import to.bitkit.appwidget.model.AppWidgetType
import to.bitkit.appwidget.ui.calculator.CalculatorGlanceWidget
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class CalculatorAppWidgetUpdater @Inject constructor(
@ApplicationContext private val context: Context,
private val preferencesStore: AppWidgetPreferencesStore,
) {
suspend fun update() {
if (!preferencesStore.hasWidgetsOfType(AppWidgetType.CALCULATOR).first()) return
CalculatorGlanceWidget().updateAll(context)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import to.bitkit.appwidget.AppWidgetRefreshWorker
import to.bitkit.appwidget.model.AppWidgetType
import to.bitkit.appwidget.ui.blocks.BlocksGlanceReceiver
import to.bitkit.appwidget.ui.blocks.BlocksGlanceWidget
import to.bitkit.appwidget.ui.calculator.CalculatorGlanceReceiver
import to.bitkit.appwidget.ui.headlines.HeadlinesGlanceReceiver
import to.bitkit.appwidget.ui.headlines.HeadlinesGlanceWidget
import to.bitkit.appwidget.ui.price.PriceGlanceReceiver
Expand Down Expand Up @@ -62,6 +63,7 @@ class AppWidgetConfigActivity : ComponentActivity() {
AppWidgetType.BLOCKS -> BlocksGlanceWidget().updateAll(this@AppWidgetConfigActivity)
AppWidgetType.FACTS -> Unit
AppWidgetType.WEATHER -> WeatherGlanceWidget().updateAll(this@AppWidgetConfigActivity)
AppWidgetType.CALCULATOR -> Unit
}
AppWidgetRefreshWorker.enqueue(this@AppWidgetConfigActivity)
val result = Intent().putExtra(
Expand Down Expand Up @@ -89,6 +91,7 @@ class AppWidgetConfigActivity : ComponentActivity() {
HeadlinesGlanceReceiver::class.java.name -> AppWidgetType.HEADLINES
BlocksGlanceReceiver::class.java.name -> AppWidgetType.BLOCKS
WeatherGlanceReceiver::class.java.name -> AppWidgetType.WEATHER
CalculatorGlanceReceiver::class.java.name -> AppWidgetType.CALCULATOR
else -> {
Logger.warn(
"Encountered unknown provider class '$providerClass' " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ fun AppWidgetConfigScreen(

AppWidgetType.FACTS -> Unit

AppWidgetType.CALCULATOR -> Unit

AppWidgetType.WEATHER -> WeatherConfigContent(
state = state,
onSelectOption = { viewModel.selectWeatherOption(it) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ class AppWidgetConfigViewModel @Inject constructor(
AppWidgetType.BLOCKS -> it.copy(blocksPreferences = BlocksPreferences())
AppWidgetType.FACTS -> it
AppWidgetType.WEATHER -> it.copy(weatherPreferences = WeatherPreferences())
AppWidgetType.CALCULATOR -> it
}
}
}
Expand All @@ -184,6 +185,7 @@ class AppWidgetConfigViewModel @Inject constructor(
AppWidgetType.BLOCKS -> saveBlocks(state)
AppWidgetType.FACTS -> Unit
AppWidgetType.WEATHER -> saveWeather(state)
AppWidgetType.CALCULATOR -> Unit
}

onComplete()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum class AppWidgetType {
BLOCKS,
FACTS,
WEATHER,
CALCULATOR,
}

@Stable
Expand Down
Loading
Loading