diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml index a9a32332..5493a6c3 100644 --- a/.idea/kotlinc.xml +++ b/.idea/kotlinc.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/apng_android/build.gradle.kts b/apng_android/build.gradle.kts index e5210118..ee1dbf15 100644 --- a/apng_android/build.gradle.kts +++ b/apng_android/build.gradle.kts @@ -45,7 +45,7 @@ android { } kotlin { - jvmToolchain( Vers.kotlinJvmToolchain) + jvmToolchain(Vers.kotlinJvmToolchain) } kotlinOptions { jvmTarget = Vers.kotlinJvmTarget @@ -65,5 +65,7 @@ dependencies { api(project(":apng")) implementation(project(":base")) + coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:${Vers.desugarLibVersion}") + testImplementation("junit:junit:${Vers.junitVersion}") } diff --git a/app/build.gradle.kts b/app/build.gradle.kts index df403376..f242dd3a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -150,7 +150,6 @@ android { } } - dependencies { // desugar_jdk_libs 2.0.0 は AGP 7.4.0-alpha10 以降を要求する @@ -172,7 +171,8 @@ dependencies { implementation("com.github.UnifiedPush:android-connector:2.1.1") implementation("jp.wasabeef:glide-transformations:4.3.0") - implementation("com.github.androidmads:QRGenerator:1.0.1") + // implementation("com.github.androidmads:QRGenerator:1.0.1") + implementation("com.github.alexzhirkevich:custom-qr-generator:1.6.2") val apng4AndroidVersion = "2.25.0" implementation("com.github.penfeizhou.android.animation:apng:$apng4AndroidVersion") diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgQRCode.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgQRCode.kt index 4514b9c1..95f744f4 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgQRCode.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgQRCode.kt @@ -1,95 +1,101 @@ package jp.juggler.subwaytooter.dialog -import android.annotation.SuppressLint import android.app.Dialog -import android.graphics.Bitmap import android.graphics.Color -import android.view.View -import android.widget.ImageView -import android.widget.TextView -import androidmads.library.qrgenearator.QRGContents -import androidmads.library.qrgenearator.QRGEncoder -import jp.juggler.subwaytooter.ActMain +import android.graphics.drawable.ColorDrawable +import androidx.appcompat.app.AppCompatActivity +import com.github.alexzhirkevich.customqrgenerator.QrData +import com.github.alexzhirkevich.customqrgenerator.vector.QrCodeDrawable +import com.github.alexzhirkevich.customqrgenerator.vector.createQrVectorOptions +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorBallShape +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorColor +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorFrameShape +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorLogoPadding +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorLogoShape +import com.github.alexzhirkevich.customqrgenerator.vector.style.QrVectorPixelShape import jp.juggler.subwaytooter.R -import jp.juggler.util.coroutine.launchProgress +import jp.juggler.subwaytooter.databinding.DlgQrCodeBinding +import jp.juggler.util.coroutine.AppDispatchers +import jp.juggler.util.coroutine.launchAndShowError +import jp.juggler.util.coroutine.withProgress import jp.juggler.util.log.LogCategory +import jp.juggler.util.os.resDrawable +import kotlinx.coroutines.withContext -@SuppressLint("StaticFieldLeak") -object DlgQRCode { +private val log = LogCategory("DlgQRCode") - private val log = LogCategory("DlgQRCode") +val UInt.int get() = toInt() - internal interface QrCodeCallback { - fun onQrCode(bitmap: Bitmap?) - } - - private fun makeQrCode( - activity: ActMain, - size: Int, - url: String, - callback: QrCodeCallback, +fun AppCompatActivity.dialogQrCode( + message: CharSequence, + url: String, +) = launchAndShowError("dialogQrCode failed.") { + val drawable = withProgress( + caption = getString(R.string.generating_qr_code), ) { - activity.launchProgress( - "making QR code", - progressInitializer = { - it.setMessageEx(activity.getString(R.string.generating_qr_code)) - }, - doInBackground = { - try { - QRGEncoder( - /* data */ url, - /* bundle */ null, - QRGContents.Type.TEXT, - /* dimension */ size, - ).apply { - // 背景色 - colorBlack = Color.WHITE - // 図柄の色 - colorWhite = Color.BLACK - }.bitmap - } catch (ex: Throwable) { - log.e(ex, "QR generation failed.") - null - } - }, - afterProc = { - if (it != null) callback.onQrCode(it) - }, - ) + withContext(AppDispatchers.DEFAULT) { + QrCodeDrawable(data = QrData.Url(url), options = qrCodeOptions()) + } + } + val dialog = Dialog(this@dialogQrCode) + + val views = DlgQrCodeBinding.inflate(layoutInflater).apply { + btnCancel.setOnClickListener { dialog.cancel() } + ivQrCode.setImageDrawable(drawable) + tvMessage.text = message + tvUrl.text = "[ $url ]" // なぜか素のURLだと@以降が表示されない } - fun open(activity: ActMain, message: CharSequence, url: String) { - - val size = (0.5f + 240f * activity.density).toInt() - makeQrCode(activity, size, url, object : QrCodeCallback { - - @SuppressLint("InflateParams") - override fun onQrCode(bitmap: Bitmap?) { - - val viewRoot = activity.layoutInflater.inflate(R.layout.dlg_qr_code, null, false) - val dialog = Dialog(activity) - dialog.setContentView(viewRoot) - dialog.setCancelable(true) - dialog.setCanceledOnTouchOutside(true) - - var tv = viewRoot.findViewById(R.id.tvMessage) - tv.text = message - - tv = viewRoot.findViewById(R.id.tvUrl) - tv.text = "[ $url ]" // なぜか素のURLだと@以降が表示されない - - val iv = viewRoot.findViewById(R.id.ivQrCode) - iv.setImageBitmap(bitmap) - - dialog.setOnDismissListener { - iv.setImageDrawable(null) - bitmap?.recycle() - } - - viewRoot.findViewById(R.id.btnCancel).setOnClickListener { dialog.cancel() } - - dialog.show() - } - }) + dialog.apply { + setContentView(views.root) + setCancelable(true) + setCanceledOnTouchOutside(true) + show() + } +} + +private fun AppCompatActivity.qrCodeOptions() = createQrVectorOptions { + background { + drawable = ColorDrawable(Color.WHITE) + } + + padding = .125f + + logo { + drawable = resDrawable(R.drawable.qr_code_center) + size = .25f + shape = QrVectorLogoShape.Default + padding = QrVectorLogoPadding.Natural(.1f) + } + shapes { + // 市松模様のドット + darkPixel = QrVectorPixelShape.RoundCorners(.5f) + // 3隅の真ん中の大きめドット + ball = QrVectorBallShape.RoundCorners(.25f) + // 3隅の枠 + frame = QrVectorFrameShape.RoundCorners(.25f) + } + colors { + val cobalt = 0xFF0088FFU.int + val cobaltDark = 0xFF004488U.int + // 市松模様のドット + dark = QrVectorColor.Solid(cobaltDark) + // 3隅の真ん中の大きめドット + ball = QrVectorColor.RadialGradient( + colors = listOf( + 0f to cobaltDark, + 1f to cobalt, + ), + radius = 2f, + ) + // 3隅の枠 + frame = QrVectorColor.LinearGradient( + colors = listOf( + 0f to cobaltDark, + 1f to cobalt, + ), + orientation = QrVectorColor.LinearGradient + .Orientation.Vertical + ) } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/DlgContextMenu.kt b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/DlgContextMenu.kt index d270bfb8..d904e4e9 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/DlgContextMenu.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/itemviewholder/DlgContextMenu.kt @@ -23,7 +23,7 @@ import jp.juggler.subwaytooter.column.Column import jp.juggler.subwaytooter.column.ColumnType import jp.juggler.subwaytooter.databinding.DlgContextMenuBinding import jp.juggler.subwaytooter.dialog.DlgListMember -import jp.juggler.subwaytooter.dialog.DlgQRCode +import jp.juggler.subwaytooter.dialog.dialogQrCode import jp.juggler.subwaytooter.pref.PrefB import jp.juggler.subwaytooter.pref.PrefI import jp.juggler.subwaytooter.span.MyClickableSpan @@ -446,11 +446,11 @@ internal class DlgContextMenu( else -> whoHost } - private fun updateGroup(btn: Button, group: View, toggle: Boolean = false): Boolean { + private fun updateGroup(btn: Button, group: View, toggle: Boolean = false) { if (btn.visibility != View.VISIBLE) { group.vg(false) - return true + return } when { @@ -463,51 +463,57 @@ internal class DlgContextMenu( else -> btn.setOnClickListener(this) } - val iconId = if (group.visibility == View.VISIBLE) { - R.drawable.ic_arrow_drop_up - } else { - R.drawable.ic_arrow_drop_down + val iconId = when (group.visibility) { + View.VISIBLE -> R.drawable.ic_arrow_drop_up + else -> R.drawable.ic_arrow_drop_down } val iconColor = activity.attrColor(R.attr.colorTimeSmall) val drawable = createColoredDrawable(activity, iconId, iconColor, 1f) btn.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null) - return true } - private fun onClickUpdateGroup(v: View): Boolean = when (v.id) { - R.id.btnGroupStatusCrossAccount -> updateGroup( - views.btnGroupStatusCrossAccount, - views.llGroupStatusCrossAccount, - toggle = true - ) + private fun onClickUpdateGroup(v: View): Boolean { + when (v.id) { + R.id.btnGroupStatusCrossAccount -> updateGroup( + views.btnGroupStatusCrossAccount, + views.llGroupStatusCrossAccount, + toggle = true + ) - R.id.btnGroupUserCrossAccount -> updateGroup( - views.btnGroupUserCrossAccount, - views.llGroupUserCrossAccount, - toggle = true - ) - R.id.btnGroupStatusAround -> updateGroup( - views.btnGroupStatusAround, - views.llGroupStatusAround, - toggle = true - ) - R.id.btnGroupStatusByMe -> updateGroup( - views.btnGroupStatusByMe, - views.llGroupStatusByMe, - toggle = true - ) - R.id.btnGroupStatusExtra -> updateGroup( - views.btnGroupStatusExtra, - views.llGroupStatusExtra, - toggle = true - ) - R.id.btnGroupUserExtra -> updateGroup( - views.btnGroupUserExtra, - views.llGroupUserExtra, - toggle = true - ) - else -> false + R.id.btnGroupUserCrossAccount -> updateGroup( + views.btnGroupUserCrossAccount, + views.llGroupUserCrossAccount, + toggle = true + ) + + R.id.btnGroupStatusAround -> updateGroup( + views.btnGroupStatusAround, + views.llGroupStatusAround, + toggle = true + ) + + R.id.btnGroupStatusByMe -> updateGroup( + views.btnGroupStatusByMe, + views.llGroupStatusByMe, + toggle = true + ) + + R.id.btnGroupStatusExtra -> updateGroup( + views.btnGroupStatusExtra, + views.llGroupStatusExtra, + toggle = true + ) + + R.id.btnGroupUserExtra -> updateGroup( + views.btnGroupUserExtra, + views.llGroupUserExtra, + toggle = true + ) + + else -> return false + } + return true } private fun ActMain.onClickUserAndStatus( @@ -552,16 +558,18 @@ internal class DlgContextMenu( accessInfo, who ) + R.id.btnNickname -> clickNicknameCustomize(accessInfo, who) - R.id.btnAccountQrCode -> DlgQRCode.open( - activity, - whoRef.decoded_display_name, - who.getUserUrl() + R.id.btnAccountQrCode -> activity.dialogQrCode( + message = whoRef.decoded_display_name, + url = who.getUserUrl() ) + R.id.btnDomainBlock -> clickDomainBlock(accessInfo, who) R.id.btnOpenTimeline -> who.apiHost.valid()?.let { timelineLocal(pos, it) } R.id.btnDomainTimeline -> who.apiHost.valid() ?.let { timelineDomain(pos, accessInfo, it) } + R.id.btnAvatarImage -> openAvatarImage(who) R.id.btnQuoteName -> quoteName(who) R.id.btnHideBoost -> userSetShowBoosts(accessInfo, who, false) @@ -574,6 +582,7 @@ internal class DlgContextMenu( column, getUserApiHost() ) + R.id.btnEndorse -> userEndorsement(accessInfo, who, !relation.endorsed) R.id.btnCopyAccountId -> who.id.toString().copyToClipboard(activity) R.id.btnOpenAccountInAdminWebUi -> openBrowser("https://${accessInfo.apiHost.ascii}/admin/accounts/${who.id}") @@ -612,6 +621,7 @@ internal class DlgContextMenu( accessInfo, status ) + R.id.btnQuoteUrlStatus -> openPost(status.url?.notEmpty()) R.id.btnShareUrlStatus -> shareText(status.url?.notEmpty()) R.id.btnConversationMute -> conversationMute(accessInfo, status) @@ -622,6 +632,7 @@ internal class DlgContextMenu( accessInfo, status ) + else -> return false } return true @@ -675,10 +686,12 @@ internal class DlgContextMenu( dialog.dismissSafe() followFromAnotherAccount(pos, accessInfo, who) } + R.id.btnProfile -> { dialog.dismissSafe() userProfileFromAnotherAccount(pos, accessInfo, who) } + R.id.btnSendMessage -> { dialog.dismissSafe() mentionFromAnotherAccount(accessInfo, who) diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt index 6721a8a0..565ba525 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.kt @@ -20,7 +20,7 @@ import jp.juggler.util.log.LogCategory import jp.juggler.util.log.errorEx import jp.juggler.util.log.showToast import jp.juggler.util.log.withCaption -import jp.juggler.util.media.MovideResizeMode +import jp.juggler.util.media.MovieResizeMode import jp.juggler.util.media.MovieResizeConfig import jp.juggler.util.media.ResizeConfig import jp.juggler.util.media.ResizeType @@ -928,7 +928,7 @@ class SavedAccount( fun getMovieResizeConfig() = MovieResizeConfig( - mode = MovideResizeMode.fromInt(movieTranscodeMode), + mode = MovieResizeMode.fromInt(movieTranscodeMode), limitBitrate = movieTranscodeBitrate.toLongOrNull() ?.takeIf { it >= 100_000L } ?: 2_000_000L, limitFrameRate = movieTranscodeFramerate.toIntOrNull() diff --git a/app/src/main/res/drawable-nodpi/qr_code_center.webp b/app/src/main/res/drawable-nodpi/qr_code_center.webp new file mode 100644 index 00000000..ba98c287 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/qr_code_center.webp differ diff --git a/app/src/main/res/drawable/qr_code_bg.xml b/app/src/main/res/drawable/qr_code_bg.xml new file mode 100644 index 00000000..f65d80ee --- /dev/null +++ b/app/src/main/res/drawable/qr_code_bg.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dlg_qr_code.xml b/app/src/main/res/layout/dlg_qr_code.xml index 2b84e7af..a729595b 100644 --- a/app/src/main/res/layout/dlg_qr_code.xml +++ b/app/src/main/res/layout/dlg_qr_code.xml @@ -30,8 +30,8 @@ tools:ignore="SmallSp"/> = 34) { - overrideActivityTransition( - when (overrideType) { - TransitionOverrideType.Open -> - AppCompatActivity.OVERRIDE_TRANSITION_OPEN + when { + Build.VERSION.SDK_INT >= 34 -> { + overrideActivityTransition( + when (overrideType) { + TransitionOverrideType.Open -> + AppCompatActivity.OVERRIDE_TRANSITION_OPEN - TransitionOverrideType.Close -> - AppCompatActivity.OVERRIDE_TRANSITION_CLOSE - }, - animEnter, - animExit - ) - } else { - overridePendingTransition( - animEnter, - animExit, - ) + TransitionOverrideType.Close -> + AppCompatActivity.OVERRIDE_TRANSITION_CLOSE + }, + animEnter, + animExit + ) + } + + else -> { + @Suppress("DEPRECATION") + overridePendingTransition( + animEnter, + animExit, + ) + } } } diff --git a/base/src/main/java/jp/juggler/util/coroutine/EmptyScope.kt b/base/src/main/java/jp/juggler/util/coroutine/EmptyScope.kt index 0eb60349..ff166bf6 100644 --- a/base/src/main/java/jp/juggler/util/coroutine/EmptyScope.kt +++ b/base/src/main/java/jp/juggler/util/coroutine/EmptyScope.kt @@ -84,6 +84,30 @@ fun AppCompatActivity.launchAndShowError( ///////////////////////////////////////////////////////////////////////// +suspend fun AppCompatActivity.withProgress( + caption:String, + progressInitializer: suspend (ProgressDialogEx) -> Unit = {}, + block: suspend (progress :ProgressDialogEx)->T, +):T { + val activity = this + var progress: ProgressDialogEx? = null + try { + progress = ProgressDialogEx(activity) + progress.setCancelable(true) + progress.isIndeterminateEx = true + progress.setMessageEx(caption) + progressInitializer(progress) + progress.show() + return supervisorScope { + val task = async(AppDispatchers.MainImmediate) { block(progress) } + progress.setOnCancelListener { task.cancel() } + task.await() + } + } finally { + progress?.dismissSafe() + } +} + fun AppCompatActivity.launchProgress( caption: String, doInBackground: suspend CoroutineScope.(ProgressDialogEx) -> T, diff --git a/base/src/main/java/jp/juggler/util/media/BitmapUtils.kt b/base/src/main/java/jp/juggler/util/media/BitmapUtils.kt index 37a56f5f..59bf6431 100644 --- a/base/src/main/java/jp/juggler/util/media/BitmapUtils.kt +++ b/base/src/main/java/jp/juggler/util/media/BitmapUtils.kt @@ -289,18 +289,14 @@ fun createResizedBitmap( // 出力用Bitmap作成 val dst = Bitmap.createBitmap(dstSizeInt.x, dstSizeInt.y, Bitmap.Config.ARGB_8888) try { - if (dst == null) { - context.showToast(false, "bitmap creation failed.") - } else { - val canvas = Canvas(dst) - val paint = Paint() - paint.isFilterBitmap = true - canvas.drawBitmap(sourceBitmap, matrix, paint) - log.d("createResizedBitmap: resized to ${dstSizeInt.x}x${dstSizeInt.y}") - return dst - } + val canvas = Canvas(dst) + val paint = Paint() + paint.isFilterBitmap = true + canvas.drawBitmap(sourceBitmap, matrix, paint) + log.d("createResizedBitmap: resized to ${dstSizeInt.x}x${dstSizeInt.y}") + return dst } catch (ex: Throwable) { - dst?.recycle() + dst.recycle() throw ex } } finally { diff --git a/base/src/main/java/jp/juggler/util/media/MovieUtils.kt b/base/src/main/java/jp/juggler/util/media/MovieUtils.kt index a25502a9..8c2dcfb1 100644 --- a/base/src/main/java/jp/juggler/util/media/MovieUtils.kt +++ b/base/src/main/java/jp/juggler/util/media/MovieUtils.kt @@ -12,7 +12,6 @@ import androidx.media3.transformer.Effects import androidx.media3.transformer.ExportException import androidx.media3.transformer.ExportResult import androidx.media3.transformer.ProgressHolder -import androidx.media3.transformer.TransformationRequest import androidx.media3.transformer.Transformer import androidx.media3.transformer.VideoEncoderSettings import com.otaliastudios.transcoder.Transcoder @@ -23,9 +22,14 @@ import com.otaliastudios.transcoder.strategy.DefaultVideoStrategy import jp.juggler.util.coroutine.AppDispatchers import jp.juggler.util.data.clip import jp.juggler.util.log.LogCategory -import kotlinx.coroutines.* +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.ClosedReceiveChannelException +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext import java.io.File import java.io.FileInputStream import java.util.concurrent.atomic.AtomicBoolean @@ -38,19 +42,19 @@ import kotlin.math.sqrt private val log = LogCategory("MovieUtils") -enum class MovideResizeMode(val int: Int) { +enum class MovieResizeMode(val int: Int) { Auto(0), No(1), Always(2), ; companion object { - fun fromInt(i: Int) = values().find { it.int == i } ?: Auto + fun fromInt(i: Int) = entries.find { it.int == i } ?: Auto } } data class MovieResizeConfig( - val mode: MovideResizeMode, + val mode: MovieResizeMode, val limitFrameRate: Int, val limitBitrate: Long, val limitSquarePixels: Int, @@ -78,9 +82,9 @@ data class MovieResizeConfig( // トランスコードをスキップする判定 fun isTranscodeRequired(info: VideoInfo) = when (mode) { - MovideResizeMode.No -> false - MovideResizeMode.Always -> true - MovideResizeMode.Auto -> + MovieResizeMode.No -> false + MovieResizeMode.Always -> true + MovieResizeMode.Auto -> info.squarePixels > limitSquarePixels || (info.actualBps ?: 0).toFloat() > limitBitrate.toFloat() * 1.5f || (info.frameRatio == null || info.frameRatio < 1f || info.frameRatio > limitFrameRate) @@ -129,9 +133,9 @@ suspend fun transcodeVideoMedia3Transformer( withContext(AppDispatchers.MainImmediate) { when (resizeConfig.mode) { - MovideResizeMode.No -> return@withContext inFile - MovideResizeMode.Always -> Unit - MovideResizeMode.Auto -> { + MovieResizeMode.No -> return@withContext inFile + MovieResizeMode.Always -> Unit + MovieResizeMode.Auto -> { if (!resizeConfig.isTranscodeRequired(info)) { log.i("transcodeVideoMedia3Transformer: transcode not required.") return@withContext inFile @@ -189,12 +193,6 @@ suspend fun transcodeVideoMedia3Transformer( } }.build() - val request = TransformationRequest.Builder().apply { - setVideoMimeType(MimeTypes.VIDEO_H264) - setAudioMimeType(MimeTypes.AUDIO_AAC) - // ビットレートがないな… - }.build() - // 完了検知 val completed = AtomicBoolean(false) val error = AtomicReference(null) @@ -226,9 +224,11 @@ suspend fun transcodeVideoMedia3Transformer( // 開始 val transformer = Transformer.Builder(context).apply { setEncoderFactory(encoderFactory) - setTransformationRequest(request) + setAudioMimeType(MimeTypes.AUDIO_AAC) + setVideoMimeType(MimeTypes.VIDEO_H264) addListener(listener) }.build() + transformer.start(editedMediaItem, outFile.canonicalPath) // 完了まで待機しつつ、定期的に進捗コールバックを呼ぶ @@ -265,9 +265,9 @@ suspend fun transcodeVideo( } when (resizeConfig.mode) { - MovideResizeMode.No -> return@withContext inFile - MovideResizeMode.Always -> Unit - MovideResizeMode.Auto -> { + MovieResizeMode.No -> return@withContext inFile + MovieResizeMode.Always -> Unit + MovieResizeMode.Auto -> { if (info.squarePixels <= resizeConfig.limitSquarePixels && (info.actualBps ?: 0).toFloat() <= resizeConfig.limitBitrate * 1.5f && (info.frameRatio?.toInt() ?: 0) <= resizeConfig.limitFrameRate diff --git a/base/src/main/java/jp/juggler/util/os/ContextUtils.kt b/base/src/main/java/jp/juggler/util/os/ContextUtils.kt index db244530..94ca8687 100644 --- a/base/src/main/java/jp/juggler/util/os/ContextUtils.kt +++ b/base/src/main/java/jp/juggler/util/os/ContextUtils.kt @@ -1,7 +1,9 @@ package jp.juggler.util.os import android.content.Context +import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import androidx.core.content.ContextCompat /** * インストゥルメントテストのContextは @@ -18,3 +20,6 @@ val Context.applicationContextSafe: Context fun Context.error(@StringRes resId: Int, vararg args: Any?): Nothing = error(getString(resId, *args)) + +fun Context.resDrawable(@DrawableRes resId: Int) = + ContextCompat.getDrawable(this, resId) diff --git a/build.gradle.kts b/build.gradle.kts index 6ae7cdc1..05929c51 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { google() mavenCentral() - // com.github.androidmads:QRGenerator + // alexzhirkevich/custom-qr-generator maven(url = "https://jitpack.io") } } diff --git a/buildSrc/src/main/java/Vers.kt b/buildSrc/src/main/java/Vers.kt index 64bd9bb7..21bc0f33 100644 --- a/buildSrc/src/main/java/Vers.kt +++ b/buildSrc/src/main/java/Vers.kt @@ -1,44 +1,49 @@ import org.gradle.api.JavaVersion +@Suppress("MemberVisibilityCanBePrivate") object Vers { + const val stBuildToolsVersion = "34.0.0" + const val stCompileSdkVersion = 34 + const val stTargetSdkVersion = 34 + const val stMinSdkVersion = 26 + val javaSourceCompatibility = JavaVersion.VERSION_1_8 val javaTargetCompatibility = JavaVersion.VERSION_1_8 - const val androidGradlePruginVersion = "8.1.4" + const val kotlinVersion = "1.9.22" + const val kotlinJvmTarget = "1.8" + const val kotlinJvmToolchain = 17 + + const val androidGradlePruginVersion = "8.2.1" + const val androidxAnnotationVersion = "1.6.0" const val androidxTestEspressoCoreVersion = "3.5.1" const val androidxTestExtJunitVersion = "1.1.5" const val androidxTestVersion = "1.5.0" - const val ankoVersion = "0.10.8" + + // const val ankoVersion = "0.10.8" const val appcompatVersion = "1.6.1" const val archVersion = "2.2.0" const val commonsCodecVersion = "1.16.0" const val composeVersion = "1.0.5" const val conscryptVersion = "2.5.2" const val coreKtxVersion = "1.12.0" - const val desugarLibVersion = "2.0.3" + const val desugarLibVersion = "2.0.4" const val detektVersion = "1.23.4" const val emoji2Version = "1.4.0" const val glideVersion = "4.15.1" const val junitVersion = "4.13.2" const val koinVersion = "3.5.0" - const val kotlinJvmTarget = "1.8" - const val kotlinJvmToolchain = 17 - const val kotlinTestVersion = "1.9.20" - const val kotlinVersion = "1.9.20" + const val kotlinTestVersion = kotlinVersion // "1.9.22" const val kotlinxCoroutinesVersion = "1.7.3" - const val kspVersion = "1.9.20-1.0.14" + const val kspVersion = "$kotlinVersion-1.0.16" const val lifecycleVersion = "2.6.2" - const val materialVersion = "1.10.0" + const val materialVersion = "1.11.0" const val media3Version = "1.2.0" const val okhttpVersion = "5.0.0-alpha.11" const val preferenceKtxVersion = "1.2.1" - const val stBuildToolsVersion = "34.0.0" - const val stCompileSdkVersion = 34 - const val stMinSdkVersion = 26 - const val stTargetSdkVersion = 34 const val startupVersion = "1.1.1" const val testKtxVersion = "1.5.0" const val webpDecoderVersion = "2.6.$glideVersion" - const val workVersion = "2.8.1" + const val workVersion = "2.9.0" } diff --git a/emoji/build.gradle.kts b/emoji/build.gradle.kts index 64eac986..cabbd983 100644 --- a/emoji/build.gradle.kts +++ b/emoji/build.gradle.kts @@ -27,19 +27,19 @@ android { } compileOptions { - sourceCompatibility =Vers. javaSourceCompatibility - targetCompatibility =Vers.javaTargetCompatibility + sourceCompatibility = Vers.javaSourceCompatibility + targetCompatibility = Vers.javaTargetCompatibility } kotlin { jvmToolchain(Vers.kotlinJvmToolchain) } kotlinOptions { - jvmTarget =Vers. kotlinJvmTarget + jvmTarget = Vers.kotlinJvmTarget } tasks.withType().configureEach { kotlinOptions { - jvmTarget =Vers. kotlinJvmTarget + jvmTarget = Vers.kotlinJvmTarget } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e9783a0b..a7c64529 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Mon Jun 13 20:53:58 JST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/sample_apng/build.gradle.kts b/sample_apng/build.gradle.kts index 3cd9a5dc..4d8d9256 100644 --- a/sample_apng/build.gradle.kts +++ b/sample_apng/build.gradle.kts @@ -40,6 +40,7 @@ android { compileOptions { sourceCompatibility = Vers.javaSourceCompatibility targetCompatibility = Vers.javaTargetCompatibility + isCoreLibraryDesugaringEnabled = true } kotlinOptions {