capacitor-sora-editor 0.0.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +32 -32
- package/android/src/main/AndroidManifest.xml +6 -9
- package/android/src/main/java/com/abc15018045126/capacitor/soraeditor/SoraEditorPlugin.kt +227 -0
- package/android/src/main/java/com/{github/soraeditor/capacitor/EditorActivity.kt → abc15018045126/capacitor/soraeditor/compose/ComposeEditorActivity.kt} +8 -7
- package/android/src/main/java/com/{github/soraeditor/capacitor → abc15018045126/capacitor/soraeditor/compose}/EditorViewModel.kt +15 -4
- package/android/src/main/java/com/{github/soraeditor/capacitor → abc15018045126/capacitor/soraeditor/compose}/ui/EditorScreen.kt +17 -5
- package/android/src/main/java/com/abc15018045126/capacitor/soraeditor/compose/ui/SoraEditorWrapper.kt +104 -0
- package/android/src/main/java/com/{github/soraeditor/capacitor → abc15018045126/capacitor/soraeditor/compose}/ui/theme/Theme.kt +1 -1
- package/capacitor-sora-editor-1.0.0.tgz +0 -0
- package/dist/esm/definitions.d.ts +39 -0
- package/dist/esm/definitions.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +21 -1
- package/dist/esm/web.d.ts.map +1 -0
- package/dist/esm/web.js +25 -2
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +25 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +25 -2
- package/dist/plugin.js.map +1 -1
- package/package.json +11 -60
- package/rollup.config.mjs +22 -0
- package/src/definitions.ts +32 -0
- package/src/index.ts +9 -0
- package/src/web.ts +32 -0
- package/tsconfig.json +26 -0
- package/README.md +0 -110
- package/android/src/main/java/com/github/soraeditor/capacitor/SoraEditorPlugin.kt +0 -33
- package/android/src/main/res/values/styles.xml +0 -6
package/android/build.gradle
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
compileSdkVersion = project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : 35
|
|
3
|
+
minSdkVersion = project.hasProperty('minSdkVersion') ? project.minSdkVersion : 26
|
|
4
|
+
targetSdkVersion = project.hasProperty('targetSdkVersion') ? project.targetSdkVersion : 35
|
|
5
|
+
}
|
|
6
|
+
|
|
1
7
|
buildscript {
|
|
2
8
|
repositories {
|
|
3
9
|
google()
|
|
4
10
|
mavenCentral()
|
|
5
11
|
}
|
|
6
12
|
dependencies {
|
|
7
|
-
classpath 'com.android.tools.build:gradle:8.2
|
|
8
|
-
classpath
|
|
9
|
-
classpath
|
|
13
|
+
classpath 'com.android.tools.build:gradle:8.7.2'
|
|
14
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0"
|
|
15
|
+
classpath "org.jetbrains.kotlin:compose-compiler-gradle-plugin:2.1.0"
|
|
10
16
|
}
|
|
11
17
|
}
|
|
12
18
|
|
|
@@ -15,31 +21,30 @@ apply plugin: 'kotlin-android'
|
|
|
15
21
|
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
|
16
22
|
|
|
17
23
|
android {
|
|
18
|
-
namespace "com.
|
|
19
|
-
compileSdk
|
|
24
|
+
namespace "com.abc15018045126.capacitor.soraeditor"
|
|
25
|
+
compileSdk project.ext.compileSdkVersion
|
|
20
26
|
|
|
21
27
|
defaultConfig {
|
|
22
|
-
minSdkVersion
|
|
23
|
-
targetSdkVersion
|
|
24
|
-
versionCode 1
|
|
25
|
-
versionName "1.0"
|
|
26
|
-
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
27
|
-
consumerProguardFiles "consumer-rules.pro"
|
|
28
|
+
minSdk project.ext.minSdkVersion
|
|
29
|
+
targetSdk project.ext.targetSdkVersion
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
buildTypes {
|
|
31
|
-
release {
|
|
32
|
-
minifyEnabled false
|
|
33
|
-
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
32
|
compileOptions {
|
|
37
33
|
sourceCompatibility JavaVersion.VERSION_21
|
|
38
34
|
targetCompatibility JavaVersion.VERSION_21
|
|
39
35
|
}
|
|
36
|
+
|
|
40
37
|
kotlinOptions {
|
|
41
38
|
jvmTarget = '21'
|
|
42
39
|
}
|
|
40
|
+
|
|
41
|
+
buildTypes {
|
|
42
|
+
release {
|
|
43
|
+
minifyEnabled false
|
|
44
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
43
48
|
buildFeatures {
|
|
44
49
|
compose true
|
|
45
50
|
}
|
|
@@ -53,25 +58,20 @@ repositories {
|
|
|
53
58
|
dependencies {
|
|
54
59
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
55
60
|
implementation project(':capacitor-android')
|
|
56
|
-
implementation "androidx.appcompat:appcompat
|
|
57
|
-
implementation "androidx.core:core-ktx:1.
|
|
61
|
+
implementation "androidx.appcompat:appcompat:1.7.0"
|
|
62
|
+
implementation "androidx.core:core-ktx:1.15.0"
|
|
58
63
|
|
|
59
|
-
// Sora Editor
|
|
60
|
-
implementation 'io.github.
|
|
61
|
-
implementation 'io.github.
|
|
64
|
+
// Correct Maven coordinates for Sora Editor
|
|
65
|
+
implementation 'io.github.rosemoe:editor:0.24.4'
|
|
66
|
+
implementation 'io.github.rosemoe:language-textmate:0.24.4'
|
|
62
67
|
|
|
63
|
-
//
|
|
64
|
-
def composeBom = platform('androidx.compose:compose-bom:2024.
|
|
68
|
+
// Compose
|
|
69
|
+
def composeBom = platform('androidx.compose:compose-bom:2024.12.01')
|
|
65
70
|
implementation composeBom
|
|
66
71
|
implementation 'androidx.compose.ui:ui'
|
|
67
72
|
implementation 'androidx.compose.material3:material3'
|
|
68
73
|
implementation 'androidx.compose.material:material-icons-extended'
|
|
69
|
-
implementation 'androidx.activity:activity-compose:1.
|
|
70
|
-
implementation 'androidx.
|
|
71
|
-
implementation 'androidx.lifecycle:lifecycle-
|
|
72
|
-
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.7.0'
|
|
73
|
-
|
|
74
|
-
testImplementation "junit:junit:4.13.2"
|
|
75
|
-
androidTestImplementation "androidx.test.ext:junit:1.1.5"
|
|
76
|
-
androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
|
|
74
|
+
implementation 'androidx.activity:activity-compose:1.10.0'
|
|
75
|
+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7'
|
|
76
|
+
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.7'
|
|
77
77
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<!-- Permissions can be added here if needed, e.g. READ_EXTERNAL_STORAGE -->
|
|
5
|
-
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
6
3
|
<application>
|
|
7
4
|
<activity
|
|
8
|
-
android:name=".
|
|
9
|
-
android:theme="@style/Theme.AppCompat.NoActionBar"
|
|
10
|
-
android:
|
|
11
|
-
|
|
5
|
+
android:name="com.abc15018045126.capacitor.soraeditor.compose.ComposeEditorActivity"
|
|
6
|
+
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
|
7
|
+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
|
|
8
|
+
android:exported="false" />
|
|
12
9
|
</application>
|
|
13
10
|
</manifest>
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
package com.abc15018045126.capacitor.soraeditor
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.widget.FrameLayout
|
|
7
|
+
import com.getcapacitor.JSObject
|
|
8
|
+
import com.getcapacitor.Plugin
|
|
9
|
+
import com.getcapacitor.PluginCall
|
|
10
|
+
import com.getcapacitor.PluginMethod
|
|
11
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
12
|
+
import io.github.rosemoe.sora.widget.CodeEditor
|
|
13
|
+
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
|
14
|
+
|
|
15
|
+
@CapacitorPlugin(name = "SoraEditor")
|
|
16
|
+
class SoraEditorPlugin : Plugin() {
|
|
17
|
+
|
|
18
|
+
private var editor: CodeEditor? = null
|
|
19
|
+
|
|
20
|
+
@PluginMethod
|
|
21
|
+
fun start(call: PluginCall) {
|
|
22
|
+
val content = call.getString("content") ?: ""
|
|
23
|
+
val topMargin = call.getInt("top") ?: 0
|
|
24
|
+
val leftMargin = call.getInt("left") ?: 0
|
|
25
|
+
val rightMargin = call.getInt("right") ?: 0
|
|
26
|
+
val bottomMargin = call.getInt("bottom") ?: 0
|
|
27
|
+
val width = call.getInt("width") ?: -1 // -1 = MATCH_PARENT
|
|
28
|
+
val height = call.getInt("height") ?: -1
|
|
29
|
+
val fontSize = call.getFloat("fontSize") ?: 18f
|
|
30
|
+
val showLineNumbers = call.getBoolean("showLineNumbers") ?: true
|
|
31
|
+
val wordWrap = call.getBoolean("wordWrap") ?: false
|
|
32
|
+
val editable = call.getBoolean("editable") ?: true
|
|
33
|
+
val bgColorStr = call.getString("backgroundColor") // e.g. "#FFFFFF"
|
|
34
|
+
|
|
35
|
+
activity.runOnUiThread {
|
|
36
|
+
if (editor == null) {
|
|
37
|
+
editor = CodeEditor(context).apply {
|
|
38
|
+
setTextSize(fontSize)
|
|
39
|
+
setTypefaceText(Typeface.MONOSPACE)
|
|
40
|
+
isLineNumberEnabled = showLineNumbers
|
|
41
|
+
isWordwrap = wordWrap
|
|
42
|
+
setEditable(editable)
|
|
43
|
+
|
|
44
|
+
var startX = 0f
|
|
45
|
+
var startY = 0f
|
|
46
|
+
var startTime = 0L
|
|
47
|
+
|
|
48
|
+
setOnTouchListener { _, event ->
|
|
49
|
+
when (event.action) {
|
|
50
|
+
android.view.MotionEvent.ACTION_DOWN -> {
|
|
51
|
+
startX = event.x
|
|
52
|
+
startY = event.y
|
|
53
|
+
startTime = System.currentTimeMillis()
|
|
54
|
+
}
|
|
55
|
+
android.view.MotionEvent.ACTION_UP -> {
|
|
56
|
+
val duration = System.currentTimeMillis() - startTime
|
|
57
|
+
val dist = Math.sqrt(Math.pow((event.x - startX).toDouble(), 2.0) + Math.pow((event.y - startY).toDouble(), 2.0))
|
|
58
|
+
if (duration < 300 && dist < 20) {
|
|
59
|
+
notifyListeners("onEditorClick", JSObject())
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
false // Allow editor to handle the event too
|
|
64
|
+
}
|
|
65
|
+
subscribeEvent(io.github.rosemoe.sora.event.ContentChangeEvent::class.java) { event, _ ->
|
|
66
|
+
notifyListeners("onContentChange", JSObject())
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
val params = FrameLayout.LayoutParams(
|
|
71
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
72
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
73
|
+
)
|
|
74
|
+
activity.addContentView(editor, params)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
editor!!.isLineNumberEnabled = showLineNumbers
|
|
78
|
+
editor!!.isWordwrap = wordWrap
|
|
79
|
+
editor!!.setEditable(editable)
|
|
80
|
+
|
|
81
|
+
if (bgColorStr != null) {
|
|
82
|
+
try {
|
|
83
|
+
val color = Color.parseColor(bgColorStr)
|
|
84
|
+
val r = Color.red(color)
|
|
85
|
+
val g = Color.green(color)
|
|
86
|
+
val b = Color.blue(color)
|
|
87
|
+
val luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0
|
|
88
|
+
|
|
89
|
+
editor!!.colorScheme.setColor(EditorColorScheme.WHOLE_BACKGROUND, color)
|
|
90
|
+
editor!!.colorScheme.setColor(EditorColorScheme.LINE_NUMBER_BACKGROUND, color)
|
|
91
|
+
|
|
92
|
+
if (luminance < 0.5) {
|
|
93
|
+
editor!!.colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.WHITE)
|
|
94
|
+
editor!!.colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.GRAY)
|
|
95
|
+
} else {
|
|
96
|
+
editor!!.colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.BLACK)
|
|
97
|
+
editor!!.colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.DKGRAY)
|
|
98
|
+
}
|
|
99
|
+
} catch (e: Exception) {}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
val density = context.resources.displayMetrics.density
|
|
103
|
+
val params = editor!!.layoutParams as FrameLayout.LayoutParams
|
|
104
|
+
params.topMargin = (topMargin * density).toInt()
|
|
105
|
+
params.leftMargin = (leftMargin * density).toInt()
|
|
106
|
+
params.rightMargin = (rightMargin * density).toInt()
|
|
107
|
+
params.bottomMargin = (bottomMargin * density).toInt()
|
|
108
|
+
if (width >= 0) params.width = (width * density).toInt() else params.width = FrameLayout.LayoutParams.MATCH_PARENT
|
|
109
|
+
if (height >= 0) params.height = (height * density).toInt() else params.height = FrameLayout.LayoutParams.MATCH_PARENT
|
|
110
|
+
|
|
111
|
+
editor!!.layoutParams = params
|
|
112
|
+
|
|
113
|
+
if (call.hasOption("content")) {
|
|
114
|
+
val currentText = editor!!.text.toString()
|
|
115
|
+
if (currentText != content) {
|
|
116
|
+
editor!!.setText(content)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
editor!!.setTextSize(fontSize)
|
|
121
|
+
editor!!.visibility = View.VISIBLE
|
|
122
|
+
editor!!.bringToFront()
|
|
123
|
+
|
|
124
|
+
if (call.hasOption("selectionLine") || call.hasOption("selectionColumn")) {
|
|
125
|
+
val l = call.getInt("selectionLine") ?: 0
|
|
126
|
+
val c = call.getInt("selectionColumn") ?: 0
|
|
127
|
+
editor!!.postDelayed({
|
|
128
|
+
try {
|
|
129
|
+
editor!!.setSelection(l, c)
|
|
130
|
+
editor!!.ensureSelectionVisible()
|
|
131
|
+
} catch(e: Exception){
|
|
132
|
+
}
|
|
133
|
+
}, 150)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
call.resolve()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@PluginMethod
|
|
140
|
+
fun close(call: PluginCall) {
|
|
141
|
+
activity.runOnUiThread {
|
|
142
|
+
editor?.visibility = View.GONE
|
|
143
|
+
}
|
|
144
|
+
call.resolve()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@PluginMethod
|
|
148
|
+
fun getText(call: PluginCall) {
|
|
149
|
+
val ret = JSObject()
|
|
150
|
+
activity.runOnUiThread {
|
|
151
|
+
ret.put("content", editor?.text?.toString() ?: "")
|
|
152
|
+
call.resolve(ret)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
@PluginMethod
|
|
157
|
+
fun getSelection(call: PluginCall) {
|
|
158
|
+
val ret = JSObject()
|
|
159
|
+
activity.runOnUiThread {
|
|
160
|
+
if (editor != null) {
|
|
161
|
+
val cursor = editor!!.cursor
|
|
162
|
+
ret.put("line", cursor.leftLine)
|
|
163
|
+
ret.put("column", cursor.leftColumn)
|
|
164
|
+
}
|
|
165
|
+
call.resolve(ret)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@PluginMethod
|
|
170
|
+
fun setText(call: PluginCall) {
|
|
171
|
+
val content = call.getString("content") ?: ""
|
|
172
|
+
activity.runOnUiThread {
|
|
173
|
+
editor?.setText(content)
|
|
174
|
+
}
|
|
175
|
+
call.resolve()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@PluginMethod
|
|
179
|
+
fun setSelection(call: PluginCall) {
|
|
180
|
+
val line = call.getInt("line") ?: 0
|
|
181
|
+
val column = call.getInt("column") ?: 0
|
|
182
|
+
activity.runOnUiThread {
|
|
183
|
+
editor?.post {
|
|
184
|
+
try {
|
|
185
|
+
editor?.setSelection(line, column)
|
|
186
|
+
editor?.ensureSelectionVisible()
|
|
187
|
+
} catch (e: Exception) {
|
|
188
|
+
e.printStackTrace()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
call.resolve()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@PluginMethod
|
|
196
|
+
fun undo(call: PluginCall) {
|
|
197
|
+
activity.runOnUiThread {
|
|
198
|
+
editor?.undo()
|
|
199
|
+
}
|
|
200
|
+
call.resolve()
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
@PluginMethod
|
|
204
|
+
fun redo(call: PluginCall) {
|
|
205
|
+
activity.runOnUiThread {
|
|
206
|
+
editor?.redo()
|
|
207
|
+
}
|
|
208
|
+
call.resolve()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@PluginMethod
|
|
212
|
+
fun openEditor(call: PluginCall) {
|
|
213
|
+
val filePath = call.getString("filePath") ?: ""
|
|
214
|
+
val autoFocus = call.getBoolean("autoFocus") ?: false
|
|
215
|
+
if (filePath.isEmpty()) {
|
|
216
|
+
call.reject("File path is required")
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
activity.runOnUiThread {
|
|
220
|
+
val intent = android.content.Intent(context, com.abc15018045126.capacitor.soraeditor.compose.ComposeEditorActivity::class.java)
|
|
221
|
+
intent.putExtra("FILE_PATH", filePath)
|
|
222
|
+
intent.putExtra("AUTO_FOCUS", autoFocus)
|
|
223
|
+
activity.startActivity(intent)
|
|
224
|
+
call.resolve()
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.abc15018045126.capacitor.soraeditor.compose
|
|
2
2
|
|
|
3
3
|
import android.os.Bundle
|
|
4
4
|
import androidx.activity.ComponentActivity
|
|
@@ -9,10 +9,10 @@ import androidx.compose.material3.*
|
|
|
9
9
|
import androidx.compose.runtime.*
|
|
10
10
|
import androidx.compose.ui.Modifier
|
|
11
11
|
import androidx.compose.ui.platform.LocalContext
|
|
12
|
-
import com.
|
|
13
|
-
import com.
|
|
12
|
+
import com.abc15018045126.capacitor.soraeditor.compose.ui.EditorScreen
|
|
13
|
+
import com.abc15018045126.capacitor.soraeditor.compose.ui.theme.NotesTheme
|
|
14
14
|
|
|
15
|
-
class
|
|
15
|
+
class ComposeEditorActivity : ComponentActivity() {
|
|
16
16
|
private val viewModel: EditorViewModel by viewModels()
|
|
17
17
|
|
|
18
18
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
@@ -20,12 +20,13 @@ class EditorActivity : ComponentActivity() {
|
|
|
20
20
|
|
|
21
21
|
// Get file path from intent
|
|
22
22
|
val filePath = intent.getStringExtra("FILE_PATH") ?: ""
|
|
23
|
-
|
|
23
|
+
val autoFocus = intent.getBooleanExtra("AUTO_FOCUS", false)
|
|
24
|
+
android.util.Log.d("ComposeEditorActivity", "onCreate with filePath: $filePath, autoFocus: $autoFocus")
|
|
24
25
|
|
|
25
26
|
if (filePath.isNotEmpty()) {
|
|
26
|
-
viewModel.loadFile(this, filePath)
|
|
27
|
+
viewModel.loadFile(this, filePath, autoFocus)
|
|
27
28
|
} else {
|
|
28
|
-
android.util.Log.e("
|
|
29
|
+
android.util.Log.e("ComposeEditorActivity", "No file path provided")
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
setContent {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.abc15018045126.capacitor.soraeditor.compose
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import androidx.lifecycle.ViewModel
|
|
@@ -44,13 +44,16 @@ data class EditorUiState(
|
|
|
44
44
|
val uiColor: String = "#F5F5F5",
|
|
45
45
|
val tocColor: String = "#FFFFFF",
|
|
46
46
|
val searchColor: String = "#F5F5F5",
|
|
47
|
-
val menuColor: String = "#FFFFFF"
|
|
47
|
+
val menuColor: String = "#FFFFFF",
|
|
48
|
+
val shouldAutoFocus: Boolean = false
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
class EditorViewModel : ViewModel() {
|
|
51
52
|
private val _uiState = MutableStateFlow(EditorUiState())
|
|
52
53
|
val uiState: StateFlow<EditorUiState> = _uiState.asStateFlow()
|
|
53
54
|
|
|
55
|
+
// ... existing loadFile method ...
|
|
56
|
+
|
|
54
57
|
fun setCursorPosition(pos: Int, line: Int, col: Int) {
|
|
55
58
|
_uiState.update { it.copy(
|
|
56
59
|
currentCursorPos = pos,
|
|
@@ -59,7 +62,7 @@ class EditorViewModel : ViewModel() {
|
|
|
59
62
|
) }
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
fun loadFile(context: Context, filePath: String) {
|
|
65
|
+
fun loadFile(context: Context, filePath: String, autoFocus: Boolean = false) {
|
|
63
66
|
viewModelScope.launch {
|
|
64
67
|
try {
|
|
65
68
|
// Convert URI to actual path if needed
|
|
@@ -83,7 +86,8 @@ class EditorViewModel : ViewModel() {
|
|
|
83
86
|
filePath = actualPath,
|
|
84
87
|
fileName = file.name,
|
|
85
88
|
originalContent = content,
|
|
86
|
-
isModified = false
|
|
89
|
+
isModified = false,
|
|
90
|
+
shouldAutoFocus = autoFocus
|
|
87
91
|
)
|
|
88
92
|
} else {
|
|
89
93
|
android.util.Log.e("EditorViewModel", "File does not exist: $actualPath")
|
|
@@ -140,6 +144,13 @@ class EditorViewModel : ViewModel() {
|
|
|
140
144
|
val contentToSave = _uiState.value.content
|
|
141
145
|
val path = _uiState.value.filePath
|
|
142
146
|
|
|
147
|
+
// Should ideally be IO, but for now we keep it simple or use runBlocking for exit safety?
|
|
148
|
+
// Better to just write. File writeText is blocking but OK for background thread.
|
|
149
|
+
// But we are in ViewModel, often main thread call.
|
|
150
|
+
// Let's protect against main thread blocking for large files?
|
|
151
|
+
// But for saveOnExit (onPause) we need synchronous or strictly ordered.
|
|
152
|
+
// For auto-save we are effectively inside a coroutine (from queueAutoSave).
|
|
153
|
+
|
|
143
154
|
android.util.Log.d("EditorViewModel", "Saving file to: $path, content length: ${contentToSave.length}")
|
|
144
155
|
|
|
145
156
|
val file = File(path)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.
|
|
1
|
+
package com.abc15018045126.capacitor.soraeditor.compose.ui
|
|
2
2
|
|
|
3
3
|
import android.graphics.Typeface
|
|
4
4
|
import android.view.View
|
|
@@ -27,8 +27,8 @@ import androidx.compose.ui.input.pointer.pointerInput
|
|
|
27
27
|
import androidx.compose.foundation.gestures.detectDragGestures
|
|
28
28
|
import androidx.compose.foundation.border
|
|
29
29
|
import kotlinx.coroutines.launch
|
|
30
|
-
import com.
|
|
31
|
-
import com.
|
|
30
|
+
import com.abc15018045126.capacitor.soraeditor.compose.EditorUiState
|
|
31
|
+
import com.abc15018045126.capacitor.soraeditor.compose.EditorViewModel
|
|
32
32
|
import io.github.rosemoe.sora.widget.CodeEditor
|
|
33
33
|
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
|
34
34
|
|
|
@@ -182,7 +182,8 @@ fun SoraEditorView(
|
|
|
182
182
|
control: EditorControl? = null,
|
|
183
183
|
onSearchMatchesChange: (Int, Int) -> Unit = { _, _ -> },
|
|
184
184
|
onScroll: () -> Unit = {},
|
|
185
|
-
onTap: () -> Unit = {}
|
|
185
|
+
onTap: () -> Unit = {},
|
|
186
|
+
autoFocus: Boolean = false
|
|
186
187
|
) {
|
|
187
188
|
var editorInstance by remember { mutableStateOf<CodeEditor?>(null) }
|
|
188
189
|
|
|
@@ -280,6 +281,16 @@ fun SoraEditorView(
|
|
|
280
281
|
|
|
281
282
|
editorInstance = this
|
|
282
283
|
control?.attach(this)
|
|
284
|
+
|
|
285
|
+
// Auto-focus if requested (for new notes)
|
|
286
|
+
if (autoFocus) {
|
|
287
|
+
postDelayed({
|
|
288
|
+
requestFocus()
|
|
289
|
+
// Show keyboard with SHOW_FORCED to ensure it appears
|
|
290
|
+
val imm = context.getSystemService(android.content.Context.INPUT_METHOD_SERVICE) as? android.view.inputmethod.InputMethodManager
|
|
291
|
+
imm?.showSoftInput(this, android.view.inputmethod.InputMethodManager.SHOW_FORCED)
|
|
292
|
+
}, 200) // Delay to ensure view is fully laid out
|
|
293
|
+
}
|
|
283
294
|
}
|
|
284
295
|
},
|
|
285
296
|
update = { view ->
|
|
@@ -483,7 +494,8 @@ fun EditorScreen(
|
|
|
483
494
|
control = editorControl,
|
|
484
495
|
onSearchMatchesChange = { current, total -> viewModel.setMatchResults(current, total) },
|
|
485
496
|
onScroll = { if (uiState.isReadOnly && uiState.showToolbar) viewModel.setShowToolbar(false) },
|
|
486
|
-
onTap = { if (uiState.isReadOnly) viewModel.toggleToolbar() }
|
|
497
|
+
onTap = { if (uiState.isReadOnly) viewModel.toggleToolbar() },
|
|
498
|
+
autoFocus = uiState.shouldAutoFocus
|
|
487
499
|
)
|
|
488
500
|
}
|
|
489
501
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package com.abc15018045126.capacitor.soraeditor.compose.ui
|
|
2
|
+
|
|
3
|
+
import android.graphics.Color
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
import androidx.compose.foundation.layout.*
|
|
6
|
+
import androidx.compose.runtime.*
|
|
7
|
+
import androidx.compose.ui.Modifier
|
|
8
|
+
import androidx.compose.ui.viewinterop.AndroidView
|
|
9
|
+
import io.github.rosemoe.sora.widget.CodeEditor
|
|
10
|
+
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
|
11
|
+
|
|
12
|
+
@Composable
|
|
13
|
+
fun SoraEditorView(
|
|
14
|
+
content: String,
|
|
15
|
+
onContentChange: (String) -> Unit,
|
|
16
|
+
fontSize: Float = 18f,
|
|
17
|
+
showLineNumbers: Boolean = true,
|
|
18
|
+
wordWrap: Boolean = false,
|
|
19
|
+
editable: Boolean = true,
|
|
20
|
+
backgroundColor: String = "#FFFFFF",
|
|
21
|
+
modifier: Modifier = Modifier,
|
|
22
|
+
onUndo: () -> Unit = {},
|
|
23
|
+
onRedo: () -> Unit = {}
|
|
24
|
+
) {
|
|
25
|
+
var editorInstance by remember { mutableStateOf<CodeEditor?>(null) }
|
|
26
|
+
|
|
27
|
+
// Expose undo/redo functions
|
|
28
|
+
LaunchedEffect(editorInstance) {
|
|
29
|
+
editorInstance?.let { editor ->
|
|
30
|
+
// Store reference for external calls
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
AndroidView(
|
|
35
|
+
factory = { context ->
|
|
36
|
+
CodeEditor(context).apply {
|
|
37
|
+
setTextSize(fontSize)
|
|
38
|
+
setTypefaceText(Typeface.MONOSPACE)
|
|
39
|
+
isLineNumberEnabled = showLineNumbers
|
|
40
|
+
isWordwrap = wordWrap
|
|
41
|
+
setEditable(editable)
|
|
42
|
+
setText(content)
|
|
43
|
+
|
|
44
|
+
// Set background color
|
|
45
|
+
try {
|
|
46
|
+
val color = Color.parseColor(backgroundColor)
|
|
47
|
+
val r = Color.red(color)
|
|
48
|
+
val g = Color.green(color)
|
|
49
|
+
val b = Color.blue(color)
|
|
50
|
+
val luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0
|
|
51
|
+
|
|
52
|
+
colorScheme.setColor(EditorColorScheme.WHOLE_BACKGROUND, color)
|
|
53
|
+
colorScheme.setColor(EditorColorScheme.LINE_NUMBER_BACKGROUND, color)
|
|
54
|
+
|
|
55
|
+
if (luminance < 0.5) {
|
|
56
|
+
colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.WHITE)
|
|
57
|
+
colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.GRAY)
|
|
58
|
+
} else {
|
|
59
|
+
colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.BLACK)
|
|
60
|
+
colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.DKGRAY)
|
|
61
|
+
}
|
|
62
|
+
} catch (e: Exception) {
|
|
63
|
+
e.printStackTrace()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
editorInstance = this
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
update = { view ->
|
|
70
|
+
view.setTextSize(fontSize)
|
|
71
|
+
view.isLineNumberEnabled = showLineNumbers
|
|
72
|
+
view.isWordwrap = wordWrap
|
|
73
|
+
view.setEditable(editable)
|
|
74
|
+
|
|
75
|
+
// Only update text if it's different to avoid cursor jump
|
|
76
|
+
if (view.text.toString() != content) {
|
|
77
|
+
view.setText(content)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Update background color
|
|
81
|
+
try {
|
|
82
|
+
val color = Color.parseColor(backgroundColor)
|
|
83
|
+
val r = Color.red(color)
|
|
84
|
+
val g = Color.green(color)
|
|
85
|
+
val b = Color.blue(color)
|
|
86
|
+
val luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255.0
|
|
87
|
+
|
|
88
|
+
view.colorScheme.setColor(EditorColorScheme.WHOLE_BACKGROUND, color)
|
|
89
|
+
view.colorScheme.setColor(EditorColorScheme.LINE_NUMBER_BACKGROUND, color)
|
|
90
|
+
|
|
91
|
+
if (luminance < 0.5) {
|
|
92
|
+
view.colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.WHITE)
|
|
93
|
+
view.colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.GRAY)
|
|
94
|
+
} else {
|
|
95
|
+
view.colorScheme.setColor(EditorColorScheme.TEXT_NORMAL, Color.BLACK)
|
|
96
|
+
view.colorScheme.setColor(EditorColorScheme.LINE_NUMBER, Color.DKGRAY)
|
|
97
|
+
}
|
|
98
|
+
} catch (e: Exception) {
|
|
99
|
+
e.printStackTrace()
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
modifier = modifier.fillMaxSize()
|
|
103
|
+
)
|
|
104
|
+
}
|
|
Binary file
|
|
@@ -1,5 +1,44 @@
|
|
|
1
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
1
2
|
export interface SoraEditorPlugin {
|
|
3
|
+
start(options: SoraStartOptions): Promise<void>;
|
|
4
|
+
close(): Promise<void>;
|
|
5
|
+
getText(): Promise<{
|
|
6
|
+
content: string;
|
|
7
|
+
}>;
|
|
8
|
+
setText(options: {
|
|
9
|
+
content: string;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
getSelection(): Promise<{
|
|
12
|
+
line: number;
|
|
13
|
+
column: number;
|
|
14
|
+
}>;
|
|
15
|
+
setSelection(options: {
|
|
16
|
+
line: number;
|
|
17
|
+
column: number;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
undo(): Promise<void>;
|
|
20
|
+
redo(): Promise<void>;
|
|
2
21
|
openEditor(options: {
|
|
3
22
|
filePath: string;
|
|
23
|
+
autoFocus?: boolean;
|
|
4
24
|
}): Promise<void>;
|
|
25
|
+
addListener(eventName: 'onEditorClick', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
|
26
|
+
addListener(eventName: 'onContentChange', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
|
27
|
+
}
|
|
28
|
+
export interface SoraStartOptions {
|
|
29
|
+
content?: string;
|
|
30
|
+
top?: number;
|
|
31
|
+
left?: number;
|
|
32
|
+
right?: number;
|
|
33
|
+
bottom?: number;
|
|
34
|
+
width?: number;
|
|
35
|
+
height?: number;
|
|
36
|
+
fontSize?: number;
|
|
37
|
+
showLineNumbers?: boolean;
|
|
38
|
+
wordWrap?: boolean;
|
|
39
|
+
editable?: boolean;
|
|
40
|
+
backgroundColor?: string;
|
|
41
|
+
selectionLine?: number;
|
|
42
|
+
selectionColumn?: number;
|
|
5
43
|
}
|
|
44
|
+
//# sourceMappingURL=definitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxC,OAAO,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,YAAY,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,YAAY,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,UAAU,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,WAAW,CAAC,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjG,WAAW,CAAC,SAAS,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACtG;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,QAAA,MAAM,UAAU,kBAEd,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,MAAM,UAAU,GAAG,cAAc,CAAmB,YAAY,EAAE;IAC9D,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;CAC9D,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
|
-
import type { SoraEditorPlugin } from './definitions';
|
|
2
|
+
import type { SoraEditorPlugin, SoraStartOptions } from './definitions';
|
|
3
3
|
export declare class SoraEditorWeb extends WebPlugin implements SoraEditorPlugin {
|
|
4
|
+
start(options: SoraStartOptions): Promise<void>;
|
|
5
|
+
close(): Promise<void>;
|
|
6
|
+
getText(): Promise<{
|
|
7
|
+
content: string;
|
|
8
|
+
}>;
|
|
9
|
+
setText(options: {
|
|
10
|
+
content: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
getSelection(): Promise<{
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
}>;
|
|
16
|
+
setSelection(options: {
|
|
17
|
+
line: number;
|
|
18
|
+
column: number;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
undo(): Promise<void>;
|
|
21
|
+
redo(): Promise<void>;
|
|
4
22
|
openEditor(options: {
|
|
5
23
|
filePath: string;
|
|
24
|
+
autoFocus?: boolean;
|
|
6
25
|
}): Promise<void>;
|
|
7
26
|
}
|
|
27
|
+
//# sourceMappingURL=web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExE,qBAAa,aAAc,SAAQ,SAAU,YAAW,gBAAgB;IAC9D,KAAK,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAG/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAGtB,OAAO,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAGvC,OAAO,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAGpD,YAAY,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAGzD,YAAY,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAGtE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAGrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAGrB,UAAU,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAGtF"}
|
package/dist/esm/web.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
2
|
export class SoraEditorWeb extends WebPlugin {
|
|
3
|
+
async start(options) {
|
|
4
|
+
console.log('SoraEditor start', options);
|
|
5
|
+
}
|
|
6
|
+
async close() {
|
|
7
|
+
console.log('SoraEditor close');
|
|
8
|
+
}
|
|
9
|
+
async getText() {
|
|
10
|
+
return { content: '' };
|
|
11
|
+
}
|
|
12
|
+
async setText(options) {
|
|
13
|
+
console.log('SoraEditor setText', options);
|
|
14
|
+
}
|
|
15
|
+
async getSelection() {
|
|
16
|
+
return { line: 0, column: 0 };
|
|
17
|
+
}
|
|
18
|
+
async setSelection(options) {
|
|
19
|
+
console.log('SoraEditor setSelection', options);
|
|
20
|
+
}
|
|
21
|
+
async undo() {
|
|
22
|
+
console.log('SoraEditor undo');
|
|
23
|
+
}
|
|
24
|
+
async redo() {
|
|
25
|
+
console.log('SoraEditor redo');
|
|
26
|
+
}
|
|
3
27
|
async openEditor(options) {
|
|
4
|
-
console.log('openEditor', options);
|
|
5
|
-
console.warn('SoraEditor is implemented for Android only');
|
|
28
|
+
console.log('SoraEditor openEditor', options);
|
|
6
29
|
}
|
|
7
30
|
}
|
|
8
31
|
//# sourceMappingURL=web.js.map
|
package/dist/esm/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IACxC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,aAAc,SAAQ,SAAS;IACxC,KAAK,CAAC,KAAK,CAAC,OAAyB;QACjC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,KAAK;QACP,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IACpC,CAAC;IACD,KAAK,CAAC,OAAO;QACT,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,OAA4B;QACtC,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,CAAC,YAAY;QACd,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAClC,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,OAAyC;QACxD,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,KAAK,CAAC,IAAI;QACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,IAAI;QACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,UAAU,CAAC,OAAkD;QAC/D,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;CACJ"}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -7,9 +7,32 @@ const SoraEditor = core.registerPlugin('SoraEditor', {
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
class SoraEditorWeb extends core.WebPlugin {
|
|
10
|
+
async start(options) {
|
|
11
|
+
console.log('SoraEditor start', options);
|
|
12
|
+
}
|
|
13
|
+
async close() {
|
|
14
|
+
console.log('SoraEditor close');
|
|
15
|
+
}
|
|
16
|
+
async getText() {
|
|
17
|
+
return { content: '' };
|
|
18
|
+
}
|
|
19
|
+
async setText(options) {
|
|
20
|
+
console.log('SoraEditor setText', options);
|
|
21
|
+
}
|
|
22
|
+
async getSelection() {
|
|
23
|
+
return { line: 0, column: 0 };
|
|
24
|
+
}
|
|
25
|
+
async setSelection(options) {
|
|
26
|
+
console.log('SoraEditor setSelection', options);
|
|
27
|
+
}
|
|
28
|
+
async undo() {
|
|
29
|
+
console.log('SoraEditor undo');
|
|
30
|
+
}
|
|
31
|
+
async redo() {
|
|
32
|
+
console.log('SoraEditor redo');
|
|
33
|
+
}
|
|
10
34
|
async openEditor(options) {
|
|
11
|
-
console.log('openEditor', options);
|
|
12
|
-
console.warn('SoraEditor is implemented for Android only');
|
|
35
|
+
console.log('SoraEditor openEditor', options);
|
|
13
36
|
}
|
|
14
37
|
}
|
|
15
38
|
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SoraEditor = registerPlugin('SoraEditor', {\n web: () => import('./web').then(m => new m.SoraEditorWeb()),\n});\nexport * from './definitions';\nexport { SoraEditor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SoraEditorWeb extends WebPlugin {\n async
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SoraEditor = registerPlugin('SoraEditor', {\n web: () => import('./web').then(m => new m.SoraEditorWeb()),\n});\nexport * from './definitions';\nexport { SoraEditor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SoraEditorWeb extends WebPlugin {\n async start(options) {\n console.log('SoraEditor start', options);\n }\n async close() {\n console.log('SoraEditor close');\n }\n async getText() {\n return { content: '' };\n }\n async setText(options) {\n console.log('SoraEditor setText', options);\n }\n async getSelection() {\n return { line: 0, column: 0 };\n }\n async setSelection(options) {\n console.log('SoraEditor setSelection', options);\n }\n async undo() {\n console.log('SoraEditor undo');\n }\n async redo() {\n console.log('SoraEditor redo');\n }\n async openEditor(options) {\n console.log('SoraEditor openEditor', options);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;AAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AAC/D,CAAC;;ACFM,MAAM,aAAa,SAASC,cAAS,CAAC;AAC7C,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;AACzB,QAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC;AAChD,IAAI;AACJ,IAAI,MAAM,KAAK,GAAG;AAClB,QAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AACvC,IAAI;AACJ,IAAI,MAAM,OAAO,GAAG;AACpB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;AAC9B,IAAI;AACJ,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE;AAC3B,QAAQ,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC;AAClD,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;AACrC,IAAI;AACJ,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;AAChC,QAAQ,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,OAAO,CAAC;AACvD,IAAI;AACJ,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACtC,IAAI;AACJ,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACtC,IAAI;AACJ,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;AAC9B,QAAQ,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,OAAO,CAAC;AACrD,IAAI;AACJ;;;;;;;;;"}
|
package/dist/plugin.js
CHANGED
|
@@ -6,9 +6,32 @@ var capacitorSoraEditor = (function (exports, core) {
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
class SoraEditorWeb extends core.WebPlugin {
|
|
9
|
+
async start(options) {
|
|
10
|
+
console.log('SoraEditor start', options);
|
|
11
|
+
}
|
|
12
|
+
async close() {
|
|
13
|
+
console.log('SoraEditor close');
|
|
14
|
+
}
|
|
15
|
+
async getText() {
|
|
16
|
+
return { content: '' };
|
|
17
|
+
}
|
|
18
|
+
async setText(options) {
|
|
19
|
+
console.log('SoraEditor setText', options);
|
|
20
|
+
}
|
|
21
|
+
async getSelection() {
|
|
22
|
+
return { line: 0, column: 0 };
|
|
23
|
+
}
|
|
24
|
+
async setSelection(options) {
|
|
25
|
+
console.log('SoraEditor setSelection', options);
|
|
26
|
+
}
|
|
27
|
+
async undo() {
|
|
28
|
+
console.log('SoraEditor undo');
|
|
29
|
+
}
|
|
30
|
+
async redo() {
|
|
31
|
+
console.log('SoraEditor redo');
|
|
32
|
+
}
|
|
9
33
|
async openEditor(options) {
|
|
10
|
-
console.log('openEditor', options);
|
|
11
|
-
console.warn('SoraEditor is implemented for Android only');
|
|
34
|
+
console.log('SoraEditor openEditor', options);
|
|
12
35
|
}
|
|
13
36
|
}
|
|
14
37
|
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SoraEditor = registerPlugin('SoraEditor', {\n web: () => import('./web').then(m => new m.SoraEditorWeb()),\n});\nexport * from './definitions';\nexport { SoraEditor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SoraEditorWeb extends WebPlugin {\n async
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SoraEditor = registerPlugin('SoraEditor', {\n web: () => import('./web').then(m => new m.SoraEditorWeb()),\n});\nexport * from './definitions';\nexport { SoraEditor };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SoraEditorWeb extends WebPlugin {\n async start(options) {\n console.log('SoraEditor start', options);\n }\n async close() {\n console.log('SoraEditor close');\n }\n async getText() {\n return { content: '' };\n }\n async setText(options) {\n console.log('SoraEditor setText', options);\n }\n async getSelection() {\n return { line: 0, column: 0 };\n }\n async setSelection(options) {\n console.log('SoraEditor setSelection', options);\n }\n async undo() {\n console.log('SoraEditor undo');\n }\n async redo() {\n console.log('SoraEditor redo');\n }\n async openEditor(options) {\n console.log('SoraEditor openEditor', options);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,UAAU,GAAGA,mBAAc,CAAC,YAAY,EAAE;IAChD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;IAC/D,CAAC;;ICFM,MAAM,aAAa,SAASC,cAAS,CAAC;IAC7C,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE;IACzB,QAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC;IAChD,IAAI;IACJ,IAAI,MAAM,KAAK,GAAG;IAClB,QAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvC,IAAI;IACJ,IAAI,MAAM,OAAO,GAAG;IACpB,QAAQ,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;IAC9B,IAAI;IACJ,IAAI,MAAM,OAAO,CAAC,OAAO,EAAE;IAC3B,QAAQ,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,OAAO,CAAC;IAClD,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;IACrC,IAAI;IACJ,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;IAChC,QAAQ,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,OAAO,CAAC;IACvD,IAAI;IACJ,IAAI,MAAM,IAAI,GAAG;IACjB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtC,IAAI;IACJ,IAAI,MAAM,IAAI,GAAG;IACjB,QAAQ,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACtC,IAAI;IACJ,IAAI,MAAM,UAAU,CAAC,OAAO,EAAE;IAC9B,QAAQ,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,OAAO,CAAC;IACrD,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,76 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-sora-editor",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "dist/plugin.
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SoraEditor plugin for Capacitor",
|
|
5
|
+
"main": "dist/plugin.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/esm/index.d.ts",
|
|
8
|
-
"unpkg": "dist/plugin.js",
|
|
9
|
-
"files": [
|
|
10
|
-
"dist/",
|
|
11
|
-
"ios/",
|
|
12
|
-
"android/",
|
|
13
|
-
"CapacitorSoraEditor.podspec"
|
|
14
|
-
],
|
|
15
|
-
"author": "",
|
|
16
|
-
"license": "MIT",
|
|
17
|
-
"repository": {
|
|
18
|
-
"type": "git",
|
|
19
|
-
"url": "git+https://github.com/abc15018045126/notes.git"
|
|
20
|
-
},
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/abc15018045126/notes/issues"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"capacitor",
|
|
26
|
-
"plugin",
|
|
27
|
-
"native"
|
|
28
|
-
],
|
|
29
8
|
"scripts": {
|
|
30
|
-
"
|
|
31
|
-
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
|
|
32
|
-
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
33
|
-
"verify:web": "npm run build",
|
|
34
|
-
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
35
|
-
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
36
|
-
"eslint": "eslint . --ext ts",
|
|
37
|
-
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
38
|
-
"swiftlint": "node-swiftlint",
|
|
39
|
-
"docgen": "docgen --api SoraEditorPlugin --output-readme README.md --output-json dist/docs.json",
|
|
40
|
-
"build": "npm run clean && tsc && rollup -c rollup.config.mjs",
|
|
41
|
-
"clean": "rimraf dist",
|
|
42
|
-
"prepublishOnly": "npm run build"
|
|
9
|
+
"build": "tsc && rollup -c rollup.config.mjs"
|
|
43
10
|
},
|
|
11
|
+
"author": "abc15018045126",
|
|
12
|
+
"license": "MIT",
|
|
44
13
|
"devDependencies": {
|
|
45
|
-
"@capacitor/android": "^
|
|
46
|
-
"@capacitor/core": "^
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"@ionic/eslint-config": "^0.3.0",
|
|
50
|
-
"@ionic/prettier-config": "^2.0.0",
|
|
51
|
-
"@ionic/swiftlint-config": "^1.1.2",
|
|
52
|
-
"eslint": "^7.11.0",
|
|
53
|
-
"prettier": "^2.4.0",
|
|
54
|
-
"prettier-plugin-java": "~1.0.2",
|
|
55
|
-
"rimraf": "^3.0.2",
|
|
56
|
-
"rollup": "^2.32.0",
|
|
57
|
-
"swiftlint": "^1.0.1",
|
|
58
|
-
"typescript": "^5.9.3"
|
|
14
|
+
"@capacitor/android": "^8.0.0",
|
|
15
|
+
"@capacitor/core": "^8.0.0",
|
|
16
|
+
"rollup": "^4.0.0",
|
|
17
|
+
"typescript": "^5.0.0"
|
|
59
18
|
},
|
|
60
19
|
"peerDependencies": {
|
|
61
|
-
"@capacitor/core": "
|
|
62
|
-
},
|
|
63
|
-
"prettier": "@ionic/prettier-config",
|
|
64
|
-
"swiftlint": "@ionic/swiftlint-config",
|
|
65
|
-
"eslintConfig": {
|
|
66
|
-
"extends": "@ionic/eslint-config/recommended"
|
|
20
|
+
"@capacitor/core": "^8.0.0"
|
|
67
21
|
},
|
|
68
22
|
"capacitor": {
|
|
69
23
|
"android": {
|
|
70
24
|
"src": "android"
|
|
71
|
-
},
|
|
72
|
-
"ios": {
|
|
73
|
-
"src": "ios"
|
|
74
25
|
}
|
|
75
26
|
}
|
|
76
27
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
input: 'dist/esm/index.js',
|
|
3
|
+
output: [
|
|
4
|
+
{
|
|
5
|
+
file: 'dist/plugin.js',
|
|
6
|
+
format: 'iife',
|
|
7
|
+
name: 'capacitorSoraEditor',
|
|
8
|
+
globals: {
|
|
9
|
+
'@capacitor/core': 'capacitorExports',
|
|
10
|
+
},
|
|
11
|
+
sourcemap: true,
|
|
12
|
+
inlineDynamicImports: true,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
file: 'dist/plugin.cjs.js',
|
|
16
|
+
format: 'cjs',
|
|
17
|
+
sourcemap: true,
|
|
18
|
+
inlineDynamicImports: true,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
external: ['@capacitor/core'],
|
|
22
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
2
|
+
|
|
3
|
+
export interface SoraEditorPlugin {
|
|
4
|
+
start(options: SoraStartOptions): Promise<void>;
|
|
5
|
+
close(): Promise<void>;
|
|
6
|
+
getText(): Promise<{ content: string }>;
|
|
7
|
+
setText(options: { content: string }): Promise<void>;
|
|
8
|
+
getSelection(): Promise<{ line: number; column: number }>;
|
|
9
|
+
setSelection(options: { line: number; column: number }): Promise<void>;
|
|
10
|
+
undo(): Promise<void>;
|
|
11
|
+
redo(): Promise<void>;
|
|
12
|
+
openEditor(options: { filePath: string; autoFocus?: boolean }): Promise<void>;
|
|
13
|
+
addListener(eventName: 'onEditorClick', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
|
14
|
+
addListener(eventName: 'onContentChange', listenerFunc: () => void): Promise<PluginListenerHandle>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface SoraStartOptions {
|
|
18
|
+
content?: string;
|
|
19
|
+
top?: number;
|
|
20
|
+
left?: number;
|
|
21
|
+
right?: number;
|
|
22
|
+
bottom?: number;
|
|
23
|
+
width?: number;
|
|
24
|
+
height?: number;
|
|
25
|
+
fontSize?: number;
|
|
26
|
+
showLineNumbers?: boolean;
|
|
27
|
+
wordWrap?: boolean;
|
|
28
|
+
editable?: boolean;
|
|
29
|
+
backgroundColor?: string;
|
|
30
|
+
selectionLine?: number;
|
|
31
|
+
selectionColumn?: number;
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
import type { SoraEditorPlugin } from './definitions';
|
|
3
|
+
|
|
4
|
+
const SoraEditor = registerPlugin<SoraEditorPlugin>('SoraEditor', {
|
|
5
|
+
web: () => import('./web').then(m => new m.SoraEditorWeb()),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export * from './definitions';
|
|
9
|
+
export { SoraEditor };
|
package/src/web.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { SoraEditorPlugin, SoraStartOptions } from './definitions';
|
|
3
|
+
|
|
4
|
+
export class SoraEditorWeb extends WebPlugin implements SoraEditorPlugin {
|
|
5
|
+
async start(options: SoraStartOptions): Promise<void> {
|
|
6
|
+
console.log('SoraEditor start', options);
|
|
7
|
+
}
|
|
8
|
+
async close(): Promise<void> {
|
|
9
|
+
console.log('SoraEditor close');
|
|
10
|
+
}
|
|
11
|
+
async getText(): Promise<{ content: string }> {
|
|
12
|
+
return { content: '' };
|
|
13
|
+
}
|
|
14
|
+
async setText(options: { content: string }): Promise<void> {
|
|
15
|
+
console.log('SoraEditor setText', options);
|
|
16
|
+
}
|
|
17
|
+
async getSelection(): Promise<{ line: number; column: number }> {
|
|
18
|
+
return { line: 0, column: 0 };
|
|
19
|
+
}
|
|
20
|
+
async setSelection(options: { line: number; column: number }): Promise<void> {
|
|
21
|
+
console.log('SoraEditor setSelection', options);
|
|
22
|
+
}
|
|
23
|
+
async undo(): Promise<void> {
|
|
24
|
+
console.log('SoraEditor undo');
|
|
25
|
+
}
|
|
26
|
+
async redo(): Promise<void> {
|
|
27
|
+
console.log('SoraEditor redo');
|
|
28
|
+
}
|
|
29
|
+
async openEditor(options: { filePath: string; autoFocus?: boolean }): Promise<void> {
|
|
30
|
+
console.log('SoraEditor openEditor', options);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": [
|
|
6
|
+
"ES2020",
|
|
7
|
+
"DOM"
|
|
8
|
+
],
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"outDir": "./dist/esm",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
"strict": true
|
|
18
|
+
},
|
|
19
|
+
"include": [
|
|
20
|
+
"src/**/*"
|
|
21
|
+
],
|
|
22
|
+
"exclude": [
|
|
23
|
+
"node_modules",
|
|
24
|
+
"dist"
|
|
25
|
+
]
|
|
26
|
+
}
|
package/README.md
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# Capacitor Sora Editor Plugin
|
|
2
|
-
|
|
3
|
-
A powerful, high-performance code editor for Capacitor Android applications, built with [Sora Editor](https://github.com/Rosemoe/sora-editor) and **Jetpack Compose**.
|
|
4
|
-
|
|
5
|
-
This plugin provides a full-featured native code editor experience within your hybrid app, significantly outperforming web-based editors (like Monaco or CodeMirror in a WebView) on mobile devices, especially for large files.
|
|
6
|
-
|
|
7
|
-
## 🚀 Features
|
|
8
|
-
|
|
9
|
-
* **High Performance**: Native rendering ensures smooth typing and scrolling, even for large files (thousands of lines).
|
|
10
|
-
* **Jetpack Compose UI**: Modern, clean, and customizable Material Design 3 interface.
|
|
11
|
-
* **Rich Editing Tools**:
|
|
12
|
-
* Undo / Redo
|
|
13
|
-
* Search & Replace (with Regex support)
|
|
14
|
-
* Go to Line
|
|
15
|
-
* Real-time Line & Column counters
|
|
16
|
-
* **Productivity Features**:
|
|
17
|
-
* **Table of Contents (TOC)**: Automatically generates a TOC based on content (chapters or line chunks).
|
|
18
|
-
* **Symbol Bar**: Quick access to common programming symbols above the keyboard.
|
|
19
|
-
* **Read-Only Mode**: Toggle between browsing and editing.
|
|
20
|
-
* **Auto-Save**: Securely saves changes to the local filesystem.
|
|
21
|
-
* **Smart Renaming**: Automatically detects "new" files and proposes a rename based on the first line of text upon exit.
|
|
22
|
-
* **Customization**:
|
|
23
|
-
* Toggle Line Numbers
|
|
24
|
-
* Toggle Word Wrap
|
|
25
|
-
* Adjust Font Size
|
|
26
|
-
* System Dark/Light Theme support
|
|
27
|
-
* Customizable colors for background, UI, etc.
|
|
28
|
-
|
|
29
|
-
## 🛠 Tech Stack & Requirements
|
|
30
|
-
|
|
31
|
-
* **Capacitor**: ^6.0.0
|
|
32
|
-
* **Android**:
|
|
33
|
-
* `minSdkVersion`: 22+
|
|
34
|
-
* `compileSdkVersion`: 34+
|
|
35
|
-
* Kotlin: 1.9.0+
|
|
36
|
-
* Jetpack Compose enabled
|
|
37
|
-
* **Sora Editor**: 0.24.4
|
|
38
|
-
|
|
39
|
-
## 📦 Installation
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
npm install capacitor-sora-editor
|
|
43
|
-
npx cap sync
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## 🔧 Android Configuration
|
|
47
|
-
|
|
48
|
-
Since this plugin allows file editing, you generally deal with local files. Ensure your app asks for necessary storage permissions if accessing files outside your app's sandbox.
|
|
49
|
-
|
|
50
|
-
No special initialization is required in `MainActivity.java` for Capacitor 3+ as plugins are auto-detected.
|
|
51
|
-
|
|
52
|
-
However, ensure your `variables.gradle` or project `build.gradle` meets the minimum Kotlin and SDK versions.
|
|
53
|
-
|
|
54
|
-
## 📖 Usage
|
|
55
|
-
|
|
56
|
-
### 1. Import the Plugin
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
import { SoraEditor } from 'capacitor-sora-editor';
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 2. Open the Editor
|
|
63
|
-
|
|
64
|
-
The plugin works by launching a native Android Activity on top of your current WebView. You trigger it by passing the absolute URI of the file you want to edit.
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
const openNativeEditor = async () => {
|
|
68
|
-
try {
|
|
69
|
-
// You need a valid "file://" URI to a local file.
|
|
70
|
-
// Use @capacitor/filesystem to get the URI if needed.
|
|
71
|
-
const fileUri = "file:///data/user/0/com.your.app/files/Documents/my_script.js";
|
|
72
|
-
|
|
73
|
-
await SoraEditor.openEditor({
|
|
74
|
-
filePath: fileUri
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
console.log("Editor closed");
|
|
78
|
-
// You might want to reload the file content in your web app here
|
|
79
|
-
// as the native editor has modified it.
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.error("Failed to open editor", error);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### 3. File Handling & Lifecycle
|
|
87
|
-
|
|
88
|
-
* **Opening**: When `openEditor` is called, the Native Activity starts. The implementation reads the file from the disk directly.
|
|
89
|
-
* **Saving**: The editor handles saving internally. It auto-saves on typing (debounced) and performs a final save/rename check when the user exits (presses Back).
|
|
90
|
-
* **Return**: When the user presses the Back button in the Native UI, the Activity finishes, and the Promise returned by `openEditor` resolves. Development flow usually involves reloading the file content in your JS layer after the promise resolves.
|
|
91
|
-
|
|
92
|
-
## 🎨 UI & Customization
|
|
93
|
-
|
|
94
|
-
The editor includes a built-in "Settings" screen (accessible via the "More" menu in the top-right corner) where the user can configure:
|
|
95
|
-
|
|
96
|
-
* Font Size
|
|
97
|
-
* Theme Colors
|
|
98
|
-
* Line Numbers / Word Wrap
|
|
99
|
-
* Auto-save behavior
|
|
100
|
-
|
|
101
|
-
These settings are persisted natively in `SharedPreferences` by the plugin.
|
|
102
|
-
|
|
103
|
-
## ⚠️ Notes
|
|
104
|
-
|
|
105
|
-
* **Android Only**: This plugin currently implements the native editor **only for Android**. Calling it on iOS or Web will print a warning and do nothing (or throw an error based on configuration).
|
|
106
|
-
* **Context**: This was extracted from a personal note-taking app "Squircle CE", designed for high-performance offline text editing.
|
|
107
|
-
|
|
108
|
-
## 📄 License
|
|
109
|
-
|
|
110
|
-
MIT
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
package com.github.soraeditor.capacitor
|
|
2
|
-
|
|
3
|
-
import android.content.Intent
|
|
4
|
-
import com.getcapacitor.JSObject
|
|
5
|
-
import com.getcapacitor.Plugin
|
|
6
|
-
import com.getcapacitor.PluginCall
|
|
7
|
-
import com.getcapacitor.PluginMethod
|
|
8
|
-
import com.getcapacitor.annotation.CapacitorPlugin
|
|
9
|
-
|
|
10
|
-
@CapacitorPlugin(name = "SoraEditor")
|
|
11
|
-
class SoraEditorPlugin : Plugin() {
|
|
12
|
-
|
|
13
|
-
@PluginMethod
|
|
14
|
-
fun openEditor(call: PluginCall) {
|
|
15
|
-
val filePath = call.getString("filePath") ?: ""
|
|
16
|
-
|
|
17
|
-
android.util.Log.d("SoraEditorPlugin", "openEditor called with filePath: $filePath")
|
|
18
|
-
|
|
19
|
-
if (filePath.isEmpty()) {
|
|
20
|
-
android.util.Log.e("SoraEditorPlugin", "File path is empty")
|
|
21
|
-
call.reject("File path is required")
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
activity.runOnUiThread {
|
|
26
|
-
val intent = Intent(context, EditorActivity::class.java)
|
|
27
|
-
intent.putExtra("FILE_PATH", filePath)
|
|
28
|
-
android.util.Log.d("SoraEditorPlugin", "Starting EditorActivity")
|
|
29
|
-
activity.startActivity(intent)
|
|
30
|
-
call.resolve()
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|