@rentlydev/rently-tuya 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +281 -0
  3. package/android/build.gradle +182 -0
  4. package/android/gradle.properties +7 -0
  5. package/android/libs/airbrake-android-1.4.0.jar +0 -0
  6. package/android/src/main/AndroidManifest.xml +1 -0
  7. package/android/src/main/AndroidManifestNew.xml +25 -0
  8. package/android/src/main/java/com/rentlytuya/RentlyTuyaModule.kt +503 -0
  9. package/android/src/main/java/com/rentlytuya/RentlyTuyaPackage.kt +18 -0
  10. package/android/src/main/java/com/rentlytuya/TuyaActivity.kt +45 -0
  11. package/android/src/main/java/com/rentlytuya/alerts/FormatSDCardAlert.kt +83 -0
  12. package/android/src/main/java/com/rentlytuya/alerts/PermissionAlert.kt +91 -0
  13. package/android/src/main/java/com/rentlytuya/alerts/RemoveDoorbellAlert.kt +83 -0
  14. package/android/src/main/java/com/rentlytuya/alerts/RemoveDoorbellFailureAlert.kt +71 -0
  15. package/android/src/main/java/com/rentlytuya/alerts/ResetWifiAlert.kt +83 -0
  16. package/android/src/main/java/com/rentlytuya/alerts/SuccessAlert.kt +74 -0
  17. package/android/src/main/java/com/rentlytuya/components/Alert.kt +47 -0
  18. package/android/src/main/java/com/rentlytuya/components/AnchorButton.kt +125 -0
  19. package/android/src/main/java/com/rentlytuya/components/Button.kt +147 -0
  20. package/android/src/main/java/com/rentlytuya/components/CustomDatePicker.kt +275 -0
  21. package/android/src/main/java/com/rentlytuya/components/Divider.kt +53 -0
  22. package/android/src/main/java/com/rentlytuya/components/EncryptedImageView.kt +59 -0
  23. package/android/src/main/java/com/rentlytuya/components/Label.kt +155 -0
  24. package/android/src/main/java/com/rentlytuya/components/LoadingIndicator.kt +75 -0
  25. package/android/src/main/java/com/rentlytuya/components/Slider.kt +66 -0
  26. package/android/src/main/java/com/rentlytuya/components/Switch.kt +51 -0
  27. package/android/src/main/java/com/rentlytuya/components/VideoView.kt +45 -0
  28. package/android/src/main/java/com/rentlytuya/dashboard/AdvancedSettings.kt +259 -0
  29. package/android/src/main/java/com/rentlytuya/dashboard/Dashboard.kt +551 -0
  30. package/android/src/main/java/com/rentlytuya/dashboard/DoorbellSettings.kt +874 -0
  31. package/android/src/main/java/com/rentlytuya/dashboard/Messages.kt +463 -0
  32. package/android/src/main/java/com/rentlytuya/dashboard/NavController.kt +358 -0
  33. package/android/src/main/java/com/rentlytuya/dashboard/OfflineScreen.kt +160 -0
  34. package/android/src/main/java/com/rentlytuya/dashboard/Playback.kt +685 -0
  35. package/android/src/main/java/com/rentlytuya/tuya/Messages.kt +234 -0
  36. package/android/src/main/java/com/rentlytuya/tuya/Playback.kt +385 -0
  37. package/android/src/main/java/com/rentlytuya/tuya/ScreenCapture.kt +244 -0
  38. package/android/src/main/java/com/rentlytuya/tuya/Settings.kt +809 -0
  39. package/android/src/main/java/com/rentlytuya/tuya/Tuya.kt +497 -0
  40. package/android/src/main/java/com/rentlytuya/ui/theme/LocalColor.kt +80 -0
  41. package/android/src/main/java/com/rentlytuya/ui/theme/LocalFont.kt +35 -0
  42. package/android/src/main/java/com/rentlytuya/ui/theme/Theme.kt +34 -0
  43. package/android/src/main/java/com/rentlytuya/ui/theme/Type.kt +34 -0
  44. package/android/src/main/java/com/rentlytuya/util/Airbrake.kt +40 -0
  45. package/android/src/main/java/com/rentlytuya/util/DpConstants.kt +53 -0
  46. package/android/src/main/java/com/rentlytuya/util/FrescoManager.kt +86 -0
  47. package/android/src/main/java/com/rentlytuya/util/HeapAnalytics.kt +16 -0
  48. package/android/src/main/java/com/rentlytuya/util/KeylessModule.kt +81 -0
  49. package/android/src/main/java/com/rentlytuya/util/PermissionHandler.kt +75 -0
  50. package/android/src/main/java/com/rentlytuya/util/ReactParamsCheck.kt +152 -0
  51. package/android/src/main/java/com/rentlytuya/util/Util.kt +128 -0
  52. package/android/src/main/res/drawable/ic_close.xml +12 -0
  53. package/android/src/main/res/drawable/ic_launcher_background.xml +170 -0
  54. package/android/src/main/res/drawable/ic_launcher_foreground.xml +30 -0
  55. package/android/src/main/res/drawable/img_place_holder.png +0 -0
  56. package/android/src/main/res/drawable-hdpi/ic_action_arrow_backward.png +0 -0
  57. package/android/src/main/res/drawable-hdpi/ic_arrow_backward_white.png +0 -0
  58. package/android/src/main/res/drawable-hdpi/ic_arrow_blue_right.png +0 -0
  59. package/android/src/main/res/drawable-hdpi/ic_calendar.png +0 -0
  60. package/android/src/main/res/drawable-hdpi/ic_camera.png +0 -0
  61. package/android/src/main/res/drawable-hdpi/ic_message.png +0 -0
  62. package/android/src/main/res/drawable-hdpi/ic_pause.png +0 -0
  63. package/android/src/main/res/drawable-hdpi/ic_play.png +0 -0
  64. package/android/src/main/res/drawable-hdpi/ic_play_back.png +0 -0
  65. package/android/src/main/res/drawable-hdpi/ic_record.png +0 -0
  66. package/android/src/main/res/drawable-hdpi/ic_retry.png +0 -0
  67. package/android/src/main/res/drawable-hdpi/ic_setting.png +0 -0
  68. package/android/src/main/res/drawable-hdpi/ic_sound_off.png +0 -0
  69. package/android/src/main/res/drawable-hdpi/ic_sound_on.png +0 -0
  70. package/android/src/main/res/drawable-mdpi/ic_action_arrow_backward.png +0 -0
  71. package/android/src/main/res/drawable-mdpi/ic_arrow_backward_white.png +0 -0
  72. package/android/src/main/res/drawable-mdpi/ic_arrow_blue_right.png +0 -0
  73. package/android/src/main/res/drawable-mdpi/ic_battery_average.png +0 -0
  74. package/android/src/main/res/drawable-mdpi/ic_battery_charging.png +0 -0
  75. package/android/src/main/res/drawable-mdpi/ic_battery_full.png +0 -0
  76. package/android/src/main/res/drawable-mdpi/ic_battery_good.png +0 -0
  77. package/android/src/main/res/drawable-mdpi/ic_battery_low.png +0 -0
  78. package/android/src/main/res/drawable-mdpi/ic_calendar.png +0 -0
  79. package/android/src/main/res/drawable-mdpi/ic_camera.png +0 -0
  80. package/android/src/main/res/drawable-mdpi/ic_message.png +0 -0
  81. package/android/src/main/res/drawable-mdpi/ic_pause.png +0 -0
  82. package/android/src/main/res/drawable-mdpi/ic_play.png +0 -0
  83. package/android/src/main/res/drawable-mdpi/ic_play_back.png +0 -0
  84. package/android/src/main/res/drawable-mdpi/ic_record.png +0 -0
  85. package/android/src/main/res/drawable-mdpi/ic_retry.png +0 -0
  86. package/android/src/main/res/drawable-mdpi/ic_setting.png +0 -0
  87. package/android/src/main/res/drawable-mdpi/ic_sound_off.png +0 -0
  88. package/android/src/main/res/drawable-mdpi/ic_sound_on.png +0 -0
  89. package/android/src/main/res/drawable-xhdpi/ic_action_arrow_backward.png +0 -0
  90. package/android/src/main/res/drawable-xhdpi/ic_arrow_backward_white.png +0 -0
  91. package/android/src/main/res/drawable-xhdpi/ic_arrow_blue_right.png +0 -0
  92. package/android/src/main/res/drawable-xhdpi/ic_battery_average.png +0 -0
  93. package/android/src/main/res/drawable-xhdpi/ic_battery_charging.png +0 -0
  94. package/android/src/main/res/drawable-xhdpi/ic_battery_full.png +0 -0
  95. package/android/src/main/res/drawable-xhdpi/ic_battery_good.png +0 -0
  96. package/android/src/main/res/drawable-xhdpi/ic_battery_low.png +0 -0
  97. package/android/src/main/res/drawable-xhdpi/ic_calendar.png +0 -0
  98. package/android/src/main/res/drawable-xhdpi/ic_camera.png +0 -0
  99. package/android/src/main/res/drawable-xhdpi/ic_message.png +0 -0
  100. package/android/src/main/res/drawable-xhdpi/ic_pause.png +0 -0
  101. package/android/src/main/res/drawable-xhdpi/ic_play.png +0 -0
  102. package/android/src/main/res/drawable-xhdpi/ic_play_back.png +0 -0
  103. package/android/src/main/res/drawable-xhdpi/ic_record.png +0 -0
  104. package/android/src/main/res/drawable-xhdpi/ic_retry.png +0 -0
  105. package/android/src/main/res/drawable-xhdpi/ic_setting.png +0 -0
  106. package/android/src/main/res/drawable-xhdpi/ic_sound_off.png +0 -0
  107. package/android/src/main/res/drawable-xhdpi/ic_sound_on.png +0 -0
  108. package/android/src/main/res/drawable-xxhdpi/ic_action_arrow_backward.png +0 -0
  109. package/android/src/main/res/drawable-xxhdpi/ic_arrow_backward_white.png +0 -0
  110. package/android/src/main/res/drawable-xxhdpi/ic_arrow_blue_right.png +0 -0
  111. package/android/src/main/res/drawable-xxhdpi/ic_battery_average.png +0 -0
  112. package/android/src/main/res/drawable-xxhdpi/ic_battery_charging.png +0 -0
  113. package/android/src/main/res/drawable-xxhdpi/ic_battery_full.png +0 -0
  114. package/android/src/main/res/drawable-xxhdpi/ic_battery_good.png +0 -0
  115. package/android/src/main/res/drawable-xxhdpi/ic_battery_low.png +0 -0
  116. package/android/src/main/res/drawable-xxhdpi/ic_calendar.png +0 -0
  117. package/android/src/main/res/drawable-xxhdpi/ic_camera.png +0 -0
  118. package/android/src/main/res/drawable-xxhdpi/ic_message.png +0 -0
  119. package/android/src/main/res/drawable-xxhdpi/ic_pause.png +0 -0
  120. package/android/src/main/res/drawable-xxhdpi/ic_play.png +0 -0
  121. package/android/src/main/res/drawable-xxhdpi/ic_play_back.png +0 -0
  122. package/android/src/main/res/drawable-xxhdpi/ic_record.png +0 -0
  123. package/android/src/main/res/drawable-xxhdpi/ic_retry.png +0 -0
  124. package/android/src/main/res/drawable-xxhdpi/ic_setting.png +0 -0
  125. package/android/src/main/res/drawable-xxhdpi/ic_sound_off.png +0 -0
  126. package/android/src/main/res/drawable-xxhdpi/ic_sound_on.png +0 -0
  127. package/android/src/main/res/drawable-xxxhdpi/ic_action_arrow_backward.png +0 -0
  128. package/android/src/main/res/drawable-xxxhdpi/ic_arrow_backward_white.png +0 -0
  129. package/android/src/main/res/drawable-xxxhdpi/ic_arrow_blue_right.png +0 -0
  130. package/android/src/main/res/drawable-xxxhdpi/ic_calendar.png +0 -0
  131. package/android/src/main/res/drawable-xxxhdpi/ic_camera.png +0 -0
  132. package/android/src/main/res/drawable-xxxhdpi/ic_message.png +0 -0
  133. package/android/src/main/res/drawable-xxxhdpi/ic_pause.png +0 -0
  134. package/android/src/main/res/drawable-xxxhdpi/ic_play.png +0 -0
  135. package/android/src/main/res/drawable-xxxhdpi/ic_play_back.png +0 -0
  136. package/android/src/main/res/drawable-xxxhdpi/ic_record.png +0 -0
  137. package/android/src/main/res/drawable-xxxhdpi/ic_retry.png +0 -0
  138. package/android/src/main/res/drawable-xxxhdpi/ic_setting.png +0 -0
  139. package/android/src/main/res/drawable-xxxhdpi/ic_sound_off.png +0 -0
  140. package/android/src/main/res/drawable-xxxhdpi/ic_sound_on.png +0 -0
  141. package/android/src/main/res/font/quicksand_bold.ttf +0 -0
  142. package/android/src/main/res/font/quicksand_light.ttf +0 -0
  143. package/android/src/main/res/font/quicksand_medium.ttf +0 -0
  144. package/android/src/main/res/font/quicksand_regular.ttf +0 -0
  145. package/android/src/main/res/font/quicksand_semi_bold.ttf +0 -0
  146. package/android/src/main/res/values/strings.xml +121 -0
  147. package/android/thingMapping.gradle +200 -0
  148. package/android/thingMapping.json +2014 -0
  149. package/ios/components/Alert.swift +54 -0
  150. package/ios/components/AnchorButton.swift +100 -0
  151. package/ios/components/Button.swift +118 -0
  152. package/ios/components/CustomDatePicker.swift +275 -0
  153. package/ios/components/Divider.swift +28 -0
  154. package/ios/components/Image.swift +72 -0
  155. package/ios/components/Label.swift +105 -0
  156. package/ios/components/Switch.swift +61 -0
  157. package/ios/dashboard/AdvanceSettings.swift +127 -0
  158. package/ios/dashboard/Dashboard.swift +354 -0
  159. package/ios/dashboard/Messages.swift +361 -0
  160. package/ios/dashboard/NavigationController.swift +173 -0
  161. package/ios/dashboard/OfflineScreen.swift +109 -0
  162. package/ios/dashboard/Playback.swift +543 -0
  163. package/ios/dashboard/PreviewManager.swift +117 -0
  164. package/ios/dashboard/Settings.swift +672 -0
  165. package/ios/icons/Charging.png +0 -0
  166. package/ios/icons/Charging@2x.png +0 -0
  167. package/ios/icons/Charging@3x.png +0 -0
  168. package/ios/icons/back_arraow.png +0 -0
  169. package/ios/icons/back_arraow@2x.png +0 -0
  170. package/ios/icons/back_arraow@3x.png +0 -0
  171. package/ios/icons/battery_average.png +0 -0
  172. package/ios/icons/battery_average@2x.png +0 -0
  173. package/ios/icons/battery_average@3x.png +0 -0
  174. package/ios/icons/battery_full.png +0 -0
  175. package/ios/icons/battery_full@2x.png +0 -0
  176. package/ios/icons/battery_full@3x.png +0 -0
  177. package/ios/icons/battery_good.png +0 -0
  178. package/ios/icons/battery_good@2x.png +0 -0
  179. package/ios/icons/battery_good@3x.png +0 -0
  180. package/ios/icons/battery_low.png +0 -0
  181. package/ios/icons/battery_low@2x.png +0 -0
  182. package/ios/icons/battery_low@3x.png +0 -0
  183. package/ios/icons/calendar.png +0 -0
  184. package/ios/icons/calendar@2x.png +0 -0
  185. package/ios/icons/calendar@3x.png +0 -0
  186. package/ios/icons/cloud.png +0 -0
  187. package/ios/icons/cloud@2x.png +0 -0
  188. package/ios/icons/cloud@3x.png +0 -0
  189. package/ios/icons/down_update.png +0 -0
  190. package/ios/icons/down_update@2x.png +0 -0
  191. package/ios/icons/down_update@3x.png +0 -0
  192. package/ios/icons/exit_fullscreen.png +0 -0
  193. package/ios/icons/exit_fullscreen@2x.png +0 -0
  194. package/ios/icons/exit_fullscreen@3x.png +0 -0
  195. package/ios/icons/expand.png +0 -0
  196. package/ios/icons/fullscreen.png +0 -0
  197. package/ios/icons/fullscreen@2x.png +0 -0
  198. package/ios/icons/fullscreen@3x.png +0 -0
  199. package/ios/icons/image_placeholder.png +0 -0
  200. package/ios/icons/information.png +0 -0
  201. package/ios/icons/information@2x.png +0 -0
  202. package/ios/icons/information@3x.png +0 -0
  203. package/ios/icons/keyless_Setting.png +0 -0
  204. package/ios/icons/keyless_Setting@2x.png +0 -0
  205. package/ios/icons/keyless_Setting@3x.png +0 -0
  206. package/ios/icons/keyless_back@1x.png +0 -0
  207. package/ios/icons/keyless_back@2x.png +0 -0
  208. package/ios/icons/keyless_back@3x.png +0 -0
  209. package/ios/icons/keyless_filter.png +0 -0
  210. package/ios/icons/keyless_filter@2x.png +0 -0
  211. package/ios/icons/keyless_filter@3x.png +0 -0
  212. package/ios/icons/keyless_message.png +0 -0
  213. package/ios/icons/keyless_message@2x.png +0 -0
  214. package/ios/icons/keyless_message@3x.png +0 -0
  215. package/ios/icons/keyless_pause.png +0 -0
  216. package/ios/icons/keyless_pause@2x.png +0 -0
  217. package/ios/icons/keyless_pause@3x.png +0 -0
  218. package/ios/icons/keyless_photo.png +0 -0
  219. package/ios/icons/keyless_photo@2x.png +0 -0
  220. package/ios/icons/keyless_photo@3x.png +0 -0
  221. package/ios/icons/keyless_play.png +0 -0
  222. package/ios/icons/keyless_play@2x.png +0 -0
  223. package/ios/icons/keyless_play@3x.png +0 -0
  224. package/ios/icons/keyless_play_list.png +0 -0
  225. package/ios/icons/keyless_play_list@2x.png +0 -0
  226. package/ios/icons/keyless_play_list@3x.png +0 -0
  227. package/ios/icons/keyless_play_playback.png +0 -0
  228. package/ios/icons/keyless_play_playback@2x.png +0 -0
  229. package/ios/icons/keyless_play_playback@3x.png +0 -0
  230. package/ios/icons/keyless_record.png +0 -0
  231. package/ios/icons/keyless_record@2x.png +0 -0
  232. package/ios/icons/keyless_record@3x.png +0 -0
  233. package/ios/icons/keyless_record_on.png +0 -0
  234. package/ios/icons/keyless_record_on@2x.png +0 -0
  235. package/ios/icons/keyless_record_on@3x.png +0 -0
  236. package/ios/icons/keyless_sound_off.png +0 -0
  237. package/ios/icons/keyless_sound_off@2x.png +0 -0
  238. package/ios/icons/keyless_sound_off@3x.png +0 -0
  239. package/ios/icons/keyless_sound_on.png +0 -0
  240. package/ios/icons/keyless_sound_on@2x.png +0 -0
  241. package/ios/icons/keyless_sound_on@3x.png +0 -0
  242. package/ios/icons/keyless_speak_off.png +0 -0
  243. package/ios/icons/keyless_speak_off@2x.png +0 -0
  244. package/ios/icons/keyless_speak_on.png +0 -0
  245. package/ios/icons/keyless_speak_on@2x.png +0 -0
  246. package/ios/icons/keyless_speak_on@3x.png +0 -0
  247. package/ios/icons/refresh.png +0 -0
  248. package/ios/icons/refresh@2x.png +0 -0
  249. package/ios/icons/refresh@3x.png +0 -0
  250. package/ios/icons/ty_camera_control_hd_normal@2x.png +0 -0
  251. package/ios/icons/ty_camera_control_hd_normal@3x.png +0 -0
  252. package/ios/icons/ty_camera_control_sd_normal@2x.png +0 -0
  253. package/ios/icons/ty_camera_control_sd_normal@3x.png +0 -0
  254. package/ios/icons/upgrade_success.png +0 -0
  255. package/ios/icons/upgrade_success@2x.png +0 -0
  256. package/ios/icons/upgrade_success@3x.png +0 -0
  257. package/ios/listener/KeylessListener.m +8 -0
  258. package/ios/listener/KeylessListener.swift +56 -0
  259. package/ios/listener/RentlyTuya-Bridging-Header.h +5 -0
  260. package/ios/listener/RentlyTuya.mm +56 -0
  261. package/ios/listener/RentlyTuya.swift +544 -0
  262. package/ios/theme/LocalColor.swift +33 -0
  263. package/ios/theme/LocalFont.swift +32 -0
  264. package/ios/theme/Theme.swift +71 -0
  265. package/ios/tuya/CameraManager.swift +296 -0
  266. package/ios/tuya/SettingsManager.swift +475 -0
  267. package/ios/tuya/Tuya.swift +570 -0
  268. package/ios/tuya/TuyaMessages.swift +98 -0
  269. package/ios/utils/Airbrake.swift +31 -0
  270. package/ios/utils/AppUtility.swift +76 -0
  271. package/ios/utils/HeapAnalytics.swift +8 -0
  272. package/ios/utils/OrientationManager.swift +60 -0
  273. package/ios/utils/PromiseHandler.swift +36 -0
  274. package/lib/commonjs/index.js +90 -0
  275. package/lib/commonjs/index.js.map +1 -0
  276. package/lib/commonjs/package.json +1 -0
  277. package/lib/module/index.js +83 -0
  278. package/lib/module/index.js.map +1 -0
  279. package/lib/module/package.json +1 -0
  280. package/lib/typescript/commonjs/package.json +1 -0
  281. package/lib/typescript/commonjs/src/index.d.ts +75 -0
  282. package/lib/typescript/commonjs/src/index.d.ts.map +1 -0
  283. package/lib/typescript/module/package.json +1 -0
  284. package/lib/typescript/module/src/index.d.ts +75 -0
  285. package/lib/typescript/module/src/index.d.ts.map +1 -0
  286. package/package.json +188 -0
  287. package/rently-tuya.podspec +52 -0
  288. package/src/index.tsx +158 -0
@@ -0,0 +1,234 @@
1
+ package com.rentlytuya.tuya
2
+
3
+ import android.os.Build
4
+ import android.util.Log
5
+ import androidx.annotation.RequiresApi
6
+ import androidx.compose.runtime.MutableLongState
7
+ import androidx.compose.runtime.MutableState
8
+ import com.rentlytuya.tuya.Tuya.TAG
9
+ import com.rentlytuya.util.Airbrake
10
+ import com.rentlytuya.util.DateUtil
11
+ import com.rentlytuya.util.DateUtil.isNotNull
12
+ import com.rentlytuya.util.DateUtil.isNull
13
+ import com.thingclips.smart.android.camera.sdk.ThingIPCSdk
14
+ import com.thingclips.smart.android.camera.sdk.api.IThingCameraMessage
15
+ import com.thingclips.smart.android.camera.sdk.api.IThingIPCMsg
16
+ import com.thingclips.smart.home.sdk.callback.IThingResultCallback
17
+ import com.thingclips.smart.ipc.messagecenter.bean.CameraMessageBean
18
+ import com.thingclips.smart.ipc.messagecenter.bean.CameraMessageClassifyBean
19
+ import kotlinx.coroutines.Dispatchers
20
+ import kotlinx.coroutines.suspendCancellableCoroutine
21
+ import kotlinx.coroutines.withContext
22
+ import kotlinx.coroutines.withTimeoutOrNull
23
+ import java.time.ZonedDateTime
24
+ import java.time.format.DateTimeFormatter
25
+ import kotlin.coroutines.resume
26
+
27
+ object Messages {
28
+
29
+ private var iThingCameraMessage: IThingCameraMessage? = null
30
+ private var alarmDetectionClassify: CameraMessageClassifyBean? = null
31
+
32
+ @RequiresApi(Build.VERSION_CODES.O)
33
+ suspend fun initializeAndFetchMessages(
34
+ offset: MutableState<Int>,
35
+ selectedDate: MutableLongState,
36
+ isLoading: MutableState<Boolean>,
37
+ noMoreMessages: MutableState<Boolean>,
38
+ messages: MutableState<List<CameraMessageBean?>?>
39
+ ) {
40
+ isLoading.value = true
41
+ val isInitialized = initialize()
42
+ if (isInitialized) {
43
+ getMessageList(
44
+ offset = offset,
45
+ messages = messages,
46
+ isLoading = isLoading,
47
+ selectedDate = selectedDate,
48
+ noMoreMessages = noMoreMessages
49
+ )
50
+ } else {
51
+ isLoading.value = false
52
+ Log.i(TAG, "Failed to initialize messages")
53
+ }
54
+ }
55
+
56
+ private suspend fun initialize(): Boolean = withTimeoutOrNull(8000) {
57
+ suspendCancellableCoroutine<Boolean> { continuation ->
58
+ val message: IThingIPCMsg? = ThingIPCSdk.getMessage()
59
+ if (message.isNotNull()) {
60
+ iThingCameraMessage = message.createCameraMessage()
61
+ continuation.resume(true)
62
+ } else {
63
+ Airbrake.logMessage(
64
+ title = "Message Initializing Failed",
65
+ message = "ThingIPCSdk.getMessage() returned null"
66
+ )
67
+ continuation.resume(false)
68
+ }
69
+ }
70
+ } ?: false
71
+
72
+ private suspend fun fetchAlarmDetectionClassify(): CameraMessageClassifyBean? {
73
+ if (alarmDetectionClassify.isNull()) {
74
+ alarmDetectionClassify = withTimeoutOrNull(8000) {
75
+ suspendCancellableCoroutine { continuation ->
76
+ iThingCameraMessage?.queryAlarmDetectionClassify(
77
+ Tuya.deviceId,
78
+ object : IThingResultCallback<List<CameraMessageClassifyBean?>?> {
79
+ override fun onSuccess(result: List<CameraMessageClassifyBean?>?) {
80
+ continuation.resume(result?.get(0))
81
+ }
82
+
83
+ override fun onError(errorCode: String, errorMessage: String) {
84
+ Airbrake.logMessage(
85
+ title = "Fetch Alarm Detection Classify Failed",
86
+ message = "Error Code: $errorCode",
87
+ additionalInfo = mapOf("Error" to errorMessage)
88
+ )
89
+ continuation.resume(null)
90
+ }
91
+ }
92
+ )
93
+ }
94
+ }
95
+ }
96
+ return alarmDetectionClassify
97
+ }
98
+
99
+ @RequiresApi(Build.VERSION_CODES.O)
100
+ suspend fun getMessageList(
101
+ offset: MutableState<Int>,
102
+ selectedDate: MutableLongState,
103
+ isLoading: MutableState<Boolean>,
104
+ noMoreMessages: MutableState<Boolean>,
105
+ messages: MutableState<List<CameraMessageBean?>?>
106
+ ) {
107
+ if (iThingCameraMessage.isNotNull()) {
108
+ isLoading.value = true
109
+
110
+ val selectedDateInSeconds = maxOf(
111
+ DateUtil.getStartOfDay(selectedDate.longValue) / 1000,
112
+ Tuya.lastMoveOutDate?.let {
113
+ ZonedDateTime.parse(it, DateTimeFormatter.ISO_ZONED_DATE_TIME)
114
+ .toEpochSecond()
115
+ } ?: 0L
116
+ )
117
+ val endTime = selectedDateInSeconds + 86340
118
+
119
+ fetchAlarmDetectionClassify()?.let { classifyBean ->
120
+ Log.i(
121
+ TAG,
122
+ "Fetching messages for: $selectedDateInSeconds to $endTime, offset: ${offset.value}"
123
+ )
124
+ iThingCameraMessage?.getAlarmDetectionMessageList(
125
+ Tuya.deviceId,
126
+ selectedDateInSeconds.toInt(),
127
+ endTime.toInt(),
128
+ classifyBean.msgCode,
129
+ offset.value,
130
+ 20,
131
+ object : IThingResultCallback<List<CameraMessageBean?>?> {
132
+ override fun onSuccess(result: List<CameraMessageBean?>?) {
133
+ if (result.isNotNull()) {
134
+ messages.value = messages.value?.plus(result)
135
+ offset.value += result.size
136
+ if (result.size < 20) {
137
+ noMoreMessages.value = true
138
+ }
139
+ isLoading.value = false
140
+ Log.i(TAG, "getAlarmDetectionMessageList success $result")
141
+ } else {
142
+ noMoreMessages.value = true
143
+ isLoading.value = false
144
+ Log.i(TAG, "Messages received is null or empty")
145
+ }
146
+ }
147
+
148
+ override fun onError(errorCode: String, errorMessage: String) {
149
+ isLoading.value = false
150
+ Airbrake.logMessage(
151
+ title = "Get Message List Failed",
152
+ message = "Error Code: $errorCode",
153
+ additionalInfo = mapOf("Error" to errorMessage)
154
+ )
155
+ }
156
+ }
157
+ )
158
+ } ?: run {
159
+ isLoading.value = false
160
+ Log.i(TAG, "Failed to fetch alarm detection classify")
161
+ }
162
+ } else {
163
+ Log.i(TAG, "iThingCameraMessage is null")
164
+ }
165
+ }
166
+
167
+ suspend fun getAvailableMessageDates(
168
+ year: Int,
169
+ month: Int,
170
+ isLoading: MutableState<Boolean>,
171
+ availableDates: MutableState<Array<Int>>
172
+ ) {
173
+ if (iThingCameraMessage.isNotNull()) {
174
+ isLoading.value = true
175
+
176
+ withContext(Dispatchers.IO) {
177
+ val result: List<String?>? = withTimeoutOrNull(5000) {
178
+ suspendCancellableCoroutine { continuation ->
179
+ iThingCameraMessage?.queryMotionDaysByMonth(
180
+ Tuya.deviceId,
181
+ year,
182
+ month,
183
+ object : IThingResultCallback<List<String?>?> {
184
+ override fun onSuccess(result: List<String?>?) {
185
+ Log.i(TAG, "getAvailableMessageDates success $result")
186
+ continuation.resume(result)
187
+ }
188
+
189
+ override fun onError(errorCode: String, errorMessage: String) {
190
+ Airbrake.logMessage(
191
+ title = "Get Available Message Dates Failed",
192
+ message = "Error Code: $errorCode",
193
+ additionalInfo = mapOf("Error" to errorMessage)
194
+ )
195
+ continuation.resume(null)
196
+ }
197
+ })
198
+ }
199
+ }
200
+
201
+ if (result.isNullOrEmpty()) {
202
+ Log.i(TAG, "Fetching available dates for Messages timed out or failed")
203
+ availableDates.value = emptyArray()
204
+ isLoading.value = false
205
+ } else {
206
+ try {
207
+ val days = result.filterNotNull().map { it.toInt() }.toTypedArray()
208
+ availableDates.value = days
209
+ Log.i(
210
+ TAG,
211
+ "Available Message Dates received: ${availableDates.value.joinToString(", ")}"
212
+ )
213
+ } catch (e: Exception) {
214
+ Log.e(TAG, "Parsing available dates for Messages failed: ${e.message}")
215
+ availableDates.value = emptyArray()
216
+ } finally {
217
+ isLoading.value = false
218
+ }
219
+ }
220
+ }
221
+
222
+ } else {
223
+ Log.i(TAG, "iThingCameraMessage is null")
224
+ availableDates.value = emptyArray()
225
+ }
226
+ }
227
+
228
+ fun destroy() {
229
+ if (iThingCameraMessage.isNotNull()) {
230
+ iThingCameraMessage?.destroy()
231
+ iThingCameraMessage = null
232
+ }
233
+ }
234
+ }
@@ -0,0 +1,385 @@
1
+ package com.rentlytuya.tuya
2
+
3
+ import android.os.Build
4
+ import android.util.Log
5
+ import androidx.annotation.RequiresApi
6
+ import androidx.compose.runtime.MutableState
7
+ import com.alibaba.fastjson.JSONObject
8
+ import com.rentlytuya.tuya.Tuya.TAG
9
+ import com.rentlytuya.util.Airbrake
10
+ import com.rentlytuya.util.DateUtil
11
+ import com.rentlytuya.util.DateUtil.isNotNull
12
+ import com.rentlytuya.util.DateUtil.isNull
13
+ import com.thingclips.smart.camera.camerasdk.thingplayer.callback.OperationDelegateCallBack
14
+ import com.thingclips.smart.ipc.camera.autotesting.excute.bean.RecordInfoBean
15
+ import com.thingclips.smart.ipc.camera.autotesting.excute.bean.TimePieceBean
16
+ import kotlinx.coroutines.Dispatchers
17
+ import kotlinx.coroutines.suspendCancellableCoroutine
18
+ import kotlinx.coroutines.withContext
19
+ import kotlinx.coroutines.withTimeoutOrNull
20
+ import kotlin.coroutines.resume
21
+
22
+ object Playback {
23
+
24
+ suspend fun getAvailableDates(
25
+ year: Int,
26
+ month: Int,
27
+ availableDates: MutableState<Array<Int>>,
28
+ isLoading: MutableState<Boolean>
29
+ ) {
30
+ if (Tuya.mCameraP2P.isNotNull()) {
31
+ isLoading.value = true
32
+
33
+ withContext(Dispatchers.IO) {
34
+ val result: String? = withTimeoutOrNull(5000) {
35
+ suspendCancellableCoroutine { continuation ->
36
+ Tuya.mCameraP2P?.queryRecordDaysByMonth(
37
+ year,
38
+ month,
39
+ object : OperationDelegateCallBack {
40
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
41
+ Log.i(TAG, "getAvailableDates Success: Data: $data")
42
+ continuation.resume(data)
43
+ }
44
+
45
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
46
+ Airbrake.logMessage(
47
+ title = "Get Available dates Failed",
48
+ message = "Error Code: $errCode",
49
+ additionalInfo = mapOf(
50
+ "sessionId" to sessionId.toString(),
51
+ "requestId" to requestId.toString()
52
+ )
53
+ )
54
+ continuation.resume(null)
55
+ }
56
+ })
57
+ }
58
+ }
59
+
60
+ if (result.isNullOrEmpty()) {
61
+ Log.i(TAG, "Fetching available dates timed out or failed")
62
+ availableDates.value = emptyArray()
63
+ isLoading.value = false
64
+ } else {
65
+ try {
66
+ val jsonObject = org.json.JSONObject(result)
67
+ val dataDaysArray = jsonObject.getJSONArray("DataDays")
68
+ val days = Array(dataDaysArray.length()) { index ->
69
+ dataDaysArray.getString(index).toInt()
70
+ }
71
+ availableDates.value = days
72
+ Log.i(TAG, "Available Dates received: ${availableDates.value.joinToString(", ")}")
73
+ } catch (e: Exception) {
74
+ Log.e(TAG, "Parsing available dates failed: ${e.message}")
75
+ availableDates.value = emptyArray()
76
+ } finally {
77
+ isLoading.value = false
78
+ }
79
+ }
80
+ }
81
+ } else {
82
+ Log.i(TAG, "mCameraP2P is null")
83
+ availableDates.value = emptyArray()
84
+ }
85
+ }
86
+
87
+ @RequiresApi(Build.VERSION_CODES.O)
88
+ suspend fun getAllTheClipsOfTheDay(
89
+ year: Int,
90
+ month: Int,
91
+ day: Int,
92
+ isPaused: MutableState<Boolean>,
93
+ isPlaying: MutableState<Boolean>,
94
+ isLoading: MutableState<Boolean>,
95
+ videos: MutableState<List<TimePieceBean>>,
96
+ selectedItem: MutableState<TimePieceBean?>
97
+ ) {
98
+ if (Tuya.mCameraP2P.isNotNull()) {
99
+ isLoading.value = true
100
+
101
+ withContext(Dispatchers.IO) {
102
+ val result: String? = withTimeoutOrNull(10000) {
103
+ suspendCancellableCoroutine { continuation ->
104
+ Tuya.mCameraP2P?.queryRecordTimeSliceByDay(
105
+ year,
106
+ month,
107
+ day,
108
+ object : OperationDelegateCallBack {
109
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
110
+ Log.i(
111
+ TAG,
112
+ "getAllTheClipsOfTheDay Success: SessionId: $sessionId, RequestID: $requestId, Date: $data"
113
+ )
114
+ continuation.resume(data)
115
+ }
116
+
117
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
118
+ isPlaying.value = false
119
+ isLoading.value = false
120
+ Airbrake.logMessage(
121
+ title = "Get Video Clips Failed",
122
+ message = "Error Code: $errCode",
123
+ additionalInfo = mapOf(
124
+ "sessionId" to sessionId.toString(),
125
+ "requestId" to requestId.toString()
126
+ )
127
+ )
128
+ continuation.resume(null)
129
+ }
130
+ }
131
+ )
132
+ }
133
+ }
134
+
135
+ if (result.isNull()) {
136
+ Log.i(TAG, "Video List fetching timed out after 10 seconds")
137
+ isPlaying.value = false
138
+ isLoading.value = false
139
+ } else {
140
+ parsePlaybackData(
141
+ data = result!!,
142
+ videos = videos,
143
+ isPaused = isPaused,
144
+ isLoading = isLoading,
145
+ isPlaying = isPlaying,
146
+ selectedItem = selectedItem
147
+ )
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ @RequiresApi(Build.VERSION_CODES.O)
154
+ private fun parsePlaybackData(
155
+ data: String,
156
+ isPaused: MutableState<Boolean>,
157
+ isLoading: MutableState<Boolean>,
158
+ isPlaying: MutableState<Boolean>,
159
+ videos: MutableState<List<TimePieceBean>>,
160
+ selectedItem: MutableState<TimePieceBean?>
161
+ ) {
162
+ val recordInfoBean: RecordInfoBean =
163
+ JSONObject.parseObject(data, RecordInfoBean::class.java)
164
+
165
+ if (recordInfoBean.count != 0) {
166
+ val timePieceBeanList: List<TimePieceBean>? = recordInfoBean.items
167
+ if (!timePieceBeanList.isNullOrEmpty()) {
168
+ videos.value = timePieceBeanList
169
+ .filter { video ->
170
+ Tuya.lastMoveOutDate?.let {
171
+ val epochTime = DateUtil.convertToEpoch(it)
172
+ val isValid = video.startTime >= epochTime
173
+ isValid
174
+ } ?: true
175
+ }
176
+ .reversed()
177
+
178
+ if (videos.value.isNotEmpty()) {
179
+ startSDCardPlayback(
180
+ isPaused = isPaused,
181
+ isLoading = isLoading,
182
+ isPlaying = isPlaying,
183
+ selectedItem = selectedItem,
184
+ video = videos.value[0],
185
+ videoList = videos.value
186
+ )
187
+ } else {
188
+ videos.value = emptyList()
189
+ isLoading.value = false
190
+ isPlaying.value = false
191
+ isPaused.value = true
192
+ Log.i(TAG, "No valid videos found before lastMoveOut")
193
+ }
194
+ }
195
+ } else {
196
+ videos.value = emptyList()
197
+ isLoading.value = false
198
+ isPlaying.value = false
199
+ isPaused.value = true
200
+ Log.i(TAG, "RecordInfoBean count is equal to 0")
201
+ }
202
+ }
203
+
204
+ fun startSDCardPlayback(
205
+ videoList: List<TimePieceBean>?,
206
+ video: TimePieceBean,
207
+ playTime: Int? = null,
208
+ isPaused: MutableState<Boolean>,
209
+ isLoading: MutableState<Boolean>,
210
+ isPlaying: MutableState<Boolean>,
211
+ selectedItem: MutableState<TimePieceBean?>
212
+ ) {
213
+ if (Tuya.mCameraP2P.isNotNull()) {
214
+
215
+ val isEndOfVideo = playTime.isNotNull() && playTime == video.endTime
216
+
217
+ if (isEndOfVideo) {
218
+ val currentIndex = videoList?.indexOf(video) ?: -1
219
+ val nextIndex = currentIndex + 1
220
+
221
+ if (videoList.isNotNull() && nextIndex < videoList.size) {
222
+ val nextVideo = videoList[nextIndex]
223
+ Log.i(TAG, "Switching to next video: $nextVideo")
224
+ startSDCardPlayback(
225
+ videoList = videoList,
226
+ video = nextVideo,
227
+ isPaused = isPaused,
228
+ isLoading = isLoading,
229
+ isPlaying = isPlaying,
230
+ selectedItem = selectedItem
231
+ )
232
+ return
233
+ } else {
234
+ Log.i(TAG, "No more videos available.")
235
+ isPlaying.value = false
236
+ return
237
+ }
238
+ }
239
+
240
+ isLoading.value = true
241
+ Tuya.mCameraP2P?.startPlayBack(
242
+ video.startTime,
243
+ video.endTime,
244
+ playTime ?: video.startTime, object : OperationDelegateCallBack {
245
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
246
+ Log.i(
247
+ TAG,
248
+ "startSDCardPlayback success: SessionId: $sessionId, RequestId: $requestId, Data: $data"
249
+ )
250
+ isLoading.value = false
251
+ isPlaying.value = true
252
+ isPaused.value = false
253
+ selectedItem.value = video
254
+ }
255
+
256
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
257
+ isLoading.value = false
258
+ isPlaying.value = false
259
+ Airbrake.logMessage(
260
+ title = "Start SD Card Playback Failed",
261
+ message = "Error Code: $errCode",
262
+ additionalInfo = mapOf(
263
+ "sessionId" to sessionId.toString(),
264
+ "requestId" to requestId.toString()
265
+ )
266
+ )
267
+ }
268
+ }, object : OperationDelegateCallBack {
269
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
270
+ Log.i(
271
+ TAG,
272
+ "Finished playback: Session Id: $sessionId, requestId: $requestId, Data: $data"
273
+ )
274
+ isLoading.value = false
275
+ isPlaying.value = false
276
+ }
277
+
278
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
279
+ isLoading.value = false
280
+ isPlaying.value = false
281
+ Airbrake.logMessage(
282
+ title = "Finish Playback Failed",
283
+ message = "Error Code: $errCode",
284
+ additionalInfo = mapOf(
285
+ "sessionId" to sessionId.toString(),
286
+ "requestId" to requestId.toString()
287
+ )
288
+ )
289
+ }
290
+ })
291
+ }
292
+ }
293
+
294
+ fun pauseSDCardPlayback(
295
+ isPaused: MutableState<Boolean>
296
+ ) {
297
+ if (Tuya.mCameraP2P.isNotNull()) {
298
+ Tuya.mCameraP2P?.pausePlayBack(object : OperationDelegateCallBack {
299
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
300
+ Log.i(
301
+ TAG,
302
+ "pauseSDCardPlayback success: SessionId: $sessionId, RequestId: $requestId, Data: $data"
303
+ )
304
+ isPaused.value = true
305
+ }
306
+
307
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
308
+ // Keep the isPaused state same
309
+ Airbrake.logMessage(
310
+ title = "Pause SD card Playback Failed",
311
+ message = "Error Code: $errCode",
312
+ additionalInfo = mapOf(
313
+ "sessionId" to sessionId.toString(),
314
+ "requestId" to requestId.toString()
315
+ )
316
+ )
317
+ }
318
+ })
319
+ } else {
320
+ Log.i(TAG, "mCameraP2P is null")
321
+ }
322
+ }
323
+
324
+ fun resumeSDCardPlayback(
325
+ isPaused: MutableState<Boolean>
326
+ ) {
327
+ if (Tuya.mCameraP2P.isNotNull()) {
328
+ Tuya.mCameraP2P?.resumePlayBack(object : OperationDelegateCallBack {
329
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
330
+ Log.i(
331
+ TAG,
332
+ "resumeSDCardPlayback success: SessionId: $sessionId. RequestId: $requestId, Data: $data"
333
+ )
334
+ isPaused.value = false
335
+ }
336
+
337
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
338
+ // Keep the isPaused state same
339
+ Airbrake.logMessage(
340
+ title = "Resume SD Card Playback Failed",
341
+ message = "Error Code: $errCode",
342
+ additionalInfo = mapOf(
343
+ "sessionId" to sessionId.toString(),
344
+ "requestId" to requestId.toString()
345
+ )
346
+ )
347
+ }
348
+ })
349
+ } else {
350
+ Log.i(TAG, "mCameraP2P is null")
351
+ }
352
+ }
353
+
354
+ fun stopSDCardPlayback(
355
+ isPlaying: MutableState<Boolean>? = null
356
+ ) {
357
+ if (Tuya.mCameraP2P.isNotNull()) {
358
+ Tuya.mCameraP2P?.stopPlayBack(object : OperationDelegateCallBack {
359
+ override fun onSuccess(sessionId: Int, requestId: Int, data: String) {
360
+ if (isPlaying.isNotNull()) {
361
+ isPlaying.value = false
362
+ }
363
+ Log.i(
364
+ TAG,
365
+ "stopSDCardPlayback success: SessionId: $sessionId. RequestId: $requestId, Data: $data"
366
+ )
367
+ }
368
+
369
+ override fun onFailure(sessionId: Int, requestId: Int, errCode: Int) {
370
+ // Keep the isPlaying and isPaused state same
371
+ Airbrake.logMessage(
372
+ title = "Stop SD card Playback Failed",
373
+ message = "Error Code: $errCode",
374
+ additionalInfo = mapOf(
375
+ "sessionId" to sessionId.toString(),
376
+ "requestId" to requestId.toString()
377
+ )
378
+ )
379
+ }
380
+ })
381
+ } else {
382
+ Log.i(TAG, "mCameraP2P is null")
383
+ }
384
+ }
385
+ }