diff --git a/build.gradle b/build.gradle index 834da88af..f0eeb58b6 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ buildscript { ext.kotlinVersion = '1.3.61' + ext.serializationVersion = '0.14.0' repositories { google() jcenter() @@ -10,6 +11,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion" classpath 'com.automattic.android:fetchstyle:1.1' classpath 'io.sentry:sentry-android-gradle-plugin:1.7.27' // NOTE: Do not place your application dependencies here; they belong diff --git a/photoeditor/build.gradle b/photoeditor/build.gradle index 92cb2cbc4..e500caf7c 100644 --- a/photoeditor/build.gradle +++ b/photoeditor/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'kotlinx-serialization' android { compileSdkVersion rootProject.compileSdkVersion @@ -36,6 +37,7 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion" implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "androidx.core:core-ktx:$coreVersion" diff --git a/photoeditor/proguard-rules.pro b/photoeditor/proguard-rules.pro index f1b424510..13a84487a 100644 --- a/photoeditor/proguard-rules.pro +++ b/photoeditor/proguard-rules.pro @@ -19,3 +19,12 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile +-keepattributes *Annotation*, InnerClasses +-dontnote kotlinx.serialization.SerializationKt +-keep,includedescriptorclasses class com.automattic.photoeditor.**$$serializer { *; } # <-- change package name to your app's +-keepclassmembers class com.automattic.photoeditor.** { # <-- change package name to your app's + *** Companion; +} +-keepclasseswithmembers class com.automattic.photoeditor.** { # <-- change package name to your app's + kotlinx.serialization.KSerializer serializer(...); +} diff --git a/photoeditor/src/main/java/com/automattic/photoeditor/PhotoEditor.kt b/photoeditor/src/main/java/com/automattic/photoeditor/PhotoEditor.kt index dac85a8d4..d3e34e9d7 100644 --- a/photoeditor/src/main/java/com/automattic/photoeditor/PhotoEditor.kt +++ b/photoeditor/src/main/java/com/automattic/photoeditor/PhotoEditor.kt @@ -35,6 +35,7 @@ import com.automattic.photoeditor.views.ViewType import com.automattic.photoeditor.views.ViewType.EMOJI import com.automattic.photoeditor.views.ViewType.TEXT import com.automattic.photoeditor.views.added.AddedView +import com.automattic.photoeditor.views.added.AddedViewInfo import com.automattic.photoeditor.views.added.AddedViewList import com.automattic.photoeditor.views.brush.BrushDrawingView import com.automattic.photoeditor.views.brush.BrushViewChangeListener @@ -52,8 +53,8 @@ import kotlinx.android.synthetic.main.view_photo_editor_emoji.view.* import kotlinx.android.synthetic.main.view_photo_editor_text.view.* import java.io.File import java.io.FileInputStream -import java.util.ArrayList import java.lang.ref.WeakReference +import java.util.ArrayList /** * @@ -233,9 +234,16 @@ class PhotoEditor private constructor(builder: Builder) : * @param colorCodeTextView text color to be displayed */ @SuppressLint("ClickableViewAccessibility") - fun addText(text: String, colorCodeTextView: Int, textTypeface: Typeface? = null, fontSizeSp: Float = 18f) { + fun addText( + text: String, + colorCodeTextView: Int, + textTypeface: Typeface? = null, + fontSizeSp: Float = 18f, + isViewBeingReadded: Boolean = false + ): View? { brushDrawingView.brushDrawingMode = false - getLayout(ViewType.TEXT)?.apply { + val view: View? + view = getLayout(ViewType.TEXT)?.apply { val textInputTv = findViewById(R.id.tvPhotoEditorText) textInputTv.text = text @@ -262,13 +270,14 @@ class PhotoEditor private constructor(builder: Builder) : setOnTouchListener(multiTouchListenerInstance) addViewToParent(this, ViewType.TEXT) - // now open TextEditor right away - if (mOnPhotoEditorListener != null) { + // now open TextEditor right away if this is new text being added + if (mOnPhotoEditorListener != null && !isViewBeingReadded) { val textInput = textInputTv.text.toString() val currentTextColor = textInputTv.currentTextColor mOnPhotoEditorListener?.onEditTextChangeListener(this, textInput, currentTextColor, true) } } + return view } /** @@ -300,7 +309,9 @@ class PhotoEditor private constructor(builder: Builder) : inputTextView.setTextColor(colorCode) parentView.updateViewLayout(view, view.layoutParams) val i = addedViews.indexOfView(view) - if (i > -1) addedViews[i] = AddedView(view, addedViews[i].viewType) + if (i > -1) { + addedViews[i] = AddedView.buildAddedViewFromView(view, addedViews[i].viewType) + } } } @@ -310,8 +321,8 @@ class PhotoEditor private constructor(builder: Builder) : * * @param emojiName unicode in form of string to display emoji */ - fun addEmoji(emojiName: String) { - addEmoji(null, emojiName) + fun addEmoji(emojiName: String): View? { + return addEmoji(null, emojiName) } /** @@ -321,9 +332,10 @@ class PhotoEditor private constructor(builder: Builder) : * @param emojiTypeface typeface for custom font to show emoji unicode in specific font * @param emojiName unicode in form of string to display emoji */ - fun addEmoji(emojiTypeface: Typeface?, emojiName: String) { + fun addEmoji(emojiTypeface: Typeface?, emojiName: String): View? { brushDrawingView.brushDrawingMode = false - getLayout(ViewType.EMOJI)?.apply { + val view = getLayout(ViewType.EMOJI) + view?.apply { val emojiTextView = findViewById(R.id.tvPhotoEditorEmoji) if (emojiTypeface != null) { @@ -366,6 +378,7 @@ class PhotoEditor private constructor(builder: Builder) : // setOnTouchListener(multiTouchListenerInstance) addViewToParent(this, ViewType.EMOJI) } + return view } /** @@ -379,11 +392,55 @@ class PhotoEditor private constructor(builder: Builder) : ) params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE) parentView.addView(rootView, params) - addedViews.add(AddedView(rootView, viewType, sourceUri)) + addedViews.add(AddedView.buildAddedViewFromView(rootView, viewType, sourceUri)) mOnPhotoEditorListener?.onAddViewListener(viewType, addedViews.size) } - fun addViewToParentWithTouchListener(rootView: View, viewType: ViewType, sourceUri: Uri? = null) { + fun addViewToParentWithTouchListener(addedView: AddedView) { + addedView.view?.let { + addViewToParentWithTouchListener(it, addedView.viewType, addedView.uri) + } ?: buildViewFromAddedViewInfo(addedView.viewInfo, addedView.viewType) + } + + private fun buildViewFromAddedViewInfo(addedViewInfo: AddedViewInfo, viewType: ViewType): View? { + var view: View? = null + when (viewType) { + EMOJI -> { + // create emoji view layout + view = addEmoji(addedViewInfo.addedViewTextInfo.text) + // apply specific TextView parameters for emoji (fontsize) + val emojiTextView = view?.findViewById(R.id.tvPhotoEditorEmoji) + // the actual calculated text size as obtained from the view is expressed in px. + emojiTextView?.setTextSize(TypedValue.COMPLEX_UNIT_PX, addedViewInfo.addedViewTextInfo.fontSizePx) + } + TEXT -> { + // create TEXT view layout + view = addText( + text = addedViewInfo.addedViewTextInfo.text, + colorCodeTextView = addedViewInfo.addedViewTextInfo.textColor, + isViewBeingReadded = true + ) + // apply specific TextView parameters for text (fontsize, text color) + val normalTextView = view?.findViewById(R.id.tvPhotoEditorText) + // the actual calculated text size as obtained from the view is expressed in px. + normalTextView?.setTextSize(TypedValue.COMPLEX_UNIT_PX, addedViewInfo.addedViewTextInfo.fontSizePx) + normalTextView?.setTextColor(addedViewInfo.addedViewTextInfo.textColor) + } + } + + // now apply all common parameters to newly created view object + view?.let { + it.rotation = addedViewInfo.rotation + it.translationX = addedViewInfo.translationX + it.translationY = addedViewInfo.translationY + it.scaleX = addedViewInfo.scale + it.scaleY = addedViewInfo.scale + } + + return view + } + + private fun addViewToParentWithTouchListener(rootView: View, viewType: ViewType, sourceUri: Uri? = null) { val multiTouchListenerInstance = getNewMultitouchListener(rootView) // newMultiTouchListener when { viewType == EMOJI -> { @@ -544,7 +601,7 @@ class PhotoEditor private constructor(builder: Builder) : redoViews.add(removeView) } mOnPhotoEditorListener?.onRemoveViewListener(addedViews.size) - val viewTag = removeView.view.tag + val viewTag = removeView.view?.tag (viewTag as? ViewType)?.let { mOnPhotoEditorListener?.onRemoveViewListener(it, addedViews.size) } @@ -567,7 +624,7 @@ class PhotoEditor private constructor(builder: Builder) : parentView.addView(redoView.view) addedViews.add(redoView) } - val viewTag = redoView.view.tag + val viewTag = redoView.view?.tag if (viewTag != null && viewTag is ViewType) { mOnPhotoEditorListener?.onAddViewListener(viewTag, addedViews.size) } @@ -585,7 +642,9 @@ class PhotoEditor private constructor(builder: Builder) : */ fun clearAllViews() { for (addedView in addedViews) { - parentView.removeView(addedView.view) + addedView.view?.let { + parentView.removeView(it) + } } if (addedViews.containsView(brushDrawingView)) { @@ -735,9 +794,9 @@ class PhotoEditor private constructor(builder: Builder) : val viewPositionInfo = ViewPositionInfo( originalCanvasWidth, originalCanvasHeight, - v.view.width, - v.view.height, - v.view.matrix + requireNotNull(v.view).width, + requireNotNull(v.view).height, + requireNotNull(v.view).matrix ) when (v.viewType) { ViewType.STICKER_ANIMATED -> { @@ -883,17 +942,17 @@ class PhotoEditor private constructor(builder: Builder) : // get the images currently on top of the screen, and add them as Filters to the mp4composer val filterCollection = ArrayList() - for (v in addedViews) { + for (oneView in addedViews) { val viewPositionInfo = ViewPositionInfo( widthParent, heightParent, - v.view.width, - v.view.height, - v.view.matrix + requireNotNull(oneView.view).width, + requireNotNull(oneView.view).height, + requireNotNull(oneView.view).matrix ) - when (v.viewType) { + when (oneView.viewType) { ViewType.STICKER_ANIMATED -> { - v.uri?.path?.let { path -> + oneView.uri?.path?.let { path -> val file = File(path) val fileInputStream = FileInputStream(file) filterCollection.add(GlGifWatermarkFilter(context, fileInputStream, viewPositionInfo)) @@ -901,7 +960,9 @@ class PhotoEditor private constructor(builder: Builder) : } else -> { clearHelperBox() - filterCollection.add(GlWatermarkFilter(BitmapUtil.createBitmapFromView(v.view), viewPositionInfo)) + filterCollection.add( + GlWatermarkFilter(BitmapUtil.createBitmapFromView(oneView.view), viewPositionInfo) + ) } } } @@ -975,15 +1036,17 @@ class PhotoEditor private constructor(builder: Builder) : if (redoViews.size > 0) { redoViews.removeAt(redoViews.size - 1) } - addedViews.add(AddedView(brushDrawingView, ViewType.BRUSH_DRAWING)) + addedViews.add(AddedView.buildAddedViewFromView(brushDrawingView, ViewType.BRUSH_DRAWING)) mOnPhotoEditorListener?.onAddViewListener(ViewType.BRUSH_DRAWING, addedViews.size) } override fun onViewRemoved(brushDrawingView: BrushDrawingView) { if (addedViews.size > 0) { val removeView = addedViews.removeAt(addedViews.size - 1) - if (removeView.view !is BrushDrawingView) { - parentView.removeView(removeView.view) + removeView.view?.let { + if (it !is BrushDrawingView) { + parentView.removeView(it) + } } redoViews.add(removeView) } diff --git a/photoeditor/src/main/java/com/automattic/photoeditor/views/ViewType.kt b/photoeditor/src/main/java/com/automattic/photoeditor/views/ViewType.kt index 2d548118c..b9e61d5e4 100644 --- a/photoeditor/src/main/java/com/automattic/photoeditor/views/ViewType.kt +++ b/photoeditor/src/main/java/com/automattic/photoeditor/views/ViewType.kt @@ -1,5 +1,7 @@ package com.automattic.photoeditor.views +import kotlinx.serialization.Serializable + /** * * @@ -10,6 +12,7 @@ package com.automattic.photoeditor.views * @version 0.1.1 * @since 18/01/2017. */ +@Serializable enum class ViewType { BRUSH_DRAWING, TEXT, diff --git a/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedView.kt b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedView.kt index a6812b5a2..bcfd5062a 100644 --- a/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedView.kt +++ b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedView.kt @@ -2,6 +2,90 @@ package com.automattic.photoeditor.views.added import android.net.Uri import android.view.View +import android.widget.TextView +import com.automattic.photoeditor.R import com.automattic.photoeditor.views.ViewType +import com.automattic.photoeditor.views.ViewType.EMOJI +import com.automattic.photoeditor.views.ViewType.TEXT +import kotlinx.serialization.Transient +import kotlinx.serialization.Decoder +import kotlinx.serialization.Encoder +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.Serializer -class AddedView(val view: View, val viewType: ViewType, val uri: Uri? = null) +@Serializable +class AddedView( + @Transient val view: View? = null, + val viewType: ViewType, + var viewInfo: AddedViewInfo, + @Serializable(with = UriSerializer::class) + val uri: Uri? = null +) { + companion object { + fun buildAddedViewFromView( + view: View, + viewType: ViewType, + uri: Uri? = null + ): AddedView { + return AddedView( + view, + viewType, + buildViewInfoFromView( + view, + getTextInfoFromActualView(view, viewType) + ), + uri + ) + } + + fun getTextInfoFromActualView(view: View, viewType: ViewType): AddedViewTextInfo { + val txtView: TextView = when (viewType) { + EMOJI -> { + view.findViewById(R.id.tvPhotoEditorEmoji) + } + TEXT -> { + view.findViewById(R.id.tvPhotoEditorText) + } + else -> { + // default text + view.findViewById(R.id.tvPhotoEditorText) + } + } + return AddedViewTextInfo(txtView.text.toString(), txtView.textSize, txtView.currentTextColor) + } + + fun buildViewInfoFromView(view: View, addedViewText: AddedViewTextInfo): AddedViewInfo { + return AddedViewInfo( + view.rotation, + view.translationX, + view.translationY, + view.scaleX, + addedViewText + ) + } + } + + fun update() { + view?.let { + viewInfo = AddedViewInfo( + it.rotation, + it.translationX, + it.translationY, + it.scaleX, + getTextInfoFromActualView(view, viewType) + ) + } + } + + @Serializer(forClass = Uri::class) + object UriSerializer : KSerializer { + override fun deserialize(input: Decoder): Uri { + return Uri.parse(input.decodeString()) + } + + override fun serialize(output: Encoder, obj: Uri) { + output.encodeString(obj.toString()) + } + } +} diff --git a/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewInfo.kt b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewInfo.kt new file mode 100644 index 000000000..275572d27 --- /dev/null +++ b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewInfo.kt @@ -0,0 +1,15 @@ +package com.automattic.photoeditor.views.added + +import kotlinx.serialization.Serializable + +@Serializable +data class AddedViewInfo( + val rotation: Float, + val translationX: Float, + val translationY: Float, + val scale: Float, + val addedViewTextInfo: AddedViewTextInfo +) + +@Serializable +data class AddedViewTextInfo(val text: String, val fontSizePx: Float, val textColor: Int) diff --git a/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewList.kt b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewList.kt index 1b0e80d27..bac2c7da9 100644 --- a/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewList.kt +++ b/photoeditor/src/main/java/com/automattic/photoeditor/views/added/AddedViewList.kt @@ -3,43 +3,52 @@ package com.automattic.photoeditor.views.added import android.view.View import com.automattic.photoeditor.views.ViewType import java.util.ArrayList +import kotlinx.serialization.Serializable -class AddedViewList(addedViewList: AddedViewList? = null) : ArrayList() { - init { - addedViewList?.let { +@Serializable +class AddedViewList : ArrayList() { + fun copyOf(addedViewList: AddedViewList): AddedViewList { + addedViewList.let { addAll(it) } + return this } fun containsView(element: View): Boolean { - for (n in this) { - if (n.view == element) { - return true + for (oneView in this) { + oneView.view?.let { + if (it == element) { + return true + } } } return false } fun removeView(element: View): AddedView? { - for (n in this) { - if (n.view == element) { - this.remove(n) - return n + for (oneView in this) { + oneView.view?.let { + if (it == element) { + this.remove(oneView) + return oneView + } } } return null } fun indexOfView(element: View): Int { - for (n in this) { - if (n.view == element) { - return this.indexOf(n) + for (oneView in this) { + oneView.view?.let { + if (it == element) { + return this.indexOf(oneView) + } } } return -1 } fun containsAnyAddedViewsOfType(type: ViewType): Boolean { - for (v: AddedView in this) { - if (v.viewType == type) { + for (oneView: AddedView in this) { + if (oneView.viewType == type) { return true } } diff --git a/stories/build.gradle b/stories/build.gradle index 2defded7c..545e636d9 100644 --- a/stories/build.gradle +++ b/stories/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'kotlinx-serialization' android { compileSdkVersion rootProject.compileSdkVersion @@ -34,6 +35,7 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion" implementation "androidx.appcompat:appcompat:$appCompatVersion" implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" diff --git a/stories/proguard-rules.pro b/stories/proguard-rules.pro index f1b424510..7a4ec1ed2 100644 --- a/stories/proguard-rules.pro +++ b/stories/proguard-rules.pro @@ -19,3 +19,12 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile +-keepattributes *Annotation*, InnerClasses +-dontnote kotlinx.serialization.SerializationKt +-keep,includedescriptorclasses class com.wordpress.stories.**$$serializer { *; } # <-- change package name to your app's +-keepclassmembers class com.wordpress.stories.** { # <-- change package name to your app's + *** Companion; +} +-keepclasseswithmembers class com.wordpress.stories.** { # <-- change package name to your app's + kotlinx.serialization.KSerializer serializer(...); +} \ No newline at end of file diff --git a/stories/src/main/java/com/wordpress/stories/compose/ComposeLoopFrameActivity.kt b/stories/src/main/java/com/wordpress/stories/compose/ComposeLoopFrameActivity.kt index 230de4c97..fcd33b4e6 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/ComposeLoopFrameActivity.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/ComposeLoopFrameActivity.kt @@ -1052,11 +1052,15 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec // purge multitouch listeners val addedViews = photoEditor.getViewsAdded() for (addedView in addedViews) { - addedView.view.setOnTouchListener(null) + addedView.view?.let { + // while iterating, also update the ViewInfo for each view + addedView.update() + addedView.view?.setOnTouchListener(null) + } } // set addedViews on the current frame (copy array so we don't share the same one with PhotoEditor) - currentStoryFrameItem?.addedViews = AddedViewList(photoEditor.getViewsAdded()) + currentStoryFrameItem?.addedViews = AddedViewList().copyOf(photoEditor.getViewsAdded()) } private fun showMediaPicker() { @@ -1757,7 +1761,7 @@ abstract class ComposeLoopFrameActivity : AppCompatActivity(), OnStoryFrameSelec // now call addViewToParent the addedViews remembered by this frame newSelectedFrame.addedViews.let { for (oneView in it) { - photoEditor.addViewToParentWithTouchListener(oneView.view, oneView.viewType) + photoEditor.addViewToParentWithTouchListener(oneView) } } diff --git a/stories/src/main/java/com/wordpress/stories/compose/frame/FrameSaveManager.kt b/stories/src/main/java/com/wordpress/stories/compose/frame/FrameSaveManager.kt index db04374d7..9c9bba8e9 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/frame/FrameSaveManager.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/frame/FrameSaveManager.kt @@ -277,8 +277,10 @@ class FrameSaveManager(private val photoEditor: PhotoEditor) : CoroutineScope { withContext(Dispatchers.Main) { // now call addViewToParent the addedViews remembered by this frame for (oneView in frame.addedViews) { - removeViewFromParent(oneView.view) - ghostPhotoEditorView.addView(oneView.view, getViewLayoutParams()) + oneView.view?.let { + removeViewFromParent(it) + ghostPhotoEditorView.addView(it, getViewLayoutParams()) + } } } } @@ -315,7 +317,9 @@ class FrameSaveManager(private val photoEditor: PhotoEditor) : CoroutineScope { fun releaseAddedViews(frame: StoryFrameItem) { // don't forget to remove these views from ghost offscreen view before exiting for (oneView in frame.addedViews) { - removeViewFromParent(oneView.view) + oneView.view?.let { + removeViewFromParent(it) + } } } } diff --git a/stories/src/main/java/com/wordpress/stories/compose/frame/StorySaveEvents.kt b/stories/src/main/java/com/wordpress/stories/compose/frame/StorySaveEvents.kt index f240d761a..e9ebd0a8e 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/frame/StorySaveEvents.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/frame/StorySaveEvents.kt @@ -24,6 +24,7 @@ class StorySaveEvents { @Parcelize data class FrameSaveResult(val frameIndex: FrameIndex, val resultReason: SaveResultReason) : Parcelable + @kotlinx.serialization.Serializable sealed class SaveResultReason : Parcelable { @Parcelize object SaveSuccess : SaveResultReason() diff --git a/stories/src/main/java/com/wordpress/stories/compose/story/Story.kt b/stories/src/main/java/com/wordpress/stories/compose/story/Story.kt index 9d62eba95..126df92f0 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/story/Story.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/story/Story.kt @@ -1,3 +1,6 @@ package com.wordpress.stories.compose.story +import kotlinx.serialization.Serializable + +@Serializable data class Story(val frames: ArrayList, var title: String? = null) diff --git a/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItem.kt b/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItem.kt index 47f86df48..466d0390a 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItem.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItem.kt @@ -5,15 +5,20 @@ import com.automattic.photoeditor.views.added.AddedViewList import com.wordpress.stories.compose.frame.StorySaveEvents.SaveResultReason import com.wordpress.stories.compose.frame.StorySaveEvents.SaveResultReason.SaveSuccess import com.wordpress.stories.compose.story.StoryFrameItemType.IMAGE +import kotlinx.serialization.ContextualSerialization +import kotlinx.serialization.Serializable import java.io.File +@Serializable data class StoryFrameItem( val source: BackgroundSource, val frameItemType: StoryFrameItemType = IMAGE, var addedViews: AddedViewList = AddedViewList(), var saveResultReason: SaveResultReason = SaveSuccess, + @ContextualSerialization var composedFrameFile: File? = null ) { + @Serializable sealed class BackgroundSource { data class UriBackgroundSource(var contentUri: Uri? = null) : BackgroundSource() data class FileBackgroundSource(var file: File? = null) : BackgroundSource() diff --git a/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItemType.kt b/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItemType.kt index fdbfde6da..2851648d0 100644 --- a/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItemType.kt +++ b/stories/src/main/java/com/wordpress/stories/compose/story/StoryFrameItemType.kt @@ -1,5 +1,8 @@ package com.wordpress.stories.compose.story +import kotlinx.serialization.Serializable + +@Serializable sealed class StoryFrameItemType { fun isSameType(second: StoryFrameItemType): Boolean { return this::class == second::class diff --git a/stories/src/main/java/com/wordpress/stories/compose/story/StorySerializerUtils.kt b/stories/src/main/java/com/wordpress/stories/compose/story/StorySerializerUtils.kt new file mode 100644 index 000000000..01146ac1b --- /dev/null +++ b/stories/src/main/java/com/wordpress/stories/compose/story/StorySerializerUtils.kt @@ -0,0 +1,26 @@ +package com.wordpress.stories.compose.story + +import com.automattic.photoeditor.views.added.AddedView +import com.automattic.photoeditor.views.added.AddedViewList +import kotlinx.serialization.internal.ArrayListSerializer +import kotlinx.serialization.json.Json + +fun serializeStory(story: Story): String = Json.stringify(Story.serializer(), story) + +fun serializeStoryFrameItem(storyFrameItem: StoryFrameItem) = + Json.stringify(StoryFrameItem.serializer(), storyFrameItem) + +fun deserializeStory(story: String) = Json.parse(Story.serializer(), story) + +fun deserializeStoryFrameItem(storyFrameItem: String) = Json.parse(StoryFrameItem.serializer(), storyFrameItem) + +fun serializeAddedViews(addedViews: AddedViewList) = + Json.stringify(ArrayListSerializer(AddedView.serializer()), addedViews) + +fun serializeAddedView(addedView: AddedView) = Json.stringify(AddedView.serializer(), addedView) + +fun deserializeAddedViews(addedViews: String): AddedViewList { + val newList = AddedViewList() + newList.addAll(Json.parse(ArrayListSerializer(AddedView.serializer()), addedViews)) + return newList +}