# 📊 Views and shared object
## Navigation
- [🏡 Native modules made easy with Expo](/gYH9xz-oR2ai0Yih8if50w)
- [👶 First Steps](/ANE6NSUlTSimTIrN-gMsBw)
- [⚙️ Native Module](/mAIt0ctDTvSL5xV4uE9nWQ)
- [📈 Passing data to view](/_gWWp8uoQwGkqKcEyfk8Tg)
- [📚 View Props](/96IjlLNDRvydILdkbfaA5A)
- [🔥 View Events](/PQWXYmxLRCebmLfx3Fh_gg)
- [🏞️ View Functions](/DcjStCFdT6euzWqnJqCL6w)
- [👷♂️ Classes and Shared Objects](/__42gVw8RqiIgfSbVseIvw)
- [👉 📊 Views and shared object](/IgHyIAHQQPCbeBD74Ri4BA)
---
### Task
Create a linear chart data representation utilizing shared objects and export it as a native class. The shared linear chart data will be passed to the view using a view function. The attached view should also be directly updated when adding new data to the shared data set. Additionally, consider making the exported class constructable from a typed array for convenience.
:::spoiler :robot_face: Android
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartModule.kt`
```kotlin
class SharedDataSetOptions : Record {
@Field
val mode: DataMode = DataMode.LINEAR
@Field
val lineWidth: Float = 5f
}
class SharedDataSet(
initValues: Uint8Array? = null,
options: SharedDataSetOptions? = null
) : SharedObject() {
fun interface Listener {
fun onNewData(newDataSet: LineDataSet)
}
private val listeners = mutableListOf<Listener>()
private val dataSet = LineDataSet(
initValues
?.withIndex()
?.map { (index, value) ->
Entry((index + 1).toFloat(), value.toFloat())
}
?.toMutableList() ?: mutableListOf<Entry?>(),
"label"
).also {
it.applyDefaultSettings()
options?.mode?.toLineDataSetMode()?.let { mode->
it.mode = mode
}
options?.lineWidth?.let { lineWidth ->
it.lineWidth = lineWidth
}
}
fun addListener(newDataListener: Listener) {
listeners.add(newDataListener)
if (dataSet.entryCount != 0) {
newDataListener.onNewData(dataSet)
}
}
fun removeListener(listener: Listener?) {
if (listener == null) {
return
}
listeners.remove(listener)
}
fun addData(value: Float) {
dataSet.addEntry(
Entry(
(dataSet.entryCount + 1).toFloat(),
value
)
)
listeners.forEach { it.onNewData(dataSet) }
}
}
// ...
AsyncFunction("setDataSet") { view: LinearChartView, sharedDataSet: SharedDataSet ->
view.setSharedDataSet(sharedDataSet)
}
// ...
Class(SharedDataSet::class) {
Constructor { initValues: Uint8Array?, options: SharedDataSetOptions? ->
return@Constructor SharedDataSet(initValues, options)
}
Function("add") { sharedObject: SharedDataSet, y: Float ->
appContext.mainQueue.launch {
sharedObject.addData(y)
}
}
}
```
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartView.kt`
```kotlin
class LinearChartView(
context: Context,
appContext: AppContext
) : ExpoView(context, appContext), SharedDataSet.Listener {
// ...
private var currentDataSet: SharedDataSet? = null
fun setSharedDataSet(dataset: SharedDataSet) {
currentDataSet?.removeListener(this)
dataset.addListener(this)
currentDataSet = dataset
}
override fun onNewData(newDataSet: LineDataSet) {
chartView.applyNewData(newDataSet)
}
}
```
:::
:::spoiler :apple: iOS
:open_file_folder: File `ios/LinearChartModule.swift`
```swift
protocol Observer: AnyObject {
func dataWasUpdated(newDataSet : LineChartDataSet)
}
struct SharedDataSetOptions : Record {
@Field
var mode: DataMode = DataMode.LINEAR
@Field
var lineWidth = 5.0
}
class SharedDataSet : SharedObject {
private var listeners: [Observer] = []
private var dataSet: LineChartDataSet
init(_ initValues: Uint8Array?, _ options: SharedDataSetOptions?) {
dataSet = LineChartDataSet()
if let initValues = initValues {
for i in 0..<initValues.length {
dataSet.append(
ChartDataEntry(x: Double(i+1), y: Double(initValues[i]))
)
}
}
dataSet.applyDefaultSettings()
if let mode = options?.mode.toLineDataSetMode() {
dataSet.mode = mode
}
if let lineWidth = options?.lineWidth {
dataSet.lineWidth = lineWidth
}
super.init()
}
func addListener(newDataListener: Observer) {
listeners.append(newDataListener)
if (dataSet.count != 0) {
newDataListener.dataWasUpdated(newDataSet: dataSet)
}
}
func removeListener(listener: Observer?) {
if let listener = listener {
listeners.removeAll(where: { $0 === listener })
}
}
func addData(value: Double) {
dataSet.append(
ChartDataEntry(x: Double(dataSet.count + 1), y: value)
)
listeners.forEach { $0.dataWasUpdated(newDataSet: dataSet) }
}
}
// ...
AsyncFunction("setDataSet") { (view: LinearChartView, sharedDataSet: SharedDataSet) in
view.setDataSet(dataSet: sharedDataSet)
}
// ...
Class(SharedDataSet.self) {
Constructor { (initValues: Uint8Array?, options: SharedDataSetOptions?) in
return SharedDataSet(initValues, options)
}
Function("add") { (sharedObject: SharedDataSet, newY: Double) in
DispatchQueue.main.async {
sharedObject.addData(value: newY)
}
}
}
```
:open_file_folder: File `ios/LinearChartView.swift`
```swift
class LinearChartView: ExpoView, ChartViewDelegate, Observer {
var currentDataSet: SharedDataSet? = nil
// ...
func setDataSet(dataSet: SharedDataSet) {
currentDataSet?.removeListener(listener: self)
dataSet.addListener(newDataListener: self)
currentDataSet = dataSet
}
func dataWasUpdated(newDataSet: LineChartDataSet) {
chartView.applyNewData(dataSet: newDataSet)
}
}
```
:::
<br />
📝 Full changelog: [open GitHub Commit](https://github.com/software-mansion-labs/appjs-2023-workshop-expo-modules/commit/86170599d9b8c141c8bc7f133600aa43c3c48724)
---