Loading src/com/android/customization/module/ThemePickerInjector.kt +2 −4 Original line number Diff line number Diff line Loading @@ -318,7 +318,6 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject secureSettingsRepository = getSecureSettingsRepository(context), registry = clockRegistry, scope = GlobalScope, backgroundDispatcher = Dispatchers.IO, ), ) .also { clockPickerInteractor = it } Loading @@ -339,9 +338,8 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject clockRegistry: ClockRegistry ): ClockCarouselViewModel { return clockCarouselViewModel ?: ClockCarouselViewModel(getClockPickerInteractor(context, clockRegistry)).also { clockCarouselViewModel = it } ?: ClockCarouselViewModel(getClockPickerInteractor(context, clockRegistry)) .also { clockCarouselViewModel = it } } override fun getClockViewFactory( Loading src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.Flow * clocks. */ interface ClockPickerRepository { val allClocks: Array<ClockMetadataModel> val allClocks: Flow<List<ClockMetadataModel>> val selectedClock: Flow<ClockMetadataModel> Loading src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt +46 −32 Original line number Diff line number Diff line Loading @@ -17,64 +17,84 @@ package com.android.customization.picker.clock.data.repository import android.provider.Settings import android.util.Log import com.android.customization.picker.clock.shared.ClockSize import com.android.customization.picker.clock.shared.model.ClockMetadataModel import com.android.systemui.plugins.ClockMetadata import com.android.systemui.shared.clocks.ClockRegistry import com.android.wallpaper.settings.data.repository.SecureSettingsRepository import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** Implementation of [ClockPickerRepository], using [ClockRegistry]. */ class ClockPickerRepositoryImpl( private val secureSettingsRepository: SecureSettingsRepository, private val registry: ClockRegistry, private val scope: CoroutineScope, private val backgroundDispatcher: CoroutineDispatcher, scope: CoroutineScope, ) : ClockPickerRepository { override val allClocks: Array<ClockMetadataModel> = @OptIn(ExperimentalCoroutinesApi::class) override val allClocks: Flow<List<ClockMetadataModel>> = callbackFlow { fun send() { val allClocks = registry .getClocks() .filter { "NOT_IN_USE" !in it.clockId } .map { it.toModel(null) } .toTypedArray() trySend(allClocks) } val listener = object : ClockRegistry.ClockChangeListener { override fun onAvailableClocksChanged() { send() } } registry.registerClockChangeListener(listener) send() awaitClose { registry.unregisterClockChangeListener(listener) } } .mapLatest { allClocks -> // Loading list of clock plugins can cause many consecutive calls of // onAvailableClocksChanged(). We only care about the final fully-initiated clock // list. Delay to avoid unnecessary too many emits. delay(100) allClocks } /** The currently-selected clock. */ override val selectedClock: Flow<ClockMetadataModel> = callbackFlow { suspend fun send() { val currentClockId = withContext(backgroundDispatcher) { registry.currentClockId } fun send() { val currentClockId = registry.currentClockId // It is possible that the model can be null since the full clock list is not // initiated. val model = registry .getClocks() .find { clockMetadata -> clockMetadata.clockId == currentClockId } ?.toModel(registry.seedColor) if (model == null) { Log.w( TAG, "Clock with ID \"$currentClockId\" not found!", ) } trySend(model) } val listener = object : ClockRegistry.ClockChangeListener { override fun onCurrentClockChanged() { scope.launch { send() } send() } override fun onAvailableClocksChanged() { send() } } registry.registerClockChangeListener(listener) Loading Loading @@ -105,19 +125,13 @@ class ClockPickerRepositoryImpl( ) override suspend fun setClockSize(size: ClockSize) { withContext(backgroundDispatcher) { secureSettingsRepository.set( name = Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, value = if (size == ClockSize.DYNAMIC) 1 else 0, ) } } private fun ClockMetadata.toModel(color: Int?): ClockMetadataModel { return ClockMetadataModel(clockId = clockId, name = name, color = color) } companion object { private const val TAG = "ClockPickerRepositoryImpl" } } src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt +2 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,8 @@ import kotlinx.coroutines.flow.map * clocks. */ class ClockPickerInteractor(private val repository: ClockPickerRepository) { val allClocks: Array<ClockMetadataModel> = repository.allClocks val allClocks: Flow<List<ClockMetadataModel>> = repository.allClocks val selectedClock: Flow<ClockMetadataModel> = repository.selectedClock Loading src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt +15 −6 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.customization.picker.clock.ui.view.ClockCarouselView import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch object ClockCarouselViewBinder { Loading @@ -42,14 +43,22 @@ object ClockCarouselViewBinder { clockViewFactory: (clockId: String) -> View, lifecycleOwner: LifecycleOwner, ): Binding { view.setUpImageCarouselView( clockIds = viewModel.allClockIds, onGetClockPreview = clockViewFactory, onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) } ) lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { viewModel.selectedClockId.collect { view.setSelectedClockId(it) } } launch { viewModel.allClockIds.collect { allClockIds -> view.setUpClockCarouselView( clockIds = allClockIds, onGetClockPreview = clockViewFactory, onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) }, ) } } launch { viewModel.selectedIndex.collect { selectedIndex -> view.setSelectedClockIndex(selectedIndex) } } } } return object : Binding { Loading Loading
src/com/android/customization/module/ThemePickerInjector.kt +2 −4 Original line number Diff line number Diff line Loading @@ -318,7 +318,6 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject secureSettingsRepository = getSecureSettingsRepository(context), registry = clockRegistry, scope = GlobalScope, backgroundDispatcher = Dispatchers.IO, ), ) .also { clockPickerInteractor = it } Loading @@ -339,9 +338,8 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject clockRegistry: ClockRegistry ): ClockCarouselViewModel { return clockCarouselViewModel ?: ClockCarouselViewModel(getClockPickerInteractor(context, clockRegistry)).also { clockCarouselViewModel = it } ?: ClockCarouselViewModel(getClockPickerInteractor(context, clockRegistry)) .also { clockCarouselViewModel = it } } override fun getClockViewFactory( Loading
src/com/android/customization/picker/clock/data/repository/ClockPickerRepository.kt +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.Flow * clocks. */ interface ClockPickerRepository { val allClocks: Array<ClockMetadataModel> val allClocks: Flow<List<ClockMetadataModel>> val selectedClock: Flow<ClockMetadataModel> Loading
src/com/android/customization/picker/clock/data/repository/ClockPickerRepositoryImpl.kt +46 −32 Original line number Diff line number Diff line Loading @@ -17,64 +17,84 @@ package com.android.customization.picker.clock.data.repository import android.provider.Settings import android.util.Log import com.android.customization.picker.clock.shared.ClockSize import com.android.customization.picker.clock.shared.model.ClockMetadataModel import com.android.systemui.plugins.ClockMetadata import com.android.systemui.shared.clocks.ClockRegistry import com.android.wallpaper.settings.data.repository.SecureSettingsRepository import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** Implementation of [ClockPickerRepository], using [ClockRegistry]. */ class ClockPickerRepositoryImpl( private val secureSettingsRepository: SecureSettingsRepository, private val registry: ClockRegistry, private val scope: CoroutineScope, private val backgroundDispatcher: CoroutineDispatcher, scope: CoroutineScope, ) : ClockPickerRepository { override val allClocks: Array<ClockMetadataModel> = @OptIn(ExperimentalCoroutinesApi::class) override val allClocks: Flow<List<ClockMetadataModel>> = callbackFlow { fun send() { val allClocks = registry .getClocks() .filter { "NOT_IN_USE" !in it.clockId } .map { it.toModel(null) } .toTypedArray() trySend(allClocks) } val listener = object : ClockRegistry.ClockChangeListener { override fun onAvailableClocksChanged() { send() } } registry.registerClockChangeListener(listener) send() awaitClose { registry.unregisterClockChangeListener(listener) } } .mapLatest { allClocks -> // Loading list of clock plugins can cause many consecutive calls of // onAvailableClocksChanged(). We only care about the final fully-initiated clock // list. Delay to avoid unnecessary too many emits. delay(100) allClocks } /** The currently-selected clock. */ override val selectedClock: Flow<ClockMetadataModel> = callbackFlow { suspend fun send() { val currentClockId = withContext(backgroundDispatcher) { registry.currentClockId } fun send() { val currentClockId = registry.currentClockId // It is possible that the model can be null since the full clock list is not // initiated. val model = registry .getClocks() .find { clockMetadata -> clockMetadata.clockId == currentClockId } ?.toModel(registry.seedColor) if (model == null) { Log.w( TAG, "Clock with ID \"$currentClockId\" not found!", ) } trySend(model) } val listener = object : ClockRegistry.ClockChangeListener { override fun onCurrentClockChanged() { scope.launch { send() } send() } override fun onAvailableClocksChanged() { send() } } registry.registerClockChangeListener(listener) Loading Loading @@ -105,19 +125,13 @@ class ClockPickerRepositoryImpl( ) override suspend fun setClockSize(size: ClockSize) { withContext(backgroundDispatcher) { secureSettingsRepository.set( name = Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, value = if (size == ClockSize.DYNAMIC) 1 else 0, ) } } private fun ClockMetadata.toModel(color: Int?): ClockMetadataModel { return ClockMetadataModel(clockId = clockId, name = name, color = color) } companion object { private const val TAG = "ClockPickerRepositoryImpl" } }
src/com/android/customization/picker/clock/domain/interactor/ClockPickerInteractor.kt +2 −1 Original line number Diff line number Diff line Loading @@ -28,7 +28,8 @@ import kotlinx.coroutines.flow.map * clocks. */ class ClockPickerInteractor(private val repository: ClockPickerRepository) { val allClocks: Array<ClockMetadataModel> = repository.allClocks val allClocks: Flow<List<ClockMetadataModel>> = repository.allClocks val selectedClock: Flow<ClockMetadataModel> = repository.selectedClock Loading
src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt +15 −6 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.customization.picker.clock.ui.view.ClockCarouselView import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch object ClockCarouselViewBinder { Loading @@ -42,14 +43,22 @@ object ClockCarouselViewBinder { clockViewFactory: (clockId: String) -> View, lifecycleOwner: LifecycleOwner, ): Binding { view.setUpImageCarouselView( clockIds = viewModel.allClockIds, onGetClockPreview = clockViewFactory, onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) } ) lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { launch { viewModel.selectedClockId.collect { view.setSelectedClockId(it) } } launch { viewModel.allClockIds.collect { allClockIds -> view.setUpClockCarouselView( clockIds = allClockIds, onGetClockPreview = clockViewFactory, onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) }, ) } } launch { viewModel.selectedIndex.collect { selectedIndex -> view.setSelectedClockIndex(selectedIndex) } } } } return object : Binding { Loading