From ed28af77319aff7cef98e12a7201c10d43607f8c Mon Sep 17 00:00:00 2001 From: Ilia <58937357+Izchomatik@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:02:47 +0200 Subject: [PATCH] Implement android bridge using pigeon (#98) --- android/app/build.gradle | 22 ++ android/app/src/main/AndroidManifest.xml | 11 +- .../org/rocstreaming/connector/Connector.g.kt | 176 ++++++++++++++++ .../org/rocstreaming/connector/Connector.kt | 36 ++++ .../org/rocstreaming/rocdroid/MainActivity.kt | 7 +- .../service}/SenderReceiverService.kt | 4 +- .../res/drawable-hdpi/ic_notification.png | Bin 0 -> 1100 bytes .../res/drawable-mdpi/ic_notification.png | Bin 0 -> 667 bytes .../drawable-night-xhdpi/ic_notification.png | Bin 0 -> 1530 bytes .../drawable-night-xxhdpi/ic_notification.png | Bin 0 -> 2406 bytes .../ic_notification.png | Bin 0 -> 3342 bytes android/app/src/main/res/drawable/ic_stop.xml | 10 + android/app/src/main/res/values/strings.xml | 58 ++++++ android/build.gradle | 22 ++ android/gradle.properties | 1 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- dodo.py | 34 +++- lib/main.dart | 1 + lib/src/agent.dart | 3 +- lib/src/agent/android_backend.dart | 36 ++++ lib/src/agent/android_service.dart | 4 - lib/src/agent/backend.dart | 32 +++ lib/src/agent/backend.g.dart | 190 ++++++++++++++++++ lib/src/agent/desktop_service.dart | 4 - lib/src/model/model_root.dart | 10 +- lib/src/model/receiver.dart | 13 +- lib/src/model/sender.dart | 12 +- pubspec.lock | 163 +++++++++------ pubspec.yaml | 5 +- test/model/receiver_test.dart | 3 +- test/model/sender_test.dart | 3 +- 31 files changed, 769 insertions(+), 93 deletions(-) create mode 100644 android/app/src/main/kotlin/org/rocstreaming/connector/Connector.g.kt create mode 100644 android/app/src/main/kotlin/org/rocstreaming/connector/Connector.kt rename {_temp_storage/app/src/main/java/org/rocstreaming/rocdroid => android/app/src/main/kotlin/org/rocstreaming/service}/SenderReceiverService.kt (99%) create mode 100644 android/app/src/main/res/drawable-hdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-mdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-night-xhdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-night-xxhdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-night-xxxhdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable/ic_stop.xml create mode 100644 android/app/src/main/res/values/strings.xml create mode 100644 lib/src/agent/android_backend.dart delete mode 100644 lib/src/agent/android_service.dart create mode 100644 lib/src/agent/backend.dart create mode 100644 lib/src/agent/backend.g.dart delete mode 100644 lib/src/agent/desktop_service.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 348262e..bbe3f74 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,6 +23,10 @@ if (flutterVersionName == null) { flutterVersionName = "1.0" } +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + android { namespace = "org.rocstreaming.rocdroid" compileSdk = flutter.compileSdkVersion @@ -33,6 +37,10 @@ android { targetCompatibility = JavaVersion.VERSION_1_8 } + kotlinOptions { + jvmTarget = '1.8' + } + defaultConfig { applicationId = "org.rocstreaming.rocdroid" // You can update the following values to match your application needs. @@ -41,6 +49,7 @@ android { targetSdk = flutter.targetSdkVersion versionCode = flutterVersionCode.toInteger() versionName = flutterVersionName + minSdkVersion = 26 } applicationVariants.all { variant -> @@ -61,3 +70,16 @@ android { flutter { source = "../.." } + +dependencies { + implementation 'org.roc-streaming.roctoolkit:roc-android:0.2.1' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.core:core-ktx:1.3.0' + implementation 'androidx.activity:activity-ktx:1.2.4' + implementation 'androidx.fragment:fragment-ktx:1.3.6' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.viewpager2:viewpager2:1.0.0' + implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25' +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cad64e5..c792549 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,13 @@ - + + + + + + + { + return listOf(result) +} + +private fun wrapError(exception: Throwable): List { + return if (exception is FlutterError) { + listOf( + exception.code, + exception.message, + exception.details + ) + } else { + listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) + ) + } +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class FlutterError ( + val code: String, + override val message: String? = null, + val details: Any? = null +) : Throwable() +private object ConnectorPigeonCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return super.readValueOfType(type, buffer) + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + super.writeValue(stream, value) + } +} + +/** + * ???. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface Backend { + fun startReceiver() + fun stopReceiver() + fun isReceiverAlive(): Boolean + fun startSender(ip: String) + fun stopSender() + fun isSenderAlive(): Boolean + + companion object { + /** The codec used by Backend. */ + val codec: MessageCodec by lazy { + ConnectorPigeonCodec + } + /** Sets up an instance of `Backend` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: Backend?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.startReceiver$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.startReceiver() + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.stopReceiver$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.stopReceiver() + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.isReceiverAlive$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isReceiverAlive()) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.startSender$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val ipArg = args[0] as String + val wrapped: List = try { + api.startSender(ipArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.stopSender$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + api.stopSender() + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.isSenderAlive$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + val wrapped: List = try { + listOf(api.isSenderAlive()) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } + + fun getHostLanguage(): String +} diff --git a/android/app/src/main/kotlin/org/rocstreaming/connector/Connector.kt b/android/app/src/main/kotlin/org/rocstreaming/connector/Connector.kt new file mode 100644 index 0000000..4db8727 --- /dev/null +++ b/android/app/src/main/kotlin/org/rocstreaming/connector/Connector.kt @@ -0,0 +1,36 @@ +package org.rocstreaming.connector + +import Backend +import org.rocstreaming.service.SenderReceiverService + +private class Connector : Backend { + override fun getHostLanguage(): String { + return "Kotlin" + } + + private var senderReceiverService: SenderReceiverService = SenderReceiverService() + + override fun startReceiver() { + senderReceiverService.startReceiver() + } + + override fun stopReceiver() { + senderReceiverService.stopReceiver() + } + + override fun isReceiverAlive(): Boolean { + return senderReceiverService.isReceiverAlive() + } + + override fun startSender(ip: String) { + senderReceiverService.startSender(ip, null) + } + + override fun stopSender() { + senderReceiverService.stopSender() + } + + override fun isSenderAlive(): Boolean { + return senderReceiverService.isSenderAlive() + } +} \ No newline at end of file diff --git a/android/app/src/main/kotlin/org/rocstreaming/rocdroid/MainActivity.kt b/android/app/src/main/kotlin/org/rocstreaming/rocdroid/MainActivity.kt index 5be9115..5ed1fe4 100644 --- a/android/app/src/main/kotlin/org/rocstreaming/rocdroid/MainActivity.kt +++ b/android/app/src/main/kotlin/org/rocstreaming/rocdroid/MainActivity.kt @@ -1,5 +1,10 @@ package org.rocstreaming.rocdroid import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.embedding.engine.plugins.FlutterPlugin -class MainActivity: FlutterActivity() +class MainActivity: FlutterActivity(){ + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) +}} diff --git a/_temp_storage/app/src/main/java/org/rocstreaming/rocdroid/SenderReceiverService.kt b/android/app/src/main/kotlin/org/rocstreaming/service/SenderReceiverService.kt similarity index 99% rename from _temp_storage/app/src/main/java/org/rocstreaming/rocdroid/SenderReceiverService.kt rename to android/app/src/main/kotlin/org/rocstreaming/service/SenderReceiverService.kt index 2f5be92..b8ffec8 100644 --- a/_temp_storage/app/src/main/java/org/rocstreaming/rocdroid/SenderReceiverService.kt +++ b/android/app/src/main/kotlin/org/rocstreaming/service/SenderReceiverService.kt @@ -1,4 +1,4 @@ -package org.rocstreaming.rocdroid +package org.rocstreaming.service import android.app.Notification import android.app.NotificationChannel @@ -23,6 +23,8 @@ import android.os.IBinder import android.util.Log import androidx.annotation.RequiresApi import androidx.appcompat.app.AlertDialog +import org.rocstreaming.rocdroid.MainActivity +import org.rocstreaming.rocdroid.R import org.rocstreaming.roctoolkit.ChannelSet import org.rocstreaming.roctoolkit.ClockSource import org.rocstreaming.roctoolkit.Endpoint diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification.png b/android/app/src/main/res/drawable-hdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..a0c06dc2dccab4f7a8236c3937b603bb722d869f GIT binary patch literal 1100 zcmV-S1he~zP)pYDcP_wVmZ=m>M z-(yA=`&xYlMPHHZcgDlK`MzeaL9r*SXkTFd6koenpwJL#C-e*SGju8JDI;G%LwxPb zAh{IU0aX`>jfUO}d%FuiK_e{pDbb57^>tGby(1h9dB@t8Ku4f|p(<<3GAQ2BF+uGw zt(}9)cE@0BwWO<1B~%5qK(9h|&^l&x_QU=r`rHW7$y_433C4UF#CS!2LyLl(=S3f? zoV=exFXbzC=Z&@B!=Qhns>*z*n4T~v0fOaFXOKibfF3B|-RgWX^cS0_#E#>kT}fNi zPc-RMfnk|Tis2mKT^MG*MbPI-OE-I4t*zn7hCRWAU@T+yL~J|bOMu8&`M~d=-zV_ z`cd?SzS6whFw=tjso9Ox!!1$4~(UCEJX;=>la8;2yn$Hc40^Horn z7m|fX@}tqjW(%BwHb~D+EaVx>;X}3%4HoBTQW~t!e)v{ETKs_cN*+*|q4q#*jqQwSD}H@)~pE@qdtbMwr(SWNFejYOZ; zX+`VI!`FzA*Q}i%lZD_!E=%@w4nLUq?Eu z*iF#~CqHS`-r%eAbJ-bwcq??%1Qo(zKZd{8?E5@{Jww=r~9@+27=pcMM&#= Skw2>d0000KIn%psavM+u-?3< zKKCmU1ykSwY=8xD6qZA?m7YZAJEFH69>UbzcUb0Ma1%bkG}r}8V5>~bS5nY7^8;>; z-d^*MkmOOB`>Uu6uEMz}?u+mxFmlTxejR4Q9rHu)Dt7ncPFQ8W>^U+q zKZE^H9W_ldN_u9QuVe*mG}mhA9C02gu7bN!bQ@-vZ;{SrGF*$CbjxC|&9`=w2=EFAg z9-ZT3xS0EEf>*FKi;aa-?pIR!F&1ry`GiAhOu>d|m|m3d++y>U<$4XxCF*r%QbQVS zkKlbc4bR{S9Dxb2Hu9-->&C$$cx3(&XW(As+tUg9;4_?suTfCYZu1-VCW*Z_H{Y4W zB=yQeUcm$_VekDa=PtqvuF~3nm@D8fY->OtSxldV9JRV-aG4m(jQp9!WCt|EOYm@mq z^-?{>E~Ci&!E1@}B=aXhPxnd~0}~_HQmFes^%I}gn3!PH+4Dl#Y=plF_3{r`9Eea<@Tp5b2KeJSyN@aLVo_gZW3d+s@F?Y&>OZe9G( z5RpBhQ=luLTY`8!mwn!ThXIp28fu6Bkz&}_4$bub+YQk>zAiJ(#&}Y;_b-A8jE6pV z6KjSqpaXr}{{##?2Kw4fXj@>6F+P5$f&qs>AGnEhgb$&iewMTFy=@H$V@E zw!NHR4|Dwrv?g3165?@e&VgK>dX@mgfx+n=XkTbG^nB=B5Q0r~KC?wr>L}Y@hUl;L zJ~Tx%QIMsfk1Jd9fan}JmmkI5xLja#4zvl{4Vo(Y{PShol>tOE#NJRp(U%+oY}ogm>ATs+2sZmcb3`-Q zc;8RZ-d*(9<4qeB+L$Ex%tu}q&3v5GBp;&?7@ui^kl&zbrvGHoJ9RwN+q54Hy=eR* zo1v-Et_VrrGs{`tt`yNngW1NzFR=vb=Y0s;X9b%gn5j;6KD93|I_8yNn2#wLx2z1K9;OV}t!x-*M7iTErs5e1C%I(m2xQ`^%8()N5fP=dQ?-z0%Ol54(Ij}v?8`ANI_N*EmT!UiBB8* z{*u3};PN3!fw+Fq8#p*-&uDLvg1HtVy6Y-~%VfK@dBhul4W^$9IPUVwm>umqjOflO zZGyQs?qMv(^zAzY g(&}{BMHj8*Us<{9 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-night-xxhdpi/ic_notification.png b/android/app/src/main/res/drawable-night-xxhdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..b48aa1b268aa60bf6c6a505804efca98eb02948d GIT binary patch literal 2406 zcmV-s37PhZP)W`o;&y5visiK5B8Uwyxo~IXJ+osojG%6-g3)LnKI?E z41f(O&!N1O^6Dh|th5cI{^J66d|%3YC_h3oKZfb<7wtUeU?-2D++FT}C%#QNlCpfX zy-dRnZB6-NxvwMfCCb*Zo@EktU1<11 z@_S6`Lt?}Br~ENAcrnoEor&#Rbl9l3#Fj21=fw6cI&9R6lrP7YE&^YntQgxj5wKw! zz#h^EC~u{lO}T<{-?07j$^(=QV!IX`Hex->4U~;yULDlk3*+5xM1D)zK2z^Tu(m!i z=FJPL2)1byH>1OFrtb2TH)H$`q?Y(SGxh1UzbWZ_hq8Xu87r({ZOS)Og$2h3of*o9 zDBq=gpYjQWk;dy;ggB+aBf}77M^e{h-ZbgGMijHIYMt&Y3CwUdlTuODLC8Hli4MG&K z2ib+cQLcw=gje=;Bzx~ldMCKFr710PlrP&GSj_l0(K`9G)43?6ea4sdFz=3}bDc|j ze@biO5z6UEBcl%HUzzkTc4@C4SSh2|v-K)m3yoYI4Brat>|mJk^NlHQsW0nc-Z@F< zK9_b3Y$q<%;QN(N`88~%`#0qR%39u59n|}9vUQnDdr3;Wlk)ZSx!{AYcz0;vX&45) z)R8w*HlzFnC@hR=E zl+7upVfdq{Z@Uz_onhgRBtv?|_77<{IKATCe|T8B42DDf@|f2L+Ib(W(!Uqbcp#7)~3rX`O+2%m0A6@7t!deK2(L^h(Swm;AduEYxsQ*~)C5oV88U z=cg8BMg=w+a&f1tgWh#6Pi@~frEdc}Qc@qgd)X}XLf9(vr1V|Bi{4|;kxqYhMN6OM z4`~mkNmvh94I9s@;eeg5{WP^jb!ZM+&E>Cw>VbhA-D36K1m?`XXlS)1EVMFZ4fp*7 zS4qJSD63}5{U_*&qrIModAm?vOSurXBI9+y;w7Jw(~f+e~(EFRQmk z55E5>!f1i`i!$~!VT+?EKXJNE=tp`5Ea)}Z%Q?I9j{DL-z>jKh%%hb+`P$#8;c-Jd z*ajq9nwaHGj*3of*A2FPv_Pny@4?z8-%TU0E{b`Vx78Y$Cmk;y=-f+z_${KofCcTf zbjyz^O{o07x3e=UrCS}aiC@mC?jOxMwh^UM-T<2;J?djGPx{bcNKWDAQLinq2Rkm_ z8|}9R_9MnQ>#(TT2n)U48PMvmRn%z<%dP`^CC7#0&`*x_v<3E%ik-iBN7QKq!w`n( z9ioJ}@K}X0Tb=?AAi%14H4NsM8hLj{RrBZXdLg&P4lN zp^Y7a-Gib|EvO#s4Wfsm0Q1cKAETk1=W+LPf~U>j5)J=A-x>nl5_{MBLCTDp=8 zQN)#UE^>jgB6QM)dyqym%u)O}${X^zkAP5qy)^OVE+zT1v9@S}Egc`jLb+}2>=VlB zB%|xzPIXoOrHW~LpnMgl{xySb4YcdtE9QA%qpB;Vi&n{w_ESwfh-zf=xlySFpYk>$ zuq%SboT(BeJ82c{RHR$SKuuI@yk;l<*k&ObXS8bc9 z{PP>rz8aOt{TV$S2y|gdw6Wm8E;e-WNp8&8$lbztTSia!uiK(~jjgWk%{$2N-!wVu z`r9d#Ke%))xuqNLu&86)bnX;%Rzvy1lmch6eH`+OMZLqf(7?{6qSH6H76W?#A9H!H z^5v6`JokcoGWmzQd~Fd1AyQObj=?3Vi2-(r!2h4>aTy&g(Yp3_OD0cu4GYfB4ZheT7*9*I~rs(DBKD~hHyQOmC zjF>-Bz(Sll6YqRk6Lu@@?wH<$>Y{uNldx*dC+y%!lrv-clmskZ-FR_x%9JTnrc9aT Y{~L70;pA;pr2qf`07*qoM6N<$g7kOL=l}o! literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-night-xxxhdpi/ic_notification.png b/android/app/src/main/res/drawable-night-xxxhdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..867045b895659bd08e637389ee0d7ed935ab8eff GIT binary patch literal 3342 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 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable/ic_stop.xml b/android/app/src/main/res/drawable/ic_stop.xml new file mode 100644 index 0000000..d099f1a --- /dev/null +++ b/android/app/src/main/res/drawable/ic_stop.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..63d4c2f --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,58 @@ + + Roc Droid + + Receiver + Start receiver + Stop receiver + + Sender + Receiver IP + 192.168.0.1 + Start sender + Stop sender + Invalid IP address + The receiver IP address looks invalid. + Mic permission + The app needs permission to record audio from your phone mic. + Thanks! The sender will now start. + + OK + + Sender and Receiver foreground service + Receiver running + Sender running + Sender and Receiver running + Neither Sender or Receiver running + Roc State + Stop Sender + Stop Receiver + + 1. Start sender on the remote device + 2. Use one of IP addresses of this device as the remote on the sender + 5. Start receiver on this device + + 1. Start receiver on the remote device + 4. Put IP address of the remote receiver device below + 5. Choose source to capture audio from + Currently playing apps + Microphone + 6. Start sender on this device + Source to capture audio from + + %s. Use this port for source stream + %s. Use this port for repair stream + About + Source Code + Bug Tracker + Contributors + Mozilla Public License 2.0 + + https://github.com/roc-streaming/roc-droid + https://github.com/roc-streaming/roc-droid/issues + https://github.com/roc-streaming/roc-droid/graphs/contributors + https://github.com/roc-streaming/roc-droid/blob/main/LICENSE + App Logo + Copy + Open dropdown + Roc Droid receiver + diff --git a/android/build.gradle b/android/build.gradle index d2ffbff..9c6a893 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,6 +1,20 @@ +buildscript { + ext.kotlin_version = '1.7.21' + + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + allprojects { repositories { google() + jcenter() mavenCentral() } } @@ -13,6 +27,14 @@ subprojects { project.evaluationDependsOn(":app") } +subprojects { + beforeEvaluate { project -> + if (project.name == "flutter_localization") { + project.buildscript.dependencies.classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}" + } + } +} + tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/android/gradle.properties b/android/gradle.properties index 3b5b324..958b7f2 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +minSdkVersion=26 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index e1ca574..5af0f53 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip diff --git a/dodo.py b/dodo.py index e20fe16..a6bf591 100644 --- a/dodo.py +++ b/dodo.py @@ -56,20 +56,37 @@ def task_wipe(): # doit gen def task_gen(): - """run flutter build_runner code generation""" + """run all flutter code generation""" + return { + 'actions': [get_action(task_gen_model()), + get_action(task_gen_agent())], + 'title': title_with_actions, + } + +# doit gen_model +def task_gen_model(): + """run flutter build_runner Model code generation""" return { 'actions': ['dart run build_runner build --delete-conflicting-outputs'], 'title': title_with_actions, } -# doit gen_watch -def task_gen_watch(): - """run flutter build_runner code watch generation""" +# doit gen_model_watch +def task_gen_model_watch(): + """run flutter build_runner Moddel code watch generation""" return { 'actions': [LongRunning('dart run build_runner watch --delete-conflicting-outputs')], 'title': title_with_actions, } +# doit gen_agent +def task_gen_agent(): + """run flutter pigeon Agent code generation""" + return { + 'actions': ['dart run pigeon --input lib/src/agent/ibackend.dart'], + 'title': title_with_actions, + } + # doit icons def task_icons(): """run flutter icons generation (flutter_launcher_icons)""" @@ -85,3 +102,12 @@ def task_splash(): 'actions': ['dart run flutter_native_splash:create '], 'title': title_with_actions, } + +# Get first doit method 'actions' value +def get_action(dic): + + for key, value in dic.items(): + if key == 'actions': + return value[0] + + return "action doesn't exist" diff --git a/lib/main.dart b/lib/main.dart index 0bd0150..5e535a4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,5 +5,6 @@ import 'src/model.dart'; import 'src/ui.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); runApp(AppRoot(ModelRoot())); } diff --git a/lib/src/agent.dart b/lib/src/agent.dart index d122d0e..c136d93 100644 --- a/lib/src/agent.dart +++ b/lib/src/agent.dart @@ -1,3 +1,2 @@ /// Agent export definition. -export 'agent/android_service.dart'; -export 'agent/desktop_service.dart'; +export 'agent/backend.dart'; diff --git a/lib/src/agent/android_backend.dart b/lib/src/agent/android_backend.dart new file mode 100644 index 0000000..2c05764 --- /dev/null +++ b/lib/src/agent/android_backend.dart @@ -0,0 +1,36 @@ +import 'backend.g.dart'; + +/// ???. +class AndroidBackend implements Backend { + final Backend _backend = Backend(); + + @override + Future isReceiverAlive() async { + return await _backend.isReceiverAlive(); + } + + @override + Future isSenderAlive() async { + return await _backend.isSenderAlive(); + } + + @override + Future startReceiver() async { + await _backend.startReceiver(); + } + + @override + Future startSender(String ip) async { + await _backend.startSender(ip); + } + + @override + Future stopReceiver() async { + await _backend.stopReceiver(); + } + + @override + Future stopSender() async { + await _backend.stopSender(); + } +} diff --git a/lib/src/agent/android_service.dart b/lib/src/agent/android_service.dart deleted file mode 100644 index c44f192..0000000 --- a/lib/src/agent/android_service.dart +++ /dev/null @@ -1,4 +0,0 @@ -/// Implementation of the Agent Android service class. -class AndroidService { - // TODO - implement this class -} diff --git a/lib/src/agent/backend.dart b/lib/src/agent/backend.dart new file mode 100644 index 0000000..3d60882 --- /dev/null +++ b/lib/src/agent/backend.dart @@ -0,0 +1,32 @@ +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon(PigeonOptions( + dartOut: 'lib/src/agent/backend.g.dart', + dartOptions: DartOptions(), + kotlinOut: + 'android/app/src/main/kotlin/org/rocstreaming/connector/Connector.g.kt', + kotlinOptions: KotlinOptions(), + dartPackageName: 'roc_droid_package', +)) + +/// ???. +@HostApi() +abstract class Backend { + void startReceiver(); + + void stopReceiver(); + + bool isReceiverAlive(); + + void startSender(String ip); + + void stopSender(); + + bool isSenderAlive(); +} + +// /// ???. +// @FlutterApi() +// abstract class FlutterHandler { +// void textChanged(String text); +// } diff --git a/lib/src/agent/backend.g.dart b/lib/src/agent/backend.g.dart new file mode 100644 index 0000000..e6a8f14 --- /dev/null +++ b/lib/src/agent/backend.g.dart @@ -0,0 +1,190 @@ +// Autogenerated from Pigeon (v21.1.0), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); +} + +/// ???. +class Backend { + /// Constructor for [Backend]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + Backend({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : __pigeon_binaryMessenger = binaryMessenger, + __pigeon_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? __pigeon_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String __pigeon_messageChannelSuffix; + + Future startReceiver() async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.startReceiver$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + Future stopReceiver() async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.stopReceiver$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + Future isReceiverAlive() async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.isReceiverAlive$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as bool?)!; + } + } + + Future startSender(String ip) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.startSender$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([ip]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + Future stopSender() async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.stopSender$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + Future isSenderAlive() async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.roc_droid_package.Backend.isSenderAlive$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as bool?)!; + } + } +} diff --git a/lib/src/agent/desktop_service.dart b/lib/src/agent/desktop_service.dart deleted file mode 100644 index 5998656..0000000 --- a/lib/src/agent/desktop_service.dart +++ /dev/null @@ -1,4 +0,0 @@ -/// Implementation of the Agent Desktop service class. -class DesktopService { - // TODO - implement this class -} diff --git a/lib/src/model/model_root.dart b/lib/src/model/model_root.dart index 4a95ad6..40aadef 100644 --- a/lib/src/model/model_root.dart +++ b/lib/src/model/model_root.dart @@ -1,5 +1,7 @@ import 'package:logger/logger.dart'; +import '../agent/android_backend.dart'; +import '../agent/backend.g.dart'; import 'receiver.dart'; import 'sender.dart'; @@ -11,8 +13,12 @@ class ModelRoot { ModelRoot() { var mainLogger = Logger(); - receiver = Receiver(mainLogger); - sender = Sender(mainLogger); + // Temporary assignment of Android backend. + // In the future we will probably need some mechanism + // to decide which type of backend to assign. + Backend backend = AndroidBackend(); + receiver = Receiver(mainLogger, backend); + sender = Sender(mainLogger, backend); logger = mainLogger; } } diff --git a/lib/src/model/receiver.dart b/lib/src/model/receiver.dart index 71f6fbb..d6e6f5d 100644 --- a/lib/src/model/receiver.dart +++ b/lib/src/model/receiver.dart @@ -3,6 +3,8 @@ import 'dart:collection'; import 'package:logger/logger.dart'; import 'package:mobx/mobx.dart'; +import '../agent/backend.g.dart'; + part 'receiver.g.dart'; /// Implementation of the Model Receiver class. @@ -10,6 +12,7 @@ class Receiver = _Receiver with _$Receiver; abstract class _Receiver with Store { final Logger _logger; + final Backend _backend; // Determines whether the receiver is running or not @observable @@ -40,7 +43,9 @@ abstract class _Receiver with Store { @computed int get repairPort => _repairPort; - _Receiver(Logger logger) : _logger = logger; + _Receiver(Logger logger, Backend backend) + : _logger = logger, + _backend = backend; // Start current receiver. @action @@ -49,6 +54,9 @@ abstract class _Receiver with Store { return; } + // Main backend call + _backend.startReceiver(); + _isStarted = !_isStarted; _logger.i('Receiver started'); } @@ -60,6 +68,9 @@ abstract class _Receiver with Store { return; } + // Main backend call + _backend.stopReceiver(); + _isStarted = !_isStarted; _logger.i('Receiver stopped'); } diff --git a/lib/src/model/sender.dart b/lib/src/model/sender.dart index 97b3aee..8994a95 100644 --- a/lib/src/model/sender.dart +++ b/lib/src/model/sender.dart @@ -1,6 +1,7 @@ import 'package:logger/logger.dart'; import 'package:mobx/mobx.dart'; +import '../agent/backend.g.dart'; import 'capture_source_type.dart'; part 'sender.g.dart'; @@ -10,6 +11,7 @@ class Sender = _Sender with _$Sender; abstract class _Sender with Store { final Logger _logger; + final Backend _backend; // Determines whether the sender is running or not @observable @@ -47,7 +49,9 @@ abstract class _Sender with Store { @computed CaptureSourceType get captureSource => _captureSource; - _Sender(Logger logger) : _logger = logger; + _Sender(Logger logger, Backend backend) + : _logger = logger, + _backend = backend; // Start current sender. @action @@ -56,6 +60,9 @@ abstract class _Sender with Store { return; } + // Main backend call + _backend.startSender(receiverIP); + _isStarted = !_isStarted; _logger.i('Sender started'); } @@ -67,6 +74,9 @@ abstract class _Sender with Store { return; } + // Main backend call + _backend.stopSender(); + _isStarted = !_isStarted; _logger.i('Sender stopped'); } diff --git a/pubspec.lock b/pubspec.lock index 0192f60..a9a289c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,31 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.7.0" ansicolor: dependency: transitive description: name: ansicolor - sha256: "8bf17a8ff6ea17499e40a2d2542c2f481cd7615760c6d34065cb22bfd22e6880" + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" archive: dependency: transitive description: @@ -93,18 +98,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" + sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04 url: "https://pub.dev" source: hosted - version: "2.4.11" + version: "2.4.12" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.3.1" + version: "7.3.2" built_collection: dependency: transitive description: @@ -181,18 +186,18 @@ packages: dependency: transitive description: name: coverage - sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" + sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5 url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" csslib: dependency: transitive description: @@ -213,10 +218,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.3.7" fake_async: dependency: transitive description: @@ -229,10 +234,10 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: @@ -266,18 +271,18 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "4.0.0" flutter_localization: dependency: "direct main" description: name: flutter_localization - sha256: faaeb1eba307473032e2c2af737f36ced61fc98735608410d0a6d9c231b50912 + sha256: "9b3b8825146a3850297a0ec3686b326d618328dca4cd5178b764af9303a26379" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.2.2" flutter_localizations: dependency: transitive description: flutter @@ -401,18 +406,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -425,10 +430,10 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" logger: dependency: "direct main" description: @@ -445,6 +450,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" matcher: dependency: transitive description: @@ -457,26 +470,26 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.6" mobx: dependency: "direct main" description: @@ -557,6 +570,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.2" + pigeon: + dependency: "direct main" + description: + name: pigeon + sha256: f77c57c204c7174e3b95fa7b32a145b1b8ddb51e4619c642f3caf17d7e537275 + url: "https://pub.dev" + source: hosted + version: "22.3.0" platform: dependency: transitive description: @@ -609,58 +630,58 @@ packages: dependency: transitive description: name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.2" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.5.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "034650b71e73629ca08a0bd789fd1d83cc63c2d1e405946f7cef7bc37432f93a" + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shelf: dependency: transitive description: @@ -681,18 +702,18 @@ packages: dependency: transitive description: name: shelf_static - sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -710,10 +731,10 @@ packages: dependency: transitive description: name: source_map_stack_trace - sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" source_maps: dependency: transitive description: @@ -774,26 +795,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e" url: "https://pub.dev" source: hosted - version: "1.25.2" + version: "1.25.7" test_api: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" test_core: dependency: transitive description: name: test_core - sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.4" timing: dependency: transitive description: @@ -830,10 +851,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" watcher: dependency: transitive description: @@ -846,18 +867,26 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.0.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "3.0.1" webkit_inspection_protocol: dependency: transitive description: @@ -891,5 +920,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.4.3 <4.0.0" + dart: ">=3.5.0-259.0.dev <4.0.0" flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index 5677bde..84ecbfe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -9,7 +9,7 @@ environment: dependencies: flutter: sdk: flutter - flutter_localization: ^0.2.0 + flutter_localization: ^0.2.2 intl: ^0.19.0 logger: ^2.4.0 mobx: ^2.3.3+2 @@ -17,11 +17,12 @@ dependencies: darq: ^2.0.0 flutter_native_splash: ^2.4.1 flutter_launcher_icons: ^0.13.1 + pigeon: ^22.3.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^3.0.0 + flutter_lints: ^4.0.0 test: ^1.25.2 build_runner: ^2.4.11 mobx_codegen: ^2.6.1 diff --git a/test/model/receiver_test.dart b/test/model/receiver_test.dart index 984f2e1..1988dde 100644 --- a/test/model/receiver_test.dart +++ b/test/model/receiver_test.dart @@ -1,10 +1,11 @@ import 'package:logger/logger.dart'; +import 'package:roc_droid/src/agent/android_backend.dart'; import 'package:roc_droid/src/model/receiver.dart'; import 'package:test/test.dart'; // Receiver class unit tests. void main() { - Receiver makeReceiver() => Receiver(Logger()); + Receiver makeReceiver() => Receiver(Logger(), AndroidBackend()); test('Check the receivers initial values and getters.', () { final receiver = makeReceiver(); diff --git a/test/model/sender_test.dart b/test/model/sender_test.dart index 5a584aa..9d0fe9a 100644 --- a/test/model/sender_test.dart +++ b/test/model/sender_test.dart @@ -1,11 +1,12 @@ import 'package:logger/logger.dart'; +import 'package:roc_droid/src/agent/android_backend.dart'; import 'package:roc_droid/src/model/capture_source_type.dart'; import 'package:roc_droid/src/model/sender.dart'; import 'package:test/test.dart'; // Receiver class unit tests. void main() { - Sender makeSender() => Sender(Logger()); + Sender makeSender() => Sender(Logger(), AndroidBackend()); test('Check the senders initial values and getters.', () { final sender = makeSender();