Skip to content

Commit

Permalink
实现结果页保存截图 (#36)
Browse files Browse the repository at this point in the history
* 添加submodule

* 接入capturable

* 调通

* 实现结果页截图(但还没实现长截图)

* 实现长截图

* 实现长截图

* fix bug that capture before requests collection was not handled

* modify build.gradle.kts

* update workflows

* Update about libraries

* update workflows

* 截图添加背景色

* update workflows

* cleanup

* update workflows

* 修复安卓崩溃

* 支持保存后打开或分享

---------

Co-authored-by: ssttkkl <[email protected]>
  • Loading branch information
ssttkkl and ssttkkl committed Aug 30, 2024
1 parent e92eab5 commit 7c44fc0
Show file tree
Hide file tree
Showing 38 changed files with 829 additions and 66 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
steps:
- name: Checkout my repository
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
Expand Down
22 changes: 17 additions & 5 deletions .github/workflows/build-desktop-distribution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ jobs:
steps:
- name: Checkout my repository
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
java-version: |
11
17
cache: 'gradle'

- name: Package Distribution
Expand Down Expand Up @@ -69,12 +73,16 @@ jobs:
steps:
- name: Checkout my repository
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
java-version: |
11
17
cache: 'gradle'

- name: Package Distribution
Expand Down Expand Up @@ -103,12 +111,16 @@ jobs:
steps:
- name: Checkout my repository
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: 17
java-version: |
11
17
cache: 'gradle'

- name: Install FUSE (linux)
Expand All @@ -125,12 +137,12 @@ jobs:
with:
name: distribution
path: |
composeApp/build/appimage/mahjong-utils-app.AppImage
composeApp/build/appimage/main-release/mahjong-utils-app.AppImage
composeApp/build/compose/jars/*.jar
- name: Upload Release Assets
if: ${{ github.event_name == 'release' }}
uses: AButler/[email protected]
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
files: "composeApp/build/appimage/*.AppImage;composeApp/build/compose/jars/*.jar"
files: "composeApp/build/appimage/main-release/*.AppImage;composeApp/build/compose/jars/*.jar"
2 changes: 2 additions & 0 deletions .github/workflows/ghpages-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/update_about_libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Setup Java JDK
uses: actions/setup-java@v3
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "external/mahjong-utils"]
path = external/mahjong-utils
url = https://github.com/ssttkkl/mahjong-utils
[submodule "external/Capturable"]
path = external/Capturable
url = https://github.com/ssttkkl/Capturable
35 changes: 30 additions & 5 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ kotlin {
implementation(libs.kotlinx.coroutines.core)

implementation(libs.mahjong.utils)

implementation(libs.capturable)
}
}

Expand All @@ -123,6 +125,10 @@ kotlin {
dependsOn(commonMain)
}

val nonAndroidMain by creating {
dependsOn(commonMain)
}

if (enableAndroid) {
val androidMain by getting {
dependsOn(nonWasmJsMain)
Expand All @@ -136,12 +142,14 @@ kotlin {
if (enableIos) {
val iosMain by getting {
dependsOn(nonWasmJsMain)
dependsOn(nonAndroidMain)
}
}

if (enableDesktop) {
val desktopMain by getting {
dependsOn(nonWasmJsMain)
dependsOn(nonAndroidMain)
dependsOn(desktopAndWasmJsMain)
dependencies {
implementation(compose.desktop.currentOs)
Expand All @@ -156,6 +164,7 @@ kotlin {
if (enableWeb) {
val wasmJsMain by getting {
dependsOn(desktopAndWasmJsMain)
dependsOn(nonAndroidMain)
}
}
}
Expand Down Expand Up @@ -308,13 +317,16 @@ if (enableDesktop) {
}

afterEvaluate {
tasks.findByName("packageAppImage")?.doLast {
fun packAppImage(isRelease: Boolean) {
val appDirSrc = project.file("mahjong-utils-app.AppDir")
val packageOutput =
val packageOutput = if (isRelease)
layout.buildDirectory.dir("compose/binaries/main-release/app/mahjong-utils-app")
.get().asFile
else
layout.buildDirectory.dir("compose/binaries/main/app/mahjong-utils-app")
.get().asFile
if (!appDirSrc.exists() || !packageOutput.exists()) {
return@doLast
return
}

val downloadDest = layout.buildDirectory.dir("tmp").get().asFile
Expand All @@ -330,7 +342,10 @@ if (enableDesktop) {
appimagetool.setExecutable(true)
}

val appDir = layout.buildDirectory.dir("appimage/mahjong-utils-app.AppDir").get().asFile
val appDir = if (isRelease)
layout.buildDirectory.dir("appimage/main-release/mahjong-utils-app.AppDir").get().asFile
else
layout.buildDirectory.dir("appimage/main/mahjong-utils-app.AppDir").get().asFile
if (appDir.exists()) {
appDir.deleteRecursively()
}
Expand All @@ -346,9 +361,19 @@ if (enableDesktop) {
workingDir = appDir.parentFile
executable = appimagetool.canonicalPath
environment("ARCH", "x86_64") // TODO: 支持arm64
args("mahjong-utils-app.AppDir", "mahjong-utils-app-linux-${rootProject.ext["versionName"]}.AppImage")
args(
"mahjong-utils-app.AppDir",
"mahjong-utils-app-linux-${rootProject.ext["versionName"]}.AppImage"
)
}
}

tasks.findByName("packageAppImage")?.doLast {
packAppImage(false)
}
tasks.findByName("packageReleaseAppImage")?.doLast {
packAppImage(true)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,45 @@
package io.ssttkkl.mahjongutils.app

import android.app.Activity
import android.app.Application
import android.os.Bundle
import io.ssttkkl.mahjongutils.app.init.AppInit
import io.ssttkkl.mahjongutils.app.utils.ActivityHelper

class MyApp : Application() {
override fun onCreate() {
super.onCreate()
_current = this

registerActivityLifecycleCallbacks(object :ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {

}

override fun onActivityStarted(activity: Activity) {
ActivityHelper.currentActivity = activity
}

override fun onActivityResumed(activity: Activity) {
}

override fun onActivityPaused(activity: Activity) {
}

override fun onActivityStopped(activity: Activity) {
if (ActivityHelper.currentActivity == activity) {
ActivityHelper.currentActivity = null
}
}

override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}

override fun onActivityDestroyed(activity: Activity) {
}

})

AppInit.doInit()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.ssttkkl.mahjongutils.app.utils

import android.app.Activity
import java.lang.ref.WeakReference

object ActivityHelper {
private var currentActivityRef: WeakReference<Activity>? = null

var currentActivity: Activity?
get() = currentActivityRef?.get()
set(value) {
currentActivityRef = WeakReference(value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package io.ssttkkl.mahjongutils.app.utils.image

import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.net.Uri
import android.os.Environment
import android.provider.MediaStore
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.toArgb
import androidx.core.content.ContextCompat.startActivity
import io.ssttkkl.mahjongutils.app.MyApp
import io.ssttkkl.mahjongutils.app.utils.ActivityHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

actual suspend fun platformWithBackground(
imageBitmap: ImageBitmap,
background: Color
): ImageBitmap {
val newBitmap =
Bitmap.createBitmap(imageBitmap.width, imageBitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(newBitmap)

// 绘制背景
val paintBackground = Paint().apply {
color = background.toArgb()
style = Paint.Style.FILL
}
canvas.drawRect(
0f,
0f,
imageBitmap.width.toFloat(),
imageBitmap.height.toFloat(),
paintBackground
)

// 将原始硬件位图转换为软件位图
val softwareBitmap = imageBitmap.asAndroidBitmap().copy(Bitmap.Config.ARGB_8888, false)
// 绘制原始位图
canvas.drawBitmap(softwareBitmap, 0f, 0f, null)

return newBitmap.asImageBitmap()
}

actual class SaveResult(val uri: Uri, val title: String) {
actual val isSupportOpen: Boolean
get() = true
actual val isSupportShare: Boolean
get() = true

actual suspend fun open() {
// 创建Intent以打开图片
val intent = Intent().apply {
action = Intent.ACTION_VIEW
setDataAndType(uri, "image/png") // 设置MIME类型
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION // 给予读权限
}

// 启动Intent
ActivityHelper.currentActivity?.startActivity(intent)
}

actual suspend fun share() {
// 创建分享意图
val shareIntent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_STREAM, uri) // 附加 URI
type = "image/png" // 或 "image/jpeg" 根据实际情况
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION // 给予读权限
}

// 启动分享意图
ActivityHelper.currentActivity?.startActivity(Intent.createChooser(shareIntent, title))
}
}

actual object ImageUtils : CommonImageUtils() {
actual suspend fun save(imageBitmap: ImageBitmap, title: String): SaveResult? {
return withContext(Dispatchers.IO) {
val values = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, title)
put(MediaStore.Images.Media.MIME_TYPE, "image/png")
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
put(MediaStore.Images.Media.IS_PENDING, 1)
}

val uri: Uri = MyApp.current.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values
) ?: return@withContext null

try {
MyApp.current.contentResolver.openOutputStream(uri)?.use {
imageBitmap.asAndroidBitmap().compress(Bitmap.CompressFormat.PNG, 100, it)
} ?: return@withContext null
values.clear()
values.put(MediaStore.Images.Media.IS_PENDING, 0)
MyApp.current.contentResolver.update(uri, values, null, null)
} catch (e: Exception) {
e.printStackTrace()
return@withContext null
}
return@withContext SaveResult(uri, title)
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<string name="label_history">ヒストリ</string>
<string name="label_clear">クリア</string>
<string name="label_share">シェア</string>
<string name="label_view">View</string>

<string name="text_empty_history">なし</string>

Expand Down Expand Up @@ -202,4 +203,6 @@
<string name="text_must_enter_hu">符数を入力してください。</string>
<string name="text_invalid_hu_number">有効な符数ではありません。</string>
<string name="text_hu_exceeded_maximum">符数は140以下(140枚含む)にするべきです。</string>

<string name="text_save_result_success">Result saved as image.</string>
</resources>
Loading

0 comments on commit 7c44fc0

Please sign in to comment.