Skip to content

Commit

Permalink
refactor: clean up widgets and restore functionality
Browse files Browse the repository at this point in the history
Picks refactoring work over the rewrite branch
  • Loading branch information
kelsos committed Jan 2, 2025
1 parent a51f165 commit ec41973
Show file tree
Hide file tree
Showing 18 changed files with 492 additions and 525 deletions.
19 changes: 13 additions & 6 deletions app/src/main/java/com/kelsos/mbrc/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import android.net.wifi.WifiManager
import androidx.annotation.CallSuper
import androidx.core.content.getSystemService
import androidx.preference.PreferenceManager
import coil3.ImageLoader
import coil3.SingletonImageLoader
import coil3.request.crossfade
import coil3.util.DebugLogger
import com.kelsos.mbrc.common.utilities.CustomLoggingTree
import com.raizlabs.android.dbflow.config.FlowConfig
import com.raizlabs.android.dbflow.config.FlowManager
import org.koin.android.ext.koin.androidContext
Expand All @@ -23,6 +28,13 @@ open class App : Application() {
@CallSuper
override fun onCreate() {
super.onCreate()
SingletonImageLoader.setSafe { context ->

Check warning on line 31 in app/src/main/java/com/kelsos/mbrc/App.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/App.kt#L30-L31

Added lines #L30 - L31 were not covered by tests
ImageLoader
.Builder(context)
.crossfade(true)
.logger(DebugLogger())
.build()

Check warning on line 36 in app/src/main/java/com/kelsos/mbrc/App.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/App.kt#L33-L36

Added lines #L33 - L36 were not covered by tests
}
initialize()

Check warning on line 38 in app/src/main/java/com/kelsos/mbrc/App.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/App.kt#L38

Added line #L38 was not covered by tests
}

Expand Down Expand Up @@ -60,12 +72,7 @@ open class App : Application() {

private fun initializeTimber() {
if (BuildConfig.DEBUG) {
Timber.plant(
object : Timber.DebugTree() {
override fun createStackElementTag(element: StackTraceElement): String =
"${super.createStackElementTag(element)}:${element.lineNumber} [${Thread.currentThread().name}]"
},
)
Timber.plant(CustomLoggingTree.create())

Check warning on line 75 in app/src/main/java/com/kelsos/mbrc/App.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/App.kt#L75

Added line #L75 was not covered by tests
}
}
}
4 changes: 4 additions & 0 deletions app/src/main/java/com/kelsos/mbrc/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ import com.kelsos.mbrc.features.settings.ConnectionRepository
import com.kelsos.mbrc.features.settings.ConnectionRepositoryImpl
import com.kelsos.mbrc.features.settings.SettingsManager
import com.kelsos.mbrc.features.settings.SettingsManagerImpl
import com.kelsos.mbrc.features.widgets.WidgetUpdater
import com.kelsos.mbrc.features.widgets.WidgetUpdaterImpl
import com.kelsos.mbrc.networking.ApiBase
import com.kelsos.mbrc.networking.RequestManager
import com.kelsos.mbrc.networking.RequestManagerImpl
Expand Down Expand Up @@ -274,6 +276,8 @@ val appModule =
factoryOf(::HandleHandshake)
factoryOf(::TerminateServiceCommand)

Check warning on line 277 in app/src/main/java/com/kelsos/mbrc/AppModule.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/AppModule.kt#L239-L277

Added lines #L239 - L277 were not covered by tests

singleOf(::WidgetUpdaterImpl) { bind<WidgetUpdater>() }

Check warning on line 279 in app/src/main/java/com/kelsos/mbrc/AppModule.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/AppModule.kt#L279

Added line #L279 was not covered by tests

single<Scheduler>(named("main")) { AndroidSchedulers.mainThread() }
single<Scheduler>(named("io")) { Schedulers.io() }

Check warning on line 282 in app/src/main/java/com/kelsos/mbrc/AppModule.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/AppModule.kt#L281-L282

Added lines #L281 - L282 were not covered by tests

Expand Down
6 changes: 1 addition & 5 deletions app/src/main/java/com/kelsos/mbrc/BaseActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,7 @@ abstract class BaseActivity :
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START)
} else {
if (this@BaseActivity is PlayerActivity) {
finish()
} else {
onBackPressedDispatcher.onBackPressed()
}
finish()
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.kelsos.mbrc.common.utilities

import timber.log.Timber

class CustomLoggingTree : Timber.DebugTree() {

Check warning on line 5 in app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt#L5

Added line #L5 was not covered by tests
override fun createStackElementTag(element: StackTraceElement): String =
with(element) {
val thread = with(Thread.currentThread()) { name }
val createStackElementTag = super.createStackElementTag(element)

Check warning on line 9 in app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt#L7-L9

Added lines #L7 - L9 were not covered by tests
val className = createStackElementTag?.split("$")?.get(0)
"($className.kt:$lineNumber)#$methodName {$thread}"

Check warning on line 11 in app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt#L11

Added line #L11 was not covered by tests
}

companion object {
fun create(): CustomLoggingTree = CustomLoggingTree()

Check warning on line 15 in app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/common/utilities/CustomLoggingTree.kt#L15

Added line #L15 was not covered by tests
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/kelsos/mbrc/common/utilities/Helpers.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.kelsos.mbrc.common.utilities

inline fun <T1 : Any, T2 : Any, R : Any> whenNotNull(
p1: T1?,
p2: T2?,
block: (T1, T2) -> R?,
): R? = if (p1 != null && p2 != null) block(p1, p2) else null
35 changes: 35 additions & 0 deletions app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.kelsos.mbrc.features.widgets

import android.os.Bundle
import androidx.core.os.BundleCompat
import com.kelsos.mbrc.annotations.PlayerState
import com.kelsos.mbrc.features.player.TrackInfo

class BundleData(
private val bundle: Bundle,

Check warning on line 9 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L8-L9

Added lines #L8 - L9 were not covered by tests
) {
fun isState() = bundle.getBoolean(WidgetUpdater.STATE, false)

Check warning on line 11 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L11

Added line #L11 was not covered by tests

fun isInfo() = bundle.getBoolean(WidgetUpdater.INFO, false)

Check warning on line 13 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L13

Added line #L13 was not covered by tests

fun isCover() = bundle.getBoolean(WidgetUpdater.COVER, false)

Check warning on line 15 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L15

Added line #L15 was not covered by tests

fun cover(): String = bundle.getString(WidgetUpdater.COVER_PATH, "")

Check warning on line 17 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L17

Added line #L17 was not covered by tests

fun state(): String = bundle.getString(WidgetUpdater.PLAYER_STATE, PlayerState.UNDEFINED)

Check warning on line 19 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L19

Added line #L19 was not covered by tests

fun playingTrack(): TrackInfo =
BundleCompat.getParcelable(
bundle,
WidgetUpdater.TRACK_INFO,
TrackInfo::class.java,
) ?: TrackInfo()

Check warning on line 26 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L23-L26

Added lines #L23 - L26 were not covered by tests

override fun toString(): String =
when {

Check warning on line 29 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L29

Added line #L29 was not covered by tests
this.isState() -> "State: ${this.state()}"
this.isInfo() -> "Info: ${this.playingTrack()}"
this.isCover() -> "Cover: ${this.cover()}"
else -> "Unknown"

Check warning on line 33 in app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/BundleData.kt#L33

Added line #L33 was not covered by tests
}
}
167 changes: 167 additions & 0 deletions app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package com.kelsos.mbrc.features.widgets

import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.RemoteViews
import coil3.imageLoader
import coil3.request.ImageRequest
import coil3.size.Precision
import coil3.size.Scale
import com.kelsos.mbrc.R
import com.kelsos.mbrc.annotations.PlayerState
import com.kelsos.mbrc.common.utilities.whenNotNull
import com.kelsos.mbrc.features.player.PlayerActivity
import com.kelsos.mbrc.features.player.TrackInfo
import timber.log.Timber
import java.io.File

abstract class WidgetBase : AppWidgetProvider() {
abstract val config: WidgetConfig
abstract val type: String

override fun onReceive(
context: Context?,
intent: Intent?,
) {
super.onReceive(context, intent)

Check warning on line 31 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L31

Added line #L31 was not covered by tests
if (intent?.action == AppWidgetManager.ACTION_APPWIDGET_UPDATE) {
whenNotNull(context, intent.extras, this::updateWidget)

Check warning on line 33 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L33

Added line #L33 was not covered by tests
}
}

private fun updateWidget(
context: Context,
extras: Bundle,
) {
val widgetManager = AppWidgetManager.getInstance(context)
val widgets = ComponentName(context.packageName, config.widgetClass.java.name)
val widgetsIds = widgetManager.getAppWidgetIds(widgets)
val data = BundleData(extras)

Check warning on line 44 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L41-L44

Added lines #L41 - L44 were not covered by tests

if (widgetsIds.isEmpty()) {
Timber.v("No $type widgets found for update")

Check warning on line 47 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L47

Added line #L47 was not covered by tests
return
}

Timber.v("Updating $type widgets ${widgetsIds.joinToString(", ")} with extras: $data")

Check warning on line 51 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L51

Added line #L51 was not covered by tests

when {

Check warning on line 53 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L53

Added line #L53 was not covered by tests
data.isCover() -> {
updateCover(context, widgetManager, widgetsIds, data.cover())

Check warning on line 55 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L55

Added line #L55 was not covered by tests
}
data.isInfo() ->
updateInfo(
context,
widgetManager,
widgetsIds,
data.playingTrack(),

Check warning on line 62 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L58-L62

Added lines #L58 - L62 were not covered by tests
)
data.isState() ->
updatePlayState(
context,
widgetManager,
widgetsIds,
data.state(),

Check warning on line 69 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L65-L69

Added lines #L65 - L69 were not covered by tests
)
}
}

override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
super.onUpdate(context, appWidgetManager, appWidgetIds)

Check warning on line 79 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L79

Added line #L79 was not covered by tests

if (!appWidgetIds.isEmpty()) {
Timber.v("onUpdate called for $type widgets: ${appWidgetIds.joinToString(", ")}")

Check warning on line 82 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L82

Added line #L82 was not covered by tests
}

for (appWidgetId in appWidgetIds) {
val intent = Intent(context, PlayerActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_IMMUTABLE,

Check warning on line 92 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L86-L92

Added lines #L86 - L92 were not covered by tests
)
val views = RemoteViews(context.packageName, config.layout)
setupActionIntents(views, pendingIntent, context)

Check warning on line 95 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L94-L95

Added lines #L94 - L95 were not covered by tests
// Tell the AppWidgetManager to perform an set on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views)

Check warning on line 97 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L97

Added line #L97 was not covered by tests
}
}

abstract fun setupActionIntents(
views: RemoteViews,
pendingIntent: PendingIntent,
context: Context,
)

abstract fun setupTrackInfo(
views: RemoteViews,
info: TrackInfo,
)

private fun updateInfo(
context: Context,
widgetManager: AppWidgetManager,
widgetsIds: IntArray,
info: TrackInfo,
) {
val views = RemoteViews(context.packageName, config.layout)
setupTrackInfo(views, info)
widgetManager.updateAppWidget(widgetsIds, views)

Check warning on line 120 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L118-L120

Added lines #L118 - L120 were not covered by tests
}

private fun updateCover(
context: Context,
widgetManager: AppWidgetManager,
widgetsIds: IntArray,
path: String,
) {
val widget = RemoteViews(context.packageName, config.layout)
val coverFile = File(path)

Check warning on line 130 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L129-L130

Added lines #L129 - L130 were not covered by tests
if (coverFile.exists()) {
val request =

Check warning on line 132 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L132

Added line #L132 was not covered by tests
ImageRequest
.Builder(context)
.data(coverFile)
.size(R.dimen.widget_small_height)
.scale(Scale.FILL)
.precision(Precision.INEXACT)
.target(RemoteViewsTarget(widgetManager, widget, widgetsIds, config.imageId))
.build()

Check warning on line 140 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L134-L140

Added lines #L134 - L140 were not covered by tests

context.imageLoader.enqueue(request)

Check warning on line 142 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L142

Added line #L142 was not covered by tests
} else {
widget.setImageViewResource(config.imageId, R.drawable.ic_image_no_cover)
widgetManager.updateAppWidget(widgetsIds, widget)

Check warning on line 145 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L144-L145

Added lines #L144 - L145 were not covered by tests
}
}

private fun updatePlayState(
context: Context,
manager: AppWidgetManager,
widgetsIds: IntArray,
state: String,
) {
val widget = RemoteViews(context.packageName, config.layout)

Check warning on line 155 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L155

Added line #L155 was not covered by tests

widget.setImageViewResource(
config.playButtonId,

Check warning on line 158 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L157-L158

Added lines #L157 - L158 were not covered by tests
if (PlayerState.PLAYING == state) {
R.drawable.ic_action_pause

Check warning on line 160 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L160

Added line #L160 was not covered by tests
} else {
R.drawable.ic_action_play

Check warning on line 162 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L162

Added line #L162 was not covered by tests
},
)
manager.updateAppWidget(widgetsIds, widget)

Check warning on line 165 in app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt

View check run for this annotation

Codecov / codecov/patch

app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetBase.kt#L165

Added line #L165 was not covered by tests
}
}
18 changes: 18 additions & 0 deletions app/src/main/java/com/kelsos/mbrc/features/widgets/WidgetConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.kelsos.mbrc.features.widgets

import androidx.annotation.DimenRes
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import kotlin.reflect.KClass

data class WidgetConfig(
@LayoutRes
val layout: Int,
@DimenRes
val imageSize: Int,
@IdRes
val imageId: Int,
@IdRes
val playButtonId: Int,
val widgetClass: KClass<out WidgetBase>,
)
Loading

0 comments on commit ec41973

Please sign in to comment.