/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.dynamicprops

import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.animated.useBinding
import com.facebook.litho.core.height
import com.facebook.litho.core.margin
import com.facebook.litho.core.padding
import com.facebook.litho.core.width
import com.facebook.litho.dp
import com.facebook.litho.flexbox.alignSelf
import com.facebook.yoga.YogaAlign
import java.util.concurrent.TimeUnit

// start_example
class CustomDynamicPropsKComponent : KComponent() {

  override fun ComponentScope.render(): Component? {
    val time = useBinding(0L)

    return Column(style = Style.padding(all = 20.dp)) {
      child(SeekBar { time.set((it * TimeUnit.HOURS.toMillis(12)).toLong()) })
      child(
          ClockFaceMountable(
              time = time,
              style =
                  Style.width(200.dp)
                      .height(200.dp)
                      .margin(top = 20.dp)
                      .alignSelf(YogaAlign.CENTER)))
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.dynamicprops

import android.content.Context
import android.widget.SeekBar
import com.facebook.litho.MeasureScope
import com.facebook.litho.MountableComponent
import com.facebook.litho.MountableComponentScope
import com.facebook.litho.MountableRenderResult
import com.facebook.litho.SimpleMountable
import com.facebook.litho.Style
import com.facebook.rendercore.MeasureResult

class SeekBarMountable(
    private val onProgressChange: (Float) -> Unit,
    private val initialValue: Float = 0f,
    private val style: Style? = null
) : MountableComponent() {

  override fun MountableComponentScope.render(): MountableRenderResult {
    return MountableRenderResult(Mountable(onProgressChange, initialValue), style)
  }

  private class Mountable(
      private val onProgressChange: (Float) -> Unit,
      private val initialValue: Float
  ) : SimpleMountable<SeekBar>(RenderType.VIEW) {

    private val MAX = 256

    override fun createContent(context: Context): SeekBar = SeekBar(context)

    override fun mount(c: Context, content: SeekBar, layoutData: Any?) {
      content.max = MAX
      content.progress = (initialValue * MAX).toInt()
      content.setOnSeekBarChangeListener(
          object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
              onProgressChange(progress / MAX.toFloat())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar) = Unit

            override fun onStopTrackingTouch(seekBar: SeekBar) = Unit
          })
    }

    override fun unmount(c: Context, content: SeekBar, layoutData: Any?) {
      content.setOnSeekBarChangeListener(null)
    }

    override fun MeasureScope.measure(widthSpec: Int, heightSpec: Int): MeasureResult =
        withEqualSize(widthSpec, heightSpec)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.dynamicprops

import android.content.Context
import com.facebook.litho.Component
import com.facebook.litho.ComponentContext
import com.facebook.litho.ResourcesScope
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.annotations.MountSpec
import com.facebook.litho.annotations.OnCreateMountContent
import com.facebook.litho.annotations.OnMount
import com.facebook.litho.annotations.OnUnmount
import com.facebook.litho.annotations.Prop
import com.facebook.litho.core.height
import com.facebook.litho.core.margin
import com.facebook.litho.dp
import com.facebook.litho.flexbox.flex
import com.facebook.litho.kotlin.widget.Text

@MountSpec
object SeekBarSpec {

  private const val MAX = 256

  @OnCreateMountContent
  fun onCreateMountContent(c: Context): android.widget.SeekBar {
    return android.widget.SeekBar(c)
  }

  @OnMount
  fun onMount(
      c: ComponentContext,
      seekBar: android.widget.SeekBar,
      @Prop initialValue: Float = 1f,
      @Prop onProgressChanged: (Float) -> Unit,
  ) {
    seekBar.max = MAX
    seekBar.progress = (initialValue * MAX).toInt()
    seekBar.setOnSeekBarChangeListener(
        object : android.widget.SeekBar.OnSeekBarChangeListener {
          override fun onProgressChanged(
              seekBar: android.widget.SeekBar,
              progress: Int,
              fromUser: Boolean
          ) {
            onProgressChanged(progress / MAX.toFloat())
          }

          override fun onStartTrackingTouch(seekBar: android.widget.SeekBar) = Unit

          override fun onStopTrackingTouch(seekBar: android.widget.SeekBar) = Unit
        })
  }

  @OnUnmount
  fun onUnmount(
      c: ComponentContext,
      seekBar: android.widget.SeekBar,
  ) {
    seekBar.setOnSeekBarChangeListener(null)
  }
}

fun ResourcesScope.SeekBar(
    initialValue: Float = 1f,
    label: CharSequence? = null,
    style: Style? = null,
    onProgressChanged: (Float) -> Unit,
): Component = Row {
  label?.let { child(Text(label, style = Style.margin(end = 10.dp))) }
  child(
      SeekBarMountable(
          initialValue = initialValue,
          onProgressChange = onProgressChanged,
          style = Style.height(14.dp).flex(grow = 1f) + style))
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.dynamicprops

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PointF
import android.util.TypedValue
import android.view.View
import androidx.annotation.Px
import java.util.concurrent.TimeUnit
import kotlin.math.min

class SimpleClockView(context: Context) : View(context) {
  private val oneHourMs = TimeUnit.HOURS.toMillis(1)
  private val twelveHours = TimeUnit.HOURS.toMillis(12)
  @Px
  private val stroke: Float =
      TypedValue.applyDimension(
          TypedValue.COMPLEX_UNIT_DIP, STROKE_WIDTH_DP, resources.displayMetrics)
  private val paint: Paint =
      Paint().apply {
        color = Color.BLACK
        isAntiAlias = true
        style = Paint.Style.STROKE
        strokeWidth = stroke
      }
  private var center = PointF(0f, 0f)
  @Px private var radius = 0f
  @Px private var shortHandLength = 0f
  @Px private var longHandLength = 0f
  private var shortHandAngle = 0f
  private var longHandAngle = 0f

  var time: Long = 0
    set(time) {
      if (field == time) {
        return
      }
      field = time % twelveHours
      val inHourProgress = time.toFloat() % oneHourMs / oneHourMs
      longHandAngle = 360 * inHourProgress
      val inTwelveHoursProgress = time.toFloat() / twelveHours
      shortHandAngle = 360 * inTwelveHoursProgress
      invalidate()
    }

  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    center.x = w / 2f
    center.y = h / 2f
    val size = min(w, h)
    radius = (size - stroke) / 2f
    shortHandLength = radius * 0.4f
    longHandLength = radius * 0.7f
  }

  override fun onDraw(canvas: Canvas) {
    canvas.drawCircle(center.x, center.y, radius, paint)
    drawHand(canvas, longHandAngle, longHandLength)
    drawHand(canvas, shortHandAngle, shortHandLength)
  }

  private fun drawHand(canvas: Canvas, angle: Float, length: Float) =
      with(canvas) {
        save()
        rotate(angle, center.x, center.y)
        drawLine(center.x, center.y, center.x, center.y - length, paint)
        restore()
      }

  companion object {
    private const val STROKE_WIDTH_DP = 6f
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.expandableelement

import ExpandableElementBottomDetail
import ExpandableElementTopDetail
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.Transition
import com.facebook.litho.animation.AnimatedProperties
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.transition.transitionKey
import com.facebook.litho.transition.useTransition
import com.facebook.litho.useState
import com.facebook.litho.view.onClick

const val TRANSITION_MSG_PARENT = "transition_msg_parent"
const val TRANSITION_TOP_DETAIL = "transition_top_detail"
const val TRANSITION_BOTTOM_DETAIL = "transition_bottom_detail"

class ExpandableElement(
    private val content: Component,
    private val timestamp: String,
    private val seen: Boolean = false
) : KComponent() {

  override fun ComponentScope.render(): Component? {
    val expanded = useState { false }

    useTransition(
        Transition.parallel(
            Transition.allLayout(),
            Transition.create(TRANSITION_MSG_PARENT)
                .animate(AnimatedProperties.HEIGHT)
                .appearFrom(0f),
            Transition.create(TRANSITION_TOP_DETAIL, TRANSITION_BOTTOM_DETAIL)
                .animate(AnimatedProperties.HEIGHT)
                .appearFrom(0f)
                .disappearTo(0f)))

    return Column(
        style =
            Style.padding(top = 8.dp).transitionKey(context, TRANSITION_MSG_PARENT).onClick {
              expanded.update(!expanded.value)
            }) {
          if (expanded.value) {
            child(ExpandableElementTopDetail(timestamp))
          }
          child(
              Column {
                child(content)
                if (expanded.value) {
                  child(ExpandableElementBottomDetail(seen))
                }
              })
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.graphics.Color
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.flexbox.alignSelf
import com.facebook.litho.flexbox.flex
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sp
import com.facebook.litho.transition.transitionKey
import com.facebook.samples.litho.kotlin.animations.expandableelement.TRANSITION_BOTTOM_DETAIL
import com.facebook.yoga.YogaAlign

class ExpandableElementBottomDetail(private val seen: Boolean) : KComponent() {

  override fun ComponentScope.render(): Component? {
    return Text(
        style =
            Style.alignSelf(YogaAlign.FLEX_END)
                .padding(end = 10.dp)
                .flex(shrink = 0f)
                .transitionKey(context, TRANSITION_BOTTOM_DETAIL),
        textSize = 14.sp,
        textColor = Color.GRAY,
        text = if (seen) "Seen" else "Sent")
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.expandableelement

import ExpandableElementMessageContent
import android.graphics.Color
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.yoga.YogaJustify

class ExpandableElementMe(
    private val messageText: String,
    private val timestamp: String,
    private val seen: Boolean = false
) : KComponent() {

  override fun ComponentScope.render(): Component? {
    return ExpandableElement(
        Row(
            style = Style.padding(start = 75.dp, end = 5.dp),
            justifyContent = YogaJustify.FLEX_END) {
              child(
                  ExpandableElementMessageContent(
                      backgroundColor = 0xFF0084FF.toInt(),
                      messageTextColor = Color.WHITE,
                      messageText = messageText))
            },
        timestamp,
        seen)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.margin
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sp
import com.facebook.litho.view.background

class ExpandableElementMessageContent(
    private val messageText: String,
    private val messageTextColor: Int,
    private val backgroundColor: Int
) : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.padding(all = 8.dp)
                .margin(all = 8.dp)
                .background(getMessageBackground(backgroundColor))) {
          child(Text(textSize = 18.sp, textColor = messageTextColor, text = messageText))
        }
  }

  fun getMessageBackground(color: Int): ShapeDrawable {
    val roundedRectShape =
        RoundRectShape(
            floatArrayOf(40f, 40f, 40f, 40f, 40f, 40f, 40f, 40f),
            null,
            floatArrayOf(40f, 40f, 40f, 40f, 40f, 40f, 40f, 40f))
    return ShapeDrawable(roundedRectShape).also { it.paint.color = color }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.expandableelement

import ExpandableElementMessageContent
import android.graphics.Color
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.OvalShape
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.ResourcesScope
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.margin
import com.facebook.litho.core.padding
import com.facebook.litho.core.width
import com.facebook.litho.dp
import com.facebook.litho.flexbox.alignSelf
import com.facebook.litho.flexbox.flex
import com.facebook.litho.view.background
import com.facebook.yoga.YogaAlign

class ExpandableElementOther(
    private val messageText: String,
    private val timestamp: String,
    private val seen: Boolean = false
) : KComponent() {

  override fun ComponentScope.render(): Component? {
    return ExpandableElement(
        Row(style = Style.padding(end = 5.dp)) {
          child(getSenderTitle())
          child(
              ExpandableElementMessageContent(
                  backgroundColor = 0xFFEAEAEA.toInt(),
                  messageTextColor = Color.BLACK,
                  messageText = messageText))
        },
        timestamp = timestamp,
        seen = seen)
  }

  private fun ResourcesScope.getSenderTitle(): Component =
      Row(
          style =
              Style.margin(all = 5.dp)
                  .alignSelf(YogaAlign.CENTER)
                  .width(55.dp)
                  .height(55.dp)
                  .flex(shrink = 0f)
                  .background(getCircle()))

  private fun getCircle(): ShapeDrawable =
      ShapeDrawable(OvalShape()).also { it.paint.color = Color.LTGRAY }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.expandableelement

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.eventHandlerWithReturn
import com.facebook.litho.flexbox.alignSelf
import com.facebook.litho.flexbox.flex
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sections.SectionContext
import com.facebook.litho.sections.common.DataDiffSection
import com.facebook.litho.sections.widget.NotAnimatedItemAnimator
import com.facebook.litho.sections.widget.RecyclerCollectionComponent
import com.facebook.litho.sp
import com.facebook.litho.useState
import com.facebook.litho.view.backgroundColor
import com.facebook.litho.view.onClick
import com.facebook.litho.view.testKey
import com.facebook.litho.widget.TextAlignment
import com.facebook.samples.litho.kotlin.animations.messages.Message
import com.facebook.yoga.YogaAlign

class ExpandableElementRootKotlinKComponent(private val initialMessages: List<Message>) :
    KComponent() {

  override fun ComponentScope.render(): Component? {
    val messages = useState { initialMessages }
    val counter = useState { 1 }

    return Column {
      child(
          Row(style = Style.backgroundColor(Color.LTGRAY)) {
            child(
                Text(
                    style =
                        Style.padding(all = 10.dp)
                            .flex(grow = 1f)
                            .alignSelf(YogaAlign.CENTER)
                            .testKey("INSERT")
                            .onClick {
                              val updatedMessageList = messages.value.toMutableList()
                              updatedMessageList.add(
                                  1,
                                  Message(true, "Just Added #${counter.value}", true, "Recently"))
                              counter.update { prevValue -> prevValue + 1 }
                              messages.update(updatedMessageList)
                            },
                    text = "INSERT",
                    textSize = 20.sp,
                    alignment = TextAlignment.CENTER))
            child(
                Text(
                    style =
                        Style.padding(all = 10.dp)
                            .flex(grow = 1f)
                            .alignSelf(YogaAlign.CENTER)
                            .onClick {
                              val updatedMessageList = messages.value.toMutableList()
                              if (initialMessages.size < updatedMessageList.size) {
                                updatedMessageList.removeAt(1)
                                messages.update(updatedMessageList)
                              }
                            },
                    text = "DELETE",
                    textSize = 20.sp,
                    alignment = TextAlignment.CENTER))
          })
      child(
          RecyclerCollectionComponent(
              style = Style.flex(grow = 1f).padding(top = 8.dp),
              disablePTR = true,
              itemAnimator = NotAnimatedItemAnimator(),
              section =
                  DataDiffSection.create<Message>(SectionContext(context))
                      .data(messages.value)
                      .renderEventHandler(
                          eventHandlerWithReturn { event -> event.model.createComponent() })
                      .build()))
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import android.graphics.Color
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.flexbox.alignSelf
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sp
import com.facebook.litho.transition.transitionKey
import com.facebook.samples.litho.kotlin.animations.expandableelement.TRANSITION_TOP_DETAIL
import com.facebook.yoga.YogaAlign

class ExpandableElementTopDetail(private val timestamp: String) : KComponent() {

  override fun ComponentScope.render(): Component? {
    return Text(
        style = Style.alignSelf(YogaAlign.CENTER).transitionKey(context, TRANSITION_TOP_DETAIL),
        textSize = 14.sp,
        textColor = Color.GRAY,
        text = timestamp)
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.messages

import com.facebook.litho.widget.ComponentRenderInfo
import com.facebook.litho.widget.RenderInfo
import com.facebook.samples.litho.kotlin.animations.expandableelement.ExpandableElementMe
import com.facebook.samples.litho.kotlin.animations.expandableelement.ExpandableElementOther

class Message(
    private val isMe: Boolean,
    private val message: String,
    private val seen: Boolean,
    private val timestamp: String
) {

  fun createComponent(): RenderInfo {
    val component =
        if (isMe) {
          ExpandableElementMe(messageText = message, timestamp = timestamp, seen = seen)
        } else {
          ExpandableElementOther(messageText = message, timestamp = timestamp, seen = seen)
        }

    return ComponentRenderInfo.create().component(component).build()
  }

  companion object {
    val MESSAGES =
        listOf(
            Message(
                true,
                "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque " +
                    "laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi " +
                    "architecto beatae vitae dicta sunt explicabo",
                true,
                "DEC 25 AT 9:55"),
            Message(
                false,
                "Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit",
                true,
                "DEC 25 AT 9:58"),
            Message(
                false,
                "sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.",
                true,
                "DEC 25 AT 9:59"),
            Message(true, "Neque porro quisquam est", true, "DEC 25 AT 9:59"),
            Message(false, "qui dolorem ipsum quia dolor sit amet", true, "DEC 25 AT 10:01"),
            Message(true, "consectetur, adipisci velit", true, "DEC 25 AT 10:02"),
            Message(
                true,
                "sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam " +
                    "quaerat voluptatem",
                true,
                "DEC 25 AT 10:07"),
            Message(
                true,
                "Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit " +
                    "laboriosam",
                true,
                "DEC 25 AT 10:11"),
            Message(false, "nisi ut aliquid ex ea commodi consequatur?", true, "DEC 25 AT 10:16"),
            Message(
                true,
                "Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil" +
                    " molestiae consequatur",
                true,
                "DEC 25 AT 10:21"),
            Message(
                false,
                "vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?",
                false,
                "DEC 25 AT 10:25"),
            Message(
                false,
                "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis " +
                    "praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias " +
                    "excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui " +
                    "officia deserunt mollitia animi, id est laborum et dolorum fuga.",
                false,
                "DEC 25 AT 10:29"))
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.transitions

import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.margin
import com.facebook.litho.core.width
import com.facebook.litho.dp
import com.facebook.litho.transition.CrossFade
import com.facebook.litho.transition.ExpandToReveal
import com.facebook.litho.useState
import com.facebook.litho.view.background
import com.facebook.litho.view.onClick
import com.facebook.samples.litho.kotlin.drawable.RoundedRect

class ContainersComponent : KComponent() {

  override fun ComponentScope.render(): Component? {

    val isExpanded = useState { true }
    val showSecondComponent = useState { false }

    val firstComponent =
        Column(
            style =
                Style.width(100.dp)
                    .height(50.dp)
                    .margin(all = 5.dp)
                    .background(RoundedRect(0xff6ab071, 8.dp)))
    val secondComponent =
        Column(
            style =
                Style.width(50.dp)
                    .height(50.dp)
                    .margin(all = 5.dp)
                    .background(RoundedRect(0xffbf678d, 8.dp)))

    return Column(style = Style.width(200.dp)) {
      child(
          Column(
              style =
                  Style.width(100.dp)
                      .height(50.dp)
                      .margin(all = 5.dp)
                      .background(RoundedRect(0xff6ab071, 8.dp))
                      .onClick { isExpanded.update(!isExpanded.value) }))

      child(
          ExpandToReveal(
              isExpanded.value,
              Column(
                  style =
                      Style.width(50.dp)
                          .height(50.dp)
                          .margin(all = 5.dp)
                          .background(RoundedRect(0xffbf678d, 8.dp)))))
      child(
          Column(
              style =
                  Style.width(150.dp)
                      .height(50.dp)
                      .margin(all = 5.dp)
                      .background(RoundedRect(0xffa4dece, 8.dp))
                      .onClick { showSecondComponent.update(!showSecondComponent.value) }))
      child(CrossFade(showSecondComponent.value, firstComponent, secondComponent))
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.animations.transitions

import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.Transition
import com.facebook.litho.animation.AnimatedProperties
import com.facebook.litho.core.height
import com.facebook.litho.core.margin
import com.facebook.litho.core.width
import com.facebook.litho.dp
import com.facebook.litho.flexbox.alignSelf
import com.facebook.litho.transition.transitionKey
import com.facebook.litho.transition.useTransition
import com.facebook.litho.useState
import com.facebook.litho.view.alpha
import com.facebook.litho.view.background
import com.facebook.litho.view.onClick
import com.facebook.samples.litho.kotlin.drawable.RoundedRect
import com.facebook.yoga.YogaAlign

private const val TRANSITION_KEY_TEXT = "key"
private const val TRANSITION_KEY2_TEXT = "key2"

class TransitionsComponent : KComponent() {

  override fun ComponentScope.render(): Component? {
    useTransition(
        Transition.parallel<Transition.BaseTransitionUnitsBuilder>(
            Transition.create(Transition.TransitionKeyType.GLOBAL, TRANSITION_KEY_TEXT)
                .animate(AnimatedProperties.X),
            Transition.create(TRANSITION_KEY_TEXT).animate(AnimatedProperties.ALPHA),
            Transition.create(Transition.TransitionKeyType.GLOBAL, TRANSITION_KEY2_TEXT)
                .animate(AnimatedProperties.HEIGHT, AnimatedProperties.WIDTH)))

    val alphaValue = useState { 1f }
    val shouldExpand = useState { false }
    val toRight = useState { true }
    return Column(
        style =
            Style.width(200.dp).alpha(alphaValue.value).onClick {
              toRight.update(!toRight.value)
              alphaValue.update { prevValue -> if (prevValue == 1f) 0.5f else 1f }
              shouldExpand.update(!shouldExpand.value)
            }) {
          child(
              Column(
                  style =
                      Style.width(50.dp)
                          .height(50.dp)
                          .margin(all = 5.dp)
                          .transitionKey(
                              context, TRANSITION_KEY_TEXT, Transition.TransitionKeyType.GLOBAL)
                          .alignSelf(
                              if (toRight.value) YogaAlign.FLEX_END else YogaAlign.FLEX_START)
                          .background(RoundedRect(0xff666699, 8.dp))))
          child(
              Column(
                  style =
                      Style.width(if (shouldExpand.value) 75.dp else 50.dp)
                          .height(if (shouldExpand.value) 75.dp else 50.dp)
                          .margin(all = 5.dp)
                          .transitionKey(
                              context, TRANSITION_KEY2_TEXT, Transition.TransitionKeyType.GLOBAL)
                          .background(RoundedRect(0xffba7bb5, 8.dp))))
          child(ContainersComponent())
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.Text

class AllBorder : KComponent() {

  override fun ComponentScope.render(): Component {

    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(NiceColor.BLUE, 5f.dp),
                ))) {
          child(
              Text(
                  "This component has all borders specified to the same color + width",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.Text

class AlternateColorBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(width = 5f.dp),
                    edgeTop = BorderEdge(color = NiceColor.YELLOW),
                    edgeBottom = BorderEdge(color = NiceColor.BLUE),
                    edgeLeft = BorderEdge(color = NiceColor.RED),
                    edgeRight = BorderEdge(color = NiceColor.GREEN),
                ))) {
          child(
              Text(
                  "This component has all borders specified to the same width, but not colors",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderEffect
import com.facebook.litho.kotlin.widget.BorderRadius
import com.facebook.litho.kotlin.widget.Text

// this doesn't actually have a path on it though?
class AlternateColorCornerPathEffectBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(width = 5f.dp),
                    edgeTop = BorderEdge(color = NiceColor.ORANGE),
                    edgeBottom = BorderEdge(color = NiceColor.BLUE),
                    edgeLeft = BorderEdge(color = NiceColor.RED),
                    edgeRight = BorderEdge(color = NiceColor.GREEN),
                    radius = BorderRadius(20f.dp),
                    effect = BorderEffect.discrete(4f, 11f)))) {
          child(
              Text(
                  "This component has a path effect with rounded corners + multiple colors",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderEffect
import com.facebook.litho.kotlin.widget.Text

class AlternateColorPathEffectBorder : KComponent() {

  override fun ComponentScope.render(): Component? {
    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(width = 5f.dp),
                    edgeLeft = BorderEdge(NiceColor.RED),
                    edgeTop = BorderEdge(NiceColor.ORANGE),
                    edgeRight = BorderEdge(NiceColor.GREEN),
                    edgeBottom = BorderEdge(NiceColor.BLUE),
                    effect = BorderEffect.discrete(5f, 10f)))) {
          child(Text("This component has a path effect with multiple colors", textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.Text

class AlternateColorWidthBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    edgeTop = BorderEdge(NiceColor.YELLOW, 4f.dp),
                    edgeBottom = BorderEdge(NiceColor.BLUE, 16f.dp),
                    edgeLeft = BorderEdge(NiceColor.RED, 2f.dp),
                    edgeRight = BorderEdge(NiceColor.GREEN, 8f.dp),
                ))) {
          child(
              Text(
                  "This component has each border specified to a different color + width",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.Text

class AlternateWidthBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(color = NiceColor.MAGENTA),
                    edgeTop = BorderEdge(width = 4f.dp),
                    edgeBottom = BorderEdge(width = 16f.dp),
                    edgeLeft = BorderEdge(width = 2f.dp),
                    edgeRight = BorderEdge(width = 8f.dp),
                ))) {
          child(
              Text(
                  "This component has all borders specified to the same color, but not width",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.eventHandlerWithReturn
import com.facebook.litho.sections.SectionContext
import com.facebook.litho.sections.common.DataDiffSection
import com.facebook.litho.sections.common.RenderEvent
import com.facebook.litho.sections.widget.RecyclerCollectionComponent
import com.facebook.litho.widget.ComponentRenderInfo
import com.facebook.litho.widget.RenderInfo

class BorderEffectsComponentKotlin : KComponent() {

  private val components =
      listOf(
          AllBorder(),
          AlternateColorBorder(),
          AlternateWidthBorder(),
          AlternateColorWidthBorder(),
          RtlColorWidthBorder(),
          DashPathEffectBorder(),
          VerticalDashPathEffectBorder(),
          AlternateColorPathEffectBorder(),
          AlternateColorCornerPathEffectBorder(),
          CompositePathEffectBorder(),
          VaryingRadiiBorder())

  override fun ComponentScope.render(): Component {
    return RecyclerCollectionComponent(
        section =
            DataDiffSection.create<Component>(SectionContext(context))
                .data(components)
                .renderEventHandler(
                    eventHandlerWithReturn { event: RenderEvent<out Component> -> onRender(event) })
                .build(),
        disablePTR = true)
  }

  private fun onRender(event: RenderEvent<out Component>): RenderInfo {
    return ComponentRenderInfo.create().component(event.model).build()
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderEffect
import com.facebook.litho.kotlin.widget.BorderRadius
import com.facebook.litho.kotlin.widget.Text

class CompositePathEffectBorder : KComponent() {

  override fun ComponentScope.render(): Component {

    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(width = 20f.dp),
                    edgeTop = BorderEdge(color = NiceColor.ORANGE),
                    edgeBottom = BorderEdge(color = NiceColor.BLUE),
                    edgeLeft = BorderEdge(color = NiceColor.RED),
                    edgeRight = BorderEdge(color = NiceColor.GREEN),
                    radius = BorderRadius(20f.dp),
                    effect = BorderEffect.dashed(floatArrayOf(10f, 5f), 0f)))) {
          child(
              Text(
                  "This component has a composite path effect of discrete + corner",
                  textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderEffect
import com.facebook.litho.kotlin.widget.Text

class DashPathEffectBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    BorderEdge(NiceColor.BLUE, 5f.dp),
                    effect = BorderEffect.dashed(floatArrayOf(10f, 5f), 0f)))) {
          child(Text("This component has a dash path effect applied", textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

object NiceColor {
  val RED: Int
    get() = 0xffee4035.toInt()

  val ORANGE: Int
    get() = 0xfff37736.toInt()

  val YELLOW: Int
    get() = 0xfffdf498.toInt()

  val GREEN: Int
    get() = 0xff7bc043.toInt()

  val BLUE: Int
    get() = 0xff0392cf.toInt()

  val MAGENTA: Int
    get() = 0xffba02cf.toInt()
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.flexbox.layoutDirection
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.Text
import com.facebook.yoga.YogaDirection

class RtlColorWidthBorder : KComponent() {

  override fun ComponentScope.render(): Component {

    return Row(
        style =
            Style.border(
                    Border(
                        edgeStart = BorderEdge(NiceColor.RED, 2f.dp),
                        edgeEnd = BorderEdge(NiceColor.GREEN, 8f.dp),
                        edgeTop = BorderEdge(NiceColor.YELLOW, 4f.dp),
                        edgeBottom = BorderEdge(NiceColor.BLUE, 16f.dp)))
                .layoutDirection(YogaDirection.RTL)) {
          child(Text("This component is RTL", textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import android.graphics.Color
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderRadius
import com.facebook.litho.kotlin.widget.Text

class VaryingRadiiBorder : KComponent() {
  override fun ComponentScope.render(): Component {

    return Row(
        style =
            Style.border(
                Border(
                    edgeAll = BorderEdge(width = 3f.dp),
                    edgeTop = BorderEdge(color = NiceColor.GREEN),
                    edgeBottom = BorderEdge(color = NiceColor.BLUE),
                    edgeLeft = BorderEdge(color = Color.BLACK),
                    edgeRight = BorderEdge(NiceColor.RED),
                    radius =
                        BorderRadius(
                            topLeft = 10f.dp,
                            topRight = 5f.dp,
                            bottomLeft = 30f.dp,
                            bottomRight = 20f.dp),
                ))) {
          child(Text("This component has varying corner radii", textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.bordereffects

import com.facebook.litho.Border
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.dp
import com.facebook.litho.flexbox.border
import com.facebook.litho.kotlin.widget.Border
import com.facebook.litho.kotlin.widget.BorderEdge
import com.facebook.litho.kotlin.widget.BorderEffect
import com.facebook.litho.kotlin.widget.Text

class VerticalDashPathEffectBorder : KComponent() {

  override fun ComponentScope.render(): Component {
    return Row(
        style =
            Style.border(
                Border(
                    BorderEdge(width = 5f.dp),
                    edgeVertical = BorderEdge(color = NiceColor.RED),
                    effect = BorderEffect.dashed(floatArrayOf(20f, 5f), 0f)))) {
          child(
              Text(
                  "This component has a dash path effect on its vertical edges", textSize = 20f.dp))
        }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.animation.ValueAnimator
import android.graphics.Color
import android.view.animation.LinearInterpolator
import com.facebook.litho.ClickEvent
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.useRef
import com.facebook.litho.useState
import com.facebook.litho.view.onClick
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.litho.widget.canvas.Transform
import com.facebook.mountable.utils.types.Point
import com.facebook.mountable.utils.types.Size
import com.facebook.mountable.utils.types.center

// start_example
class DrawAnimatedSquareCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    val rotation = useState { 0f }
    val animator = useRef<ValueAnimator?> { null }

    val startAnimator: (ClickEvent) -> Unit = {
      animator.value?.cancel()
      animator.value =
          ValueAnimator.ofFloat(0f, 360f).apply {
            duration = 2000
            interpolator = LinearInterpolator()
            repeatCount = ValueAnimator.INFINITE
            addUpdateListener { rotation.update(it.animatedValue as Float) }
          }
      animator.value?.start()
    }

    return Column {
      child(
          CanvasComponent(
              style = Style.widthPercent(100f).height(100.px).onClick(action = startAnimator)) {
                group(
                    transform =
                        Transform {
                          translate(dx = size.center.x, dy = size.center.y)
                          rotate(rotation.value, pivot = size.center)
                        }) {
                      // draw square
                      fill(
                          shape = Shape.rect(topLeft = Point(-30f, -30f), size = Size(60f, 60f)),
                          shading = Shading.solidColor(Color.RED))
                    }
              })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.useCached
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Gradient
import com.facebook.litho.widget.canvas.Path
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.litho.widget.canvas.Transform
import com.facebook.mountable.utils.types.Point

// start_example
class DrawPathCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    // Using useCached to avoid recreating Path object on state updates
    val heartPath = useCached {
      // A heart shape, the path data taken from some random svg found online
      Path {
        add(
            Path {
              moveTo(Point(75f, 40f))
              cubicTo(Point(75f, 37f), Point(70f, 25f), Point(50f, 25f))
              cubicTo(Point(20f, 25f), Point(20f, 62.5f), Point(20f, 62.5f))
              cubicTo(Point(20f, 80f), Point(40f, 102f), Point(75f, 120f))
              cubicTo(Point(110f, 102f), Point(130f, 80f), Point(130f, 62.5f))
              cubicTo(Point(130f, 62.5f), Point(130f, 25f), Point(100f, 25f))
              cubicTo(Point(85f, 25f), Point(75f, 37f), Point(75f, 40f))
            },
            // the heart path starts at 20,25 so translate it to make it start at 0,0 in order to
            // make
            // positioning easier
            Transform { translate(dx = -20f, dy = -25f) })
      }
    }

    return Column {
      child(
          CanvasComponent(style = Style.widthPercent(100f).height(100.px)) {
            // left heart
            fill(shape = Shape.path(heartPath), shading = Shading.solidColor(Color.RED))
            // right heart translated using a group
            group(transform = Transform { translate(dx = 120f) }) {
              fill(
                  shape = Shape.path(heartPath),
                  shading =
                      Shading.linearGradient(
                          gradient = Gradient(Color.RED, Color.GREEN, Color.BLUE),
                          startPoint = Point.Zero,
                          endPoint = Point(110f, 0f)))
            }
          })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.litho.widget.canvas.Transform
import com.facebook.mountable.utils.types.Point
import com.facebook.mountable.utils.types.Size

// start_example
class DrawRotatedGroupCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    return Column {
      child(
          CanvasComponent(style = Style.widthPercent(100f).height(100.px)) {
            group(transform = Transform { rotate(degrees = 45f, pivot = Point(50f, 20f)) }) {
              // first square
              fill(
                  shape = Shape.rect(topLeft = Point(40f, 10f), size = Size(40f, 40f)),
                  shading = Shading.solidColor(Color.RED))
              // second square
              fill(
                  shape = Shape.rect(topLeft = Point(90f, 10f), size = Size(40f, 40f)),
                  shading = Shading.solidColor(Color.GREEN))
            }
          })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Gradient
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.mountable.utils.types.Point

// start_example
class DrawShapeCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    return Column {
      child(
          CanvasComponent(style = Style.widthPercent(100f).height(100.px)) {
            // left circle
            fill(
                shape = Shape.circle(center = Point(40f, 40f), radius = 40f),
                shading = Shading.solidColor(Color.RED))
            // right circle
            fill(
                shape = Shape.circle(center = Point(140f, 40f), radius = 40f),
                shading =
                    Shading.linearGradient(
                        gradient = Gradient(Color.RED, Color.GREEN, Color.BLUE),
                        startPoint = Point.Zero,
                        endPoint = Point(180f, 0f)))
          })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Gradient
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.mountable.utils.types.Point
import com.facebook.mountable.utils.types.Size

// start_example
class DrawStrokedShapeCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    return Column {
      child(
          CanvasComponent(style = Style.widthPercent(100f).height(100.px)) {
            // first ellipse
            stroke(
                shape = Shape.ellipse(Point(10f, 10f), Size(60f, 30f)),
                shading = Shading.solidColor(Color.RED),
                lineWidth = 4f,
                dashLengths = floatArrayOf(8f, 4f))
            // second ellipse
            stroke(
                shape = Shape.ellipse(Point(90f, 10f), Size(60f, 30f)),
                shading =
                    Shading.linearGradient(
                        gradient = Gradient(Color.RED, Color.GREEN, Color.BLUE),
                        startPoint = Point(90f, 0f),
                        endPoint = Point(150f, 0f)),
                lineWidth = 4f,
                dashLengths = floatArrayOf(8f, 4f))
          })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.canvas

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.widthPercent
import com.facebook.litho.px
import com.facebook.litho.widget.canvas.CanvasComponent
import com.facebook.litho.widget.canvas.Gradient
import com.facebook.litho.widget.canvas.Shading
import com.facebook.litho.widget.canvas.Shape
import com.facebook.litho.widget.canvas.Transform
import com.facebook.mountable.utils.types.BlendingMode
import com.facebook.mountable.utils.types.Point

// start_example
class DrawTransparentHoleCanvasKComponent : KComponent() {
  override fun ComponentScope.render(): Component {
    return Column {
      child(
          CanvasComponent(style = Style.widthPercent(100f).height(100.px)) {
            // gradient background
            fill(
                // this.size returns the size of the current drawing scope, in this case it'll be
                // the size of the canvas
                shape = Shape.rect(topLeft = Point.Zero, size = size),
                shading =
                    Shading.linearGradient(
                        gradient = Gradient(Color.RED, Color.GREEN, Color.BLUE),
                        startPoint = Point.Zero,
                        endPoint = Point(size.width, 0f)))
            layer(
                transform =
                    Transform { translate(dx = size.width * 0.1f, dy = size.height * 0.1f) },
                size = size * 0.8f // 80% of the canvas size
                ) {
                  // layer background
                  fill(
                      shape = Shape.rect(topLeft = Point.Zero, size = size),
                      shading = Shading.solidColor(Color.CYAN))
                  // ellipse with xor blending mode
                  fill(
                      shape =
                          Shape.ellipse(
                              topLeft = Point(size.width * 0.1f, size.height * 0.1f),
                              size = size * 0.8f),
                      shading = Shading.solidColor(Color.BLACK),
                      blendingMode = BlendingMode.Xor)
                }
          })
    }
  }
}
// end_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import com.facebook.litho.ClickEvent
import com.facebook.litho.ResourcesScope
import com.facebook.litho.Style
import com.facebook.litho.kotlinStyle
import com.facebook.litho.view.onClick
import com.facebook.litho.widget.Text

@Suppress("FunctionName")
inline fun ResourcesScope.Button(
    text: String,
    noinline onClick: (ClickEvent) -> Unit,
): Text =
    Text.create(context, android.R.attr.buttonStyle, 0)
        .text(text)
        .kotlinStyle(Style.onClick(action = onClick))
        .build()


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.useState
import com.facebook.litho.widget.collection.LazyList

class ChangeableItemsCollectionKComponent : KComponent() {

  data class Person(val id: Int, val name: String, val score: Int)

  private val comparator = compareBy<Person> { it.score }.thenBy { it.name }

  override fun ComponentScope.render(): Component {
    val counter = useState { 0 }
    val inOrder = useState { true }

    val people =
        listOf(
            Person(1, "Jeff Winger", counter.value),
            Person(2, "Annie Edison", 3),
            Person(3, "Britta Perry", 1),
            Person(4, "Abed Nadir", 4))

    val orderedPeople =
        people.sortedWith(if (inOrder.value) comparator else comparator.reversed<Person>())

    return Column(style = Style.padding(16.dp)) {
      child(
          Row {
            child(Button("Reverse Order") { inOrder.update { !it } })
            child(Button("Jeff +1") { counter.update { (it + 1) % 5 } })
          })
      child(
          LazyList {
            children(items = orderedPeople, id = { it.id }) {
              Text("${it.name} ${"\uD83D\uDC31".repeat(it.score + 1)}")
            }
          })
    }
  }
}


// (c) Facebook, Inc. and its affiliates. Confidential and proprietary.

package com.facebook.samples.litho.kotlin.collection

/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.flexbox.flex
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.widget.collection.LazyList

class CollectionKComponent : KComponent() {

  private val friends = listOf("Ross", "Rachel", "Joey", "Phoebe", "Monica", "Chandler")

  override fun ComponentScope.render(): Component =
      LazyList(style = Style.flex(grow = 1f)) {
        child(Text(text = "Header"))
        children(items = friends, id = { it }) { Text(it) }
        child(Text(text = "Footer"))
      }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import android.graphics.Color
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Row
import com.facebook.litho.Style
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sp
import com.facebook.litho.useState
import com.facebook.litho.view.alpha
import com.facebook.litho.widget.collection.LazyList

class DepsCollectionKComponent : KComponent() {

  override fun ComponentScope.render(): Component? {
    val color = useState { Color.RED }
    val size = useState { 14 }
    val alpha = useState { 1f }

    return Column(style = Style.padding(16.dp)) {
      child(
          Row {
            child(
                Button("Toggle Color") {
                  color.update { prevColor ->
                    if (prevColor == Color.RED) Color.BLUE else Color.RED
                  }
                })
            child(
                Button("Toggle Size") {
                  size.update { prevSize -> if (prevSize == 14) 28 else 14 }
                })
            child(
                Button("Toggle Alpha") {
                  alpha.update { prevAlpha -> if (prevAlpha == 0.5f) 1f else 0.5f }
                })
          })
      child(
          LazyList {
            child(
                Text(
                    "deps = null (all props)",
                    textColor = color.value,
                    textSize = size.value.sp,
                    style = Style.alpha(alpha.value)))
            child(deps = arrayOf(color.value)) {
              Text(
                  "deps = arrayOf(color.value)",
                  textColor = color.value,
                  textSize = size.value.sp,
                  style = Style.alpha(alpha.value))
            }
            child(deps = arrayOf(size.value)) {
              Text(
                  "deps = arrayOf(size.value)",
                  textColor = color.value,
                  textSize = size.value.sp,
                  style = Style.alpha(alpha.value))
            }
            child(deps = arrayOf()) {
              Text(
                  "deps = arrayOf()",
                  textColor = color.value,
                  textSize = size.value.sp,
                  style = Style.alpha(alpha.value))
            }
          })
    }
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.kotlin.widget.VerticalScroll
import com.facebook.litho.widget.collection.LazyList

// start_data
class Person(val name: String, val id: Int)

private val friends =
    listOf(
        Person("Ross Geller", 1),
        Person("Monica Geller", 2),
        Person("Rachel Green", 3),
        Person("Phoebe Buffay", 4),
        Person("Joey Tribbiani", 5),
        Person("Chandler Bing", 6),
    )
// end_data

// start_column_example
class FriendsColumn(private val friends: List<Person>) : KComponent() {
  override fun ComponentScope.render(): Component = VerticalScroll {
    Column { friends.forEach { friend -> child(Text(friend.name)) } }
  }
}
// end_column_example

class FriendsCollectionKComponent : KComponent() {
  override fun ComponentScope.render(): Component = FriendLazyList(friends)
}

// start_lazy_list_example
class FriendLazyList(private val friends: List<Person>) : KComponent() {
  override fun ComponentScope.render(): Component = LazyList {
    children(friends, id = { it.id }) { Text(it.name) }
  }
}
// end_lazy_list_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import android.graphics.Color
import androidx.recyclerview.widget.RecyclerView
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.core.padding
import com.facebook.litho.dp
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.sp
import com.facebook.litho.view.background
import com.facebook.litho.widget.collection.CrossAxisWrapMode
import com.facebook.litho.widget.collection.LazyList
import com.facebook.litho.widget.collection.LinearSpacing
import com.facebook.samples.litho.kotlin.drawable.RoundedRect

class HorizontalScrollKComponent : KComponent() {

  override fun ComponentScope.render(): Component? {
    return LazyList(
        itemDecoration = LinearSpacing(all = 20.dp),
    ) {
      child(FixedHeightHScroll())
      child(WrapFirstItemHeightHScroll())
      child(WrapDynamicHScroll())
    }
  }
}

// start_example
class FixedHeightHScroll : KComponent() {

  override fun ComponentScope.render(): Component =
      LazyList(
          orientation = RecyclerView.HORIZONTAL,
          itemDecoration = LinearSpacing(all = 10.dp),
          style = Style.height(100.dp),
      ) {
        children(items = (0..10), id = { it }) { ListItem("$it") }
      }
}
// end_example

class WrapFirstItemHeightHScroll : KComponent() {

  override fun ComponentScope.render(): Component =
      LazyList(
          orientation = RecyclerView.HORIZONTAL,
          crossAxisWrapMode = CrossAxisWrapMode.MatchFirstChild,
          itemDecoration = LinearSpacing(all = 10.dp),
      ) {
        children(items = (0..10), id = { it }) { ListItem("$it") }
      }
}

class WrapDynamicHScroll : KComponent() {

  override fun ComponentScope.render(): Component =
      LazyList(
          orientation = RecyclerView.HORIZONTAL,
          crossAxisWrapMode = CrossAxisWrapMode.Dynamic,
          itemDecoration = LinearSpacing(all = 10.dp),
      ) {
        children(items = (0..10), id = { it }) {
          ListItem(
              text = "$it",
              style = Style.padding(horizontal = 30.dp, vertical = (it * 5).dp),
          )
        }
      }
}

class ListItem(private val text: String, private val style: Style? = null) : KComponent() {
  override fun ComponentScope.render(): Component =
      Text(
          text = text,
          textSize = 24.sp,
          style = Style.padding(all = 30.dp).background(RoundedRect(Color.LTGRAY, 10.dp)) + style)
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.useState
import com.facebook.litho.widget.collection.LazyCollectionController
import com.facebook.litho.widget.collection.LazyList

// start_scrolling_example
class ScrollingExample() : KComponent() {

  override fun ComponentScope.render(): Component {
    val controller = useState { LazyCollectionController() }.value

    // Use one of these lambdas to scroll, e.g. in an onClick callback
    val scrollToTenth = controller.scrollToIndex(10)
    val smoothScrollToEnd = controller.smoothScrollToId("End")

    return LazyList(
        lazyCollectionController = controller,
    ) {
      children(items = (0..20), id = { it }) { Text("$it") }
      child(id = "End", component = Text("End"))
    }
  }
}
// end_scrolling_example

// start_pull_to_refresh_example
class PullToRefreshExample(
    val data: List<String>,
    val refresh: () -> Unit,
) : KComponent() {

  override fun ComponentScope.render(): Component {
    val controller = useState { LazyCollectionController() }.value
    return LazyList(
        lazyCollectionController = controller,
        onPullToRefresh = {
          refresh()
          controller.setRefreshing(false)
        },
    ) { /* Add children */}
  }
}
// end_pull_to_refresh_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.RecyclerView
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.Style
import com.facebook.litho.core.height
import com.facebook.litho.dp
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.widget.collection.LazyList
import com.facebook.litho.widget.collection.LinearSpacing

// start_linear_spacing_example
class LinearSpacingExample : KComponent() {
  override fun ComponentScope.render(): Component =
      LazyList(
          itemDecoration = LinearSpacing(start = 10.dp, between = 5.dp),
      ) { /* Add children */}
}
// end_linear_spacing_example

// start_fixed_height_hscroll_example
class HScrollFixedHeight : KComponent() {
  override fun ComponentScope.render(): Component =
      LazyList(
          orientation = RecyclerView.HORIZONTAL,
          style = Style.height(100.dp),
      ) { /* Add children */}
}
// end_fixed_height_hscroll_example

@RequiresApi(Build.VERSION_CODES.N)
// start_sticky_header_example
class StickyHeader(val names: List<String>) : KComponent() {
  override fun ComponentScope.render(): Component {
    val namesGroupedByFirstLetter = names.groupBy { it.first() }
    return LazyList {
      namesGroupedByFirstLetter.forEach { (firstLetter, names) ->
        child(id = firstLetter, isSticky = true, component = Text("$firstLetter"))
        children(items = names, id = { it }) { Text(it) }
      }
    }
  }
}
// end_sticky_header_example


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.State
import com.facebook.litho.Style
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.useState
import com.facebook.litho.view.onClick
import com.facebook.litho.widget.collection.LazyList
import com.facebook.litho.widget.collection.LazyListScope

class ModularCollectionKComponent : KComponent() {

  override fun ComponentScope.render(): Component {
    val nestedContentVisible = useState { true }

    return LazyList {
      addHeader()
      addBody(nestedContentVisible)
      addFooter()
    }
  }

  private fun LazyListScope.addHeader() {
    child(isSticky = true, component = Text("Header"))
  }

  private fun LazyListScope.addBody(nestedContentVisible: State<Boolean>) {
    child(
        Text(
            "${if (nestedContentVisible.value) "-" else "+"} Body",
            style = Style.onClick { nestedContentVisible.update(!nestedContentVisible.value) }))
    if (nestedContentVisible.value) {
      children(items = listOf(0, 1, 2, 3), id = { it }) { Text("  Nested Body Item $it") }
    }
  }

  private fun LazyListScope.addFooter() {
    child(Text("Footer"))
  }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.facebook.samples.litho.kotlin.collection

import android.graphics.Typeface
import com.facebook.litho.Column
import com.facebook.litho.Component
import com.facebook.litho.ComponentScope
import com.facebook.litho.KComponent
import com.facebook.litho.kotlin.widget.Text
import com.facebook.litho.useState
import com.facebook.litho.widget.collection.LazyList

class MultiListCollectionKComponent : KComponent() {

  companion object {
    private const val ALL_FRIENDS_TAG = "all_friends_"
    private const val TOP_FRIENDS_TAG = "top_friends_"
  }

  private val friends = listOf("Ross", "Rachel", "Joey", "Phoebe", "Monica", "Chandler")
  private val topFriends = (0..1)
  private val allFriends = (0..5)

  override fun ComponentScope.render(): Component {
    val shouldShowTopFriends = useState { false }

    return Column {
      child(
          Button("Toggle Top Friends") { shouldShowTopFriends.update(!shouldShowTopFriends.value) })
      child(
          LazyList {
            if (shouldShowTopFriends.value) {
              child(
                  id = TOP_FRIENDS_TAG + "title",
                  component = Text("Top Friends", textStyle = Typeface.BOLD))

              children(items = topFriends, id = { TOP_FRIENDS_TAG + it }) { Text(friends[it]) }
            }

            child(
                id = ALL_FRIENDS_TAG + "title",
                component = Text("All Friends", textStyle = Typeface.BOLD))
            children(items = allFriends, id = { ALL_FRIENDS_TAG + it }) { Text(friends[it]) }
          })
    }
  }
}