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

Ks/updating logging #60

Merged
merged 5 commits into from
Dec 12, 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
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
package com.kevinschildhorn

import MainView
import android.Manifest
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import co.touchlab.kermit.Logger
import coil3.ImageLoader
import coil3.compose.setSingletonImageLoaderFactory
import coil3.disk.DiskCache
import coil3.disk.directory
import coil3.memory.MemoryCache
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberPermissionState
import com.kevinschildhorn.fotopresenter.baseLogger
import com.kevinschildhorn.fotopresenter.data.network.SMBJHandler
import com.kevinschildhorn.fotopresenter.data.repositories.ImageRepository
import com.kevinschildhorn.fotopresenter.extension.logLargeTitle
import com.kevinschildhorn.fotopresenter.startKoin
import com.kevinschildhorn.fotopresenter.ui.ByteArrayFetcher
import com.kevinschildhorn.fotopresenter.ui.SMBJFetcher
Expand All @@ -39,18 +34,20 @@ class MainActivity : AppCompatActivity(), KoinComponent {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startKoin(this)
val logger = Logger.withTag("MainActivity")
logger.logLargeTitle("App has started")

setContent {

setSingletonImageLoaderFactory { context ->
ImageLoader.Builder(context)
.components {
add(SMBJFetcher.Factory(imageRepository, baseLogger))
add(ByteArrayFetcher.Factory(Logger.withTag("ByteArrayFetcher")))
add(SMBJFetcher.Factory(imageRepository, Logger))
add(ByteArrayFetcher.Factory(Logger))
}
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(context,0.25)
.maxSizePercent(context, 0.25)
.build()
}
.diskCache {
Expand Down
4 changes: 2 additions & 2 deletions desktopApp/src/jvmMain/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ fun main() = application {
setSingletonImageLoaderFactory { context ->
ImageLoader.Builder(context)
.components {
add(SMBJFetcher.Factory(imageRepository, Logger.withTag("SMBJFetcher")))
add(ByteArrayFetcher.Factory(Logger.withTag("ByteArrayFetcher")))
add(SMBJFetcher.Factory(imageRepository, baseLogger))
add(ByteArrayFetcher.Factory(baseLogger))
}
.build()
}
Expand Down
37 changes: 19 additions & 18 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
[versions]
accompanistPermissions = "0.36.0"
activity-compose = "1.9.2"
activity-compose = "1.9.3"
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"
coil = "3.0.4"
core-ktx = "1.15.0"
eva-icons = "1.1.0"
fileKache = "2.1.0"
firebase-crashlytics = "19.2.0"
kermit = "2.0.4"
kermit-koin = "1.2.2"
firebase-crashlytics = "19.3.0"
kermit = "2.0.5"
kermit-koin = "2.0.4"
kim = "0.8.3"
koin-core = "3.5.3"
koin-test = "3.4.0"
kotlin = "2.0.10"
koin-core = "4.0.0"
koin-test = "3.5.3"
kotlin = "2.1.0"
crashlytics = "3.0.2"
google-services = "4.4.2"
kotlinx-datetime = "0.6.0"
kotlinx-datetime = "0.6.1"
kotlinx-serialization-json = "1.7.3"
kotlinx-coroutines = "1.9.0"
ktlint = "0.0.26"
ktlint-plugin = "12.1.1"
multiplatform-settings = "1.1.1"
multiplatform-settings-test = "1.0.0"
multiplatform-settings = "1.2.0"
multiplatform-settings-test = "1.2.0"
navigationCompose = "2.7.0-alpha07"
resources-version = "0.23.0"
security-crypto = "1.1.0-alpha06"
smbj = "0.11.5"
sqldelight = "2.0.2"
resources = "0.23.0"
compose = "1.6.11"
sqlite-driver = "2.0.1"
turbine = "1.0.0"
compose = "1.7.1"
sqlite-driver = "2.0.2"
turbine = "1.2.0"

## SDK Versions
minSdk = "29"
targetSdk = "34"
compileSdk = "34"
targetSdk = "35"
compileSdk = "35"
java = "21"

[libraries]
Expand All @@ -58,7 +59,7 @@ 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" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-serialization-json" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
ktlint = { module = "com.twitter.compose.rules:ktlint", version.ref = "ktlint" }
Expand Down
6 changes: 6 additions & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,9 @@ sqldelight {
}
}
}

compose.resources {
publicResClass = false
packageOfResClass = "com.kevinschildhorn.fotopresenter"
generateResClass = auto
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import android.content.Context
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import app.cash.sqldelight.db.SqlDriver
import co.touchlab.kermit.Logger
import co.touchlab.kermit.koin.kermitLoggerModule
import com.kevinschildhorn.fotopresenter.data.datasources.CredentialsDataSource
import com.kevinschildhorn.fotopresenter.data.network.NetworkHandler
import com.kevinschildhorn.fotopresenter.data.network.SMBJHandler
import com.kevinschildhorn.fotopresenter.ui.shared.CacheInterface
import com.kevinschildhorn.fotopresenter.ui.shared.DriverFactory
import com.kevinschildhorn.fotopresenter.ui.shared.SharedFileCache
import com.russhwolf.settings.Settings
import com.russhwolf.settings.SharedPreferencesSettings
import org.koin.core.KoinApplication
Expand All @@ -24,7 +24,7 @@ import org.koin.dsl.module
fun startKoin(context: Context) {
startKoin {
androidContext(context)
modules(commonModule, platformModule)
modules(kermitLoggerModule(Logger), commonModule, platformModule)
}
}

Expand Down Expand Up @@ -53,10 +53,6 @@ internal actual val platformModule: Module =
SMBJHandler
}
single<SqlDriver> { DriverFactory(context = get()).createDriver() }
single<CacheInterface> {
val context: Context = get()
SharedFileCache(context.cacheDir.path)
}
}

@OptIn(KoinInternalApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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.Path
import com.kevinschildhorn.fotopresenter.data.network.MockNetworkDirectoryDetails
import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridCellState
import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryGridState
Expand Down Expand Up @@ -60,7 +61,14 @@ fun DirectoryNavigationItemPreview() {
@Composable
fun DirectoryNavigationBarPreview() {
DirectoryNavigationBar(
listOf("Photos1", "Subfolder1", "Photos2", "Subfolder2", "Photos3", "Subfolder3"),
directories = listOf(
"Photos1",
"Subfolder1",
"Photos2",
"Subfolder2",
"Photos3",
"Subfolder3"
).map { Path(it) },
{},
{},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,61 @@ package com.kevinschildhorn.fotopresenter.ui.shared

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import coil3.Image
import co.touchlab.kermit.Logger
import coil3.asImage
import coil3.decode.DataSource
import coil3.fetch.FetchResult
import coil3.fetch.ImageFetchResult

actual open class SharedImage actual constructor(actual val byteArray: ByteArray) {
actual fun getFetchResult(size: Int): FetchResult? {
val image: Image? = getAndroidBitmap(byteArray, size)?.asImage()
actual fun getFetchResult(size: Int, logger: Logger?): FetchResult? {
if(byteArray.isEmpty()){
logger?.e { "Byte Array is Empty!" }
return null
}

logger?.d { "Getting Android Bitmap from Byte Array" }
val bitmap = getAndroidBitmap(byteArray, size, logger)
if (bitmap == null) logger?.e { "Could not generate Bitmap" }
logger?.v { "Getting Image from Bitmap" }
val image = bitmap?.asImage()
return if (image != null) {
logger?.v { "Returning result" }
ImageFetchResult(
image = image,
isSampled = true,
dataSource = DataSource.NETWORK,
)
} else {
logger?.e { "Image NOT Found" }
null
}
}

private fun getCoilImage(size: Int): Image? = getAndroidBitmap(byteArray, size)?.asImage()

private fun getAndroidBitmap(
byteArray: ByteArray,
size: Int,
logger: Logger?,
): Bitmap? {
logger?.v { "Getting Android Bitmap" }
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)

logger?.v { "Got Options for bitmap: ${options.outWidth} x ${options.outHeight}" }
val height: Int = options.outHeight
val width: Int = options.outWidth
val dimensions = getScaledDimensions(width, height, size)
logger?.v { "Got scaled dimensions for bitmap: ${dimensions.first} x ${dimensions.second}" }

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
val sampleSize = if (heightRatio < widthRatio) heightRatio else widthRatio
logger?.v { "Setting Sample Size: $sampleSize" }
options.inSampleSize = sampleSize

options.inJustDecodeBounds = false
logger?.v { "Decoding Byte Array (Size: ${byteArray.size})" }
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)
}
}
9 changes: 9 additions & 0 deletions shared/src/commonMain/composeResources/drawable/error.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M480,680q17,0 28.5,-11.5T520,640q0,-17 -11.5,-28.5T480,600q-17,0 -28.5,11.5T440,640q0,17 11.5,28.5T480,680ZM440,520h80v-240h-80v240ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880Z"
android:fillColor="#5f6368"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M480,700q75,0 127.5,-52.5T660,520q0,-75 -52.5,-127.5T480,340q-75,0 -127.5,52.5T300,520q0,75 52.5,127.5T480,700ZM480,620q-42,0 -71,-29t-29,-71q0,-42 29,-71t71,-29q42,0 71,29t29,71q0,42 -29,71t-71,29ZM160,840q-33,0 -56.5,-23.5T80,760v-480q0,-33 23.5,-56.5T160,200h126l74,-80h240l74,80h126q33,0 56.5,23.5T880,280v480q0,33 -23.5,56.5T800,840L160,840ZM160,760h640v-480L638,280l-73,-80L395,200l-73,80L160,280v480ZM480,520Z"
android:fillColor="#5f6368"/>
</vector>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.kevinschildhorn.fotopresenter

import co.touchlab.kermit.Logger
import co.touchlab.kermit.koin.getLoggerWithTag
import com.kevinschildhorn.fotopresenter.data.datasources.CredentialsDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.DirectoryDataSource
import com.kevinschildhorn.fotopresenter.data.datasources.ImageMetadataDataSource
Expand All @@ -22,63 +22,70 @@ import com.kevinschildhorn.fotopresenter.domain.image.RetrieveImageDirectoriesUs
import com.kevinschildhorn.fotopresenter.domain.image.RetrieveImageUseCase
import com.kevinschildhorn.fotopresenter.domain.image.RetrieveSlideshowFromPlaylistUseCase
import com.kevinschildhorn.fotopresenter.domain.image.SaveMetadataForPathUseCase
import com.kevinschildhorn.fotopresenter.extension.LoggerTagSuffix
import com.kevinschildhorn.fotopresenter.ui.screens.directory.DirectoryViewModel
import com.kevinschildhorn.fotopresenter.ui.screens.login.LoginViewModel
import com.kevinschildhorn.fotopresenter.ui.screens.playlist.PlaylistViewModel
import com.kevinschildhorn.fotopresenter.ui.screens.slideshow.SlideshowViewModel
import com.kevinschildhorn.fotopresenter.ui.shared.CacheInterface
import com.kevinschildhorn.fotopresenter.ui.shared.SharedInMemoryCache
import org.koin.core.module.Module
import org.koin.dsl.module

val baseLogger = Logger.withTag("")

val commonModule =
module {

// Data
single { NetworkImageDataSource(get()) }
single { CredentialsDataSource(get()) }
single { CredentialsRepository(get()) }
single { DirectoryDataSource(get(), baseLogger.withTag("DirectoryDataSource")) }
single { DirectoryDataSource(get(), getLoggerWithTag("DirectoryDataSource$LoggerTagSuffix")) }
single { DirectoryRepository(get(), get()) }
single { CachedImageDataSource(get(), baseLogger.withTag("ImageCacheDataSource"), get()) }
single { PlaylistFileDataSource(baseLogger.withTag("PlaylistDataSource"), get()) }
single { PlaylistSQLDataSource(get(), baseLogger.withTag("PlaylistDataSource")) }
single { PlaylistRepository(get(), get()) }
factory { ImageMetadataDataSource(baseLogger.withTag("ImageMetadataDataSource"), get()) }
single { ImageRepository(get(), get(), baseLogger.withTag("ImageRepository")) }
single { CachedImageDataSource(get(), getLoggerWithTag("ImageCacheDataSource$LoggerTagSuffix")) }
single { PlaylistFileDataSource(getLoggerWithTag("PlaylistDataSource$LoggerTagSuffix"), get()) }
single { PlaylistSQLDataSource(get(), getLoggerWithTag("PlaylistDataSource$LoggerTagSuffix")) }
single { PlaylistRepository(get(), get(), getLoggerWithTag("PlaylistRepository$LoggerTagSuffix")) }
factory { ImageMetadataDataSource(getLoggerWithTag("ImageMetadataDataSource$LoggerTagSuffix"), get()) }
single { ImageRepository(get(), get(), getLoggerWithTag("ImageRepository$LoggerTagSuffix")) }
single<CacheInterface> {
//val context: Context = get()
//SharedFileCache(context.filesDir.path, getLoggerWithTag("SharedFileCache$LoggerTagSuffix"))
SharedInMemoryCache
}

// Domain
factory { ConnectToServerUseCase(get(), baseLogger.withTag("ConnectToServerUseCase")) }
factory { ChangeDirectoryUseCase(get(), baseLogger.withTag("ChangeDirectoryUseCase")) }
factory { AutoConnectUseCase(get(), get(), baseLogger.withTag("AutoConnectUseCase")) }
factory { SaveCredentialsUseCase(get(), baseLogger.withTag("SaveCredentialsUseCase")) }
factory { ConnectToServerUseCase(get(), getLoggerWithTag("ConnectToServerUseCase$LoggerTagSuffix")) }
factory { ChangeDirectoryUseCase(get(), getLoggerWithTag("ChangeDirectoryUseCase$LoggerTagSuffix")) }
factory { AutoConnectUseCase(get(), get(), getLoggerWithTag("AutoConnectUseCase$LoggerTagSuffix")) }
factory { SaveCredentialsUseCase(get(), getLoggerWithTag("SaveCredentialsUseCase$LoggerTagSuffix")) }
factory {
DisconnectFromServerUseCase(
get(),
get(),
baseLogger.withTag("DisconnectFromServerUseCase"),
getLoggerWithTag("DisconnectFromServerUseCase$LoggerTagSuffix"),
)
}
factory { RetrieveImageDirectoriesUseCase(baseLogger.withTag("RetrieveImageDirectoriesUseCase")) }
factory { RetrieveImageDirectoriesUseCase(getLoggerWithTag("RetrieveImageDirectoriesUseCase$LoggerTagSuffix")) }
factory {
RetrieveSlideshowFromPlaylistUseCase(
baseLogger.withTag("RetrieveSlideshowFromPlaylistUseCase"),
getLoggerWithTag("RetrieveSlideshowFromPlaylistUseCase$LoggerTagSuffix"),
get(),
)
}
factory {
RetrieveDirectoryContentsUseCase(
get(),
baseLogger.withTag("RetrieveDirectoryContentsUseCase"),
getLoggerWithTag("RetrieveDirectoryContentsUseCase$LoggerTagSuffix"),
)
}
factory { RetrieveImageUseCase(get(), baseLogger.withTag("RetrieveImageUseCase")) }
factory { RetrieveImageUseCase(get(), getLoggerWithTag("RetrieveImageUseCase$LoggerTagSuffix")) }
factory { SaveMetadataForPathUseCase(get()) }
// UI
single { LoginViewModel(baseLogger.withTag("LoginViewModel"), get()) }
single { DirectoryViewModel(get(), baseLogger.withTag("DirectoryViewModel")) }
single { SlideshowViewModel(baseLogger.withTag("SlideshowViewModel")) }
single { PlaylistViewModel(get(), baseLogger.withTag("PlaylistViewModel")) }
single { LoginViewModel(getLoggerWithTag("LoginViewModel$LoggerTagSuffix"), get()) }
single { DirectoryViewModel(get(), getLoggerWithTag("DirectoryViewModel$LoggerTagSuffix")) }
single { SlideshowViewModel(getLoggerWithTag("SlideshowViewModel$LoggerTagSuffix")) }
single { PlaylistViewModel(get(), getLoggerWithTag("PlaylistViewModel$LoggerTagSuffix")) }
}


internal expect val platformModule: Module
Loading
Loading