diff --git a/packages/kbot/dist/win-64/tauri-app.exe b/packages/kbot/dist/win-64/tauri-app.exe index dcea3002..65d01c60 100644 Binary files a/packages/kbot/dist/win-64/tauri-app.exe and b/packages/kbot/dist/win-64/tauri-app.exe differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/2 b/packages/kbot/gui/tauri-app/src-tauri/2 new file mode 100644 index 00000000..c78ecc4b --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/2 @@ -0,0 +1,7 @@ + +up to date, audited 206 packages in 2s + +31 packages are looking for funding + run `npm fund` for details + +found 0 vulnerabilities diff --git a/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml b/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml index 8777bafc..a2bca53d 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml +++ b/packages/kbot/gui/tauri-app/src-tauri/Cargo.toml @@ -22,27 +22,34 @@ tauri = { version = "2", features = ["protocol-asset", "devtools"] } tauri-plugin-opener = "2.5.0" tauri-plugin-dialog = "2.4.0" tauri-plugin-fs = "2.0.0" -tauri-plugin-http = "2.0.0" serde = { version = "1", features = ["derive"] } serde_json = "1" pathdiff = "0.2.3" dirs = "5.0.1" rand = "0.8" tauri-plugin-deep-link = "2.4.3" -tauri-plugin-upload = "2.3.1" tauri-plugin-store = "2.4.0" tauri-plugin-log = "2.7.0" url = "2.5.7" +nanoid = "0.4.0" +image = "0.25.8" +glob = "0.3.3" +tauri-plugin-notification = "2.3.1" +log = "0.4" + +# Desktop-only dependencies (these may cause OpenSSL issues on Android) +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +tauri-plugin-http = "2.0.0" +tauri-plugin-upload = "2.3.1" +tauri-plugin-aptabase = "1.0.0" arboard = "3.6.1" clap = "4.5.48" clap_derive = "4.5.47" tauri-plugin-shell = "2.3.1" tauri-plugin-process = "2.3.0" -tauri-plugin-aptabase = "1.0.0" -nanoid = "0.4.0" -image = "0.25.8" -glob = "0.3.3" -tauri-plugin-notification = "2.3.1" tauri-plugin-clipboard-manager = "2.3.0" -log = "0.4" + +# Android-specific dependencies with rustls for TLS +[target.'cfg(any(target_os = "android", target_os = "ios"))'.dependencies] +tauri-plugin-http = { version = "2.0.0", features = ["rustls-tls"], default-features = false } diff --git a/packages/kbot/gui/tauri-app/src-tauri/capabilities/base.json b/packages/kbot/gui/tauri-app/src-tauri/capabilities/base.json index cb4dfbb7..013af15e 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/capabilities/base.json +++ b/packages/kbot/gui/tauri-app/src-tauri/capabilities/base.json @@ -37,16 +37,10 @@ "core:default", "core:window:allow-set-size", "core:webview:allow-set-webview-size", - "clipboard-manager:default", - "clipboard-manager:allow-write-text", - "clipboard-manager:allow-write-image", - "clipboard-manager:allow-read-text", - "clipboard-manager:allow-read-image", "log:default", "store:default", "http:default", "dialog:default", - "upload:default", "fs:allow-open", "fs:allow-write", "fs:allow-read", diff --git a/packages/kbot/gui/tauri-app/src-tauri/capabilities/desktop.json b/packages/kbot/gui/tauri-app/src-tauri/capabilities/desktop.json index bc5b8943..30a07f5f 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/capabilities/desktop.json +++ b/packages/kbot/gui/tauri-app/src-tauri/capabilities/desktop.json @@ -17,6 +17,14 @@ "dialog:allow-confirm", "dialog:allow-message", "opener:default", + "clipboard-manager:default", + "clipboard-manager:allow-write-text", + "clipboard-manager:allow-write-image", + "clipboard-manager:allow-read-text", + "clipboard-manager:allow-read-image", + "upload:default", + "shell:default", + "process:default", { "identifier": "http:default", "allow": [ diff --git a/packages/kbot/gui/tauri-app/src-tauri/capabilities/mobile.json b/packages/kbot/gui/tauri-app/src-tauri/capabilities/mobile.json index da77f5e5..57118b30 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/capabilities/mobile.json +++ b/packages/kbot/gui/tauri-app/src-tauri/capabilities/mobile.json @@ -5,20 +5,7 @@ "windows": ["main"], "platforms": ["android", "iOS"], "permissions": [ - "nfc:allow-write", - "nfc:allow-scan", - "biometric:allow-authenticate", - "barcode-scanner:allow-scan", - "barcode-scanner:allow-cancel", - "barcode-scanner:allow-request-permissions", - "barcode-scanner:allow-check-permissions", - "geolocation:allow-check-permissions", - "geolocation:allow-request-permissions", - "geolocation:allow-watch-position", - "geolocation:allow-get-current-position", - "haptics:allow-impact-feedback", - "haptics:allow-notification-feedback", - "haptics:allow-selection-feedback", - "haptics:allow-vibrate" + "core:default", + "notification:default" ] } diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/MainActivity.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/MainActivity.kt new file mode 100644 index 00000000..1870c043 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/MainActivity.kt @@ -0,0 +1,11 @@ +package com.zx.tauri_app + +import android.os.Bundle +import androidx.activity.enableEdgeToEdge + +class MainActivity : TauriActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() + super.onCreate(savedInstanceState) + } +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Ipc.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Ipc.kt new file mode 100644 index 00000000..9c1ae5e4 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Ipc.kt @@ -0,0 +1,33 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +@file:Suppress("unused") + +package com.zx.tauri_app + +import android.webkit.* + +class Ipc(val webViewClient: RustWebViewClient) { + @JavascriptInterface + fun postMessage(message: String?) { + message?.let {m -> + // we're not using WebView::getUrl() here because it needs to be executed on the main thread + // and it would slow down the Ipc + // so instead we track the current URL on the webview client + this.ipc(webViewClient.currentUrl, m) + } + } + + companion object { + init { + System.loadLibrary("tauri_app_lib") + } + } + + private external fun ipc(url: String, message: String) + + +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Logger.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Logger.kt new file mode 100644 index 00000000..689a59be --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/Logger.kt @@ -0,0 +1,89 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +@file:Suppress("unused", "MemberVisibilityCanBePrivate") + +package com.zx.tauri_app + +// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/Logger.java + +import android.text.TextUtils +import android.util.Log + +class Logger { + companion object { + private const val LOG_TAG_CORE = "Tauri" + + fun tags(vararg subtags: String): String { + return if (subtags.isNotEmpty()) { + LOG_TAG_CORE + "/" + TextUtils.join("/", subtags) + } else LOG_TAG_CORE + } + + fun verbose(message: String) { + verbose(LOG_TAG_CORE, message) + } + + private fun verbose(tag: String, message: String) { + if (!shouldLog()) { + return + } + Log.v(tag, message) + } + + fun debug(message: String) { + debug(LOG_TAG_CORE, message) + } + + fun debug(tag: String, message: String) { + if (!shouldLog()) { + return + } + Log.d(tag, message) + } + + fun info(message: String) { + info(LOG_TAG_CORE, message) + } + + fun info(tag: String, message: String) { + if (!shouldLog()) { + return + } + Log.i(tag, message) + } + + fun warn(message: String) { + warn(LOG_TAG_CORE, message) + } + + fun warn(tag: String, message: String) { + if (!shouldLog()) { + return + } + Log.w(tag, message) + } + + fun error(message: String) { + error(LOG_TAG_CORE, message, null) + } + + fun error(message: String, e: Throwable?) { + error(LOG_TAG_CORE, message, e) + } + + fun error(tag: String, message: String, e: Throwable?) { + if (!shouldLog()) { + return + } + Log.e(tag, message, e) + } + + private fun shouldLog(): Boolean { + return BuildConfig.DEBUG + } + } +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/PermissionHelper.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/PermissionHelper.kt new file mode 100644 index 00000000..f7f32323 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/PermissionHelper.kt @@ -0,0 +1,117 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.zx.tauri_app + +// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/PermissionHelper.java + +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.ActivityCompat +import java.util.ArrayList + +object PermissionHelper { + /** + * Checks if a list of given permissions are all granted by the user + * + * @param permissions Permissions to check. + * @return True if all permissions are granted, false if at least one is not. + */ + fun hasPermissions(context: Context?, permissions: Array): Boolean { + for (perm in permissions) { + if (ActivityCompat.checkSelfPermission( + context!!, + perm + ) != PackageManager.PERMISSION_GRANTED + ) { + return false + } + } + return true + } + + /** + * Check whether the given permission has been defined in the AndroidManifest.xml + * + * @param permission A permission to check. + * @return True if the permission has been defined in the Manifest, false if not. + */ + fun hasDefinedPermission(context: Context, permission: String): Boolean { + var hasPermission = false + val requestedPermissions = getManifestPermissions(context) + if (!requestedPermissions.isNullOrEmpty()) { + val requestedPermissionsList = listOf(*requestedPermissions) + val requestedPermissionsArrayList = ArrayList(requestedPermissionsList) + if (requestedPermissionsArrayList.contains(permission)) { + hasPermission = true + } + } + return hasPermission + } + + /** + * Check whether all of the given permissions have been defined in the AndroidManifest.xml + * @param context the app context + * @param permissions a list of permissions + * @return true only if all permissions are defined in the AndroidManifest.xml + */ + fun hasDefinedPermissions(context: Context, permissions: Array): Boolean { + for (permission in permissions) { + if (!hasDefinedPermission(context, permission)) { + return false + } + } + return true + } + + /** + * Get the permissions defined in AndroidManifest.xml + * + * @return The permissions defined in AndroidManifest.xml + */ + private fun getManifestPermissions(context: Context): Array? { + var requestedPermissions: Array? = null + try { + val pm = context.packageManager + val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + pm.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong())) + } else { + @Suppress("DEPRECATION") + pm.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS) + } + if (packageInfo != null) { + requestedPermissions = packageInfo.requestedPermissions + } + } catch (_: Exception) { + } + return requestedPermissions + } + + /** + * Given a list of permissions, return a new list with the ones not present in AndroidManifest.xml + * + * @param neededPermissions The permissions needed. + * @return The permissions not present in AndroidManifest.xml + */ + fun getUndefinedPermissions(context: Context, neededPermissions: Array): Array { + val undefinedPermissions = ArrayList() + val requestedPermissions = getManifestPermissions(context) + if (!requestedPermissions.isNullOrEmpty()) { + val requestedPermissionsList = listOf(*requestedPermissions) + val requestedPermissionsArrayList = ArrayList(requestedPermissionsList) + for (permission in neededPermissions) { + if (!requestedPermissionsArrayList.contains(permission)) { + undefinedPermissions.add(permission) + } + } + var undefinedPermissionArray = arrayOfNulls(undefinedPermissions.size) + undefinedPermissionArray = undefinedPermissions.toArray(undefinedPermissionArray) + return undefinedPermissionArray + } + return neededPermissions + } +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebChromeClient.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebChromeClient.kt new file mode 100644 index 00000000..211d30c8 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebChromeClient.kt @@ -0,0 +1,495 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +@file:Suppress("ObsoleteSdkInt", "RedundantOverride", "QueryPermissionsNeeded", "SimpleDateFormat") + +package com.zx.tauri_app + +// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java + +import android.Manifest +import android.app.Activity +import android.app.AlertDialog +import android.content.ActivityNotFoundException +import android.content.DialogInterface +import android.content.Intent +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.provider.MediaStore +import android.view.View +import android.webkit.* +import android.widget.EditText +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultCallback +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.FileProvider +import java.io.File +import java.io.IOException +import java.text.SimpleDateFormat +import java.util.* + +class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() { + private interface PermissionListener { + fun onPermissionSelect(isGranted: Boolean?) + } + + private interface ActivityResultListener { + fun onActivityResult(result: ActivityResult?) + } + + private val activity: WryActivity + private var permissionLauncher: ActivityResultLauncher> + private var activityLauncher: ActivityResultLauncher + private var permissionListener: PermissionListener? = null + private var activityListener: ActivityResultListener? = null + + init { + activity = appActivity + val permissionCallback = + ActivityResultCallback { isGranted: Map -> + if (permissionListener != null) { + var granted = true + for ((_, value) in isGranted) { + if (!value) granted = false + } + permissionListener!!.onPermissionSelect(granted) + } + } + permissionLauncher = + activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions(), permissionCallback) + activityLauncher = activity.registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (activityListener != null) { + activityListener!!.onActivityResult(result) + } + } + } + + /** + * Render web content in `view`. + * + * Both this method and [.onHideCustomView] are required for + * rendering web content in full screen. + * + * @see [](https://developer.android.com/reference/android/webkit/WebChromeClient.onShowCustomView + ) */ + override fun onShowCustomView(view: View, callback: CustomViewCallback) { + callback.onCustomViewHidden() + super.onShowCustomView(view, callback) + } + + /** + * Render web content in the original Web View again. + * + * Do not remove this method--@see #onShowCustomView(View, CustomViewCallback). + */ + override fun onHideCustomView() { + super.onHideCustomView() + } + + override fun onPermissionRequest(request: PermissionRequest) { + val isRequestPermissionRequired = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + val permissionList: MutableList = ArrayList() + if (listOf(*request.resources).contains("android.webkit.resource.VIDEO_CAPTURE")) { + permissionList.add(Manifest.permission.CAMERA) + } + if (listOf(*request.resources).contains("android.webkit.resource.AUDIO_CAPTURE")) { + permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS) + permissionList.add(Manifest.permission.RECORD_AUDIO) + } + if (permissionList.isNotEmpty() && isRequestPermissionRequired) { + val permissions = permissionList.toTypedArray() + permissionListener = object : PermissionListener { + override fun onPermissionSelect(isGranted: Boolean?) { + if (isGranted == true) { + request.grant(request.resources) + } else { + request.deny() + } + } + } + permissionLauncher.launch(permissions) + } else { + request.grant(request.resources) + } + } + + /** + * Show the browser alert modal + * @param view + * @param url + * @param message + * @param result + * @return + */ + override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean { + if (activity.isFinishing) { + return true + } + val builder = AlertDialog.Builder(view.context) + builder + .setMessage(message) + .setPositiveButton( + "OK" + ) { dialog: DialogInterface, _: Int -> + dialog.dismiss() + result.confirm() + } + .setOnCancelListener { dialog: DialogInterface -> + dialog.dismiss() + result.cancel() + } + val dialog = builder.create() + dialog.show() + return true + } + + /** + * Show the browser confirm modal + * @param view + * @param url + * @param message + * @param result + * @return + */ + override fun onJsConfirm(view: WebView, url: String, message: String, result: JsResult): Boolean { + if (activity.isFinishing) { + return true + } + val builder = AlertDialog.Builder(view.context) + builder + .setMessage(message) + .setPositiveButton( + "OK" + ) { dialog: DialogInterface, _: Int -> + dialog.dismiss() + result.confirm() + } + .setNegativeButton( + "Cancel" + ) { dialog: DialogInterface, _: Int -> + dialog.dismiss() + result.cancel() + } + .setOnCancelListener { dialog: DialogInterface -> + dialog.dismiss() + result.cancel() + } + val dialog = builder.create() + dialog.show() + return true + } + + /** + * Show the browser prompt modal + * @param view + * @param url + * @param message + * @param defaultValue + * @param result + * @return + */ + override fun onJsPrompt( + view: WebView, + url: String, + message: String, + defaultValue: String, + result: JsPromptResult + ): Boolean { + if (activity.isFinishing) { + return true + } + val builder = AlertDialog.Builder(view.context) + val input = EditText(view.context) + builder + .setMessage(message) + .setView(input) + .setPositiveButton( + "OK" + ) { dialog: DialogInterface, _: Int -> + dialog.dismiss() + val inputText1 = input.text.toString().trim { it <= ' ' } + result.confirm(inputText1) + } + .setNegativeButton( + "Cancel" + ) { dialog: DialogInterface, _: Int -> + dialog.dismiss() + result.cancel() + } + .setOnCancelListener { dialog: DialogInterface -> + dialog.dismiss() + result.cancel() + } + val dialog = builder.create() + dialog.show() + return true + } + + /** + * Handle the browser geolocation permission prompt + * @param origin + * @param callback + */ + override fun onGeolocationPermissionsShowPrompt( + origin: String, + callback: GeolocationPermissions.Callback + ) { + super.onGeolocationPermissionsShowPrompt(origin, callback) + Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: $origin") + val geoPermissions = + arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION) + if (!PermissionHelper.hasPermissions(activity, geoPermissions)) { + permissionListener = object : PermissionListener { + override fun onPermissionSelect(isGranted: Boolean?) { + if (isGranted == true) { + callback.invoke(origin, true, false) + } else { + val coarsePermission = + arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && + PermissionHelper.hasPermissions(activity, coarsePermission) + ) { + callback.invoke(origin, true, false) + } else { + callback.invoke(origin, false, false) + } + } + } + } + permissionLauncher.launch(geoPermissions) + } else { + // permission is already granted + callback.invoke(origin, true, false) + Logger.debug("onGeolocationPermissionsShowPrompt: has required permission") + } + } + + override fun onShowFileChooser( + webView: WebView, + filePathCallback: ValueCallback?>, + fileChooserParams: FileChooserParams + ): Boolean { + val acceptTypes = listOf(*fileChooserParams.acceptTypes) + val captureEnabled = fileChooserParams.isCaptureEnabled + val capturePhoto = captureEnabled && acceptTypes.contains("image/*") + val captureVideo = captureEnabled && acceptTypes.contains("video/*") + if (capturePhoto || captureVideo) { + if (isMediaCaptureSupported) { + showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo) + } else { + permissionListener = object : PermissionListener { + override fun onPermissionSelect(isGranted: Boolean?) { + if (isGranted == true) { + showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo) + } else { + Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted") + filePathCallback.onReceiveValue(null) + } + } + } + val camPermission = arrayOf(Manifest.permission.CAMERA) + permissionLauncher.launch(camPermission) + } + } else { + showFilePicker(filePathCallback, fileChooserParams) + } + return true + } + + private val isMediaCaptureSupported: Boolean + get() { + val permissions = arrayOf(Manifest.permission.CAMERA) + return PermissionHelper.hasPermissions(activity, permissions) || + !PermissionHelper.hasDefinedPermission(activity, Manifest.permission.CAMERA) + } + + private fun showMediaCaptureOrFilePicker( + filePathCallback: ValueCallback?>, + fileChooserParams: FileChooserParams, + isVideo: Boolean + ) { + val isVideoCaptureSupported = true + val shown = if (isVideo && isVideoCaptureSupported) { + showVideoCapturePicker(filePathCallback) + } else { + showImageCapturePicker(filePathCallback) + } + if (!shown) { + Logger.warn( + Logger.tags("FileChooser"), + "Media capture intent could not be launched. Falling back to default file picker." + ) + showFilePicker(filePathCallback, fileChooserParams) + } + } + + private fun showImageCapturePicker(filePathCallback: ValueCallback?>): Boolean { + val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) + if (takePictureIntent.resolveActivity(activity.packageManager) == null) { + return false + } + val imageFileUri: Uri = try { + createImageFileUri() + } catch (ex: Exception) { + Logger.error("Unable to create temporary media capture file: " + ex.message) + return false + } + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri) + activityListener = object : ActivityResultListener { + override fun onActivityResult(result: ActivityResult?) { + var res: Array? = null + if (result?.resultCode == Activity.RESULT_OK) { + res = arrayOf(imageFileUri) + } + filePathCallback.onReceiveValue(res) + } + } + activityLauncher.launch(takePictureIntent) + return true + } + + private fun showVideoCapturePicker(filePathCallback: ValueCallback?>): Boolean { + val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) + if (takeVideoIntent.resolveActivity(activity.packageManager) == null) { + return false + } + activityListener = object : ActivityResultListener { + override fun onActivityResult(result: ActivityResult?) { + var res: Array? = null + if (result?.resultCode == Activity.RESULT_OK) { + res = arrayOf(result.data!!.data) + } + filePathCallback.onReceiveValue(res) + } + } + activityLauncher.launch(takeVideoIntent) + return true + } + + private fun showFilePicker( + filePathCallback: ValueCallback?>, + fileChooserParams: FileChooserParams + ) { + val intent = fileChooserParams.createIntent() + if (fileChooserParams.mode == FileChooserParams.MODE_OPEN_MULTIPLE) { + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) + } + if (fileChooserParams.acceptTypes.size > 1 || intent.type!!.startsWith(".")) { + val validTypes = getValidTypes(fileChooserParams.acceptTypes) + intent.putExtra(Intent.EXTRA_MIME_TYPES, validTypes) + if (intent.type!!.startsWith(".")) { + intent.type = validTypes[0] + } + } + try { + activityListener = object : ActivityResultListener { + override fun onActivityResult(result: ActivityResult?) { + val res: Array? + val resultIntent = result?.data + if (result?.resultCode == Activity.RESULT_OK && resultIntent!!.clipData != null) { + val numFiles = resultIntent.clipData!!.itemCount + res = arrayOfNulls(numFiles) + for (i in 0 until numFiles) { + res[i] = resultIntent.clipData!!.getItemAt(i).uri + } + } else { + res = FileChooserParams.parseResult( + result?.resultCode ?: 0, + resultIntent + ) + } + filePathCallback.onReceiveValue(res) + } + } + activityLauncher.launch(intent) + } catch (e: ActivityNotFoundException) { + filePathCallback.onReceiveValue(null) + } + } + + private fun getValidTypes(currentTypes: Array): Array { + val validTypes: MutableList = ArrayList() + val mtm = MimeTypeMap.getSingleton() + for (mime in currentTypes) { + if (mime.startsWith(".")) { + val extension = mime.substring(1) + val extensionMime = mtm.getMimeTypeFromExtension(extension) + if (extensionMime != null && !validTypes.contains(extensionMime)) { + validTypes.add(extensionMime) + } + } else if (!validTypes.contains(mime)) { + validTypes.add(mime) + } + } + val validObj: Array = validTypes.toTypedArray() + return Arrays.copyOf( + validObj, validObj.size, + Array::class.java + ) + } + + override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { + val tag: String = Logger.tags("Console") + if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) { + val msg = String.format( + "File: %s - Line %d - Msg: %s", + consoleMessage.sourceId(), + consoleMessage.lineNumber(), + consoleMessage.message() + ) + val level = consoleMessage.messageLevel().name + if ("ERROR".equals(level, ignoreCase = true)) { + Logger.error(tag, msg, null) + } else if ("WARNING".equals(level, ignoreCase = true)) { + Logger.warn(tag, msg) + } else if ("TIP".equals(level, ignoreCase = true)) { + Logger.debug(tag, msg) + } else { + Logger.info(tag, msg) + } + } + return true + } + + private fun isValidMsg(msg: String): Boolean { + return !(msg.contains("%cresult %c") || + msg.contains("%cnative %c") || + msg.equals("[object Object]", ignoreCase = true) || + msg.equals("console.groupEnd", ignoreCase = true)) + } + + @Throws(IOException::class) + private fun createImageFileUri(): Uri { + val photoFile = createImageFile(activity) + return FileProvider.getUriForFile( + activity, + activity.packageName.toString() + ".fileprovider", + photoFile + ) + } + + @Throws(IOException::class) + private fun createImageFile(activity: Activity): File { + // Create an image file name + val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date()) + val imageFileName = "JPEG_" + timeStamp + "_" + val storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + return File.createTempFile(imageFileName, ".jpg", storageDir) + } + + override fun onReceivedTitle( + view: WebView, + title: String + ) { + handleReceivedTitle(view, title) + } + + private external fun handleReceivedTitle(webview: WebView, title: String) +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebView.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebView.kt new file mode 100644 index 00000000..c22de2d0 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebView.kt @@ -0,0 +1,101 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +@file:Suppress("unused", "SetJavaScriptEnabled") + +package com.zx.tauri_app + +import android.annotation.SuppressLint +import android.webkit.* +import android.content.Context +import androidx.webkit.WebViewCompat +import androidx.webkit.WebViewFeature +import kotlin.collections.Map + +@SuppressLint("RestrictedApi") +class RustWebView(context: Context, val initScripts: Array, val id: String): WebView(context) { + val isDocumentStartScriptEnabled: Boolean + + init { + settings.javaScriptEnabled = true + settings.domStorageEnabled = true + settings.setGeolocationEnabled(true) + settings.databaseEnabled = true + settings.mediaPlaybackRequiresUserGesture = false + settings.javaScriptCanOpenWindowsAutomatically = true + + if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) { + isDocumentStartScriptEnabled = true + for (script in initScripts) { + WebViewCompat.addDocumentStartJavaScript(this, script, setOf("*")); + } + } else { + isDocumentStartScriptEnabled = false + } + + + } + + fun loadUrlMainThread(url: String) { + post { + loadUrl(url) + } + } + + fun loadUrlMainThread(url: String, additionalHttpHeaders: Map) { + post { + loadUrl(url, additionalHttpHeaders) + } + } + + override fun loadUrl(url: String) { + if (!shouldOverride(url)) { + super.loadUrl(url); + } + } + + override fun loadUrl(url: String, additionalHttpHeaders: Map) { + if (!shouldOverride(url)) { + super.loadUrl(url, additionalHttpHeaders); + } + } + + fun loadHTMLMainThread(html: String) { + post { + super.loadData(html, "text/html", null) + } + } + + fun evalScript(id: Int, script: String) { + post { + super.evaluateJavascript(script) { result -> + onEval(id, result) + } + } + } + + fun clearAllBrowsingData() { + try { + super.getContext().deleteDatabase("webviewCache.db") + super.getContext().deleteDatabase("webview.db") + super.clearCache(true) + super.clearHistory() + super.clearFormData() + } catch (ex: Exception) { + Logger.error("Unable to create temporary media capture file: " + ex.message) + } + } + + fun getCookies(url: String): String { + val cookieManager = CookieManager.getInstance() + return cookieManager.getCookie(url) + } + + private external fun shouldOverride(url: String): Boolean + private external fun onEval(id: Int, result: String) + + +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebViewClient.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebViewClient.kt new file mode 100644 index 00000000..7b9cc2c0 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/RustWebViewClient.kt @@ -0,0 +1,107 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.zx.tauri_app + +import android.net.Uri +import android.webkit.* +import android.content.Context +import android.graphics.Bitmap +import android.os.Handler +import android.os.Looper +import androidx.webkit.WebViewAssetLoader + +class RustWebViewClient(context: Context): WebViewClient() { + private val interceptedState = mutableMapOf() + var currentUrl: String = "about:blank" + private var lastInterceptedUrl: Uri? = null + private var pendingUrlRedirect: String? = null + + private val assetLoader = WebViewAssetLoader.Builder() + .setDomain(assetLoaderDomain()) + .addPathHandler("/", WebViewAssetLoader.AssetsPathHandler(context)) + .build() + + override fun shouldInterceptRequest( + view: WebView, + request: WebResourceRequest + ): WebResourceResponse? { + pendingUrlRedirect?.let { + Handler(Looper.getMainLooper()).post { + view.loadUrl(it) + } + pendingUrlRedirect = null + return null + } + + lastInterceptedUrl = request.url + return if (withAssetLoader()) { + assetLoader.shouldInterceptRequest(request.url) + } else { + val rustWebview = view as RustWebView; + val response = handleRequest(rustWebview.id, request, rustWebview.isDocumentStartScriptEnabled) + interceptedState[request.url.toString()] = response != null + return response + } + } + + override fun shouldOverrideUrlLoading( + view: WebView, + request: WebResourceRequest + ): Boolean { + return shouldOverride(request.url.toString()) + } + + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + currentUrl = url + if (interceptedState[url] == false) { + val webView = view as RustWebView + for (script in webView.initScripts) { + view.evaluateJavascript(script, null) + } + } + return onPageLoading(url) + } + + override fun onPageFinished(view: WebView, url: String) { + onPageLoaded(url) + } + + override fun onReceivedError( + view: WebView, + request: WebResourceRequest, + error: WebResourceError + ) { + // we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol + // e.g. oauth flow, because shouldInterceptRequest is not called on redirects + // so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in + if (error.errorCode == ERROR_CONNECT && request.isForMainFrame && request.url != lastInterceptedUrl) { + // prevent the default error page from showing + view.stopLoading() + // without this initial loadUrl the app is stuck + view.loadUrl(request.url.toString()) + // ensure the URL is actually loaded - for some reason there's a race condition and we need to call loadUrl() again later + pendingUrlRedirect = request.url.toString() + } else { + super.onReceivedError(view, request, error) + } + } + + companion object { + init { + System.loadLibrary("tauri_app_lib") + } + } + + private external fun assetLoaderDomain(): String + private external fun withAssetLoader(): Boolean + private external fun handleRequest(webviewId: String, request: WebResourceRequest, isDocumentStartScriptEnabled: Boolean): WebResourceResponse? + private external fun shouldOverride(url: String): Boolean + private external fun onPageLoading(url: String) + private external fun onPageLoaded(url: String) + + +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/TauriActivity.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/TauriActivity.kt new file mode 100644 index 00000000..1d5cd60b --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/TauriActivity.kt @@ -0,0 +1,30 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +package com.zx.tauri_app + +import android.os.Bundle +import android.content.Intent +import app.tauri.plugin.PluginManager + +abstract class TauriActivity : WryActivity() { + var pluginManager: PluginManager = PluginManager(this) + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + pluginManager.onNewIntent(intent) + } + + override fun onResume() { + super.onResume() + pluginManager.onResume() + } + + override fun onPause() { + super.onPause() + pluginManager.onPause() + } +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/WryActivity.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/WryActivity.kt new file mode 100644 index 00000000..27df53b8 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/WryActivity.kt @@ -0,0 +1,136 @@ +/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */ + +// Copyright 2020-2023 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.zx.tauri_app + +import com.zx.tauri_app.RustWebView +import android.annotation.SuppressLint +import android.os.Build +import android.os.Bundle +import android.webkit.WebView +import android.view.KeyEvent +import androidx.appcompat.app.AppCompatActivity + +abstract class WryActivity : AppCompatActivity() { + private lateinit var mWebView: RustWebView + + open fun onWebViewCreate(webView: WebView) { } + + fun setWebView(webView: RustWebView) { + mWebView = webView + onWebViewCreate(webView) + } + + val version: String + @SuppressLint("WebViewApiAvailability", "ObsoleteSdkInt") + get() { + // Check getCurrentWebViewPackage() directly if above Android 8 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return WebView.getCurrentWebViewPackage()?.versionName ?: "" + } + + // Otherwise manually check WebView versions + var webViewPackage = "com.google.android.webview" + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + webViewPackage = "com.android.chrome" + } + try { + @Suppress("DEPRECATION") + val info = packageManager.getPackageInfo(webViewPackage, 0) + return info.versionName.toString() + } catch (ex: Exception) { + Logger.warn("Unable to get package info for '$webViewPackage'$ex") + } + + try { + @Suppress("DEPRECATION") + val info = packageManager.getPackageInfo("com.android.webview", 0) + return info.versionName.toString() + } catch (ex: Exception) { + Logger.warn("Unable to get package info for 'com.android.webview'$ex") + } + + // Could not detect any webview, return empty string + return "" + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + create(this) + } + + override fun onStart() { + super.onStart() + start() + } + + override fun onResume() { + super.onResume() + resume() + } + + override fun onPause() { + super.onPause() + pause() + } + + override fun onStop() { + super.onStop() + stop() + } + + override fun onWindowFocusChanged(hasFocus: Boolean) { + super.onWindowFocusChanged(hasFocus) + focus(hasFocus) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + save() + } + + override fun onDestroy() { + super.onDestroy() + destroy() + onActivityDestroy() + } + + override fun onLowMemory() { + super.onLowMemory() + memory() + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { + if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { + mWebView.goBack() + return true + } + return super.onKeyDown(keyCode, event) + } + + fun getAppClass(name: String): Class<*> { + return Class.forName(name) + } + + companion object { + init { + System.loadLibrary("tauri_app_lib") + } + } + + private external fun create(activity: WryActivity) + private external fun start() + private external fun resume() + private external fun pause() + private external fun stop() + private external fun save() + private external fun destroy() + private external fun onActivityDestroy() + private external fun memory() + private external fun focus(focus: Boolean) + + +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/proguard-wry.pro b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/proguard-wry.pro new file mode 100644 index 00000000..3194a7c7 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/app/src/main/java/com/zx/tauri_app/generated/proguard-wry.pro @@ -0,0 +1,35 @@ +# THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! + +# Copyright 2020-2023 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +-keep class com.zx.tauri_app.* { + native ; +} + +-keep class com.zx.tauri_app.WryActivity { + public (...); + + void setWebView(com.zx.tauri_app.RustWebView); + java.lang.Class getAppClass(...); + java.lang.String getVersion(); +} + +-keep class com.zx.tauri_app.Ipc { + public (...); + + @android.webkit.JavascriptInterface public ; +} + +-keep class com.zx.tauri_app.RustWebView { + public (...); + + void loadUrlMainThread(...); + void loadHTMLMainThread(...); + void evalScript(...); +} + +-keep class com.zx.tauri_app.RustWebChromeClient,com.zx.tauri_app.RustWebViewClient { + public (...); +} diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/BuildTask.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/BuildTask.kt new file mode 100644 index 00000000..293ec8eb --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/BuildTask.kt @@ -0,0 +1,52 @@ +import java.io.File +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +open class BuildTask : DefaultTask() { + @Input + var rootDirRel: String? = null + @Input + var target: String? = null + @Input + var release: Boolean? = null + + @TaskAction + fun assemble() { + val executable = """npm"""; + try { + runTauriCli(executable) + } catch (e: Exception) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + runTauriCli("$executable.cmd") + } else { + throw e; + } + } + } + + fun runTauriCli(executable: String) { + val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") + val target = target ?: throw GradleException("target cannot be null") + val release = release ?: throw GradleException("release cannot be null") + val args = listOf("run", "--", "tauri", "android", "android-studio-script"); + + project.exec { + workingDir(File(project.projectDir, rootDirRel)) + executable(executable) + args(args) + if (project.logger.isEnabled(LogLevel.DEBUG)) { + args("-vv") + } else if (project.logger.isEnabled(LogLevel.INFO)) { + args("-v") + } + if (release) { + args("--release") + } + args(listOf("--target", target)) + }.assertNormalExitValue() + } +} \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/RustPlugin.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/RustPlugin.kt new file mode 100644 index 00000000..a1c766e8 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android/buildSrc/src/main/java/com/zx/tauri_app/kotlin/RustPlugin.kt @@ -0,0 +1,85 @@ +import com.android.build.api.dsl.ApplicationExtension +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.get + +const val TASK_GROUP = "rust" + +open class Config { + lateinit var rootDirRel: String +} + +open class RustPlugin : Plugin { + private lateinit var config: Config + + override fun apply(project: Project) = with(project) { + config = extensions.create("rust", Config::class.java) + + val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); + val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList + + val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); + val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList + + val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") + + extensions.configure { + @Suppress("UnstableApiUsage") + flavorDimensions.add("abi") + productFlavors { + create("universal") { + dimension = "abi" + ndk { + abiFilters += abiList + } + } + defaultArchList.forEachIndexed { index, arch -> + create(arch) { + dimension = "abi" + ndk { + abiFilters.add(defaultAbiList[index]) + } + } + } + } + } + + afterEvaluate { + for (profile in listOf("debug", "release")) { + val profileCapitalized = profile.replaceFirstChar { it.uppercase() } + val buildTask = tasks.maybeCreate( + "rustBuildUniversal$profileCapitalized", + DefaultTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for all targets" + } + + tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) + + for (targetPair in targetsList.withIndex()) { + val targetName = targetPair.value + val targetArch = archList[targetPair.index] + val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } + val targetBuildTask = project.tasks.maybeCreate( + "rustBuild$targetArchCapitalized$profileCapitalized", + BuildTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for $targetArch" + rootDirRel = config.rootDirRel + target = targetName + release = profile == "release" + } + + buildTask.dependsOn(targetBuildTask) + tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( + targetBuildTask + ) + } + } + } + } +} \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.editorconfig b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.editorconfig new file mode 100644 index 00000000..ebe51d3b --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.gitignore b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.gitignore new file mode 100644 index 00000000..b2482031 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/.gitignore @@ -0,0 +1,19 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +build +/captures +.externalNativeBuild +.cxx +local.properties +key.properties + +/.tauri +/tauri.settings.gradle \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/.gitignore b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/.gitignore new file mode 100644 index 00000000..4008dd74 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/.gitignore @@ -0,0 +1,6 @@ +/src/main/java/com/tauri/api/generated +/src/main/jniLibs/**/*.so +/src/main/assets/tauri.conf.json +/tauri.build.gradle.kts +/proguard-tauri.pro +/tauri.properties \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/build.gradle.kts b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/build.gradle.kts new file mode 100644 index 00000000..f7047ca0 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/build.gradle.kts @@ -0,0 +1,69 @@ +import java.util.Properties + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("rust") +} + +val tauriProperties = Properties().apply { + val propFile = file("tauri.properties") + if (propFile.exists()) { + propFile.inputStream().use { load(it) } + } +} + +android { + compileSdk = 34 + namespace = "com.tauri.api" + defaultConfig { + manifestPlaceholders["usesCleartextTraffic"] = "false" + applicationId = "com.tauri.api" + minSdk = 24 + targetSdk = 34 + versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() + versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") + } + buildTypes { + getByName("debug") { + manifestPlaceholders["usesCleartextTraffic"] = "true" + isDebuggable = true + isJniDebuggable = true + isMinifyEnabled = false + packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") + jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") + jniLibs.keepDebugSymbols.add("*/x86/*.so") + jniLibs.keepDebugSymbols.add("*/x86_64/*.so") + } + } + getByName("release") { + isMinifyEnabled = true + proguardFiles( + *fileTree(".") { include("**/*.pro") } + .plus(getDefaultProguardFile("proguard-android-optimize.txt")) + .toList().toTypedArray() + ) + } + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + buildConfig = true + } +} + +rust { + rootDirRel = "../../../" +} + +dependencies { + implementation("androidx.webkit:webkit:1.6.1") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.8.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.4") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") +} + +apply(from = "tauri.build.gradle.kts") \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/proguard-rules.pro b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/AndroidManifest.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8ebe7c4b --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/AndroidManifest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/java/com/tauri/api/MainActivity.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/java/com/tauri/api/MainActivity.kt new file mode 100644 index 00000000..0a05f42b --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/java/com/tauri/api/MainActivity.kt @@ -0,0 +1,3 @@ +package com.tauri.api + +class MainActivity : TauriActivity() \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable/ic_launcher_background.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/layout/activity_main.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..4fc24441 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..28f1aa11 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..85d0c88a Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..28f1aa11 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..73e48dbf Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..13dd2147 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..73e48dbf Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..1d98044f Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..a888b336 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..1d98044f Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..08183246 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..a2a838e7 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..08183246 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..b18bceb6 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 00000000..3f8a57f3 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..b18bceb6 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values-night/themes.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..f0378527 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values-night/themes.xml @@ -0,0 +1,6 @@ + + + + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/colors.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8c6127d --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/strings.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..6f4305e0 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + Tauri API + Tauri API + \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/themes.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..f0378527 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/values/themes.xml @@ -0,0 +1,6 @@ + + + + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/xml/file_paths.xml b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/xml/file_paths.xml new file mode 100644 index 00000000..782d63b9 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/build.gradle.kts b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/build.gradle.kts new file mode 100644 index 00000000..c5ef452a --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/build.gradle.kts @@ -0,0 +1,22 @@ +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:8.5.1") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +tasks.register("clean").configure { + delete("build") +} + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/build.gradle.kts b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/build.gradle.kts new file mode 100644 index 00000000..39e90b05 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + `kotlin-dsl` +} + +gradlePlugin { + plugins { + create("pluginsForCoolKids") { + id = "rust" + implementationClass = "RustPlugin" + } + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + compileOnly(gradleApi()) + implementation("com.android.tools.build:gradle:8.5.1") +} + diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/BuildTask.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/BuildTask.kt new file mode 100644 index 00000000..f9874825 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/BuildTask.kt @@ -0,0 +1,52 @@ +import java.io.File +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +open class BuildTask : DefaultTask() { + @Input + var rootDirRel: String? = null + @Input + var target: String? = null + @Input + var release: Boolean? = null + + @TaskAction + fun assemble() { + val executable = """pnpm"""; + try { + runTauriCli(executable) + } catch (e: Exception) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + runTauriCli("$executable.cmd") + } else { + throw e; + } + } + } + + fun runTauriCli(executable: String) { + val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") + val target = target ?: throw GradleException("target cannot be null") + val release = release ?: throw GradleException("release cannot be null") + val args = listOf("tauri", "android", "android-studio-script"); + + project.exec { + workingDir(File(project.projectDir, rootDirRel)) + executable(executable) + args(args) + if (project.logger.isEnabled(LogLevel.DEBUG)) { + args("-vv") + } else if (project.logger.isEnabled(LogLevel.INFO)) { + args("-v") + } + if (release) { + args("--release") + } + args(listOf("--target", target)) + }.assertNormalExitValue() + } +} \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/RustPlugin.kt b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/RustPlugin.kt new file mode 100644 index 00000000..4aa7fcaf --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/buildSrc/src/main/java/com/tauri/api/kotlin/RustPlugin.kt @@ -0,0 +1,85 @@ +import com.android.build.api.dsl.ApplicationExtension +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.get + +const val TASK_GROUP = "rust" + +open class Config { + lateinit var rootDirRel: String +} + +open class RustPlugin : Plugin { + private lateinit var config: Config + + override fun apply(project: Project) = with(project) { + config = extensions.create("rust", Config::class.java) + + val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64"); + val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList + + val defaultArchList = listOf("arm64", "arm", "x86", "x86_64"); + val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList + + val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64") + + extensions.configure { + @Suppress("UnstableApiUsage") + flavorDimensions.add("abi") + productFlavors { + create("universal") { + dimension = "abi" + ndk { + abiFilters += abiList + } + } + defaultArchList.forEachIndexed { index, arch -> + create(arch) { + dimension = "abi" + ndk { + abiFilters.add(defaultAbiList[index]) + } + } + } + } + } + + afterEvaluate { + for (profile in listOf("debug", "release")) { + val profileCapitalized = profile.replaceFirstChar { it.uppercase() } + val buildTask = tasks.maybeCreate( + "rustBuildUniversal$profileCapitalized", + DefaultTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for all targets" + } + + tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) + + for (targetPair in targetsList.withIndex()) { + val targetName = targetPair.value + val targetArch = archList[targetPair.index] + val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } + val targetBuildTask = project.tasks.maybeCreate( + "rustBuild$targetArchCapitalized$profileCapitalized", + BuildTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for $targetArch" + rootDirRel = config.rootDirRel + target = targetName + release = profile == "release" + } + + buildTask.dependsOn(targetBuildTask) + tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( + targetBuildTask + ) + } + } + } + } +} \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle.properties b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle.properties new file mode 100644 index 00000000..2a7ec695 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.jar b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.jar differ diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.properties b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..0df10d55 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue May 10 19:22:52 CST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew new file mode 100644 index 00000000..4f906e0c --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew.bat b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/packages/kbot/gui/tauri-app/src-tauri/gen/android_/settings.gradle b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/settings.gradle new file mode 100644 index 00000000..39391166 --- /dev/null +++ b/packages/kbot/gui/tauri-app/src-tauri/gen/android_/settings.gradle @@ -0,0 +1,3 @@ +include ':app' + +apply from: 'tauri.settings.gradle' diff --git a/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs b/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs index ed75e89a..ee36a076 100644 --- a/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs +++ b/packages/kbot/gui/tauri-app/src-tauri/src/lib.rs @@ -3,9 +3,15 @@ use serde::{Serialize, Deserialize}; mod handlers; mod stdin_processor; + +// Desktop-only modules +#[cfg(not(any(target_os = "android", target_os = "ios")))] mod clipboard; pub use handlers::*; + +// Desktop-only exports +#[cfg(not(any(target_os = "android", target_os = "ios")))] pub use clipboard::*; #[derive(Serialize)] @@ -44,13 +50,27 @@ pub struct DebugPayload { #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - let app = tauri::Builder::default() + let mut builder = tauri::Builder::default() .manage(Counter(std::sync::Mutex::new(0))) .manage(DebugMessages(std::sync::Mutex::new(Vec::new()))) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_fs::init()) - .plugin(tauri_plugin_http::init()) + .plugin(tauri_plugin_http::init()); + + // Desktop-only plugins + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + builder = builder + .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_process::init()) + .plugin(tauri_plugin_upload::init()) + .plugin(tauri_plugin_clipboard_manager::init()); + } + + // Desktop invoke handlers (includes clipboard functions) + #[cfg(not(any(target_os = "android", target_os = "ios")))] + let app = builder .invoke_handler(tauri::generate_handler![ submit_prompt, log_error_to_console, @@ -69,7 +89,31 @@ pub fn run() { generate_image_via_backend, request_file_deletion, ipc_parse_clipboard_images - ]) + ]); + + // Mobile invoke handlers (no clipboard functions) + #[cfg(any(target_os = "android", target_os = "ios"))] + let app = builder + .invoke_handler(tauri::generate_handler![ + submit_prompt, + log_error_to_console, + resolve_path_relative_to_home, + increment_counter, + get_counter, + reset_counter, + add_debug_message, + get_debug_messages, + clear_debug_messages, + send_message_to_stdout, + send_ipc_message, + request_config_from_images, + forward_config_to_frontend, + forward_image_to_frontend, + generate_image_via_backend, + request_file_deletion + ]); + + let app = app .setup(|app| { #[cfg(debug_assertions)] // only include this code on debug builds {