Skip to content
Open
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
22 changes: 22 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@
android:resource="@xml/car_widget_info" />
</receiver>

<!-- Home screen widget: recent trip summary -->
<receiver
android:name=".widget.TripSummaryWidgetReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/trip_summary_widget_info" />
</receiver>

<!-- Widget configuration activity: car selection -->
<activity
android:name=".widget.CarWidgetConfigActivity"
Expand All @@ -97,6 +109,16 @@
</intent-filter>
</activity>

<!-- Widget configuration activity: car selection for trip summaries -->
<activity
android:name=".widget.TripSummaryWidgetConfigActivity"
android:exported="true"
android:theme="@style/Theme.MateDroid">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>

</application>

</manifest>
4 changes: 3 additions & 1 deletion app/src/main/java/com/matedroid/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
currentIntent = intent
if (intent.hasExtra("EXTRA_CAR_ID")) {
if (intent.hasExtra("EXTRA_CAR_ID") &&
!intent.getBooleanExtra("EXTRA_SKIP_CAR_WIDGET_UPDATE", false)
) {
CarWidgetUpdateWorker.scheduleImmediateUpdate(this)
}
enableEdgeToEdge()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ data class AppSettings(
val currencyCode: String = "EUR",
val showShortDrivesCharges: Boolean = false,
val teslamateBaseUrl: String = "",
val unitOfLength: String = "km",
val lastSelectedCarId: Int? = null
) {
val isConfigured: Boolean
Expand All @@ -76,6 +77,7 @@ class SettingsDataStore @Inject constructor(
private val currencyCodeKey = stringPreferencesKey("currency_code")
private val showShortDrivesChargesKey = booleanPreferencesKey("show_short_drives_charges")
private val teslamateBaseUrlKey = stringPreferencesKey("teslamate_base_url")
private val unitOfLengthKey = stringPreferencesKey("unit_of_length")
private val lastSelectedCarIdKey = intPreferencesKey("last_selected_car_id")
private val carImageOverridesKey = stringPreferencesKey("car_image_overrides")
private val notificationPermissionAskedKey = booleanPreferencesKey("notification_permission_asked")
Expand All @@ -95,6 +97,7 @@ class SettingsDataStore @Inject constructor(
currencyCode = preferences[currencyCodeKey] ?: "EUR",
showShortDrivesCharges = preferences[showShortDrivesChargesKey] ?: false,
teslamateBaseUrl = preferences[teslamateBaseUrlKey] ?: "",
unitOfLength = preferences[unitOfLengthKey] ?: "km",
lastSelectedCarId = preferences[lastSelectedCarIdKey]
)
}
Expand Down Expand Up @@ -194,6 +197,12 @@ class SettingsDataStore @Inject constructor(
}
}

suspend fun saveUnitOfLength(unitOfLength: String) {
context.dataStore.edit { preferences ->
preferences[unitOfLengthKey] = unitOfLength
}
}

suspend fun saveLastSelectedCarId(carId: Int) {
context.dataStore.edit { preferences ->
preferences[lastSelectedCarIdKey] = carId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ interface ChargeSummaryDao {
""")
suspend fun sumCostInRange(carId: Int, startDate: String, endDate: String): Double

@Query("""
SELECT COUNT(*) FROM charges_summary
WHERE carId = :carId
AND startDate >= :startDate AND startDate < :endDate
AND cost IS NOT NULL
""")
suspend fun countWithCostInRange(carId: Int, startDate: String, endDate: String): Int

// Average cost per kWh
@Query("""
SELECT COALESCE(SUM(cost) / NULLIF(SUM(energyAdded), 0), 0)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/matedroid/data/sync/DataSyncWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import java.util.concurrent.TimeUnit
import com.matedroid.R
import com.matedroid.data.repository.ApiResult
import com.matedroid.data.repository.TeslamateRepository
import com.matedroid.widget.TripSummaryWidgetUpdateWorker
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject

Expand Down Expand Up @@ -134,6 +135,7 @@ class DataSyncWorker @AssistedInject constructor(
log("Sync complete for all cars")
// Schedule background geocoding for location data
scheduleGeocoding()
TripSummaryWidgetUpdateWorker.scheduleImmediateUpdate(applicationContext)
Result.success()
}
} catch (e: Exception) {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/com/matedroid/ui/navigation/NavGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ fun NavGraph(
"mileage" -> Screen.Mileage(carId, exteriorColor)
"battery" -> Screen.Battery(carId, exteriorColor = exteriorColor)
"stats" -> Screen.Stats(carId, exteriorColor)
"trips" -> Screen.Trips(carId, exteriorColor)
"countries_visited" -> Screen.CountriesVisited(carId, exteriorColor)
"updates" -> Screen.Updates(carId, exteriorColor)
"sentry_history" -> Screen.SentryHistory(carId, exteriorColor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,16 +396,20 @@ class DashboardViewModel @Inject constructor(
}

/**
* Fetches global settings from the API and caches the base_url.
* Fetches global settings from the API and caches settings used offline.
* This runs silently - failures don't affect the user experience.
*/
private fun fetchAndCacheGlobalSettings() {
viewModelScope.launch {
when (val result = repository.getGlobalSettings()) {
is ApiResult.Success -> {
result.data.settings?.teslamateUrls?.baseUrl?.let { url ->
val globalSettings = result.data.settings
globalSettings?.teslamateUrls?.baseUrl?.let { url ->
settingsDataStore.saveTeslamateBaseUrl(url.trimEnd('/'))
}
globalSettings?.teslamateUnits?.unitOfLength
?.takeIf { it == "km" || it == "mi" }
?.let { settingsDataStore.saveUnitOfLength(it) }
}
is ApiResult.Error -> {
// Silent fail - this is optional functionality
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,19 @@ class SettingsViewModel @Inject constructor(
}

/**
* Fetches global settings from the API and caches the base_url.
* Fetches global settings from the API and caches settings used offline.
* This runs silently - failures don't affect the user experience.
*/
private suspend fun fetchAndCacheGlobalSettings() {
when (val result = repository.getGlobalSettings()) {
is ApiResult.Success -> {
result.data.settings?.teslamateUrls?.baseUrl?.let { url ->
val globalSettings = result.data.settings
globalSettings?.teslamateUrls?.baseUrl?.let { url ->
settingsDataStore.saveTeslamateBaseUrl(url.trimEnd('/'))
}
globalSettings?.teslamateUnits?.unitOfLength
?.takeIf { it == "km" || it == "mi" }
?.let { settingsDataStore.saveUnitOfLength(it) }
}
is ApiResult.Error -> {
// Silent fail - this is optional functionality
Expand Down
Loading