From e48b40535aeb15f53ea36600e24473e89ab4c38b Mon Sep 17 00:00:00 2001 From: Kevin Schildhorn Date: Fri, 11 Oct 2024 13:23:51 -0400 Subject: [PATCH 1/5] updating to use coil --- androidApp/build.gradle.kts | 2 + .../com/kevinschildhorn/MainActivity.kt | 13 +++- gradle/libs.versions.toml | 2 + shared/build.gradle.kts | 2 + .../fotopresenter/SMBJFetcher.kt | 73 +++++++++++++++++++ .../data/repositories/DirectoryRepository.kt | 4 +- .../ui/screens/directory/DirectoryScreen.kt | 8 +- .../screens/directory/DirectoryViewModel.kt | 42 +++-------- .../grid/ImageDirectoryGridCell.kt | 8 +- .../fotopresenter/data/network/SMBJHandler.kt | 1 - 10 files changed, 115 insertions(+), 40 deletions(-) create mode 100644 shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt diff --git a/androidApp/build.gradle.kts b/androidApp/build.gradle.kts index d536b274..1d80406e 100644 --- a/androidApp/build.gradle.kts +++ b/androidApp/build.gradle.kts @@ -1,4 +1,5 @@ import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.implementation import org.gradle.kotlin.dsl.java plugins { @@ -18,6 +19,7 @@ kotlin { implementation(project(":shared")) implementation(libs.koin.android) implementation(libs.firebase.crashlytics) + implementation(libs.coil) } } } diff --git a/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt b/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt index b9d912e0..3a42c8ea 100644 --- a/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt +++ b/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt @@ -4,6 +4,9 @@ import MainView import android.os.Bundle import androidx.activity.compose.setContent import androidx.appcompat.app.AppCompatActivity +import coil3.ImageLoader +import coil3.compose.setSingletonImageLoaderFactory +import com.kevinschildhorn.fotopresenter.SMBJFetcher import com.kevinschildhorn.fotopresenter.startKoin import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryViewModel import com.kevinschildhorn.fotopresenter.ui.screens.login.LoginViewModel @@ -22,8 +25,16 @@ class MainActivity : AppCompatActivity(), KoinComponent { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) startKoin(this) - + setContent { + setSingletonImageLoaderFactory { context -> + ImageLoader.Builder(context) + .components { + add(SMBJFetcher.Factory()) + } + .build() + } + MainView(loginViewModel, directoryViewModel, slideshowViewModel, playlistViewModel) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a7874c79..1f474617 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,6 +4,7 @@ agp = "8.5.2" appcompat = "1.7.0" atomik = "0.0.6" cache4k = "0.12.0" +coil = "3.0.0-rc01" core-ktx = "1.13.1" eva-icons = "1.1.0" firebase-crashlytics = "19.2.0" @@ -48,6 +49,7 @@ firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics", ve kermit = { module = "co.touchlab:kermit", version.ref = "kermit" } kermit-koin = { module = "co.touchlab:kermit-koin", version.ref = "kermit-koin" } kim = { module = "com.ashampoo:kim", version.ref = "kim" } +coil = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin-core" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin-core" } koin-test = { module = "io.insert-koin:koin-test", version.ref = "koin-test" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index dd964183..c5e78e59 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -52,6 +52,8 @@ kotlin { implementation(libs.multiplatform.settings) implementation(libs.kotlinx.datetime) implementation(libs.kim) + implementation(libs.coil) + } } val commonTest by getting { diff --git a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt new file mode 100644 index 00000000..20242768 --- /dev/null +++ b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt @@ -0,0 +1,73 @@ +package com.kevinschildhorn.fotopresenter + +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import coil3.ImageLoader +import coil3.asImage +import coil3.decode.DataSource +import coil3.fetch.FetchResult +import coil3.fetch.Fetcher +import coil3.fetch.ImageFetchResult +import coil3.request.Options +import com.hierynomus.smbj.share.File +import com.kevinschildhorn.fotopresenter.data.network.SMBJHandler +import com.kevinschildhorn.fotopresenter.ui.screens.directory.PhotoData +import com.kevinschildhorn.fotopresenter.ui.shared.getScaledDimensions +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class SMBJFetcher( + private val photoData: PhotoData, +) : Fetcher { + + override suspend fun fetch(): FetchResult? { + return withContext(Dispatchers.IO) { + if (SMBJHandler.isConnected) { + val image = SMBJHandler.openImage(path = photoData.path) + val file = image?.file + if(file != null) { + val bitmap = getBitmapFromFile(file, 256) + if (bitmap != null) { + file.close() + ImageFetchResult( + image = bitmap.asImage(), + isSampled = true, + dataSource = DataSource.NETWORK, + ) + } else { + throw Exception("Failed to fetch image from FTP") + } + } else { + throw Exception("Failed to fetch image from FTP") + } + } else { + throw Exception("Failed to fetch image from FTP") + } + } + } + + private fun getBitmapFromFile(file: File, size: Int): Bitmap? { + + val options = BitmapFactory.Options() + options.inJustDecodeBounds = true + BitmapFactory.decodeStream(file.inputStream, null, options) + + val height: Int = options.outHeight + val width: Int = options.outWidth + val dimensions = getScaledDimensions(width, height, size) + val heightRatio: Int = Math.round(height.toFloat() / dimensions.second.toFloat()) + val widthRatio: Int = Math.round(width.toFloat() / dimensions.first.toFloat()) + options.inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio + + options.inJustDecodeBounds = false + return BitmapFactory.decodeStream(file.inputStream, null, options) + } + + class Factory() : Fetcher.Factory { + override fun create( + data: PhotoData, + options: Options, + imageLoader: ImageLoader + ): Fetcher? = SMBJFetcher(data) + } +} \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/repositories/DirectoryRepository.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/repositories/DirectoryRepository.kt index 7bf66afa..e4aea211 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/repositories/DirectoryRepository.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/repositories/DirectoryRepository.kt @@ -18,7 +18,7 @@ class DirectoryRepository( val imageDirectories: List = directoryDataSource.getImageDirectories(path) - val metaData = metadataDataSource.importMetaData() + //val metaData = metadataDataSource.importMetaData() return DirectoryContents( @@ -26,7 +26,7 @@ class DirectoryRepository( images = imageDirectories.map { networkDetails -> ImageDirectory( networkDetails, - metaData = metaData.files.find { networkDetails.fullPath == it.filePath } + metaData = null,// metaData.files.find { networkDetails.fullPath == it.filePath } ) }, ) diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt index ab3ee5a1..40380317 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt @@ -69,10 +69,10 @@ fun DirectoryScreen( var overlayVisible by remember { mutableStateOf(DirectoryOverlay.NONE) } // Navigation - if (!uiState.loggedIn) onLogout() - uiState.slideshowDetails?.let { - onStartSlideshow(it) - } + //if (!uiState.loggedIn) onLogout() + //uiState.slideshowDetails?.let { + // onStartSlideshow(it) + //} //region UI Column { diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt index 4be35edf..491862a5 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt @@ -75,7 +75,7 @@ class DirectoryViewModel( //region Connection fun setLoggedIn() { - _uiState.update { it.copy(loggedIn = true) } + //_uiState.update { it.copy(loggedIn = true) } } fun logout() { @@ -85,7 +85,7 @@ class DirectoryViewModel( val logoutUseCase = UseCaseFactory.disconnectFromServerUseCase logoutUseCase() logger.d { "Setting loggedIn state to false" } - _uiState.update { it.copy(loggedIn = false) } + //_uiState.update { it.copy(loggedIn = false) } } } @@ -105,7 +105,7 @@ class DirectoryViewModel( val retrieveImagesUseCase = UseCaseFactory.retrieveImageDirectoriesUseCase val images = retrieveImagesUseCase(it.details) logger.v { "Retrieved images, copying them to state" } - _uiState.update { it.copy(slideshowDetails = ImageSlideshowDetails(images)) } + //_uiState.update { it.copy(slideshowDetails = ImageSlideshowDetails(images)) } } } } ?: run { @@ -114,7 +114,7 @@ class DirectoryViewModel( } fun clearSlideshow() { - _uiState.update { it.copy(slideshowDetails = null) } + // _uiState.update { it.copy(slideshowDetails = null) } } fun setSelectedImageById(imageId: Int?) { @@ -208,35 +208,17 @@ class DirectoryViewModel( imageScope.launch { val startTime = Clock.System.now().toEpochMilliseconds() logger.i { "Updating Photos" } - val retrieveImagesUseCase: RetrieveImageUseCase = UseCaseFactory.retrieveImageUseCase val imageDirectories: List = imageUiState.value.imageDirectories imageDirectories.mapIndexed { index, imageDirectory -> - async { - retrieveImagesUseCase( - imageDirectory, - imageSize = 512, // TODO: Change - )?.let { newImage -> - logger.i { "Downloaded Image at index $index" } - downloadedImageSet.add(index) - - _uiState.update { - it.copyImageState( - imageDirectory.id, - state = State.SUCCESS(newImage), - ).copy( - currentImageCount = downloadedImageSet.size - ) - } - - if (_uiState.value.currentImageCount == _uiState.value.totalImageCount) { - val endTime = Clock.System.now().toEpochMilliseconds() - val difference: Float = (endTime.toFloat() - startTime.toFloat()) / 1000 - logger.i { "Downloading all images took $difference seconds" } - } - } + _uiState.update { + it.copyImageState( + imageDirectory.id, + state = State.SUCCESS(PhotoData(imageDirectory.details.fullPath)), + ).copy( + currentImageCount = downloadedImageSet.size + ) } - }.awaitAll() - + } // TODO: STORE LARGEST IMAGES IN CHUNKS } } diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt index 5b1fc4f2..ab3b6b0a 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt @@ -12,6 +12,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp +import coil3.compose.AsyncImage +import coil3.compose.LocalPlatformContext +import coil3.request.ImageRequest import com.kevinschildhorn.fotopresenter.ui.atoms.fotoColors import com.kevinschildhorn.fotopresenter.ui.screens.directory.ImageDirectoryGridCellState import compose.icons.EvaIcons @@ -23,10 +26,11 @@ fun ImageDirectoryGridCell( imageContent: ImageDirectoryGridCellState, modifier: Modifier = Modifier, ) { + DirectoryGridCell(modifier) { imageContent.imageState.onSuccess { - Image( - bitmap = it, + AsyncImage( + model = it, contentDescription = imageContent.name, contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize().background(fotoColors.surface), diff --git a/shared/src/jvmMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/SMBJHandler.kt b/shared/src/jvmMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/SMBJHandler.kt index 63033d22..9f7aa7c0 100644 --- a/shared/src/jvmMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/SMBJHandler.kt +++ b/shared/src/jvmMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/SMBJHandler.kt @@ -107,7 +107,6 @@ object SMBJHandler : NetworkHandler { override suspend fun openImage(path: String): SharedImage? = getFile(path)?.let { val sharedImage = SharedImage(it) - it.close() sharedImage } ?: run { null } From 9356282646cb2c0e6e02973415c8cd1b192ec252 Mon Sep 17 00:00:00 2001 From: Kevin Schildhorn Date: Fri, 11 Oct 2024 13:26:21 -0400 Subject: [PATCH 2/5] cleaning up --- .../ui/screens/directory/DirectoryViewModel.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt index 491862a5..42209d32 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt @@ -6,13 +6,11 @@ import com.kevinschildhorn.fotopresenter.data.Directory import com.kevinschildhorn.fotopresenter.data.DirectoryContents import com.kevinschildhorn.fotopresenter.data.FolderDirectory import com.kevinschildhorn.fotopresenter.data.ImageDirectory -import com.kevinschildhorn.fotopresenter.data.ImageSlideshowDetails import com.kevinschildhorn.fotopresenter.data.MetadataFileDetails import com.kevinschildhorn.fotopresenter.data.PlaylistDetails import com.kevinschildhorn.fotopresenter.data.State import com.kevinschildhorn.fotopresenter.data.network.NetworkHandlerException import com.kevinschildhorn.fotopresenter.data.repositories.PlaylistRepository -import com.kevinschildhorn.fotopresenter.domain.image.RetrieveImageUseCase import com.kevinschildhorn.fotopresenter.extension.addPath import com.kevinschildhorn.fotopresenter.extension.navigateBackToPathAtIndex import com.kevinschildhorn.fotopresenter.ui.SortingType @@ -23,10 +21,7 @@ import com.kevinschildhorn.fotopresenter.ui.screens.common.ImageViewModel import com.kevinschildhorn.fotopresenter.ui.screens.playlist.PlaylistViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll import kotlinx.coroutines.cancelChildren -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -37,7 +32,7 @@ import kotlinx.datetime.Clock import org.koin.core.component.KoinComponent class DirectoryViewModel( - private val playlistRepository: PlaylistRepository, + playlistRepository: PlaylistRepository, private val logger: Logger, ) : PlaylistViewModel(playlistRepository, logger), ImageViewModel by DefaultImageViewModel(logger), @@ -60,7 +55,6 @@ class DirectoryViewModel( val actionSheetContexts: List get() = uiState.value.selectedDirectory?.actionSheetContexts ?: emptyList() - val selectedMetadata: MetadataFileDetails? get() = findSelectedImageDirectory()?.metaData @@ -114,7 +108,7 @@ class DirectoryViewModel( } fun clearSlideshow() { - // _uiState.update { it.copy(slideshowDetails = null) } + // _uiState.update { it.copy(slideshowDetails = null) } } fun setSelectedImageById(imageId: Int?) { From 20d82a8bc0a04f2cd593c1a56f5f08c95b0ded1d Mon Sep 17 00:00:00 2001 From: Kevin Schildhorn Date: Fri, 11 Oct 2024 14:24:51 -0400 Subject: [PATCH 3/5] Getting Fetcher working --- .../fotopresenter/SMBJFetcher.kt | 28 +++++-- .../ui/compose/DirectoryPreviews.kt | 13 ++-- shared/src/commonMain/kotlin/App.kt | 1 - .../data/network/NetworkDirectoryDetails.kt | 6 ++ .../RetrieveDirectoryContentsUseCase.kt | 18 +---- .../ui/screens/directory/DirectoryScreen.kt | 21 +---- .../screens/directory/DirectoryScreenState.kt | 77 ++++--------------- .../screens/directory/DirectoryViewModel.kt | 64 ++++----------- .../composables/grid/DirectoryGrid.kt | 24 +++--- .../grid/FolderDirectoryGridCell.kt | 6 +- .../grid/ImageDirectoryGridCell.kt | 53 ++----------- 11 files changed, 87 insertions(+), 224 deletions(-) diff --git a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt index 20242768..0ed96bad 100644 --- a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt +++ b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt @@ -1,5 +1,6 @@ package com.kevinschildhorn.fotopresenter +import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import coil3.ImageLoader @@ -10,23 +11,34 @@ import coil3.fetch.Fetcher import coil3.fetch.ImageFetchResult import coil3.request.Options import com.hierynomus.smbj.share.File +import com.kevinschildhorn.fotopresenter.data.datasources.ImageCacheDataSource +import com.kevinschildhorn.fotopresenter.data.network.NetworkDirectoryDetails import com.kevinschildhorn.fotopresenter.data.network.SMBJHandler -import com.kevinschildhorn.fotopresenter.ui.screens.directory.PhotoData +import com.kevinschildhorn.fotopresenter.ui.shared.DriverFactory +import com.kevinschildhorn.fotopresenter.ui.shared.SharedCache import com.kevinschildhorn.fotopresenter.ui.shared.getScaledDimensions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class SMBJFetcher( - private val photoData: PhotoData, + private val directoryDetails: NetworkDirectoryDetails, + context: Context, ) : Fetcher { + val imageCacheDataSource = ImageCacheDataSource( + cache = SharedCache, + driver = DriverFactory(context).createDriver(), + logger = baseLogger.withTag("ImageCacheDataSource") + ) + override suspend fun fetch(): FetchResult? { return withContext(Dispatchers.IO) { + imageCacheDataSource.getImage(directoryDetails) if (SMBJHandler.isConnected) { - val image = SMBJHandler.openImage(path = photoData.path) + val image = SMBJHandler.openImage(path = directoryDetails.fullPath) val file = image?.file - if(file != null) { - val bitmap = getBitmapFromFile(file, 256) + if (file != null) { + val bitmap = getBitmapFromFile(file, 64) if (bitmap != null) { file.close() ImageFetchResult( @@ -63,11 +75,11 @@ class SMBJFetcher( return BitmapFactory.decodeStream(file.inputStream, null, options) } - class Factory() : Fetcher.Factory { + class Factory() : Fetcher.Factory { override fun create( - data: PhotoData, + data: NetworkDirectoryDetails, options: Options, imageLoader: ImageLoader - ): Fetcher? = SMBJFetcher(data) + ): Fetcher? = SMBJFetcher(data, options.context) } } \ No newline at end of file diff --git a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/ui/compose/DirectoryPreviews.kt b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/ui/compose/DirectoryPreviews.kt index 630aad00..d6fddee5 100644 --- a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/ui/compose/DirectoryPreviews.kt +++ b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/ui/compose/DirectoryPreviews.kt @@ -3,13 +3,14 @@ package com.kevinschildhorn.fotopresenter.ui.compose import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview -import com.kevinschildhorn.fotopresenter.data.State +import com.kevinschildhorn.fotopresenter.data.network.DefaultNetworkDirectoryDetails +import com.kevinschildhorn.fotopresenter.data.network.MockNetworkDirectoryDetails +import com.kevinschildhorn.fotopresenter.data.network.NetworkDirectoryDetails +import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridCellState import com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.grid.DirectoryGridCell import com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.grid.DirectoryGrid import com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.grid.FolderDirectoryGridCell import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridState -import com.kevinschildhorn.fotopresenter.ui.screens.directory.FolderDirectoryGridCellState -import com.kevinschildhorn.fotopresenter.ui.screens.directory.ImageDirectoryGridCellState import com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.navbar.DirectoryNavigationBar import com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.navbar.DirectoryNavigationItem @@ -25,7 +26,7 @@ fun BaseDirectoryPreview() { @Composable fun FolderDirectoryEmptyPreview() { Column { - FolderDirectoryGridCell(FolderDirectoryGridCellState("Hello",0)) + FolderDirectoryGridCell(DirectoryGridCellState.Folder("Hello",0)) } } @@ -35,10 +36,10 @@ fun DirectoryGridPreview() { DirectoryGrid( directoryContent = DirectoryGridState( folderStates = listOf( - FolderDirectoryGridCellState("Hello",0), + DirectoryGridCellState.Folder("Hello",0), ), imageStates = mutableListOf( - ImageDirectoryGridCellState(State.IDLE,"Hello", 1) + DirectoryGridCellState.Image(MockNetworkDirectoryDetails(),"Hello", 1) ) ), onFolderPressed = {}, diff --git a/shared/src/commonMain/kotlin/App.kt b/shared/src/commonMain/kotlin/App.kt index e0d2632c..aed9a377 100644 --- a/shared/src/commonMain/kotlin/App.kt +++ b/shared/src/commonMain/kotlin/App.kt @@ -35,7 +35,6 @@ fun App( typography = FotoTypography(), shapes = fotoShapes, ) { - Scaffold { innerPadding -> NavHost( navController = navController, diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/NetworkDirectoryDetails.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/NetworkDirectoryDetails.kt index 40cb6568..5a9fd98f 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/NetworkDirectoryDetails.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/data/network/NetworkDirectoryDetails.kt @@ -28,3 +28,9 @@ class DefaultNetworkDirectoryDetails( override val id: Int, override val dateMillis: Long = Clock.System.now().toEpochMilliseconds() ) : NetworkDirectoryDetails + +class MockNetworkDirectoryDetails( + override val fullPath: String = "", + override val id: Int = 0, + override val dateMillis: Long = Clock.System.now().toEpochMilliseconds() +) : NetworkDirectoryDetails diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/domain/RetrieveDirectoryContentsUseCase.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/domain/RetrieveDirectoryContentsUseCase.kt index a50bec8d..8f88a152 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/domain/RetrieveDirectoryContentsUseCase.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/domain/RetrieveDirectoryContentsUseCase.kt @@ -18,22 +18,6 @@ class RetrieveDirectoryContentsUseCase( ) { suspend operator fun invoke(path: String): DirectoryContents { logger.i { "Getting directory Contents at path $path" } - val directoryContents = directoryRepository.getDirectoryContents(path) - return directoryContents.updateImages { - logger.i { "Updating Image File ${it.name}" } - imageRepository.getImage(it) - } + return directoryRepository.getDirectoryContents(path) } } - -private suspend fun DirectoryContents.updateImages(block: suspend (NetworkDirectoryDetails) -> SharedImage?): DirectoryContents = - this.copy( - images = - images.map { - ImageDirectory( - it.details, - it.metaData, - image = block(it.details) - ) - }, - ) diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt index 6fc74670..18def33b 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreen.kt @@ -58,6 +58,7 @@ enum class DirectoryOverlay { fun DirectoryScreen( viewModel: DirectoryViewModel, onLogout: () -> Unit, + onStartSlideshow: (ImageSlideshowDetails) -> Unit, onShowPlaylists: () -> Unit, ) { LaunchedEffect(Unit) { @@ -97,24 +98,6 @@ fun DirectoryScreen( }, modifier = Modifier.padding(Padding.SMALL.dp) ) - if (uiState.imageCountString.isNotEmpty()) { - Text( - uiState.imageCountString, - modifier = Modifier.fillMaxWidth(), - textAlign = TextAlign.Center, - style = FotoTypography().caption, - color = fotoColors.onBackground, - ) - LinearProgressIndicator( - progress = uiState.currentImageCount.toFloat() / uiState.totalImageCount.toFloat(), - modifier = Modifier.fillMaxWidth() - .height(25.dp) - .padding(horizontal = Padding.EXTRA_LARGE.dp, vertical = Padding.SMALL.dp) - .clip(RoundedCornerShape(5.dp)), - color = fotoColors.primary, - ) - - } DirectoryGrid( uiState.directoryGridState, onFolderPressed = { @@ -143,6 +126,7 @@ fun DirectoryScreen( when (it.action) { ActionSheetAction.START_SLIDESHOW -> { viewModel.startSlideshow() + onStartSlideshow(uiState.slideshowDetails!!) overlayVisible = DirectoryOverlay.NONE viewModel.setSelectedDirectory(null) } @@ -217,6 +201,7 @@ fun DirectoryScreen( }, onConfirmation = { viewModel.logout() + onLogout() overlayVisible = DirectoryOverlay.NONE }, ) diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt index f2ee82b1..d7e4e6e0 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt @@ -1,8 +1,7 @@ package com.kevinschildhorn.fotopresenter.ui.screens.directory -import androidx.compose.ui.graphics.ImageBitmap import com.kevinschildhorn.fotopresenter.data.ImageSlideshowDetails -import com.kevinschildhorn.fotopresenter.data.State +import com.kevinschildhorn.fotopresenter.data.network.NetworkDirectoryDetails import com.kevinschildhorn.fotopresenter.ui.SortingType import com.kevinschildhorn.fotopresenter.ui.UiState import com.kevinschildhorn.fotopresenter.ui.screens.common.ActionSheetAction @@ -14,49 +13,20 @@ data class DirectoryScreenState( var directoryGridState: DirectoryGridState = DirectoryGridState(emptyList(), mutableListOf()), val slideshowDetails: ImageSlideshowDetails? = null, val selectedDirectory: DirectoryGridCellState? = null, - val currentImageCount: Int = 0, - val totalImageCount: Int = 0, val sortingType: SortingType = SortingType.NAME_ASC, override val state: UiState = UiState.IDLE, ) : ScreenState { - fun copyImageState( - id: Int, - state: State, - ): DirectoryScreenState { - val list = directoryGridState.imageStates.toMutableList() - val index = list.indexOfFirst { it.id == id } - if (index != -1) { - val element = list[index] - list[index] = - element.copy( - imageState = state, - ) - } - return this.copy( - directoryGridState = - directoryGridState.copy( - imageStates = list, - ), - ) - } fun getImageIndexFromId(id: Int): Int = directoryGridState.imageStates.indexOfFirst { it.id == id } val currentPathList: List get() = currentPath.split("\\").filter { it.isNotEmpty() } - - val imageCountString: String - get() = - if (totalImageCount != 0 && currentImageCount < totalImageCount) - "$currentImageCount of $totalImageCount downloaded" - else "" - } data class DirectoryGridState( - val folderStates: List, - val imageStates: List, + val folderStates: List, + val imageStates: List, ) { val allStates: List get() = folderStates + imageStates @@ -71,41 +41,24 @@ data class DirectoryGridState( """ } -data class FolderDirectoryGridCellState( - override val name: String, - override val id: Int, -) : DirectoryGridCellState { - override val actionSheetContexts: List - get() = listOf( +sealed class DirectoryGridCellState( + val name: String, + val id: Int, + val actionSheetContexts: List + +) { + class Folder(name: String, id: Int) : DirectoryGridCellState( + name, id, listOf( ActionSheetContext(ActionSheetAction.START_SLIDESHOW, 1), ActionSheetContext(ActionSheetAction.ADD_DYNAMIC_LOCATION, 2), ) + ) - override fun toString(): String = "(F:$name:$id)" -} - -data class ImageDirectoryGridCellState( - val imageState: State, - override val name: String, - override val id: Int, -) : DirectoryGridCellState { - override val actionSheetContexts: List - get() = listOf( + class Image(val directoryDetails: NetworkDirectoryDetails, name: String, id: Int) : DirectoryGridCellState( + name, id, listOf( ActionSheetContext(ActionSheetAction.ADD_STATIC_LOCATION, 1), ActionSheetContext(ActionSheetAction.ADD_METADATA, 2), ) - + ) override fun toString(): String = "(I:$name:$id)" } - -interface DirectoryGridCellState { - val name: String - val id: Int - val actionSheetContexts: List - - val isFolderGridCell: Boolean - get() = (this is FolderDirectoryGridCellState) - - val isImageGridCell: Boolean - get() = (this is ImageDirectoryGridCellState) -} diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt index 0bd7134b..62a6cd77 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryViewModel.kt @@ -8,7 +8,6 @@ import com.kevinschildhorn.fotopresenter.data.FolderDirectory import com.kevinschildhorn.fotopresenter.data.ImageDirectory import com.kevinschildhorn.fotopresenter.data.MetadataFileDetails import com.kevinschildhorn.fotopresenter.data.PlaylistDetails -import com.kevinschildhorn.fotopresenter.data.State import com.kevinschildhorn.fotopresenter.data.network.NetworkHandlerException import com.kevinschildhorn.fotopresenter.data.repositories.PlaylistRepository import com.kevinschildhorn.fotopresenter.extension.addPath @@ -28,7 +27,6 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.coroutines.plus -import kotlinx.datetime.Clock import org.koin.core.component.KoinComponent class DirectoryViewModel( @@ -41,14 +39,10 @@ class DirectoryViewModel( private val slideshowScope: CoroutineScope = viewModelScope + Dispatchers.IO private val imageScope: CoroutineScope = viewModelScope + Dispatchers.IO + private val _directoryContentsState = MutableStateFlow(DirectoryContents()) private val _uiState = MutableStateFlow(DirectoryScreenState()) val uiState: StateFlow = _uiState.asStateFlow() - private val _directoryContentsState = MutableStateFlow(DirectoryContents()) - - // Indexes of all Downloaded images - private val downloadedImageSet: MutableSet = mutableSetOf() - private val currentPath: String get() = uiState.value.currentPath @@ -102,7 +96,7 @@ class DirectoryViewModel( } fun clearSlideshow() { - // _uiState.update { it.copy(slideshowDetails = null) } + _uiState.update { it.copy(slideshowDetails = null) } } fun setSelectedImageById(imageId: Int?) { @@ -140,7 +134,7 @@ class DirectoryViewModel( logger.i { "Changing directory to path $path" } cancelJobs() - slideshowScope.launch(Dispatchers.Default) { + viewModelScope.launch(Dispatchers.Default) { val changeDirectoryUseCase = UseCaseFactory.changeDirectoryUseCase try { logger.i { "Getting New Path" } @@ -152,21 +146,13 @@ class DirectoryViewModel( logger.e(e) { "Error Occurred Getting new path" } _uiState.update { it.copy( - state = - UiState.ERROR( - e.message ?: "An Unknown Network Error Occurred", - ), + state = UiState.ERROR(e.message ?: "An Unknown Network Error Occurred"), ) } } catch (e: Exception) { logger.e(e) { "Something went wrong" } _uiState.update { - it.copy( - state = - UiState.ERROR( - e.message ?: "Something Went Wrong", - ), - ) + it.copy(state = UiState.ERROR(e.message ?: "Something Went Wrong")) } } } @@ -185,29 +171,6 @@ class DirectoryViewModel( updateGrid() logger.i { "Current State ${uiState.value.state}" } - updatePhotos() - } - } - - private fun updatePhotos() { - val count = imageUiState.value.imageDirectories.count() - downloadedImageSet.clear() - _uiState.update { it.copy(totalImageCount = count, currentImageCount = 0) } - imageScope.launch { - val startTime = Clock.System.now().toEpochMilliseconds() - logger.i { "Updating Photos" } - val imageDirectories: List = imageUiState.value.imageDirectories - imageDirectories.mapIndexed { index, imageDirectory -> - _uiState.update { - it.copyImageState( - imageDirectory.id, - state = State.SUCCESS(PhotoData(imageDirectory.details.fullPath)), - ).copy( - currentImageCount = downloadedImageSet.size - ) - } - } - // TODO: STORE LARGEST IMAGES IN CHUNKS } } @@ -228,11 +191,15 @@ class DirectoryViewModel( private val DirectoryContents.asDirectoryGridState: DirectoryGridState get() = DirectoryGridState( - folderStates = this.folders.map { FolderDirectoryGridCellState(it.name, it.id) }, - imageStates = - this.images.map { - ImageDirectoryGridCellState( - State.IDLE, + folderStates = folders.map { + DirectoryGridCellState.Folder( + it.name, + it.id + ) + }, + imageStates = images.map { + DirectoryGridCellState.Image( + it.details, it.name, it.id, ) @@ -249,7 +216,7 @@ class DirectoryViewModel( logger.i { "Inserting Playlist Image ${playlist.id} as ${uiState.value.selectedDirectory}" } val states: List = - if (selectedDirectory.isImageGridCell) this.images + if (selectedDirectory is DirectoryGridCellState.Image) this.images else this.folders states.find { it.id == selectedDirectory.id } @@ -288,7 +255,6 @@ class DirectoryViewModel( slideshowScope.coroutineContext.cancelChildren() imageScope.coroutineContext.cancelChildren() logger.v { "Finished Cancelling Jobs!" } - } private fun findSelectedFolderDirectory(): FolderDirectory? = diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/DirectoryGrid.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/DirectoryGrid.kt index 366b8702..1cf3745e 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/DirectoryGrid.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/DirectoryGrid.kt @@ -17,8 +17,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridCellState import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridState -import com.kevinschildhorn.fotopresenter.ui.screens.directory.FolderDirectoryGridCellState -import com.kevinschildhorn.fotopresenter.ui.screens.directory.ImageDirectoryGridCellState @OptIn(ExperimentalFoundationApi::class) @Composable @@ -44,7 +42,8 @@ fun DirectoryGrid( awaitPointerEventScope { val event = awaitPointerEvent() if (event.type == PointerEventType.Press && - event.buttons.isSecondaryPressed) { + event.buttons.isSecondaryPressed + ) { event.changes.forEach { e -> e.consume() } onActionSheet(state) } @@ -52,10 +51,9 @@ fun DirectoryGrid( } .combinedClickable( onClick = { - (state as? ImageDirectoryGridCellState)?.let { imageContent -> - onImageDirectoryPressed(imageContent.id) - } ?: run { - onFolderPressed(state.id) + when (state) { + is DirectoryGridCellState.Folder -> onFolderPressed(state.id) + is DirectoryGridCellState.Image -> onImageDirectoryPressed(state.id) } }, onLongClick = { @@ -64,15 +62,13 @@ fun DirectoryGrid( }, onLongClickLabel = "Action Sheet", ) - (state as? FolderDirectoryGridCellState)?.let { folderContent -> - FolderDirectoryGridCell( - folderContent, + when (state) { + is DirectoryGridCellState.Folder -> FolderDirectoryGridCell( + state, modifier = directoryItemModifier, ) - } - (state as? ImageDirectoryGridCellState)?.let { imageContent -> - ImageDirectoryGridCell( - imageContent, + is DirectoryGridCellState.Image -> ImageDirectoryGridCell( + state, modifier = directoryItemModifier, ) } diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/FolderDirectoryGridCell.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/FolderDirectoryGridCell.kt index e244af3e..7457d889 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/FolderDirectoryGridCell.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/FolderDirectoryGridCell.kt @@ -6,21 +6,19 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.Icon -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Edit import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.kevinschildhorn.fotopresenter.ui.atoms.fotoColors -import com.kevinschildhorn.fotopresenter.ui.screens.directory.FolderDirectoryGridCellState +import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridCellState import compose.icons.EvaIcons import compose.icons.evaicons.Fill import compose.icons.evaicons.fill.Folder @Composable fun FolderDirectoryGridCell( - folderState: FolderDirectoryGridCellState, + folderState: DirectoryGridCellState, modifier: Modifier = Modifier, ) { DirectoryGridCell(modifier) { diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt index ab3b6b0a..566d3f72 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/composables/grid/ImageDirectoryGridCell.kt @@ -1,62 +1,25 @@ package com.kevinschildhorn.fotopresenter.ui.screens.directory.composables.grid -import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.material.CircularProgressIndicator import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import coil3.compose.LocalPlatformContext -import coil3.request.ImageRequest import com.kevinschildhorn.fotopresenter.ui.atoms.fotoColors -import com.kevinschildhorn.fotopresenter.ui.screens.directory.ImageDirectoryGridCellState -import compose.icons.EvaIcons -import compose.icons.evaicons.Fill -import compose.icons.evaicons.fill.QuestionMark +import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridCellState @Composable fun ImageDirectoryGridCell( - imageContent: ImageDirectoryGridCellState, + imageContent: DirectoryGridCellState.Image, modifier: Modifier = Modifier, ) { - DirectoryGridCell(modifier) { - imageContent.imageState.onSuccess { - AsyncImage( - model = it, - contentDescription = imageContent.name, - contentScale = ContentScale.Crop, - modifier = Modifier.fillMaxSize().background(fotoColors.surface), - ) - }.onError { - Column( - modifier = - Modifier - .fillMaxSize() - .padding(5.dp), - ) { - Image( - imageVector = EvaIcons.Fill.QuestionMark, - contentDescription = "Question Mark", - modifier = Modifier.align(Alignment.CenterHorizontally), - ) - DirectoryGridCellText( - imageContent.name, - modifier = Modifier.align(Alignment.CenterHorizontally), - ) - } - }.onLoading { - CircularProgressIndicator( - modifier = Modifier.width(33.dp).align(Alignment.Center), - color = fotoColors.primary, - ) - } + AsyncImage( + model = imageContent.directoryDetails, + contentDescription = imageContent.name, + contentScale = ContentScale.Crop, + modifier = Modifier.fillMaxSize().background(fotoColors.surface), + ) } } From 1ad69363cf9e365fcb9713f483888cce6cb957a0 Mon Sep 17 00:00:00 2001 From: Kevin Schildhorn Date: Fri, 11 Oct 2024 14:30:46 -0400 Subject: [PATCH 4/5] updating code --- .../kotlin/com/kevinschildhorn/MainActivity.kt | 5 ++++- .../kevinschildhorn/fotopresenter/SMBJFetcher.kt | 16 +++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt b/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt index 3a42c8ea..9a0a6233 100644 --- a/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt +++ b/androidApp/src/androidMain/kotlin/com/kevinschildhorn/MainActivity.kt @@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity import coil3.ImageLoader import coil3.compose.setSingletonImageLoaderFactory import com.kevinschildhorn.fotopresenter.SMBJFetcher +import com.kevinschildhorn.fotopresenter.data.network.NetworkHandler import com.kevinschildhorn.fotopresenter.startKoin import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryViewModel import com.kevinschildhorn.fotopresenter.ui.screens.login.LoginViewModel @@ -14,6 +15,7 @@ import com.kevinschildhorn.fotopresenter.ui.screens.playlist.PlaylistViewModel import com.kevinschildhorn.fotopresenter.ui.screens.slideshow.SlideshowViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.component.KoinComponent +import org.koin.core.component.inject class MainActivity : AppCompatActivity(), KoinComponent { @@ -21,6 +23,7 @@ class MainActivity : AppCompatActivity(), KoinComponent { private val directoryViewModel by viewModel() private val slideshowViewModel by viewModel() private val playlistViewModel by viewModel() + private val networkHandler: NetworkHandler by inject() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,7 +33,7 @@ class MainActivity : AppCompatActivity(), KoinComponent { setSingletonImageLoaderFactory { context -> ImageLoader.Builder(context) .components { - add(SMBJFetcher.Factory()) + add(SMBJFetcher.Factory(networkHandler)) } .build() } diff --git a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt index 0ed96bad..30e7299c 100644 --- a/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt +++ b/shared/src/androidMain/kotlin/com/kevinschildhorn/fotopresenter/SMBJFetcher.kt @@ -13,15 +13,17 @@ import coil3.request.Options import com.hierynomus.smbj.share.File import com.kevinschildhorn.fotopresenter.data.datasources.ImageCacheDataSource import com.kevinschildhorn.fotopresenter.data.network.NetworkDirectoryDetails -import com.kevinschildhorn.fotopresenter.data.network.SMBJHandler +import com.kevinschildhorn.fotopresenter.data.network.NetworkHandler import com.kevinschildhorn.fotopresenter.ui.shared.DriverFactory import com.kevinschildhorn.fotopresenter.ui.shared.SharedCache import com.kevinschildhorn.fotopresenter.ui.shared.getScaledDimensions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import kotlin.math.roundToInt class SMBJFetcher( private val directoryDetails: NetworkDirectoryDetails, + private val networkHandler: NetworkHandler, context: Context, ) : Fetcher { @@ -34,8 +36,8 @@ class SMBJFetcher( override suspend fun fetch(): FetchResult? { return withContext(Dispatchers.IO) { imageCacheDataSource.getImage(directoryDetails) - if (SMBJHandler.isConnected) { - val image = SMBJHandler.openImage(path = directoryDetails.fullPath) + if (networkHandler.isConnected) { + val image = networkHandler.openImage(path = directoryDetails.fullPath) val file = image?.file if (file != null) { val bitmap = getBitmapFromFile(file, 64) @@ -67,19 +69,19 @@ class SMBJFetcher( val height: Int = options.outHeight val width: Int = options.outWidth val dimensions = getScaledDimensions(width, height, size) - val heightRatio: Int = Math.round(height.toFloat() / dimensions.second.toFloat()) - val widthRatio: Int = Math.round(width.toFloat() / dimensions.first.toFloat()) + val heightRatio: Int = (height.toFloat() / dimensions.second.toFloat()).roundToInt() + val widthRatio: Int = (width.toFloat() / dimensions.first.toFloat()).roundToInt() options.inSampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio options.inJustDecodeBounds = false return BitmapFactory.decodeStream(file.inputStream, null, options) } - class Factory() : Fetcher.Factory { + class Factory(private val networkHandler: NetworkHandler) : Fetcher.Factory { override fun create( data: NetworkDirectoryDetails, options: Options, imageLoader: ImageLoader - ): Fetcher? = SMBJFetcher(data, options.context) + ): Fetcher? = SMBJFetcher(data, networkHandler, options.context) } } \ No newline at end of file From 68906d5fe3d17f2a3433578522263784da002ff4 Mon Sep 17 00:00:00 2001 From: Kevin Schildhorn Date: Fri, 11 Oct 2024 14:32:47 -0400 Subject: [PATCH 5/5] Update DirectoryScreenState.kt --- .../ui/screens/directory/DirectoryScreenState.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt index d7e4e6e0..9d717074 100644 --- a/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt +++ b/shared/src/commonMain/kotlin/com/kevinschildhorn/fotopresenter/ui/screens/directory/DirectoryScreenState.kt @@ -25,8 +25,8 @@ data class DirectoryScreenState( } data class DirectoryGridState( - val folderStates: List, - val imageStates: List, + val folderStates: List, + val imageStates: List, ) { val allStates: List get() = folderStates + imageStates