paint_box_react_native 0.1.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.
Files changed (82) hide show
  1. package/LICENSE +20 -0
  2. package/PaintBoxReactNative.podspec +20 -0
  3. package/README.md +161 -0
  4. package/android/build.gradle +70 -0
  5. package/android/gradle.properties +45 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/paintboxreactnative/NativeViewHandler.kt +26 -0
  8. package/android/src/main/java/com/paintboxreactnative/PaintBoxNativeView.kt +61 -0
  9. package/android/src/main/java/com/paintboxreactnative/PaintBoxNativeViewManager.kt +105 -0
  10. package/android/src/main/java/com/paintboxreactnative/PaintBoxReactNativeModule.kt +74 -0
  11. package/android/src/main/java/com/paintboxreactnative/PaintBoxReactNativePackage.kt +41 -0
  12. package/android/src/main/java/com/paintboxreactnative/dto/ColorDTO.kt +37 -0
  13. package/ios/PaintBoxReactNative.h +5 -0
  14. package/ios/PaintBoxReactNative.mm +21 -0
  15. package/lib/module/IPaintEditor.js +7 -0
  16. package/lib/module/IPaintEditor.js.map +1 -0
  17. package/lib/module/NativePaintBoxReactNative.js +5 -0
  18. package/lib/module/NativePaintBoxReactNative.js.map +1 -0
  19. package/lib/module/PaintBoxContext.js +50 -0
  20. package/lib/module/PaintBoxContext.js.map +1 -0
  21. package/lib/module/PaintBoxRNView.js +90 -0
  22. package/lib/module/PaintBoxRNView.js.map +1 -0
  23. package/lib/module/PaintBoxViewNativeComponent.ts +63 -0
  24. package/lib/module/PaintEditor.js +121 -0
  25. package/lib/module/PaintEditor.js.map +1 -0
  26. package/lib/module/dto/BaseDTO.js +8 -0
  27. package/lib/module/dto/BaseDTO.js.map +1 -0
  28. package/lib/module/dto/ColorDTO.js +33 -0
  29. package/lib/module/dto/ColorDTO.js.map +1 -0
  30. package/lib/module/index.js +6 -0
  31. package/lib/module/index.js.map +2 -0
  32. package/lib/module/model/Color.js +12 -0
  33. package/lib/module/model/Color.js.map +1 -0
  34. package/lib/module/model/MimeType.js +12 -0
  35. package/lib/module/model/MimeType.js.map +1 -0
  36. package/lib/module/model/PaintMode.js +11 -0
  37. package/lib/module/model/PaintMode.js.map +1 -0
  38. package/lib/module/model/index.js +6 -0
  39. package/lib/module/model/index.js.map +1 -0
  40. package/lib/module/package.json +1 -0
  41. package/lib/typescript/package.json +1 -0
  42. package/lib/typescript/src/IPaintEditor.d.ts +18 -0
  43. package/lib/typescript/src/IPaintEditor.d.ts.map +1 -0
  44. package/lib/typescript/src/NativePaintBoxReactNative.d.ts +11 -0
  45. package/lib/typescript/src/NativePaintBoxReactNative.d.ts.map +1 -0
  46. package/lib/typescript/src/PaintBoxContext.d.ts +18 -0
  47. package/lib/typescript/src/PaintBoxContext.d.ts.map +1 -0
  48. package/lib/typescript/src/PaintBoxRNView.d.ts +11 -0
  49. package/lib/typescript/src/PaintBoxRNView.d.ts.map +1 -0
  50. package/lib/typescript/src/PaintBoxViewNativeComponent.d.ts +24 -0
  51. package/lib/typescript/src/PaintBoxViewNativeComponent.d.ts.map +1 -0
  52. package/lib/typescript/src/PaintEditor.d.ts +22 -0
  53. package/lib/typescript/src/PaintEditor.d.ts.map +1 -0
  54. package/lib/typescript/src/dto/BaseDTO.d.ts +5 -0
  55. package/lib/typescript/src/dto/BaseDTO.d.ts.map +1 -0
  56. package/lib/typescript/src/dto/ColorDTO.d.ts +19 -0
  57. package/lib/typescript/src/dto/ColorDTO.d.ts.map +1 -0
  58. package/lib/typescript/src/index.d.ts +5 -0
  59. package/lib/typescript/src/index.d.ts.map +1 -0
  60. package/lib/typescript/src/model/Color.d.ts +8 -0
  61. package/lib/typescript/src/model/Color.d.ts.map +1 -0
  62. package/lib/typescript/src/model/MimeType.d.ts +9 -0
  63. package/lib/typescript/src/model/MimeType.d.ts.map +1 -0
  64. package/lib/typescript/src/model/PaintMode.d.ts +8 -0
  65. package/lib/typescript/src/model/PaintMode.d.ts.map +1 -0
  66. package/lib/typescript/src/model/index.d.ts +4 -0
  67. package/lib/typescript/src/model/index.d.ts.map +1 -0
  68. package/package.json +175 -0
  69. package/src/IPaintEditor.ts +32 -0
  70. package/src/NativePaintBoxReactNative.ts +20 -0
  71. package/src/PaintBoxContext.ts +67 -0
  72. package/src/PaintBoxRNView.tsx +98 -0
  73. package/src/PaintBoxViewNativeComponent.ts +63 -0
  74. package/src/PaintEditor.ts +152 -0
  75. package/src/dto/BaseDTO.ts +7 -0
  76. package/src/dto/ColorDTO.ts +44 -0
  77. package/src/index.ts +5 -0
  78. package/src/index.tsx +3 -0
  79. package/src/model/Color.ts +13 -0
  80. package/src/model/MimeType.ts +8 -0
  81. package/src/model/PaintMode.ts +7 -0
  82. package/src/model/index.ts +3 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sinem.avci
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,20 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "PaintBoxReactNative"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/sinemavci/paint_box_react_native.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
17
+ s.private_header_files = "ios/**/*.h"
18
+
19
+ install_modules_dependencies(s)
20
+ end
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # 🎨 paint_box_react_native
2
+
3
+ <p align="center">
4
+ <img src="./assets/demo.gif" width="200" />
5
+ </p>
6
+
7
+ paint_box_react_native is a lightweight drawing component for React Native that allows users to draw on a canvas with customizable brush settings.
8
+
9
+ ## ⚙️ Installation
10
+ ```sh
11
+ npm install paint_box_react_native
12
+ ```
13
+
14
+ ## 🚀 Usage
15
+ ```js
16
+ import { PaintBoxRNView, PaintEditor } from 'paint_box_react_native';
17
+
18
+ // ...
19
+
20
+ <PaintBoxRNView
21
+ paintEditor={paintEditor1}
22
+ onPaintBoxReady={async () => {
23
+ paintEditor1.isEnable().then((val) => {
24
+ if (val) {
25
+ paintEditor1.getStrokeSize().then((size) => {
26
+ setStrokeWidth1(size);
27
+ });
28
+ paintEditor1.getPaintMode().then((mode) => {
29
+ setPaintMode1(mode);
30
+ });
31
+ }
32
+ });
33
+ }}
34
+ />
35
+ ```
36
+
37
+
38
+ ## Api Reference
39
+
40
+ #### 🧠 Core Concepts
41
+ PaintEditor
42
+
43
+ PaintEditor is the controller object used to interact with a specific PaintBoxRNView instance.
44
+
45
+ Each PaintBoxRNView must have its own PaintEditor instance.
46
+
47
+ #### ⚠️ Multiple PaintBox Support
48
+ You can use multiple paint boxes independently:
49
+
50
+ ```js
51
+ const paintEditor1 = new PaintEditor();
52
+ const paintEditor2 = new PaintEditor();
53
+ ```
54
+
55
+ ```js
56
+ <PaintBoxRNView paintEditor={paintEditor1} />
57
+ <PaintBoxRNView paintEditor={paintEditor2} />
58
+ ```
59
+
60
+ #### Undo
61
+ Reverts the last drawing action.
62
+
63
+ ```js
64
+ paintEditor.undo();
65
+ ```
66
+
67
+ #### Redo
68
+ Restores the last undone action.
69
+
70
+ ```js
71
+ paintEditor.redo();
72
+ ```
73
+
74
+ #### Reset
75
+ Clears the entire canvas.
76
+
77
+ ```js
78
+ paintEditor.reset();
79
+ ```
80
+
81
+ #### Import
82
+ | Param | Type | Required | Description |
83
+ | ------ | ------ | -------- | --------------- |
84
+ | path | string | ✅ | Image file path |
85
+ | width | number | ❌ | Target width |
86
+ | height | number | ❌ | Target height |
87
+
88
+ ```js
89
+ import(path: string, width?: number, height?: number): Promise<void>
90
+ ```
91
+
92
+ #### Export
93
+ ```js
94
+ export(path: string, fileName: string, mimeType: MimeType): Promise<string>
95
+ ```
96
+
97
+ ```js
98
+ type MimeType = "jpeg" | "png" | "gif" | "tif" | "bmp" | "pdf";
99
+ ```
100
+
101
+ | Param | Type | Required | Description |
102
+ | -------- | -------- | -------- | --------------------------- |
103
+ | path | string | ✅ | Output directory path |
104
+ | fileName | string | ✅ | File name without extension |
105
+ | mimeType | MimeType | ✅ | Output format |
106
+
107
+
108
+ #### Enable
109
+ ```js
110
+ isEnable(): Promise<boolean>
111
+ setEnable(value: boolean): void
112
+ ```
113
+
114
+
115
+ #### 🎨 Paint Mode
116
+ ```js
117
+ enum PaintMode {
118
+ PEN = "Pen",
119
+ MARKER = "Marker",
120
+ BUCKET = "Bucket",
121
+ BRUSH = "Brush",
122
+ ERASER = "Eraser"
123
+ }
124
+ ```
125
+
126
+ ```js
127
+ getPaintMode(): Promise<PaintMode>
128
+ setPaintMode(mode: PaintMode): void
129
+ ```
130
+
131
+ #### 🌈 Stroke Color
132
+ ```js
133
+ getStrokeColor(): Promise<Color>
134
+ setStrokeColor(color: Color): void
135
+ ```
136
+
137
+ Color Definition
138
+
139
+ ```js
140
+ class Color {
141
+ constructor(r: number, g: number, b: number)
142
+ }
143
+ ```
144
+
145
+ #### Stroke Size
146
+ ```js
147
+ getStrokeSize(): Promise<number>
148
+ setStrokeSize(size: number): void
149
+ ```
150
+
151
+ ## ⚙️ Component Props
152
+ | Prop | Type | Required | Description |
153
+ | --------------- | ----------- | -------- | --------------------------- |
154
+ | paintEditor | PaintEditor | ✅ | Controller instance |
155
+ | onPaintBoxReady | () => void | ❌ | Called when canvas is ready |
156
+
157
+ ## Best Practices
158
+ - Always create one PaintEditor per PaintBox
159
+ - Wait for onPaintBoxReady before calling methods
160
+ - Avoid very large stroke sizes (performance impact)
161
+
@@ -0,0 +1,70 @@
1
+ buildscript {
2
+ ext.PaintBoxReactNative = [
3
+ kotlinVersion: "2.0.21",
4
+ minSdkVersion: 24,
5
+ compileSdkVersion: 36,
6
+ targetSdkVersion: 36
7
+ ]
8
+
9
+ ext.getExtOrDefault = { prop ->
10
+ if (rootProject.ext.has(prop)) {
11
+ return rootProject.ext.get(prop)
12
+ }
13
+
14
+ return PaintBoxReactNative[prop]
15
+ }
16
+
17
+ repositories {
18
+ google()
19
+ mavenCentral()
20
+ }
21
+
22
+ dependencies {
23
+ classpath "com.android.tools.build:gradle:8.7.2"
24
+ // noinspection DifferentKotlinGradleVersion
25
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
26
+ }
27
+ }
28
+
29
+
30
+ apply plugin: "com.android.library"
31
+ apply plugin: "kotlin-android"
32
+
33
+ apply plugin: "com.facebook.react"
34
+
35
+ android {
36
+ namespace "com.paintboxreactnative"
37
+
38
+ compileSdkVersion getExtOrDefault("compileSdkVersion")
39
+
40
+ defaultConfig {
41
+ minSdkVersion getExtOrDefault("minSdkVersion")
42
+ targetSdkVersion getExtOrDefault("targetSdkVersion")
43
+ }
44
+
45
+ buildFeatures {
46
+ buildConfig true
47
+ }
48
+
49
+ buildTypes {
50
+ release {
51
+ minifyEnabled false
52
+ }
53
+ }
54
+
55
+ lint {
56
+ disable "GradleCompatible"
57
+ }
58
+
59
+ compileOptions {
60
+ sourceCompatibility JavaVersion.VERSION_1_8
61
+ targetCompatibility JavaVersion.VERSION_1_8
62
+ }
63
+ }
64
+
65
+ dependencies {
66
+ implementation(project(":nativebox"))
67
+ implementation("com.google.code.gson:gson:2.13.2")
68
+ implementation "com.facebook.react:react-android"
69
+ implementation("io.github.beyka:Android-TiffBitmapFactory:0.9.9.1")
70
+ }
@@ -0,0 +1,45 @@
1
+ # Project-wide Gradle settings.
2
+
3
+ # IDE (e.g. Android Studio) users:
4
+ # Gradle settings configured through the IDE *will override*
5
+ # any settings specified in this file.
6
+
7
+ # For more details on how to configure your build environment visit
8
+ # http://www.gradle.org/docs/current/userguide/build_environment.html
9
+
10
+ # Specifies the JVM arguments used for the daemon process.
11
+ # The setting is particularly useful for tweaking memory settings.
12
+ # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
13
+ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
14
+
15
+ # When configured, Gradle will run in incubating parallel mode.
16
+ # This option should only be used with decoupled projects. More details, visit
17
+ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18
+ # org.gradle.parallel=true
19
+
20
+ # AndroidX package structure to make it clearer which packages are bundled with the
21
+ # Android operating system, and which are packaged with your app's APK
22
+ # https://developer.android.com/topic/libraries/support-library/androidx-rn
23
+ android.useAndroidX=true
24
+
25
+ # Use this property to specify which architecture you want to build.
26
+ # You can also override it from the CLI using
27
+ # ./gradlew <task> -PreactNativeArchitectures=x86_64
28
+ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
29
+
30
+ # Use this property to enable support to the new architecture.
31
+ # This will allow you to use TurboModules and the Fabric render in
32
+ # your application. You should enable this flag either if you want
33
+ # to write custom TurboModules/Fabric components OR use libraries that
34
+ # are providing them.
35
+ newArchEnabled=true
36
+
37
+ # Use this property to enable or disable the Hermes JS engine.
38
+ # If set to false, you will be using JSC instead.
39
+ hermesEnabled=true
40
+
41
+ # Use this property to enable edge-to-edge display support.
42
+ # This allows your app to draw behind system bars for an immersive UI.
43
+ # Note: Only works with ReactActivity and should not be used with custom Activity.
44
+ edgeToEdgeEnabled=false
45
+ NODE_BINARY=/Users/sinemavci/.nvm/versions/node/v20.19.0/bin/node
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,26 @@
1
+ package com.paintboxreactnative
2
+
3
+ import com.facebook.react.bridge.ReactContext
4
+ import com.facebook.react.bridge.UiThreadUtil
5
+ import com.facebook.react.uimanager.UIManagerHelper
6
+ import com.facebook.react.uimanager.UIManagerModule
7
+ import com.facebook.react.uimanager.common.UIManagerType
8
+
9
+ object NativeViewHandler {
10
+ fun resolve(
11
+ reactContext: ReactContext,
12
+ viewTag: Int,
13
+ callback: (view: PaintBoxNativeView) -> Unit
14
+ ) {
15
+ UiThreadUtil.runOnUiThread {
16
+
17
+ val uiManager = UIManagerHelper.getUIManager(
18
+ reactContext,
19
+ UIManagerType.FABRIC
20
+ )
21
+
22
+ val paintBoxView: PaintBoxNativeView = uiManager?.resolveView(viewTag) as PaintBoxNativeView
23
+ callback(paintBoxView)
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,61 @@
1
+ package com.paintboxreactnative
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.util.Log
5
+ import android.widget.FrameLayout
6
+ import com.facebook.react.bridge.Arguments
7
+ import com.facebook.react.bridge.ReactContext
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.uimanager.UIManagerHelper
10
+ import com.facebook.react.uimanager.events.Event
11
+ import com.kotlin.native_drawing_plugin.PaintBoxView
12
+
13
+ class ViewAttachedEvent(surfaceId: Int, viewId: Int, val payload: WritableMap) : Event<ViewAttachedEvent>(surfaceId, viewId) {
14
+ override fun getEventName(): String {
15
+ return EVENT_NAME
16
+ }
17
+
18
+ override fun getEventData(): WritableMap {
19
+ return payload
20
+ }
21
+
22
+ companion object {
23
+ const val EVENT_NAME: String = "onPaintBoxReady"
24
+ }
25
+ }
26
+
27
+ @SuppressLint("ViewConstructor")
28
+ class PaintBoxNativeView(context: ReactContext): FrameLayout(context) {
29
+ val paintBox: PaintBoxView = PaintBoxView(context)
30
+ private var hasDispatchedReady = false
31
+
32
+ init {
33
+ this.addView(paintBox)
34
+ }
35
+
36
+ fun dispatchEvent() {
37
+ if (!hasDispatchedReady) {
38
+ post {
39
+ if (id == -1) {
40
+ post { dispatchEvent() }
41
+ return@post
42
+ } else {
43
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
44
+ val eventDispatcher =
45
+ UIManagerHelper.getEventDispatcher(context as ReactContext, id)
46
+ val payload = Arguments.createMap().apply {
47
+ putBoolean("result", true)
48
+ }
49
+ val event = ViewAttachedEvent(surfaceId, id, payload)
50
+ eventDispatcher?.dispatchEvent(event)
51
+ hasDispatchedReady = true
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ override fun onAttachedToWindow() {
58
+ super.onAttachedToWindow()
59
+ dispatchEvent()
60
+ }
61
+ }
@@ -0,0 +1,105 @@
1
+ package com.paintboxreactnative
2
+
3
+ import android.os.Build
4
+ import android.util.Log
5
+ import android.widget.FrameLayout
6
+ import androidx.annotation.RequiresApi
7
+ import com.facebook.react.bridge.ReactApplicationContext
8
+ import com.facebook.react.uimanager.SimpleViewManager
9
+ import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.ViewManagerDelegate
11
+ import com.facebook.react.viewmanagers.PaintBoxViewManagerDelegate
12
+ import com.facebook.react.viewmanagers.PaintBoxViewManagerInterface
13
+ import com.google.gson.Gson
14
+ import com.kotlin.native_drawing_plugin.PaintMode
15
+ import com.paintboxreactnative.dto.ColorDTO
16
+
17
+ class PaintBoxNativeViewManager(private val callerContext: ReactApplicationContext) :
18
+ SimpleViewManager<PaintBoxNativeView>(), PaintBoxViewManagerInterface<PaintBoxNativeView> {
19
+
20
+ override fun getName() = REACT_CLASS
21
+
22
+ override fun createViewInstance(context: ThemedReactContext): PaintBoxNativeView {
23
+ return PaintBoxNativeView(context).apply {
24
+ isClickable = true
25
+ isFocusable = true
26
+ layoutParams = FrameLayout.LayoutParams(
27
+ FrameLayout.LayoutParams.MATCH_PARENT,
28
+ FrameLayout.LayoutParams.MATCH_PARENT
29
+ )
30
+ }
31
+ }
32
+
33
+ override fun getCommandsMap() = mapOf(
34
+ "setViewMode" to COMMAND_SET_VIEW_MODE,
35
+ )
36
+
37
+ override fun getDelegate(): ViewManagerDelegate<PaintBoxNativeView> {
38
+ return PaintBoxViewManagerDelegate(this)
39
+ }
40
+
41
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
42
+ override fun undo(view: PaintBoxNativeView?) {
43
+ view?.paintBox?.paintEditor?.undo()
44
+ }
45
+
46
+ override fun redo(view: PaintBoxNativeView?) {
47
+ view?.paintBox?.paintEditor?.redo()
48
+ }
49
+
50
+ override fun reset(view: PaintBoxNativeView?) {
51
+ view?.paintBox?.paintEditor?.reset()
52
+ }
53
+
54
+ override fun importImage(
55
+ view: PaintBoxNativeView?,
56
+ path: String?,
57
+ width: Double,
58
+ height: Double
59
+ ) {
60
+ if (path != null) {
61
+ Log.e("import image path exist", "import image path exist: ${path}")
62
+ val _width = if (width != -1.0) {
63
+ width
64
+ } else {
65
+ null
66
+ }
67
+ val _height = if (height != -1.0) {
68
+ height
69
+ } else {
70
+ null
71
+ }
72
+ Log.e("import image path exist", "import image path exist: ${_width} ${_height}")
73
+ view?.paintBox?.paintEditor?.import(path, _width, _height)
74
+ }
75
+ }
76
+
77
+ override fun setEnable(view: PaintBoxNativeView, enable: Boolean) {
78
+ view.paintBox.paintEditor.setEnable(enable)
79
+ }
80
+
81
+
82
+ override fun setPaintMode(view: PaintBoxNativeView?, paintMode: String?) {
83
+ if(paintMode != null) {
84
+ view?.paintBox?.paintEditor?.setPaintMode(PaintMode.valueOf(paintMode))
85
+ }
86
+ }
87
+
88
+ override fun setStrokeColor(view: PaintBoxNativeView?, color: String?) {
89
+ if (color != null) {
90
+ val colorDTO = Gson().fromJson(color, ColorDTO::class.java)
91
+ val _color = colorDTO.toDataModel()
92
+ Log.e("color: ", "setStrokeColor: ${_color.alpha()}")
93
+ view?.paintBox?.paintEditor?.setStrokeColor(_color)
94
+ }
95
+ }
96
+
97
+ override fun setStrokeSize(view: PaintBoxNativeView?, size: Double) {
98
+ view?.paintBox?.paintEditor?.setStrokeWidth(size)
99
+ }
100
+
101
+ companion object {
102
+ private const val REACT_CLASS = "PaintBoxView"
103
+ private const val COMMAND_SET_VIEW_MODE = 1
104
+ }
105
+ }
@@ -0,0 +1,74 @@
1
+ package com.paintboxreactnative
2
+
3
+ import com.facebook.react.bridge.Promise
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.google.gson.Gson
6
+ import com.google.gson.GsonBuilder
7
+ import com.kotlin.native_drawing_plugin.MimeType
8
+ import com.paintboxreactnative.dto.ColorDTO
9
+
10
+ class PaintBoxReactNativeModule(val reactContext: ReactApplicationContext) :
11
+ NativePaintBoxReactNativeSpec(reactContext) {
12
+ val converter: Gson = GsonBuilder()
13
+ .create()
14
+
15
+ override fun export(viewTag: Double?, path: String?, fileName: String?, mimeType: String?, promise: Promise) {
16
+ if (viewTag != null) {
17
+
18
+ NativeViewHandler.resolve(reactContext, viewTag.toInt(), { paintBoxView: PaintBoxNativeView ->
19
+ if (path != null && mimeType != null) {
20
+ paintBoxView.paintBox.paintEditor.export(path, MimeType.fromValue(mimeType), fileName)
21
+ } else {
22
+ promise.reject(Throwable("Path or file Name is not valid"))
23
+ }
24
+ })
25
+ }
26
+ }
27
+
28
+ override fun isEnable(viewTag: Double?, promise: Promise) {
29
+ if(viewTag != null) {
30
+ NativeViewHandler.resolve(reactContext, viewTag.toInt(), { paintBoxView: PaintBoxNativeView ->
31
+ val isEnabled = paintBoxView.paintBox.isEnabled
32
+ promise.resolve(isEnabled)
33
+ })
34
+ }
35
+ }
36
+
37
+
38
+ override fun getPaintMode(viewTag: Double?, promise: Promise) {
39
+ if(viewTag != null) {
40
+ NativeViewHandler.resolve(reactContext, viewTag.toInt(), { paintBoxView: PaintBoxNativeView ->
41
+ val paintMode = paintBoxView.paintBox.paintEditor.getPaintMode()
42
+ promise.resolve(paintMode.name)
43
+ })
44
+ }
45
+ }
46
+
47
+ override fun getStrokeColor(viewTag: Double?, promise: Promise) {
48
+ if (viewTag != null) {
49
+ NativeViewHandler.resolve(reactContext, viewTag.toInt(), { paintBoxView: PaintBoxNativeView ->
50
+ try {
51
+ val strokeColor = paintBoxView.paintBox.paintEditor.getStrokeColor()
52
+ var strokeColorDTO: ColorDTO?
53
+ strokeColorDTO = ColorDTO.fromDataModel(strokeColor)
54
+ promise.resolve(converter.toJson(strokeColorDTO))
55
+ } catch (error: Error) {
56
+ promise.reject(Throwable(error))
57
+ }
58
+ })
59
+ }
60
+ }
61
+
62
+ override fun getStrokeSize(viewTag: Double?, promise: Promise) {
63
+ if (viewTag != null) {
64
+ NativeViewHandler.resolve(reactContext, viewTag.toInt(), { paintBoxView: PaintBoxNativeView ->
65
+ val size = paintBoxView.paintBox.paintEditor.getStrokeWidth()
66
+ promise.resolve(size)
67
+ })
68
+ }
69
+ }
70
+
71
+ companion object {
72
+ const val NAME = NativePaintBoxReactNativeSpec.NAME
73
+ }
74
+ }
@@ -0,0 +1,41 @@
1
+ package com.paintboxreactnative
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
8
+ import com.facebook.react.uimanager.ViewManager
9
+ import java.util.HashMap
10
+
11
+ class PaintBoxReactNativePackage : BaseReactPackage() {
12
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
13
+ return (if (name == PaintBoxReactNativeModule.NAME) {
14
+ PaintBoxReactNativeModule(reactContext)
15
+ } else {
16
+ null
17
+ }) as NativeModule?
18
+ }
19
+
20
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
21
+ return ReactModuleInfoProvider {
22
+ val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
23
+ moduleInfos[PaintBoxReactNativeModule.NAME] = ReactModuleInfo(
24
+ PaintBoxReactNativeModule.NAME,
25
+ PaintBoxReactNativeModule.NAME,
26
+ false, // canOverrideExistingModule
27
+ false, // needsEagerInit
28
+ true, // isCxxModule
29
+ false,
30
+ true,// isTurboModule
31
+ )
32
+ moduleInfos
33
+ }
34
+ }
35
+
36
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<in Nothing, in Nothing>> {
37
+ return listOf(
38
+ PaintBoxNativeViewManager(reactContext)
39
+ )
40
+ }
41
+ }
@@ -0,0 +1,37 @@
1
+ package com.paintboxreactnative.dto
2
+
3
+ import android.annotation.TargetApi
4
+ import android.graphics.Color
5
+ import android.os.Build
6
+ import androidx.annotation.RequiresApi
7
+
8
+ data class ColorDTO(
9
+ val red: Double,
10
+ val green: Double,
11
+ val blue: Double,
12
+ val alpha: Double = 255.0,
13
+ ) {
14
+ companion object {
15
+ @TargetApi(Build.VERSION_CODES.O)
16
+ @RequiresApi(Build.VERSION_CODES.O)
17
+ fun fromDataModel(color: Color): ColorDTO {
18
+ return ColorDTO(
19
+ red = color.red().toDouble(),
20
+ green = color.green().toDouble(),
21
+ blue = color.blue().toDouble(),
22
+ alpha = color.alpha().toDouble()
23
+ )
24
+ }
25
+ }
26
+
27
+ @TargetApi(Build.VERSION_CODES.O)
28
+ @RequiresApi(Build.VERSION_CODES.O)
29
+ fun toDataModel(): Color {
30
+ return Color.valueOf(
31
+ (red / 255.0).toFloat(),
32
+ (green / 255.0).toFloat(),
33
+ (blue.toFloat() / 255.0).toFloat(),
34
+ (alpha.toFloat() / 255.0).toFloat(),
35
+ )
36
+ }
37
+ }
@@ -0,0 +1,5 @@
1
+ #import <PaintBoxReactNativeSpec/PaintBoxReactNativeSpec.h>
2
+
3
+ @interface PaintBoxReactNative : NSObject <NativePaintBoxReactNativeSpec>
4
+
5
+ @end
@@ -0,0 +1,21 @@
1
+ #import "PaintBoxReactNative.h"
2
+
3
+ @implementation PaintBoxReactNative
4
+ - (NSNumber *)multiply:(double)a b:(double)b {
5
+ NSNumber *result = @(a * b);
6
+
7
+ return result;
8
+ }
9
+
10
+ - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
11
+ (const facebook::react::ObjCTurboModule::InitParams &)params
12
+ {
13
+ return std::make_shared<facebook::react::NativePaintBoxReactNativeSpecJSI>(params);
14
+ }
15
+
16
+ + (NSString *)moduleName
17
+ {
18
+ return @"PaintBoxReactNative";
19
+ }
20
+
21
+ @end