All Downloads are FREE. Search and download functionalities are using the official Maven repository.

simpleivr.IvrChoices.scala Maven / Gradle / Ivy

package simpleivr

import cats.free.Free
import cats.implicits._


class IvrChoices(sayables: Sayables) extends Ivr(sayables) {

  import sayables._


  def paginated[T](maximum: Int, choices: List[Choice[T]], fixedChoices: List[Choice[T]]): List[Choice[IvrStep[T]]] = {
    def doPage(page: List[Choice[T]], rest: List[Choice[T]], back: List[Choice[T]]): List[Choice[IvrStep[T]]] = {
      def askNextPage: IvrStep[T] = Free.defer {
        val (p, r) = rest.splitAt(7)
        val b = page ::: back
        askChoice(ChoiceMenu(Sayable.Empty, doPage(p, r, b))).flatten
      }

      def askPrevPage: IvrStep[T] = Free.defer {
        if (back.length >= maximum) {
          val num = if (back.length <= 8) back.length else 7
          val (page2, back2) = back.splitAt(num)
          val rest2 = page ::: rest
          askChoice(ChoiceMenu(Sayable.Empty, doPage(page2, rest2, back2))).flatten
        } else {
          val (page2, rest2) = choices.splitAt(maximum - 1)
          val back2 = Nil
          askChoice(ChoiceMenu(Sayable.Empty, doPage(page2, rest2, back2))).flatten
        }
      }

      page.map(_ map IvrStep.apply) ++
        List(Choice(DTMF.`8`, `For more choices`, askNextPage)).filter(_ => rest.nonEmpty) ++
        List(Choice(DTMF.`9`, `For the previous choices`, askPrevPage)).filter(_ => back.nonEmpty) ++
        fixedChoices.map(_ map IvrStep.apply)
    }

    doPage(choices.take(maximum - 1), choices.drop(maximum - 1), Nil)
  }

  sealed class SayChoice(val func: (DTMF, Sayable) => Sayable)
  object SayChoice {
    case object LabelFirst extends SayChoice((key, label) => label & `Press` & dtmfWord(key))
    case object LabelLast extends SayChoice((key, label) => `Press` & dtmfWord(key) & label)
  }

  def choiceMenuSayable[A](choiceMenu: ChoiceMenu[A], pauseMs: Int, sayChoice: SayChoice) =
    choiceMenu.title &
      Sayable.Many(
        choiceMenu.assigned.map {
          case Choice.Assigned(key, label, _) =>
            Sayable.Group(Pause(pauseMs) & sayChoice.func(key, label))
        }
      )

  protected def defaultAskChoicePauseMs: Int = 750
  protected def defaultAskChoiceSayChoice: SayChoice = SayChoice.LabelLast

  def askChoice[A](choiceMenu: ChoiceMenu[A],
                   pauseMs: Int = defaultAskChoicePauseMs,
                   sayChoice: SayChoice = defaultAskChoiceSayChoice): IvrStep[A] = {
    val menuSayable = choiceMenuSayable(choiceMenu, pauseMs, sayChoice)

    def loop: IvrStep[A] =
      sayAndGetDigit(menuSayable)
        .flatMap {
          case None    => IvrStep.say(`Please make a selection` & Pause(pauseMs)) *> loop
          case Some(c) =>
            choiceMenu.assigned.find(_.maybeDtmf.contains(c)) match {
              case Some(choice) => IvrStep(choice.value)
              case None         => IvrStep.say(`That is not one of the choices.` & Pause(pauseMs)) *> loop
            }
        }

    loop
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy