# 🏞️ View Functions
### 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 1
Export a `moveToStart` view function that scrolls the chart view to the fist data point.
:::spoiler :robot_face: Android
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartModule.kt`
```kotlin
AsyncFunction("moveToStart") { view: LinearChartView ->
view.moveToStart()
}
```
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartView.kt`
```kotlin
fun moveToStart() {
val dataSet = chartView.data ?: return
chartView.moveTo(dataSet.xMin - 1f)
}
```
:::
:::spoiler :apple: iOS
:open_file_folder: File `ios/LinearChartModule.swift`
```swift
AsyncFunction("moveToStart") { (view: LinearChartView) in
view.moveToStart()
}
```
:open_file_folder: File `ios/LinearChartView.swift`
```swift
func moveToStart() {
if let dataSet = chartView.data {
chartView.moveViewToX(dataSet.xMin - 1)
}
}
```
:::
<br />
📝 Full changelog: [open GitHub Commit](https://github.com/software-mansion-labs/appjs-2023-workshop-expo-modules/commit/be4f5f66832269a66c9a5d79790028d43f40d579)
---
### Task 2
Similar to the previous example, export two additional functions that can scroll the view to the last data point (`moveToEnd`) or to a provided point (`moveToPoint`).
:::spoiler :robot_face: Android
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartModule.kt`
```kotlin
AsyncFunction("moveToEnd") { view: LinearChartView ->
view.moveToEnd()
}
AsyncFunction("moveToPoint") { view: LinearChartView, x: Float, y: Float ->
view.moveToPoint(x, y)
}
```
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartView.kt`
```kotlin
fun moveToEnd() {
val dataSet = chartView.data ?: return
chartView.moveTo(dataSet.xMax + 1f)
}
fun moveToPoint(x: Float, y: Float) {
chartView.moveTo(x, y)
}
```
:::
:::spoiler :apple: iOS
:open_file_folder: File `ios/LinearChartModule.swift`
```swift
AsyncFunction("moveToEnd") { (view: LinearChartView) in
view.moveToEnd()
}
AsyncFunction("moveToPoint") { (view: LinearChartView, x: Double, y: Double) in
view.moveToPoint(x, y)
}
```
:open_file_folder: File `ios/LinearChartView.swift`
```swift
func moveToEnd() {
if let dataSet = chartView.data {
chartView.moveViewToX(dataSet.xMax - 1)
}
}
func moveToPoint(_ x: Double, _ y: Double) {
chartView.moveViewTo(xValue: x, yValue: y, axis: .left)
}
```
:::
<br />
📝 Full changelog: [open GitHub Commit](https://github.com/software-mansion-labs/appjs-2023-workshop-expo-modules/commit/d5d09847ef49780236d53975dd0b5459ada0b9eb)
---
### Task 3
Export the `saveToGallery` view function which can save the visible portion of the view as an image into the camera roll.
:::spoiler :robot_face: Android
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartModule.kt`
```kotlin
class UserRejectedPermissionsException : CodedException(
message = "User rejected permissions"
)
private var wasScopedInitialized = false
internal val moduleScope by lazy {
wasScopedInitialized = true
CoroutineScope(
Dispatchers.IO +
SupervisorJob() +
CoroutineName("LinearChartModuleScope")
)
}
// ...
override fun definition() = ModuleDefinition {
OnDestroy {
if (wasScopedInitialized) {
moduleScope.cancel(ContextDestroyedException())
}
}
// ...
AsyncFunction("saveToGallery") { view: LinearChartView, promise: Promise ->
val permissionManager = appContext.permissions
?: throw Exceptions.MissingPermissions()
permissionManager.askForPermissions({ result ->
if (result[Manifest.permission.WRITE_EXTERNAL_STORAGE]?.status != PermissionsStatus.GRANTED) {
promise.reject(UserRejectedPermissionsException())
return@askForPermissions
}
view.saveToGallery(promise)
}, Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}
```
:open_file_folder: File `android/src/main/java/expo/modules/workshopscharts/LinearChartView.kt`
```kotlin
fun saveToGallery(promise: Promise) {
appContext
.registry
.getModule<LinearChartModule>()
?.moduleScope
?.launch {
val bitmap = chartView.chartBitmap
Utils.saveImage(bitmap, context, "MyApp")
promise.resolve(null)
}
}
```
:::
:::spoiler :apple: iOS
:open_file_folder: File `ios/LinearChartModule.swift`
```swift
AsyncFunction("saveToGallery") { (view: LinearChartView, promise: Promise) in
view.saveToGallery(promise)
}
```
:open_file_folder: File `ios/LinearChartView.swift`
```swift
class ImageSaver: NSObject {
private let promise: Promise
init(promise: Promise) {
self.promise = promise
}
func writeToPhotoAlbum(image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveCompleted), nil)
}
@objc func saveCompleted(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
promise.resolve(error == nil)
}
}
// ...
func saveToGallery(_ promise: Promise) {
if let imageData = chartView.getChartImage(transparent: true) {
ImageSaver(promise: promise).writeToPhotoAlbum(image: imageData)
return
}
promise.resolve(false)
}
```
:::
<br />
📝 Full changelog: [open GitHub Commit](https://github.com/software-mansion-labs/appjs-2023-workshop-expo-modules/commit/e76d324d18f1b8b758b3ff1d33ce2e8f366c73a8)
---
### [👷♂️ Classes and Shared Objects](/__42gVw8RqiIgfSbVseIvw)