Search code examples
androidwidgetandroid-jetpack-composeglance

Display data from database (room) in widget (glance) using jetpack compose?


While developing my note-taking app and as a new feature I wanna create a widget for my app by jetpack lib glance.

At first, I thought it would be like a normal database implementation, but it didn't work, And I have no idea how it does, even when I made some searches I get only network and API stuff.

But in my case, I wanted the local data.

And here are my classes.

@HiltViewModel
class AppWidgetVM @Inject constructor(
    private val repo: EntityRepoImp
): ViewModel() {
    private val _allNotesById = MutableStateFlow<List<Entity>>(emptyList())
    val allNotesById: StateFlow<List<Entity>>
        get() = _allNotesById.stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(),
            initialValue = listOf()
        )
    init {
        viewModelScope.launch(Dispatchers.IO) {
            repo.getAllNotesById.collect {
                _allNotesById.value = it
            }
        }
    }
}
@AndroidEntryPoint
class AppWidgetReceiver: GlanceAppWidgetReceiver() {
    override val glanceAppWidget: GlanceAppWidget = AppWidget()
}
class AppWidget: GlanceAppWidget() {

    @Composable
    override fun Content() {

      ...

    }
}

I know its looks like empty code, But like I said I have no idea how it does.

The variable allNotesById holds all my local notes, And that is exactly what I want to display in AppWidget class.


Solution

  • So after a long search in public similar apps for my app and depending on favorite-apps-widget project. I finally ended with this solution:

    GlanceAppWidget

    class AppWidget:GlanceAppWidget() {
    
        @Composable
        override fun Content() {
    
            val ctx = LocalContext.current.applicationContext
    
            val viewModel = EntryPoints.get(
                ctx,
                EntryPoint::class.java
            ).vm()
    
            WidgetListNotes(ctx = ctx, widgetVm = viewModel)
        }
    
        @Composable
        fun WidgetListNotes(
            ctx: Context,
            widgetVm: WidgetVM
        ) {
             ...
        }
    }
    

    EntryPoint

    @EntryPoint
    @InstallIn(SingletonComponent::class)
    interface EntryPoint {
    
        fun vm(): WidgetVM
    }
    

    GlanceAppWidgetReceiver

    @AndroidEntryPoint
    class WidgetReceiver:GlanceAppWidgetReceiver() {
        override val glanceAppWidget: GlanceAppWidget
            get() = AppWidget()
    
         override fun onReceive(context: Context, intent: Intent) {
            ...
         }
    
    

    WidgetViewModel

    class WidgetVM @Inject constructor(
        private val widgetEntityRepoImpl: WidgetEntityRepoImpl
    ) {
    
        @WorkerThread
        fun getAllEntities() = widgetEntityRepoImpl.getAllWidgetEntityById
    
        ...
    }
    

    In MainActivity I decided to update the widget data every pause in the application, you can do it in another place.

    ...
        override fun onPause() {
            super.onPause()
            WidgetReceiver.updateBroadcast(this)
        }
    ...
    

    Screenshot.

    enter image description here

    For the rest of the code check my project JetNote.