diff --git a/app/config/detekt/baseline.xml b/app/config/detekt/baseline.xml
index 11e4674..1f21eee 100644
--- a/app/config/detekt/baseline.xml
+++ b/app/config/detekt/baseline.xml
@@ -6,9 +6,12 @@
CyclomaticComplexMethod:ControlScreen.kt$@Composable fun ControlScreen( windowSizeClass: WindowSizeClass, viewModel: ControlViewModel, onNavigateUp: () -> Unit )
EmptyFunctionBlock:ItemAudio.kt$<no name provided>${ }
EmptyFunctionBlock:ItemDisplay.kt$<no name provided>${ }
+ ForbiddenComment:FiioKa13UsbRepository.kt$FiioKa13UsbRepository$// FIXME: Reading current state is not working properly (firmware issue?)
+ ForbiddenComment:FiioKa13UsbRepository.kt$FiioKa13UsbRepository$// TODO: Is it actually working?
LargeClass:FiioKa5UsbRepository.kt$FiioKa5UsbRepository : UsbRepository
LongMethod:ControlScreen.kt$@Composable fun ControlScreen( modifier: Modifier = Modifier, windowSizeClass: WindowSizeClass = WindowSizeClass.calculateFromSize(DpSize.Zero), scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(), profileListState: LazyStaggeredGridState = rememberLazyStaggeredGridState(), snackBarHostState: SnackbarHostState = remember { SnackbarHostState() }, profiles: LazyPagingItems<Profile> = UnsupportedUsbDongle.profileFlow().collectAsLazyPagingItems(), usbDongle: UsbDongle = UnsupportedUsbDongle, isLoading: Boolean = false, onRefresh: () -> Unit = {}, onReset: () -> Unit = {}, onProfileShortcutAdd: (Profile) -> Unit = {}, onProfileShortcutRemove: (Profile) -> Unit = {}, onProfileDelete: (Profile) -> Unit = { _ -> }, onProfileApply: (Profile) -> Unit = { _ -> }, onProfileExport: (String) -> Unit = { _ -> }, onChannelBalanceSelected: (Int) -> Unit = { _ -> }, onDacModeSelected: (Byte) -> Unit = { _ -> }, onDisplayBrightnessSelected: (Int) -> Unit = { _ -> }, onDisplayTimeoutSelected: (Int) -> Unit = { _ -> }, onDisplayInvertChange: (Boolean) -> Unit = { _ -> }, onFilterSelected: (Byte) -> Unit = { _ -> }, onGainSelected: (Byte) -> Unit = { _ -> }, onHardwareMuteEnabledSelected: (Boolean) -> Unit = { _ -> }, onHidModeSelected: (Byte) -> Unit = { _ -> }, onIndicatorStateSelected: (Byte) -> Unit = { _ -> }, onSpdifOutEnabledSelected: (Boolean) -> Unit = { _ -> }, onVolumeLevelSelected: (Int) -> Unit = { _ -> }, onVolumeModeSelected: (Byte) -> Unit = { _ -> } )
LongMethod:ControlScreen.kt$@Composable fun ControlScreen( windowSizeClass: WindowSizeClass, viewModel: ControlViewModel, onNavigateUp: () -> Unit )
+ LongMethod:FiioKa13UsbRepository.kt$FiioKa13UsbRepository$suspend fun setVolumeLevel(fiioKa13: FiioKa13, volumeLevel: VolumeLevel): Result<FiioKa13>
LongMethod:FiioKa5Items.kt$@Composable fun FiioKa5Items( modifier: Modifier = Modifier, fiioKa5: FiioKa5 = FiioKa5(), onChannelBalanceSelected: (Int) -> Unit = {}, onVolumeLevelSelected: (Int) -> Unit = {}, onVolumeModeSelected: (Byte) -> Unit = {}, onDisplayBrightnessSelected: (Int) -> Unit = {}, onDisplayTimeoutSelected: (Int) -> Unit = {}, onDisplayInvertSelected: (Boolean) -> Unit = {}, onGainSelected: (Byte) -> Unit = {}, onFilterSelected: (Byte) -> Unit = {}, onSpdifOutSelected: (Boolean) -> Unit = {}, onHardwareMuteSelected: (Boolean) -> Unit = {}, onDacModeSelected: (Byte) -> Unit = {}, onHidModeSelected: (Byte) -> Unit = {} )
LongMethod:FiioKa5UsbRepository.kt$FiioKa5UsbRepository$suspend fun getCurrentState(usbDongle: FiioKa5): Result<FiioKa5>
LongMethod:FiioKa5UsbRepository.kt$FiioKa5UsbRepository$suspend fun setAll( fiioKa5: FiioKa5, channelBalance: ChannelBalance, dacMode: DacMode, displayBrightness: DisplayBrightness, displayInvert: DisplayInvert, displayTimeout: DisplayTimeout, filter: Filter, gain: Gain, hardwareMute: HardwareMute, hidMode: HidMode, spdifOut: SpdifOut, volumeLevel: VolumeLevel, volumeMode: VolumeMode ): Result<FiioKa5>
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/business/ControlViewModel.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/business/ControlViewModel.kt
index 21cc103..c684348 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/business/ControlViewModel.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/business/ControlViewModel.kt
@@ -25,7 +25,6 @@ import androidx.lifecycle.ViewModel
import androidx.paging.Pager
import androidx.paging.PagingConfig
import dagger.hilt.android.lifecycle.HiltViewModel
-import io.github.tommygeenexus.usbdonglecontrol.core.db.Profile
import io.github.tommygeenexus.usbdonglecontrol.control.data.ProfileRepository
import io.github.tommygeenexus.usbdonglecontrol.control.domain.GetCurrentStateUseCase
import io.github.tommygeenexus.usbdonglecontrol.control.domain.GetVolumeLevelUseCase
@@ -44,6 +43,7 @@ import io.github.tommygeenexus.usbdonglecontrol.control.domain.SetSpdifOutEnable
import io.github.tommygeenexus.usbdonglecontrol.control.domain.SetVolumeLevelUseCase
import io.github.tommygeenexus.usbdonglecontrol.control.domain.SetVolumeModeUseCase
import io.github.tommygeenexus.usbdonglecontrol.core.data.UsbRepository
+import io.github.tommygeenexus.usbdonglecontrol.core.db.Profile
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongle
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
import io.github.tommygeenexus.usbdonglecontrol.core.volume.HardwareVolumeControl
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetCurrentStateUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetCurrentStateUseCase.kt
index b22ae6d..ac399b0 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetCurrentStateUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetCurrentStateUseCase.kt
@@ -22,8 +22,10 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
@@ -31,11 +33,15 @@ import javax.inject.Singleton
@Singleton
class GetCurrentStateUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle): Result = when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.getCurrentState(usbDongle)
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.getCurrentState(usbDongle)
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetVolumeLevelUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetVolumeLevelUseCase.kt
index dc497ec..877ca94 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetVolumeLevelUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/GetVolumeLevelUseCase.kt
@@ -22,8 +22,10 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
@@ -31,11 +33,15 @@ import javax.inject.Singleton
@Singleton
class GetVolumeLevelUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle): Result = when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.getCurrentState(usbDongle)
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.getVolumeLevelAndMode(usbDongle)
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetDacFilterUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetDacFilterUseCase.kt
index 82697ce..cc1d878 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetDacFilterUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetDacFilterUseCase.kt
@@ -22,9 +22,12 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.Filter as FilterFiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Filter
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Filter as FilterFiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
@@ -32,22 +35,29 @@ import javax.inject.Singleton
@Singleton
class SetDacFilterUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle, id: Byte): Result =
when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.setFilter(
+ fiioKa13 = usbDongle,
+ filter = FilterFiioKa13.findByIdOrDefault(id)
+ )
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.setFilter(
fiioKa5 = usbDongle,
- filter = Filter.findByIdOrDefault(id)
+ filter = FilterFiioKa5.findByIdOrDefault(id)
)
}
is MoondropDawn -> {
moondropDawnUsbRepository.setFilter(
moondropDawn = usbDongle,
- filter = Filter.findByIdOrDefault(id)
+ filter = FilterFiioKa5.findByIdOrDefault(id)
)
}
else -> Result.failure(UnsupportedUsbDongleException())
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetIndicatorStateUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetIndicatorStateUseCase.kt
index a2b3909..5ba1bac 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetIndicatorStateUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetIndicatorStateUseCase.kt
@@ -22,23 +22,33 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.IndicatorState as IndicatorStateFiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.IndicatorState
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.IndicatorState as IndicatorStateMoondropDawn
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SetIndicatorStateUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle, id: Byte): Result =
when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.setIndicatorState(
+ fiioKa13 = usbDongle,
+ indicatorState = IndicatorStateFiioKa13.findByIdOrDefault(id)
+ )
+ }
is MoondropDawn -> {
moondropDawnUsbRepository.setIndicatorState(
moondropDawn = usbDongle,
- indicatorState = IndicatorState.findByIdOrDefault(id)
+ indicatorState = IndicatorStateMoondropDawn.findByIdOrDefault(id)
)
}
else -> Result.failure(UnsupportedUsbDongleException())
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetProfileUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetProfileUseCase.kt
index 142f0b8..599ec65 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetProfileUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetProfileUseCase.kt
@@ -23,13 +23,18 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.db.Profile
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.Filter as FilterFiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.IndicatorState as IndicatorStateFiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.VolumeLevel as VolumeLevelFiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.createFromDisplayValue
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.ChannelBalance
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.DacMode
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.DisplayBrightness
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.DisplayInvert
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.DisplayTimeout
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Filter
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Filter as FilterFiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Gain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.HardwareMute
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.HidMode
@@ -38,9 +43,10 @@ import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.Vol
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.VolumeMode
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.createFromDisplayValue
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.IndicatorState
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.VolumeLevel
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.IndicatorState as IndicatorStateMoondropDawn
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.VolumeLevel as VolumeLevelMoondropDawn
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.createFromDisplayValue
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
@@ -48,12 +54,24 @@ import javax.inject.Singleton
@Singleton
class SetProfileUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle, profile: Profile): Result =
when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.setAll(
+ fiioKa13 = usbDongle,
+ filter = FilterFiioKa13.findByIdOrDefault(profile.filterId),
+ indicatorState = IndicatorStateFiioKa13.findByIdOrDefault(
+ profile.indicatorStateId
+ ),
+ spdifOut = SpdifOut(isEnabled = profile.isSpdifOutEnabled),
+ volumeLevel = VolumeLevelFiioKa13.createFromDisplayValue(profile.volumeLevel)
+ )
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.setAll(
fiioKa5 = usbDongle,
@@ -68,7 +86,7 @@ class SetProfileUseCase @Inject constructor(
displayTimeout = DisplayTimeout.createFromDisplayValue(
profile.displayTimeout
),
- filter = Filter.findByIdOrDefault(id = profile.filterId),
+ filter = FilterFiioKa5.findByIdOrDefault(id = profile.filterId),
gain = Gain.findByIdOrDefault(id = profile.gainId),
hardwareMute = HardwareMute(isEnabled = profile.isHardwareMuteEnabled),
hidMode = HidMode.findByIdOrDefault(id = profile.hidModeId),
@@ -85,12 +103,12 @@ class SetProfileUseCase @Inject constructor(
is MoondropDawn -> {
moondropDawnUsbRepository.setAll(
moondropDawn = usbDongle,
- filter = Filter.findByIdOrDefault(id = profile.filterId),
+ filter = FilterFiioKa5.findByIdOrDefault(id = profile.filterId),
gain = Gain.findByIdOrDefault(id = profile.gainId),
- indicatorState = IndicatorState.findByIdOrDefault(
+ indicatorState = IndicatorStateMoondropDawn.findByIdOrDefault(
id = profile.indicatorStateId
),
- volumeLevel = VolumeLevel.createFromDisplayValue(
+ volumeLevel = VolumeLevelMoondropDawn.createFromDisplayValue(
displayValue = profile.volumeLevel
)
)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetSpdifOutEnabledUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetSpdifOutEnabledUseCase.kt
index 0e9f5f3..dce90bb 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetSpdifOutEnabledUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetSpdifOutEnabledUseCase.kt
@@ -22,14 +22,17 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.SpdifOut
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SetSpdifOutEnabledUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository
) {
@@ -37,6 +40,12 @@ class SetSpdifOutEnabledUseCase @Inject constructor(
usbDongle: UsbDongle,
isSpdifOutEnabled: Boolean
): Result = when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.setSpdifOut(
+ fiioKa13 = usbDongle,
+ spdifOut = SpdifOut(isEnabled = isSpdifOutEnabled)
+ )
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.setSpdifOut(
fiioKa5 = usbDongle,
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetVolumeLevelUseCase.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetVolumeLevelUseCase.kt
index 1632ac7..040e68b 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetVolumeLevelUseCase.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/domain/SetVolumeLevelUseCase.kt
@@ -22,12 +22,16 @@ package io.github.tommygeenexus.usbdonglecontrol.control.domain
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongleException
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.VolumeLevel as VolumeLevelFiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.createFromDisplayValue
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.VolumeLevel as VolumeLevelFiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.createFromDisplayValue
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
-import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.VolumeLevel
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.VolumeLevel as VolumeLevelMoondropDawn
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.feature.createFromDisplayValue
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data.FiioKa13UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.data.FiioKa5UsbRepository
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.data.MoondropDawnUsbRepository
import javax.inject.Inject
@@ -35,12 +39,21 @@ import javax.inject.Singleton
@Singleton
class SetVolumeLevelUseCase @Inject constructor(
+ private val fiioKa13UsbRepository: FiioKa13UsbRepository,
private val fiioKa5UsbRepository: FiioKa5UsbRepository,
private val moondropDawnUsbRepository: MoondropDawnUsbRepository
) {
suspend operator fun invoke(usbDongle: UsbDongle, volumeLevel: Int): Result =
when (usbDongle) {
+ is FiioKa13 -> {
+ fiioKa13UsbRepository.setVolumeLevel(
+ fiioKa13 = usbDongle,
+ volumeLevel = VolumeLevelFiioKa13.createFromDisplayValue(
+ displayValue = volumeLevel
+ )
+ )
+ }
is FiioKa5 -> {
fiioKa5UsbRepository.setVolumeLevel(
fiioKa5 = usbDongle,
@@ -53,7 +66,7 @@ class SetVolumeLevelUseCase @Inject constructor(
is MoondropDawn -> {
moondropDawnUsbRepository.setVolumeLevel(
moondropDawn = usbDongle,
- volumeLevel = VolumeLevel.createFromDisplayValue(
+ volumeLevel = VolumeLevelMoondropDawn.createFromDisplayValue(
displayValue = volumeLevel
)
)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/ui/ControlScreen.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/ui/ControlScreen.kt
index 5047b9e..f5b70fd 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/ui/ControlScreen.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/control/ui/ControlScreen.kt
@@ -83,6 +83,7 @@ import io.github.tommygeenexus.usbdonglecontrol.core.control.ControlTabs
import io.github.tommygeenexus.usbdonglecontrol.core.db.Profile
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UnsupportedUsbDongle
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.UsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.productName
@@ -90,6 +91,7 @@ import io.github.tommygeenexus.usbdonglecontrol.core.dongle.profileFlow
import io.github.tommygeenexus.usbdonglecontrol.core.extension.consumeProfileShortcut
import io.github.tommygeenexus.usbdonglecontrol.core.receiver.UsbDeviceAttachDetachPermissionReceiver
import io.github.tommygeenexus.usbdonglecontrol.core.receiver.UsbServiceVolumeLevelChangedReceiver
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.ui.FiioKa13Items
import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.ui.FiioKa5Items
import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.ui.MoondropDawnItems
import io.github.tommygeenexus.usbdonglecontrol.theme.getHorizontalPadding
@@ -477,6 +479,26 @@ fun ControlScreen(
)
if (selectedTabIndex == ControlTabs.State.index) {
when (usbDongle) {
+ is FiioKa13 -> {
+ FiioKa13Items(
+ modifier = Modifier.padding(
+ horizontal = windowSizeClass.getHorizontalPadding()
+ ),
+ fiioKa13 = usbDongle,
+ onFilterSelected = { filterId ->
+ onFilterSelected(filterId)
+ },
+ onIndicatorStateSelected = { indicatorStateId ->
+ onIndicatorStateSelected(indicatorStateId)
+ },
+ onSpdifOutSelected = { isSpdifOutEnabled ->
+ onSpdifOutEnabledSelected(isSpdifOutEnabled)
+ },
+ onVolumeLevelSelected = { volumeLevel ->
+ onVolumeLevelSelected(volumeLevel)
+ }
+ )
+ }
is FiioKa5 -> {
FiioKa5Items(
modifier = Modifier.padding(
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/data/UsbRepository.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/data/UsbRepository.kt
index 5916fc9..2204198 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/data/UsbRepository.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/data/UsbRepository.kt
@@ -96,11 +96,11 @@ open class UsbRepository @Inject constructor(
}
@Throws(UnsupportedUsbDongleException::class, IllegalStateException::class)
- suspend fun openFirstAttachedUsbDongleOrThrow(): UsbDeviceConnection =
+ suspend fun openFirstAttachedUsbDongleOrThrow(): Pair =
withContext(dispatcherIo) {
val (usbDevice, _, _) = getFirstAttachedUsbDongle().getOrThrow()
val manager = context.getSystemService(Context.USB_SERVICE) as UsbManager
- manager.openDevice(usbDevice).also { connection ->
+ usbDevice to manager.openDevice(usbDevice).also { connection ->
if (connection == null) {
error("manager.openDevice() failed")
}
@@ -170,16 +170,20 @@ open class UsbRepository @Inject constructor(
@Throws(IllegalStateException::class)
suspend fun UsbDeviceConnection.controlWrite(
+ requestType: Int = REQUEST_TYPE_WRITE,
+ requestId: Int = REQUEST_ID_WRITE,
+ requestValue: Int = REQUEST_VALUE,
+ requestIndex: Int = REQUEST_INDEX,
payload: ByteArray,
payloadSize: Int,
transferTimeout: Int,
delayInMillisecondsAfterTransfer: Long
) = withContext(dispatcherIo) {
val result = controlTransfer(
- REQUEST_TYPE_WRITE,
- REQUEST_ID_WRITE,
- REQUEST_VALUE,
- REQUEST_INDEX,
+ requestType,
+ requestId,
+ requestValue,
+ requestIndex,
payload,
payloadSize,
transferTimeout
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/SupportedDongles.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/SupportedDongles.kt
index 937f13a..65fbdfa 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/SupportedDongles.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/SupportedDongles.kt
@@ -21,12 +21,14 @@
package io.github.tommygeenexus.usbdonglecontrol.core.dongle
import android.hardware.usb.UsbDevice
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.FiioKa5
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn35
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawn44
import io.github.tommygeenexus.usbdonglecontrol.core.dongle.moondrop.dawn.MoondropDawnPro
val supportedDongles = listOf(
+ FiioKa13(),
FiioKa5(),
MoondropDawn35(),
MoondropDawn44(),
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13.kt
new file mode 100644
index 0000000..88f7e06
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13
+
+import io.github.tommygeenexus.usbdonglecontrol.core.db.Profile
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.FiioUsbDongle
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.Filter
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.FirmwareVersion
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.IndicatorState
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.SampleRate
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.VolumeLevel
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.default
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.displayValueToPercent
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.SpdifOut
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.default
+import io.github.tommygeenexus.usbdonglecontrol.core.volume.HardwareVolumeControl
+import kotlinx.parcelize.IgnoredOnParcel
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class FiioKa13(
+ val filter: Filter = Filter.default(),
+ val firmwareVersion: FirmwareVersion = FirmwareVersion.default(),
+ val indicatorState: IndicatorState = IndicatorState.default(),
+ val sampleRate: SampleRate = SampleRate.default(),
+ val spdifOut: SpdifOut = SpdifOut.default(),
+ val volumeLevel: VolumeLevel = VolumeLevel.default()
+) : FiioUsbDongle(
+ modelName = MODEL_NAME,
+ productId = PRODUCT_ID
+),
+ HardwareVolumeControl,
+ FiioKa13UsbCommand {
+
+ companion object {
+ const val MODEL_NAME = "KA13"
+ const val PRODUCT_ID = 98
+ }
+
+ @IgnoredOnParcel
+ override val setFilter
+ get() = listOf(
+ byteArrayOf(0, 17, -96, -94, 2, 2, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0),
+ byteArrayOf(9, 17, -128, 96, 0, 0, 5, 9, 0, 0, 1, 0, 0, 0, 0, 0)
+ )
+
+ @IgnoredOnParcel
+ override val setIndicatorState
+ get() = byteArrayOf(8, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+ @IgnoredOnParcel
+ override val setSpdifOut
+ get() = byteArrayOf(10, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+ @IgnoredOnParcel
+ override val setVolumeLevel
+ get() = listOf(
+ byteArrayOf(12, 17, -96, -94, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ byteArrayOf(13, 17, -96, -94, 0, 17, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ byteArrayOf(6, 17, 0, 98, 0, 0, 5, 9, 0, 2, 1, 0, 0, 0, 0, 0),
+ byteArrayOf(7, 17, 0, 102, 0, 0, 5, 9, 0, 2, 1, 0, 0, 0, 0, 0),
+ byteArrayOf(7, 17, 0, 98, 0, 0, 5, 9, 0, 1, 1, 0, 0, 0, 0, 0),
+ byteArrayOf(8, 17, 0, 102, 0, 0, 5, 9, 0, 1, 1, 0, 0, 0, 0, 0)
+ )
+
+ @IgnoredOnParcel
+ override val maxVolumeStepSize
+ get() = HardwareVolumeControl.VOLUME_STEP_SIZE_2
+
+ @IgnoredOnParcel
+ override val isVolumeControlAsc
+ get() = false
+
+ override val currentVolumeLevel
+ get() = volumeLevel.displayValueAndPayload
+
+ override val displayVolumeLevel: String
+ get() = volumeLevel.displayValueToPercent()
+
+ override fun currentStateAsProfile(profileName: String) = Profile(
+ name = profileName,
+ vendorId = vendorId,
+ productId = productId,
+ filterId = filter.id,
+ firmwareVersion = firmwareVersion.displayValue,
+ indicatorStateId = indicatorState.id,
+ isSpdifOutEnabled = spdifOut.isEnabled,
+ sampleRate = sampleRate.displayValue,
+ volumeLevel = volumeLevel.displayValueAndPayload
+ )
+
+ override fun defaultStateAsProfile() = Profile(
+ name = "",
+ vendorId = vendorId,
+ productId = productId,
+ filterId = Filter.default().id,
+ firmwareVersion = FirmwareVersion.default().displayValue,
+ indicatorStateId = IndicatorState.default().id,
+ isSpdifOutEnabled = SpdifOut.default().isEnabled,
+ sampleRate = SampleRate.default().displayValue,
+ volumeLevel = VolumeLevel.default().displayValueAndPayload
+ )
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13UsbCommand.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13UsbCommand.kt
new file mode 100644
index 0000000..4b394cb
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/FiioKa13UsbCommand.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13
+
+interface FiioKa13UsbCommand {
+
+ val setFilter: List
+ val setIndicatorState: ByteArray
+ val setSpdifOut: ByteArray
+ val setVolumeLevel: List
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/Filter.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/Filter.kt
new file mode 100644
index 0000000..21e0dfa
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/Filter.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Immutable
+sealed class Filter(val id: Byte, val payload: Byte) : Parcelable {
+
+ companion object {
+
+ fun default() = FastRollOffLowLatency
+
+ fun findByIdOrDefault(id: Byte): Filter = when (id) {
+ FastRollOffLowLatency.id -> FastRollOffLowLatency
+ FastRollOffPhaseCompensated.id -> FastRollOffPhaseCompensated
+ SlowRollOffLowLatency.id -> SlowRollOffLowLatency
+ SlowRollOffPhaseCompensated.id -> SlowRollOffPhaseCompensated
+ NonOversampling.id -> NonOversampling
+ else -> default()
+ }
+ }
+
+ @Parcelize
+ data object FastRollOffLowLatency : Filter(id = 0, payload = 2)
+
+ @Parcelize
+ data object FastRollOffPhaseCompensated : Filter(id = 1, payload = 66)
+
+ @Parcelize
+ data object SlowRollOffLowLatency : Filter(id = 2, payload = 130.toByte())
+
+ @Parcelize
+ data object SlowRollOffPhaseCompensated : Filter(id = 3, payload = 194.toByte())
+
+ @Parcelize
+ data object NonOversampling : Filter(id = 4, payload = 34)
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/FirmwareVersion.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/FirmwareVersion.kt
new file mode 100644
index 0000000..5d4a1a9
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/FirmwareVersion.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Immutable
+@Parcelize
+data class FirmwareVersion(val displayValue: String) : Parcelable {
+
+ companion object {
+
+ const val DEFAULT = "0.00"
+ }
+}
+
+fun FirmwareVersion.Companion.default() = FirmwareVersion(displayValue = DEFAULT)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/IndicatorState.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/IndicatorState.kt
new file mode 100644
index 0000000..416523b
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/IndicatorState.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Immutable
+sealed class IndicatorState(val id: Byte, val payload: ByteArray) : Parcelable {
+
+ companion object {
+
+ private val payloadIndicatorStateEnabled = byteArrayOf(-1, 0)
+ private val payloadIndicatorStateDisabledTemp = byteArrayOf(-2, 1)
+ private val payloadIndicatorStateDisabled = byteArrayOf(-3, 2)
+
+ fun default() = Enabled
+
+ fun findByIdOrDefault(id: Byte): IndicatorState = when (id) {
+ Enabled.id -> Enabled
+ DisabledTemp.id -> DisabledTemp
+ Disabled.id -> Disabled
+ else -> default()
+ }
+ }
+
+ @Parcelize
+ data object Enabled : IndicatorState(id = 0, payload = payloadIndicatorStateEnabled)
+
+ @Parcelize
+ data object DisabledTemp : IndicatorState(id = 1, payload = payloadIndicatorStateDisabledTemp)
+
+ @Parcelize
+ data object Disabled : IndicatorState(id = 2, payload = payloadIndicatorStateDisabled)
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/SampleRate.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/SampleRate.kt
new file mode 100644
index 0000000..6d6dce9
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/SampleRate.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Immutable
+@Parcelize
+data class SampleRate(val displayValue: String) : Parcelable {
+
+ companion object {
+
+ const val DEFAULT = "48kHz"
+ }
+}
+
+fun SampleRate.Companion.create(key: Int) = SampleRate(
+ displayValue = sampleRates.getOrDefault(
+ key = key,
+ defaultValue = DEFAULT
+ )
+)
+
+fun SampleRate.Companion.default() = SampleRate(displayValue = DEFAULT)
+
+private val sampleRates = mapOf(
+ 0 to "44.1kHz",
+ 1 to "48kHz",
+ 2 to "88.2kHz",
+ 3 to "96kHz",
+ 4 to "176.4kHz",
+ 5 to "192kHz",
+ 6 to "352.8kHz",
+ 7 to "384kHz",
+ 8 to "705.6kHz",
+ 9 to "768kHz",
+ 16 to "DoP64",
+ 17 to "DoP64",
+ 18 to "DoP128",
+ 19 to "DoP128",
+ 20 to "DoP256",
+ 21 to "DoP256",
+ 32 to "Native64",
+ 33 to "Native64",
+ 34 to "Native128",
+ 35 to "Native128",
+ 36 to "Native256",
+ 37 to "Native256",
+ 38 to "Native512",
+ 39 to "Native512"
+)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/VolumeLevel.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/VolumeLevel.kt
new file mode 100644
index 0000000..349592c
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka13/feature/VolumeLevel.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature
+
+import android.os.Parcelable
+import androidx.compose.runtime.Immutable
+import kotlinx.parcelize.Parcelize
+
+@Immutable
+@Parcelize
+data class VolumeLevel(val displayValueAndPayload: Int) : Parcelable {
+
+ companion object {
+ const val MIN = 100
+ const val MAX = 0
+ const val DEFAULT = MAX
+ }
+}
+
+fun VolumeLevel.Companion.createFromDisplayValue(displayValue: Int) = VolumeLevel(
+ displayValueAndPayload = displayValue.coerceIn(
+ minimumValue = MAX,
+ maximumValue = MIN
+ )
+)
+
+fun VolumeLevel.Companion.default() = VolumeLevel(displayValueAndPayload = DEFAULT)
+
+fun VolumeLevel.displayValueToPercent(): String =
+ "${(VolumeLevel.MIN - displayValueAndPayload) * 100 / VolumeLevel.MIN}%"
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka5/FiioKa5.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka5/FiioKa5.kt
index 2b6f04e..f090c0b 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka5/FiioKa5.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/fiio/ka5/FiioKa5.kt
@@ -59,72 +59,92 @@ data class FiioKa5(
val volumeLevel: VolumeLevel = VolumeLevel.default(),
val volumeMode: VolumeMode = VolumeMode.default()
) : FiioUsbDongle(
- modelName = "KA5",
+ modelName = MODEL_NAME,
productId = PRODUCT_ID
),
HardwareVolumeControl,
FiioKa5UsbCommand {
companion object {
+ const val MODEL_NAME = "KA5"
const val PRODUCT_ID = 85
}
@IgnoredOnParcel
- override val getFilter = byteArrayOf(-57, -91, -93)
+ override val getFilter
+ get() = byteArrayOf(-57, -91, -93)
@IgnoredOnParcel
- override val getOtherState = byteArrayOf(-57, -91, -92)
+ override val getOtherState
+ get() = byteArrayOf(-57, -91, -92)
@IgnoredOnParcel
- override val getSampleRate = byteArrayOf(-57, -91, -95)
+ override val getSampleRate
+ get() = byteArrayOf(-57, -91, -95)
@IgnoredOnParcel
- override val getVersion = byteArrayOf(-57, -91, -96)
+ override val getVersion
+ get() = byteArrayOf(-57, -91, -96)
@IgnoredOnParcel
- override val getVolumeLevel = byteArrayOf(-57, -91, -94)
+ override val getVolumeLevel
+ get() = byteArrayOf(-57, -91, -94)
@IgnoredOnParcel
- override val setChannelBalance = byteArrayOf(-57, -91, 5)
+ override val setChannelBalance
+ get() = byteArrayOf(-57, -91, 5)
@IgnoredOnParcel
- override val setDacMode = byteArrayOf(-57, -91, 6)
+ override val setDacMode
+ get() = byteArrayOf(-57, -91, 6)
@IgnoredOnParcel
- override val setDisplayBrightness = byteArrayOf(-57, -91, 11)
+ override val setDisplayBrightness
+ get() = byteArrayOf(-57, -91, 11)
@IgnoredOnParcel
- override val setDisplayInvert = byteArrayOf(-57, -91, 12)
+ override val setDisplayInvert
+ get() = byteArrayOf(-57, -91, 12)
@IgnoredOnParcel
- override val setDisplayTimeout = byteArrayOf(-57, -91, 9)
+ override val setDisplayTimeout
+ get() = byteArrayOf(-57, -91, 9)
@IgnoredOnParcel
- override val setFilter = byteArrayOf(-57, -91, 1)
+ override val setFilter
+ get() = byteArrayOf(-57, -91, 1)
@IgnoredOnParcel
- override val setGain = byteArrayOf(-57, -91, 2)
+ override val setGain
+ get() = byteArrayOf(-57, -91, 2)
@IgnoredOnParcel
- override val setHardwareMute = byteArrayOf(-57, -91, 7)
+ override val setHardwareMute
+ get() = byteArrayOf(-57, -91, 7)
@IgnoredOnParcel
- override val setHidMode = byteArrayOf(-57, -91, 10)
+ override val setHidMode
+ get() = byteArrayOf(-57, -91, 10)
@IgnoredOnParcel
- override val setSpdifOut = byteArrayOf(-57, -91, 8)
+ override val setSpdifOut
+ get() = byteArrayOf(-57, -91, 8)
@IgnoredOnParcel
- override val setVolumeLevel = byteArrayOf(-57, -91, 4)
+ override val setVolumeLevel
+ get() = byteArrayOf(-57, -91, 4)
@IgnoredOnParcel
- override val setVolumeMode = byteArrayOf(-57, -91, 13)
+ override val setVolumeMode
+ get() = byteArrayOf(-57, -91, 13)
@IgnoredOnParcel
- override val maxVolumeStepSize = HardwareVolumeControl.VOLUME_STEP_SIZE_MAX
+ override val maxVolumeStepSize
+ get() = HardwareVolumeControl.VOLUME_STEP_SIZE_4
@IgnoredOnParcel
- override val isVolumeControlAsc = true
+ override val isVolumeControlAsc
+ get() = true
override val currentVolumeLevel
get() = volumeLevel.displayValue
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn.kt
index 7fdc9ec..5908a48 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn.kt
@@ -41,19 +41,26 @@ sealed class MoondropDawn(
HardwareVolumeControl,
MoondropDawnUsbCommand {
- override val getAny = byteArrayOf(-64, -91, -93)
+ override val getAny
+ get() = byteArrayOf(-64, -91, -93)
- override val getVolumeLevel = byteArrayOf(-64, -91, -94)
+ override val getVolumeLevel
+ get() = byteArrayOf(-64, -91, -94)
- override val setFilter = byteArrayOf(-64, -91, 1)
+ override val setFilter
+ get() = byteArrayOf(-64, -91, 1)
- override val setGain = byteArrayOf(-64, -91, 2)
+ override val setGain
+ get() = byteArrayOf(-64, -91, 2)
- override val setIndicatorState = byteArrayOf(-64, -91, 6)
+ override val setIndicatorState
+ get() = byteArrayOf(-64, -91, 6)
- override val setVolumeLevel = byteArrayOf(-64, -91, 4)
+ override val setVolumeLevel
+ get() = byteArrayOf(-64, -91, 4)
- override val maxVolumeStepSize = HardwareVolumeControl.VOLUME_STEP_SIZE_MAX - 1
+ override val maxVolumeStepSize
+ get() = HardwareVolumeControl.VOLUME_STEP_SIZE_3
override val isVolumeControlAsc: Boolean
get() = false
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn35.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn35.kt
index 2cbf351..d5a2777 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn35.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn35.kt
@@ -34,7 +34,7 @@ data class MoondropDawn35(
override val indicatorState: IndicatorState = IndicatorState.default(),
override val volumeLevel: VolumeLevel = VolumeLevel.default()
) : MoondropDawn(
- modelName = "Dawn 3.5mm",
+ modelName = MODEL_NAME,
productId = PRODUCT_ID,
filter = filter,
gain = gain,
@@ -43,7 +43,7 @@ data class MoondropDawn35(
) {
companion object {
-
+ const val MODEL_NAME = "Dawn 3.5mm"
const val PRODUCT_ID = 61544
}
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn44.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn44.kt
index 37a8c30..af3fa97 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn44.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawn44.kt
@@ -34,7 +34,7 @@ data class MoondropDawn44(
override val indicatorState: IndicatorState = IndicatorState.default(),
override val volumeLevel: VolumeLevel = VolumeLevel.default()
) : MoondropDawn(
- modelName = "Dawn 4.4mm",
+ modelName = MODEL_NAME,
productId = PRODUCT_ID,
filter = filter,
gain = gain,
@@ -43,7 +43,7 @@ data class MoondropDawn44(
) {
companion object {
-
+ const val MODEL_NAME = "Dawn 4.4mm"
const val PRODUCT_ID = 61543
}
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawnPro.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawnPro.kt
index 59c8a49..2f51635 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawnPro.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/dongle/moondrop/dawn/MoondropDawnPro.kt
@@ -34,7 +34,7 @@ data class MoondropDawnPro(
override val indicatorState: IndicatorState = IndicatorState.default(),
override val volumeLevel: VolumeLevel = VolumeLevel.default()
) : MoondropDawn(
- modelName = "Dawn Pro",
+ modelName = MODEL_NAME,
productId = PRODUCT_ID,
filter = filter,
gain = gain,
@@ -43,7 +43,7 @@ data class MoondropDawnPro(
) {
companion object {
-
+ const val MODEL_NAME = "Dawn Pro"
const val PRODUCT_ID = 61546
}
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/extension/UsbDeviceConnectionExtensions.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/extension/UsbDeviceConnectionExtensions.kt
new file mode 100644
index 0000000..38cc23f
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/extension/UsbDeviceConnectionExtensions.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.core.extension
+
+import android.hardware.usb.UsbDeviceConnection
+import android.hardware.usb.UsbInterface
+
+fun UsbDeviceConnection.claimInterface(usbInterface: UsbInterface): Boolean {
+ var success = claimInterface(usbInterface, false)
+ if (!success) {
+ success = claimInterface(usbInterface, true)
+ }
+ return success
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/volume/HardwareVolumeControl.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/volume/HardwareVolumeControl.kt
index 2dc71d7..c0a2f57 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/volume/HardwareVolumeControl.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/core/volume/HardwareVolumeControl.kt
@@ -28,9 +28,11 @@ interface HardwareVolumeControl {
companion object {
- const val VOLUME_STEP_SIZE_MIN = 1
- const val VOLUME_STEP_SIZE_MAX = 4
- const val VOLUME_STEP_SIZE_DEFAULT = VOLUME_STEP_SIZE_MIN
+ const val VOLUME_STEP_SIZE_1 = 1
+ const val VOLUME_STEP_SIZE_2 = 2
+ const val VOLUME_STEP_SIZE_3 = 3
+ const val VOLUME_STEP_SIZE_4 = 4
+ const val VOLUME_STEP_SIZE_DEFAULT = VOLUME_STEP_SIZE_1
}
}
@@ -49,7 +51,7 @@ fun HardwareVolumeControl.volumeUp(volumeStepSize: Int) = if (isVolumeControlAsc
fun HardwareVolumeControl.incrementOrWrapVolumeStepSize(volumeStepSize: Int): Int {
var nextVolumeStepSize = volumeStepSize.inc()
if (nextVolumeStepSize > maxVolumeStepSize) {
- nextVolumeStepSize = HardwareVolumeControl.VOLUME_STEP_SIZE_MIN
+ nextVolumeStepSize = HardwareVolumeControl.VOLUME_STEP_SIZE_1
}
return nextVolumeStepSize
}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/data/FiioKa13UsbRepository.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/data/FiioKa13UsbRepository.kt
new file mode 100644
index 0000000..ad72fac
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/data/FiioKa13UsbRepository.kt
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.data
+
+import android.content.Context
+import dagger.hilt.android.qualifiers.ApplicationContext
+import io.github.tommygeenexus.usbdonglecontrol.core.data.UsbRepository
+import io.github.tommygeenexus.usbdonglecontrol.core.di.DispatcherIo
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.Filter
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.FirmwareVersion
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.IndicatorState
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.VolumeLevel
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka5.feature.SpdifOut
+import io.github.tommygeenexus.usbdonglecontrol.core.extension.claimInterface
+import io.github.tommygeenexus.usbdonglecontrol.core.extension.suspendRunCatching
+import javax.inject.Inject
+import javax.inject.Singleton
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import timber.log.Timber
+
+@Singleton
+class FiioKa13UsbRepository @Inject constructor(
+ @ApplicationContext private val context: Context,
+ @DispatcherIo private val dispatcherIo: CoroutineDispatcher
+) : UsbRepository(context, dispatcherIo) {
+
+ private companion object {
+
+ const val DELAY_MS = 100L
+ const val TIMEOUT_MS = 200
+
+ const val REQUEST_INDEX_SET_FILTER_1 = 0
+ const val REQUEST_INDEX_SET_FILTER_VOLUME_2 = 11
+ const val REQUEST_INDEX_SET_INDICATOR_STATE_SPDIF_OUT = 2
+ const val REQUEST_INDEX_SET_VOLUME_1 = 7
+
+ private const val REQUEST_TYPE = 33
+ private const val REQUEST_ID = 9
+ private const val REQUEST_VALUE = 512
+ private const val REQUEST_INDEX = 0
+ }
+
+ // FIXME: Reading current state is not working properly (firmware issue?)
+ suspend fun getCurrentState(usbDongle: FiioKa13): Result {
+ return withContext(dispatcherIo) {
+ val (usbDevice, usbConnection) = coroutineContext.suspendRunCatching {
+ openFirstAttachedUsbDongleOrThrow()
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ return@withContext Result.failure(exception)
+ }
+ coroutineContext.suspendRunCatching(onReleaseResources = { usbConnection.close() }) {
+ Result.success(
+ value = usbDongle.copy(
+ firmwareVersion = FirmwareVersion(displayValue = usbDevice.version)
+ )
+ )
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ Result.failure(exception)
+ }
+ }
+ }
+
+ // TODO: Is it actually working?
+ suspend fun setFilter(fiioKa13: FiioKa13, filter: Filter): Result {
+ return withContext(dispatcherIo) {
+ val (usbDevice, usbConnection) = coroutineContext.suspendRunCatching {
+ openFirstAttachedUsbDongleOrThrow()
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ return@withContext Result.failure(exception)
+ }
+ coroutineContext.suspendRunCatching(onReleaseResources = { usbConnection.close() }) {
+ val usbInterface = usbDevice.getInterface(0)
+ mutex.withLock {
+ check(usbConnection.claimInterface(usbInterface))
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setFilter.first().apply {
+ set(REQUEST_INDEX_SET_FILTER_1, filter.payload)
+ },
+ payloadSize = fiioKa13.setFilter.size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setFilter.last().apply {
+ set(REQUEST_INDEX_SET_FILTER_VOLUME_2, filter.payload)
+ },
+ payloadSize = fiioKa13.setFilter.size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ check(usbConnection.releaseInterface(usbInterface))
+ }
+ Result.success(value = fiioKa13.copy(filter = filter))
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ Result.failure(exception)
+ }
+ }
+ }
+
+ suspend fun setIndicatorState(
+ fiioKa13: FiioKa13,
+ indicatorState: IndicatorState
+ ): Result {
+ return withContext(dispatcherIo) {
+ val (usbDevice, usbConnection) = coroutineContext.suspendRunCatching {
+ openFirstAttachedUsbDongleOrThrow()
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ return@withContext Result.failure(exception)
+ }
+ coroutineContext.suspendRunCatching(onReleaseResources = { usbConnection.close() }) {
+ val usbInterface = usbDevice.getInterface(0)
+ mutex.withLock {
+ check(usbConnection.claimInterface(usbInterface))
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = indicatorState.payload.copyInto(
+ destination = fiioKa13.setIndicatorState,
+ destinationOffset = REQUEST_INDEX_SET_INDICATOR_STATE_SPDIF_OUT
+ ),
+ payloadSize = fiioKa13.setIndicatorState.size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ check(usbConnection.releaseInterface(usbInterface))
+ }
+ Result.success(value = fiioKa13.copy(indicatorState = indicatorState))
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ Result.failure(exception)
+ }
+ }
+ }
+
+ suspend fun setSpdifOut(fiioKa13: FiioKa13, spdifOut: SpdifOut): Result {
+ return withContext(dispatcherIo) {
+ val (usbDevice, usbConnection) = coroutineContext.suspendRunCatching {
+ openFirstAttachedUsbDongleOrThrow()
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ return@withContext Result.failure(exception)
+ }
+ coroutineContext.suspendRunCatching(onReleaseResources = { usbConnection.close() }) {
+ val usbInterface = usbDevice.getInterface(0)
+ mutex.withLock {
+ check(usbConnection.claimInterface(usbInterface))
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = byteArrayOf(spdifOut.payload).copyInto(
+ destination = fiioKa13.setSpdifOut,
+ destinationOffset = REQUEST_INDEX_SET_INDICATOR_STATE_SPDIF_OUT
+ ),
+ payloadSize = fiioKa13.setSpdifOut.size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ check(usbConnection.releaseInterface(usbInterface))
+ }
+ Result.success(value = fiioKa13.copy(spdifOut = spdifOut))
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ Result.failure(exception)
+ }
+ }
+ }
+
+ suspend fun setVolumeLevel(fiioKa13: FiioKa13, volumeLevel: VolumeLevel): Result {
+ return withContext(dispatcherIo) {
+ val (usbDevice, usbConnection) = coroutineContext.suspendRunCatching {
+ openFirstAttachedUsbDongleOrThrow()
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ return@withContext Result.failure(exception)
+ }
+ coroutineContext.suspendRunCatching(onReleaseResources = { usbConnection.close() }) {
+ val usbInterface = usbDevice.getInterface(0)
+ val payload = volumeLevel.displayValueAndPayload.toByte()
+ mutex.withLock {
+ check(usbConnection.claimInterface(usbInterface))
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel.first().apply {
+ set(REQUEST_INDEX_SET_VOLUME_1, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel[1].apply {
+ set(REQUEST_INDEX_SET_VOLUME_1, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel[2].apply {
+ set(REQUEST_INDEX_SET_FILTER_VOLUME_2, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel[3].apply {
+ set(REQUEST_INDEX_SET_FILTER_VOLUME_2, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel[4].apply {
+ set(REQUEST_INDEX_SET_FILTER_VOLUME_2, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ usbConnection.controlWrite(
+ requestType = REQUEST_TYPE,
+ requestId = REQUEST_ID,
+ requestValue = REQUEST_VALUE,
+ requestIndex = REQUEST_INDEX,
+ payload = fiioKa13.setVolumeLevel.last().apply {
+ set(REQUEST_INDEX_SET_FILTER_VOLUME_2, payload)
+ },
+ payloadSize = fiioKa13.setVolumeLevel.first().size,
+ transferTimeout = TIMEOUT_MS,
+ delayInMillisecondsAfterTransfer = DELAY_MS
+ )
+ check(usbConnection.releaseInterface(usbInterface))
+ }
+ Result.success(value = fiioKa13.copy(volumeLevel = volumeLevel))
+ }.getOrElse { exception ->
+ Timber.e(exception)
+ Result.failure(exception)
+ }
+ }
+ }
+
+ suspend fun setAll(
+ fiioKa13: FiioKa13,
+ filter: Filter,
+ indicatorState: IndicatorState,
+ spdifOut: SpdifOut,
+ volumeLevel: VolumeLevel
+ ): Result = withContext(dispatcherIo) {
+ setFilter(fiioKa13, filter)
+ setIndicatorState(fiioKa13, indicatorState)
+ setSpdifOut(fiioKa13, spdifOut)
+ setVolumeLevel(fiioKa13, volumeLevel)
+ }
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Items.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Items.kt
new file mode 100644
index 0000000..e48195e
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Items.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.ui
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
+import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.VolumeLevel
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.createFromDisplayValue
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.displayValueToPercent
+import io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka5.ui.ItemFilter
+import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.ui.ItemAudio
+import io.github.tommygeenexus.usbdonglecontrol.dongle.moondrop.dawn.ui.ItemIndicatorState
+import io.github.tommygeenexus.usbdonglecontrol.theme.cardPaddingBetween
+import io.github.tommygeenexus.usbdonglecontrol.theme.cardSizeMinDp
+
+@Composable
+fun FiioKa13Items(
+ modifier: Modifier = Modifier,
+ fiioKa13: FiioKa13 = FiioKa13(),
+ onFilterSelected: (Byte) -> Unit = {},
+ onIndicatorStateSelected: (Byte) -> Unit = {},
+ onSpdifOutSelected: (Boolean) -> Unit = {},
+ onVolumeLevelSelected: (Int) -> Unit = {}
+) {
+ LazyVerticalStaggeredGrid(
+ columns = StaggeredGridCells.Adaptive(minSize = cardSizeMinDp),
+ modifier = modifier,
+ contentPadding = PaddingValues(all = cardPaddingBetween),
+ verticalItemSpacing = cardPaddingBetween,
+ horizontalArrangement = Arrangement.spacedBy(cardPaddingBetween)
+ ) {
+ item {
+ ItemInfo(
+ firmwareVersion = fiioKa13.firmwareVersion.displayValue,
+ sampleRate = fiioKa13.sampleRate.displayValue
+ )
+ }
+ item {
+ ItemMisc(
+ isSpdifOutEnabled = fiioKa13.spdifOut.isEnabled,
+ onSpdifOutEnabledSwitched = onSpdifOutSelected
+ )
+ }
+ item {
+ ItemIndicatorState(
+ indicatorStateId = fiioKa13.indicatorState.id,
+ onIndicatorStateSelected = onIndicatorStateSelected
+ )
+ }
+ item {
+ ItemAudio(
+ volumeLevel =
+ VolumeLevel.MIN - fiioKa13.volumeLevel.displayValueAndPayload.toFloat(),
+ volumeLevelInPercent = fiioKa13.displayVolumeLevel,
+ volumeLevelStart = VolumeLevel.MAX.toFloat(),
+ volumeLevelEnd = VolumeLevel.MIN.toFloat(),
+ volumeLevelStepSize = 2f,
+ onVolumeLevelToPercent = { volumeLevel ->
+ VolumeLevel
+ .createFromDisplayValue(VolumeLevel.MIN - volumeLevel)
+ .displayValueToPercent()
+ },
+ onVolumeLevelSelected = { volumeLevel ->
+ onVolumeLevelSelected(VolumeLevel.MIN - volumeLevel)
+ }
+ )
+ }
+ item {
+ ItemFilter(
+ filterId = fiioKa13.filter.id,
+ onFilterSelected = onFilterSelected
+ )
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun FiioKa13ItemsPreview() {
+ FiioKa13Items()
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Previews.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Previews.kt
new file mode 100644
index 0000000..8cf6935
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/FiioKa13Previews.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.ui
+
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import io.github.tommygeenexus.usbdonglecontrol.control.ui.ControlScreen
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.FiioKa13
+
+private val usbDongle = FiioKa13()
+
+@Preview(name = "Loading")
+@Composable
+private fun ControlScreenPreview1() {
+ ControlScreen(
+ usbDongle = usbDongle,
+ isLoading = true
+ )
+}
+
+@Preview(name = "Compact")
+@Composable
+private fun ControlScreenPreview2() {
+ ControlScreen(usbDongle = usbDongle)
+}
+
+@Preview(name = "Medium")
+@Composable
+private fun ControlScreenPreview3() {
+ ControlScreen(
+ windowSizeClass = WindowSizeClass.calculateFromSize(DpSize.Zero.copy(width = 600.dp)),
+ usbDongle = usbDongle
+ )
+}
+
+@Preview(name = "Expanded")
+@Composable
+private fun ControlScreenPreview4() {
+ ControlScreen(
+ windowSizeClass = WindowSizeClass.calculateFromSize(DpSize.Zero.copy(width = 840.dp)),
+ usbDongle = usbDongle
+ )
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemInfo.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemInfo.kt
new file mode 100644
index 0000000..d68266d
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemInfo.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.ui
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.BuildCircle
+import androidx.compose.material.icons.outlined.MusicNote
+import androidx.compose.material3.ElevatedCard
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import io.github.tommygeenexus.usbdonglecontrol.R
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.FirmwareVersion
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.SampleRate
+import io.github.tommygeenexus.usbdonglecontrol.core.dongle.fiio.ka13.feature.default
+import io.github.tommygeenexus.usbdonglecontrol.theme.cardPadding
+
+@Composable
+fun ItemInfo(
+ modifier: Modifier = Modifier,
+ firmwareVersion: String = FirmwareVersion.default().displayValue,
+ sampleRate: String = SampleRate.default().displayValue
+) {
+ ElevatedCard(modifier = modifier.fillMaxWidth()) {
+ Column(modifier = Modifier.padding(all = cardPadding)) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Icon(
+ imageVector = Icons.Outlined.BuildCircle,
+ contentDescription = stringResource(id = R.string.fw_version)
+ )
+ Text(
+ text = stringResource(id = R.string.fw_version, firmwareVersion),
+ modifier = Modifier.padding(horizontal = cardPadding),
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+ Row(
+ modifier = Modifier.padding(top = cardPadding),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.MusicNote,
+ contentDescription = stringResource(id = R.string.sample_rate)
+ )
+ Text(
+ text = stringResource(id = R.string.sample_rate, sampleRate),
+ modifier = Modifier.padding(horizontal = cardPadding),
+ style = MaterialTheme.typography.bodyMedium
+ )
+ }
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun ItemInfoPreview() {
+ ItemInfo()
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemMisc.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemMisc.kt
new file mode 100644
index 0000000..8da0e9a
--- /dev/null
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka13/ui/ItemMisc.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2024, Tom Geiselmann (tomgapplicationsdevelopment@gmail.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY,WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package io.github.tommygeenexus.usbdonglecontrol.dongle.fiio.ka13.ui
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ElevatedCard
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Switch
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import io.github.tommygeenexus.usbdonglecontrol.R
+import io.github.tommygeenexus.usbdonglecontrol.theme.cardPadding
+
+@Composable
+fun ItemMisc(
+ modifier: Modifier = Modifier,
+ isSpdifOutEnabled: Boolean = false,
+ onSpdifOutEnabledSwitched: (Boolean) -> Unit = {}
+) {
+ ElevatedCard(modifier = modifier.fillMaxWidth()) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(all = cardPadding),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = R.string.spdif_out),
+ style = MaterialTheme.typography.titleMedium
+ )
+ Switch(
+ checked = isSpdifOutEnabled,
+ onCheckedChange = onSpdifOutEnabledSwitched
+ )
+ }
+ }
+}
+
+@Preview
+@Composable
+private fun ItemMiscPreview() {
+ ItemMisc()
+}
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka5/data/FiioKa5UsbRepository.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka5/data/FiioKa5UsbRepository.kt
index 49c5ea2..a964a6a 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka5/data/FiioKa5UsbRepository.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/fiio/ka5/data/FiioKa5UsbRepository.kt
@@ -80,7 +80,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun getCurrentState(usbDongle: FiioKa5): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -200,7 +200,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun getVolumeLevelAndMode(usbDongle: FiioKa5): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -254,7 +254,7 @@ class FiioKa5UsbRepository @Inject constructor(
channelBalance: ChannelBalance
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -283,7 +283,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setDacMode(fiioKa5: FiioKa5, dacMode: DacMode): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -314,7 +314,7 @@ class FiioKa5UsbRepository @Inject constructor(
displayBrightness: DisplayBrightness
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -342,7 +342,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setDisplayInvert(fiioKa5: FiioKa5, displayInvert: DisplayInvert): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -373,7 +373,7 @@ class FiioKa5UsbRepository @Inject constructor(
displayTimeout: DisplayTimeout
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -401,7 +401,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setFilter(fiioKa5: FiioKa5, filter: Filter): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -429,7 +429,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setGain(fiioKa5: FiioKa5, gain: Gain): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -457,7 +457,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setHardwareMute(fiioKa5: FiioKa5, hardwareMute: HardwareMute): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -485,7 +485,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setHidMode(fiioKa5: FiioKa5, hidMode: HidMode): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -513,7 +513,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setSpdifOut(fiioKa5: FiioKa5, spdifOut: SpdifOut): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -541,7 +541,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setVolumeMode(fiioKa5: FiioKa5, volumeMode: VolumeMode): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -569,7 +569,7 @@ class FiioKa5UsbRepository @Inject constructor(
suspend fun setVolumeLevel(fiioKa5: FiioKa5, volumeLevel: VolumeLevel): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -611,7 +611,7 @@ class FiioKa5UsbRepository @Inject constructor(
volumeMode: VolumeMode
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/data/MoondropDawnUsbRepository.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/data/MoondropDawnUsbRepository.kt
index eaebe3c..b0bdf70 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/data/MoondropDawnUsbRepository.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/data/MoondropDawnUsbRepository.kt
@@ -59,7 +59,7 @@ class MoondropDawnUsbRepository @Inject constructor(
suspend fun getCurrentState(usbDongle: MoondropDawn): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -140,7 +140,7 @@ class MoondropDawnUsbRepository @Inject constructor(
suspend fun setFilter(moondropDawn: MoondropDawn, filter: Filter): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -178,7 +178,7 @@ class MoondropDawnUsbRepository @Inject constructor(
suspend fun setGain(moondropDawn: MoondropDawn, gain: Gain): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -219,7 +219,7 @@ class MoondropDawnUsbRepository @Inject constructor(
indicatorState: IndicatorState
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -260,7 +260,7 @@ class MoondropDawnUsbRepository @Inject constructor(
volumeLevel: VolumeLevel
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
@@ -304,7 +304,7 @@ class MoondropDawnUsbRepository @Inject constructor(
volumeLevel: VolumeLevel
): Result {
return withContext(dispatcherIo) {
- val usbConnection = coroutineContext.suspendRunCatching {
+ val (_, usbConnection) = coroutineContext.suspendRunCatching {
openFirstAttachedUsbDongleOrThrow()
}.getOrElse { exception ->
Timber.e(exception)
diff --git a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/ui/ItemAudio.kt b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/ui/ItemAudio.kt
index 73c1eb6..7490433 100644
--- a/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/ui/ItemAudio.kt
+++ b/app/src/main/kotlin/io/github/tommygeenexus/usbdonglecontrol/dongle/moondrop/dawn/ui/ItemAudio.kt
@@ -46,6 +46,7 @@ fun ItemAudio(
volumeLevelInPercent: String = VolumeLevel.default().displayValueToPercent(),
volumeLevelStart: Float = VolumeLevel.MAX.toFloat(),
volumeLevelEnd: Float = VolumeLevel.MIN.toFloat(),
+ volumeLevelStepSize: Float = 0f,
onVolumeLevelToPercent: (Int) -> String = { _ -> volumeLevelInPercent },
onVolumeLevelSelected: (Int) -> Unit = {}
) {
@@ -56,16 +57,14 @@ fun ItemAudio(
style = MaterialTheme.typography.titleMedium
)
Text(
- text = stringResource(
- id = R.string.volume_level,
- volumeLevelInPercent
- ),
+ text = stringResource(id = R.string.volume_level, volumeLevelInPercent),
modifier = Modifier.padding(top = cardPadding),
style = MaterialTheme.typography.bodyMedium
)
AndroidView(
factory = { context ->
Slider(context).apply {
+ stepSize = volumeLevelStepSize
setLabelFormatter { value ->
onVolumeLevelToPercent(value.roundToInt())
}
diff --git a/app/src/main/res/xml/device_filter.xml b/app/src/main/res/xml/device_filter.xml
index 5c42d8c..882db37 100644
--- a/app/src/main/res/xml/device_filter.xml
+++ b/app/src/main/res/xml/device_filter.xml
@@ -1,5 +1,7 @@
+
+