diff --git a/.gitignore b/.gitignore
index 11b4829..4852434 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,7 +5,7 @@
.DS_Store
/build
/captures
-/app/release
+/app-sample/release
/keystoreDetails
.externalNativeBuild
.cxx
diff --git a/README.md b/README.md
index 1a9f752..029dfbf 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,17 @@
-#
QuickEdit - Photo Editor
-QuickEdit is a user-friendly photo editor for Android, built using **Jetpack Compose**. It offers essential photo editing tools with a clean and smooth interface.
-
-## Latest Release
-
-[](https://github.com/Abizer-R/QuickEdit-Photo-Editor/releases/tag/v1.1.0-4)
-
-- [Download from the Google Play Store](https://play.google.com/store/apps/details?id=com.abizer_r.quickedit)
-- [Download Apk (v1.1.0)](https://github.com/Abizer-R/QuickEdit-Photo-Editor/releases/download/v1.1.0-4/app-release.apk)
-
-
-## [Click Here To Watch Demo Video](https://drive.google.com/file/d/18IipYR_jbUQVFL8U1jNEJd_KTm_Y9ije/view?usp=sharing)
+## ⚠️ Partial Readme (Will be updated after draw tool is completed)
+---
+#
QuickEdit - Photo Editor (Compose, Modular, Pluggable)
+[](https://github.com/Abizer-R/QuickEdit-Photo-Editor/releases)
+[](#)
+[](#)
+[](#license)
+**QuickEdit** is a modular, pluggable photo editor for Android with a **stable core engine**, a **Compose UI shell**, and **tool plugins** (Crop ✅, Draw/Text/Effects scaffolds).
+It preserves legacy UX (slide-out editor bars → full-screen tools) while cleaning layering, performance, and testability.
+- 📱 **Play Store:** [Install](https://play.google.com/store/apps/details?id=com.abizer_r.quickedit)
+- 📦 **Latest APK:** [Releases](https://github.com/Abizer-R/QuickEdit-Photo-Editor/releases)

@@ -35,16 +34,61 @@ QuickEdit is a user-friendly photo editor for Android, built using **Jetpack Com
- **Add Text**: Add text with option to customize fonts and format (bold, italic and more).
- **Smooth Animations**: Enjoy a seamless experience thanks to Jetpack Compose.
+---
+
+## Architecture (v0.x)
+
+**Goal:** a reusable editor published as Maven artifacts with a stable engine API and pluggable tools.
+**Status:** engine + shell done; Crop tool delivered; Draw in progress; Effects & Text planned.
+
+## Modules & Dependency Rules
+
+```
+app-sample/ # Host app; exercises the library
+quickedit/ # Legacy façade (keeps old entrypoints stable)
+quickedit-core-engine/ # Engine API + default impl (no Compose/UI deps)
+quickedit-compose-ui/ # Shell + tool contracts (Compose UI, no tool logic)
+quickedit-tool-crop/ # Crop tool (full-screen)
+quickedit-tool-draw/ # (ongoing)
+quickedit-tool-text/ # (planned)
+quickedit-tool-effects/ # (planned)
+```
+
+### **Dependency graph (enforced):**
+```
+app-sample ──► quickedit (legacy)
+ ├──► quickedit-compose-ui ──api──► quickedit-core-engine
+ └──► quickedit-tool-*
+quickedit-tool-* ──► quickedit-compose-ui
+quickedit-core-engine (Android framework only; no UI)
+```
+
+**Why `api(..)` from UI → Engine?** The UI public API mentions engine types (`EditImage`, `SaveFormat`). Re-exporting via `api(project(":quickedit-core-engine"))` makes those types visible to consumers cleanly.
+
+
+## Tech Stack & Versions (from `libs.versions.toml`)
+
+- **Android:** minSdk 24 · target/compile 35 · JDK 17
+- **Gradle/AGP:** 8.6.1
+- **Kotlin:** 2.1.10 (+ Compose plugin)
+- **Compose BOM:** 2025.05.00
+- **Compose libs:** Material3, Animation `1.7.0-beta04`, UI/Test/Tooling
+- **AndroidX:** Activity Compose 1.9.0 · Lifecycle 2.8.2 · Navigation 2.7.7 · AppCompat 1.7.0 · Core-ktx 1.13.1
+- **DI:** Hilt 2.57.1 (with hilt-navigation-compose 1.2.0)
+- **Coroutines:** 1.10.1
+- **Imaging:** GPUImage 2.1.0 · CanHub Cropper 4.5.0 · Compose-Screenshot 1.0.3
+- **UX Utils:** Cloudy 0.2.7 · ColorPicker 1.0.0
+- **Testing:** JUnit 4.13.2 · AndroidX JUnit 1.2.0 · Espresso 3.6.0
+
+---
+
## Libraries Used
QuickEdit makes use of the following libraries to provide its features:
- **Jetpack Compose**: A modern toolkit for building native Android UI.
- **Compose Animations**: For smooth and customizable UI animations.
-- **[GPUImage](https://github.com/CyberAgent/android-gpuimage)**: A library for GPU-based image processing by CyberAgent.
-- **[Cloudy](https://github.com/skydoves/cloudy)**: A library by Skydoves for blurring a composable.
- **[Image Cropper](https://github.com/CanHub/Android-Image-Cropper)**: A cropping library by Canhub that allows users to crop images seamlessly.
-- **[Compose-Screenshot](https://github.com/SmartToolFactory/Compose-Screenshot)**: A library by SmartToolFactory for capturing screenshots of composables in Jetpack Compose.
# License
diff --git a/app/.gitignore b/app-sample/.gitignore
similarity index 100%
rename from app/.gitignore
rename to app-sample/.gitignore
diff --git a/app/build.gradle.kts b/app-sample/build.gradle.kts
similarity index 100%
rename from app/build.gradle.kts
rename to app-sample/build.gradle.kts
diff --git a/app/proguard-rules.pro b/app-sample/proguard-rules.pro
similarity index 100%
rename from app/proguard-rules.pro
rename to app-sample/proguard-rules.pro
diff --git a/app/src/androidTest/java/com/abizer_r/sketchdraft/ExampleInstrumentedTest.kt b/app-sample/src/androidTest/java/com/abizer_r/sketchdraft/ExampleInstrumentedTest.kt
similarity index 100%
rename from app/src/androidTest/java/com/abizer_r/sketchdraft/ExampleInstrumentedTest.kt
rename to app-sample/src/androidTest/java/com/abizer_r/sketchdraft/ExampleInstrumentedTest.kt
diff --git a/app/src/main/AndroidManifest.xml b/app-sample/src/main/AndroidManifest.xml
similarity index 100%
rename from app/src/main/AndroidManifest.xml
rename to app-sample/src/main/AndroidManifest.xml
diff --git a/app/src/main/ic_launcher-playstore.png b/app-sample/src/main/ic_launcher-playstore.png
similarity index 100%
rename from app/src/main/ic_launcher-playstore.png
rename to app-sample/src/main/ic_launcher-playstore.png
diff --git a/app/src/main/java/com/abizer_r/quickedit/ui/QuickEditApplication.kt b/app-sample/src/main/java/com/abizer_r/quickedit/ui/QuickEditApplication.kt
similarity index 100%
rename from app/src/main/java/com/abizer_r/quickedit/ui/QuickEditApplication.kt
rename to app-sample/src/main/java/com/abizer_r/quickedit/ui/QuickEditApplication.kt
diff --git a/app/src/main/java/com/abizer_r/quickedit/ui/main/MainActivity.kt b/app-sample/src/main/java/com/abizer_r/quickedit/ui/main/MainActivity.kt
similarity index 100%
rename from app/src/main/java/com/abizer_r/quickedit/ui/main/MainActivity.kt
rename to app-sample/src/main/java/com/abizer_r/quickedit/ui/main/MainActivity.kt
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app-sample/src/main/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_launcher_background.xml
rename to app-sample/src/main/res/drawable/ic_launcher_background.xml
diff --git a/app/src/main/res/drawable/ic_launcher_background2.xml b/app-sample/src/main/res/drawable/ic_launcher_background2.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_launcher_background2.xml
rename to app-sample/src/main/res/drawable/ic_launcher_background2.xml
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app-sample/src/main/res/drawable/ic_launcher_foreground.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_launcher_foreground.xml
rename to app-sample/src/main/res/drawable/ic_launcher_foreground.xml
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app-sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to app-sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app-sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to app-sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app-sample/src/main/res/mipmap-hdpi/ic_launcher.webp
similarity index 100%
rename from app/src/main/res/mipmap-hdpi/ic_launcher.webp
rename to app-sample/src/main/res/mipmap-hdpi/ic_launcher.webp
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground2.webp b/app-sample/src/main/res/mipmap-hdpi/ic_launcher_foreground2.webp
similarity index 100%
rename from app/src/main/res/mipmap-hdpi/ic_launcher_foreground2.webp
rename to app-sample/src/main/res/mipmap-hdpi/ic_launcher_foreground2.webp
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app-sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp
similarity index 100%
rename from app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
rename to app-sample/src/main/res/mipmap-hdpi/ic_launcher_round.webp
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app-sample/src/main/res/mipmap-mdpi/ic_launcher.webp
similarity index 100%
rename from app/src/main/res/mipmap-mdpi/ic_launcher.webp
rename to app-sample/src/main/res/mipmap-mdpi/ic_launcher.webp
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground2.webp b/app-sample/src/main/res/mipmap-mdpi/ic_launcher_foreground2.webp
similarity index 100%
rename from app/src/main/res/mipmap-mdpi/ic_launcher_foreground2.webp
rename to app-sample/src/main/res/mipmap-mdpi/ic_launcher_foreground2.webp
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app-sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp
similarity index 100%
rename from app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
rename to app-sample/src/main/res/mipmap-mdpi/ic_launcher_round.webp
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app-sample/src/main/res/mipmap-xhdpi/ic_launcher.webp
similarity index 100%
rename from app/src/main/res/mipmap-xhdpi/ic_launcher.webp
rename to app-sample/src/main/res/mipmap-xhdpi/ic_launcher.webp
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground2.webp b/app-sample/src/main/res/mipmap-xhdpi/ic_launcher_foreground2.webp
similarity index 100%
rename from app/src/main/res/mipmap-xhdpi/ic_launcher_foreground2.webp
rename to app-sample/src/main/res/mipmap-xhdpi/ic_launcher_foreground2.webp
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
similarity index 100%
rename from app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
rename to app-sample/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app-sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
rename to app-sample/src/main/res/mipmap-xxhdpi/ic_launcher.webp
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground2.webp b/app-sample/src/main/res/mipmap-xxhdpi/ic_launcher_foreground2.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground2.webp
rename to app-sample/src/main/res/mipmap-xxhdpi/ic_launcher_foreground2.webp
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
rename to app-sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
rename to app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground2.webp b/app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground2.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground2.webp
rename to app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground2.webp
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
similarity index 100%
rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
rename to app-sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
diff --git a/app/src/main/res/values/colors.xml b/app-sample/src/main/res/values/colors.xml
similarity index 100%
rename from app/src/main/res/values/colors.xml
rename to app-sample/src/main/res/values/colors.xml
diff --git a/app/src/main/res/values/strings.xml b/app-sample/src/main/res/values/strings.xml
similarity index 100%
rename from app/src/main/res/values/strings.xml
rename to app-sample/src/main/res/values/strings.xml
diff --git a/app/src/main/res/values/themes.xml b/app-sample/src/main/res/values/themes.xml
similarity index 100%
rename from app/src/main/res/values/themes.xml
rename to app-sample/src/main/res/values/themes.xml
diff --git a/app/src/main/res/xml/backup_rules.xml b/app-sample/src/main/res/xml/backup_rules.xml
similarity index 100%
rename from app/src/main/res/xml/backup_rules.xml
rename to app-sample/src/main/res/xml/backup_rules.xml
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app-sample/src/main/res/xml/data_extraction_rules.xml
similarity index 100%
rename from app/src/main/res/xml/data_extraction_rules.xml
rename to app-sample/src/main/res/xml/data_extraction_rules.xml
diff --git a/app/src/test/java/com/abizer_r/quickedit/ExampleUnitTest.kt b/app-sample/src/test/java/com/abizer_r/quickedit/ExampleUnitTest.kt
similarity index 100%
rename from app/src/test/java/com/abizer_r/quickedit/ExampleUnitTest.kt
rename to app-sample/src/test/java/com/abizer_r/quickedit/ExampleUnitTest.kt
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 905f308..2595be9 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -21,6 +21,7 @@ lifecycleRuntimeKtx = "2.8.2"
material = "1.12.0"
navigationCompose = "2.7.7"
composeAnimation = "1.7.0-beta04"
+coroutines = "1.10.1"
[libraries]
@@ -53,6 +54,8 @@ hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltA
hilt-compiler = { module = "com.google.dagger:hilt-compiler", version.ref = "hiltAndroid" }
junit = { module = "junit:junit", version.ref = "junit" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
+kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
+kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines" }
material = { module = "com.google.android.material:material", version.ref = "material" }
[plugins]
diff --git a/quickedit-core-engine/.gitignore b/quickedit-core-engine/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-core-engine/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-core-engine/build.gradle.kts b/quickedit-core-engine/build.gradle.kts
new file mode 100644
index 0000000..164080d
--- /dev/null
+++ b/quickedit-core-engine/build.gradle.kts
@@ -0,0 +1,48 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.engine"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.kotlinx.coroutines.core)
+// implementation(libs.androidx.appcompat)
+// implementation(libs.material)
+// testImplementation(libs.junit)
+// androidTestImplementation(libs.androidx.junit)
+// androidTestImplementation(libs.androidx.espresso.core)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/quickedit-core-engine/consumer-rules.pro b/quickedit-core-engine/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-core-engine/proguard-rules.pro b/quickedit-core-engine/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-core-engine/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-core-engine/src/androidTest/java/io/github/abizerr/quickedit/engine/ExampleInstrumentedTest.kt b/quickedit-core-engine/src/androidTest/java/io/github/abizerr/quickedit/engine/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..a2498fe
--- /dev/null
+++ b/quickedit-core-engine/src/androidTest/java/io/github/abizerr/quickedit/engine/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.engine
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.engine.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/AndroidManifest.xml b/quickedit-core-engine/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b67b168
--- /dev/null
+++ b/quickedit-core-engine/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditEngine.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditEngine.kt
new file mode 100644
index 0000000..1be5c6a
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditEngine.kt
@@ -0,0 +1,37 @@
+package io.github.abizerr.quickedit.engine.api
+
+interface EditEngine {
+ suspend fun newSession(image: EditImage): EditSnapshot
+ suspend fun apply(op: EditOp): EditSnapshot
+ suspend fun render(snapshot: EditSnapshot, size: Size): RenderResult
+ suspend fun save(snapshot: EditSnapshot, format: SaveFormat): Result
+ val history: HistoryView
+ /**
+ * FUTURE-1: Capabilities & queries (non-breaking):
+ * fun supports(op: kotlin.reflect.KClass): Boolean = true
+ * val maxCanvasSize: Size get() = Size(8192, 8192)
+ * FUTURE-2: Observability hooks:
+ * var events: ((EngineEvent) -> Unit)?
+ */
+}
+
+interface HistoryView {
+ val canUndo: Boolean
+ val canRedo: Boolean
+ val undoCount: Int
+ val redoCount: Int
+ /**
+ * FUTURE: Expose memory footprint if required
+ * val approxMemoryBytes: Long get() = 0
+ */
+}
+
+
+/**
+ * FUTURE: Emit non-fatal diagnostics without throwing:
+ * sealed interface EngineEvent {
+ * data class OpLatency(val op: EditOp, val ms: Long): EngineEvent
+ * data class RenderDownscaled(val requested: Size, val actual: Size): EngineEvent
+ * data class OOMPrevented(val reducedHistory: Int): EngineEvent
+ * }
+ */
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditModels.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditModels.kt
new file mode 100644
index 0000000..b9aa89b
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditModels.kt
@@ -0,0 +1,48 @@
+package io.github.abizerr.quickedit.engine.api
+
+import android.graphics.Bitmap
+
+
+/** A lightweight reference to the image the editor works on. */
+sealed interface EditImage {
+ data class FromUri(val uri: android.net.Uri) : EditImage
+ data class FromBitmap(val bitmap: android.graphics.Bitmap) : EditImage
+ /**
+ * FUTURE: Possible additions without breaking callers:
+ * example: FromBytes, FromFile, FromHardwareBuffer, ContentProvider, etc.
+ */
+}
+
+/** Immutable snapshot of the editing graph at a point in time. */
+data class EditSnapshot(
+ val image: EditImage,
+ val rev: Long = 0L,
+ val operations: List = emptyList()
+ /**
+ * FUTURE: Add graph states without breaking callers:
+ * example: Layers, Selection, Metadata
+ */
+)
+
+/** Output from save(). You can extend later with Uri/bytes/metadata. */
+data class EditedImage(
+ val mimeType: String,
+ val bytes: ByteArray? = null
+ /**
+ * FUTURE: Add destination/EXIF without breaking callers:
+ * example: savedFile: android.net.Uri, exif: Map
+ */
+)
+
+/** Sizes used by render() */
+data class Size(val width: Int, val height: Int)
+
+/** Render output placeholder (Phase 5 will hold a Bitmap or ImageBitmap). */
+data class RenderResult(
+ val ok: Boolean,
+ val preview: Bitmap?
+)
+/**
+ * FUTURE: Add preview payloads without chaning the signature of render() in EditEngine interface:
+ * example: bitmap, downscaleFactor, etc.
+ */
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditOp.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditOp.kt
new file mode 100644
index 0000000..7f07fc5
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/EditOp.kt
@@ -0,0 +1,16 @@
+package io.github.abizerr.quickedit.engine.api
+
+import android.graphics.Rect
+import android.graphics.RectF
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+
+/** Minimum set; expand in Phase 6 with tool packs. */
+sealed interface EditOp {
+// data class ApplyCurve(val presetId: String) : EditOp
+ data class CropImage(val rect: Rect) : EditOp
+// data class InsertText(val text: String, val x: Float, val y: Float) : EditOp
+ data object Undo : EditOp
+ data object Redo : EditOp
+
+ data class DrawShape(val spec: ShapeSpec)
+}
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/SaveFormat.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/SaveFormat.kt
new file mode 100644
index 0000000..7d405dd
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/api/SaveFormat.kt
@@ -0,0 +1,11 @@
+package io.github.abizerr.quickedit.engine.api
+
+sealed interface SaveFormat {
+ data class Png(val lossless: Boolean = true) : SaveFormat
+ data class Jpeg(val quality: Int = 90) : SaveFormat
+ data class WebP(val lossless: Boolean = false, val quality: Int = 90) : SaveFormat
+ /**
+ * FUTURE: Add new Codecs additively
+ * example: Heif, Avif
+ */
+}
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/PaintSpec.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/PaintSpec.kt
new file mode 100644
index 0000000..8c25a87
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/PaintSpec.kt
@@ -0,0 +1,15 @@
+package io.github.abizerr.quickedit.engine.drawspec
+
+data class PaintSpec(
+ val argb: Int,
+ val alpha: Float,
+ val widthPx: Float,
+ val isEraser: Boolean
+)
+
+fun ShapeSpec.toPaintSpec(): PaintSpec = PaintSpec(
+ argb = this.argb,
+ alpha = this.alpha.coerceIn(0f,1f),
+ widthPx = this.widthPx.coerceAtLeast(0.5f),
+ isEraser = this.isEraser
+)
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeSpec.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeSpec.kt
new file mode 100644
index 0000000..8b51e7d
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeSpec.kt
@@ -0,0 +1,31 @@
+package io.github.abizerr.quickedit.engine.drawspec
+
+import androidx.annotation.FloatRange
+
+sealed interface ShapeSpec {
+
+ companion object {
+ val defaultOffset = Pair(Float.NaN, Float.NaN)
+ }
+ val argb: Int
+ val alpha: Float // 0f..1f
+ val widthPx: Float
+ val isEraser: Boolean get() = false
+
+ data class Brush(
+ val points: MutableList> = mutableListOf(),
+ override val argb: Int,
+ @FloatRange(from = 0.0, to = 1.0) override val alpha: Float,
+ override val widthPx: Float,
+ override val isEraser: Boolean = false
+ ) : ShapeSpec
+
+ data class Shape(
+ val shapeType: ShapeType,
+ var startOffset: Pair = defaultOffset,
+ var endOffset: Pair = defaultOffset,
+ override val argb: Int,
+ @FloatRange(from = 0.0, to = 1.0) override val alpha: Float,
+ override val widthPx: Float,
+ ) : ShapeSpec
+}
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeType.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeType.kt
new file mode 100644
index 0000000..b8724a3
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/drawspec/ShapeType.kt
@@ -0,0 +1,5 @@
+package io.github.abizerr.quickedit.engine.drawspec
+
+enum class ShapeType {
+ LINE, OVAL, RECTANGLE
+}
\ No newline at end of file
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/DefaultEditEngine.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/DefaultEditEngine.kt
new file mode 100644
index 0000000..02ee004
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/DefaultEditEngine.kt
@@ -0,0 +1,175 @@
+package io.github.abizerr.quickedit.engine.impl
+
+import android.content.ContentResolver
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Canvas
+import android.graphics.ImageDecoder
+import android.graphics.Paint
+import android.graphics.Rect
+import android.os.Build
+import io.github.abizerr.quickedit.engine.api.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import androidx.core.graphics.scale
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+import io.github.abizerr.quickedit.engine.util.applySpec
+import io.github.abizerr.quickedit.engine.util.drawOn
+import java.io.ByteArrayOutputStream
+
+/**
+ * Minimal but real engine:
+ * - Decodes source (Uri/Bitmap)
+ * - Renders a scaled preview Bitmap
+ * - Saves to bytes (PNG/JPEG/WebP)
+ */
+class DefaultEditEngine(
+ private val maxUndo: Int = 20,
+ private val resolver: ContentResolver? = null
+) : EditEngine {
+
+ private val historyManager = HistoryManager(maxUndo)
+
+ override val history: HistoryView = object : HistoryView {
+ override val canUndo: Boolean get() = this@DefaultEditEngine.historyManager.canUndo()
+ override val canRedo: Boolean get() = this@DefaultEditEngine.historyManager.canRedo()
+ override val undoCount: Int get() = this@DefaultEditEngine.historyManager.undoCount()
+ override val redoCount: Int get() = this@DefaultEditEngine.historyManager.redoCount()
+ }
+
+ override suspend fun newSession(image: EditImage): EditSnapshot {
+ val snap = EditSnapshot(image = image, rev = 0)
+ historyManager.setInitial(snap)
+ return snap
+ }
+
+ override suspend fun apply(op: EditOp): EditSnapshot = withContext(Dispatchers.Default) {
+ val current = historyManager.current() ?: error("Call newSession() first")
+ val next = when (op) {
+ is EditOp.Undo -> historyManager.undo() ?: current
+ is EditOp.Redo -> historyManager.redo() ?: current
+
+ is EditOp.CropImage -> {
+ val baseBitmap = decode(current.image) ?: return@withContext current
+ val croppedBitmap = cropBitmapImageSpace(baseBitmap, op.rect)
+ current.copy(
+ image = EditImage.FromBitmap(croppedBitmap),
+ rev = current.rev + 1
+ )
+ }
+
+ is EditOp.DrawShape -> {
+ current.copy(
+ rev = current.rev + 1,
+ operations = current.operations + op
+ )
+ }
+
+ else -> current.copy(rev = current.rev + 1) // TODO (revamp): placeholder; real ops later
+ }
+ if (op !is EditOp.Undo && op !is EditOp.Redo) historyManager.push(next)
+ return@withContext next
+ }
+
+ override suspend fun render(snapshot: EditSnapshot, size: Size): RenderResult {
+ val bitmap = withContext(Dispatchers.Default) {
+ val baseBitmap = decode(snapshot.image) ?: return@withContext null
+ val scaledBitmap = scaleToFit(baseBitmap, size.width, size.height)
+
+ // draw operations on top
+ val mutable = scaledBitmap.copy(Bitmap.Config.ARGB_8888, true)
+ val canvas = Canvas(mutable)
+ snapshot.operations.forEach { op ->
+ when (op) {
+ is EditOp.DrawShape -> {
+ val paintSpec = op.spec.toPaintSpec()
+ val paint = Paint().applySpec(paintSpec)
+ op.spec.drawOn(canvas, paint)
+ }
+ else -> Unit
+ }
+
+ }
+ mutable
+ } ?: return RenderResult(ok = false, preview = null)
+
+ return RenderResult(ok = true, preview = bitmap)
+ }
+
+ override suspend fun save(snapshot: EditSnapshot, format: SaveFormat): Result = withContext(Dispatchers.IO) {
+ val baseBitmap = decode(snapshot.image)
+ ?: return@withContext Result.failure(IllegalStateException("Decode failed"))
+
+ val (compressFormat, quality, mime) = when (format) {
+ is SaveFormat.Png -> Triple(Bitmap.CompressFormat.PNG, 100, "image/png")
+ is SaveFormat.Jpeg -> Triple(Bitmap.CompressFormat.JPEG, format.quality.coerceIn(0, 100), "image/jpeg")
+ is SaveFormat.WebP -> {
+ val q = format.quality.coerceIn(0, 100)
+ val mimeType = "image/webp"
+ val compress = if (Build.VERSION.SDK_INT >= 30) {
+ if (format.lossless) Bitmap.CompressFormat.WEBP_LOSSLESS else Bitmap.CompressFormat.WEBP_LOSSY
+ } else {
+ Bitmap.CompressFormat.WEBP
+ }
+ Triple(compress, q, mimeType)
+ }
+ }
+
+ val outputStream = ByteArrayOutputStream()
+ baseBitmap.compress(compressFormat, quality, outputStream)
+ Result.success(EditedImage(
+ mimeType = mime,
+ bytes = outputStream.toByteArray()
+ ))
+ }
+
+ private fun decode(image: EditImage): Bitmap? {
+ return when (image) {
+ is EditImage.FromBitmap -> image.bitmap
+ is EditImage.FromUri -> {
+ decodeBitmapFromUri(image)
+ }
+ }
+ }
+
+ private fun decodeBitmapFromUri(
+ image: EditImage.FromUri
+ ): Bitmap? = try {
+ val contentResolver = resolver ?: return null
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ // ImageDecoder handles EXIF orientation, wide color, scaling hints
+ val src = ImageDecoder.createSource(contentResolver, image.uri)
+ ImageDecoder.decodeBitmap(src)
+ } else {
+ // BitmapFactory.decodeStream doesn't auto-rotate based on EXIF
+ // But, it is the only safe option we have below API-P
+ contentResolver.openInputStream(image.uri)?.use { inputStream ->
+ BitmapFactory.decodeStream(inputStream)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+
+ private fun scaleToFit(src: Bitmap, targetW: Int, targetH: Int): Bitmap {
+ if (targetW <= 0 || targetH <= 0) return src
+ val wScale = targetW.toFloat() / src.width
+ val hScale = targetH.toFloat() / src.height
+ val scale = minOf(wScale, hScale)
+ val w = (src.width * scale).toInt().coerceAtLeast(1)
+ val h = (src.height * scale).toInt().coerceAtLeast(1)
+ return src.scale(w, h)
+ }
+
+ private fun cropBitmapImageSpace(src: Bitmap, rect: Rect): Bitmap {
+ val left = rect.left.coerceIn(0, src.width)
+ val right = rect.right.coerceIn(left, src.width)
+ val top = rect.top.coerceIn(0, src.height)
+ val bottom = rect.bottom.coerceIn(top, src.height)
+ val width = (right - left).coerceAtLeast(1)
+ val height = (bottom - top).coerceAtLeast(1)
+ return Bitmap.createBitmap(src, left, top, width, height)
+ }
+}
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/HistoryManager.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/HistoryManager.kt
new file mode 100644
index 0000000..af05ae5
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/impl/HistoryManager.kt
@@ -0,0 +1,45 @@
+package io.github.abizerr.quickedit.engine.impl
+
+import io.github.abizerr.quickedit.engine.api.EditSnapshot
+
+internal class HistoryManager(maxUndo: Int) {
+ private val cap = maxUndo.coerceAtLeast(0)
+ private val past = ArrayDeque()
+ private var present: EditSnapshot? = null
+ private val future = ArrayDeque()
+
+ fun setInitial(snapshot: EditSnapshot) {
+ present = snapshot; past.clear(); future.clear()
+ }
+
+ fun push(next: EditSnapshot) {
+ present?.let { past.addLast(it); if (past.size > cap) past.removeFirst() }
+ present = next; future.clear()
+ }
+
+ fun undo(): EditSnapshot? {
+ val prev = past.removeLastOrNull() ?: return null
+ present?.let { future.addLast(it) }
+ present = prev
+ return present
+ }
+
+ fun redo(): EditSnapshot? {
+ val next = future.removeLastOrNull() ?: return null
+ present?.let { past.addLast(it); if (past.size > cap) past.removeFirst() }
+ present = next
+ return present
+ }
+
+ fun current(): EditSnapshot? = present
+ fun canUndo() = past.isNotEmpty()
+ fun canRedo() = future.isNotEmpty()
+ fun undoCount() = past.size
+ fun redoCount() = future.size
+
+ /**
+ * FUTURE: Add cap management strategy:
+ * - Drop oldest diffs
+ * - Merge consecutive strokes (from draw tool) into one snapshot
+ */
+}
diff --git a/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/util/Extensions.kt b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/util/Extensions.kt
new file mode 100644
index 0000000..d997d92
--- /dev/null
+++ b/quickedit-core-engine/src/main/java/io/github/abizerr/quickedit/engine/util/Extensions.kt
@@ -0,0 +1,73 @@
+package io.github.abizerr.quickedit.engine.util
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import io.github.abizerr.quickedit.engine.drawspec.PaintSpec
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+
+fun Paint.applySpec(paintSpec: PaintSpec): Paint = this.apply {
+ isAntiAlias = true
+ style = Paint.Style.STROKE
+ strokeCap = Paint.Cap.ROUND
+ strokeJoin = Paint.Join.ROUND
+ strokeWidth = paintSpec.widthPx
+ color = paintSpec.argb
+ alpha = (paintSpec.alpha * 255f).toInt()
+ xfermode = if (paintSpec.isEraser) PorterDuffXfermode(PorterDuff.Mode.CLEAR) else null
+}
+
+fun ShapeSpec.drawOn(canvas: Canvas, paint: Paint) {
+ val ps = toPaintSpec()
+ paint.applySpec(ps)
+ when (this) {
+ is ShapeSpec.Brush -> {
+ val path = android.graphics.Path()
+ var last: Pair? = null
+ for (p in points) {
+ if (last == null) {
+ path.moveTo(p.first, p.second)
+ } else {
+ path.quadTo(
+ last.first,
+ last.second,
+ (last.first + p.first) / 2,
+ (last.second + p.second) / 2,
+ )
+ }
+ last = p
+ }
+ canvas.drawPath(path, paint)
+ }
+
+ is ShapeSpec.Shape -> {
+ when (this.shapeType) {
+ ShapeType.LINE -> canvas.drawLine(
+ startOffset.first,
+ startOffset.second,
+ endOffset.first,
+ endOffset.second,
+ paint
+ )
+
+ ShapeType.OVAL -> canvas.drawOval(
+ startOffset.first,
+ startOffset.second,
+ endOffset.first,
+ endOffset.second,
+ paint
+ )
+ ShapeType.RECTANGLE -> canvas.drawRect(
+ startOffset.first,
+ startOffset.second,
+ endOffset.first,
+ endOffset.second,
+ paint
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickedit-core-engine/src/test/java/io/github/abizerr/quickedit/engine/ExampleUnitTest.kt b/quickedit-core-engine/src/test/java/io/github/abizerr/quickedit/engine/ExampleUnitTest.kt
new file mode 100644
index 0000000..3e9d250
--- /dev/null
+++ b/quickedit-core-engine/src/test/java/io/github/abizerr/quickedit/engine/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.engine
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-crop/.gitignore b/quickedit-tool-crop/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-tool-crop/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-tool-crop/build.gradle.kts b/quickedit-tool-crop/build.gradle.kts
new file mode 100644
index 0000000..64a0f5a
--- /dev/null
+++ b/quickedit-tool-crop/build.gradle.kts
@@ -0,0 +1,54 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.tool.crop"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+ implementation(project(":quickedit-ui"))
+
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+ implementation(libs.androidx.compose.material.icons.extended)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+
+ implementation(libs.android.image.cropper) // canhub cropper
+}
\ No newline at end of file
diff --git a/quickedit-tool-crop/consumer-rules.pro b/quickedit-tool-crop/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-tool-crop/proguard-rules.pro b/quickedit-tool-crop/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-tool-crop/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-tool-crop/src/androidTest/java/io/github/abizerr/quickedit/tool/crop/ExampleInstrumentedTest.kt b/quickedit-tool-crop/src/androidTest/java/io/github/abizerr/quickedit/tool/crop/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..4b2fa96
--- /dev/null
+++ b/quickedit-tool-crop/src/androidTest/java/io/github/abizerr/quickedit/tool/crop/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.tool.crop
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.tool.crop.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-crop/src/main/AndroidManifest.xml b/quickedit-tool-crop/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..989d6cc
--- /dev/null
+++ b/quickedit-tool-crop/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/crop/AspectRatioDialog.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/AspectRatioDialog.kt
similarity index 89%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/common/crop/AspectRatioDialog.kt
rename to quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/AspectRatioDialog.kt
index b881fa3..ab22afc 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/crop/AspectRatioDialog.kt
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/AspectRatioDialog.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.ui.common.crop
+package io.github.abizerr.quickedit.tool.crop
import android.content.res.Configuration
import androidx.annotation.StringRes
@@ -33,11 +33,9 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
-import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.DarkPanel
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.utils.defaultTextColor
-import com.abizer_r.quickedit.utils.toast
+import io.github.abizerr.quickedit.ui.theme.DarkPanel
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.utils.errorToast
const val MIN_RATIO = 0.15f
const val MAX_RATIO = 5.0f
@@ -61,12 +59,8 @@ fun AspectRatioDialog(
var aspectX by remember { mutableStateOf("1") }
var aspectY by remember { mutableStateOf("1") }
- val titleTextStyle = MaterialTheme.typography.titleMedium.copy(
- color = defaultTextColor()
- )
- val bodyTextStyle = MaterialTheme.typography.bodySmall.copy(
- color = defaultTextColor()
- )
+ val titleTextStyle = MaterialTheme.typography.titleMedium
+ val bodyTextStyle = MaterialTheme.typography.bodySmall
Box(
modifier = Modifier.background(
@@ -127,7 +121,7 @@ fun AspectRatioDialog(
if (validation.isValid) {
onSetRatio(aspectX.toInt(), aspectY.toInt())
} else {
- context.toast(context.getString(validation.errorResId ?: R.string.something_went_wrong))
+ context.errorToast(validation.errorResId)
}
}
) {
@@ -189,11 +183,6 @@ private fun RatioInputField(
OutlinedTextField(
modifier = modifier,
singleLine = true,
-// value = TextFieldValue(
-// text = text,
-// selection = TextRange(text.length)
-// ),
-// onValueChange = onValueChange,
value = text,
onValueChange = { newValue ->
// Allow only digits and empty value
@@ -207,9 +196,9 @@ private fun RatioInputField(
)
}
-@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Preview
@Composable
-fun PreviewAspectRatioDialog() {
+private fun PreviewAspectRatioDialog() {
QuickEditTheme {
AspectRatioDialog(
onDismiss = {},
diff --git a/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropContribution.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropContribution.kt
new file mode 100644
index 0000000..a77825b
--- /dev/null
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropContribution.kt
@@ -0,0 +1,43 @@
+package io.github.abizerr.quickedit.tool.crop
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Crop
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolContribution
+import io.github.abizerr.quickedit.ui.api.ToolController
+
+class CropContribution : ToolContribution {
+ override val id: String = "crop"
+ override val label: String = "Crop"
+ override val supportsFullScreen: Boolean get() = true
+
+ @Composable
+ override fun ToolbarIcon(selected: Boolean, onClick: () -> Unit) {
+ IconWithLabel(
+ selected = selected,
+ imageVector = Icons.Outlined.Crop,
+ labelText = label,
+ onClick = onClick
+ )
+ }
+
+ @Composable
+ override fun Panel(state: QuickEditState, controller: ToolController) {
+ Text("Crop tool placeholder")
+ }
+
+ @Composable
+ override fun FullScreenTool(
+ state: QuickEditState,
+ controller: ToolController,
+ onExit: () -> Unit
+ ) {
+ CropToolScreen(
+ state = state,
+ controller = controller,
+ onExit = onExit
+ )
+ }
+}
diff --git a/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropToolScreen.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropToolScreen.kt
new file mode 100644
index 0000000..b442cba
--- /dev/null
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropToolScreen.kt
@@ -0,0 +1,320 @@
+package io.github.abizerr.quickedit.tool.crop
+
+import android.graphics.Rect
+import android.view.ViewGroup
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.canhub.cropper.CropImageOptions
+import com.canhub.cropper.CropImageView
+import io.github.abizerr.quickedit.engine.api.EditImage
+import io.github.abizerr.quickedit.engine.api.EditOp
+import io.github.abizerr.quickedit.tool.crop.model.CropperOption
+import io.github.abizerr.quickedit.tool.crop.utils.CropModeUtils
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolController
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.TOOLBAR_HEIGHT_LARGE
+import io.github.abizerr.quickedit.ui.common.TOOLBAR_HEIGHT_SMALL
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.PreviewUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils.TOOLBAR_COLLAPSE_ANIM_DURATION_FAST
+import io.github.abizerr.quickedit.ui.utils.errorToast
+import io.github.abizerr.quickedit.ui.utils.toast
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+private val topToolbarHeight = TOOLBAR_HEIGHT_SMALL
+private val bottomToolbarHeight = TOOLBAR_HEIGHT_LARGE
+
+@Composable
+fun CropToolScreen(
+ state: QuickEditState,
+ controller: ToolController,
+ onExit: () -> Unit
+) {
+ val context = LocalContext.current
+
+ var toolbarVisible by remember { mutableStateOf(true) }
+ val scope = rememberCoroutineScope()
+
+ var cropView: CropImageView? by remember { mutableStateOf(null) }
+ var cropImageOptions by remember { mutableStateOf(CropImageOptions()) }
+
+ val cropperOptionsList = remember { CropModeUtils.getCropperOptionsList() }
+ var selectedCropOptionIndex by remember { mutableIntStateOf(0) }
+ var showCropRatioDialog by remember { mutableStateOf(false) }
+
+ fun emitCropAndExit(rect: Rect?, rotationDeg: Int = 0) {
+ if (rect == null) {
+ context.errorToast()
+ return
+ }
+ scope.launch {
+ controller.emit(EditOp.CropImage(rect))
+ toolbarVisible = false
+ delay(AnimUtils.TOOLBAR_COLLAPSE_ANIM_DURATION_FAST.toLong())
+ onExit()
+ }
+ }
+
+ Box(Modifier.fillMaxSize()) {
+ TopToolbar(
+ modifier = Modifier
+ .align(Alignment.TopCenter)
+ .fillMaxWidth(),
+ visible = toolbarVisible,
+ height = topToolbarHeight,
+ onClose = {
+ scope.launch {
+ toolbarVisible = false
+ delay(TOOLBAR_COLLAPSE_ANIM_DURATION_FAST.toLong())
+ onExit()
+ }
+ },
+ onDone = {
+ val rect = cropView?.cropRect
+ emitCropAndExit(rect)
+ }
+ )
+
+ BottomToolbar(
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .fillMaxWidth(),
+ visible = toolbarVisible,
+ height = bottomToolbarHeight,
+ cropperOptionsList = cropperOptionsList,
+ selectedCropOptionIndex = selectedCropOptionIndex,
+ onCropOptionItemClicked = { position, cropOption ->
+ selectedCropOptionIndex = position
+ when (cropOption.aspectRatioX) {
+ -1f -> {
+ cropImageOptions = cropImageOptions.copy(
+ fixAspectRatio = false,
+ aspectRatioX = 1,
+ aspectRatioY = 1
+ )
+ }
+ -2f -> {
+ showCropRatioDialog = true
+ }
+ else -> {
+ cropImageOptions = cropImageOptions.copy(
+ fixAspectRatio = true,
+ aspectRatioX = cropOption.aspectRatioX.toInt(),
+ aspectRatioY = cropOption.aspectRatioY.toInt()
+ )
+ }
+ }
+ }
+ )
+
+ Box(
+ Modifier
+ .fillMaxSize()
+ .padding(top = topToolbarHeight, bottom = bottomToolbarHeight)
+ ) {
+ AndroidView(
+ modifier = Modifier.fillMaxSize(),
+ factory = { context ->
+
+ // 1) Stable container the compose world will measure/layout
+ val container = android.widget.FrameLayout(context).apply {
+ layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ clipToPadding = false
+ }
+
+ // 2) The self-mutating library with its own onLayout()
+ // which triggers compose's measure causing recurring calls and ANR
+ // Adding this inside the stable container fixes the recurring calls and ANR
+ val mCropView = CropImageView(context).apply {
+ layoutParams = ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ when (val img = state.snapshot.image) {
+ is EditImage.FromBitmap -> setImageBitmap(img.bitmap)
+ is EditImage.FromUri -> setImageUriAsync(img.uri)
+ }
+ setImageCropOptions(cropImageOptions)
+ }
+
+ container.addView(mCropView)
+ cropView = mCropView
+ container
+ },
+ update = { container ->
+ val mCropView = cropView ?: return@AndroidView
+ mCropView.setImageCropOptions(cropImageOptions)
+ }
+ )
+ }
+
+ AnimatedVisibility(
+ visible = showCropRatioDialog,
+ ) {
+ AspectRatioDialog(
+ onDismiss = { showCropRatioDialog = false },
+ onSetRatio = { x, y ->
+ context.toast("x = $x, y = $x. r = ${x.toFloat() / y.toFloat()}")
+ selectedCropOptionIndex = cropperOptionsList.indexOfFirst { it.aspectRatioX == -2f }
+ cropImageOptions = cropImageOptions.copy(
+ fixAspectRatio = true,
+ aspectRatioX = x,
+ aspectRatioY = y
+ )
+ showCropRatioDialog = false
+ }
+ )
+ }
+ }
+
+}
+
+@Composable
+private fun TopToolbar(
+ modifier: Modifier = Modifier,
+ visible: Boolean,
+ height: Dp,
+ onClose: () -> Unit,
+ onDone: () -> Unit
+) {
+ AnimatedToolbarContainer(
+ toolbarVisible = visible,
+ modifier = modifier
+ ) {
+ Surface(tonalElevation = 2.dp) {
+ Row(
+ Modifier
+ .height(height)
+ .fillMaxSize()
+ .background(ToolBarBackgroundColor)
+ .padding(horizontal = 8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ IconButton(
+ onClick = { onClose() },
+ enabled = true
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.Default.Close,
+ contentDescription = "Close",
+ )
+ }
+ Text(
+ text = "Crop",
+ style = MaterialTheme.typography.titleMedium
+ )
+ IconButton(
+ onClick = { onDone() },
+ enabled = true
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.Default.Check,
+ contentDescription = "Done",
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun BottomToolbar(
+ modifier: Modifier = Modifier,
+ visible: Boolean,
+ height: Dp,
+ cropperOptionsList: List,
+ selectedCropOptionIndex: Int,
+ onCropOptionItemClicked: (pos: Int, option: CropperOption) -> Unit,
+) {
+ AnimatedToolbarContainer(
+ toolbarVisible = visible,
+ modifier = modifier
+ ) {
+ Surface(tonalElevation = 3.dp) {
+ CropperOptionsFullWidth(
+ modifier = Modifier,
+ toolbarHeight = height,
+ cropperOptionList = cropperOptionsList,
+ selectedIndex = selectedCropOptionIndex,
+ onItemClicked = onCropOptionItemClicked
+ )
+ }
+ }
+}
+
+
+@Preview @Composable
+private fun PreviewTopToolbar() {
+ QuickEditTheme {
+ TopToolbar(
+ visible = true,
+ height = topToolbarHeight,
+ onClose = {},
+ onDone = {}
+ )
+ }
+}
+
+@Preview @Composable
+private fun PreviewBottomToolbar() {
+ QuickEditTheme {
+ BottomToolbar(
+ visible = true,
+ height = bottomToolbarHeight,
+ cropperOptionsList = CropModeUtils.getCropperOptionsList(),
+ selectedCropOptionIndex = 0,
+ onCropOptionItemClicked = {_, _ -> }
+ )
+ }
+}
+
+@Preview @Composable
+private fun PreviewCropToolScreen() {
+ QuickEditTheme {
+ CropToolScreen(
+ state = PreviewUtils.getDummyEditorState(),
+ controller = PreviewUtils.getDummyToolController(),
+ onExit = {}
+ )
+ }
+}
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOptionsFullWidth.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropperOptionsFullWidth.kt
similarity index 78%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOptionsFullWidth.kt
rename to quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropperOptionsFullWidth.kt
index 47ea5de..d1f47b7 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOptionsFullWidth.kt
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/CropperOptionsFullWidth.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.ui.cropMode.cropperOptions
+package io.github.abizerr.quickedit.tool.crop
import android.content.res.Configuration
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -7,6 +7,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -16,6 +17,9 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Crop
+import androidx.compose.material.icons.filled.CropFree
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -31,18 +35,19 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_LARGE
-import com.abizer_r.quickedit.utils.defaultTextColor
-import com.abizer_r.quickedit.utils.editorScreen.CropModeUtils
+import io.github.abizerr.quickedit.tool.crop.model.CropperOption
+import io.github.abizerr.quickedit.tool.crop.utils.CropModeUtils
+import io.github.abizerr.quickedit.ui.common.TOOLBAR_HEIGHT_LARGE
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CropperOptionsFullWidth(
modifier: Modifier = Modifier,
toolbarHeight: Dp = TOOLBAR_HEIGHT_LARGE,
- cropperOptionList: ArrayList,
+ cropperOptionList: List,
selectedIndex: Int,
onItemClicked: (position: Int, effectItem: CropperOption) -> Unit
) {
@@ -51,8 +56,10 @@ fun CropperOptionsFullWidth(
modifier = modifier
.fillMaxWidth()
.height(toolbarHeight)
+ .background(ToolBarBackgroundColor)
.padding(vertical = 8.dp),
- verticalAlignment = Alignment.CenterVertically
+ verticalAlignment = Alignment.CenterVertically,
+ contentPadding = PaddingValues(horizontal = 16.dp)
) {
items(
count = cropperOptionList.size,
@@ -93,7 +100,7 @@ fun CropperOptionView(
.background(color = borderColor)
.padding(selectedBorderWidth)
.clip(clipShape)
- .background(MaterialTheme.colorScheme.background)
+ .background(ToolBarBackgroundColor)
.padding(4.dp)
.clickable {
onClick(cropperOption)
@@ -111,8 +118,9 @@ fun CropperOptionView(
if (cropperOption.aspectRatioX == -1f) {
Image(
modifier = Modifier.fillMaxSize(),
- imageVector = ImageVector.vectorResource(id = com.abizer_r.quickedit.R.drawable.baseline_crop_free_24),
- contentDescription = null,
+ imageVector = Icons.Default.CropFree,
+// imageVector = ImageVector.vectorResource(id = com.abizer_r.quickedit.R.drawable.baseline_crop_free_24),
+ contentDescription = "Free Aspect Ratio",
colorFilter = ColorFilter.tint(
color = MaterialTheme.colorScheme.onBackground
)
@@ -120,8 +128,9 @@ fun CropperOptionView(
} else if (cropperOption.aspectRatioX == -2f) {
Image(
modifier = Modifier.fillMaxSize(),
- imageVector = ImageVector.vectorResource(id = com.abizer_r.quickedit.R.drawable.ic_crop),
- contentDescription = null,
+ imageVector = Icons.Default.Crop,
+// imageVector = ImageVector.vectorResource(id = com.abizer_r.quickedit.R.drawable.ic_crop),
+ contentDescription = "Custom Aspect Ratio",
colorFilter = ColorFilter.tint(
color = MaterialTheme.colorScheme.onBackground
)
@@ -155,9 +164,9 @@ fun CropperOptionView(
}
-@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Preview
@Composable
-fun Selected_EffectPreviewItem() {
+private fun Selected_EffectPreviewItem() {
QuickEditTheme {
CropperOptionView(
modifier = Modifier.padding(8.dp),
@@ -172,9 +181,9 @@ fun Selected_EffectPreviewItem() {
}
}
-@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Preview
@Composable
-fun Unselected_EffectPreviewItem() {
+private fun Unselected_EffectPreviewItem() {
QuickEditTheme {
CropperOptionView(
modifier = Modifier.padding(8.dp),
@@ -190,13 +199,12 @@ fun Unselected_EffectPreviewItem() {
}
-@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Preview
@Composable
-fun Preview_EffectsPreviewList() {
+private fun Preview_EffectsPreviewList() {
QuickEditTheme {
CropperOptionsFullWidth(
- modifier = Modifier
- .background(ToolBarBackgroundColor)
+ modifier = Modifier.background(ToolBarBackgroundColor)
.padding(vertical = 12.dp),
cropperOptionList = CropModeUtils.getCropperOptionsList(),
selectedIndex = 0,
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOption.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/model/CropperOption.kt
similarity index 67%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOption.kt
rename to quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/model/CropperOption.kt
index 09758bb..3d358ff 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/cropperOptions/CropperOption.kt
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/model/CropperOption.kt
@@ -1,6 +1,5 @@
-package com.abizer_r.quickedit.ui.cropMode.cropperOptions
+package io.github.abizerr.quickedit.tool.crop.model
-import android.graphics.Bitmap
import java.util.UUID
data class CropperOption(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/cropMode/CropModeUtils.kt b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/utils/CropModeUtils.kt
similarity index 90%
rename from quickedit/src/main/java/com/abizer_r/quickedit/utils/cropMode/CropModeUtils.kt
rename to quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/utils/CropModeUtils.kt
index edea4bb..7fba93f 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/cropMode/CropModeUtils.kt
+++ b/quickedit-tool-crop/src/main/java/io/github/abizerr/quickedit/tool/crop/utils/CropModeUtils.kt
@@ -1,6 +1,6 @@
-package com.abizer_r.quickedit.utils.editorScreen
+package io.github.abizerr.quickedit.tool.crop.utils
-import com.abizer_r.quickedit.ui.cropMode.cropperOptions.CropperOption
+import io.github.abizerr.quickedit.tool.crop.model.CropperOption
object CropModeUtils {
diff --git a/quickedit-tool-crop/src/main/res/values/strings.xml b/quickedit-tool-crop/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9467dbf
--- /dev/null
+++ b/quickedit-tool-crop/src/main/res/values/strings.xml
@@ -0,0 +1,11 @@
+
+
+ Enter Aspect Ratio
+ X
+ Y
+ Select
+ Not a valid number
+ Fields cannot be empty
+ Ratio is lesser than minimum allowed
+ Ratio is greater than maximum allowed
+
\ No newline at end of file
diff --git a/quickedit-tool-crop/src/test/java/io/github/abizerr/quickedit/tool/crop/ExampleUnitTest.kt b/quickedit-tool-crop/src/test/java/io/github/abizerr/quickedit/tool/crop/ExampleUnitTest.kt
new file mode 100644
index 0000000..290e05b
--- /dev/null
+++ b/quickedit-tool-crop/src/test/java/io/github/abizerr/quickedit/tool/crop/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.tool.crop
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/.gitignore b/quickedit-tool-draw/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-tool-draw/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-tool-draw/build.gradle.kts b/quickedit-tool-draw/build.gradle.kts
new file mode 100644
index 0000000..c643bdf
--- /dev/null
+++ b/quickedit-tool-draw/build.gradle.kts
@@ -0,0 +1,55 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.tool.draw"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+ implementation(project(":quickedit-ui"))
+
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+ implementation(libs.androidx.compose.material.icons.extended)
+
+ implementation(libs.colorpicker)
+ implementation(libs.compose.screenshot)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/consumer-rules.pro b/quickedit-tool-draw/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-tool-draw/proguard-rules.pro b/quickedit-tool-draw/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-tool-draw/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/androidTest/java/io/github/abizerr/quickedit/tool/draw/ExampleInstrumentedTest.kt b/quickedit-tool-draw/src/androidTest/java/io/github/abizerr/quickedit/tool/draw/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..2ff20ba
--- /dev/null
+++ b/quickedit-tool-draw/src/androidTest/java/io/github/abizerr/quickedit/tool/draw/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.tool.draw
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.tool.draw.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/AndroidManifest.xml b/quickedit-tool-draw/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..582c8f4
--- /dev/null
+++ b/quickedit-tool-draw/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolContribution.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolContribution.kt
new file mode 100644
index 0000000..7d3d150
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolContribution.kt
@@ -0,0 +1,33 @@
+package io.github.abizerr.quickedit.tool.draw
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Brush
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolContribution
+import io.github.abizerr.quickedit.ui.api.ToolContributionWithFactory
+import io.github.abizerr.quickedit.ui.api.ToolController
+import io.github.abizerr.quickedit.ui.api.ToolFactory
+
+class DrawToolContribution : ToolContributionWithFactory {
+ override val id: String = "draw"
+ override val factory: ToolFactory get() = DrawToolFactory()
+ override val label: String = "Draw"
+ override val supportsFullScreen: Boolean get() = true
+
+ @Composable
+ override fun ToolbarIcon(selected: Boolean, onClick: () -> Unit) {
+ IconWithLabel(
+ selected = selected,
+ imageVector = Icons.Outlined.Brush,
+ labelText = label,
+ onClick = onClick
+ )
+ }
+
+ @Composable
+ override fun Panel(state: QuickEditState, controller: ToolController) {
+ Text("Draw tool placeholder")
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolFactory.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolFactory.kt
new file mode 100644
index 0000000..fe6f00f
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/DrawToolFactory.kt
@@ -0,0 +1,10 @@
+package io.github.abizerr.quickedit.tool.draw
+
+import io.github.abizerr.quickedit.tool.draw.session.DrawToolSession
+import io.github.abizerr.quickedit.ui.api.ToolFactory
+import io.github.abizerr.quickedit.ui.api.ToolParams
+import io.github.abizerr.quickedit.ui.api.ToolSession
+
+class DrawToolFactory: ToolFactory {
+ override fun create(params: ToolParams): ToolSession = DrawToolSession()
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/DrawToolItem.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/DrawToolItem.kt
new file mode 100644
index 0000000..58bd2ac
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/DrawToolItem.kt
@@ -0,0 +1,131 @@
+package io.github.abizerr.quickedit.tool.draw.models
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+import io.github.abizerr.quickedit.tool.draw.models.shapes.BaseShape
+import io.github.abizerr.quickedit.tool.draw.models.shapes.BrushShape
+import io.github.abizerr.quickedit.tool.draw.models.shapes.LineShape
+import io.github.abizerr.quickedit.tool.draw.models.shapes.OvalShape
+import io.github.abizerr.quickedit.tool.draw.models.shapes.RectangleShape
+
+sealed class DrawToolItem {
+ object NONE: DrawToolItem()
+ object ColorItem : DrawToolItem()
+ object PanItem : DrawToolItem()
+ class BrushTool(var width: Float, var opacity: Float) : DrawToolItem()
+ class ShapeTool(var width: Float, var opacity: Float, var shapeType: ShapeType) :
+ DrawToolItem()
+ class EraserTool(var width: Float) : DrawToolItem()
+}
+
+fun DrawToolItem.getShape(
+ selectedColor: Color,
+ scale: Float = 1f,
+): BaseShape? {
+ return when (val toolbarItem = this) {
+ is DrawToolItem.BrushTool -> {
+ BrushShape(
+ shapeSpec = ShapeSpec.Brush(
+ argb = selectedColor.toArgb(),
+ widthPx = toolbarItem.width / scale,
+ alpha = toolbarItem.opacity / 100f
+ )
+ )
+ }
+
+ is DrawToolItem.EraserTool -> {
+ BrushShape(
+ shapeSpec = ShapeSpec.Brush(
+ argb = selectedColor.toArgb(),
+ widthPx = toolbarItem.width / scale,
+ alpha = 1f,
+ isEraser = true
+ )
+ )
+ }
+
+ is DrawToolItem.ShapeTool -> when (toolbarItem.shapeType) {
+ ShapeType.LINE -> LineShape(
+ shapeSpec = ShapeSpec.Shape(
+ shapeType = ShapeType.LINE,
+ argb = selectedColor.toArgb(),
+ widthPx = toolbarItem.width / scale,
+ alpha = toolbarItem.opacity / 100f
+ )
+ )
+
+ ShapeType.OVAL -> OvalShape(
+ shapeSpec = ShapeSpec.Shape(
+ shapeType = ShapeType.OVAL,
+ argb = selectedColor.toArgb(),
+ widthPx = toolbarItem.width / scale,
+ alpha = toolbarItem.opacity / 100f
+ )
+ )
+
+ ShapeType.RECTANGLE -> RectangleShape(
+ shapeSpec = ShapeSpec.Shape(
+ shapeType = ShapeType.RECTANGLE,
+ argb = selectedColor.toArgb(),
+ widthPx = toolbarItem.width / scale,
+ alpha = toolbarItem.opacity / 100f
+ )
+ )
+ }
+
+ else -> null
+ }
+}
+
+fun DrawToolItem.getWidthOrNull(): Float? {
+ return when (this) {
+ is DrawToolItem.BrushTool -> this.width
+ is DrawToolItem.EraserTool -> this.width
+ is DrawToolItem.ShapeTool -> this.width
+ else -> null
+ }
+}
+
+fun DrawToolItem.setWidthIfPossible(mWidth: Float): DrawToolItem {
+ when (this) {
+ is DrawToolItem.BrushTool -> this.width = mWidth
+ is DrawToolItem.EraserTool -> this.width = mWidth
+ is DrawToolItem.ShapeTool -> this.width = mWidth
+ else -> {}
+ }
+ return this
+}
+
+fun DrawToolItem.getOpacityOrNull(): Float? {
+ return when (this) {
+ is DrawToolItem.BrushTool -> this.opacity
+ is DrawToolItem.ShapeTool -> this.opacity
+ else -> null
+ }
+}
+
+fun DrawToolItem.setOpacityIfPossible(mOpacity: Float): DrawToolItem {
+ when (this) {
+ is DrawToolItem.BrushTool -> this.opacity = mOpacity
+ is DrawToolItem.ShapeTool -> this.opacity = mOpacity
+ else -> {}
+ }
+ return this
+}
+
+fun DrawToolItem.getShapeTypeOrNull(): ShapeType? {
+ return when (this) {
+ is DrawToolItem.ShapeTool -> this.shapeType
+ else -> null
+ }
+}
+
+fun DrawToolItem.setShapeTypeIfPossible(mShapeType: ShapeType): DrawToolItem {
+ when (this) {
+ is DrawToolItem.ShapeTool -> this.shapeType = mShapeType
+ else -> {}
+ }
+ return this
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/PathDetails.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/PathDetails.kt
new file mode 100644
index 0000000..f183cd8
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/PathDetails.kt
@@ -0,0 +1,7 @@
+package io.github.abizerr.quickedit.tool.draw.models
+
+import io.github.abizerr.quickedit.tool.draw.models.shapes.BaseShape
+
+data class PathDetails(
+ val drawingShape: BaseShape,
+)
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/AbstractShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/AbstractShape.kt
new file mode 100644
index 0000000..1f5c4ca
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/AbstractShape.kt
@@ -0,0 +1,13 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import androidx.compose.ui.graphics.Color
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.tool.draw.util.DrawingConstants
+
+abstract class AbstractShape: BaseShape {
+ abstract var shapeSpec: ShapeSpec
+// var mColor: Color = Color.White
+// var mWidth: Float = DrawingConstants.DEFAULT_STROKE_WIDTH
+// var mAlpha: Float = DrawingConstants.DEFAULT_STROKE_ALPHA
+
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BaseShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BaseShape.kt
new file mode 100644
index 0000000..efbb47f
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BaseShape.kt
@@ -0,0 +1,10 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import android.graphics.Canvas
+
+interface BaseShape {
+ fun drawOnAndroidCanvas(canvas: Canvas)
+ fun initShape(startX: Float, startY: Float)
+ fun moveShape(endX: Float, endY: Float)
+ fun shouldDraw(): Boolean
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BrushShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BrushShape.kt
new file mode 100644
index 0000000..ce49c99
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/BrushShape.kt
@@ -0,0 +1,31 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+import io.github.abizerr.quickedit.engine.util.applySpec
+import io.github.abizerr.quickedit.engine.util.drawOn
+
+class BrushShape(
+ private val shapeSpec: ShapeSpec.Brush
+): BaseShape {
+
+ override fun drawOnAndroidCanvas(canvas: Canvas) {
+ val paintSpec = shapeSpec.toPaintSpec()
+ val paint = Paint().applySpec(paintSpec)
+ shapeSpec.drawOn(canvas, paint)
+ }
+
+ override fun initShape(startX: Float, startY: Float) {
+ shapeSpec.points.add(Pair(startX, startY))
+ }
+
+ override fun moveShape(endX: Float, endY: Float) {
+ shapeSpec.points.add(Pair(endX, endY))
+ }
+
+ override fun shouldDraw(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/LineShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/LineShape.kt
new file mode 100644
index 0000000..1726924
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/LineShape.kt
@@ -0,0 +1,32 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+import io.github.abizerr.quickedit.engine.util.applySpec
+import io.github.abizerr.quickedit.engine.util.drawOn
+
+class LineShape(
+ private val shapeSpec: ShapeSpec.Shape
+) : BaseShape {
+
+ override fun drawOnAndroidCanvas(canvas: Canvas) {
+ val paintSpec = shapeSpec.toPaintSpec()
+ val paint = Paint().applySpec(paintSpec)
+ shapeSpec.drawOn(canvas, paint)
+ }
+
+ override fun initShape(startX: Float, startY: Float) {
+ shapeSpec.startOffset = Pair(startX, startY)
+ }
+
+ override fun moveShape(endX: Float, endY: Float) {
+ shapeSpec.endOffset = Pair(endX, endY)
+ }
+
+ override fun shouldDraw(): Boolean {
+ return shapeSpec.startOffset != ShapeSpec.defaultOffset
+ && shapeSpec.endOffset != ShapeSpec.defaultOffset
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/OvalShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/OvalShape.kt
new file mode 100644
index 0000000..5568a2f
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/OvalShape.kt
@@ -0,0 +1,32 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+import io.github.abizerr.quickedit.engine.util.applySpec
+import io.github.abizerr.quickedit.engine.util.drawOn
+
+class OvalShape(
+ private val shapeSpec: ShapeSpec.Shape
+) : BaseShape {
+
+ override fun drawOnAndroidCanvas(canvas: Canvas) {
+ val paintSpec = shapeSpec.toPaintSpec()
+ val paint = Paint().applySpec(paintSpec)
+ shapeSpec.drawOn(canvas, paint)
+ }
+
+ override fun initShape(startX: Float, startY: Float) {
+ shapeSpec.startOffset = Pair(startX, startY)
+ }
+
+ override fun moveShape(endX: Float, endY: Float) {
+ shapeSpec.endOffset = Pair(endX, endY)
+ }
+
+ override fun shouldDraw(): Boolean {
+ return shapeSpec.startOffset != ShapeSpec.defaultOffset
+ && shapeSpec.endOffset != ShapeSpec.defaultOffset
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/RectangleShape.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/RectangleShape.kt
new file mode 100644
index 0000000..498c692
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/models/shapes/RectangleShape.kt
@@ -0,0 +1,33 @@
+package io.github.abizerr.quickedit.tool.draw.models.shapes
+
+import android.graphics.Canvas
+import android.graphics.Paint
+import io.github.abizerr.quickedit.engine.drawspec.ShapeSpec
+import io.github.abizerr.quickedit.engine.drawspec.toPaintSpec
+import io.github.abizerr.quickedit.engine.util.applySpec
+import io.github.abizerr.quickedit.engine.util.drawOn
+
+class RectangleShape(
+ private val shapeSpec: ShapeSpec.Shape
+): BaseShape {
+
+
+ override fun drawOnAndroidCanvas(canvas: Canvas) {
+ val paintSpec = shapeSpec.toPaintSpec()
+ val paint = Paint().applySpec(paintSpec)
+ shapeSpec.drawOn(canvas, paint)
+ }
+
+ override fun initShape(startX: Float, startY: Float) {
+ shapeSpec.startOffset = Pair(startX, startY)
+ }
+
+ override fun moveShape(endX: Float, endY: Float) {
+ shapeSpec.endOffset = Pair(endX, endY)
+ }
+
+ override fun shouldDraw(): Boolean {
+ return shapeSpec.startOffset != ShapeSpec.defaultOffset
+ && shapeSpec.endOffset != ShapeSpec.defaultOffset
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/session/DrawToolSession.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/session/DrawToolSession.kt
new file mode 100644
index 0000000..fa637fd
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/session/DrawToolSession.kt
@@ -0,0 +1,51 @@
+package io.github.abizerr.quickedit.tool.draw.session
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import io.github.abizerr.quickedit.ui.api.ToolController
+import io.github.abizerr.quickedit.ui.api.ToolHost
+import io.github.abizerr.quickedit.ui.api.ToolSession
+
+internal class DrawToolSession : ToolSession {
+ override val id: String get() = "draw"
+
+ @OptIn(ExperimentalMaterial3Api::class)
+ @Composable
+ override fun Ui(host: ToolHost, controller: ToolController, onExit: () -> Unit) {
+ // Ask shell for exclusive gestures while this full-screen tool is active
+
+ // Placeholder
+ Surface(modifier = Modifier.Companion.fillMaxSize()) {
+ Column(Modifier.Companion.fillMaxSize()) {
+ TopAppBar(
+ title = { Text("Draw (stub)") },
+ actions = {
+ TextButton(onClick = onExit) { Text("Done") }
+ }
+ )
+ Box(
+ modifier = Modifier.Companion
+ .fillMaxSize()
+ .padding(16.dp)
+ .background(MaterialTheme.colorScheme.surfaceVariant),
+ contentAlignment = Alignment.Companion.Center
+ ) {
+ Text("Canvas placeholder — wiring test")
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeEvent.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeEvent.kt
new file mode 100644
index 0000000..289e0ad
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeEvent.kt
@@ -0,0 +1,18 @@
+package io.github.abizerr.quickedit.tool.draw.ui
+
+import androidx.compose.ui.graphics.Color
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.models.PathDetails
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+
+sealed class DrawModeEvent {
+ data class AddNewPath(val pathDetail: PathDetails): DrawModeEvent()
+ data class ToggleColorPicker(val selectedColor: Color?): DrawModeEvent()
+ data class UpdateToolbarExtensionVisibility(val isVisible: Boolean): DrawModeEvent()
+ object OnUndo: DrawModeEvent()
+ object OnRedo: DrawModeEvent()
+ data class OnToolbarItemClicked(val toolbarItem: DrawToolItem): DrawModeEvent()
+ data class UpdateWidth(val newWidth: Float): DrawModeEvent()
+ data class UpdateOpacity(val newOpacity: Float): DrawModeEvent()
+ data class UpdateShapeType(val newShapeType: ShapeType): DrawModeEvent()
+}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeState.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeState.kt
similarity index 50%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeState.kt
rename to quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeState.kt
index 057fef4..6b70d5c 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeState.kt
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/DrawModeState.kt
@@ -1,14 +1,14 @@
-package com.abizer_r.quickedit.ui.drawMode.stateHandling
+package io.github.abizerr.quickedit.tool.draw.ui
import androidx.compose.ui.graphics.Color
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.models.PathDetails
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.models.PathDetails
import java.util.Stack
data class DrawModeState(
val showColorPicker: Boolean = false,
- val selectedColor: Color = Color.White,
- val selectedTool: BottomToolbarItem = BottomToolbarItem.NONE,
+ val selectedColor: Color = Color.Companion.White,
+ val selectedTool: DrawToolItem = DrawToolItem.NONE,
val showBottomToolbarExtension: Boolean = false,
val pathDetailStack: Stack = Stack(),
val redoStack: Stack = Stack(),
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvas.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/drawingCanvas/DrawingCanvas.kt
similarity index 64%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvas.kt
rename to quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/drawingCanvas/DrawingCanvas.kt
index a8769ae..2b1f552 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvas.kt
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/ui/drawingCanvas/DrawingCanvas.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas
+package io.github.abizerr.quickedit.tool.draw.ui.drawingCanvas
import android.util.Log
import android.view.MotionEvent
@@ -14,22 +14,17 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.input.pointer.pointerInteropFilter
-import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.platform.LocalConfiguration
-import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeEvent
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.AbstractShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.models.PathDetails
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
-import com.abizer_r.quickedit.utils.drawMode.getShape
-import com.abizer_r.quickedit.utils.drawMode.toPx
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.models.PathDetails
+import io.github.abizerr.quickedit.tool.draw.models.getShape
+import io.github.abizerr.quickedit.tool.draw.models.shapes.BaseShape
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeEvent
import java.util.Stack
-import kotlin.math.abs
@OptIn(ExperimentalComposeUiApi::class)
@Composable
@@ -37,7 +32,7 @@ fun DrawingCanvas(
modifier: Modifier = Modifier,
pathDetailStack: Stack,
selectedColor: Color,
- currentTool: BottomToolbarItem,
+ currentTool: DrawToolItem,
scale: Float,
onDrawingEvent: (DrawModeEvent) -> Unit,
transformableState: TransformableState,
@@ -49,7 +44,7 @@ fun DrawingCanvas(
* And when these are changed, the draw phase is called (compose has 3 phases: composition, layout and draw)
* SO, Recomposition isn't triggered
*/
- var currentShape: AbstractShape? = null
+ var currentShape: BaseShape? = null
var drawPhaseTrigger by remember { mutableDoubleStateOf(0.0) }
var canvasModifier = modifier
@@ -60,16 +55,19 @@ fun DrawingCanvas(
translationY = offset.y
)
- if (currentTool is BottomToolbarItem.PanItem) {
+ if (currentTool is DrawToolItem.PanItem) {
canvasModifier = canvasModifier
.transformable(transformableState)
} else {
canvasModifier = canvasModifier
- .pointerInteropFilter {
+ .pointerInteropFilter { it ->
val adjustedX = it.x / scale
val adjustedY = it.y / scale
- Log.i("TEST_pan", "Drag: scale = $scale, actualPos = (${it.x}, ${it.y}), adjustedPos = ($adjustedX, $adjustedY)", )
+ Log.i(
+ "TEST_pan",
+ "Drag: scale = $scale, actualPos = (${it.x}, ${it.y}), adjustedPos = ($adjustedX, $adjustedY)",
+ )
when (it.action) {
MotionEvent.ACTION_DOWN -> {
@@ -89,15 +87,15 @@ fun DrawingCanvas(
MotionEvent.ACTION_CANCEL,
MotionEvent.ACTION_UP -> {
- if (currentShape != null && currentShape!!.shouldDraw()) {
- onDrawingEvent(
- DrawModeEvent.AddNewPath(
- pathDetail = PathDetails(
- drawingShape = currentShape!!,
+ currentShape
+ ?.takeIf { shape -> shape.shouldDraw() }
+ ?.let { shape ->
+ onDrawingEvent(
+ DrawModeEvent.AddNewPath(
+ pathDetail = PathDetails(drawingShape = shape)
)
)
- )
- }
+ }
}
}
true
@@ -109,15 +107,20 @@ fun DrawingCanvas(
modifier = canvasModifier.clipToBounds()
) {
pathDetailStack.forEach { pathDetails ->
- Log.e("TEST", "DrawingCanvas: drawing from stack. drawingShape = ${pathDetails.drawingShape}", )
- pathDetails.drawingShape.draw(
- drawScope = this,
+ Log.e(
+ "TEST",
+ "DrawingCanvas: drawing from stack. drawingShape = ${pathDetails.drawingShape}",
)
+ drawIntoCanvas { composeCanvas ->
+ pathDetails.drawingShape.drawOnAndroidCanvas(composeCanvas.nativeCanvas)
+ }
}
- Log.e("TEST", "DrawingCanvas: done \n\n\n", )
+ Log.e("TEST", "DrawingCanvas: done \n\n\n")
if (drawPhaseTrigger > 0) {
- currentShape?.draw(drawScope = this)
+ drawIntoCanvas { composeCanvas ->
+ currentShape?.drawOnAndroidCanvas(composeCanvas.nativeCanvas)
+ }
}
}
}
diff --git a/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawToolUtil.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawToolUtil.kt
new file mode 100644
index 0000000..d0dfe8b
--- /dev/null
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawToolUtil.kt
@@ -0,0 +1,4 @@
+package io.github.abizerr.quickedit.tool.draw.util
+
+object DrawToolUtil {
+}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawingConstants.kt b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawingConstants.kt
similarity index 83%
rename from quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawingConstants.kt
rename to quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawingConstants.kt
index d7c0530..512a094 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawingConstants.kt
+++ b/quickedit-tool-draw/src/main/java/io/github/abizerr/quickedit/tool/draw/util/DrawingConstants.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.utils.drawMode
+package io.github.abizerr.quickedit.tool.draw.util
object DrawingConstants {
const val DEFAULT_STROKE_WIDTH = 12f
diff --git a/quickedit-tool-draw/src/test/java/io/github/abizerr/quickedit/tool/draw/ExampleUnitTest.kt b/quickedit-tool-draw/src/test/java/io/github/abizerr/quickedit/tool/draw/ExampleUnitTest.kt
new file mode 100644
index 0000000..02f7ed7
--- /dev/null
+++ b/quickedit-tool-draw/src/test/java/io/github/abizerr/quickedit/tool/draw/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.tool.draw
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-effects/.gitignore b/quickedit-tool-effects/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-tool-effects/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-tool-effects/build.gradle.kts b/quickedit-tool-effects/build.gradle.kts
new file mode 100644
index 0000000..60cc57a
--- /dev/null
+++ b/quickedit-tool-effects/build.gradle.kts
@@ -0,0 +1,51 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.tool.effects"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+ implementation(project(":quickedit-ui"))
+
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/quickedit-tool-effects/consumer-rules.pro b/quickedit-tool-effects/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-tool-effects/proguard-rules.pro b/quickedit-tool-effects/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-tool-effects/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-tool-effects/src/androidTest/java/io/github/abizerr/quickedit/tool/effects/ExampleInstrumentedTest.kt b/quickedit-tool-effects/src/androidTest/java/io/github/abizerr/quickedit/tool/effects/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..41d61cf
--- /dev/null
+++ b/quickedit-tool-effects/src/androidTest/java/io/github/abizerr/quickedit/tool/effects/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.tool.effects
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.tool.effects.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-effects/src/main/AndroidManifest.xml b/quickedit-tool-effects/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..caa0bea
--- /dev/null
+++ b/quickedit-tool-effects/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-tool-effects/src/main/java/io/github/abizerr/quickedit/tool/effects/EffectsContribution.kt b/quickedit-tool-effects/src/main/java/io/github/abizerr/quickedit/tool/effects/EffectsContribution.kt
new file mode 100644
index 0000000..bb55bcd
--- /dev/null
+++ b/quickedit-tool-effects/src/main/java/io/github/abizerr/quickedit/tool/effects/EffectsContribution.kt
@@ -0,0 +1,29 @@
+package io.github.abizerr.quickedit.tool.effects
+
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolContribution
+import io.github.abizerr.quickedit.ui.api.ToolController
+
+class EffectsContribution : ToolContribution {
+ override val id: String = "effects"
+ override val label: String = "Effects"
+
+ @Composable
+ override fun ToolbarIcon(selected: Boolean, onClick: () -> Unit) {
+ IconWithLabel(
+ selected = selected,
+ imageVector = ImageVector.vectorResource(id = R.drawable.ic_effects),
+ labelText = label,
+ onClick = onClick
+ )
+ }
+
+ @Composable
+ override fun Panel(state: QuickEditState, controller: ToolController) {
+ Text("Effects tool placeholder")
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-effects/src/main/res/drawable/ic_effects.xml b/quickedit-tool-effects/src/main/res/drawable/ic_effects.xml
new file mode 100644
index 0000000..131ae56
--- /dev/null
+++ b/quickedit-tool-effects/src/main/res/drawable/ic_effects.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-tool-effects/src/test/java/io/github/abizerr/quickedit/tool/effects/ExampleUnitTest.kt b/quickedit-tool-effects/src/test/java/io/github/abizerr/quickedit/tool/effects/ExampleUnitTest.kt
new file mode 100644
index 0000000..6cbf705
--- /dev/null
+++ b/quickedit-tool-effects/src/test/java/io/github/abizerr/quickedit/tool/effects/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.tool.effects
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-text/.gitignore b/quickedit-tool-text/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-tool-text/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-tool-text/build.gradle.kts b/quickedit-tool-text/build.gradle.kts
new file mode 100644
index 0000000..73b13b3
--- /dev/null
+++ b/quickedit-tool-text/build.gradle.kts
@@ -0,0 +1,52 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.tool.text"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+ implementation(project(":quickedit-ui"))
+
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ debugImplementation(libs.androidx.compose.ui.tooling)
+ implementation(libs.androidx.compose.material.icons.extended)
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/quickedit-tool-text/consumer-rules.pro b/quickedit-tool-text/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-tool-text/proguard-rules.pro b/quickedit-tool-text/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-tool-text/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-tool-text/src/androidTest/java/io/github/abizerr/quickedit/tool/text/ExampleInstrumentedTest.kt b/quickedit-tool-text/src/androidTest/java/io/github/abizerr/quickedit/tool/text/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..93b27fe
--- /dev/null
+++ b/quickedit-tool-text/src/androidTest/java/io/github/abizerr/quickedit/tool/text/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.tool.text
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.tool.text.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-text/src/main/AndroidManifest.xml b/quickedit-tool-text/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..560d129
--- /dev/null
+++ b/quickedit-tool-text/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-tool-text/src/main/java/io/github/abizerr/quickedit/tool/text/TextContribution.kt b/quickedit-tool-text/src/main/java/io/github/abizerr/quickedit/tool/text/TextContribution.kt
new file mode 100644
index 0000000..9e2e946
--- /dev/null
+++ b/quickedit-tool-text/src/main/java/io/github/abizerr/quickedit/tool/text/TextContribution.kt
@@ -0,0 +1,29 @@
+package io.github.abizerr.quickedit.tool.text
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.TextFields
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolContribution
+import io.github.abizerr.quickedit.ui.api.ToolController
+
+class TextContribution : ToolContribution {
+ override val id: String = "text"
+ override val label: String = "Text"
+
+ @Composable
+ override fun ToolbarIcon(selected: Boolean, onClick: () -> Unit) {
+ IconWithLabel(
+ selected = selected,
+ imageVector = Icons.Default.TextFields,
+ labelText = label,
+ onClick = onClick
+ )
+ }
+
+ @Composable
+ override fun Panel(state: QuickEditState, controller: ToolController) {
+ Text("Text tool placeholder")
+ }
+}
\ No newline at end of file
diff --git a/quickedit-tool-text/src/test/java/io/github/abizerr/quickedit/tool/text/ExampleUnitTest.kt b/quickedit-tool-text/src/test/java/io/github/abizerr/quickedit/tool/text/ExampleUnitTest.kt
new file mode 100644
index 0000000..016ac7e
--- /dev/null
+++ b/quickedit-tool-text/src/test/java/io/github/abizerr/quickedit/tool/text/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.tool.text
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-ui/.gitignore b/quickedit-ui/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/quickedit-ui/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/quickedit-ui/build.gradle.kts b/quickedit-ui/build.gradle.kts
new file mode 100644
index 0000000..acd1630
--- /dev/null
+++ b/quickedit-ui/build.gradle.kts
@@ -0,0 +1,61 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "io.github.abizerr.quickedit.ui"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+}
+
+dependencies {
+ api(project(":quickedit-core-engine"))
+
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.compose.ui)
+ implementation(libs.androidx.compose.material3)
+ implementation(libs.androidx.compose.ui.tooling.preview)
+ implementation(libs.androidx.compose.animation) // for AnimatedContent / transitions
+ debugImplementation(libs.androidx.compose.ui.tooling)
+ implementation(libs.androidx.compose.material.icons.extended)
+
+ implementation(libs.kotlinx.coroutines.android)
+
+ implementation(libs.androidx.constraintlayout.compose)
+
+// implementation(libs.androidx.core.ktx)
+// implementation(libs.androidx.appcompat)
+// implementation(libs.material)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/quickedit-ui/consumer-rules.pro b/quickedit-ui/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/proguard-rules.pro b/quickedit-ui/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/quickedit-ui/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/quickedit-ui/src/androidTest/java/io/github/abizerr/quickedit/ui/ExampleInstrumentedTest.kt b/quickedit-ui/src/androidTest/java/io/github/abizerr/quickedit/ui/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..10c9835
--- /dev/null
+++ b/quickedit-ui/src/androidTest/java/io/github/abizerr/quickedit/ui/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.github.abizerr.quickedit.ui
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.github.abizerr.quickedit.ui.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/quickedit-ui/src/main/AndroidManifest.xml b/quickedit-ui/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7791bb8
--- /dev/null
+++ b/quickedit-ui/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/QuickEditEditor.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/QuickEditEditor.kt
new file mode 100644
index 0000000..6f0efdc
--- /dev/null
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/QuickEditEditor.kt
@@ -0,0 +1,399 @@
+package io.github.abizerr.quickedit.ui.api
+
+import android.content.ContentResolver
+import android.graphics.Bitmap
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.Redo
+import androidx.compose.material.icons.automirrored.filled.Undo
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material.icons.filled.Save
+import androidx.compose.material.icons.filled.SaveAlt
+import androidx.compose.material.icons.filled.Share
+import androidx.compose.material.icons.filled.Undo
+import androidx.compose.material.icons.rounded.Share
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import io.github.abizerr.quickedit.engine.api.EditEngine
+import io.github.abizerr.quickedit.engine.api.EditImage
+import io.github.abizerr.quickedit.engine.api.EditOp
+import io.github.abizerr.quickedit.engine.api.EditSnapshot
+import io.github.abizerr.quickedit.engine.api.EditedImage
+import io.github.abizerr.quickedit.engine.api.SaveFormat
+import io.github.abizerr.quickedit.engine.api.Size
+import io.github.abizerr.quickedit.engine.impl.DefaultEditEngine
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.TOOLBAR_HEIGHT_MEDIUM
+import io.github.abizerr.quickedit.ui.common.TOOLBAR_HEIGHT_SMALL
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.PreviewUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils.TOOLBAR_COLLAPSE_ANIM_DURATION_FAST
+import io.github.abizerr.quickedit.ui.utils.getDummyBitmap
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+data class QuickEditConfig(
+ val tools: List = emptyList(),
+ val maxUndo: Int = 20,
+ val defaultFormat: SaveFormat = SaveFormat.Jpeg(90)
+)
+
+private enum class UiMode { Editor, FullScreenTool }
+
+
+private val topToolbarHeight = TOOLBAR_HEIGHT_SMALL
+private val bottomToolbarHeight = TOOLBAR_HEIGHT_MEDIUM
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun QuickEditEditor(
+ image: EditImage?,
+ config: QuickEditConfig = QuickEditConfig(),
+ engine: EditEngine = rememberEngine(config.maxUndo),
+ onSave: (Result) -> Unit = {}
+) {
+
+ var snapshot by remember { mutableStateOf(null) }
+ var viewport by remember { mutableStateOf(IntSize.Zero) }
+ var preview by remember { mutableStateOf(null) }
+ val scope = rememberCoroutineScope()
+
+ var uiMode by remember { mutableStateOf(UiMode.Editor) }
+ var editorToolbarsVisible by remember { mutableStateOf(true) }
+
+ // Start/replace session when image changes
+ LaunchedEffect(image, engine) {
+ snapshot = image?.let { engine.newSession(it) }
+ }
+
+ // Render when snapshot, viewport or uiMode changes
+ LaunchedEffect(snapshot, viewport, uiMode) {
+ if (uiMode != UiMode.Editor) {
+ preview = null
+ return@LaunchedEffect // skip preview rendering while a tool is active
+ }
+ if (viewport.width <= 0 || viewport.height <= 0) return@LaunchedEffect
+ val renderResult = engine.render(
+ snapshot = snapshot ?: return@LaunchedEffect,
+ size = Size(viewport.width, viewport.height)
+ )
+ preview = renderResult.preview
+ }
+
+ val state = snapshot?.let { QuickEditState(it) }
+
+ // Controller wires to the engine's apply/undo/redo
+ val controller = remember(engine, snapshot) {
+ object : ToolController {
+ override fun emit(op: EditOp) {
+ scope.launch { snapshot = engine.apply(op) }
+ }
+
+ override fun undo() {
+ scope.launch { snapshot = engine.apply(EditOp.Undo) }
+ }
+
+ override fun redo() {
+ scope.launch { snapshot = engine.apply(EditOp.Redo) }
+ }
+
+ }
+ }
+
+ var selectedToolId: String? by remember(config.tools) {
+ mutableStateOf(null)
+ }
+ val selectedTool: ToolContribution? = remember(selectedToolId, config.tools) {
+ config.tools.firstOrNull { it.id == selectedToolId }
+ }
+
+ suspend fun goToTool(toolId: String) {
+ // 1) hide toolbars
+ editorToolbarsVisible = false
+ delay(TOOLBAR_COLLAPSE_ANIM_DURATION_FAST.toLong())
+ // 2) switch to tool
+ selectedToolId = toolId
+ uiMode = UiMode.FullScreenTool
+ }
+
+ suspend fun exitTool() {
+ // 1) exit tool
+ uiMode = UiMode.Editor
+ // 2) show toolbars
+ editorToolbarsVisible = true
+ selectedToolId = null
+ }
+
+ fun saveSnapshot() {
+ snapshot?.let {
+ scope.launch {
+ onSave(engine.save(snapshot!!, config.defaultFormat))
+ }
+ }
+ }
+
+ Box(Modifier.fillMaxSize()) {
+
+ TopToolbar(
+ modifier = Modifier
+ .align(Alignment.TopCenter)
+ .fillMaxWidth(),
+ visible = editorToolbarsVisible,
+ height = topToolbarHeight,
+ engine = engine,
+ controller = controller,
+ saveEnabled = snapshot != null,
+ onSave = { saveSnapshot() }
+ )
+
+ BottomToolbar(
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .fillMaxWidth(),
+ visible = editorToolbarsVisible,
+ height = bottomToolbarHeight,
+ selectedToolId = selectedToolId,
+ tools = config.tools,
+ onToolClicked = { toolId ->
+ scope.launch { goToTool(toolId) }
+ }
+ )
+
+ Box(
+ Modifier
+ .fillMaxSize()
+ .padding(top = topToolbarHeight, bottom = bottomToolbarHeight)
+ .onSizeChanged { viewport = it },
+ contentAlignment = Alignment.Center
+ ) {
+ // Don’t draw the editor preview when a tool is active
+ if (uiMode == UiMode.Editor) {
+ if (preview != null) {
+ Image(bitmap = preview!!.asImageBitmap(), contentDescription = "Preview")
+ } else {
+ Text("Preparing preview…")
+ }
+ }
+ }
+
+ // --- Full-screen tool layer (tool owns its own bars & content) ---
+ if (uiMode == UiMode.FullScreenTool && selectedTool != null && state != null) {
+ selectedTool.FullScreenTool(
+ state = state,
+ controller = controller,
+ onExit = { scope.launch { exitTool() } }
+ )
+ }
+ }
+}
+
+@Composable
+private fun TopToolbar(
+ modifier: Modifier = Modifier,
+ visible: Boolean,
+ height: Dp,
+ engine: EditEngine,
+ controller: ToolController,
+ saveEnabled: Boolean,
+ onSave: () -> Unit
+) {
+ AnimatedToolbarContainer(
+ toolbarVisible = visible,
+ modifier = modifier
+ ) {
+ Surface(tonalElevation = 2.dp) {
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .height(height)
+ .background(ToolBarBackgroundColor),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+
+ // TODO (revamp): handle cancel button
+ IconButton(
+ onClick = { /* onCancel() */ },
+ enabled = false /* cancelEnabled */
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.Default.Close,
+ contentDescription = "Cancel",
+ )
+ }
+
+ Row {
+ IconButton(
+ onClick = { controller.undo() },
+ enabled = engine.history.canUndo
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.AutoMirrored.Default.Undo,
+ contentDescription = "Undo",
+ )
+ }
+
+ IconButton(
+ onClick = { controller.redo() },
+ enabled = engine.history.canRedo
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.AutoMirrored.Default.Redo,
+ contentDescription = "Redo",
+ )
+ }
+ }
+
+
+ IconButton(
+ onClick = { onSave() },
+ enabled = saveEnabled
+ ) {
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = Icons.Default.Save,
+ contentDescription = "Save",
+ )
+ }
+
+ // TODO (revamp): Implement share button (add a shareEnabled boolean in config)
+// IconButton(
+// onClick = { /* onShare() */ },
+// enabled = true
+// ) {
+// Icon(
+// modifier = Modifier.size(28.dp),
+// imageVector = Icons.Default.Share,
+// contentDescription = "Share",
+// )
+// }
+ }
+ }
+ }
+}
+
+@Composable
+private fun BottomToolbar(
+ modifier: Modifier = Modifier,
+ visible: Boolean,
+ height: Dp,
+ selectedToolId: String?,
+ tools: List,
+ onToolClicked: (toolId: String) -> Unit
+) {
+ AnimatedToolbarContainer(
+ toolbarVisible = visible,
+ modifier = modifier
+ ) {
+ Surface(tonalElevation = 3.dp) {
+ Row(
+ modifier = Modifier
+ .height(height)
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ tools.forEach { tool ->
+ // Delegate icon rendering to the tool
+ tool.ToolbarIcon(
+ selected = tool.id == selectedToolId,
+ onClick = { onToolClicked(tool.id) }
+ )
+ }
+ }
+ }
+ }
+}
+
+
+@Composable
+private fun rememberEngine(maxUndo: Int): EditEngine {
+ val resolver: ContentResolver = LocalContext.current.contentResolver
+ return remember(resolver, maxUndo) {
+ DefaultEditEngine(
+ maxUndo = maxUndo,
+ resolver = resolver
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewTopToolbar() {
+ QuickEditTheme {
+ TopToolbar(
+ visible = true,
+ height = topToolbarHeight,
+ engine = DefaultEditEngine(),
+ controller = PreviewUtils.getDummyToolController(),
+ saveEnabled = true,
+ onSave = {}
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun PreviewBottomToolbar() {
+ QuickEditTheme {
+ val tools = PreviewUtils.getDummyTools()
+ BottomToolbar(
+ visible = true,
+ height = bottomToolbarHeight,
+ selectedToolId = tools[0].id,
+ tools = tools,
+ onToolClicked = { toolId -> }
+ )
+ }
+}
+
+@Preview
+@Composable
+private fun Preview() {
+ QuickEditTheme {
+ QuickEditEditor(
+ image = EditImage.FromBitmap(getDummyBitmap()),
+ config = QuickEditConfig(tools = PreviewUtils.getDummyTools()),
+ onSave = {}
+ )
+ }
+}
\ No newline at end of file
diff --git a/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContracts.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContracts.kt
new file mode 100644
index 0000000..a64327f
--- /dev/null
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContracts.kt
@@ -0,0 +1,38 @@
+package io.github.abizerr.quickedit.ui.api
+
+import androidx.compose.runtime.Composable
+import io.github.abizerr.quickedit.engine.api.EditOp
+import io.github.abizerr.quickedit.engine.api.EditSnapshot
+
+interface ToolHost {
+ /** Latest immutable snapshot produced by the engine. */
+ val snapshot: EditSnapshot
+
+ /** Hint the shell to switch to gesture policy (e.g., disable editor pan/zoom */
+ fun requestGestureMode(mode: GestureMode)
+}
+
+enum class GestureMode { EditorGestures, ToolExclusive }
+
+/** A running instance of a tool (state + Composabel UI) */
+interface ToolSession {
+ /** Stable identifier (e.g., "draw", "crop") */
+ val id: String
+
+ /** Tool's full-screen UI; shell passes in host, controller & exit callback */
+ @Composable
+ fun Ui(host: ToolHost, controller: ToolController, onExit: () -> Unit)
+
+ /** Optional: flush pending ops on exit. Kept simple for now. */
+ fun onClose(): List = emptyList()
+}
+
+/** Factory keeps the module boundary DI-free. */
+fun interface ToolFactory {
+ fun create(params: ToolParams): ToolSession
+}
+
+/** Arbitrary inputs supplied by host (e.g., initial brush/ratio) */
+data class ToolParams(
+ val initial: Map = emptyMap()
+)
\ No newline at end of file
diff --git a/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContribution.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContribution.kt
new file mode 100644
index 0000000..8d711ac
--- /dev/null
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/api/ToolContribution.kt
@@ -0,0 +1,139 @@
+package io.github.abizerr.quickedit.ui.api
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.dp
+import io.github.abizerr.quickedit.engine.api.EditOp
+import io.github.abizerr.quickedit.engine.api.EditSnapshot
+
+interface ToolContribution {
+ val id: String
+ val label: String get() = id
+ @Composable
+ fun ToolbarIcon(selected: Boolean, onClick: () -> Unit)
+ @Composable
+ fun Panel(state: QuickEditState, controller: ToolController)
+ /**
+ * FUTURE: Add optional lifecycle hooks without breaking:
+ * fun onAttach() {}
+ * fun onDetach() {}
+ * val requiredOps: Set> get() = emptySet()
+ */
+
+ /** Optional full-screen tool (own top/bottom bars + content). */
+ val supportsFullScreen: Boolean get() = false
+ @Composable
+ fun FullScreenTool(
+ state: QuickEditState,
+ controller: ToolController,
+ onExit: () -> Unit
+ ) { /* default no-op */ }
+
+ @Composable
+ fun Modifier.selectionModifier(selected: Boolean): Modifier {
+ return if (selected.not()) {
+ this
+ .padding(horizontal = 8.dp, vertical = 4.dp)
+ } else {
+ this
+ .clip(RoundedCornerShape(3.dp))
+ .background(MaterialTheme.colorScheme.onBackground)
+ .padding((0.5).dp)
+ .clip(RoundedCornerShape(3.dp))
+ .background(Color.DarkGray)
+ .padding(horizontal = 8.dp, vertical = 4.dp)
+ }
+ }
+
+ @Composable
+ fun IconWithLabel(
+ selected: Boolean,
+ imageVector: ImageVector,
+ labelText: String,
+ onClick: () -> Unit
+ ) {
+ val imageSize = 28.dp
+ val labelTextStyle = MaterialTheme.typography.bodySmall
+
+ Column(
+ modifier = Modifier
+ .clickable { onClick() }
+ .selectionModifier(selected),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Image(
+ modifier = Modifier.size(imageSize),
+ contentDescription = labelText,
+ imageVector = imageVector,
+ colorFilter = ColorFilter.tint(
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ )
+ Spacer(modifier = Modifier.size(4.dp))
+ Text(
+ style = labelTextStyle,
+ text = labelText
+ )
+ }
+ }
+}
+
+interface ToolController {
+ fun emit(op: EditOp) // placeholder; will be EditOp in future
+ fun undo()
+ fun redo()
+ /**
+ * FUTURE: add batch ops for atomic changes
+ * fun emitAll(ops: List)
+ */
+}
+
+class QuickEditState internal constructor(
+ val snapshot: EditSnapshot
+)
+
+/** A contribution that provides a ToolFactory */
+interface ToolContributionWithFactory: ToolContribution {
+ val factory: ToolFactory
+
+ @Composable
+ override fun FullScreenTool(
+ state: QuickEditState,
+ controller: ToolController,
+ onExit: () -> Unit
+ ) {
+ val host = rememberToolHostFrom(state)
+ val session = remember { factory.create(ToolParams()) }
+ session.Ui(host, controller, onExit)
+ }
+
+}
+
+internal fun rememberToolHostFrom(state: QuickEditState): ToolHost = object : ToolHost {
+ override val snapshot: EditSnapshot
+ get() = state.snapshot
+
+ override fun requestGestureMode(mode: GestureMode) {
+ // Shell toggles its state machine to enforce gesture policy while in tool mode
+ // (editor preview not composed; render paused per design).
+ }
+
+}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AnimatedToolbarContainer.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/common/AnimatedToolbarContainer.kt
similarity index 80%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AnimatedToolbarContainer.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/common/AnimatedToolbarContainer.kt
index d4f77dc..206eedf 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AnimatedToolbarContainer.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/common/AnimatedToolbarContainer.kt
@@ -1,17 +1,22 @@
-package com.abizer_r.quickedit.ui.common
+package io.github.abizerr.quickedit.ui.common
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstrainedLayoutReference
import androidx.constraintlayout.compose.ConstraintLayoutScope
import androidx.constraintlayout.compose.Dimension
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
+
+val TOOLBAR_HEIGHT_SMALL = 48.dp
+val TOOLBAR_HEIGHT_MEDIUM = 64.dp
+val TOOLBAR_HEIGHT_LARGE = 88.dp
+val TOOLBAR_HEIGHT_XL = 104.dp
@Composable
fun AnimatedToolbarContainer(
@@ -32,7 +37,7 @@ fun AnimatedToolbarContainer(
@Composable
fun ConstraintLayoutScope.topToolbarModifier(
constraintRef: ConstrainedLayoutReference,
-) = Modifier.constrainAs(constraintRef) {
+) = Modifier.Companion.constrainAs(constraintRef) {
top.linkTo(parent.top)
width = Dimension.matchParent
height = Dimension.wrapContent
@@ -41,7 +46,7 @@ fun ConstraintLayoutScope.topToolbarModifier(
@Composable
fun ConstraintLayoutScope.bottomToolbarModifier(
constraintRef: ConstrainedLayoutReference,
-) = Modifier.constrainAs(constraintRef) {
+) = Modifier.Companion.constrainAs(constraintRef) {
bottom.linkTo(parent.bottom)
width = Dimension.matchParent
height = Dimension.wrapContent
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Color.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Color.kt
similarity index 87%
rename from quickedit/src/main/java/com/abizer_r/quickedit/theme/Color.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Color.kt
index 13d4d9a..851cc9d 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Color.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Color.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.theme
+package io.github.abizerr.quickedit.ui.theme
import androidx.compose.ui.graphics.Color
@@ -17,8 +17,9 @@ val Black_alpha_30 = Color(0x4D000000)
val TextInputBackgroundColor = Color(0xB3000000)
val ToolBarBackgroundColor = DarkerGray
+val White = Color.White
val BackgroundColor_Dark = Color(0xFF141414)
-val ColorOnBackground_Dark = Color.White
+val ColorOnBackground_Dark = White
/**
* NOTE: While changing Light theme colors, we also need to change static colors, such as "ToolBarBackgroundColor"
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Theme.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Theme.kt
similarity index 75%
rename from quickedit/src/main/java/com/abizer_r/quickedit/theme/Theme.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Theme.kt
index 7a9a824..cd67744 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Theme.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Theme.kt
@@ -1,25 +1,28 @@
-package com.abizer_r.quickedit.theme
+package io.github.abizerr.quickedit.ui.theme
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.dynamicDarkColorScheme
-import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
+ onPrimary = White,
secondary = PurpleGrey80,
+ onSecondary = White,
tertiary = Pink80,
+ onTertiary = White,
background = BackgroundColor_Dark,
onBackground = ColorOnBackground_Dark
)
@@ -47,10 +50,11 @@ fun QuickEditTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
- val colorScheme = when {
- darkTheme -> DarkColorScheme
- else -> LightColorScheme
- }
+ val colorScheme = DarkColorScheme
+// val colorScheme = when {
+// darkTheme -> DarkColorScheme
+// else -> LightColorScheme
+// }
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
@@ -69,6 +73,12 @@ fun QuickEditTheme(
MaterialTheme(
colorScheme = colorScheme,
typography = Typography,
- content = content
+ content = {
+ CompositionLocalProvider(
+ LocalContentColor provides colorScheme.onPrimary, // default text color
+ ) {
+ content()
+ }
+ }
)
}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Type.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Type.kt
similarity index 84%
rename from quickedit/src/main/java/com/abizer_r/quickedit/theme/Type.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Type.kt
index cb15045..1ac7aad 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/theme/Type.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/theme/Type.kt
@@ -1,11 +1,7 @@
-package com.abizer_r.quickedit.theme
+package io.github.abizerr.quickedit.ui.theme
import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-import com.abizer_r.quickedit.utils.textMode.FontUtils
+import io.github.abizerr.quickedit.ui.utils.font.FontUtils
// Set of Material typography styles to start with
val Typography = Typography(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/CommonExtensions.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/CommonExtensions.kt
similarity index 63%
rename from quickedit/src/main/java/com/abizer_r/quickedit/utils/CommonExtensions.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/CommonExtensions.kt
index 3141e46..f7a2307 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/CommonExtensions.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/CommonExtensions.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.utils
+package io.github.abizerr.quickedit.ui.utils
import android.content.Context
import android.content.ContextWrapper
@@ -8,15 +8,13 @@ import android.provider.Settings
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.annotation.StringRes
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.AnimatedVisibilityScope
-import androidx.compose.animation.ExperimentalSharedTransitionApi
-import androidx.compose.animation.SharedTransitionLayout
-import androidx.compose.animation.SharedTransitionScope
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.platform.LocalContext
-import com.abizer_r.quickedit.R
+import androidx.compose.ui.res.imageResource
+import io.github.abizerr.quickedit.ui.R
val Any.TAG: String
get() {
@@ -24,17 +22,17 @@ val Any.TAG: String
return if (tag.length <= 23) tag else tag.substring(0, 23)
}
-@OptIn(ExperimentalSharedTransitionApi::class)
-@Composable
-fun SharedTransitionPreviewExtension(
- content: @Composable SharedTransitionScope.(AnimatedVisibilityScope) -> Unit
-) {
- SharedTransitionLayout {
- AnimatedVisibility(visible = true) {
- content(this)
- }
- }
-}
+//@OptIn(ExperimentalSharedTransitionApi::class)
+//@Composable
+//fun SharedTransitionPreviewExtension(
+// content: @Composable SharedTransitionScope.(AnimatedVisibilityScope) -> Unit
+//) {
+// SharedTransitionLayout {
+// AnimatedVisibility(visible = true) {
+// content(this)
+// }
+// }
+//}
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
@@ -55,6 +53,11 @@ fun toast(@StringRes stringRes: Int) {
LocalContext.current.toast(stringRes)
}
+fun Context.errorToast(@StringRes resId: Int? = null) {
+ if (resId == null) defaultErrorToast()
+ else toast(resId)
+}
+
fun Context.defaultErrorToast() {
Toast.makeText(this, this.getString(R.string.something_went_wrong), Toast.LENGTH_SHORT).show()
}
@@ -73,4 +76,8 @@ fun Context.getOpenAppSettingsIntent(): Intent {
}
@Composable
-fun defaultTextColor() = MaterialTheme.colorScheme.onBackground
\ No newline at end of file
+fun defaultTextColor() = MaterialTheme.colorScheme.onBackground
+
+
+@Composable
+fun getDummyBitmap() = ImageBitmap.imageResource(id = R.drawable.dummy_image).asAndroidBitmap()
\ No newline at end of file
diff --git a/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/PreviewUtils.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/PreviewUtils.kt
new file mode 100644
index 0000000..3e31cab
--- /dev/null
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/PreviewUtils.kt
@@ -0,0 +1,55 @@
+package io.github.abizerr.quickedit.ui.utils
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.runtime.Composable
+import io.github.abizerr.quickedit.engine.api.EditImage
+import io.github.abizerr.quickedit.engine.api.EditOp
+import io.github.abizerr.quickedit.engine.api.EditSnapshot
+import io.github.abizerr.quickedit.ui.api.QuickEditState
+import io.github.abizerr.quickedit.ui.api.ToolContribution
+import io.github.abizerr.quickedit.ui.api.ToolController
+
+object PreviewUtils {
+
+ @Composable
+ fun getDummyEditorState(): QuickEditState {
+ val snapShot = EditSnapshot(image = EditImage.FromBitmap(getDummyBitmap()))
+ return QuickEditState(snapShot)
+ }
+
+ fun getDummyTools(): List {
+ val tools = arrayListOf()
+ repeat(4) { i ->
+ tools.add(getDummyToolContribution(i))
+ }
+ return tools
+ }
+
+ private fun getDummyToolContribution(i: Int = 0): ToolContribution {
+ val dummyToolContribution = object : ToolContribution {
+ override val id: String get() = "dummy$i"
+ @Composable
+ override fun Panel(state: QuickEditState, controller: ToolController) { }
+ @Composable
+ override fun ToolbarIcon(selected: Boolean, onClick: () -> Unit) {
+ IconWithLabel(
+ selected = selected,
+ imageVector = Icons.Default.Edit,
+ labelText = "Tool-$i",
+ onClick = {}
+ )
+ }
+ }
+ return dummyToolContribution
+ }
+
+ fun getDummyToolController(): ToolController {
+ val dummyController = object : ToolController {
+ override fun emit(op: EditOp) {}
+ override fun undo() {}
+ override fun redo() {}
+ }
+ return dummyController
+ }
+}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/other/anim/AnimUtils.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/anim/AnimUtils.kt
similarity index 88%
rename from quickedit/src/main/java/com/abizer_r/quickedit/utils/other/anim/AnimUtils.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/anim/AnimUtils.kt
index 0b160d3..08111d5 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/other/anim/AnimUtils.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/anim/AnimUtils.kt
@@ -1,26 +1,18 @@
-package com.abizer_r.quickedit.utils.other.anim
+package io.github.abizerr.quickedit.ui.utils.anim
-import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.core.CubicBezierEasing
-import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.FastOutSlowInEasing
-import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkOut
import androidx.compose.animation.slideIn
-import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOut
-import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
-import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.IntOffset
-import androidx.navigation.NavBackStackEntry
object AnimUtils {
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontItem.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontItem.kt
similarity index 60%
rename from quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontItem.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontItem.kt
index 9652638..318e253 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontItem.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontItem.kt
@@ -1,4 +1,4 @@
-package com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.fontFamilyOptions
+package io.github.abizerr.quickedit.ui.utils.font
import androidx.compose.ui.text.font.FontFamily
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/FontUtils.kt b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontUtils.kt
similarity index 53%
rename from quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/FontUtils.kt
rename to quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontUtils.kt
index 9cd31fc..d47ace4 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/FontUtils.kt
+++ b/quickedit-ui/src/main/java/io/github/abizerr/quickedit/ui/utils/font/FontUtils.kt
@@ -1,72 +1,71 @@
-package com.abizer_r.quickedit.utils.textMode
+package io.github.abizerr.quickedit.ui.utils.font
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
-import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.fontFamilyOptions.FontItem
+import io.github.abizerr.quickedit.ui.R
object FontUtils {
val eduVicwantFontFamily = FontFamily(
- Font(R.font.edu_vicwant_regular, FontWeight.Normal),
- Font(R.font.edu_vicwant_bold, FontWeight.Bold),
+ Font(R.font.edu_vicwant_regular, FontWeight.Companion.Normal),
+ Font(R.font.edu_vicwant_bold, FontWeight.Companion.Bold),
)
val greyQoFontFamily = FontFamily(
- Font(R.font.grey_qo_regular, FontWeight.Normal),
+ Font(R.font.grey_qo_regular, FontWeight.Companion.Normal),
)
val matemasieFontFamily = FontFamily(
- Font(R.font.matemasie_regular, FontWeight.Bold),
+ Font(R.font.matemasie_regular, FontWeight.Companion.Bold),
)
val moderusticFontFamily = FontFamily(
- Font(R.font.moderustic_regular, FontWeight.Normal),
- Font(R.font.moderustic_bold, FontWeight.Bold),
+ Font(R.font.moderustic_regular, FontWeight.Companion.Normal),
+ Font(R.font.moderustic_bold, FontWeight.Companion.Bold),
)
val montserratFontFamily = FontFamily(
- Font(R.font.montserrat_regular, FontWeight.Normal),
- Font(R.font.montserrat_italic, FontWeight.Normal, FontStyle.Italic),
- Font(R.font.montserrat_bold, FontWeight.Bold),
- Font(R.font.montserrat_bold_italic, FontWeight.Bold, FontStyle.Italic),
+ Font(R.font.montserrat_regular, FontWeight.Companion.Normal),
+ Font(R.font.montserrat_italic, FontWeight.Companion.Normal, FontStyle.Companion.Italic),
+ Font(R.font.montserrat_bold, FontWeight.Companion.Bold),
+ Font(R.font.montserrat_bold_italic, FontWeight.Companion.Bold, FontStyle.Companion.Italic),
)
val newAmsterdamFontFamily = FontFamily(
- Font(R.font.new_amsterdam_regular, FontWeight.Bold),
+ Font(R.font.new_amsterdam_regular, FontWeight.Companion.Bold),
)
val oswaldFontFamily = FontFamily(
- Font(R.font.oswald_regular, FontWeight.Normal),
- Font(R.font.oswald_bold, FontWeight.Bold),
+ Font(R.font.oswald_regular, FontWeight.Companion.Normal),
+ Font(R.font.oswald_bold, FontWeight.Companion.Bold),
)
val playwrightFontFamily = FontFamily(
- Font(R.font.playwrite_regular, FontWeight.Normal),
- Font(R.font.playwrite_italic, FontWeight.Normal, FontStyle.Italic),
+ Font(R.font.playwrite_regular, FontWeight.Companion.Normal),
+ Font(R.font.playwrite_italic, FontWeight.Companion.Normal, FontStyle.Companion.Italic),
)
val poppinsFontFamily = FontFamily(
- Font(R.font.poppins_regular, FontWeight.Normal),
- Font(R.font.poppins_italic, FontWeight.Normal, FontStyle.Italic),
- Font(R.font.poppins_bold, FontWeight.Bold),
- Font(R.font.poppins_bold_italic, FontWeight.Bold, FontStyle.Italic),
+ Font(R.font.poppins_regular, FontWeight.Companion.Normal),
+ Font(R.font.poppins_italic, FontWeight.Companion.Normal, FontStyle.Companion.Italic),
+ Font(R.font.poppins_bold, FontWeight.Companion.Bold),
+ Font(R.font.poppins_bold_italic, FontWeight.Companion.Bold, FontStyle.Companion.Italic),
)
val robotoFontFamily = FontFamily(
- Font(R.font.roboto_regular, FontWeight.Normal),
- Font(R.font.roboto_italic, FontWeight.Normal, FontStyle.Italic),
- Font(R.font.roboto_bold, FontWeight.Bold),
- Font(R.font.roboto_bold_italic, FontWeight.Bold, FontStyle.Italic),
+ Font(R.font.roboto_regular, FontWeight.Companion.Normal),
+ Font(R.font.roboto_italic, FontWeight.Companion.Normal, FontStyle.Companion.Italic),
+ Font(R.font.roboto_bold, FontWeight.Companion.Bold),
+ Font(R.font.roboto_bold_italic, FontWeight.Companion.Bold, FontStyle.Companion.Italic),
)
val tekoFontFamily = FontFamily(
- Font(R.font.teko_regular, FontWeight.Normal),
- Font(R.font.teko_bold, FontWeight.Bold),
+ Font(R.font.teko_regular, FontWeight.Companion.Normal),
+ Font(R.font.teko_bold, FontWeight.Companion.Bold),
)
val DefaultFontFamily = poppinsFontFamily
diff --git a/quickedit-ui/src/main/res/drawable/dummy_image.jpg b/quickedit-ui/src/main/res/drawable/dummy_image.jpg
new file mode 100644
index 0000000..a1d0ad5
Binary files /dev/null and b/quickedit-ui/src/main/res/drawable/dummy_image.jpg differ
diff --git a/quickedit-ui/src/main/res/font/edu_vicwant_bold.ttf b/quickedit-ui/src/main/res/font/edu_vicwant_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit/src/main/res/font/edu_vicwant_regular.ttf b/quickedit-ui/src/main/res/font/edu_vicwant_regular.ttf
similarity index 100%
rename from quickedit/src/main/res/font/edu_vicwant_regular.ttf
rename to quickedit-ui/src/main/res/font/edu_vicwant_regular.ttf
diff --git a/quickedit/src/main/res/font/grey_qo_regular.ttf b/quickedit-ui/src/main/res/font/grey_qo_regular.ttf
similarity index 100%
rename from quickedit/src/main/res/font/grey_qo_regular.ttf
rename to quickedit-ui/src/main/res/font/grey_qo_regular.ttf
diff --git a/quickedit-ui/src/main/res/font/matemasie_regular.ttf b/quickedit-ui/src/main/res/font/matemasie_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/moderustic_bold.ttf b/quickedit-ui/src/main/res/font/moderustic_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit/src/main/res/font/moderustic_regular.ttf b/quickedit-ui/src/main/res/font/moderustic_regular.ttf
similarity index 100%
rename from quickedit/src/main/res/font/moderustic_regular.ttf
rename to quickedit-ui/src/main/res/font/moderustic_regular.ttf
diff --git a/quickedit-ui/src/main/res/font/montserrat_bold.ttf b/quickedit-ui/src/main/res/font/montserrat_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/montserrat_bold_italic.ttf b/quickedit-ui/src/main/res/font/montserrat_bold_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/montserrat_italic.ttf b/quickedit-ui/src/main/res/font/montserrat_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/montserrat_regular.ttf b/quickedit-ui/src/main/res/font/montserrat_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit/src/main/res/font/new_amsterdam_regular.ttf b/quickedit-ui/src/main/res/font/new_amsterdam_regular.ttf
similarity index 100%
rename from quickedit/src/main/res/font/new_amsterdam_regular.ttf
rename to quickedit-ui/src/main/res/font/new_amsterdam_regular.ttf
diff --git a/quickedit-ui/src/main/res/font/oswald_bold.ttf b/quickedit-ui/src/main/res/font/oswald_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/oswald_regular.ttf b/quickedit-ui/src/main/res/font/oswald_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/playwrite_italic.ttf b/quickedit-ui/src/main/res/font/playwrite_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/playwrite_regular.ttf b/quickedit-ui/src/main/res/font/playwrite_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit/src/main/res/font/poppins_bold.ttf b/quickedit-ui/src/main/res/font/poppins_bold.ttf
similarity index 100%
rename from quickedit/src/main/res/font/poppins_bold.ttf
rename to quickedit-ui/src/main/res/font/poppins_bold.ttf
diff --git a/quickedit-ui/src/main/res/font/poppins_bold_italic.ttf b/quickedit-ui/src/main/res/font/poppins_bold_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/poppins_italic.ttf b/quickedit-ui/src/main/res/font/poppins_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit/src/main/res/font/poppins_regular.ttf b/quickedit-ui/src/main/res/font/poppins_regular.ttf
similarity index 100%
rename from quickedit/src/main/res/font/poppins_regular.ttf
rename to quickedit-ui/src/main/res/font/poppins_regular.ttf
diff --git a/quickedit-ui/src/main/res/font/roboto_bold.ttf b/quickedit-ui/src/main/res/font/roboto_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/roboto_bold_italic.ttf b/quickedit-ui/src/main/res/font/roboto_bold_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/roboto_italic.ttf b/quickedit-ui/src/main/res/font/roboto_italic.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/roboto_regular.ttf b/quickedit-ui/src/main/res/font/roboto_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/teko_bold.ttf b/quickedit-ui/src/main/res/font/teko_bold.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/font/teko_regular.ttf b/quickedit-ui/src/main/res/font/teko_regular.ttf
new file mode 100644
index 0000000..e69de29
diff --git a/quickedit-ui/src/main/res/values/strings.xml b/quickedit-ui/src/main/res/values/strings.xml
new file mode 100644
index 0000000..eeabb56
--- /dev/null
+++ b/quickedit-ui/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Something went wrong
+
\ No newline at end of file
diff --git a/quickedit-ui/src/test/java/io/github/abizerr/quickedit/ui/ExampleUnitTest.kt b/quickedit-ui/src/test/java/io/github/abizerr/quickedit/ui/ExampleUnitTest.kt
new file mode 100644
index 0000000..67fbf52
--- /dev/null
+++ b/quickedit-ui/src/test/java/io/github/abizerr/quickedit/ui/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.github.abizerr.quickedit.ui
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/quickedit/build.gradle.kts b/quickedit/build.gradle.kts
index cb4363e..802eedd 100644
--- a/quickedit/build.gradle.kts
+++ b/quickedit/build.gradle.kts
@@ -42,6 +42,11 @@ android {
}
dependencies {
+ implementation(project(":quickedit-ui"))
+ implementation(project(":quickedit-tool-draw"))
+ implementation(project(":quickedit-tool-text"))
+ implementation(project(":quickedit-tool-crop"))
+ implementation(project(":quickedit-tool-effects"))
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.activity.compose)
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AppIconWithName.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AppIconWithName.kt
index 9aa30fc..5045780 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AppIconWithName.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/AppIconWithName.kt
@@ -15,7 +15,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
@Preview
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/ErrorView.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/ErrorView.kt
index a1acea6..66cbbd7 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/ErrorView.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/ErrorView.kt
@@ -9,7 +9,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
@Composable
fun ErrorView(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/PermissionDeniedView.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/PermissionDeniedView.kt
index 5655d00..189934b 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/PermissionDeniedView.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/PermissionDeniedView.kt
@@ -11,7 +11,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
import com.abizer_r.quickedit.utils.PermissionUtils
import com.abizer_r.quickedit.utils.PermissionUtils.PermissionTypes
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/toolbar/SelectableToolbarItem.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/toolbar/SelectableToolbarItem.kt
index b9bd0fb..ff2aa0e 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/toolbar/SelectableToolbarItem.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/common/toolbar/SelectableToolbarItem.kt
@@ -20,7 +20,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
@Composable
fun SelectableToolbarItem(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/CropperScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/CropperScreen.kt
index e7f2f15..15c3c77 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/CropperScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/cropMode/CropperScreen.kt
@@ -32,22 +32,22 @@ import androidx.constraintlayout.compose.Dimension
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.lifecycleScope
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.utils.defaultErrorToast
-import com.abizer_r.quickedit.ui.common.AnimatedToolbarContainer
-import com.abizer_r.quickedit.ui.common.bottomToolbarModifier
-import com.abizer_r.quickedit.ui.common.crop.AspectRatioDialog
-import com.abizer_r.quickedit.ui.common.topToolbarModifier
-import com.abizer_r.quickedit.ui.cropMode.cropperOptions.CropperOption
-import com.abizer_r.quickedit.ui.cropMode.cropperOptions.CropperOptionsFullWidth
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.utils.defaultErrorToast
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.bottomToolbarModifier
+import io.github.abizerr.quickedit.tool.crop.AspectRatioDialog
+import io.github.abizerr.quickedit.ui.common.topToolbarModifier
+import io.github.abizerr.quickedit.tool.crop.model.CropperOption
+import io.github.abizerr.quickedit.tool.crop.CropperOptionsFullWidth
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_LARGE
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
import com.abizer_r.quickedit.ui.editorScreen.topToolbar.TextModeTopToolbar
-import com.abizer_r.quickedit.utils.editorScreen.CropModeUtils
-import com.abizer_r.quickedit.utils.getActivity
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.tool.crop.utils.CropModeUtils
+import io.github.abizerr.quickedit.ui.utils.getActivity
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
-import com.abizer_r.quickedit.utils.toast
+import io.github.abizerr.quickedit.ui.utils.toast
import com.canhub.cropper.CropImageOptions
import com.canhub.cropper.CropImageView
import com.canhub.cropper.CropImageView.OnCropImageCompleteListener
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeScreen.kt
index d616a39..5b93725 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeScreen.kt
@@ -1,6 +1,5 @@
package com.abizer_r.quickedit.ui.drawMode
-import com.abizer_r.quickedit.ui.drawMode.bottomToolbarExtension.DrawModeToolbarExtension
import android.graphics.Bitmap
import android.util.Log
import androidx.activity.compose.BackHandler
@@ -13,13 +12,27 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.rememberTransformableState
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AddCircleOutline
+import androidx.compose.material.icons.filled.TextFields
+import androidx.compose.material.icons.outlined.Brush
+import androidx.compose.material.icons.outlined.Category
+import androidx.compose.material.icons.outlined.Crop
+import androidx.compose.material.icons.outlined.PanTool
import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
@@ -28,47 +41,58 @@ import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.imageResource
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.zIndex
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
-import com.abizer_r.quickedit.utils.ImmutableList
-import com.abizer_r.quickedit.utils.defaultErrorToast
-import com.abizer_r.quickedit.ui.common.AnimatedToolbarContainer
-import com.abizer_r.quickedit.ui.common.bottomToolbarModifier
-import com.abizer_r.quickedit.ui.common.topToolbarModifier
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeEvent
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.BottomToolBarStatic
+import com.abizer_r.quickedit.R
+import com.abizer_r.quickedit.ui.drawMode.bottomToolbarExtension.DrawModeToolbarExtension
+import com.abizer_r.quickedit.ui.drawMode.toptoolbar.DrawModeTopToolBar
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_MEDIUM
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarEvent
-import com.abizer_r.quickedit.ui.drawMode.toptoolbar.DrawModeTopToolBar
import com.abizer_r.quickedit.utils.AppUtils
+import com.abizer_r.quickedit.utils.ImmutableList
import com.abizer_r.quickedit.utils.drawMode.DrawModeUtils
-import com.abizer_r.quickedit.utils.drawMode.getOpacityOrNull
-import com.abizer_r.quickedit.utils.drawMode.getShapeTypeOrNull
-import com.abizer_r.quickedit.utils.drawMode.getWidthOrNull
import com.abizer_r.quickedit.utils.drawMode.toPx
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
import com.smarttoolfactory.screenshot.ImageResult
import com.smarttoolfactory.screenshot.ScreenshotBox
import com.smarttoolfactory.screenshot.rememberScreenshotState
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.models.getOpacityOrNull
+import io.github.abizerr.quickedit.tool.draw.models.getShapeTypeOrNull
+import io.github.abizerr.quickedit.tool.draw.models.getWidthOrNull
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeEvent
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.bottomToolbarModifier
+import io.github.abizerr.quickedit.ui.common.topToolbarModifier
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.defaultErrorToast
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
import io.mhssn.colorpicker.ColorPickerDialog
import io.mhssn.colorpicker.ColorPickerType
import kotlinx.coroutines.Dispatchers
@@ -95,7 +119,7 @@ fun DrawModeScreen(
val backgroundColor = MaterialTheme.colorScheme.background
val bottomToolbarItems = remember {
- ImmutableList(DrawModeUtils.getDefaultBottomToolbarItemsList())
+ ImmutableList(DrawModeUtils.getDefaultDrawToolItemsList())
}
val topToolbarHeight = TOOLBAR_HEIGHT_SMALL
@@ -139,8 +163,8 @@ fun DrawModeScreen(
LaunchedEffect(key1 = Unit) {
toolbarVisible = true
delay(AnimUtils.TOOLBAR_EXPAND_ANIM_DURATION_FAST.toLong())
- viewModel.onBottomToolbarEvent(
- BottomToolbarEvent.OnItemClicked(
+ viewModel.onEvent(
+ DrawModeEvent.OnToolbarItemClicked(
bottomToolbarItems.items[DrawModeUtils.DEFAULT_SELECTED_INDEX]
)
)
@@ -218,8 +242,8 @@ fun DrawModeScreen(
val onRedoLambda = remember<() -> Unit> {{
viewModel.onEvent(DrawModeEvent.OnRedo)
}}
- val onBottomToolbarEventLambda = remember<(BottomToolbarEvent) -> Unit> {{
- viewModel.onBottomToolbarEvent(it)
+ val onBottomToolbarEventLambda = remember<(DrawModeEvent) -> Unit> {{
+ viewModel.onEvent(it)
}}
ConstraintLayout(
@@ -291,7 +315,7 @@ fun DrawModeScreen(
showColorPickerIcon = viewModel.showColorPickerIconInToolbar,
toolbarHeight = bottomToolbarHeight,
selectedColor = state.selectedColor,
- selectedItem = state.selectedTool,
+ selectedItem = state.selectedTool, // comment to support latest changes
onEvent = onBottomToolbarEventLambda
)
}
@@ -332,18 +356,18 @@ fun DrawModeScreen(
val emptyLambda = remember<() -> Unit> {{
}}
val onWidthChangeLambda = remember<(Float) -> Unit> {{ mWidth ->
- viewModel.onBottomToolbarEvent(
- BottomToolbarEvent.UpdateWidth(mWidth)
+ viewModel.onEvent(
+ DrawModeEvent.UpdateWidth(mWidth)
)
}}
val onOpacityChangeLambda = remember<(Float) -> Unit> {{ mOpacity ->
- viewModel.onBottomToolbarEvent(
- BottomToolbarEvent.UpdateOpacity(mOpacity)
+ viewModel.onEvent(
+ DrawModeEvent.UpdateOpacity(mOpacity)
)
}}
val onShapeTypeChangeLambda = remember<(ShapeType) -> Unit> {{ mShapeType ->
- viewModel.onBottomToolbarEvent(
- BottomToolbarEvent.UpdateShapeType(mShapeType)
+ viewModel.onEvent(
+ DrawModeEvent.UpdateShapeType(mShapeType)
)
}}
@@ -387,4 +411,192 @@ fun DrawModeScreen(
)
}
+}
+
+val TOOLBAR_HEIGHT_SMALL = 48.dp
+val TOOLBAR_HEIGHT_MEDIUM = 64.dp
+val TOOLBAR_HEIGHT_LARGE = 88.dp
+val TOOLBAR_HEIGHT_EXTRA_LARGE = 104.dp
+
+@Composable
+private fun BottomToolBarStatic(
+ modifier: Modifier,
+ toolbarItems: ImmutableList,
+ toolbarHeight: Dp = TOOLBAR_HEIGHT_MEDIUM,
+ selectedItem: DrawToolItem = DrawToolItem.NONE,
+ showColorPickerIcon: Boolean = true,
+ selectedColor: Color = Color.White,
+ onEvent: (DrawModeEvent) -> Unit
+) {
+
+ Row(
+ modifier = modifier
+ .fillMaxWidth()
+ .height(toolbarHeight)
+ .background(ToolBarBackgroundColor),
+ horizontalArrangement = Arrangement.SpaceEvenly,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ toolbarItems.items.forEachIndexed { index, mToolbarItem ->
+ ToolbarItem(
+ toolbarItem = mToolbarItem,
+ selectedColor = selectedColor,
+ showColorPickerIcon = showColorPickerIcon,
+ isSelected = mToolbarItem == selectedItem,
+ onEvent = onEvent
+ )
+ }
+ }
+}
+
+
+@Composable
+private fun ToolbarItem(
+ modifier: Modifier = Modifier,
+ selectedColor: Color,
+ showColorPickerIcon: Boolean,
+ toolbarItem: DrawToolItem,
+ isSelected: Boolean,
+ onEvent: (DrawModeEvent) -> Unit
+) {
+ val labelTextStyle = MaterialTheme.typography.bodySmall.copy(color = defaultTextColor())
+
+ val commonPaddingModifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
+
+ if (toolbarItem is DrawToolItem.ColorItem) {
+ ColorToolbarItem(
+ modifier = modifier.then(commonPaddingModifier),
+ selectedColor = selectedColor,
+ showColorPickerIcon = showColorPickerIcon,
+ colorItem = toolbarItem,
+ labelTextStyle = labelTextStyle,
+ onEvent = onEvent
+ )
+ return
+ }
+ var columnModifier = modifier.clickable {
+ onEvent(DrawModeEvent.OnToolbarItemClicked(toolbarItem))
+ }
+ if (isSelected) {
+ columnModifier = columnModifier
+ .clip(RoundedCornerShape(3.dp))
+ .background(MaterialTheme.colorScheme.onBackground)
+ .padding((0.5).dp)
+ .clip(RoundedCornerShape(3.dp))
+ .background(Color.DarkGray)
+// .padding(start = 8.dp, end = 8.dp, bottom = 4.dp)
+ }
+ columnModifier = columnModifier.then(commonPaddingModifier)
+
+
+ val (imageVector, labelText) = when (toolbarItem) {
+
+ is DrawToolItem.EraserTool -> Pair(
+ ImageVector.vectorResource(id = R.drawable.ic_eraser),
+ stringResource(id = R.string.eraser)
+ )
+
+ is DrawToolItem.ShapeTool -> Pair(
+ Icons.Outlined.Category,
+ stringResource(id = R.string.shape)
+ )
+
+ is DrawToolItem.BrushTool -> Pair(
+ ImageVector.vectorResource(id = R.drawable.ic_stylus_note),
+ stringResource(id = R.string.brush)
+ )
+
+ is DrawToolItem.PanItem -> Pair(
+ Icons.Outlined.PanTool,
+ stringResource(id = R.string.zoom)
+ )
+
+ // We won't reach here
+ else -> Pair(
+ Icons.Default.AddCircleOutline,
+ ""
+ )
+ }
+
+
+ Column(
+ modifier = columnModifier,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+
+ val verticalPaddingBeforeSize = if (labelText.isBlank()) 4.dp else 0.dp
+ val imageSize = if (labelText.isBlank()) 32.dp else 28.dp
+ Image(
+ modifier = Modifier
+ .padding(vertical = verticalPaddingBeforeSize)
+ .size(imageSize),
+ contentDescription = null,
+ imageVector = imageVector,
+ colorFilter = ColorFilter.tint(
+ color = MaterialTheme.colorScheme.onBackground
+ )
+ )
+ Spacer(modifier = Modifier.size(
+ if (labelText.isNotBlank()) 4.dp else 0.dp
+ ))
+
+ if (labelText.isNotBlank()) {
+ Text(
+ style = labelTextStyle,
+ text = labelText
+ )
+ }
+ }
+}
+
+@Composable
+private fun ColorToolbarItem(
+ modifier: Modifier = Modifier,
+ selectedColor: Color,
+ showColorPickerIcon: Boolean,
+ colorItem: DrawToolItem.ColorItem,
+ labelTextStyle: TextStyle,
+ onEvent: (DrawModeEvent) -> Unit
+) {
+ Column(
+ modifier = modifier,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+
+ if (showColorPickerIcon) {
+ Image(
+ bitmap = ImageBitmap.imageResource(id = R.drawable.ic_color_picker),
+ contentDescription = null,
+ modifier = Modifier
+ .size(26.dp)
+ .clickable {
+ onEvent(DrawModeEvent.OnToolbarItemClicked(colorItem))
+ }
+ )
+ } else {
+ Image(
+ painter = ColorPainter(selectedColor),
+ contentDescription = null,
+ modifier = Modifier
+ .clip(CircleShape)
+ .background(color = MaterialTheme.colorScheme.onBackground)
+ .padding(1.dp)
+ .clip(CircleShape)
+ .size(26.dp)
+ .clickable {
+ onEvent(DrawModeEvent.OnToolbarItemClicked(colorItem))
+ }
+ )
+ }
+
+
+ Spacer(modifier = Modifier.size(4.dp))
+
+ Text(
+ style = labelTextStyle,
+ text = stringResource(id = R.string.color)
+ )
+ }
}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeViewModel.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeViewModel.kt
index 90158da..eb3a329 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeViewModel.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawModeViewModel.kt
@@ -1,19 +1,16 @@
package com.abizer_r.quickedit.ui.drawMode
-import android.icu.util.Calendar
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeEvent
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeState
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarEvent
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
-import com.abizer_r.quickedit.utils.drawMode.DrawModeUtils
-import com.abizer_r.quickedit.utils.drawMode.setOpacityIfPossible
-import com.abizer_r.quickedit.utils.drawMode.setShapeTypeIfPossible
-import com.abizer_r.quickedit.utils.drawMode.setWidthIfPossible
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
import dagger.hilt.android.lifecycle.HiltViewModel
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.models.setOpacityIfPossible
+import io.github.abizerr.quickedit.tool.draw.models.setShapeTypeIfPossible
+import io.github.abizerr.quickedit.tool.draw.models.setWidthIfPossible
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeEvent
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeState
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -80,43 +77,37 @@ class DrawModeViewModel @Inject constructor(
it.copy(recompositionTrigger = it.recompositionTrigger + 1)
}
}
- }
- }
- fun onBottomToolbarEvent(event: BottomToolbarEvent) {
- when (event) {
- is BottomToolbarEvent.OnItemClicked -> {
- onBottomToolbarItemClicked(event.toolbarItem)
+ is DrawModeEvent.OnToolbarItemClicked -> {
+ handleToolbarItemClicked(event.toolbarItem)
}
- is BottomToolbarEvent.UpdateOpacity -> {
+ is DrawModeEvent.UpdateOpacity -> {
_state.update { it.copy(
selectedTool = it.selectedTool.setOpacityIfPossible(event.newOpacity),
recompositionTrigger = it.recompositionTrigger + 1
) }
}
- is BottomToolbarEvent.UpdateWidth -> {
+ is DrawModeEvent.UpdateWidth -> {
_state.update { it.copy(
selectedTool = it.selectedTool.setWidthIfPossible(event.newWidth),
recompositionTrigger = it.recompositionTrigger + 1
) }
}
- is BottomToolbarEvent.UpdateShapeType -> {
+ is DrawModeEvent.UpdateShapeType -> {
_state.update { it.copy(
selectedTool = it.selectedTool.setShapeTypeIfPossible(event.newShapeType),
recompositionTrigger = it.recompositionTrigger + 1
) }
}
-
- else -> {}
}
}
- private fun onBottomToolbarItemClicked(selectedItem: BottomToolbarItem) = viewModelScope.launch {
+ private fun handleToolbarItemClicked(selectedItem: DrawToolItem) = viewModelScope.launch {
when (selectedItem) {
- is BottomToolbarItem.ColorItem -> {
+ is DrawToolItem.ColorItem -> {
_state.update {
it.copy(showColorPicker = it.showColorPicker.not())
}
@@ -124,7 +115,7 @@ class DrawModeViewModel @Inject constructor(
// Clicked on already selected item
state.value.selectedTool -> {
- if (selectedItem != BottomToolbarItem.PanItem) {
+ if (selectedItem != DrawToolItem.PanItem) {
_state.update {
it.copy(showBottomToolbarExtension = it.showBottomToolbarExtension.not())
}
@@ -139,7 +130,7 @@ class DrawModeViewModel @Inject constructor(
delay(AnimUtils.TOOLBAR_COLLAPSE_ANIM_DURATION.toLong())
}
_state.update { it.copy(selectedTool = selectedItem) }
- if (selectedItem != BottomToolbarItem.PanItem) {
+ if (selectedItem != DrawToolItem.PanItem) {
// open toolbarExtension for new item
_state.update { it.copy(showBottomToolbarExtension = true) }
}
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawingCanvasContainer.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawingCanvasContainer.kt
index 8af46a7..cc9ce4f 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawingCanvasContainer.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/DrawingCanvasContainer.kt
@@ -1,10 +1,8 @@
package com.abizer_r.quickedit.ui.drawMode
-import android.util.Log
import android.view.View
import androidx.compose.foundation.Image
import androidx.compose.foundation.gestures.TransformableState
-import androidx.compose.foundation.gestures.rememberTransformableState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
@@ -13,20 +11,14 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.platform.LocalConfiguration
-import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.DrawingCanvas
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeEvent
-import com.abizer_r.quickedit.ui.drawMode.stateHandling.DrawModeState
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarEvent
import com.abizer_r.quickedit.utils.drawMode.CustomLayerTypeComposable
-import com.abizer_r.quickedit.utils.drawMode.toPx
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
-import kotlin.math.abs
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeEvent
+import io.github.abizerr.quickedit.tool.draw.ui.DrawModeState
+import io.github.abizerr.quickedit.tool.draw.ui.drawingCanvas.DrawingCanvas
@Composable
fun DrawingCanvasContainer(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/CustomSliderItem.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/CustomSliderItem.kt
index 71c5d01..e22483f 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/CustomSliderItem.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/CustomSliderItem.kt
@@ -28,8 +28,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.constraintlayout.compose.Dimension
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/DrawModeToolbarExtension.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/DrawModeToolbarExtension.kt
index 1b7eb7c..015c393 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/DrawModeToolbarExtension.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/bottomToolbarExtension/DrawModeToolbarExtension.kt
@@ -18,15 +18,14 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
-import com.abizer_r.quickedit.utils.defaultTextColor
-import com.abizer_r.quickedit.utils.drawMode.DrawingConstants
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
+import io.github.abizerr.quickedit.tool.draw.util.DrawingConstants
/**
* Contains additional option for drawMode tools
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvasState.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvasState.kt
deleted file mode 100644
index 556aa8a..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/DrawingCanvasState.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas
-
-import androidx.compose.ui.graphics.Color
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.DrawingTool
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.models.PathDetails
-import java.util.Stack
-
-data class DrawingCanvasState (
- val strokeWidth: Int,
- val strokeColor: Color,
- val drawingTool: DrawingTool,
- val opacity: Int,
- val pathDetailStack: Stack,
- val redoStack: Stack
-)
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/DrawingTool.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/DrawingTool.kt
deleted file mode 100644
index 67e0f43..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/DrawingTool.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool
-
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
-
-/**
- * TODO: delete this class (this is not used in EditorScreen implementation)
- */
-sealed class DrawingTool {
- object Brush : DrawingTool()
-
- object Eraser : DrawingTool()
-
- class Shape(
- val shapeType: ShapeType
- ) : DrawingTool()
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/AbstractShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/AbstractShape.kt
deleted file mode 100644
index ffb7cca..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/AbstractShape.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.graphics.Color
-import com.abizer_r.quickedit.utils.drawMode.DrawingConstants
-
-abstract class AbstractShape: BaseShape {
- var mColor: Color = Color.White
- var mWidth: Float = DrawingConstants.DEFAULT_STROKE_WIDTH
- var mAlpha: Float = DrawingConstants.DEFAULT_STROKE_ALPHA
-
- fun updatePaintValues(
- color: Color? = null,
- width: Float? = null,
- alpha: Float? = null
- ) {
- color?.let { mColor = it }
- width?.let { mWidth = it }
- alpha?.let { mAlpha = it }
- }
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BaseShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BaseShape.kt
deleted file mode 100644
index a6c92e1..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BaseShape.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.graphics.drawscope.DrawScope
-
-interface BaseShape {
- fun draw(drawScope: DrawScope)
- fun initShape(startX: Float, startY: Float)
- fun moveShape(endX: Float, endY: Float)
- fun shouldDraw(): Boolean
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BrushShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BrushShape.kt
deleted file mode 100644
index a986003..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/BrushShape.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.BlendMode
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Path
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.StrokeJoin
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.Stroke
-
-class BrushShape(
- private val isEraser: Boolean = false,
- color: Color? = null,
- width: Float? = null,
- alpha: Float? = null
-): AbstractShape() {
-
- init {
- updatePaintValues(color, width, alpha)
- }
-
- private var path = Path()
- private var prevOffSet = Offset.Zero
-
- override fun draw(drawScope: DrawScope) {
- drawScope.drawPath(
- path = path,
- brush = SolidColor(mColor),
- style = Stroke(
- width = mWidth,
- cap = StrokeCap.Round,
- join = StrokeJoin.Round
- ),
- alpha = mAlpha,
- blendMode = if (isEraser) BlendMode.Clear else BlendMode.SrcOver
- )
- }
-
- override fun initShape(startX: Float, startY: Float) {
- path = Path()
- path.moveTo(startX, startY)
- prevOffSet = Offset(startX, startY)
- }
-
- override fun moveShape(endX: Float, endY: Float) {
- /**
- * Following this answer for SO:
- * https://stackoverflow.com/a/71090112/23198795
- */
- path.quadraticBezierTo(
- x1 = prevOffSet.x,
- y1 = prevOffSet.y,
- x2 = (prevOffSet.x + endX) / 2,
- y2 = (prevOffSet.y + endY) / 2,
- )
- prevOffSet = Offset(endX, endY)
- }
-
- override fun shouldDraw(): Boolean {
- return true
- }
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/LineShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/LineShape.kt
deleted file mode 100644
index b52b9b0..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/LineShape.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.drawscope.DrawScope
-
-class LineShape(
- color: Color? = null,
- width: Float? = null,
- alpha: Float? = null
-) : AbstractShape() {
-
- init {
- updatePaintValues(color, width, alpha)
- }
-
- private var startOffset: Offset = Offset.Unspecified
- private var endOffset: Offset = Offset.Unspecified
-
- override fun draw(drawScope: DrawScope) {
- drawScope.drawLine(
- start = startOffset,
- end = endOffset,
- brush = SolidColor(mColor),
- strokeWidth = mWidth,
- cap = StrokeCap.Round,
- alpha = mAlpha
- )
- }
-
- override fun initShape(startX: Float, startY: Float) {
- startOffset = Offset(startX, startY)
- }
-
- override fun moveShape(endX: Float, endY: Float) {
- endOffset = Offset(endX, endY)
- }
-
- override fun shouldDraw(): Boolean {
- return startOffset != Offset.Unspecified && endOffset != Offset.Unspecified
- }
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/OvalShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/OvalShape.kt
deleted file mode 100644
index c81c66f..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/OvalShape.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.StrokeJoin
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.Stroke
-
-class OvalShape(
- color: Color? = null,
- width: Float? = null,
- alpha: Float? = null
-): AbstractShape() {
-
- init {
- updatePaintValues(color, width, alpha)
- }
-
- private var startOffset: Offset = Offset.Unspecified
- private var endOffset: Offset = Offset.Unspecified
-
- override fun draw(drawScope: DrawScope) {
- drawScope.drawOval(
- topLeft = startOffset,
- size = Size(
- width = (endOffset.x - startOffset.x),
- height = (endOffset.y - startOffset.y)
- ),
- brush = SolidColor(mColor),
- style = Stroke(
- width = mWidth,
- cap = StrokeCap.Round,
- join = StrokeJoin.Round
- ),
- alpha = mAlpha
- )
- }
-
- override fun initShape(startX: Float, startY: Float) {
- startOffset = Offset(startX, startY)
- }
-
- override fun moveShape(endX: Float, endY: Float) {
- endOffset = Offset(endX, endY)
- }
-
- override fun shouldDraw(): Boolean {
- return startOffset != Offset.Unspecified && endOffset != Offset.Unspecified
- }
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/RectangleShape.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/RectangleShape.kt
deleted file mode 100644
index bb50bf1..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/RectangleShape.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.graphics.StrokeCap
-import androidx.compose.ui.graphics.StrokeJoin
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.Stroke
-
-class RectangleShape(
- color: Color? = null,
- width: Float? = null,
- alpha: Float? = null
-): AbstractShape() {
-
- init {
- updatePaintValues(color, width, alpha)
- }
-
- private var startOffset: Offset = Offset.Unspecified
- private var endOffset: Offset = Offset.Unspecified
-
- override fun draw(drawScope: DrawScope) {
- drawScope.drawRect(
- topLeft = startOffset,
- size = Size(
- width = (endOffset.x - startOffset.x),
- height = (endOffset.y - startOffset.y)
- ),
- brush = SolidColor(mColor),
- style = Stroke(
- width = mWidth,
- cap = StrokeCap.Round,
- join = StrokeJoin.Round
- ),
- alpha = mAlpha
- )
- }
-
- override fun initShape(startX: Float, startY: Float) {
- startOffset = Offset(startX, startY)
- }
-
- override fun moveShape(endX: Float, endY: Float) {
- endOffset = Offset(endX, endY)
- }
-
- override fun shouldDraw(): Boolean {
- return startOffset != Offset.Unspecified && endOffset != Offset.Unspecified
- }
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/ShapeType.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/ShapeType.kt
deleted file mode 100644
index 99cf092..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/drawingTool/shapes/ShapeType.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes
-
-enum class ShapeType {
- LINE, OVAL, RECTANGLE
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/models/PathDetails.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/models/PathDetails.kt
deleted file mode 100644
index d8ba3ae..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/drawingCanvas/models/PathDetails.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.drawingCanvas.models
-
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.AbstractShape
-
-data class PathDetails(
- val drawingShape: AbstractShape,
-)
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeEvent.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeEvent.kt
deleted file mode 100644
index 6c4da2b..0000000
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/stateHandling/DrawModeEvent.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.abizer_r.quickedit.ui.drawMode.stateHandling
-
-import androidx.compose.ui.graphics.Color
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.models.PathDetails
-
-
-sealed class DrawModeEvent {
- data class AddNewPath(val pathDetail: PathDetails): DrawModeEvent()
- data class ToggleColorPicker(val selectedColor: Color?): DrawModeEvent()
- data class UpdateToolbarExtensionVisibility(val isVisible: Boolean): DrawModeEvent()
- object OnUndo: DrawModeEvent()
- object OnRedo: DrawModeEvent()
-}
\ No newline at end of file
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/toptoolbar/DrawModeTopToolbar.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/toptoolbar/DrawModeTopToolbar.kt
index fb2c3b7..5b99bed 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/toptoolbar/DrawModeTopToolbar.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/drawMode/toptoolbar/DrawModeTopToolbar.kt
@@ -25,8 +25,8 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/EditorScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/EditorScreen.kt
index bca5b1e..b7163d5 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/EditorScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/EditorScreen.kt
@@ -31,11 +31,11 @@ import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.abizer_r.quickedit.utils.ImmutableList
-import com.abizer_r.quickedit.ui.common.AnimatedToolbarContainer
-import com.abizer_r.quickedit.ui.common.bottomToolbarModifier
-import com.abizer_r.quickedit.ui.common.topToolbarModifier
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.bottomToolbarModifier
+import io.github.abizerr.quickedit.ui.common.topToolbarModifier
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.BottomToolBarStatic
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_MEDIUM
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
@@ -45,9 +45,9 @@ import com.abizer_r.quickedit.ui.editorScreen.topToolbar.EditorTopToolBar
import com.abizer_r.quickedit.utils.AppUtils
import com.abizer_r.quickedit.utils.FileUtils
import com.abizer_r.quickedit.utils.editorScreen.EditorScreenUtils
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import com.abizer_r.quickedit.utils.other.bitmap.BitmapUtils
-import com.abizer_r.quickedit.utils.toast
+import io.github.abizerr.quickedit.ui.utils.toast
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/BottomToolbar.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/BottomToolbar.kt
index 9a0975f..85cb368 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/BottomToolbar.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/BottomToolbar.kt
@@ -41,14 +41,14 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.utils.ImmutableList
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarEvent
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableTextBoxState
-import com.abizer_r.quickedit.utils.defaultTextColor
import com.abizer_r.quickedit.utils.drawMode.DrawModeUtils
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
import com.abizer_r.quickedit.utils.editorScreen.EditorScreenUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils
import java.util.UUID
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarEvent.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarEvent.kt
index 70af41d..184dc11 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarEvent.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarEvent.kt
@@ -1,6 +1,6 @@
package com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
sealed class BottomToolbarEvent {
data class OnItemClicked(val toolbarItem: BottomToolbarItem): BottomToolbarEvent()
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarItem.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarItem.kt
index 416f593..c5e253d 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarItem.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/bottomToolbar/state/BottomToolbarItem.kt
@@ -3,7 +3,7 @@ package com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.caseOptions.TextCaseType
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleAttr
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/topToolbar/EditorTopToolbar.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/topToolbar/EditorTopToolbar.kt
index a0f345d..f939e54 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/topToolbar/EditorTopToolbar.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/editorScreen/topToolbar/EditorTopToolbar.kt
@@ -12,12 +12,9 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
-import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.Redo
import androidx.compose.material.icons.filled.SaveAlt
-import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Undo
import androidx.compose.material.icons.rounded.Share
import androidx.compose.material3.MaterialTheme
@@ -29,8 +26,8 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/EffectsModeScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/EffectsModeScreen.kt
index 4384ed7..e677a74 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/EffectsModeScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/EffectsModeScreen.kt
@@ -36,20 +36,20 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
-import com.abizer_r.quickedit.utils.defaultErrorToast
-import com.abizer_r.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.defaultErrorToast
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
import com.abizer_r.quickedit.ui.common.LoadingView
-import com.abizer_r.quickedit.ui.common.bottomToolbarModifier
-import com.abizer_r.quickedit.ui.common.topToolbarModifier
+import io.github.abizerr.quickedit.ui.common.bottomToolbarModifier
+import io.github.abizerr.quickedit.ui.common.topToolbarModifier
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_EXTRA_LARGE
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
import com.abizer_r.quickedit.ui.editorScreen.topToolbar.TextModeTopToolbar
import com.abizer_r.quickedit.ui.effectsMode.effectsPreview.EffectItem
import com.abizer_r.quickedit.ui.effectsMode.effectsPreview.EffectsPreviewListFullWidth
import com.abizer_r.quickedit.utils.effectsMode.EffectsModeUtils
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
import com.smarttoolfactory.screenshot.ImageResult
import com.smarttoolfactory.screenshot.ScreenshotBox
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/effectsPreview/EffectsPreviewListFullWidth.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/effectsPreview/EffectsPreviewListFullWidth.kt
index fc3f7c0..64d75f8 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/effectsPreview/EffectsPreviewListFullWidth.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/effectsMode/effectsPreview/EffectsPreviewListFullWidth.kt
@@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentHeight
-import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -29,19 +28,17 @@ import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.imageResource
-import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.Black_alpha_30
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.Black_alpha_30
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_EXTRA_LARGE
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_LARGE
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_MEDIUM
-import com.abizer_r.quickedit.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
@OptIn(ExperimentalFoundationApi::class)
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreen.kt
index d4abe49..4cbaab0 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreen.kt
@@ -1,13 +1,10 @@
package com.abizer_r.quickedit.ui.mainScreen
import android.Manifest
-import android.content.res.Configuration
import android.graphics.Bitmap
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.background
-import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -16,18 +13,16 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.tooling.preview.Preview
import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.lifecycleScope
-import com.abizer_r.quickedit.theme.QuickEditTheme
import com.abizer_r.quickedit.ui.common.permission.PermissionDialog
import com.abizer_r.quickedit.ui.common.permission.StoragePermissionTextProvider
import com.abizer_r.quickedit.utils.FileUtils
import com.abizer_r.quickedit.utils.PermissionUtils
-import com.abizer_r.quickedit.utils.getActivity
-import com.abizer_r.quickedit.utils.getOpenAppSettingsIntent
+import io.github.abizerr.quickedit.ui.utils.getActivity
+import io.github.abizerr.quickedit.ui.utils.getOpenAppSettingsIntent
import com.abizer_r.quickedit.utils.other.bitmap.BitmapStatus
import com.abizer_r.quickedit.utils.other.bitmap.BitmapUtils
import kotlinx.coroutines.Dispatchers
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenButtonsLayout.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenButtonsLayout.kt
index fd07d43..aade61f 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenButtonsLayout.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenButtonsLayout.kt
@@ -21,7 +21,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.abizer_r.quickedit.R
import com.abizer_r.quickedit.ui.common.LoadingView
-import com.abizer_r.quickedit.utils.toast
+import io.github.abizerr.quickedit.ui.utils.toast
@Composable
fun MainScreenButtonsLayout(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenLayout.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenLayout.kt
index 3c9e752..75c8851 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenLayout.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/mainScreen/MainScreenLayout.kt
@@ -21,12 +21,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.abizer_r.quickedit.ui.common.AppIconWithName
import com.abizer_r.quickedit.ui.common.ErrorView
import com.abizer_r.quickedit.ui.common.PermissionDeniedView
import com.abizer_r.quickedit.utils.PermissionUtils.PermissionTypes
-import com.abizer_r.quickedit.utils.getOpenAppSettingsIntent
+import io.github.abizerr.quickedit.ui.utils.getOpenAppSettingsIntent
import com.abizer_r.quickedit.utils.other.bitmap.BitmapStatus
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditApp.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditApp.kt
index c484571..6a420a9 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditApp.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditApp.kt
@@ -10,9 +10,24 @@ import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.engine.api.EditImage
+import io.github.abizerr.quickedit.engine.api.SaveFormat
+import io.github.abizerr.quickedit.tool.crop.CropContribution
+import io.github.abizerr.quickedit.tool.draw.DrawToolContribution
+import io.github.abizerr.quickedit.tool.effects.EffectsContribution
+import io.github.abizerr.quickedit.tool.text.TextContribution
+import io.github.abizerr.quickedit.ui.api.QuickEditConfig
+import io.github.abizerr.quickedit.ui.api.QuickEditEditor
+import io.github.abizerr.quickedit.ui.utils.getDummyBitmap
+/**
+ * Legacy entry kept for binary/source compatibility.
+ * Internally delegates to the new :quickedit-compose-ui editor.
+ *
+ */
@Composable
fun QuickEditApp(
initialImageUri: Uri? = null
@@ -28,7 +43,35 @@ fun QuickEditApp(
.padding(innerPadding)
.background(MaterialTheme.colorScheme.background)
) {
+ // Old navigation (removed intentionally)
QuickEditNavigation(initialImageUri)
+
+
+// val editImage: EditImage? = initialImageUri?.let {
+// EditImage.FromUri(it)
+// } ?: EditImage.FromBitmap(getDummyBitmap())
+//
+// val tools = remember {
+// listOf(
+// CropContribution(),
+// DrawToolContribution(),
+// TextContribution(),
+// EffectsContribution()
+// )
+// }
+//
+// QuickEditEditor(
+// image = editImage,
+// config = QuickEditConfig(
+// tools = tools,
+// maxUndo = 20,
+// defaultFormat = SaveFormat.Jpeg(90)
+// ),
+//// state = QuickEditState(),
+// onSave = {
+// // TODO (revamp): map Result back if needed
+// }
+// )
}
}
}
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditNavigation.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditNavigation.kt
index 0ee17e7..64a4a8a 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditNavigation.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/navigation/QuickEditNavigation.kt
@@ -4,17 +4,9 @@ import android.graphics.Bitmap
import android.net.Uri
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
-import androidx.compose.animation.core.tween
-import androidx.compose.animation.slideIn
-import androidx.compose.animation.slideOut
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.unit.IntOffset
import androidx.hilt.navigation.compose.hiltViewModel
-import androidx.lifecycle.compose.LocalLifecycleOwner
-import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavOptions
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
@@ -27,18 +19,11 @@ import com.abizer_r.quickedit.ui.editorScreen.EditorScreenState
import com.abizer_r.quickedit.ui.effectsMode.EffectsModeScreen
import com.abizer_r.quickedit.ui.mainScreen.MainScreen
import com.abizer_r.quickedit.ui.textMode.TextModeScreen
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
-import com.abizer_r.quickedit.utils.other.anim.enterTransition
-import com.abizer_r.quickedit.utils.other.anim.exitTransition
-import com.abizer_r.quickedit.utils.other.anim.popEnterTransition
-import com.abizer_r.quickedit.utils.other.anim.popExitTransition
-import com.abizer_r.quickedit.utils.other.bitmap.BitmapUtils
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.launch
+import io.github.abizerr.quickedit.ui.utils.anim.enterTransition
+import io.github.abizerr.quickedit.ui.utils.anim.exitTransition
+import io.github.abizerr.quickedit.ui.utils.anim.popEnterTransition
+import io.github.abizerr.quickedit.ui.utils.anim.popExitTransition
@Composable
fun QuickEditNavigation(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeScreen.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeScreen.kt
index aa1f7f1..3ef8eba 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeScreen.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeScreen.kt
@@ -1,7 +1,6 @@
package com.abizer_r.quickedit.ui.textMode
import android.graphics.Bitmap
-import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
@@ -34,12 +33,11 @@ import androidx.constraintlayout.compose.Dimension
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
-import com.abizer_r.quickedit.utils.ImmutableList
import com.abizer_r.quickedit.utils.textMode.blurBackground.BlurBitmapBackground
-import com.abizer_r.quickedit.utils.defaultErrorToast
-import com.abizer_r.quickedit.ui.common.AnimatedToolbarContainer
-import com.abizer_r.quickedit.ui.common.bottomToolbarModifier
-import com.abizer_r.quickedit.ui.common.topToolbarModifier
+import io.github.abizerr.quickedit.ui.utils.defaultErrorToast
+import io.github.abizerr.quickedit.ui.common.AnimatedToolbarContainer
+import io.github.abizerr.quickedit.ui.common.bottomToolbarModifier
+import io.github.abizerr.quickedit.ui.common.topToolbarModifier
import com.abizer_r.quickedit.ui.textMode.TextModeEvent.*
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.BottomToolBarStatic
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_MEDIUM
@@ -48,14 +46,11 @@ import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarE
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
import com.abizer_r.quickedit.ui.editorScreen.topToolbar.TextModeTopToolbar
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.TextModeToolbarExtension
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.caseOptions.TextCaseType
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleAttr
import com.abizer_r.quickedit.ui.textMode.textEditorLayout.TextEditorLayout
import com.abizer_r.quickedit.ui.textMode.textEditorLayout.TextEditorState
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableTextBoxState
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import com.abizer_r.quickedit.utils.other.bitmap.ImmutableBitmap
-import com.abizer_r.quickedit.utils.textMode.TextModeUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils.BorderForSelectedViews
import com.abizer_r.quickedit.utils.textMode.TextModeUtils.DrawAllTransformableViews
import com.smarttoolfactory.screenshot.ImageResult
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeViewModel.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeViewModel.kt
index d8af534..b023486 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeViewModel.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/TextModeViewModel.kt
@@ -17,7 +17,7 @@ import com.abizer_r.quickedit.ui.transformableViews.base.TransformableTextBoxSta
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableBoxEvents
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableBoxState
import com.abizer_r.quickedit.utils.ImmutableList
-import com.abizer_r.quickedit.utils.other.anim.AnimUtils
+import io.github.abizerr.quickedit.ui.utils.anim.AnimUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils.isTextModeItem
import dagger.hilt.android.lifecycle.HiltViewModel
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/TextModeToolbarExtension.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/TextModeToolbarExtension.kt
index 2c63164..07eadf4 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/TextModeToolbarExtension.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/TextModeToolbarExtension.kt
@@ -14,8 +14,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.TextModeToolbarExtensionEvent.*
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.fontFamilyOptions.FontFamilyOptions
@@ -25,7 +25,7 @@ import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptio
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleOptions
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleAttr
import com.abizer_r.quickedit.utils.drawMode.DrawModeUtils
-import com.abizer_r.quickedit.utils.textMode.FontUtils
+import io.github.abizerr.quickedit.ui.utils.font.FontUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils
/**
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontFamilyOptions.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontFamilyOptions.kt
index fdff2d6..b342d43 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontFamilyOptions.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/fontFamilyOptions/FontFamilyOptions.kt
@@ -1,56 +1,31 @@
package com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.fontFamilyOptions
import android.content.res.Configuration
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.outlined.FormatAlignLeft
-import androidx.compose.material.icons.automirrored.outlined.FormatAlignRight
-import androidx.compose.material.icons.filled.FormatAlignCenter
-import androidx.compose.material.icons.filled.FormatBold
-import androidx.compose.material.icons.filled.FormatItalic
-import androidx.compose.material.icons.filled.FormatStrikethrough
-import androidx.compose.material.icons.filled.FormatUnderlined
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
-import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
-import com.abizer_r.quickedit.ui.common.toolbar.SelectableToolbarItem
-import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.alignmentOptions.TextAlignOptions
-import com.abizer_r.quickedit.utils.ImmutableList
-import com.abizer_r.quickedit.utils.defaultTextColor
-import com.abizer_r.quickedit.utils.textMode.FontUtils
-import com.abizer_r.quickedit.utils.textMode.TextModeUtils
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.utils.font.FontItem
+import io.github.abizerr.quickedit.ui.utils.defaultTextColor
+import io.github.abizerr.quickedit.ui.utils.font.FontUtils
@Composable
fun FontFamilyOptions(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/alignmentOptions/AlignmentOptions.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/alignmentOptions/AlignmentOptions.kt
index 0799ed2..fb58fa2 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/alignmentOptions/AlignmentOptions.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/alignmentOptions/AlignmentOptions.kt
@@ -1,36 +1,25 @@
package com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.alignmentOptions
import android.content.res.Configuration
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.FormatAlignLeft
import androidx.compose.material.icons.automirrored.outlined.FormatAlignRight
import androidx.compose.material.icons.filled.FormatAlignCenter
-import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.common.toolbar.SelectableToolbarItem
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleAttr
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleOptions
import com.abizer_r.quickedit.utils.textMode.TextModeUtils
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/caseOptions/TextCaseOptions.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/caseOptions/TextCaseOptions.kt
index c1558cf..c4a914b 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/caseOptions/TextCaseOptions.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/caseOptions/TextCaseOptions.kt
@@ -1,46 +1,23 @@
package com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.caseOptions
import android.content.res.Configuration
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.wrapContentWidth
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.outlined.FormatAlignLeft
-import androidx.compose.material.icons.automirrored.outlined.FormatAlignRight
-import androidx.compose.material.icons.filled.FormatAlignCenter
-import androidx.compose.material.icons.filled.FormatBold
-import androidx.compose.material.icons.filled.FormatItalic
-import androidx.compose.material.icons.filled.FormatStrikethrough
-import androidx.compose.material.icons.filled.FormatUnderlined
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
-import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.common.toolbar.SelectableToolbarItem
-import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.alignmentOptions.TextAlignOptions
-import com.abizer_r.quickedit.utils.textMode.TextModeUtils
@Composable
fun TextCaseOptions(
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/styleOptions/TextStyleOptions.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/styleOptions/TextStyleOptions.kt
index e74ec79..c022479 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/styleOptions/TextStyleOptions.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/bottomToolbarExtension/textFormatOptions/styleOptions/TextStyleOptions.kt
@@ -1,36 +1,26 @@
package com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions
import android.content.res.Configuration
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FormatBold
import androidx.compose.material.icons.filled.FormatItalic
import androidx.compose.material.icons.filled.FormatStrikethrough
import androidx.compose.material.icons.filled.FormatUnderlined
-import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.common.toolbar.SelectableToolbarItem
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/textEditorLayout/TextEditorLayout.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/textEditorLayout/TextEditorLayout.kt
index f687d4b..99da489 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/textEditorLayout/TextEditorLayout.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/textEditorLayout/TextEditorLayout.kt
@@ -8,7 +8,6 @@ import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
@@ -23,7 +22,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
-import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -33,7 +31,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
import com.abizer_r.quickedit.ui.editorScreen.topToolbar.TextModeTopToolbar
import com.abizer_r.quickedit.utils.textMode.colorList.ColorListFullWidth
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/topToolbar/TextModeTopToolbar.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/topToolbar/TextModeTopToolbar.kt
index e0b9d61..da960cb 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/topToolbar/TextModeTopToolbar.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/textMode/topToolbar/TextModeTopToolbar.kt
@@ -21,8 +21,8 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.TOOLBAR_HEIGHT_SMALL
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/TransformableTextBox.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/TransformableTextBox.kt
index c119794..7491435 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/TransformableTextBox.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/TransformableTextBox.kt
@@ -10,19 +10,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.caseOptions.TextCaseType
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextDecoration.*
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableTextBoxState
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableBox
import com.abizer_r.quickedit.ui.transformableViews.base.TransformableBoxEvents
-import com.abizer_r.quickedit.utils.textMode.FontUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils.getDefaultEditorTextStyle
@Composable
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBox.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBox.kt
index d73c996..6996007 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBox.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBox.kt
@@ -35,7 +35,6 @@ import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
-import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -45,7 +44,7 @@ import androidx.compose.ui.unit.coerceIn
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
import androidx.constraintlayout.compose.ConstraintLayout
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.abizer_r.quickedit.ui.transformableViews.TransformableTextBox
import com.abizer_r.quickedit.utils.drawMode.DrawModeUtils
import com.abizer_r.quickedit.utils.drawMode.pxToDp
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBoxState.kt b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBoxState.kt
index 32d717f..fd901e0 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBoxState.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/ui/transformableViews/base/TransformableBoxState.kt
@@ -8,7 +8,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.TextUnit
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.caseOptions.TextCaseType
import com.abizer_r.quickedit.ui.textMode.bottomToolbarExtension.textFormatOptions.styleOptions.TextStyleAttr
-import com.abizer_r.quickedit.utils.textMode.FontUtils
+import io.github.abizerr.quickedit.ui.utils.font.FontUtils
import com.abizer_r.quickedit.utils.textMode.TextModeUtils
abstract class TransformableBoxState {
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawModeUtils.kt b/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawModeUtils.kt
index 117e133..cf2c8bd 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawModeUtils.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/utils/drawMode/DrawModeUtils.kt
@@ -2,16 +2,12 @@ package com.abizer_r.quickedit.utils.drawMode
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.BrushShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.AbstractShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.LineShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.OvalShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.RectangleShape
-import com.abizer_r.quickedit.ui.drawMode.drawingCanvas.drawingTool.shapes.ShapeType
import com.abizer_r.quickedit.ui.editorScreen.bottomToolbar.state.BottomToolbarItem
+import io.github.abizerr.quickedit.engine.drawspec.ShapeType
+import io.github.abizerr.quickedit.tool.draw.models.DrawToolItem
+import io.github.abizerr.quickedit.tool.draw.util.DrawingConstants
import kotlin.math.cos
import kotlin.math.sin
@@ -19,6 +15,25 @@ object DrawModeUtils {
const val DEFAULT_SELECTED_INDEX = 2
+ fun getDefaultDrawToolItemsList(): ArrayList {
+ return arrayListOf(
+ DrawToolItem.ColorItem,
+ DrawToolItem.PanItem,
+ DrawToolItem.BrushTool(
+ width = DrawingConstants.DEFAULT_STROKE_WIDTH,
+ opacity = DrawingConstants.DEFAULT_STROKE_OPACITY
+ ),
+ DrawToolItem.ShapeTool(
+ width = DrawingConstants.DEFAULT_STROKE_WIDTH,
+ opacity = DrawingConstants.DEFAULT_STROKE_OPACITY,
+ shapeType = ShapeType.LINE
+ ),
+ DrawToolItem.EraserTool(
+ width = DrawingConstants.DEFAULT_STROKE_WIDTH
+ ),
+ )
+ }
+
fun getDefaultBottomToolbarItemsList(): ArrayList {
return arrayListOf(
BottomToolbarItem.ColorItem,
@@ -57,105 +72,6 @@ object DrawModeUtils {
}
-fun BottomToolbarItem.getShape(
- selectedColor: Color,
- scale: Float = 1f,
-): AbstractShape {
- return when (val toolbarItem = this) {
- is BottomToolbarItem.BrushTool -> {
- BrushShape(
- color = selectedColor,
- width = toolbarItem.width / scale,
- alpha = toolbarItem.opacity / 100f
- )
- }
-
- is BottomToolbarItem.ShapeTool -> when (toolbarItem.shapeType) {
- ShapeType.LINE -> LineShape(
- color = selectedColor,
- width = toolbarItem.width / scale,
- alpha = toolbarItem.opacity / 100f
- )
-
- ShapeType.OVAL -> OvalShape(
- color = selectedColor,
- width = toolbarItem.width / scale,
- alpha = toolbarItem.opacity / 100f
- )
-
- ShapeType.RECTANGLE -> RectangleShape(
- color = selectedColor,
- width = toolbarItem.width / scale,
- alpha = toolbarItem.opacity / 100f
- )
- }
-
- else -> {
- /**
- * this else block represents the EraserTool, as any other item (ColorItem, PanItem) won't be sent here
- */
- val width =
- if (toolbarItem is BottomToolbarItem.EraserTool) toolbarItem.width
- else DrawingConstants.DEFAULT_STROKE_WIDTH
- BrushShape(
- isEraser = true,
- width = width / scale
- )
- }
- }
-}
-
-fun BottomToolbarItem.getWidthOrNull(): Float? {
- return when (this) {
- is BottomToolbarItem.BrushTool -> this.width
- is BottomToolbarItem.EraserTool -> this.width
- is BottomToolbarItem.ShapeTool -> this.width
- else -> null
- }
-}
-
-fun BottomToolbarItem.setWidthIfPossible(mWidth: Float): BottomToolbarItem {
- when (this) {
- is BottomToolbarItem.BrushTool -> this.width = mWidth
- is BottomToolbarItem.EraserTool -> this.width = mWidth
- is BottomToolbarItem.ShapeTool -> this.width = mWidth
- else -> {}
- }
- return this
-}
-
-fun BottomToolbarItem.getOpacityOrNull(): Float? {
- return when (this) {
- is BottomToolbarItem.BrushTool -> this.opacity
- is BottomToolbarItem.ShapeTool -> this.opacity
- else -> null
- }
-}
-
-fun BottomToolbarItem.setOpacityIfPossible(mOpacity: Float): BottomToolbarItem {
- when (this) {
- is BottomToolbarItem.BrushTool -> this.opacity = mOpacity
- is BottomToolbarItem.ShapeTool -> this.opacity = mOpacity
- else -> {}
- }
- return this
-}
-
-fun BottomToolbarItem.getShapeTypeOrNull(): ShapeType? {
- return when (this) {
- is BottomToolbarItem.ShapeTool -> this.shapeType
- else -> null
- }
-}
-
-fun BottomToolbarItem.setShapeTypeIfPossible(mShapeType: ShapeType): BottomToolbarItem {
- when (this) {
- is BottomToolbarItem.ShapeTool -> this.shapeType = mShapeType
- else -> {}
- }
- return this
-}
-
@Composable
fun Dp.toPx(): Float {
return with(LocalDensity.current) {
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/blurBackground/BlurBitmapBackground.kt b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/blurBackground/BlurBitmapBackground.kt
index f276aeb..e14bd10 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/blurBackground/BlurBitmapBackground.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/blurBackground/BlurBitmapBackground.kt
@@ -10,12 +10,11 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.tooling.preview.Preview
import com.abizer_r.quickedit.R
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
import com.skydoves.cloudy.cloudy
@OptIn(ExperimentalComposeUiApi::class)
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/ColorListFullWidth.kt b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/ColorListFullWidth.kt
index 94c5e6e..2846f4a 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/ColorListFullWidth.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/ColorListFullWidth.kt
@@ -14,8 +14,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
-import com.abizer_r.quickedit.theme.ToolBarBackgroundColor
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.ToolBarBackgroundColor
import com.abizer_r.quickedit.utils.ColorUtils
import com.abizer_r.quickedit.utils.ImmutableList
diff --git a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/SelectableColor.kt b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/SelectableColor.kt
index f68ef44..ca11548 100644
--- a/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/SelectableColor.kt
+++ b/quickedit/src/main/java/com/abizer_r/quickedit/utils/textMode/colorList/SelectableColor.kt
@@ -16,7 +16,7 @@ import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import com.abizer_r.quickedit.theme.QuickEditTheme
+import io.github.abizerr.quickedit.ui.theme.QuickEditTheme
/**
* The total size of this item is the adding of [itemSize] and [selectedBorderWidth]
diff --git a/quickedit/src/main/res/font/edu_vicwant_bold.ttf b/quickedit/src/main/res/font/edu_vicwant_bold.ttf
deleted file mode 100644
index 316d7a4..0000000
Binary files a/quickedit/src/main/res/font/edu_vicwant_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/matemasie_regular.ttf b/quickedit/src/main/res/font/matemasie_regular.ttf
deleted file mode 100644
index 63e3a0b..0000000
Binary files a/quickedit/src/main/res/font/matemasie_regular.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/moderustic_bold.ttf b/quickedit/src/main/res/font/moderustic_bold.ttf
deleted file mode 100644
index d920e4f..0000000
Binary files a/quickedit/src/main/res/font/moderustic_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/montserrat_bold.ttf b/quickedit/src/main/res/font/montserrat_bold.ttf
deleted file mode 100644
index 0927b81..0000000
Binary files a/quickedit/src/main/res/font/montserrat_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/montserrat_bold_italic.ttf b/quickedit/src/main/res/font/montserrat_bold_italic.ttf
deleted file mode 100644
index 02f5784..0000000
Binary files a/quickedit/src/main/res/font/montserrat_bold_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/montserrat_italic.ttf b/quickedit/src/main/res/font/montserrat_italic.ttf
deleted file mode 100644
index cff3ceb..0000000
Binary files a/quickedit/src/main/res/font/montserrat_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/montserrat_regular.ttf b/quickedit/src/main/res/font/montserrat_regular.ttf
deleted file mode 100644
index f4a266d..0000000
Binary files a/quickedit/src/main/res/font/montserrat_regular.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/oswald_bold.ttf b/quickedit/src/main/res/font/oswald_bold.ttf
deleted file mode 100644
index b9c6e37..0000000
Binary files a/quickedit/src/main/res/font/oswald_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/oswald_regular.ttf b/quickedit/src/main/res/font/oswald_regular.ttf
deleted file mode 100644
index 5903df4..0000000
Binary files a/quickedit/src/main/res/font/oswald_regular.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/playwrite_italic.ttf b/quickedit/src/main/res/font/playwrite_italic.ttf
deleted file mode 100644
index e27a6a4..0000000
Binary files a/quickedit/src/main/res/font/playwrite_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/playwrite_regular.ttf b/quickedit/src/main/res/font/playwrite_regular.ttf
deleted file mode 100644
index 73e55d7..0000000
Binary files a/quickedit/src/main/res/font/playwrite_regular.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/poppins_bold_italic.ttf b/quickedit/src/main/res/font/poppins_bold_italic.ttf
deleted file mode 100644
index e61e8e8..0000000
Binary files a/quickedit/src/main/res/font/poppins_bold_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/poppins_italic.ttf b/quickedit/src/main/res/font/poppins_italic.ttf
deleted file mode 100644
index 12b7b3c..0000000
Binary files a/quickedit/src/main/res/font/poppins_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/roboto_bold.ttf b/quickedit/src/main/res/font/roboto_bold.ttf
deleted file mode 100644
index e64db79..0000000
Binary files a/quickedit/src/main/res/font/roboto_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/roboto_bold_italic.ttf b/quickedit/src/main/res/font/roboto_bold_italic.ttf
deleted file mode 100644
index 5e39ae9..0000000
Binary files a/quickedit/src/main/res/font/roboto_bold_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/roboto_italic.ttf b/quickedit/src/main/res/font/roboto_italic.ttf
deleted file mode 100644
index 65498ee..0000000
Binary files a/quickedit/src/main/res/font/roboto_italic.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/roboto_regular.ttf b/quickedit/src/main/res/font/roboto_regular.ttf
deleted file mode 100644
index 2d116d9..0000000
Binary files a/quickedit/src/main/res/font/roboto_regular.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/teko_bold.ttf b/quickedit/src/main/res/font/teko_bold.ttf
deleted file mode 100644
index f9f1e84..0000000
Binary files a/quickedit/src/main/res/font/teko_bold.ttf and /dev/null differ
diff --git a/quickedit/src/main/res/font/teko_regular.ttf b/quickedit/src/main/res/font/teko_regular.ttf
deleted file mode 100644
index 553ac65..0000000
Binary files a/quickedit/src/main/res/font/teko_regular.ttf and /dev/null differ
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a9a9ccb..5d50d24 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -15,5 +15,11 @@ dependencyResolutionManagement {
}
rootProject.name = "QuickEdit"
-include(":app")
-include(":quickedit")
\ No newline at end of file
+include(":app-sample")
+include(":quickedit")
+include(":quickedit-core-engine")
+include(":quickedit-ui")
+include(":quickedit-tool-draw")
+include(":quickedit-tool-text")
+include(":quickedit-tool-crop")
+include(":quickedit-tool-effects")