Initial release: Claude Pro usage widget for Android
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
package me.khodak.claudeusage
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.SystemClock
|
||||
import androidx.work.*
|
||||
import me.khodak.claudeusage.data.PreferencesManager
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class UsageUpdateWorker(
|
||||
private val context: Context,
|
||||
workerParams: WorkerParameters
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val prefs = PreferencesManager(context)
|
||||
if (!prefs.isLoggedIn()) return Result.success()
|
||||
|
||||
prefs.markTodayActive()
|
||||
|
||||
// Try API — save result (even on failure, local data is preserved)
|
||||
try {
|
||||
val data = UsageRepository(prefs).fetchUsage()
|
||||
prefs.saveUsageData(data)
|
||||
} catch (_: Exception) {
|
||||
// API failed — don't save, keep existing cached data
|
||||
}
|
||||
|
||||
// Always push widget update using latest prefs + cached api data
|
||||
pushWidgetUpdate()
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun pushWidgetUpdate() {
|
||||
ClaudeUsageWidget.isRefreshing = false
|
||||
val manager = AppWidgetManager.getInstance(context)
|
||||
val ids = manager.getAppWidgetIds(ComponentName(context, ClaudeUsageWidget::class.java))
|
||||
ids.forEach { id -> ClaudeUsageWidget.updateWidget(context, manager, id) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val WORK_ONE_SHOT = "claude_oneshot"
|
||||
private const val ALARM_CODE = 1001
|
||||
private const val INTERVAL_MS = 5 * 60 * 1000L
|
||||
|
||||
fun schedulePeriodicRefresh(context: Context) {
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
am.setAndAllowWhileIdle(
|
||||
AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + INTERVAL_MS,
|
||||
alarmIntent(context)
|
||||
)
|
||||
}
|
||||
|
||||
fun cancelPeriodicRefresh(context: Context) =
|
||||
(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager)
|
||||
.cancel(alarmIntent(context))
|
||||
|
||||
fun triggerImmediateRefresh(context: Context) {
|
||||
WorkManager.getInstance(context).enqueueUniqueWork(
|
||||
WORK_ONE_SHOT,
|
||||
ExistingWorkPolicy.REPLACE,
|
||||
OneTimeWorkRequestBuilder<UsageUpdateWorker>().build()
|
||||
)
|
||||
}
|
||||
|
||||
private fun alarmIntent(context: Context) = PendingIntent.getBroadcast(
|
||||
context, ALARM_CODE,
|
||||
Intent(context, AlarmReceiver::class.java),
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user