diff --git a/common/preference/src/main/java/com/my/kizzy/preference/Prefs.kt b/common/preference/src/main/java/com/my/kizzy/preference/Prefs.kt index ad02fc05..af15ba9e 100644 --- a/common/preference/src/main/java/com/my/kizzy/preference/Prefs.kt +++ b/common/preference/src/main/java/com/my/kizzy/preference/Prefs.kt @@ -18,7 +18,7 @@ import com.tencent.mmkv.MMKV import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json -import kotlin.time.Duration.Companion.days +import kotlin.time.Duration.Companion.hours object Prefs { val kv = MMKV.defaultMMKV() @@ -89,11 +89,10 @@ object Prefs { val lastDeleted = get( key = LAST_DELETED, // Force delete everyone's saved images for the first time - // Same time as Cloudflare cache invalidation - defaultValue = System.currentTimeMillis() - 7.days.inWholeMilliseconds + defaultValue = System.currentTimeMillis() - 24.hours.inWholeMilliseconds ) val currentTime = System.currentTimeMillis() - if (currentTime - lastDeleted > 7.days.inWholeMilliseconds) { + if (currentTime - lastDeleted > 24.hours.inWholeMilliseconds) { remove(SAVED_IMAGES) remove(SAVED_ARTWORK) set(LAST_DELETED, currentTime) diff --git a/data/src/main/java/com/my/kizzy/data/di/AppModule.kt b/data/src/main/java/com/my/kizzy/data/di/AppModule.kt index 223169d6..8a8dad93 100644 --- a/data/src/main/java/com/my/kizzy/data/di/AppModule.kt +++ b/data/src/main/java/com/my/kizzy/data/di/AppModule.kt @@ -18,6 +18,7 @@ import com.my.kizzy.data.remote.Base import com.my.kizzy.data.remote.Discord import com.my.kizzy.data.remote.Github import com.my.kizzy.data.remote.Imgur +import com.my.kizzy.data.remote.ImgurApiService import com.my.kizzy.data.repository.KizzyRepositoryImpl import com.my.kizzy.domain.repository.KizzyRepository import dagger.Module @@ -94,7 +95,7 @@ object AppModule { @Provides fun providesKizzyRepository( apiService: ApiService, - imgurApiService: ApiService.ImgurApiService + imgurApiService: ImgurApiService ): KizzyRepository { return KizzyRepositoryImpl(apiService, imgurApiService) } diff --git a/data/src/main/java/com/my/kizzy/data/remote/ApiResponse.kt b/data/src/main/java/com/my/kizzy/data/remote/ApiResponse.kt index 306f4c00..7ec597d2 100644 --- a/data/src/main/java/com/my/kizzy/data/remote/ApiResponse.kt +++ b/data/src/main/java/com/my/kizzy/data/remote/ApiResponse.kt @@ -6,12 +6,4 @@ import kotlinx.serialization.Serializable data class ApiResponse( @SerialName("id") val id: String -) - -@Serializable -data class ExternalAsset( - @SerialName("external_asset_path") - val externalAssetPath: String, - @SerialName("url") - val url: String ) \ No newline at end of file diff --git a/data/src/main/java/com/my/kizzy/data/remote/ApiService.kt b/data/src/main/java/com/my/kizzy/data/remote/ApiService.kt index b9c1868b..74cb84bc 100644 --- a/data/src/main/java/com/my/kizzy/data/remote/ApiService.kt +++ b/data/src/main/java/com/my/kizzy/data/remote/ApiService.kt @@ -32,20 +32,20 @@ import io.ktor.http.contentType import java.io.File import javax.inject.Inject -open class ApiService @Inject constructor( +class ApiService @Inject constructor( private val client: HttpClient, @Base private val baseUrl: String, @Discord private val discordBaseUrl: String, @Github private val githubBaseUrl: String, ) { - open suspend fun getImage(url: String, token: String) = runCatching { + suspend fun getImage(url: String) = runCatching { client.get { url("$baseUrl/image") parameter("url", url) } }.getOrNull()?.toImageAsset() - open suspend fun uploadImage(file: File, token: String) = runCatching { + suspend fun uploadImage(file: File) = runCatching { client.post { url("$baseUrl/upload") setBody(MultiPartFormDataContent( @@ -59,7 +59,7 @@ open class ApiService @Inject constructor( } }.getOrNull()?.toImageAsset() - open suspend fun HttpResponse.toImageAsset(): String? { + suspend fun HttpResponse.toImageAsset(): String? { return try { if (this.status == HttpStatusCode.OK) this.body().id @@ -70,63 +70,6 @@ open class ApiService @Inject constructor( } } - class ImgurApiService @Inject constructor( - private val client: HttpClient, - @Discord private val discordBaseUrl: String, - @Imgur private val imgurBaseUrl: String, - ) : ApiService(client, "", discordBaseUrl, "") { - override suspend fun getImage(url: String, token: String) = runCatching { - client.post { - url("$discordBaseUrl/applications/$APPLICATION_ID/external-assets") - headers { - append(HttpHeaders.Authorization, token) - append(HttpHeaders.ContentType, "application/json") - } - setBody(mapOf("urls" to arrayOf(url))) - } - }.getOrNull()?.toExternalImage() - - override suspend fun uploadImage(file: File, token: String) = runCatching { - client.post { - url("$imgurBaseUrl/image") - headers { - // Imgur web client API key, unchanged for at least >5 years as of 2024 - append(HttpHeaders.Authorization, "Client-ID 546c25a59c58ad7") - } - contentType(ContentType.MultiPart.FormData) - setBody( - MultiPartFormDataContent( - formData { - append("image", file.readBytes()) - append("type", "raw") - } - ) - ) - } - }.getOrNull()?.toImageAsset()?.let { this.getImage(it, token) } - - override suspend fun HttpResponse.toImageAsset(): String? { - return try { - if (this.status == HttpStatusCode.OK) - this.body().data.link - else - null - } catch (e: Exception) { - null - } - } - - suspend fun HttpResponse.toExternalImage(): String? { - return try { - if (this.status == HttpStatusCode.OK) - "mp:" + this.body>().first().externalAssetPath - else - null - } catch (e: Exception) { - null - } - } - } suspend fun getGames() = runCatching { client.get { diff --git a/data/src/main/java/com/my/kizzy/data/remote/ExternalAsset.kt b/data/src/main/java/com/my/kizzy/data/remote/ExternalAsset.kt new file mode 100644 index 00000000..b4ef0eee --- /dev/null +++ b/data/src/main/java/com/my/kizzy/data/remote/ExternalAsset.kt @@ -0,0 +1,24 @@ +/* + * + * ****************************************************************** + * * * Copyright (C) 2022 + * * * ExternalAsset.kt is part of Kizzy + * * * and can not be copied and/or distributed without the express + * * * permission of yzziK(Vaibhav) + * * ***************************************************************** + * + * + */ + +package com.my.kizzy.data.remote + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ExternalAsset( + @SerialName("external_asset_path") + val externalAssetPath: String, + @SerialName("url") + val url: String +) \ No newline at end of file diff --git a/data/src/main/java/com/my/kizzy/data/remote/ImgurApiService.kt b/data/src/main/java/com/my/kizzy/data/remote/ImgurApiService.kt new file mode 100644 index 00000000..e1dae130 --- /dev/null +++ b/data/src/main/java/com/my/kizzy/data/remote/ImgurApiService.kt @@ -0,0 +1,88 @@ +/* + * + * ****************************************************************** + * * * Copyright (C) 2022 + * * * ImgurApiService.kt is part of Kizzy + * * * and can not be copied and/or distributed without the express + * * * permission of yzziK(Vaibhav) + * * ***************************************************************** + * + * + */ + +package com.my.kizzy.data.remote + +import com.my.kizzy.data.rpc.Constants.APPLICATION_ID +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.request.forms.MultiPartFormDataContent +import io.ktor.client.request.forms.formData +import io.ktor.client.request.headers +import io.ktor.client.request.post +import io.ktor.client.request.setBody +import io.ktor.client.request.url +import io.ktor.client.statement.HttpResponse +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.contentType +import java.io.File +import javax.inject.Inject + +class ImgurApiService @Inject constructor( + private val client: HttpClient, + @Discord private val discordBaseUrl: String, + @Imgur private val imgurBaseUrl: String, +) { + suspend fun getImage(url: String, token: String) = runCatching { + client.post { + url("$discordBaseUrl/applications/$APPLICATION_ID/external-assets") + headers { + append(HttpHeaders.Authorization, token) + append(HttpHeaders.ContentType, "application/json") + } + setBody(mapOf("urls" to arrayOf(url))) + } + }.getOrNull()?.toExternalImage() + + suspend fun uploadImage(file: File, token: String) = runCatching { + client.post { + url("$imgurBaseUrl/image") + headers { + // Imgur web client API key, unchanged for at least >5 years as of 2024 + append(HttpHeaders.Authorization, "Client-ID 546c25a59c58ad7") + } + contentType(ContentType.MultiPart.FormData) + setBody( + MultiPartFormDataContent( + formData { + append("image", file.readBytes()) + append("type", "raw") + } + ) + ) + } + }.getOrNull()?.toImageAsset()?.let { this.getImage(it, token) } + + suspend fun HttpResponse.toImageAsset(): String? { + return try { + if (this.status == HttpStatusCode.OK) + this.body().data.link + else + null + } catch (e: Exception) { + null + } + } + + suspend fun HttpResponse.toExternalImage(): String? { + return try { + if (this.status == HttpStatusCode.OK) + "mp:" + this.body>().first().externalAssetPath + else + null + } catch (e: Exception) { + null + } + } +} \ No newline at end of file diff --git a/data/src/main/java/com/my/kizzy/data/repository/KizzyRepositoryImpl.kt b/data/src/main/java/com/my/kizzy/data/repository/KizzyRepositoryImpl.kt index 1429e73e..e6403550 100644 --- a/data/src/main/java/com/my/kizzy/data/repository/KizzyRepositoryImpl.kt +++ b/data/src/main/java/com/my/kizzy/data/repository/KizzyRepositoryImpl.kt @@ -14,6 +14,7 @@ package com.my.kizzy.data.repository import com.my.kizzy.data.remote.ApiService import com.my.kizzy.data.remote.GamesResponse +import com.my.kizzy.data.remote.ImgurApiService import com.my.kizzy.data.remote.toGame import com.my.kizzy.domain.model.Contributor import com.my.kizzy.domain.model.Game @@ -29,22 +30,22 @@ import javax.inject.Inject class KizzyRepositoryImpl @Inject constructor( private val api: ApiService, - private val imgurApi: ApiService.ImgurApiService + private val imgurApi: ImgurApiService ): KizzyRepository { - override suspend fun getImage(url: String, token: String): String? { + override suspend fun getImage(url: String): String? { return if (Prefs[Prefs.USE_IMGUR, false]) { - imgurApi.getImage(url, token) + imgurApi.getImage(url, Prefs[Prefs.TOKEN]) } else { - api.getImage(url, token) + api.getImage(url) } } - override suspend fun uploadImage(file: File, token: String): String? { + override suspend fun uploadImage(file: File): String? { return if (Prefs[Prefs.USE_IMGUR, false]) { - imgurApi.uploadImage(file, token) + imgurApi.uploadImage(file, Prefs[Prefs.TOKEN]) } else { - api.uploadImage(file, token) + api.uploadImage(file) } } diff --git a/data/src/main/java/com/my/kizzy/data/rpc/KizzyRPC.kt b/data/src/main/java/com/my/kizzy/data/rpc/KizzyRPC.kt index fcdee6d6..60d508c3 100644 --- a/data/src/main/java/com/my/kizzy/data/rpc/KizzyRPC.kt +++ b/data/src/main/java/com/my/kizzy/data/rpc/KizzyRPC.kt @@ -318,7 +318,7 @@ class KizzyRPC( ), afk = true, since = startTimestamps, - status = this.status + status = Constants.DND ) ) } diff --git a/data/src/main/java/com/my/kizzy/data/rpc/RpcImage.kt b/data/src/main/java/com/my/kizzy/data/rpc/RpcImage.kt index acc2d817..14a46cb0 100644 --- a/data/src/main/java/com/my/kizzy/data/rpc/RpcImage.kt +++ b/data/src/main/java/com/my/kizzy/data/rpc/RpcImage.kt @@ -34,7 +34,7 @@ sealed class RpcImage { class ExternalImage(val image: String) : RpcImage() { override suspend fun resolveImage(repository: KizzyRepository): String? { - return repository.getImage(image, Prefs[Prefs.TOKEN]) + return repository.getImage(image) } } @@ -56,7 +56,7 @@ sealed class RpcImage { ): String? { val applicationInfo = context.getAppInfo(packageName) val bitmap = applicationInfo.toBitmap(context) - val response = repository.uploadImage(bitmap.toFile(context, "image"), Prefs[Prefs.TOKEN]) + val response = repository.uploadImage(bitmap.toFile(context, "image")) response?.let { savedImages[packageName] = it Prefs[Prefs.SAVED_IMAGES] = Json.encodeToString(savedImages) @@ -78,7 +78,7 @@ sealed class RpcImage { return if (savedImages.containsKey(schema)) savedImages[schema] else { - val result = repository.uploadImage(bitmap.toFile(this.context, "art"), Prefs[Prefs.TOKEN]) + val result = repository.uploadImage(bitmap.toFile(this.context, "art")) result?.let { savedImages[schema] = it Prefs[Prefs.SAVED_ARTWORK] = Json.encodeToString(savedImages) diff --git a/domain/src/main/java/com/my/kizzy/domain/repository/KizzyRepository.kt b/domain/src/main/java/com/my/kizzy/domain/repository/KizzyRepository.kt index 20ea5af1..45576b73 100644 --- a/domain/src/main/java/com/my/kizzy/domain/repository/KizzyRepository.kt +++ b/domain/src/main/java/com/my/kizzy/domain/repository/KizzyRepository.kt @@ -19,8 +19,8 @@ import com.my.kizzy.domain.model.user.User import java.io.File interface KizzyRepository { - suspend fun getImage(url: String, token: String): String? - suspend fun uploadImage(file: File, token: String): String? + suspend fun getImage(url: String): String? + suspend fun uploadImage(file: File): String? suspend fun getGames(): List suspend fun getUser(userid: String): User suspend fun getContributors(): List diff --git a/domain/src/main/java/com/my/kizzy/domain/use_case/upload_galleryImage/UploadGalleryImageUseCase.kt b/domain/src/main/java/com/my/kizzy/domain/use_case/upload_galleryImage/UploadGalleryImageUseCase.kt index 9d5eec11..eb440348 100644 --- a/domain/src/main/java/com/my/kizzy/domain/use_case/upload_galleryImage/UploadGalleryImageUseCase.kt +++ b/domain/src/main/java/com/my/kizzy/domain/use_case/upload_galleryImage/UploadGalleryImageUseCase.kt @@ -19,10 +19,10 @@ import javax.inject.Inject class UploadGalleryImageUseCase @Inject constructor( private val kizzyRepository: KizzyRepository ) { - suspend operator fun invoke(file: File, token: String): String? { + suspend operator fun invoke(file: File): String? { return try { file.deleteOnExit() - kizzyRepository.uploadImage(file, token) + kizzyRepository.uploadImage(file) } catch (ex: Exception) { null } diff --git a/feature_custom_rpc/src/main/java/com/my/kizzy/feature_custom_rpc/CustomScreenViewModel.kt b/feature_custom_rpc/src/main/java/com/my/kizzy/feature_custom_rpc/CustomScreenViewModel.kt index bb93c32d..4d04bd47 100644 --- a/feature_custom_rpc/src/main/java/com/my/kizzy/feature_custom_rpc/CustomScreenViewModel.kt +++ b/feature_custom_rpc/src/main/java/com/my/kizzy/feature_custom_rpc/CustomScreenViewModel.kt @@ -54,7 +54,7 @@ class CustomScreenViewModel @Inject constructor( } private suspend fun uploadImage(file: File, result: (String) -> Unit) { - uploadGalleryImageUseCase(file, Prefs[Prefs.TOKEN])?.let { + uploadGalleryImageUseCase(file)?.let { withContext(Dispatchers.Main) { result(it.drop(3)) } diff --git a/feature_profile/src/main/java/com/my/kizzy/feature_profile/ui/component/ActivityRow.kt b/feature_profile/src/main/java/com/my/kizzy/feature_profile/ui/component/ActivityRow.kt index bb0e70e9..790a608b 100644 --- a/feature_profile/src/main/java/com/my/kizzy/feature_profile/ui/component/ActivityRow.kt +++ b/feature_profile/src/main/java/com/my/kizzy/feature_profile/ui/component/ActivityRow.kt @@ -86,9 +86,6 @@ fun ActivityRow( } } - fun isAsset(url: String?): Boolean { - return url?.startsWith("attachments") == true || url?.startsWith("external") == true - } Column( Modifier.fillMaxWidth(), @@ -288,7 +285,11 @@ fun ActivityRow( } } -fun getFormatFromMs(ms: Long): String { +private fun isAsset(url: String?): Boolean { + return url?.startsWith("attachments") == true || url?.startsWith("external") == true +} + +private fun getFormatFromMs(ms: Long): String { var remainingMs = ms val daysDifference = TimeUnit.MILLISECONDS.toDays(remainingMs) @@ -303,7 +304,7 @@ fun getFormatFromMs(ms: Long): String { String.format(Locale.US, "%02d:%02d", minutesDifference, secondsDifference) } -fun formatTime(start: Long?, end: Long? = null): String { +private fun formatTime(start: Long?, end: Long? = null): String { val startTime = end ?: start ?: return "" val endTime = System.currentTimeMillis() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e8343cdb..9895dd4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,15 +7,15 @@ version-code ="9" # app level accompanist = "0.31.0-alpha" -activity-compose = "1.9.3" +activity-compose = "1.9.2" android-svg = "1.4" androidx-material = "1.12.0" app-compat = "1.7.0" blankj-utilcodex = "1.31.0" coil = "2.1.0" -compose = "1.7.4" +compose = "1.7.3" compose-compiler = "1.4.0" -compose-navigation = "2.8.3" +compose-navigation = "2.8.2" core-ktx = "1.13.1" crashx = "v6.0.19" glide = "1.6.1"