Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Json playlist #48

Merged
merged 4 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ plugins {
id("org.jlleitschuh.gradle.ktlint").version("12.0.2").apply(false)
id("dev.icerock.mobile.multiplatform-resources").version("0.23.0").apply(false)
id("app.cash.sqldelight").version("2.0.1").apply(false)
kotlin("plugin.serialization").version("1.9.21").apply(false)
}
3 changes: 3 additions & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
id("org.jlleitschuh.gradle.ktlint")
id("dev.icerock.mobile.multiplatform-resources")
id("app.cash.sqldelight")
kotlin("plugin.serialization")
}

kotlin {
Expand Down Expand Up @@ -36,6 +37,7 @@ kotlin {

implementation("io.github.reactivecircus.cache4k:cache4k:0.12.0")

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("io.insert-koin:koin-core:3.4.0")
implementation("androidx.security:security-crypto:1.1.0-alpha06")
implementation("co.touchlab:kermit:1.2.2")
Expand All @@ -53,6 +55,7 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
implementation("io.insert-koin:koin-test:3.4.0")
implementation("app.cash.turbine:turbine:1.0.0")
implementation("app.cash.sqldelight:sqlite-driver:2.0.1")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import com.kevinschildhorn.fotopresenter.data.datasources.CredentialsDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.DirectoryDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.ImageCacheDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.ImageRemoteDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistFileDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistSQLDataSource
import com.kevinschildhorn.fotopresenter.data.repositories.CredentialsRepository
import com.kevinschildhorn.fotopresenter.data.repositories.DirectoryRepository
import com.kevinschildhorn.fotopresenter.data.repositories.ImageRepository
Expand Down Expand Up @@ -43,8 +44,9 @@ val commonModule =
single { ImageRemoteDataSource(get()) }
single { ImageRepository(get()) }
single { ImageCacheDataSource(get(), get(), baseLogger.withTag("ImageCacheDataSource")) }
single { PlaylistDataSource(get(), baseLogger.withTag("PlaylistDataSource")) }
single { PlaylistRepository(get()) }
single { PlaylistFileDataSource(baseLogger.withTag("PlaylistDataSource"), get()) }
single { PlaylistSQLDataSource(get(), baseLogger.withTag("PlaylistDataSource")) }
single { PlaylistRepository(get(), get()) }

// Domain
factory { ConnectToServerUseCase(get(), baseLogger.withTag("ConnectToServerUseCase")) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,16 @@ data class LoginCredentials(
username.isNotBlank() &&
password.isNotBlank() &&
sharedFolder.isNotBlank()

override fun toString(): String {
return """
LoginCredentials(
hostname: $hostname
username: $username
password: $password
sharedFolder: $sharedFolder
shouldAutoConnect: $shouldAutoConnect
)
""".trimIndent()
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.kevinschildhorn.fotopresenter.data

import com.kevinschildhorn.fotopresenter.PlaylistItems
import com.kevinschildhorn.fotopresenter.data.network.DefaultNetworkDirectoryDetails
import com.kevinschildhorn.fotopresenter.extension.isImagePath
import kotlinx.serialization.Serializable

@Serializable
data class PlaylistDetails(
val id: Long,
val name: String,
val items: List<PlaylistItems> = emptyList(),
){
val items: List<PlaylistItem> = emptyList(),
) {
override fun toString(): String {
return """
Playlist Details:
Expand All @@ -17,4 +17,19 @@ data class PlaylistDetails(
images: ${items.count()}
"""
}
}

@Serializable
data class PlaylistItem(
val id: Long,
val playlistId: Long,
val directoryPath: String,
val directoryId: Long,
) {
constructor(item: PlaylistItems) : this(
id = item.id,
playlistId = item.playlist_id,
directoryPath = item.directory_path,
directoryId = item.directory_id
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ Fetches Directory info from a NAS
**/
class DirectoryDataSource(
private val networkHandler: NetworkHandler,
private val logger: Logger,
private val logger: Logger?,
) {
@Throws(NetworkHandlerException::class, CancellationException::class)
suspend fun changeDirectory(directoryName: String): String {
logger.i { "Changing directory to $directoryName" }
logger.i { "Is network Connected? ${networkHandler.isConnected}" }
logger?.i { "Changing directory to $directoryName" }
logger?.i { "Is network Connected? ${networkHandler.isConnected}" }
if (!networkHandler.isConnected) throw NetworkHandlerException(NetworkHandlerError.NOT_CONNECTED)

logger.i { "Does the directory exist?" }
logger?.i { "Does the directory exist?" }
//val exists = networkHandler.folderExists(directoryName)
//logger.i { "Does the directory exist? $exists" }
//logger?.i { "Does the directory exist? $exists" }

logger.i { "Opening the directory..." }
logger?.i { "Opening the directory..." }
networkHandler.openDirectory(directoryName)?.let { return it }
throw NetworkHandlerException(NetworkHandlerError.DIRECTORY_NOT_FOUND)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.kevinschildhorn.fotopresenter.data.datasources

import co.touchlab.kermit.Logger
import com.kevinschildhorn.fotopresenter.data.PlaylistDetails
import com.kevinschildhorn.fotopresenter.data.network.NetworkHandler
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.koin.core.component.KoinComponent

class PlaylistFileDataSource(
private val logger: Logger?,
private val networkHandler: NetworkHandler,
) : KoinComponent {

suspend fun importPlaylists(): List<PlaylistDetails> =
networkHandler.getPlaylists().mapNotNull {
try {
Json.decodeFromString<PlaylistDetails>(it)
} catch (e: Exception) {
logger?.e(e) { "Error importing Playlist" }
null
}
}

suspend fun deletePlaylist(playlist: PlaylistDetails): Boolean =
try {
networkHandler.deletePlaylist(playlist.name)
true
} catch (e: Exception) {
logger?.e(e) { "Error Deleting Playlist" }
false
}

suspend fun exportPlaylist(playlist: PlaylistDetails): Boolean {
try {
val jsonString = Json.encodeToString(playlist)
networkHandler.savePlaylist(playlist.name, jsonString)
} catch (e: Exception) {
logger?.e(e) { "Error Exporting Playlists" }
return false
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import com.kevinschildhorn.fotopresenter.PlaylistItems
import com.kevinschildhorn.fotopresenter.data.Directory
import com.kevinschildhorn.fotopresenter.data.ImageDirectory
import com.kevinschildhorn.fotopresenter.data.PlaylistDetails
import com.kevinschildhorn.fotopresenter.data.PlaylistItem
import org.koin.core.component.KoinComponent

class PlaylistDataSource(
class PlaylistSQLDataSource(
driver: SqlDriver,
private val logger: Logger? = null,
) : KoinComponent {
Expand All @@ -35,10 +36,10 @@ class PlaylistDataSource(

fun getAllPlaylists(): List<PlaylistDetails> {
return try {
database.playlistQueries.selectAllPlaylists().executeAsList().map {
database.playlistQueries.selectAllPlaylists().executeAsList().map { playlist ->
val images =
database.playlistItemsQueries.selectPlaylistImages(it.id).executeAsList()
PlaylistDetails(it.id,it.name, images)
database.playlistItemsQueries.selectPlaylistImages(playlist.id).executeAsList()
PlaylistDetails(playlist.id, playlist.name, images.map { PlaylistItem(it) })
}
} catch (e: Exception) {
emptyList()
Expand All @@ -53,13 +54,27 @@ class PlaylistDataSource(
val images =
database.playlistItemsQueries.selectPlaylistImages(playList.id).executeAsList()
logger?.i { "Retrieved Playlist!" }
PlaylistDetails(playList.id, playList.name, images)
PlaylistDetails(playList.id, playList.name, images.map { PlaylistItem(it) })
} catch (e: Exception) {
null
}
}

fun insertPlaylistImage(playlistId: Long, directory: Directory): PlaylistItems? {
fun getPlaylistById(id: Long): PlaylistDetails? {
return try {
logger?.i { "Selecting playlist by id $id" }
val playList: Playlist =
database.playlistQueries.selectPlaylistById(id).executeAsOne()
val images =
database.playlistItemsQueries.selectPlaylistImages(playList.id).executeAsList()
logger?.i { "Retrieved Playlist!" }
PlaylistDetails(playList.id, playList.name, images.map { PlaylistItem(it) })
} catch (e: Exception) {
null
}
}

fun insertPlaylistImage(playlistId: Long, directory: Directory): PlaylistItem? {
logger?.i { "Inserting Playlist Image ${directory.name}" }
database.playlistItemsQueries.insertPlaylistImage(
playlist_id = playlistId,
Expand All @@ -69,14 +84,14 @@ class PlaylistDataSource(
return getPlaylistImage(playlistId, directory.details.fullPath)
}

fun getPlaylistImage(playlistId: Long, directoryPath: String): PlaylistItems? {
fun getPlaylistImage(playlistId: Long, directoryPath: String): PlaylistItem? {
return try {
logger?.i { "Selecting Playlist Image $playlistId" }
val image: PlaylistItems =
database.playlistItemsQueries.selectPlaylistImage(playlistId, directoryPath)
.executeAsOne()
logger?.i { "Selecting Playlist Image" }
image
PlaylistItem(image)
} catch (e: Exception) {
null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ interface NetworkHandler {
suspend fun openImage(path: String): SharedImage?

suspend fun folderExists(path: String): Boolean?

suspend fun savePlaylist(playlistName:String, json:String): Boolean
suspend fun getPlaylists(): List<String>

suspend fun setMetadata(json:String): Boolean
suspend fun getMetadata(): String?

suspend fun deletePlaylist(playlistName: String)
}

class NetworkHandlerException : Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,44 @@
package com.kevinschildhorn.fotopresenter.data.repositories

import com.kevinschildhorn.fotopresenter.Playlist
import com.kevinschildhorn.fotopresenter.PlaylistItems
import com.kevinschildhorn.fotopresenter.data.Directory
import com.kevinschildhorn.fotopresenter.data.ImageDirectory
import com.kevinschildhorn.fotopresenter.data.PlaylistDetails
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistDataSource
import com.kevinschildhorn.fotopresenter.data.PlaylistItem
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistFileDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.PlaylistSQLDataSource

class PlaylistRepository(
private val playlistDataSource: PlaylistDataSource,
private val playlistSQLDataSource: PlaylistSQLDataSource,
private val playlistFileDataSource: PlaylistFileDataSource,
) {

fun createPlaylist(name: String, directories: List<ImageDirectory> = emptyList()): Playlist? =
playlistDataSource.createPlaylist(name, directories)
suspend fun createPlaylist(name: String, directories: List<ImageDirectory> = emptyList()): Playlist? {
val playlist = playlistSQLDataSource.createPlaylist(name, directories)
playlistSQLDataSource.getPlaylistByName(name)?.let {
playlistFileDataSource.exportPlaylist(it)
}
return playlist
}

suspend fun getAllPlaylists(): List<PlaylistDetails> {
playlistFileDataSource.importPlaylists()
return playlistSQLDataSource.getAllPlaylists()
}

suspend fun insertPlaylistImage(playlistId: Long, directory: Directory): PlaylistItem? {
val item = playlistSQLDataSource.insertPlaylistImage(playlistId, directory)
playlistSQLDataSource.getPlaylistById(playlistId)?.let {
playlistFileDataSource.exportPlaylist(it)
}
return item
}

suspend fun deletePlaylist(id: Long): Boolean {
playlistSQLDataSource.getPlaylistById(id)?.let {
playlistFileDataSource.deletePlaylist(it)
}
return playlistSQLDataSource.deletePlaylist(id)
}

fun getAllPlaylists(): List<PlaylistDetails> =
playlistDataSource.getAllPlaylists()

fun getPlaylistByName(name: String): PlaylistDetails? =
playlistDataSource.getPlaylistByName(name)

fun insertPlaylistImage(playlistId: Long, directory: Directory): PlaylistItems? =
playlistDataSource.insertPlaylistImage(playlistId, directory)

fun getPlaylistImage(playlistId: Long, directoryPath: String): PlaylistItems? =
playlistDataSource.getPlaylistImage(playlistId, directoryPath)

fun deletePlaylist(id: Long): Boolean =
playlistDataSource.deletePlaylist(id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ConnectToServerUseCase(
) {
suspend operator fun invoke(credentials: LoginCredentials): Boolean =
try {
logger.i { "Connecting to Client" }
logger.i { "Connecting to Client ${credentials.hostname}" }
client.connect(credentials)
} catch (e: Exception) {
logger.e(e) { "Something went wrong" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class RetrieveSlideshowFromPlaylistUseCase(
logger.i { "Starting to get details from playlist ${playlistDetails.name}" }
val directories: List<ImageDirectory> = playlistDetails.items.map { item ->
val directoryDetails = DefaultNetworkDirectoryDetails(
id = item.directory_id.toInt(),
fullPath = item.directory_path
id = item.directoryId.toInt(),
fullPath = item.directoryPath
)
if (item.directory_path.isImagePath) {
if (item.directoryPath.isImagePath) {
listOf(ImageDirectory(directoryDetails))
} else {
retrieveDirectoryUseCase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class DefaultImageViewModel(private val logger: Logger? = null) : ImageViewModel
}

override fun cancelImageJobs() {
logger?.d { "Cancelling Image Jobs" }
jobs.forEach {
it.cancel()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ class DirectoryViewModel(
fun startSlideshow() {
logger.i { "Starting Slideshow" }
cancelJobs()
logger.d { "Checking for Selected Directory" }
uiState.value.selectedDirectory?.id?.let { id ->
logger.d { "Finding Folder" }
_directoryContentsState.value.folders.find { it.id == id }?.let {
logger.d { "Folder found, starting to retrieve images" }
val job = viewModelScope.launch(Dispatchers.Default) {
val retrieveImagesUseCase = UseCaseFactory.retrieveImageDirectoriesUseCase
val images = retrieveImagesUseCase(it.details)
logger.v { "Retrieved images, copying them to state" }
_uiState.update { it.copy(slideshowDetails = ImageSlideshowDetails(images)) }
}
jobs.add(job)
Expand Down Expand Up @@ -273,11 +277,13 @@ class DirectoryViewModel(
}

private fun cancelJobs() {
logger.i { "Cancelling Jobs!" }
logger.d { "Cancelling Jobs!" }
cancelImageJobs()
jobs.forEach {
it.cancel()
}
jobs.clear()
logger.v { "Finished Cancelling Jobs!" }

}
}
Loading