Skip to content

Commit

Permalink
Merge pull request #42 from enteraname74/develop
Browse files Browse the repository at this point in the history
v0.10.1
  • Loading branch information
enteraname74 authored Jan 2, 2025
2 parents ce1aea4 + 0556a87 commit 3eb1017
Show file tree
Hide file tree
Showing 47 changed files with 521 additions and 271 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.github.enteraname74.soulsearching.coreui.button

import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.github.enteraname74.soulsearching.coreui.theme.color.SoulSearchingColorTheme

@Composable
fun SoulCheckBox(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
color: Color = SoulSearchingColorTheme.colorScheme.onPrimary,
) {
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
colors = CheckboxDefaults.colors(
checkmarkColor = color,
checkedColor = Color.Transparent,
uncheckedColor = color,
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package com.github.enteraname74.soulsearching.coreui.textfield
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.github.enteraname74.soulsearching.coreui.ext.clickableWithHandCursor
import com.github.enteraname74.soulsearching.coreui.image.SoulIcon
import kotlinx.coroutines.CoroutineScope
Expand All @@ -29,6 +32,10 @@ fun SoulDropdownTextField(
modifier: Modifier = Modifier,
colors : SoulTextFieldColors = SoulTextFieldDefaults.secondaryColors(),
style: SoulTextFieldStyle,
keyboardOptions: KeyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
),
leadingIconSpec: SoulTextFieldLeadingIconSpec? = null,
focusManager: FocusManager
) {
Expand Down Expand Up @@ -78,6 +85,7 @@ fun SoulDropdownTextField(
isExpanded = false
}
),
keyboardOptions = keyboardOptions,
leadingIcon = leadingIconSpec?.let {
{
SoulIcon(
Expand Down Expand Up @@ -123,6 +131,10 @@ class SoulDropdownTextFieldHolderImpl(
private val modifier: Modifier = Modifier,
private val updateProposedValues: suspend (fieldValue: String) -> List<String>,
private val style: SoulTextFieldStyle = SoulTextFieldStyle.Unique,
private val keyboardOptions: KeyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
),
onChange: (String) -> Unit = {},
): SoulTextFieldHolder(
initialValue = initialValue,
Expand Down Expand Up @@ -163,6 +175,7 @@ class SoulDropdownTextFieldHolderImpl(
isInError = isInError,
error = error,
leadingIconSpec = leadingIconSpec,
keyboardOptions = keyboardOptions,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.VisualTransformation
import com.github.enteraname74.soulsearching.coreui.UiConstants
Expand All @@ -43,7 +44,10 @@ fun SoulTextField(
modifier: Modifier = Modifier,
colors: SoulTextFieldColors = SoulTextFieldDefaults.secondaryColors(),
style: SoulTextFieldStyle,
keyboardType: KeyboardType = KeyboardType.Text,
keyboardOptions: KeyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
),
keyboardActions: KeyboardActions = KeyboardActions(
onDone = { focusManager.clearFocus() }
),
Expand Down Expand Up @@ -73,9 +77,7 @@ fun SoulTextField(
interactionSource = interactionSource,
maxLines = 1,
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
),
keyboardOptions = keyboardOptions,
textStyle = UiConstants.Typography.bodyLarge.copy(color = colors.contentColor),
keyboardActions = keyboardActions,
cursorBrush = SolidColor(colors.contentColor),
Expand Down Expand Up @@ -150,7 +152,10 @@ class SoulTextFieldHolderImpl(
private val modifier: Modifier = Modifier,
private val style: SoulTextFieldStyle = SoulTextFieldStyle.Unique,
private val onValueChange: ((String) -> Unit)? = null,
private val keyboardType: KeyboardType = KeyboardType.Text,
private val keyboardOptions: KeyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
),
onChange: (String) -> Unit = {},
) : SoulTextFieldHolder(
initialValue = initialValue,
Expand Down Expand Up @@ -178,7 +183,7 @@ class SoulTextFieldHolderImpl(
onValueChange = ::onValueChanged,
labelName = label,
focusManager = focusManager,
keyboardType = keyboardType,
keyboardOptions = keyboardOptions,
style = style,
colors = colors,
error = error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ val domainModule = module {
singleOf(::DeleteArtistIfEmptyUseCase)
singleOf(::DeleteArtistUseCase)
singleOf(::GetAllArtistsUseCase)
singleOf(::GetAllArtistsWithNameUseCase)
singleOf(::GetAllArtistWithMusicsFromQuickAccessUseCase)
singleOf(::GetAllArtistWithMusicsSortedByMostSongsUseCase)
singleOf(::GetAllArtistWithMusicsSortedUseCase)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package com.github.enteraname74.domain.model

import com.github.enteraname74.domain.util.serializer.LocalDateTimeSerializer
import com.github.enteraname74.domain.util.serializer.UUIDSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import java.time.LocalDateTime
import java.util.UUID

/**
* Represent an artist with information related to it.
* It does not possess its musics or its cover directly.
*/
@Serializable
data class Artist(
@Serializable(with = UUIDSerializer::class)
val artistId: UUID = UUID.randomUUID(),
var artistName: String = "",
var cover: Cover? = null,
@Serializable(with = LocalDateTimeSerializer::class)
var addedDate: LocalDateTime = LocalDateTime.now(),
var nbPlayed: Int = 0,
var isInQuickAccess: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ interface ArtistRepository {
*/
suspend fun getFromName(artistName: String): Artist?

suspend fun getAllFromName(artistsNames: List<String>): List<Artist>

/**
* Retrieves a flow of all Artist.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,4 @@ class DeleteArtistUseCase(
deleteArtistIfEmptyUseCase(it.artistId)
}
}

suspend operator fun invoke(artistId: UUID) {
artistRepository.getArtistWithMusics(artistId).firstOrNull()?.let {
artistRepository.delete(it.artist)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.enteraname74.domain.usecase.artist

import com.github.enteraname74.domain.repository.ArtistRepository

class GetAllArtistsWithNameUseCase(
private val artistRepository: ArtistRepository
) {
suspend operator fun invoke(artistsNames: List<String>) =
artistRepository.getAllFromName(artistsNames)
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.github.enteraname74.domain.usecase.month

import com.github.enteraname74.domain.model.MonthMusicList
import com.github.enteraname74.domain.usecase.music.GetAllMusicUseCase
import com.github.enteraname74.domain.model.SortDirection
import com.github.enteraname74.domain.model.SortType
import com.github.enteraname74.domain.usecase.music.GetAllMusicsSortedUseCase
import com.github.enteraname74.domain.util.DateUtils
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapLatest

class GetMonthMusicListUseCase(
private val getAllMusicsUseCase: GetAllMusicUseCase,
private val getAllMusicsSortedUseCase: GetAllMusicsSortedUseCase,
) {
@OptIn(ExperimentalCoroutinesApi::class)
operator fun invoke(month: String): Flow<MonthMusicList?> =
getAllMusicsUseCase().mapLatest { allMusics ->
getAllMusicsSortedUseCase(
sortDirection = SortDirection.DESC,
sortType = SortType.ADDED_DATE,
).mapLatest { allMusics ->
val musics = allMusics.filter { DateUtils.getMonthAndYearOfDate(date = it.addedDate) == month }
MonthMusicList(
month = month,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.github.enteraname74.domain.util.serializer

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.time.LocalDateTime

object LocalDateTimeSerializer: KSerializer<LocalDateTime> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)

override fun deserialize(decoder: Decoder): LocalDateTime {
val string = decoder.decodeString()
return LocalDateTime.parse(string)
}

override fun serialize(encoder: Encoder, value: LocalDateTime) {
val string = value.toString()
encoder.encodeString(string)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.enteraname74.domain.util.serializer

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.util.*

object UUIDSerializer : KSerializer<UUID> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
"UUID",
PrimitiveKind.STRING,
)

override fun deserialize(decoder: Decoder): UUID {
val string = decoder.decodeString()
return UUID.fromString(string)
}

override fun serialize(encoder: Encoder, value: UUID) {
encoder.encodeString(value.toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ class UpdateMusicUseCase(
private suspend fun handleFirstArtistOfMusic(
legacyMusic: Music,
newMusicInformation: Music,
previousArtist: String,
previousArtist: Artist,
newArtist: String,
) {
// It's the same artist, we got nothing to do.
if (previousArtist == newArtist) return
if (previousArtist.artistName == newArtist) return

val legacyArtist = artistRepository.getFromName(artistName = previousArtist)
val existingNewArtist = getOrCreateArtist(
artistName = newArtist,
music = newMusicInformation
Expand All @@ -73,39 +72,34 @@ class UpdateMusicUseCase(
newAlbumName = newMusicInformation.album,
)

legacyArtist?.let { artist ->
musicArtistRepository.deleteMusicArtist(
musicArtist = MusicArtist(
musicId = legacyMusic.musicId,
artistId = legacyArtist.artistId,
)
musicArtistRepository.deleteMusicArtist(
musicArtist = MusicArtist(
musicId = legacyMusic.musicId,
artistId = previousArtist.artistId,
)
deleteArtistIfEmptyUseCase(artistId = artist.artistId)
}
)
deleteArtistIfEmptyUseCase(artistId = previousArtist.artistId)
}

private suspend fun handleMultipleArtistsOfMusic(
legacyMusic: Music,
newMusicInformation: Music,
previousArtistsName: List<String>,
previousArtists: List<Artist>,
newArtistsName: List<String>
) {
// We first need to handle the first artist of the song (it's the one that possess the album of the song)
handleFirstArtistOfMusic(
legacyMusic = legacyMusic,
newMusicInformation = newMusicInformation,
previousArtist = previousArtistsName.first(),
previousArtist = previousArtists.first(),
newArtist = newArtistsName.first(),
)

val previousArtists: List<Artist> = previousArtistsName
.subList(1, previousArtistsName.size)
.mapNotNull { previousArtistName ->
artistRepository.getFromName(artistName = previousArtistName)
}
val previousArtistsWithoutFirstOne: List<Artist> = previousArtists
.subList(1, previousArtists.size)

// We will remove the link of the music to all its other previous artists
previousArtists.forEach { artist ->
previousArtistsWithoutFirstOne.forEach { artist ->
musicArtistRepository.deleteMusicArtist(
musicArtist = MusicArtist(
musicId = legacyMusic.musicId,
Expand All @@ -129,7 +123,7 @@ class UpdateMusicUseCase(
}

// We finally check if the previous artists can be deleted :
previousArtists.forEach { artist ->
previousArtistsWithoutFirstOne.forEach { artist ->
deleteArtistIfEmptyUseCase(
artistId = artist.artistId,
)
Expand All @@ -145,15 +139,15 @@ class UpdateMusicUseCase(
*/
suspend operator fun invoke(
legacyMusic: Music,
previousArtistsNames: List<String>,
previousArtists: List<Artist>,
newArtistsNames: List<String>,
newMusicInformation: Music,
) {
if (previousArtistsNames != newArtistsNames) {
if (previousArtists.map { it.artistName } != newArtistsNames) {
handleMultipleArtistsOfMusic(
legacyMusic = legacyMusic,
newMusicInformation = newMusicInformation,
previousArtistsName = previousArtistsNames,
previousArtists = previousArtists,
newArtistsName = newArtistsNames,
)
} else if (legacyMusic.album != newMusicInformation.album) {
Expand Down
Loading

0 comments on commit 3eb1017

Please sign in to comment.