@imgly/editor-react-native 1.72.3 → 1.73.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/IMGLYEditorModule.podspec +23 -0
- package/android/build.gradle +9 -6
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/assets/scene/apparel.scene +1 -0
- package/android/src/main/assets/scene/design.scene +1 -0
- package/android/src/main/assets/scene/postcard.scene +1 -0
- package/android/src/main/assets/scene/video.scene +1 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/ApparelConfigurationBuilder.kt +113 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnCreate.kt +190 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/callback/OnLoaded.kt +88 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Dock.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/apparel/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/DesignConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnCreate.kt +162 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/callback/OnLoaded.kt +10 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Dock.kt +35 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/design/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/PhotoConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnCreate.kt +143 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/callback/OnLoaded.kt +49 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Dock.kt +43 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/NavigationBar.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/photo/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/PostcardConfigurationBuilder.kt +106 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnCreate.kt +149 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnExport.kt +82 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/callback/OnLoaded.kt +58 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Dock.kt +243 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/InspectorBar.kt +52 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/NavigationBar.kt +76 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/component/Overlay.kt +15 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/postcard/ext/Engine.kt +107 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/EditorActivity.kt +37 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/VideoConfigurationBuilder.kt +135 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnCreate.kt +191 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnExport.kt +98 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/callback/OnLoaded.kt +20 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/BottomPanel.kt +13 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/CanvasMenu.kt +45 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Dock.kt +71 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/InspectorBar.kt +68 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/NavigationBar.kt +57 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/component/Overlay.kt +421 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/CheckCircleOutline.kt +79 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/ErrorOutline.kt +92 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/iconPack/IconPack.kt +14 -0
- package/android/src/main/kotlin/ly/img/editor/configuration/video/model/ExportStatus.kt +39 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/activity/EditorActivity.kt +2 -0
- package/android/src/main/kotlin/ly/img/editor/reactnative/module/builder/EditorBuilder.kt +240 -282
- package/ios/Extensions/OnCreate+.swift +38 -62
- package/ios/IMGLYEditorModule.swift +10 -1
- package/ios/Model/EditorBuilder.swift +132 -225
- package/ios/Model/ModalEditorConfiguration.swift +40 -0
- package/ios/Model/Source.swift +8 -0
- package/ios/StarterKits/Apparel/ApparelEditorConfiguration.swift +46 -0
- package/ios/StarterKits/Apparel/ApparelEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Apparel/callbacks/OnChanged+Apparel.swift +116 -0
- package/ios/StarterKits/Apparel/callbacks/OnCreate+Apparel.swift +197 -0
- package/ios/StarterKits/Apparel/callbacks/OnExport+Apparel.swift +29 -0
- package/ios/StarterKits/Apparel/components/CanvasMenu+Apparel.swift +22 -0
- package/ios/StarterKits/Apparel/components/Dock+Apparel.swift +19 -0
- package/ios/StarterKits/Apparel/components/InspectorBar+Apparel.swift +35 -0
- package/ios/StarterKits/Apparel/components/NavigationBar+Apparel.swift +26 -0
- package/ios/StarterKits/Design/DesignEditorConfiguration.swift +43 -0
- package/ios/StarterKits/Design/DesignEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Design/callbacks/OnCreate+Design.swift +131 -0
- package/ios/StarterKits/Design/callbacks/OnExport+Design.swift +30 -0
- package/ios/StarterKits/Design/components/CanvasMenu+Design.swift +22 -0
- package/ios/StarterKits/Design/components/Dock+Design.swift +23 -0
- package/ios/StarterKits/Design/components/InspectorBar+Design.swift +35 -0
- package/ios/StarterKits/Design/components/NavigationBar+Design.swift +24 -0
- package/ios/StarterKits/Photo/PhotoEditorConfiguration.swift +48 -0
- package/ios/StarterKits/Photo/PhotoEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Photo/callbacks/OnChanged+Photo.swift +25 -0
- package/ios/StarterKits/Photo/callbacks/OnCreate+Photo.swift +138 -0
- package/ios/StarterKits/Photo/callbacks/OnExport+Photo.swift +29 -0
- package/ios/StarterKits/Photo/callbacks/OnLoaded+Photo.swift +18 -0
- package/ios/StarterKits/Photo/components/CanvasMenu+Photo.swift +22 -0
- package/ios/StarterKits/Photo/components/Dock+Photo.swift +23 -0
- package/ios/StarterKits/Photo/components/InspectorBar+Photo.swift +39 -0
- package/ios/StarterKits/Photo/components/NavigationBar+Photo.swift +24 -0
- package/ios/StarterKits/Photo/examples/ExampleForceCrop.swift +30 -0
- package/ios/StarterKits/Postcard/PostcardEditorConfiguration.swift +45 -0
- package/ios/StarterKits/Postcard/PostcardEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Postcard/callbacks/OnChanged+Postcard.swift +92 -0
- package/ios/StarterKits/Postcard/callbacks/OnCreate+Postcard.swift +127 -0
- package/ios/StarterKits/Postcard/callbacks/OnExport+Postcard.swift +29 -0
- package/ios/StarterKits/Postcard/components/CanvasMenu+Postcard.swift +22 -0
- package/ios/StarterKits/Postcard/components/Dock+Postcard.swift +34 -0
- package/ios/StarterKits/Postcard/components/DockButtons+Postcard.swift +129 -0
- package/ios/StarterKits/Postcard/components/InspectorBar+Postcard.swift +35 -0
- package/ios/StarterKits/Postcard/components/NavigationBar+Postcard.swift +38 -0
- package/ios/StarterKits/Video/VideoEditorConfiguration.swift +54 -0
- package/ios/StarterKits/Video/VideoEditorStarterKit.swift +30 -0
- package/ios/StarterKits/Video/callbacks/OnCreate+Video.swift +137 -0
- package/ios/StarterKits/Video/callbacks/OnExport+Video.swift +46 -0
- package/ios/StarterKits/Video/components/BottomPanel+Video.swift +16 -0
- package/ios/StarterKits/Video/components/CanvasMenu+Video.swift +22 -0
- package/ios/StarterKits/Video/components/Dock+Video.swift +30 -0
- package/ios/StarterKits/Video/components/InspectorBar+Video.swift +43 -0
- package/ios/StarterKits/Video/components/NavigationBar+Video.swift +32 -0
- package/ios/StarterKits/Video/examples/ExampleVideoDurationConstraints.swift +23 -0
- package/ios/StarterKits/apparel-ui-b-empty.scene +1 -0
- package/ios/StarterKits/design-ui-empty.scene +1 -0
- package/ios/StarterKits/photo-ui-empty.png +0 -0
- package/ios/StarterKits/postcard-empty.scene +1 -0
- package/ios/StarterKits/video-empty.scene +1 -0
- package/package.json +1 -1
- package/src/NativeIMGLYEditor.ts +1 -1
- package/ios/View/ModalEditor.swift +0 -43
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package ly.img.editor.configuration.video.component
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.Composable
|
|
4
|
+
import ly.img.editor.core.component.Timeline
|
|
5
|
+
import ly.img.editor.core.component.remember
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The configuration of the component that is displayed over the editor. It is useful if you want to display a popup dialog or anything in the
|
|
9
|
+
* overlay.
|
|
10
|
+
* Implementation shows [Timeline] in the bottom panel.
|
|
11
|
+
*/
|
|
12
|
+
@Composable
|
|
13
|
+
fun rememberBottomPanel() = Timeline.remember()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.video.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import ly.img.editor.configuration.video.VideoConfigurationBuilder
|
|
7
|
+
import ly.img.editor.core.component.CanvasMenu
|
|
8
|
+
import ly.img.editor.core.component.EditorComponentId
|
|
9
|
+
import ly.img.editor.core.component.remember
|
|
10
|
+
import ly.img.editor.core.component.rememberBringForward
|
|
11
|
+
import ly.img.editor.core.component.rememberDelete
|
|
12
|
+
import ly.img.editor.core.component.rememberDuplicate
|
|
13
|
+
import ly.img.editor.core.component.rememberSelectGroup
|
|
14
|
+
import ly.img.editor.core.component.rememberSendBackward
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The configuration of the component that is displayed as horizontal list of items next to
|
|
18
|
+
* the selected design block.
|
|
19
|
+
*/
|
|
20
|
+
@Composable
|
|
21
|
+
fun VideoConfigurationBuilder.rememberCanvasMenu() = CanvasMenu.remember {
|
|
22
|
+
listBuilder = {
|
|
23
|
+
CanvasMenu.ListBuilder.remember {
|
|
24
|
+
add { CanvasMenu.Button.rememberSelectGroup() }
|
|
25
|
+
if (editorContext.isSelectionInGroup) {
|
|
26
|
+
add {
|
|
27
|
+
CanvasMenu.Divider.remember {
|
|
28
|
+
id = { EditorComponentId("ly.img.component.canvasMenu.divider1") }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
add { CanvasMenu.Button.rememberBringForward() }
|
|
33
|
+
add { CanvasMenu.Button.rememberSendBackward() }
|
|
34
|
+
if (editorContext.canSelectionMove) {
|
|
35
|
+
add {
|
|
36
|
+
CanvasMenu.Divider.remember {
|
|
37
|
+
id = { EditorComponentId("ly.img.component.canvasMenu.divider2") }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
add { CanvasMenu.Button.rememberDuplicate() }
|
|
42
|
+
add { CanvasMenu.Button.rememberDelete() }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter", "UnusedFlow")
|
|
2
|
+
@file:OptIn(ExperimentalCoroutinesApi::class)
|
|
3
|
+
|
|
4
|
+
package ly.img.editor.configuration.video.component
|
|
5
|
+
|
|
6
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
7
|
+
import androidx.compose.runtime.Composable
|
|
8
|
+
import androidx.compose.runtime.remember
|
|
9
|
+
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
10
|
+
import ly.img.editor.configuration.video.VideoConfigurationBuilder
|
|
11
|
+
import ly.img.editor.core.component.Dock
|
|
12
|
+
import ly.img.editor.core.component.EditorTrigger
|
|
13
|
+
import ly.img.editor.core.component.remember
|
|
14
|
+
import ly.img.editor.core.component.rememberAudiosLibrary
|
|
15
|
+
import ly.img.editor.core.component.rememberOverlaysLibrary
|
|
16
|
+
import ly.img.editor.core.component.rememberReorder
|
|
17
|
+
import ly.img.editor.core.component.rememberResizeAll
|
|
18
|
+
import ly.img.editor.core.component.rememberStickersAndShapesLibrary
|
|
19
|
+
import ly.img.editor.core.component.rememberSystemCamera
|
|
20
|
+
import ly.img.editor.core.component.rememberSystemGallery
|
|
21
|
+
import ly.img.editor.core.component.rememberTextLibrary
|
|
22
|
+
import ly.img.editor.core.component.rememberVoiceoverRecord
|
|
23
|
+
import ly.img.editor.core.iconpack.AddCameraBackground
|
|
24
|
+
import ly.img.editor.core.iconpack.AddGalleryBackground
|
|
25
|
+
import ly.img.editor.core.iconpack.IconPack
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The configuration of the component that is displayed as horizontal list of items at the bottom of the editor.
|
|
29
|
+
*/
|
|
30
|
+
@Composable
|
|
31
|
+
fun VideoConfigurationBuilder.rememberDock() = Dock.remember {
|
|
32
|
+
scope = {
|
|
33
|
+
val activeSceneTrigger by EditorTrigger.remember {
|
|
34
|
+
editorContext.engine.scene.onActiveChanged()
|
|
35
|
+
}
|
|
36
|
+
// Update Dock whenever the active scene changes.
|
|
37
|
+
remember(this, activeSceneTrigger) {
|
|
38
|
+
Dock.Scope(parentScope = this)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
horizontalArrangement = {
|
|
42
|
+
// All buttons should have equal size
|
|
43
|
+
Arrangement.SpaceEvenly
|
|
44
|
+
}
|
|
45
|
+
listBuilder = {
|
|
46
|
+
// highlight-starter-kit-imgly-camera
|
|
47
|
+
Dock.ListBuilder.remember {
|
|
48
|
+
add {
|
|
49
|
+
Dock.Button.rememberSystemGallery {
|
|
50
|
+
vectorIcon = { IconPack.AddGalleryBackground }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
add {
|
|
54
|
+
// As an alternative to the system camera we also provide our own camera tech accessible via [Dock.Button.rememberImglyCamera].
|
|
55
|
+
// In order to make it work the following dependency is required:
|
|
56
|
+
// implementation "ly.img:camera:<same version as editor>".
|
|
57
|
+
Dock.Button.rememberSystemCamera(captureVideo = { true }) {
|
|
58
|
+
vectorIcon = { IconPack.AddCameraBackground }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
add { Dock.Button.rememberOverlaysLibrary() }
|
|
62
|
+
add { Dock.Button.rememberTextLibrary() }
|
|
63
|
+
add { Dock.Button.rememberStickersAndShapesLibrary() }
|
|
64
|
+
add { Dock.Button.rememberAudiosLibrary() }
|
|
65
|
+
add { Dock.Button.rememberVoiceoverRecord() }
|
|
66
|
+
add { Dock.Button.rememberResizeAll() }
|
|
67
|
+
add { Dock.Button.rememberReorder() }
|
|
68
|
+
}
|
|
69
|
+
// highlight-starter-kit-imgly-camera
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.video.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import ly.img.editor.configuration.video.VideoConfigurationBuilder
|
|
7
|
+
import ly.img.editor.core.component.InspectorBar
|
|
8
|
+
import ly.img.editor.core.component.remember
|
|
9
|
+
import ly.img.editor.core.component.rememberAdjustments
|
|
10
|
+
import ly.img.editor.core.component.rememberAnimations
|
|
11
|
+
import ly.img.editor.core.component.rememberBlur
|
|
12
|
+
import ly.img.editor.core.component.rememberClipSpeed
|
|
13
|
+
import ly.img.editor.core.component.rememberCrop
|
|
14
|
+
import ly.img.editor.core.component.rememberDelete
|
|
15
|
+
import ly.img.editor.core.component.rememberDuplicate
|
|
16
|
+
import ly.img.editor.core.component.rememberEditText
|
|
17
|
+
import ly.img.editor.core.component.rememberEffect
|
|
18
|
+
import ly.img.editor.core.component.rememberEnterGroup
|
|
19
|
+
import ly.img.editor.core.component.rememberFillStroke
|
|
20
|
+
import ly.img.editor.core.component.rememberFilter
|
|
21
|
+
import ly.img.editor.core.component.rememberFormatText
|
|
22
|
+
import ly.img.editor.core.component.rememberLayer
|
|
23
|
+
import ly.img.editor.core.component.rememberMoveAsClip
|
|
24
|
+
import ly.img.editor.core.component.rememberMoveAsOverlay
|
|
25
|
+
import ly.img.editor.core.component.rememberReorder
|
|
26
|
+
import ly.img.editor.core.component.rememberReplace
|
|
27
|
+
import ly.img.editor.core.component.rememberSelectGroup
|
|
28
|
+
import ly.img.editor.core.component.rememberShape
|
|
29
|
+
import ly.img.editor.core.component.rememberSplit
|
|
30
|
+
import ly.img.editor.core.component.rememberTextBackground
|
|
31
|
+
import ly.img.editor.core.component.rememberVoiceover
|
|
32
|
+
import ly.img.editor.core.component.rememberVolume
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The configuration of the component that is displayed as horizontal list of items at the
|
|
36
|
+
* bottom of the editor when a design block is selected.
|
|
37
|
+
*/
|
|
38
|
+
@Composable
|
|
39
|
+
fun VideoConfigurationBuilder.rememberInspectorBar() = InspectorBar.remember {
|
|
40
|
+
listBuilder = {
|
|
41
|
+
InspectorBar.ListBuilder.remember {
|
|
42
|
+
add { InspectorBar.Button.rememberVoiceover() } // Voiceover Audio
|
|
43
|
+
add { InspectorBar.Button.rememberReplace() } // Video, Image, Sticker, Audio
|
|
44
|
+
add { InspectorBar.Button.rememberEditText() } // Text
|
|
45
|
+
add { InspectorBar.Button.rememberFormatText() } // Text
|
|
46
|
+
add { InspectorBar.Button.rememberFillStroke() } // Page, Video, Image, Shape, Text
|
|
47
|
+
add { InspectorBar.Button.rememberTextBackground() } // Text
|
|
48
|
+
add { InspectorBar.Button.rememberVolume() } // Video, Audio
|
|
49
|
+
add { InspectorBar.Button.rememberClipSpeed() } // Video
|
|
50
|
+
add { InspectorBar.Button.rememberCrop() } // Video, Image
|
|
51
|
+
add { InspectorBar.Button.rememberAnimations() } // Video, Image, Sticker, Shape, Text
|
|
52
|
+
add { InspectorBar.Button.rememberAdjustments() } // Video, Image
|
|
53
|
+
add { InspectorBar.Button.rememberFilter() } // Video, Image
|
|
54
|
+
add { InspectorBar.Button.rememberEffect() } // Video, Image
|
|
55
|
+
add { InspectorBar.Button.rememberBlur() } // Video, Image
|
|
56
|
+
add { InspectorBar.Button.rememberShape() } // Video, Image, Shape
|
|
57
|
+
add { InspectorBar.Button.rememberSelectGroup() } // Video, Image, Sticker, Shape, Text
|
|
58
|
+
add { InspectorBar.Button.rememberEnterGroup() } // Group
|
|
59
|
+
add { InspectorBar.Button.rememberLayer() } // Video, Image, Sticker, Shape, Text
|
|
60
|
+
add { InspectorBar.Button.rememberSplit() } // Video, Image, Sticker, Shape, Text, Audio
|
|
61
|
+
add { InspectorBar.Button.rememberMoveAsClip() } // Video, Image, Sticker, Shape, Text
|
|
62
|
+
add { InspectorBar.Button.rememberMoveAsOverlay() } // Video, Image, Sticker, Shape, Text
|
|
63
|
+
add { InspectorBar.Button.rememberReorder() } // Video, Image, Sticker, Shape, Text
|
|
64
|
+
add { InspectorBar.Button.rememberDuplicate() } // Video, Image, Sticker, Shape, Text
|
|
65
|
+
add { InspectorBar.Button.rememberDelete() } // Video, Image, Sticker, Shape, Text
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.video.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.runtime.Composable
|
|
6
|
+
import androidx.compose.runtime.remember
|
|
7
|
+
import androidx.compose.ui.Alignment
|
|
8
|
+
import ly.img.editor.configuration.video.VideoConfigurationBuilder
|
|
9
|
+
import ly.img.editor.core.component.EditorTrigger
|
|
10
|
+
import ly.img.editor.core.component.NavigationBar
|
|
11
|
+
import ly.img.editor.core.component.remember
|
|
12
|
+
import ly.img.editor.core.component.rememberCloseEditor
|
|
13
|
+
import ly.img.editor.core.component.rememberExport
|
|
14
|
+
import ly.img.editor.core.component.rememberRedo
|
|
15
|
+
import ly.img.editor.core.component.rememberUndo
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The configuration of the component that is displayed as horizontal list of items at the top of the editor.
|
|
19
|
+
*/
|
|
20
|
+
@Composable
|
|
21
|
+
fun VideoConfigurationBuilder.rememberNavigationBar() = NavigationBar.remember {
|
|
22
|
+
scope = {
|
|
23
|
+
val activeSceneTrigger by EditorTrigger.remember {
|
|
24
|
+
editorContext.engine.scene.onActiveChanged()
|
|
25
|
+
}
|
|
26
|
+
val historyTrigger by EditorTrigger.remember(activeSceneTrigger) {
|
|
27
|
+
editorContext.engine.editor.onHistoryUpdated()
|
|
28
|
+
}
|
|
29
|
+
// Update NavigationBar whenever the active scene or editor history changes.
|
|
30
|
+
remember(this, historyTrigger) {
|
|
31
|
+
NavigationBar.Scope(parentScope = this)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
listBuilder = {
|
|
35
|
+
NavigationBar.ListBuilder.remember {
|
|
36
|
+
aligned(alignment = Alignment.Start) {
|
|
37
|
+
add { NavigationBar.Button.rememberCloseEditor() }
|
|
38
|
+
}
|
|
39
|
+
aligned(alignment = Alignment.End) {
|
|
40
|
+
add { NavigationBar.Button.rememberUndo() }
|
|
41
|
+
add { NavigationBar.Button.rememberRedo() }
|
|
42
|
+
add {
|
|
43
|
+
NavigationBar.Button.rememberExport {
|
|
44
|
+
enabled = {
|
|
45
|
+
// Show export button if the duration of scene is greater than 0
|
|
46
|
+
remember(this) {
|
|
47
|
+
editorContext.engine.scene.get()?.let {
|
|
48
|
+
editorContext.engine.block.getDuration(it) > 0
|
|
49
|
+
} ?: false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
@file:Suppress("UnusedReceiverParameter")
|
|
2
|
+
|
|
3
|
+
package ly.img.editor.configuration.video.component
|
|
4
|
+
|
|
5
|
+
import androidx.compose.animation.core.LinearEasing
|
|
6
|
+
import androidx.compose.animation.core.animateFloat
|
|
7
|
+
import androidx.compose.animation.core.animateFloatAsState
|
|
8
|
+
import androidx.compose.animation.core.infiniteRepeatable
|
|
9
|
+
import androidx.compose.animation.core.rememberInfiniteTransition
|
|
10
|
+
import androidx.compose.animation.core.tween
|
|
11
|
+
import androidx.compose.foundation.Canvas
|
|
12
|
+
import androidx.compose.foundation.background
|
|
13
|
+
import androidx.compose.foundation.gestures.detectTapGestures
|
|
14
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
15
|
+
import androidx.compose.foundation.layout.Box
|
|
16
|
+
import androidx.compose.foundation.layout.Column
|
|
17
|
+
import androidx.compose.foundation.layout.Spacer
|
|
18
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
19
|
+
import androidx.compose.foundation.layout.fillMaxWidth
|
|
20
|
+
import androidx.compose.foundation.layout.height
|
|
21
|
+
import androidx.compose.foundation.layout.navigationBarsPadding
|
|
22
|
+
import androidx.compose.foundation.layout.padding
|
|
23
|
+
import androidx.compose.foundation.layout.size
|
|
24
|
+
import androidx.compose.foundation.progressSemantics
|
|
25
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
26
|
+
import androidx.compose.material3.AlertDialog
|
|
27
|
+
import androidx.compose.material3.ButtonDefaults
|
|
28
|
+
import androidx.compose.material3.Icon
|
|
29
|
+
import androidx.compose.material3.MaterialTheme
|
|
30
|
+
import androidx.compose.material3.ProgressIndicatorDefaults
|
|
31
|
+
import androidx.compose.material3.Surface
|
|
32
|
+
import androidx.compose.material3.Text
|
|
33
|
+
import androidx.compose.material3.TextButton
|
|
34
|
+
import androidx.compose.runtime.Composable
|
|
35
|
+
import androidx.compose.runtime.getValue
|
|
36
|
+
import androidx.compose.runtime.remember
|
|
37
|
+
import androidx.compose.ui.Alignment
|
|
38
|
+
import androidx.compose.ui.Modifier
|
|
39
|
+
import androidx.compose.ui.geometry.Offset
|
|
40
|
+
import androidx.compose.ui.geometry.Size
|
|
41
|
+
import androidx.compose.ui.graphics.Brush
|
|
42
|
+
import androidx.compose.ui.graphics.Color
|
|
43
|
+
import androidx.compose.ui.graphics.StrokeCap
|
|
44
|
+
import androidx.compose.ui.graphics.drawscope.DrawScope
|
|
45
|
+
import androidx.compose.ui.graphics.drawscope.Stroke
|
|
46
|
+
import androidx.compose.ui.graphics.drawscope.rotate
|
|
47
|
+
import androidx.compose.ui.input.pointer.pointerInput
|
|
48
|
+
import androidx.compose.ui.platform.LocalDensity
|
|
49
|
+
import androidx.compose.ui.res.stringResource
|
|
50
|
+
import androidx.compose.ui.text.style.TextAlign
|
|
51
|
+
import androidx.compose.ui.unit.Dp
|
|
52
|
+
import androidx.compose.ui.unit.dp
|
|
53
|
+
import androidx.compose.ui.window.DialogProperties
|
|
54
|
+
import ly.img.editor.configuration.video.VideoConfigurationBuilder
|
|
55
|
+
import ly.img.editor.configuration.video.iconPack.CheckCircleOutline
|
|
56
|
+
import ly.img.editor.configuration.video.iconPack.ErrorOutline
|
|
57
|
+
import ly.img.editor.configuration.video.iconPack.IconPack
|
|
58
|
+
import ly.img.editor.configuration.video.model.ExportStatus
|
|
59
|
+
import ly.img.editor.core.R
|
|
60
|
+
import ly.img.editor.core.component.EditorComponent
|
|
61
|
+
import ly.img.editor.core.component.remember
|
|
62
|
+
import ly.img.editor.core.event.EditorEvent
|
|
63
|
+
import ly.img.editor.core.theme.LocalExtendedColorScheme
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The configuration of the component that is displayed over the editor. It is useful if you want to display a popup dialog or anything in the
|
|
67
|
+
* overlay.
|
|
68
|
+
*/
|
|
69
|
+
@Composable
|
|
70
|
+
fun VideoConfigurationBuilder.rememberOverlay() = EditorComponent.remember {
|
|
71
|
+
decoration = {
|
|
72
|
+
// Other than the main overlay also display export related overlays
|
|
73
|
+
Overlay()
|
|
74
|
+
if (exportStatus != null) {
|
|
75
|
+
ExportOverlay()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The export related overlay composable.
|
|
82
|
+
*
|
|
83
|
+
* @param loading the export loading composable.
|
|
84
|
+
* @param success the export success composable.
|
|
85
|
+
* @param error the export error composable.
|
|
86
|
+
*/
|
|
87
|
+
@Composable
|
|
88
|
+
fun VideoConfigurationBuilder.ExportOverlay(
|
|
89
|
+
loading: @Composable VideoConfigurationBuilder.(ExportStatus.Loading) -> Unit = {
|
|
90
|
+
ExportLoading(it)
|
|
91
|
+
},
|
|
92
|
+
success: @Composable VideoConfigurationBuilder.(ExportStatus.Success) -> Unit = {
|
|
93
|
+
ExportSuccess(it)
|
|
94
|
+
},
|
|
95
|
+
error: @Composable VideoConfigurationBuilder.(ExportStatus.Error) -> Unit = {
|
|
96
|
+
ExportError()
|
|
97
|
+
},
|
|
98
|
+
) {
|
|
99
|
+
Box(
|
|
100
|
+
modifier = Modifier
|
|
101
|
+
.fillMaxSize()
|
|
102
|
+
.background(MaterialTheme.colorScheme.onSurface.copy(alpha = 0.32f))
|
|
103
|
+
.pointerInput(Unit) {
|
|
104
|
+
detectTapGestures {
|
|
105
|
+
// do nothing
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
) {
|
|
109
|
+
Surface(
|
|
110
|
+
modifier = Modifier
|
|
111
|
+
.fillMaxWidth()
|
|
112
|
+
.align(Alignment.BottomStart),
|
|
113
|
+
shape = RoundedCornerShape(
|
|
114
|
+
topStart = 28.0.dp,
|
|
115
|
+
topEnd = 28.0.dp,
|
|
116
|
+
bottomEnd = 0.0.dp,
|
|
117
|
+
bottomStart = 0.0.dp,
|
|
118
|
+
),
|
|
119
|
+
shadowElevation = 16.dp,
|
|
120
|
+
) {
|
|
121
|
+
Box(
|
|
122
|
+
Modifier
|
|
123
|
+
.fillMaxWidth()
|
|
124
|
+
.navigationBarsPadding()
|
|
125
|
+
.padding(all = 16.dp),
|
|
126
|
+
) {
|
|
127
|
+
val localExportStatus = exportStatus
|
|
128
|
+
when (localExportStatus) {
|
|
129
|
+
is ExportStatus.Loading -> loading(localExportStatus)
|
|
130
|
+
is ExportStatus.Success -> success(localExportStatus)
|
|
131
|
+
is ExportStatus.Error -> error(localExportStatus)
|
|
132
|
+
null -> {} // not possible
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The export loading composable.
|
|
141
|
+
*
|
|
142
|
+
* @param status the current status of the export.
|
|
143
|
+
*/
|
|
144
|
+
@Composable
|
|
145
|
+
fun VideoConfigurationBuilder.ExportLoading(status: ExportStatus.Loading) {
|
|
146
|
+
ExportOverlayContent(
|
|
147
|
+
title = stringResource(R.string.ly_img_editor_dialog_export_progress_title),
|
|
148
|
+
text = stringResource(R.string.ly_img_editor_dialog_export_progress_text),
|
|
149
|
+
button = stringResource(R.string.ly_img_editor_dialog_export_progress_button_dismiss),
|
|
150
|
+
buttonColor = MaterialTheme.colorScheme.error,
|
|
151
|
+
onClick = { showCancelExportConfirmationDialog = true },
|
|
152
|
+
centerContent = {
|
|
153
|
+
Box {
|
|
154
|
+
ExportProgressIndicator(progress = status.progress)
|
|
155
|
+
Text(
|
|
156
|
+
text = "${(status.progress * 100).toInt()}%",
|
|
157
|
+
style = MaterialTheme.typography.labelLarge,
|
|
158
|
+
color = MaterialTheme.colorScheme.onSurface,
|
|
159
|
+
modifier = Modifier.align(Alignment.Center),
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
if (showCancelExportConfirmationDialog) {
|
|
165
|
+
CancelExportConfirmationDialog()
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The export success composable.
|
|
171
|
+
*
|
|
172
|
+
* @param status the current status of the export.
|
|
173
|
+
*/
|
|
174
|
+
@Composable
|
|
175
|
+
fun VideoConfigurationBuilder.ExportSuccess(status: ExportStatus.Success) {
|
|
176
|
+
ExportOverlayContent(
|
|
177
|
+
title = stringResource(R.string.ly_img_editor_dialog_export_success_title),
|
|
178
|
+
text = stringResource(R.string.ly_img_editor_dialog_export_success_text),
|
|
179
|
+
button = stringResource(R.string.ly_img_editor_dialog_export_success_button_dismiss),
|
|
180
|
+
onClick = {
|
|
181
|
+
exportStatus = null
|
|
182
|
+
shareFile(file = status.file, mimeType = status.mimeType)
|
|
183
|
+
},
|
|
184
|
+
centerContent = {
|
|
185
|
+
Icon(
|
|
186
|
+
imageVector = IconPack.CheckCircleOutline,
|
|
187
|
+
contentDescription = null,
|
|
188
|
+
modifier = Modifier.size(144.dp),
|
|
189
|
+
tint = LocalExtendedColorScheme.current.green.color,
|
|
190
|
+
)
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* The error loading composable.
|
|
197
|
+
*/
|
|
198
|
+
@Composable
|
|
199
|
+
fun VideoConfigurationBuilder.ExportError() {
|
|
200
|
+
ExportOverlayContent(
|
|
201
|
+
title = stringResource(R.string.ly_img_editor_dialog_export_error_title),
|
|
202
|
+
text = stringResource(R.string.ly_img_editor_dialog_export_error_text),
|
|
203
|
+
button = stringResource(R.string.ly_img_editor_dialog_export_error_button_dismiss),
|
|
204
|
+
onClick = { exportStatus = null },
|
|
205
|
+
centerContent = {
|
|
206
|
+
Icon(
|
|
207
|
+
imageVector = IconPack.ErrorOutline,
|
|
208
|
+
contentDescription = null,
|
|
209
|
+
modifier = Modifier.size(144.dp),
|
|
210
|
+
tint = MaterialTheme.colorScheme.error,
|
|
211
|
+
)
|
|
212
|
+
},
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* The confirmation dialog to cancel the export process.
|
|
218
|
+
*/
|
|
219
|
+
@Composable
|
|
220
|
+
fun VideoConfigurationBuilder.CancelExportConfirmationDialog() {
|
|
221
|
+
AlertDialog(
|
|
222
|
+
icon = {
|
|
223
|
+
Icon(
|
|
224
|
+
imageVector = IconPack.ErrorOutline,
|
|
225
|
+
contentDescription = null,
|
|
226
|
+
tint = MaterialTheme.colorScheme.error,
|
|
227
|
+
)
|
|
228
|
+
},
|
|
229
|
+
title = {
|
|
230
|
+
Text(text = stringResource(R.string.ly_img_editor_dialog_export_cancel_title))
|
|
231
|
+
},
|
|
232
|
+
text = {
|
|
233
|
+
Text(text = stringResource(R.string.ly_img_editor_dialog_export_cancel_text))
|
|
234
|
+
},
|
|
235
|
+
confirmButton = {
|
|
236
|
+
TextButton(
|
|
237
|
+
onClick = {
|
|
238
|
+
showCancelExportConfirmationDialog = false
|
|
239
|
+
editorContext.eventHandler.send(EditorEvent.Export.Cancel())
|
|
240
|
+
},
|
|
241
|
+
colors = ButtonDefaults.textButtonColors(
|
|
242
|
+
containerColor = MaterialTheme.colorScheme.errorContainer,
|
|
243
|
+
contentColor = MaterialTheme.colorScheme.onErrorContainer,
|
|
244
|
+
),
|
|
245
|
+
) {
|
|
246
|
+
Text(stringResource(R.string.ly_img_editor_dialog_export_cancel_button_confirm))
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
dismissButton = {
|
|
250
|
+
TextButton(
|
|
251
|
+
onClick = {
|
|
252
|
+
showCancelExportConfirmationDialog = false
|
|
253
|
+
},
|
|
254
|
+
) {
|
|
255
|
+
Text(stringResource(R.string.ly_img_editor_dialog_export_cancel_button_dismiss))
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
onDismissRequest = {
|
|
259
|
+
showCancelExportConfirmationDialog = false
|
|
260
|
+
},
|
|
261
|
+
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false),
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Generic export overlay content that should be used by all the states of the [ExportStatus].
|
|
267
|
+
*
|
|
268
|
+
* @param modifier the modifier.
|
|
269
|
+
* @param title the title of the export state.
|
|
270
|
+
* @param text the title of the export state.
|
|
271
|
+
* @param button the action button of the export state.
|
|
272
|
+
*/
|
|
273
|
+
@Composable
|
|
274
|
+
fun VideoConfigurationBuilder.ExportOverlayContent(
|
|
275
|
+
modifier: Modifier = Modifier.fillMaxWidth(),
|
|
276
|
+
title: String,
|
|
277
|
+
text: String,
|
|
278
|
+
button: String,
|
|
279
|
+
buttonColor: Color = MaterialTheme.colorScheme.primary,
|
|
280
|
+
onClick: () -> Unit,
|
|
281
|
+
centerContent: @Composable () -> Unit,
|
|
282
|
+
) {
|
|
283
|
+
Column(
|
|
284
|
+
modifier = modifier,
|
|
285
|
+
verticalArrangement = Arrangement.Center,
|
|
286
|
+
horizontalAlignment = Alignment.CenterHorizontally,
|
|
287
|
+
) {
|
|
288
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
289
|
+
centerContent()
|
|
290
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
291
|
+
Text(
|
|
292
|
+
text = title,
|
|
293
|
+
style = MaterialTheme.typography.headlineSmall,
|
|
294
|
+
color = MaterialTheme.colorScheme.onSurface,
|
|
295
|
+
textAlign = TextAlign.Center,
|
|
296
|
+
)
|
|
297
|
+
Spacer(modifier = Modifier.height(4.dp))
|
|
298
|
+
Text(
|
|
299
|
+
text = text,
|
|
300
|
+
style = MaterialTheme.typography.bodyMedium,
|
|
301
|
+
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
302
|
+
textAlign = TextAlign.Center,
|
|
303
|
+
)
|
|
304
|
+
Spacer(modifier = Modifier.height(24.dp))
|
|
305
|
+
TextButton(
|
|
306
|
+
onClick = onClick,
|
|
307
|
+
colors = ButtonDefaults.textButtonColors(
|
|
308
|
+
contentColor = buttonColor,
|
|
309
|
+
),
|
|
310
|
+
) {
|
|
311
|
+
Text(button)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Circular export progress indicator.
|
|
318
|
+
*
|
|
319
|
+
* @param progress the progress of the export, between 0F and 1F.
|
|
320
|
+
* @param fillColor the fill color of the circle.
|
|
321
|
+
* @param gradientColor the gradient color of the circle.
|
|
322
|
+
* @param strokeWidth the stroke width of the circle.
|
|
323
|
+
* @param strokeWidth the size (width/height) of the circle.
|
|
324
|
+
*/
|
|
325
|
+
@Composable
|
|
326
|
+
fun VideoConfigurationBuilder.ExportProgressIndicator(
|
|
327
|
+
progress: Float,
|
|
328
|
+
fillColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
329
|
+
gradientColor: Color = MaterialTheme.colorScheme.onSurface,
|
|
330
|
+
strokeWidth: Dp = 8.dp,
|
|
331
|
+
size: Dp = 144.dp,
|
|
332
|
+
) {
|
|
333
|
+
val animatedProgress by animateFloatAsState(
|
|
334
|
+
targetValue = progress,
|
|
335
|
+
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
val stroke = with(LocalDensity.current) {
|
|
339
|
+
Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Round)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
val transition = rememberInfiniteTransition()
|
|
343
|
+
val rotationAngle by transition.animateFloat(
|
|
344
|
+
initialValue = 0f,
|
|
345
|
+
targetValue = 360f,
|
|
346
|
+
animationSpec = infiniteRepeatable(
|
|
347
|
+
animation = tween(1500, easing = LinearEasing),
|
|
348
|
+
),
|
|
349
|
+
label = "Gradient Rotation",
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
val sweepGradient = remember(gradientColor) {
|
|
353
|
+
Brush.sweepGradient(
|
|
354
|
+
colorStops = listOf(
|
|
355
|
+
0.02f to Color.Transparent,
|
|
356
|
+
0.5f to gradientColor.copy(alpha = 0.24f),
|
|
357
|
+
1f to Color.Transparent,
|
|
358
|
+
).toTypedArray(),
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
Canvas(
|
|
363
|
+
modifier = Modifier
|
|
364
|
+
.progressSemantics(animatedProgress)
|
|
365
|
+
.size(size - strokeWidth * 2),
|
|
366
|
+
) {
|
|
367
|
+
drawSweepGradientCircularIndicator(
|
|
368
|
+
rotationAngle = rotationAngle,
|
|
369
|
+
stroke = stroke,
|
|
370
|
+
gradientBrush = sweepGradient,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
drawCircularIndicator(
|
|
374
|
+
startAngle = 270f,
|
|
375
|
+
sweep = animatedProgress * 360f,
|
|
376
|
+
color = fillColor,
|
|
377
|
+
stroke = stroke,
|
|
378
|
+
)
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private fun DrawScope.drawSweepGradientCircularIndicator(
|
|
383
|
+
rotationAngle: Float,
|
|
384
|
+
stroke: Stroke,
|
|
385
|
+
gradientBrush: Brush,
|
|
386
|
+
) {
|
|
387
|
+
rotate(-180f + rotationAngle) {
|
|
388
|
+
val diameterOffset = stroke.width / 2
|
|
389
|
+
val arcDimen = size.width - 2 * diameterOffset
|
|
390
|
+
drawArc(
|
|
391
|
+
brush = gradientBrush,
|
|
392
|
+
startAngle = 0f,
|
|
393
|
+
sweepAngle = 180f,
|
|
394
|
+
useCenter = false,
|
|
395
|
+
topLeft = Offset(diameterOffset, diameterOffset),
|
|
396
|
+
style = stroke,
|
|
397
|
+
size = Size(arcDimen, arcDimen),
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private fun DrawScope.drawCircularIndicator(
|
|
403
|
+
startAngle: Float,
|
|
404
|
+
sweep: Float,
|
|
405
|
+
color: Color,
|
|
406
|
+
stroke: Stroke,
|
|
407
|
+
) {
|
|
408
|
+
// To draw this circle we need a rect with edges that line up with the midpoint of the stroke.
|
|
409
|
+
// To do this we need to remove half the stroke width from the total diameter for both sides.
|
|
410
|
+
val diameterOffset = stroke.width / 2
|
|
411
|
+
val arcDimen = size.width - 2 * diameterOffset
|
|
412
|
+
drawArc(
|
|
413
|
+
color = color,
|
|
414
|
+
startAngle = startAngle,
|
|
415
|
+
sweepAngle = sweep,
|
|
416
|
+
useCenter = false,
|
|
417
|
+
topLeft = Offset(diameterOffset, diameterOffset),
|
|
418
|
+
size = Size(arcDimen, arcDimen),
|
|
419
|
+
style = stroke,
|
|
420
|
+
)
|
|
421
|
+
}
|