diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..fdcc671 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/lib/controller/dashboard_controller.dart b/lib/controller/dashboard_controller.dart index 4a94db0..7600a9f 100644 --- a/lib/controller/dashboard_controller.dart +++ b/lib/controller/dashboard_controller.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:get/get.dart'; import 'package:mqtt_flutter_web/controller/mqtt_controller.dart'; @@ -8,34 +9,45 @@ class DashboardController extends GetxController { var passwordController = TextEditingController(); var topicController = TextEditingController(); var messageController = TextEditingController(); + var publishTopicController = TextEditingController(); var brokerConnected = false.obs; + var receivedMessage = ''.obs; + var messageList = [].obs; var mqttController = MQTTController(); - // nO1cANsTOPuS - // "d\$2N@8p&1V#1" - Future connectToBroker() async { - if (brokerConnected.isFalse) { - mqttController.initializeAndConnect( - hostName: "ws://test.smartnode.in/mqtt", - portNumber: 8083, - keepAliveTime: 10, - clientId: clientIdController.text, - username: usernameController.text, - password: passwordController.text, + if (clientIdController.text.isEmpty) { + Fluttertoast.showToast( + msg: 'Client Id should not be empty', + gravity: ToastGravity.CENTER, + textColor: Colors.black, + webPosition: "center", + webBgColor: "#b2dfdb", + timeInSecForIosWeb: 2, ); - brokerConnected.value = await mqttController.onConnected(); } else { - mqttController - .disconnect() - .then((value) => brokerConnected.value = false); + if (brokerConnected.isFalse) { + mqttController.initializeAndConnect( + hostName: "ws://test.smartnode.in/mqtt", + portNumber: 8083, + keepAliveTime: 10, + clientId: clientIdController.text, + username: usernameController.text, + password: passwordController.text, + ); + brokerConnected.value = await mqttController.onConnected(); + } else { + mqttController + .disconnect() + .then((value) => brokerConnected.value = false); + } } } publishMessage() { mqttController.publishMessage( - topic: topicController.text, + topic: publishTopicController.text, publishMessage: messageController.text, ); } @@ -46,5 +58,13 @@ class DashboardController extends GetxController { void unSubscribeToTopic() { mqttController.unSubscribeToMQTT(topic: topicController.text); + topicController.clear(); + } + + void handleMessage(dynamic message) { + // Handle the received message here + debugPrint('Received message in Dashboard: $message'); + // receivedMessage.value = '$topic: $message'; + messageList.add(message); } } diff --git a/lib/controller/mqtt_controller.dart b/lib/controller/mqtt_controller.dart index a4f261a..5b07bb0 100644 --- a/lib/controller/mqtt_controller.dart +++ b/lib/controller/mqtt_controller.dart @@ -1,8 +1,11 @@ +import 'dart:convert'; import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:mqtt_client/mqtt_browser_client.dart'; import 'package:mqtt_client/mqtt_client.dart'; +import 'package:mqtt_flutter_web/controller/dashboard_controller.dart'; class MQTTController { MqttBrowserClient? mqttBrowserClient; @@ -20,8 +23,6 @@ class MQTTController { String? username, String? password, }) async { - debugPrint( - 'clientId: $clientId, username: $username, password: $password, portNumber: $portNumber, host: $hostName, keepAlive: $keepAliveTime'); mqttBrowserClient = MqttBrowserClient( hostName, clientId!, @@ -32,10 +33,6 @@ class MQTTController { mqttBrowserClient!.websocketProtocols = MqttClientConstants.protocolsSingleDefault; - - mqttBrowserClient!.onSubscribed = onSubscribed; - mqttBrowserClient!.onUnsubscribed = onUnSubscribed; - mqttBrowserClient!.onDisconnected = onDisconnected; MqttConnectMessage connMessage = MqttConnectMessage() .withClientIdentifier(clientId) @@ -45,14 +42,13 @@ class MQTTController { mqttBrowserClient!.connectionMessage = connMessage; try { - await mqttBrowserClient!.connect(username, password).then((value) { - var connectionStatus = value!.state; - if (connectionStatus == MqttConnectionState.connected) { - startListeningMessages(); - - mqttBrowserClient!.onConnected = onConnected; - } - }); + await mqttBrowserClient!.connect(username, password); + mqttBrowserClient!.onConnected = onConnected; + mqttBrowserClient!.onSubscribed = onSubscribed; + mqttBrowserClient!.onUnsubscribed = onUnSubscribed; + mqttBrowserClient!.onDisconnected = onDisconnected; + + startListeningMessages(); } catch (e) { debugPrint('EXAMPLE::client exception - $e'); mqttBrowserClient!.disconnect(); @@ -70,6 +66,7 @@ class MQTTController { Future onConnected() async { debugPrint("connected successfully"); + return true; } Future onSubscribed(String topic) async { @@ -95,7 +92,7 @@ class MQTTController { try { mqttBrowserClient!.publishMessage( topic, - MqttQos.exactlyOnce, + MqttQos.atMostOnce, builder.payload!, ); } catch (e) { @@ -107,7 +104,6 @@ class MQTTController { MqttSubscriptionStatus status = mqttBrowserClient!.getSubscriptionsStatus(topic); if (status == MqttSubscriptionStatus.doesNotExist) { - debugPrint("topic :$topic"); mqttBrowserClient!.subscribe(topic, MqttQos.atLeastOnce); } } @@ -128,8 +124,11 @@ class MQTTController { final MqttPublishMessage? recMess = c[0].payload as MqttPublishMessage?; final String receivedMessage = MqttPublishPayload.bytesToStringAsString(recMess!.payload.message); - // _currentState.setReceivedText(recMess.toString()); - debugPrint(receivedMessage); + // Get the YourController instance + DashboardController dashboardController = Get.find(); + // Call the method to handle the message + dynamic object = {"topic": c[0].topic, "message": receivedMessage}; + dashboardController.handleMessage(json.encode(object)); }); } } diff --git a/lib/views/dashboard_screen.dart b/lib/views/dashboard_screen.dart index 4e72e38..86a7ace 100644 --- a/lib/views/dashboard_screen.dart +++ b/lib/views/dashboard_screen.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:get/instance_manager.dart'; -import 'package:get/state_manager.dart'; +import 'package:get/get.dart'; import 'package:mqtt_flutter_web/controller/dashboard_controller.dart'; class DashboardScreen extends StatelessWidget { @@ -16,94 +15,163 @@ class DashboardScreen extends StatelessWidget { Obx(() { debugPrint('brokerConnected: ${controller.brokerConnected.value}'); return ExpansionTile( - title: Row( - children: [ - CircleAvatar( - radius: 10, - backgroundColor: controller.brokerConnected.isTrue - ? Colors.green - : Colors.red, - ), - const SizedBox(width: 10), - Text( - controller.brokerConnected.isTrue - ? 'Connected' - : 'Not connected', - ), - ], + title: ListTile( + leading: CircleAvatar( + radius: 10, + backgroundColor: controller.brokerConnected.isTrue + ? Colors.green + : Colors.red, + ), + title: Text( + controller.brokerConnected.isTrue + ? 'Connected' + : 'Not connected', + ), ), initiallyExpanded: true, children: [ - Form( - child: Column( - children: [ - Row( - children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.all(20.0), - child: TextFormField( - controller: controller.clientIdController, - decoration: const InputDecoration( - labelText: 'Client ID', - ), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(20.0), - child: TextFormField( - controller: controller.usernameController, - decoration: const InputDecoration( - labelText: 'Username', - ), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(20.0), - child: TextFormField( - controller: controller.passwordController, - decoration: const InputDecoration( - labelText: 'Password', - ), - ), - ), - ), - ], - ), - IconButton( - onPressed: () => controller.connectToBroker(), - icon: Icon( - Icons.power_settings_new, - color: controller.brokerConnected.isTrue - ? Colors.red - : Colors.grey, - ), - ), - ], + Row( + children: [ + _customTextField( + labelText: 'Client ID', + textEditingController: controller.clientIdController, + ), + _customTextField( + labelText: 'Username', + textEditingController: controller.usernameController, + ), + _customTextField( + labelText: 'Password', + textEditingController: controller.passwordController, + ), + ], + ), + Padding( + padding: const EdgeInsets.all(20), + child: _customButton( + onPressed: () => controller.connectToBroker(), + buttonText: controller.brokerConnected.isTrue + ? 'Disconnect' + : 'Connect', ), ), ], ); }), - ListTile( - title: Padding( - padding: const EdgeInsets.all(20.0), - child: TextFormField( - controller: controller.topicController, - decoration: const InputDecoration(labelText: 'Topic'), - ), + const SizedBox(height: 20), + SizedBox( + height: 80, + child: Row( + children: [ + _customTextField( + labelText: 'Topic', + textEditingController: controller.topicController, + ), + const SizedBox(width: 50), + _customButton( + onPressed: () => controller.subScribeToTopic(), + buttonText: 'Subscribe', + ), + const SizedBox(width: 100), + _customButton( + onPressed: () => controller.unSubscribeToTopic(), + buttonText: 'Unsubscribe', + ), + const SizedBox(width: 100), + ], + ), + ), + const SizedBox(height: 20), + const Divider(thickness: 1, color: Colors.grey), + SizedBox( + height: 80, + child: Row( + children: [ + _customTextField( + labelText: 'Publish Topic', + textEditingController: controller.publishTopicController, + ), + _customTextField( + labelText: 'Publish Message', + textEditingController: controller.messageController, + ), + const SizedBox(width: 50), + _customButton( + onPressed: () => controller.publishMessage(), + buttonText: 'Publish', + ), + const SizedBox(width: 50), + ], ), - trailing: MaterialButton( - onPressed: () => controller.subScribeToTopic(), - child: const Text('Subscribe'), + ), + const SizedBox(height: 20), + Obx( + () => Container( + width: double.infinity, + height: 100, + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(15)), + border: Border.all(color: Colors.grey), + ), + child: ListView.builder( + itemCount: controller.messageList.length, + itemBuilder: (context, index) { + return Text( + controller.messageList[index].toString(), + style: const TextStyle(fontSize: 16), + ); + }, + ), ), + ), + const SizedBox(height: 10), + _customButton( + onPressed: () => controller.messageList.clear(), + buttonText: 'Clear Messages', ) ], ), ); } + + _customButton({required VoidCallback onPressed, required String buttonText}) { + return MaterialButton( + padding: const EdgeInsets.symmetric( + horizontal: 50, + vertical: 20, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + color: Colors.teal.shade100, + onPressed: onPressed, + child: Text(buttonText), + ); + } + + _customTextField( + {required String labelText, + required TextEditingController textEditingController}) { + return Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + margin: const EdgeInsets.symmetric(horizontal: 5), + decoration: const BoxDecoration( + color: Color.fromARGB(89, 178, 212, 223), + borderRadius: BorderRadius.all(Radius.circular(15)), + ), + child: TextFormField( + controller: textEditingController, + decoration: InputDecoration( + labelText: labelText, + labelStyle: const TextStyle(color: Colors.black), + border: InputBorder.none, // Remove the default border + contentPadding: const EdgeInsets.symmetric(horizontal: 8.0), + ), + ), + ), + ); + } } diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/macos/Flutter/Flutter-Debug.xcconfig index c2efd0b..4b81f9b 100644 --- a/macos/Flutter/Flutter-Debug.xcconfig +++ b/macos/Flutter/Flutter-Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Flutter/Flutter-Release.xcconfig b/macos/Flutter/Flutter-Release.xcconfig index c2efd0b..5caa9d1 100644 --- a/macos/Flutter/Flutter-Release.xcconfig +++ b/macos/Flutter/Flutter-Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" diff --git a/macos/Podfile b/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/pubspec.lock b/pubspec.lock index 6072fa7..d5862ed 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -227,6 +227,19 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "474f7d506230897a3cd28c965ec21c5328ae5605fc9c400cd330e9e9d6ac175c" + url: "https://pub.dev" + source: hosted + version: "8.2.2" frontend_server_client: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3e5cbd3..a58027d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: mqtt_client: ^9.8.0 get: ^4.6.6 build_runner: ^2.4.6 + fluttertoast: ^8.2.2 dev_dependencies: flutter_test: