Upgrade to Pro — share decks privately, control downloads, hide ads and more …

3년차 개발자, 10년차 에디터 모던화 하기 in Android

kakao
November 01, 2024

3년차 개발자, 10년차 에디터 모던화 하기 in Android

#android #editor #compose #modernization #리팩토링

10년된 브런치 안드로이드 에디터를 3년차 개발자가 모던화 하기까지의 과정의 개발 경험기 입니다.
10년전에 만들어진 리치 텍스트 에디터를 Compose, MVI, 클린아키텍쳐를 적용하여 모던화하는 프로젝트를 발제하고, POC 를 통해서 점진적으로 개선하는 과정을 공유합니다.

발표자 : evan.969
브런치개발파트에서 브런치와 티스토리 안드로이드 앱 개발을 담당하고 있는 에반입니다.

kakao

November 01, 2024
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1. ݆ࣻ਷-JTUFOFSઓ੤ -JTUFOFS -JTUFOFS -JTUFOFS ী٣ఠ ӝמ 5FYU *NBHF 7JEFP &UDj

    ੗ز੷੢ স۽٘ ݏ୺ߨѨࢎ ઁݾழߡ ҳࢿਃࣗ
  2. interface Clickable { fun onClick() } interface Draggable { fun

    onDragStart() fun onDragEnd() } interface Modifiable { fun onChange() fun onAdd() fun onRemove() } interface EditorEventHandler: Clickable, Draggable, Modifiable &WFOUJOUFSGBDF
  3. class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable {

    private var eventHandler: T? = null @Composable override fun Draw() { // Draw UI } override fun setEventHandler(eventHandler: T) { this.eventHandler = eventHandler } ... } 5FYU1MVHJO
  4. class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable {

    private var eventHandler: T? = null @Composable override fun Draw() { // Draw UI } override fun setEventHandler(eventHandler: T) { this.eventHandler = eventHandler } ... } 5FYU1MVHJO
  5. Object : EditorEventHandler { override fun onChange() { ... }

    override fun onAdd() { ... } override fun onRemove() { ... } override fun onClick() { ... } override fun onDragStart() { ... } } &EJUPS&WFOU
  6. &WFOUJO1MVHJO class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable

    { private var eventHandler: T? = null override fun setEventHandler(eventHandler: T) { this.eventHandler = eventHandler } ... }
  7. class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable {

    private var eventHandler: T? = null override fun setEventHandler(eventHandler: T) { this.eventHandler = eventHandler } ... } interface EditorEventHandler: Clickable, Draggable, Modifiable &WFOUJO1MVHJO
  8. റࠁ റࠁ QTUZMFt_u উ֞ೞࣁਃ QTUZMFt_u ࠳۠஖ѐߊ੗j QQ റࠁ <উ֞> <#PME

    :FMMPX> <ೞࣁਃ> <#PME TUSJLF> <࠳۠஖> <6OEFS-JOF> <ѐߊ੗ੑפ׮> <3FE> ؘ੉ఠ੷੢ҳઑ 5FYUtউ֞ೞࣁਃju #PME< > < > 4USJLF< > 6OEFS-JOF< >
  9. റࠁ റࠁ റࠁ <উ֞> <#PME :FMMPX> <ೞࣁਃ> <#PME TUSJLF> <࠳۠஖>

    <6OEFS-JOF> <ѐߊ੗ੑפ׮> <3FE> ؘ੉ఠ੷੢ҳઑ 5FYUtউ֞ೞࣁਃju #PME< > < > 4USJLF< > 6OEFS-JOF< > QTUZMFt_u উ֞ೞࣁਃ QTUZMFt_u ࠳۠஖ѐߊ੗j QQ
  10. റࠁ റࠁ റࠁ 5FYUtউ֞ೞࣁਃju #PME< > < > 4USJLF< >

    6OEFS-JOF< > <উ֞> <#PME :FMMPX> <ೞࣁਃ> <#PME TUSJLF> <࠳۠஖> <6OEFS-JOF> <ѐߊ੗ੑפ׮> <3FE> ؘ੉ఠ੷੢ҳઑ QTUZMFt_u উ֞ೞࣁਃ QTUZMFt_u ࠳۠஖ѐߊ੗j QQ
  11. റࠁ റࠁ റࠁ <উ֞> <#PME :FMMPX> <ೞࣁਃ> <#PME TUSJLF> <࠳۠஖>

    <6OEFS-JOF> <ѐߊ੗ੑפ׮> <3FE> ؘ੉ఠ੷੢ҳઑ 5FYUtউ֞ೞࣁਃju #PME< > < > 4USJLF< > 6OEFS-JOF< > QTUZMFt_u উ֞ೞࣁਃ QTUZMFt_u ࠳۠஖ѐߊ੗j QQ
  12. য় উ֞ೞࣁਃ࠳۠஖ѐߊ੗ੑפ׮   ੉੹ޙ੢EJGG   \tżu^ \߸҃^ അ੤ޙ੢EJGG

      \tয়u^ \߸҃^ ࢎਊ੗ੑ۱୊ܻ߸҃ ੑ۱ ੑ۱ೡٸࢎਊ
  13. class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable {

    private var eventHandler: T? = null @Composable override fun Draw() { // Draw UI } override fun setEventHandler(eventHandler: T) { this.eventHandler = eventHandler } ... } &WFOU୊ܻ FOUFS
  14. class TextPlugin<T: EditorEventHandler>(): EditorPlugin<T> where T: Clickable, T: Modifiable {

    private var eventHandler: T? = null override fun ‘ূఠद ز੘’() { ... val (frontData, BackData) = splitData(Data) val newTextPluginItem = TextPlugin(BackData) this.eventHandler?.onEnter(newTextPluginItem) } ... } &WFOU୊ܻ FOUFS
  15. 5FTU @Test fun inputTest() { val textPlugin = TextPlugin<EditorEvent>() val

    textRange = TextRange(5, 10) textPlugin.onStyleChange(TextStyle(fontWeight = FontWeight.Bold), textRange) assertEquals(TextStyle.Bold, textPlugin.textData.getStyle(textRange)) }
  16. UPVDI%PXO੿ࠁܳ߉ח׮ -POH1SFTTੋ૑ഛੋೠ׮ -POH1SFTT੉ݶUPVDI*Eчਸֈѹળ׮ pointerInput(Unit) { awaitEachGesture { val down =

    awaitFirstDown() val drag = awaitLongPressOrCancellation(down.id) if (drag != null) onDragStart(drag.id) } } %SBH%SPQद੘௏٘
  17. awaitEachGesture { var touchSlop = Offset.Zero awaitPointerEvent().changes.firstOrNull()?.let { val drag

    = awaitLongPressOrCancellation(it.id) drag?.scrollDelta?.let { delta -> touchSlop = delta } } val down = currentEvent.changes.firstOrNull { it.id == dragDropListState.pointerId } if (down != null && down.pressed) { dragDropListState.onDrag(touchSlop, null) if ( !drag(down.id) { dragDropListState.onDrag(it.positionChange(), null) it.consume() } ) { dragDropListState.onDragCancel() } else { dragDropListState.onDragEnd() ... } } }
  18. ࠗ࠙߸҃੉ࠛоמ var annotatedString = annotatedString(text = “Hello world!") annotatedString.setStyle(style =

    SpanStyle(color = ~, range = ~)) val spannableText = editText.text spannableText.setSpan( StyleSpan(Typeface.BOLD), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE )
  19. var textFieldValue by remember { mutableStateOf( TextFieldValue( annotatedString = buildAnnotatedString

    { withStyle(SpanStyle(color = Color.Red)) { append("hello") } }, ) ) } TextField( value = textFieldValue, modifier = Modifier.fillMaxWidth(), onValueChange = { textFieldValue = it } )
  20. ೠӖ੗ܻࣗ࠙ޙઁ var textFieldValue by remember { mutableStateOf( TextFieldValue(annotatedString = AnnotatedString(""))

    ) } val onValueChange = { inputTextFieldValue: TextFieldValue -> val annotatedString = buildAnnotatedString { withStyle(SpanStyle(color = Color.Black)) { append(inputTextFieldValue.text) } } textFieldValue = inputTextFieldValue.copy(annotatedString) }
  21. ӝࣿ۽٘ݗ        .77. +BWBUP,PUMJO

    $MFBO"SDIJUFDUVSF .VMUJ.PEVMF )JMU 3YUP$PSPVUJOFT 5FTU $PNQPTF 6TF$BTF .JDSP4FSWJDF &EJUPS.PEFSOJ[F
  22.        .77. +BWBUP,PUMJO $MFBO"SDIJUFDUVSF

    .VMUJ.PEVMF )JMU 3YUP$PSPVUJOFT 5FTU $PNQPTF 6TF$BTF .JDSP4FSWJDF &EJUPS.PEFSOJ[F ӝࣿ۽٘ݗ
  23.        .77. +BWBUP,PUMJO $MFBO"SDIJUFDUVSF

    .VMUJ.PEVMF )JMU 3YUP$PSPVUJOFT 5FTU $PNQPTF 6TF$BTF .JDSP4FSWJDF &EJUPS.PEFSOJ[F ӝࣿ۽٘ݗ
  24.        .77. +BWBUP,PUMJO $MFBO"SDIJUFDUVSF

    .VMUJ.PEVMF )JMU 3YUP$PSPVUJOFT 5FTU $PNQPTF 6TF$BTF .JDSP4FSWJDF &EJUPS.PEFSOJ[F ӝࣿ۽٘ݗ
  25.        .77. +BWBUP,PUMJO $MFBO"SDIJUFDUVSF

    .VMUJ.PEVMF )JMU 3YUP$PSPVUJOFT 5FTU $PNQPTF 6TF$BTF .JDSP4FSWJDF &EJUPS.PEFSOJ[F ӝࣿ۽٘ݗ
  26. 2"