From 5f7f4c34ec3c2732f29716e483113a5473c520b6 Mon Sep 17 00:00:00 2001 From: tateisu Date: Sat, 6 Jan 2024 02:18:28 +0900 Subject: [PATCH] =?UTF-8?q?=E4=BE=9D=E5=AD=98=E9=96=A2=E4=BF=82=E3=81=AE?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E3=80=82QR=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=83=A9=E3=82=A4=E3=83=96=E3=83=A9=E3=83=AA?= =?UTF-8?q?=E3=81=AE=E5=A4=89=E6=9B=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/kotlinc.xml | 2 +- apng_android/build.gradle.kts | 4 +- app/build.gradle.kts | 4 +- .../juggler/subwaytooter/dialog/DlgQRCode.kt | 168 +++++++++--------- .../itemviewholder/DlgContextMenu.kt | 101 ++++++----- .../subwaytooter/table/SavedAccount.kt | 4 +- .../res/drawable-nodpi/qr_code_center.webp | Bin 0 -> 38144 bytes app/src/main/res/drawable/qr_code_bg.xml | 5 + app/src/main/res/layout/dlg_qr_code.xml | 4 +- base/build.gradle.kts | 4 +- .../java/jp/juggler/media/AudioTranscoder.kt | 6 +- base/src/main/java/jp/juggler/util/Compat.kt | 37 ++-- .../jp/juggler/util/coroutine/EmptyScope.kt | 24 +++ .../java/jp/juggler/util/media/BitmapUtils.kt | 18 +- .../java/jp/juggler/util/media/MovieUtils.kt | 42 ++--- .../java/jp/juggler/util/os/ContextUtils.kt | 5 + build.gradle.kts | 2 +- buildSrc/src/main/java/Vers.kt | 33 ++-- emoji/build.gradle.kts | 8 +- gradle/wrapper/gradle-wrapper.properties | 2 +- sample_apng/build.gradle.kts | 1 + 21 files changed, 265 insertions(+), 209 deletions(-) create mode 100644 app/src/main/res/drawable-nodpi/qr_code_center.webp create mode 100644 app/src/main/res/drawable/qr_code_bg.xml 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 0000000000000000000000000000000000000000..ba98c2879312a912e69f157cdf630a74204b14ef GIT binary patch literal 38144 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

q+BpQn(>zjh!H;Tl#k6Gp74u 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 literal 0 HcmV?d00001 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 {