# 📊 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) ---