Requirements

Installation

Add io.elements.pay:treasure to your build.gradle dependencies.

Gradle

dependencies {
    implementation 'io.elements.pay:treasure:1.0.0-beta01'
}

TreasureHost

TreasureHost class is the main interface that communicates between client application and flexible UI SDK. You can initialize TreasureHost in the following way.

val treasureHost = TreasureHost(
  configuration = Treasure.Configuration(
    TreasureEnvironment.sandbox("Your client token goes here...")
  )
)

Set up client side dependencies

Treasure provides interfaces to support passing client dependencies to itself.

Load Images

Treasure allows you to pass customized image downloader to the SDK and Treasure will use it to load images when needed.

See code below for an example on how to create a customized image loader using popular image loading libraries -> Coil

class ImageLoader : TreasureImageLoadable {

  @OptIn(ExperimentalCoilApi::class)
  @Composable
  override fun getPainter(url: String): Painter {
    return rememberImagePainter(data = url)
  }
}

Now you can pass the customized image loader to TreasureDependency in the following way.

TreasureDependency.getInstance().imageLoader = ImageLoader()

Theme + UI resources

Treasure supports dark/light themes at the moment. Client side colors/fonts/image are passed to TreasureDependency using ThemeComponent interface.

Fonts

Treasure supports providing fonts using the following way

enum class FontPlate(val decodeName: String) {
  PRIMARY(decodeName = "primary") {
    override fun toDarkThemeFont() = FontAndSize(io.blocks.treasure.R.font.poppins_medium, 20)
    override fun toLightThemeFont() = FontAndSize(io.blocks.treasure.R.font.poppins_medium, 20)
  },

  SECONDARY(decodeName = "secondary") {
    override fun toLightThemeFont() = FontAndSize(io.blocks.treasure.R.font.poppins_medium, 17)
    override fun toDarkThemeFont() = FontAndSize(io.blocks.treasure.R.font.poppins_medium, 17)
  };

  abstract fun toLightThemeFont(): FontAndSize
  abstract fun toDarkThemeFont(): FontAndSize

  companion object {

    fun toFonts(): ThemeComponent<FontAndSize> {
      val result: MutableMap<String, MutableMap<SystemThemeType, FontAndSize>> = mutableMapOf()
      for (type in FontPlate.values()) {
        result[type.decodeName] = mutableMapOf(
          Pair(SystemThemeType.DARK, type.toDarkThemeFont()),
          Pair(SystemThemeType.LIGHT, type.toLightThemeFont())
        )
      }
      return ThemeComponent(values = result)
    }
  }
}

function toFonts() shows how to provide a ThemeComponent object to the theme class and then passing to TreasureDepedency

So once Treasure SDK sees "primary" in fonts json block, it will be mapped to the primary font provided by the application.

Colors

Similar to fonts, Treasure currently supports two different ways of initializing colors.

  1. Using hex string
"text_color": "#000000" // this represents a black text color
  1. Using color string representation provided by the application.
"text_color": "primary"
enum class ColorPlate(val decodeName: String) {
  PRIMARY(decodeName = "primary") {
    override fun toDarkThemeColor() = Color.White
    override fun toLightThemeColor() = Color.Black
  },

  SECONDARY(decodeName = "secondary") {
    override fun toLightThemeColor() = Color.DarkGray
    override fun toDarkThemeColor() = Color.White
  };

  abstract fun toLightThemeColor(): Color
  abstract fun toDarkThemeColor(): Color

  companion object {

    fun toColors(): ThemeComponent<Color> {
      val result: MutableMap<String, MutableMap<SystemThemeType, Color>> = mutableMapOf()
      for (type in ColorPlate.values()) {
        result[type.decodeName] = mutableMapOf(
          Pair(SystemThemeType.DARK, type.toDarkThemeColor()),
          Pair(SystemThemeType.LIGHT, type.toLightThemeColor())
        )
      }
      return ThemeComponent(values = result)
    }
  }
}

Images

Treasure provides initializing images from local assets folder and remote download URL. In order to use images from local assets folder you can do the following.

import io.blocks.treasure.R
import io.blocks.treasure.core.view.theme.SystemThemeType
import io.blocks.treasure.core.view.theme.ThemeComponent

enum class LocalImages(val decodeName: String) {
  MASTERCARD(decodeName = "mastercard") {
    override fun toDarkThemeImage() = R.drawable.ic_mastercard_32
    override fun toLightThemeImage() = R.drawable.ic_mastercard_32
  },

  SETTINGS(decodeName = "settings") {
    override fun toLightThemeImage() = io.blocks.treasure.R.drawable.ic_settings
    override fun toDarkThemeImage() = io.blocks.treasure.R.drawable.ic_settings
  };

  abstract fun toLightThemeImage(): Int
  abstract fun toDarkThemeImage(): Int

  companion object {

    fun toImages(): ThemeComponent<Int> {
      val result: MutableMap<String, MutableMap<SystemThemeType, Int>> = mutableMapOf()
      for (type in values()) {
        result[type.decodeName] = mutableMapOf(
          Pair(SystemThemeType.DARK, type.toDarkThemeImage()),
          Pair(SystemThemeType.LIGHT, type.toLightThemeImage())
        )
      }
      return ThemeComponent(values = result)
    }
  }
}

Constructing theme object from fonts, colors, images and styles.

In order for treasure to utilize provided resources, you need to construct an object that implements ThemeRegistrable interface and then pass that object to TreasureDependency.

data class Theme(
  override var styles: Map<String, ElementStyle>?,
  override var fonts: ThemeComponent<FontAndSize>?,
  override var colors: ThemeComponent<Color>?,
  override var images: ThemeComponent<Int>?
): ThemeRegistrable {

  // Providing typefaces that can be interpreted in the server json
  override fun getTypeface(id: String): Int? {
    return when (id) {
      "Poppins-Medium" -> R.font.poppins_medium
      "Avenir-Medium" -> R.font.poppins_medium
      else -> null
    }
  }

  // Providing interfaces that TreasureSDK can read and generate the image that mapped to the naming.
  override fun getLocalImage(id: String): Int? {
    return when (id) {
      "checkmark_grey" -> io.blocks.treasure.R.drawable.ic_grey_check
      "payment_mastercard" -> io.blocks.treasure.R.drawable.ic_mastercard_32
      "ic_rider_payment_paypal" -> io.blocks.treasure.R.drawable.ic_paypal_32
      "ic_google_pay" -> io.blocks.treasure.R.drawable.ic_googlepay_32
      "disclosure_indicator_dark" -> R.drawable.ic_glyph_chevron
      "delete_card_gray" -> io.blocks.treasure.R.drawable.ic_circle_x
      "dark_gray_close" -> io.blocks.treasure.R.drawable.ic_close_gray
      "ic_supreme_payment_creditcard" -> io.blocks.treasure.R.drawable.ic_card_blank
      "lime_logomark" -> io.blocks.treasure.R.drawable.ic_lime_cash
      "supreme_close_light_background" -> io.blocks.treasure.R.drawable.ic_close_round
      else -> null
    }
  }
}

TreasureDependency.getInstance().theme = Theme(
  styles = null,
  fonts = FontPlate.toFonts(), 
  colors = ColorPlate.toColors(), 
  images = LocalImages.toImages()
)

Starting Treasure UI

Method 1: Load from Elements' server.

private fun loadFromCheckoutUI() {
  treasureHost.loadFragmentFromCheckoutUI {
    replaceFragment(it)
  }
}

Method 2: Load from local file

private fun loadFromLocal() {
  val fileContent = resources.openRawResource(R.raw.payment_methods_view)
    .bufferedReader().use { it.readText() }
  val fragment = treasureHost.loadFragmentFromLocal(fileContent)
  replaceFragment(fragment)
}

Example App

Clone this repo and open/build the project. The demo app demonstrated how to use Treasure.