Integrate nav drawer settings for default home page (#888)

## Description
Customizing the home page (#803) and nav drawer (#886) were developed
independently, so this PR just cleans up somethings so that those two
changes work together.

This PR restores the default home page when there is no customization to
be the same as before: continue watching/next up row(s) followed by the
order of the nav drawer libraries' recently added rows.

Finally gets rid of `NavDrawerIteRepository` and related functions which
all had weird, hard to follow code.

### Related issues
Related to #803 & #886

### Testing
Emulator testing

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Ray 2026-02-12 21:19:33 -05:00 committed by GitHub
parent 17b0eef5c5
commit 7fcd66f407
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 58 additions and 153 deletions

View file

@ -1,97 +0,0 @@
package com.github.damontecres.wholphin.data
import android.content.Context
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem
import com.github.damontecres.wholphin.data.model.NavPinType
import com.github.damontecres.wholphin.services.SeerrServerRepository
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
import com.github.damontecres.wholphin.util.supportedCollectionTypes
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.first
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.liveTvApi
import org.jellyfin.sdk.api.client.extensions.userViewsApi
import org.jellyfin.sdk.model.api.CollectionType
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NavDrawerItemRepository
@Inject
constructor(
@param:ApplicationContext private val context: Context,
private val api: ApiClient,
private val serverRepository: ServerRepository,
private val serverPreferencesDao: ServerPreferencesDao,
private val seerrServerRepository: SeerrServerRepository,
) {
suspend fun getNavDrawerItems(): List<NavDrawerItem> {
val user = serverRepository.currentUser.value
val tvAccess =
serverRepository.currentUserDto.value
?.policy
?.enableLiveTvAccess ?: false
val userViews =
api.userViewsApi
.getUserViews(userId = user?.id)
.content.items
val recordingFolders =
if (tvAccess) {
api.liveTvApi
.getRecordingFolders(userId = user?.id)
.content.items
.map { it.id }
.toSet()
} else {
setOf()
}
val builtins =
if (seerrServerRepository.active.first()) {
listOf(NavDrawerItem.Favorites, NavDrawerItem.Discover)
} else {
listOf(NavDrawerItem.Favorites)
}
val libraries =
userViews
.filter { it.collectionType in supportedCollectionTypes || it.id in recordingFolders }
.map {
val destination =
if (it.id in recordingFolders) {
Destination.Recordings(it.id)
} else {
BaseItem.from(it, api).destination()
}
ServerNavDrawerItem(
itemId = it.id,
name = it.name ?: it.id.toString(),
destination = destination,
type = it.collectionType ?: CollectionType.UNKNOWN,
)
}
return builtins + libraries
}
suspend fun getFilteredNavDrawerItems(items: List<NavDrawerItem>): List<NavDrawerItem> {
val user = serverRepository.currentUser.value
val navDrawerPins =
user
?.let {
serverPreferencesDao.getNavDrawerPinnedItems(it)
}.orEmpty()
val filtered = items.filter { navDrawerPins.isPinned(it.id) }
if (items.size != filtered.size) {
// Some were filtered out, check if should include More
if (navDrawerPins.isPinned(NavDrawerItem.More.id)) {
return filtered + listOf(NavDrawerItem.More)
}
}
return filtered
}
}
fun List<NavDrawerPinnedItem>.isPinned(id: String) = (firstOrNull { it.itemId == id }?.type ?: NavPinType.PINNED) == NavPinType.PINNED

View file

@ -2,7 +2,7 @@ package com.github.damontecres.wholphin.services
import android.content.Context import android.content.Context
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomePageSettings
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
@ -12,8 +12,8 @@ import com.github.damontecres.wholphin.preferences.HomePagePreferences
import com.github.damontecres.wholphin.ui.DefaultItemFields import com.github.damontecres.wholphin.ui.DefaultItemFields
import com.github.damontecres.wholphin.ui.SlimItemFields import com.github.damontecres.wholphin.ui.SlimItemFields
import com.github.damontecres.wholphin.ui.components.getGenreImageMap import com.github.damontecres.wholphin.ui.components.getGenreImageMap
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.main.settings.Library import com.github.damontecres.wholphin.ui.main.settings.Library
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.toServerString
import com.github.damontecres.wholphin.util.GetGenresRequestHandler import com.github.damontecres.wholphin.util.GetGenresRequestHandler
import com.github.damontecres.wholphin.util.GetItemsRequestHandler import com.github.damontecres.wholphin.util.GetItemsRequestHandler
@ -64,8 +64,9 @@ class HomeSettingsService
constructor( constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val api: ApiClient, private val api: ApiClient,
private val serverRepository: ServerRepository,
private val userPreferencesService: UserPreferencesService, private val userPreferencesService: UserPreferencesService,
private val navDrawerItemRepository: NavDrawerItemRepository, private val navDrawerService: NavDrawerService,
private val latestNextUpService: LatestNextUpService, private val latestNextUpService: LatestNextUpService,
private val imageUrlService: ImageUrlService, private val imageUrlService: ImageUrlService,
private val suggestionService: SuggestionService, private val suggestionService: SuggestionService,
@ -233,7 +234,7 @@ class HomeSettingsService
} }
HomePageResolvedSettings(resolvedRows) HomePageResolvedSettings(resolvedRows)
} else { } else {
createDefault() createDefault(userId)
} }
currentSettings.update { resolvedSettings } currentSettings.update { resolvedSettings }
@ -251,25 +252,24 @@ class HomeSettingsService
/** /**
* Create a default [HomePageResolvedSettings] using the available libraries * Create a default [HomePageResolvedSettings] using the available libraries
*/ */
suspend fun createDefault(): HomePageResolvedSettings { suspend fun createDefault(userId: UUID): HomePageResolvedSettings {
Timber.v("Creating default settings") Timber.v("Creating default settings")
val navDrawerItems = navDrawerItemRepository.getNavDrawerItems() val user = serverRepository.currentUser.value?.takeIf { it.id == userId }
val libraries = val libraries =
navDrawerItems if (user != null) {
.filter { it is ServerNavDrawerItem } navDrawerService.getFilteredUserLibraries(user)
.map { } else {
it as ServerNavDrawerItem navDrawerService.getAllUserLibraries(userId)
Library(it.itemId, it.name, it.type) }
}
val prefs = val prefs =
userPreferencesService.getCurrent().appPreferences.homePagePreferences userPreferencesService.getCurrent().appPreferences.homePagePreferences
val includedIds = val includedIds =
navDrawerItemRepository libraries
.getFilteredNavDrawerItems(navDrawerItems)
.filter { it is ServerNavDrawerItem }
.mapIndexed { index, it -> .mapIndexed { index, it ->
val parentId = (it as ServerNavDrawerItem).itemId val parentId = it.itemId
val name = libraries.firstOrNull { it.itemId == parentId }?.name val name = it.name.takeIf { it.isNotNullOrBlank() }
val title = val title =
name?.let { context.getString(R.string.recently_added_in, it) } name?.let { context.getString(R.string.recently_added_in, it) }
?: context.getString(R.string.recently_added) ?: context.getString(R.string.recently_added)

View file

@ -8,6 +8,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.data.model.JellyfinUser
import com.github.damontecres.wholphin.data.model.NavPinType import com.github.damontecres.wholphin.data.model.NavPinType
import com.github.damontecres.wholphin.services.hilt.DefaultCoroutineScope import com.github.damontecres.wholphin.services.hilt.DefaultCoroutineScope
import com.github.damontecres.wholphin.ui.main.settings.Library
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
@ -26,6 +27,7 @@ import org.jellyfin.sdk.api.client.extensions.userViewsApi
import org.jellyfin.sdk.model.api.CollectionType import org.jellyfin.sdk.model.api.CollectionType
import org.jellyfin.sdk.model.api.UserDto import org.jellyfin.sdk.model.api.UserDto
import timber.log.Timber import timber.log.Timber
import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -66,6 +68,29 @@ class NavDrawerService
}.launchIn(coroutineScope) }.launchIn(coroutineScope)
} }
suspend fun getAllUserLibraries(userId: UUID): List<Library> {
val userViews =
api.userViewsApi
.getUserViews(userId = userId)
.content.items
val libraries =
userViews
.filter { it.collectionType in supportedCollectionTypes }
.map { Library(it.id, it.name ?: "", it.collectionType ?: CollectionType.UNKNOWN) }
return libraries
}
suspend fun getFilteredUserLibraries(user: JellyfinUser): List<Library> {
val pins =
serverPreferencesDao
.getNavDrawerPinnedItems(user)
.associateBy { it.itemId }
val libraries =
getAllUserLibraries(user.id)
.filterNot { pins[ServerNavDrawerItem.getId(it.itemId)]?.type == NavPinType.UNPINNED }
return libraries
}
suspend fun updateNavDrawer( suspend fun updateNavDrawer(
user: JellyfinUser, user: JellyfinUser,
userDto: UserDto, userDto: UserDto,

View file

@ -3,7 +3,6 @@ package com.github.damontecres.wholphin.ui.main
import android.content.Context import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
@ -13,11 +12,10 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.HomePageResolvedSettings import com.github.damontecres.wholphin.services.HomePageResolvedSettings
import com.github.damontecres.wholphin.services.HomeSettingsService import com.github.damontecres.wholphin.services.HomeSettingsService
import com.github.damontecres.wholphin.services.MediaReportService import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.NavDrawerService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.main.settings.Library
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.HomeRowLoadingState import com.github.damontecres.wholphin.util.HomeRowLoadingState
@ -46,8 +44,8 @@ class HomeViewModel
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
val navigationManager: NavigationManager, val navigationManager: NavigationManager,
val serverRepository: ServerRepository, val serverRepository: ServerRepository,
val navDrawerItemRepository: NavDrawerItemRepository,
val mediaReportService: MediaReportService, val mediaReportService: MediaReportService,
private val navDrawerService: NavDrawerService,
private val homeSettingsService: HomeSettingsService, private val homeSettingsService: HomeSettingsService,
private val favoriteWatchManager: FavoriteWatchManager, private val favoriteWatchManager: FavoriteWatchManager,
private val datePlayedService: DatePlayedService, private val datePlayedService: DatePlayedService,
@ -69,17 +67,8 @@ class HomeViewModel
val preferences = userPreferencesService.getCurrent() val preferences = userPreferencesService.getCurrent()
val prefs = preferences.appPreferences.homePagePreferences val prefs = preferences.appPreferences.homePagePreferences
val navDrawerItems =
navDrawerItemRepository
.getNavDrawerItems()
val libraries =
navDrawerItems
.filter { it is ServerNavDrawerItem }
.map {
it as ServerNavDrawerItem
Library(it.itemId, it.name, it.type)
}
serverRepository.currentUserDto.value?.let { userDto -> serverRepository.currentUserDto.value?.let { userDto ->
val libraries = navDrawerService.getAllUserLibraries(userDto.id)
val settings = val settings =
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY } homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
val state = state.value val state = state.value

View file

@ -7,7 +7,6 @@ import androidx.datastore.core.DataStore
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomePageSettings
@ -26,12 +25,12 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.HomePageResolvedSettings import com.github.damontecres.wholphin.services.HomePageResolvedSettings
import com.github.damontecres.wholphin.services.HomeRowConfigDisplay import com.github.damontecres.wholphin.services.HomeRowConfigDisplay
import com.github.damontecres.wholphin.services.HomeSettingsService import com.github.damontecres.wholphin.services.HomeSettingsService
import com.github.damontecres.wholphin.services.NavDrawerService
import com.github.damontecres.wholphin.services.SeerrServerRepository import com.github.damontecres.wholphin.services.SeerrServerRepository
import com.github.damontecres.wholphin.services.UnsupportedHomeSettingsVersionException import com.github.damontecres.wholphin.services.UnsupportedHomeSettingsVersionException
import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope
import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.ui.showToast
import com.github.damontecres.wholphin.util.HomeRowLoadingState import com.github.damontecres.wholphin.util.HomeRowLoadingState
import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.LoadingState
@ -68,7 +67,7 @@ class HomeSettingsViewModel
private val homeSettingsService: HomeSettingsService, private val homeSettingsService: HomeSettingsService,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val userPreferencesService: UserPreferencesService, private val userPreferencesService: UserPreferencesService,
private val navDrawerItemRepository: NavDrawerItemRepository, private val navDrawerService: NavDrawerService,
private val backdropService: BackdropService, private val backdropService: BackdropService,
private val seerrServerRepository: SeerrServerRepository, private val seerrServerRepository: SeerrServerRepository,
val preferencesDataStore: DataStore<AppPreferences>, val preferencesDataStore: DataStore<AppPreferences>,
@ -84,16 +83,8 @@ class HomeSettingsViewModel
init { init {
addCloseable { saveToLocal() } addCloseable { saveToLocal() }
viewModelScope.launchIO { viewModelScope.launchIO {
val navDrawerItems = val userId = serverRepository.currentUser.value?.id ?: return@launchIO
navDrawerItemRepository val libraries = navDrawerService.getAllUserLibraries(userId)
.getNavDrawerItems()
val libraries =
navDrawerItems
.filter { it is ServerNavDrawerItem }
.map {
it as ServerNavDrawerItem
Library(it.itemId, it.name, it.type)
}
val currentSettings = val currentSettings =
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY } homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
Timber.v("currentSettings=%s", currentSettings) Timber.v("currentSettings=%s", currentSettings)
@ -525,8 +516,9 @@ class HomeSettingsViewModel
fun resetToDefault() { fun resetToDefault() {
viewModelScope.launchIO { viewModelScope.launchIO {
val userId = serverRepository.currentUser.value?.id ?: return@launchIO
_state.update { it.copy(loading = LoadingState.Loading) } _state.update { it.copy(loading = LoadingState.Loading) }
val result = homeSettingsService.createDefault() val result = homeSettingsService.createDefault(userId)
_state.update { _state.update {
it.copy(rows = result.rows) it.copy(rows = result.rows)
} }

View file

@ -65,7 +65,6 @@ import androidx.tv.material3.ProvideTextStyle
import androidx.tv.material3.Text import androidx.tv.material3.Text
import androidx.tv.material3.surfaceColorAtElevation import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.model.JellyfinServer import com.github.damontecres.wholphin.data.model.JellyfinServer
import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.data.model.JellyfinUser
import com.github.damontecres.wholphin.preferences.AppThemeColors import com.github.damontecres.wholphin.preferences.AppThemeColors
@ -73,7 +72,6 @@ import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.NavDrawerService import com.github.damontecres.wholphin.services.NavDrawerService
import com.github.damontecres.wholphin.services.NavigationManager import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SeerrServerRepository
import com.github.damontecres.wholphin.services.SetupDestination import com.github.damontecres.wholphin.services.SetupDestination
import com.github.damontecres.wholphin.services.SetupNavigationManager import com.github.damontecres.wholphin.services.SetupNavigationManager
import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.FontAwesome
@ -98,11 +96,9 @@ class NavDrawerViewModel
constructor( constructor(
private val api: ApiClient, private val api: ApiClient,
private val navDrawerService: NavDrawerService, private val navDrawerService: NavDrawerService,
private val navDrawerItemRepository: NavDrawerItemRepository,
val navigationManager: NavigationManager, val navigationManager: NavigationManager,
val setupNavigationManager: SetupNavigationManager, val setupNavigationManager: SetupNavigationManager,
val backdropService: BackdropService, val backdropService: BackdropService,
private val seerrServerRepository: SeerrServerRepository,
) : ViewModel() { ) : ViewModel() {
val state = navDrawerService.state val state = navDrawerService.state
@ -184,9 +180,13 @@ data class ServerNavDrawerItem(
val destination: Destination, val destination: Destination,
val type: CollectionType, val type: CollectionType,
) : NavDrawerItem { ) : NavDrawerItem {
override val id: String = "s_" + itemId.toServerString() override val id: String = getId(itemId)
override fun name(context: Context): String = name override fun name(context: Context): String = name
companion object {
fun getId(itemId: UUID) = "s_" + itemId.toServerString()
}
} }
/** /**

View file

@ -5,7 +5,6 @@ import androidx.datastore.core.DataStore
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.asFlow import androidx.lifecycle.asFlow
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.ServerPreferencesDao import com.github.damontecres.wholphin.data.ServerPreferencesDao
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.JellyfinUser import com.github.damontecres.wholphin.data.model.JellyfinUser
@ -50,7 +49,6 @@ class PreferencesViewModel
val backdropService: BackdropService, val backdropService: BackdropService,
private val rememberTabManager: RememberTabManager, private val rememberTabManager: RememberTabManager,
private val serverRepository: ServerRepository, private val serverRepository: ServerRepository,
private val navDrawerItemRepository: NavDrawerItemRepository,
private val navDrawerService: NavDrawerService, private val navDrawerService: NavDrawerService,
private val serverPreferencesDao: ServerPreferencesDao, private val serverPreferencesDao: ServerPreferencesDao,
private val seerrServerRepository: SeerrServerRepository, private val seerrServerRepository: SeerrServerRepository,
@ -58,9 +56,6 @@ class PreferencesViewModel
private val clientInfo: ClientInfo, private val clientInfo: ClientInfo,
) : ViewModel(), ) : ViewModel(),
RememberTabManager by rememberTabManager { RememberTabManager by rememberTabManager {
private lateinit var allNavDrawerItems: List<NavDrawerItem>
// val navDrawerPins = MutableLiveData<List<NavDrawerPin>>(emptyList())
val navDrawerPins = val navDrawerPins =
navDrawerService.state navDrawerService.state
.combine( .combine(

View file

@ -121,8 +121,9 @@ class TestHomeRowSamples {
HomeSettingsService( HomeSettingsService(
context = mockk(), context = mockk(),
api = mockk(), api = mockk(),
serverRepository = mockk(),
userPreferencesService = mockk(), userPreferencesService = mockk(),
navDrawerItemRepository = mockk(), navDrawerService = mockk(),
latestNextUpService = mockk(), latestNextUpService = mockk(),
imageUrlService = mockk(), imageUrlService = mockk(),
suggestionService = mockk(), suggestionService = mockk(),