# Run with tooling from https://github.com/flutter/codelabs/tree/main/tooling/codelab_rebuild
name: Animations rebuild script
steps:
  - name: Remove runners
    rmdirs: 
      - android
      - ios
  - name: Flutter recreate
    flutter: create --platform android,ios --org dev.flutter .
  - name: Patch android/app/build.gradle
    path: android/app/build.gradle
    patch-u: |
      --- b/platform_channels/android/app/build.gradle
      +++ a/platform_channels/android/app/build.gradle
      @@ -64,4 +64,6 @@ flutter {
           source '../..'
       }
       
      -dependencies {}
      +dependencies {
      +    implementation 'com.google.code.gson:gson:2.8.6'
      +}
  - name: Mkdir ios/Runner/Assets.xcassets/eat_new_orleans.imageset
    mkdir: ios/Runner/Assets.xcassets/eat_new_orleans.imageset
  - name: Add ios/Runner/Assets.xcassets/eat_new_orleans.imageset/Contents.json
    path: ios/Runner/Assets.xcassets/eat_new_orleans.imageset/Contents.json
    replace-contents: |
      {
        "images" : [
          {
            "filename" : "eat_new_orleans.jpg",
            "idiom" : "universal",
            "scale" : "1x"
          },
          {
            "idiom" : "universal",
            "scale" : "2x"
          },
          {
            "idiom" : "universal",
            "scale" : "3x"
          }
        ],
        "info" : {
          "author" : "xcode",
          "version" : 1
        }
      }
  - name: Add ios/Runner/Assets.xcassets/eat_new_orleans.imageset/eat_new_orleans.jpg
    path: ios/Runner/Assets.xcassets/eat_new_orleans.imageset/eat_new_orleans.jpg
    base64-contents: |
[encoded data, 103696 characters]
  - name: Mkdir android/app/src/main/assets
    mkdir: android/app/src/main/assets
  - name: Add android/app/src/main/assets/eat_new_orleans.jpg
    path: android/app/src/main/assets/eat_new_orleans.jpg
    base64-contents: |
[encoded data, 103696 characters]
  - name: Remove widget_test.dart
    rm: test/widget_test.dart
  - name: Add android/app/src/main/kotlin/dev/flutter/platform_channels/AccelerometerStreamHandler.kt
    path: android/app/src/main/kotlin/dev/flutter/platform_channels/AccelerometerStreamHandler.kt
    replace-contents: |
      // Copyright 2020 The Flutter team. All rights reserved.
      // Use of this source code is governed by a BSD-style license that can be
      // found in the LICENSE file.
      
      package dev.flutter.platform_channels
      
      import android.hardware.Sensor
      import android.hardware.SensorEvent
      import android.hardware.SensorEventListener
      import android.hardware.SensorManager
      import io.flutter.plugin.common.EventChannel
      
      class AccelerometerStreamHandler(sManager: SensorManager, s: Sensor) : EventChannel.StreamHandler, SensorEventListener {
          private val sensorManager: SensorManager = sManager
          private val accelerometerSensor: Sensor = s
          private lateinit var eventSink: EventChannel.EventSink
      
          override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
              if (events != null) {
                  eventSink = events
                  sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_UI)
              }
          }
      
          override fun onCancel(arguments: Any?) {
              sensorManager.unregisterListener(this)
          }
      
          override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
      
          override fun onSensorChanged(sensorEvent: SensorEvent?) {
              if (sensorEvent != null) {
                  val axisValues = listOf(sensorEvent.values[0], sensorEvent.values[1], sensorEvent.values[2])
                  eventSink.success(axisValues)
              } else {
                  eventSink.error("DATA_UNAVAILABLE", "Cannot get accelerometer data", null)
              }
          }
      }
  - name: Replace android/app/src/main/kotlin/dev/flutter/platform_channels/MainActivity.kt
    path: android/app/src/main/kotlin/dev/flutter/platform_channels/MainActivity.kt
    replace-contents: |
      // Copyright 2020 The Flutter team. All rights reserved.
      // Use of this source code is governed by a BSD-style license that can be
      // found in the LICENSE file.
      
      package dev.flutter.platform_channels
      
      import android.content.Context
      import android.hardware.Sensor
      import android.hardware.SensorManager
      import com.google.gson.Gson
      import com.google.gson.reflect.TypeToken
      import io.flutter.embedding.android.FlutterActivity
      import io.flutter.embedding.engine.FlutterEngine
      import io.flutter.plugin.common.*
      import java.io.InputStream
      import java.nio.ByteBuffer
      
      class MainActivity : FlutterActivity() {
          override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
              // Creates a MethodChannel as soon as the FlutterEngine is attached to
              // the Activity, and registers a MethodCallHandler. The Method.setMethodCallHandler
              // is responsible to register a MethodCallHandler to handle the incoming calls.
      
              // The call parameter of MethodCallHandler has information about the incoming call,
              // like method name, and arguments. The result parameter of MethodCallHandler is
              // responsible to send the results of the call.
              MethodChannel(flutterEngine.dartExecutor, "methodChannelDemo")
                      .setMethodCallHandler { call, result ->
                          val count: Int? = call.argument<Int>("count")
      
                          if (count == null) {
                              result.error("INVALID ARGUMENT", "Value of count cannot be null", null)
                          } else {
                              when (call.method) {
                                  "increment" -> result.success(count + 1)
                                  "decrement" -> result.success(count - 1)
                                  else -> result.notImplemented()
                              }
                          }
                      }
      
              val sensorManger: SensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
              val accelerometerSensor: Sensor = sensorManger.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
              EventChannel(flutterEngine.dartExecutor, "eventChannelDemo")
                      .setStreamHandler(AccelerometerStreamHandler(sensorManger, accelerometerSensor))
      
              // Registers a MessageHandler for BasicMessageChannel to receive a message from Dart and send
              // image data in reply.
              BasicMessageChannel(flutterEngine.dartExecutor, "platformImageDemo", StandardMessageCodec())
                      .setMessageHandler { message, reply ->
                          if (message == "getImage") {
                              val inputStream: InputStream = assets.open("eat_new_orleans.jpg")
                              reply.reply(inputStream.readBytes())
                          }
                      }
      
              val petList = mutableListOf<Map<String, String>>()
              val gson = Gson()
      
              // A BasicMessageChannel for sending petList to Dart.
              val stringCodecChannel = BasicMessageChannel(flutterEngine.dartExecutor, "stringCodecDemo", StringCodec.INSTANCE)
      
              // Registers a MessageHandler for BasicMessageChannel to receive pet details to be
              // added in petList and send the it back to Dart using stringCodecChannel.
              BasicMessageChannel(flutterEngine.dartExecutor, "jsonMessageCodecDemo", JSONMessageCodec.INSTANCE)
                      .setMessageHandler { message, reply ->
                          petList.add(0, gson.fromJson(message.toString(), object : TypeToken<Map<String, String>>() {}.type))
                          stringCodecChannel.send(gson.toJson(mapOf("petList" to petList)))
                      }
      
              // Registers a MessageHandler for BasicMessageChannel to receive the index of pet
              // details to be removed from the petList and send the petList back to Dart using
              // stringCodecChannel. If the index is not in the range of petList, we send null
              // back to Dart.
              BasicMessageChannel(flutterEngine.dartExecutor, "binaryCodecDemo", BinaryCodec.INSTANCE)
                      .setMessageHandler { message, reply ->
                          val index = String(message!!.array()).toInt()
                          if (index >= 0 && index < petList.size) {
                              petList.removeAt(index)
                              val replyMessage = "Removed Successfully"
                              reply.reply(ByteBuffer.allocateDirect(replyMessage.toByteArray().size).put(replyMessage.toByteArray()))
                              stringCodecChannel.send(gson.toJson(mapOf("petList" to petList)))
                          } else {
                              reply.reply(null)
                          }
                      }
          }
      }
  - name: Add ios/Runner/AccelerometerStreamHandler.swift
    path: ios/Runner/AccelerometerStreamHandler.swift
    replace-contents: |
      // Copyright 2020 The Flutter team. All rights reserved.
      // Use of this source code is governed by a BSD-style license that can be
      // found in the LICENSE file.
      
      import CoreMotion
      
      class AccelerometerStreamHandler: NSObject, FlutterStreamHandler {
          
          var motionManager: CMMotionManager;
          
          override init() {
              motionManager = CMMotionManager()
          }
          
          func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
              
              if !motionManager.isAccelerometerAvailable {
                  events(FlutterError(code: "SENSOR_UNAVAILABLE", message: "Accelerometer is not available", details: nil))
              }
              
              motionManager.accelerometerUpdateInterval = 0.1
              
              motionManager.startAccelerometerUpdates(to: OperationQueue.main) {(data, error) in
                  guard let accelerationData = data?.acceleration else {
                      events(FlutterError(code: "DATA_UNAVAILABLE", message: "Cannot get accelerometer data", details: nil ))
                      return
                  }
                  
                  events([accelerationData.x, accelerationData.y, accelerationData.z])
              }
              
              return nil
          }
          
          func onCancel(withArguments arguments: Any?) -> FlutterError? {
              return nil
          }
      }
  - name: Add AccelerometerStreamHandler.swift to Xcode project
    xcode-project-path: ios/Runner.xcodeproj
    xcode-add-file: AccelerometerStreamHandler.swift
  - name: Replace ios/Runner/AppDelegate.swift
    path: ios/Runner/AppDelegate.swift
    replace-contents: |
      // Copyright 2020 The Flutter team. All rights reserved.
      // Use of this source code is governed by a BSD-style license that can be
      // found in the LICENSE file.
      
      import UIKit
      import Flutter
      
      @UIApplicationMain
      @objc class AppDelegate: FlutterAppDelegate {
          override func application(
              _ application: UIApplication,
              didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
          ) -> Bool {
              let flutterViewController = window.rootViewController as! FlutterViewController
              FlutterMethodChannel(name: "methodChannelDemo", binaryMessenger: flutterViewController.binaryMessenger).setMethodCallHandler({
                  (call: FlutterMethodCall, result: FlutterResult) -> Void in
                  
                  guard let count = (call.arguments as? NSDictionary)?["count"] as? Int else {
                      result(FlutterError(code: "INVALID_ARGUMENT", message: "Value of count cannot be null", details: nil))
                      return
                  }
                  
                  switch call.method {
                  case "increment":
                      result(count + 1)
                  case "decrement":
                      result(count - 1)
                  default:
                      result(FlutterMethodNotImplemented)
                  }
              })
              
              FlutterBasicMessageChannel(name: "platformImageDemo", binaryMessenger: flutterViewController.binaryMessenger, codec: FlutterStandardMessageCodec.sharedInstance()).setMessageHandler{
                  (message: Any?, reply: FlutterReply) -> Void in
                  
                  if(message as! String == "getImage") {
                      guard let image = UIImage(named: "eat_new_orleans.jpg") else {
                          reply(nil)
                          return
                      }
                      
                      reply(FlutterStandardTypedData(bytes: image.jpegData(compressionQuality: 1)!))
                  }
              }
              
              FlutterEventChannel(name: "eventChannelDemo", binaryMessenger: flutterViewController.binaryMessenger).setStreamHandler(AccelerometerStreamHandler())
              
              var petList : [[String:String]] = []
              
              // A FlutterBasicMessageChannel for sending petList to Dart.
              let stringCodecChannel = FlutterBasicMessageChannel(name: "stringCodecDemo", binaryMessenger: flutterViewController.binaryMessenger, codec: FlutterStringCodec.sharedInstance())
              
              // Registers a MessageHandler for FlutterBasicMessageChannel to receive pet details.
              FlutterBasicMessageChannel(name: "jsonMessageCodecDemo", binaryMessenger: flutterViewController.binaryMessenger, codec: FlutterJSONMessageCodec.sharedInstance())
                  .setMessageHandler{(message: Any?, reply: FlutterReply) -> Void in
                      petList.insert(message! as! [String: String], at: 0)
                      stringCodecChannel.sendMessage(self.convertPetListToJson(petList: petList))
                  }
              
              // Registers a MessageHandler for FlutterBasicMessageHandler to receive indices of detail records to remove from the petList.
              FlutterBasicMessageChannel(name: "binaryCodecDemo", binaryMessenger: flutterViewController.binaryMessenger, codec: FlutterBinaryCodec.sharedInstance()).setMessageHandler{
                  (message: Any?, reply: FlutterReply) -> Void in
                  
                  guard let index = Int.init(String.init(data: message! as! Data, encoding: String.Encoding.utf8)!) else {
                      reply(nil)
                      return
                  }
                  
                  if (index >= 0 && index < petList.count) {
                      petList.remove(at: index)
                      reply("Removed Successfully".data(using: .utf8)!)
                      stringCodecChannel.sendMessage(self.convertPetListToJson(petList: petList))
                  } else {
                      reply(nil)
                  }
              }
              
              GeneratedPluginRegistrant.register(with: self)
              return super.application(application, didFinishLaunchingWithOptions: launchOptions)
          }
          
          // Function to convert petList to json string.
          func convertPetListToJson(petList: [[String: String]]) -> String? {
              guard let data = try? JSONSerialization.data(withJSONObject: ["petList": petList], options: .prettyPrinted) else {
                  return nil
              }
              return String(data: data, encoding: String.Encoding.utf8)
          }
      }
  - name: Add ios/Runner/Assets.xcassets/Contents.json
    path: ios/Runner/Assets.xcassets/Contents.json
    replace-contents: |
      {
        "info" : {
          "author" : "xcode",
          "version" : 1
        }
      }
