mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 12:28:42 +00:00
feat(android): integrate web api & native AI chat button (#10239)
This commit is contained in:
@@ -67,12 +67,15 @@ dependencies {
|
||||
implementation project(':capacitor-cordova-android-plugins')
|
||||
implementation project(':service')
|
||||
implementation libs.kotlinx.coroutines.core
|
||||
implementation libs.kotlinx.coroutines.android
|
||||
implementation libs.androidx.appcompat
|
||||
implementation libs.androidx.browser
|
||||
implementation libs.androidx.coordinatorlayout
|
||||
implementation libs.androidx.core.splashscreen
|
||||
implementation libs.androidx.core.ktx
|
||||
implementation libs.androidx.material3
|
||||
implementation libs.apollo.runtime
|
||||
implementation libs.google.material
|
||||
implementation libs.jna
|
||||
testImplementation libs.junit
|
||||
androidTestImplementation libs.androidx.junit
|
||||
|
||||
@@ -1,26 +1,80 @@
|
||||
package app.affine.pro
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.RequiresApi
|
||||
import android.content.res.ColorStateList
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateMargins
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import app.affine.pro.plugin.AIButtonPlugin
|
||||
import app.affine.pro.plugin.AffineThemePlugin
|
||||
import app.affine.pro.utils.dp
|
||||
import com.getcapacitor.BridgeActivity
|
||||
import com.getcapacitor.plugin.CapacitorCookies
|
||||
import com.getcapacitor.plugin.CapacitorHttp
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
class MainActivity : BridgeActivity() {
|
||||
class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AffineThemePlugin.Callback,
|
||||
View.OnClickListener {
|
||||
|
||||
init {
|
||||
registerPlugins(
|
||||
listOf(
|
||||
AffineThemePlugin::class.java,
|
||||
AIButtonPlugin::class.java,
|
||||
CapacitorHttp::class.java,
|
||||
CapacitorCookies::class.java,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
private val fab: FloatingActionButton by lazy {
|
||||
FloatingActionButton(this).apply {
|
||||
visibility = View.GONE
|
||||
layoutParams = CoordinatorLayout.LayoutParams(dp(52), dp(52)).apply {
|
||||
gravity = Gravity.END or Gravity.BOTTOM
|
||||
updateMargins(0, 0, dp(24), dp(86))
|
||||
}
|
||||
customSize = dp(52)
|
||||
setImageResource(R.drawable.ic_ai)
|
||||
setOnClickListener(this@MainActivity)
|
||||
val parent = bridge.webView.parent as CoordinatorLayout
|
||||
parent.addView(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun present() {
|
||||
lifecycleScope.launch {
|
||||
fab.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
lifecycleScope.launch {
|
||||
fab.hide()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onThemeChanged(darkMode: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
fab.backgroundTintList = ColorStateList.valueOf(
|
||||
ContextCompat.getColor(
|
||||
this@MainActivity,
|
||||
if (darkMode) {
|
||||
R.color.layer_background_primary_dark
|
||||
} else {
|
||||
R.color.layer_background_primary
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
Toast.makeText(this, "TODO: Start AI chat~", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package app.affine.pro.plugin
|
||||
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
|
||||
@CapacitorPlugin(name = "AIButton")
|
||||
class AIButtonPlugin : Plugin() {
|
||||
|
||||
interface Callback {
|
||||
fun present()
|
||||
fun dismiss()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun present(call: PluginCall) {
|
||||
(activity as? Callback)?.present()
|
||||
call.resolve()
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun dismiss(call: PluginCall) {
|
||||
(activity as? Callback)?.dismiss()
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package app.affine.pro.plugin
|
||||
|
||||
import com.getcapacitor.Plugin
|
||||
import com.getcapacitor.PluginCall
|
||||
import com.getcapacitor.PluginMethod
|
||||
import com.getcapacitor.annotation.CapacitorPlugin
|
||||
|
||||
@CapacitorPlugin(name = "AffineTheme")
|
||||
class AffineThemePlugin : Plugin() {
|
||||
|
||||
interface Callback {
|
||||
fun onThemeChanged(darkMode: Boolean)
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun onThemeChanged(call: PluginCall) {
|
||||
(bridge.activity as? Callback)?.onThemeChanged(call.data.optBoolean("darkMode"))
|
||||
call.resolve()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package app.affine.pro.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
|
||||
fun Context.dp(dp: Int) = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.toFloat(),
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.174,5.491C12.133,5.13 11.828,4.858 11.465,4.857C11.102,4.857 10.796,5.129 10.754,5.49C10.484,7.835 9.783,9.484 8.651,10.616C7.52,11.747 5.871,12.448 3.525,12.719C3.164,12.761 2.892,13.066 2.893,13.429C2.893,13.792 3.166,14.097 3.526,14.138C5.833,14.4 7.518,15.101 8.676,16.238C9.83,17.371 10.546,19.02 10.752,21.349C10.785,21.718 11.094,22 11.465,22C11.835,22 12.144,21.716 12.176,21.347C12.374,19.056 13.089,17.373 14.249,16.213C15.408,15.054 17.092,14.339 19.383,14.14C19.752,14.108 20.035,13.8 20.035,13.429C20.036,13.059 19.753,12.75 19.384,12.717C17.055,12.51 15.406,11.794 14.273,10.64C13.136,9.482 12.435,7.798 12.174,5.491Z"
|
||||
android:fillColor="#1E96EB"/>
|
||||
<path
|
||||
android:pathData="M19.835,2.247C19.819,2.106 19.701,2 19.559,2C19.418,2 19.299,2.106 19.283,2.246C19.178,3.158 18.905,3.8 18.465,4.239C18.025,4.679 17.384,4.952 16.472,5.057C16.332,5.074 16.226,5.192 16.226,5.334C16.226,5.475 16.332,5.593 16.472,5.609C17.369,5.711 18.025,5.984 18.475,6.426C18.924,6.866 19.202,7.508 19.283,8.413C19.295,8.557 19.416,8.667 19.56,8.667C19.704,8.667 19.824,8.556 19.836,8.413C19.913,7.522 20.191,6.867 20.642,6.416C21.093,5.965 21.748,5.687 22.639,5.61C22.782,5.598 22.892,5.478 22.893,5.334C22.893,5.19 22.783,5.069 22.639,5.057C21.734,4.976 21.092,4.698 20.652,4.249C20.209,3.799 19.937,3.144 19.835,2.247Z"
|
||||
android:fillColor="#1E96EB"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="layer.background.primary">#FFFFFF</color>
|
||||
<color name="layer.background.primary.dark">#141414</color>
|
||||
</resources>
|
||||
@@ -1,13 +1,15 @@
|
||||
[versions]
|
||||
androidxEspressoCoreVersion = "3.6.1"
|
||||
androidxJunitVersion = "1.2.1"
|
||||
androidxEspressoCore = "3.6.1"
|
||||
androidxJunit = "1.2.1"
|
||||
browser = "1.8.0"
|
||||
coreKtx = "1.15.0"
|
||||
coreSplashScreenVersion = "1.0.1"
|
||||
material = "1.12.0"
|
||||
material3 = "1.3.1"
|
||||
coreSplashScreen = "1.0.1"
|
||||
jna = "5.16.0"
|
||||
junitVersion = "4.13.2"
|
||||
kotlin = "2.1.10"
|
||||
kotlinxCoroutinesCore = "1.10.1"
|
||||
kotlinxCoroutines = "1.10.1"
|
||||
rustAndroid = "0.9.6"
|
||||
appcompat = "1.7.0"
|
||||
coordinatorLayout = "1.2.0"
|
||||
@@ -20,12 +22,15 @@ androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "a
|
||||
androidx-browser = { module = "androidx.browser:browser", version.ref = "browser" }
|
||||
androidx-coordinatorlayout = { module = "androidx.coordinatorlayout:coordinatorlayout", version.ref = "coordinatorLayout" }
|
||||
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
|
||||
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashScreenVersion" }
|
||||
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidxEspressoCoreVersion" }
|
||||
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidxJunitVersion" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
|
||||
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashScreen" }
|
||||
androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidxEspressoCore" }
|
||||
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidxJunit" }
|
||||
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutines"}
|
||||
|
||||
google-services = { module = "com.google.gms:google-services", version.ref = "googleServices" }
|
||||
google-material = { module = "com.google.android.material:material", version.ref = "material" }
|
||||
android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" }
|
||||
jna = { module = "net.java.dev.jna:jna", version.ref = "jna" }
|
||||
junit = { module = "junit:junit", version.ref = "junitVersion" }
|
||||
|
||||
Reference in New Issue
Block a user