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

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

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for kakao kakao
November 01, 2024

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

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

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

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

Avatar for kakao

kakao

November 01, 2024

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"