diff --git a/android/app/build.gradle b/android/app/build.gradle index e048597..47e1108 100755 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -18,7 +18,7 @@ def keystorePropertiesFile = rootProject.file("key.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { - compileSdkVersion 28 + compileSdkVersion 29 lintOptions { disable 'InvalidPackage' @@ -27,7 +27,7 @@ android { defaultConfig { applicationId "team.whatever.sms_forwarder_app" minSdkVersion 21 - targetSdkVersion 28 + targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 5c0a9a7..825e3ee 100755 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -39,5 +39,12 @@ + + + + + + diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index ad749ea..2e49317 100755 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -5,10 +5,8 @@ export "FLUTTER_APPLICATION_PATH=/home/george/projects/sms_forwarder_app" export "FLUTTER_TARGET=lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build/ios" -export "OTHER_LDFLAGS=$(inherited) -framework Flutter" -export "FLUTTER_FRAMEWORK_DIR=/opt/flutter/bin/cache/artifacts/engine/ios" -export "FLUTTER_BUILD_NAME=1.0.0" -export "FLUTTER_BUILD_NUMBER=1" +export "FLUTTER_BUILD_NAME=1.4.0" +export "FLUTTER_BUILD_NUMBER=1.4.0" export "DART_OBFUSCATION=false" export "TRACK_WIDGET_CREATION=false" export "TREE_SHAKE_ICONS=false" diff --git a/lib/background_forwarder.dart b/lib/background_forwarder.dart new file mode 100644 index 0000000..abd2b1d --- /dev/null +++ b/lib/background_forwarder.dart @@ -0,0 +1,67 @@ +import 'package:telephony/telephony.dart'; + +import 'forwarding.dart'; +import 'manager.dart'; + +/// A wrapper for [ForwarderManager] that registers a background message handler. +/// Resets the background forwarder every time a field is updated. +class BackgroundForwarder { + static ForwarderManager _backgroundManager; + final ForwarderManager mgr = new ForwarderManager(); + + BackgroundForwarder(Telephony telephony) { + telephony.listenIncomingSms( + onNewMessage: (msg) async => await mgr.forward(msg), + onBackgroundMessage: onBackgroundMessage + ); + } + + static void onBackgroundMessage(SmsMessage msg) async { + if (_backgroundManager == null) { + _backgroundManager = new ForwarderManager(); + await _backgroundManager.loadFromPrefs(); + } + await _backgroundManager.forward(msg); + } + + HttpCallbackForwarder get httpCallbackForwarder => mgr.httpCallbackForwarder; + + TelegramBotForwarder get telegramBotForwarder => mgr.telegramBotForwarder; + + DeployedTelegramBotForwarder get deployedTelegramBotForwarder => + mgr.deployedTelegramBotForwarder; + + set httpCallbackForwarder(HttpCallbackForwarder fwd) { + mgr.httpCallbackForwarder = fwd; + invalidateBackgroundManager(); + } + + set telegramBotForwarder(TelegramBotForwarder fwd) { + mgr.telegramBotForwarder = fwd; + invalidateBackgroundManager(); + } + + set deployedTelegramBotForwarder(DeployedTelegramBotForwarder fwd) { + mgr.deployedTelegramBotForwarder = fwd; + invalidateBackgroundManager(); + } + + /// Loads the forwarders from a json. + Future loadFromPrefs() async { + var result = await mgr.loadFromPrefs(); + return result; + } + + /// Dumps the forwarders to shared preferences. + void dumpToPrefs() async => mgr.dumpToPrefs(); + + /// Returns the mapping (forwarder name -> not null) + Map reportReadiness() { + return mgr.reportReadiness(); + } + + /// Sets the background manager to `null`. + static void invalidateBackgroundManager() { + _backgroundManager = null; + } +} diff --git a/lib/forwarding.dart b/lib/forwarding.dart index 81d0d00..3943281 100755 --- a/lib/forwarding.dart +++ b/lib/forwarding.dart @@ -3,9 +3,28 @@ import 'dart:core'; import 'dart:convert'; import 'package:http/http.dart' as http; -import 'package:sms_maintained/sms.dart'; +import 'package:telephony/telephony.dart'; import 'package:flutter/foundation.dart'; +extension ToMap on SmsMessage { + Map get toMap { + return { + "id": this.id, + "address": this.address, + "body": this.body, + "date": this.date, + "dateSent": this.dateSent, + "read": this.read, + "seen": this.seen, + "subject": this.subject, + "subscriptionId": this.subscriptionId, + "threadId": this.threadId, + "type": this.type, + "status": this.status, + }; + } +} + /// Defines the forwarder interface. abstract class AbstractForwarder { /// Should forward the given sms. @@ -60,9 +79,9 @@ abstract class HttpForwarder implements AbstractForwarder { static String mapToJson(Map map) => json.encode(_castMap(map)); /// Casts all keys and values in the map to String. Removes the entry with - /// the key thread_id. + /// the key threadId. static Map _castMap(Map map) { - map.remove('thread_id'); + map.remove('threadId'); return Map.from(map.map( // Cast each field to string (k, v) => MapEntry(k.toString(), v.toString()))); @@ -176,20 +195,20 @@ class HttpCallbackForwarder extends AbstractForwarder with HttpForwarder { switch (method) { case HttpMethod.GET: // Convert the sms to JSON and merge it with the uri payload - var smsData = sms.toMap; + final smsData = sms.toMap; smsData.addAll(uriPayload); // Then URI encode the map and perform the request - String uriParams = HttpForwarder.mapToUri(smsData); + final uriParams = HttpForwarder.mapToUri(smsData); return http.get("$_callbackUrl$uriParams"); case HttpMethod.POST: case HttpMethod.PUT: // Convert the sms to json and merge it with the json payload - var payload = sms.toMap; + final payload = sms.toMap; payload.addAll(jsonPayload); // URI encode the uri payload and append it to the url - var uriParams = HttpForwarder.mapToUri(uriPayload); - var url = "$_callbackUrl$uriParams"; + final uriParams = HttpForwarder.mapToUri(uriPayload); + final url = "$_callbackUrl$uriParams"; // Perform the request using the required method return method == HttpMethod.POST ? http.post(url, body: HttpForwarder.mapToJson(payload)) @@ -240,13 +259,14 @@ class TelegramBotForwarder extends AbstractForwarder with HttpForwarder { /// Sends the SMS data to the user with [_chatId]. @override Future send(SmsMessage sms) { + final date = DateTime.fromMillisecondsSinceEpoch(sms.date); // Encode message String uriParams = HttpForwarder.mapToUri({ "chat_id": _chatId, "text": "New SMS message from ${sms.address}:\n${sms.body}\n\n" - "Date: ${sms.date}." + "Date: $date." }); - String url = this.method("sendMessage"); + final url = this.method("sendMessage"); return http.post("$url$uriParams"); } @@ -305,8 +325,8 @@ class DeployedTelegramBotForwarder extends HttpCallbackForwarder { /// Checks if the user with [_tgHandle] exists on the server. Future checkSetupURL() async { - var params = {"username": _tgHandle, "code": _tgCode}; - var r = + final params = {"username": _tgHandle, "code": _tgCode}; + final r = await http.get("$_baseUrl/check_user${HttpForwarder.mapToUri(params)}"); _isSetUp = r?.statusCode == 200; return Future(() => isSetUp); @@ -314,9 +334,9 @@ class DeployedTelegramBotForwarder extends HttpCallbackForwarder { /// Sends the SMS data to the server via a POST request. Future send(SmsMessage sms) { - var map = sms.toMap; - map['date'] = - sms.date.toString(); // the date field is in milliseconds by default + final map = sms.toMap; + final date = DateTime.fromMillisecondsSinceEpoch(sms.date); + map['date'] = date.toString(); String payload = HttpForwarder.mapToJson(map); String url = "$_callbackUrl?code=$_tgCode&username=$_tgHandle"; return http.post(url, body: payload); @@ -324,7 +344,7 @@ class DeployedTelegramBotForwarder extends HttpCallbackForwarder { /// Generates a random 8-character code. String _genCode() { - var rand = Random(); + final rand = Random(); return String.fromCharCodes( new List.generate(8, (_) => rand.nextInt(26) + 65)); } @@ -332,7 +352,7 @@ class DeployedTelegramBotForwarder extends HttpCallbackForwarder { /// Dumps the forwarder's settings to json. @override String toJson() { - var fields = { + final fields = { "tgCode": _tgCode, "baseUrl": _baseUrl, "tgHandle": _tgHandle, diff --git a/lib/KeyValueSettings.dart b/lib/key_value_settings.dart similarity index 99% rename from lib/KeyValueSettings.dart rename to lib/key_value_settings.dart index 286d11d..6ee8210 100644 --- a/lib/KeyValueSettings.dart +++ b/lib/key_value_settings.dart @@ -197,7 +197,6 @@ class _KeyValuePairWidgetState extends State<_KeyValuePairWidget> { @override Widget build(BuildContext context) { - var pairs = _parentState.pairs; return Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 125, diff --git a/lib/main.dart b/lib/main.dart index 3da2fd4..9591fc9 100755 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,25 +1,21 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:sms_forwarder/observer.dart'; +import 'package:telephony/telephony.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:sms_maintained/sms.dart'; import 'forwarding.dart'; -import 'KeyValueSettings.dart'; +import 'key_value_settings.dart'; +import 'background_forwarder.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); - runApp(new MyApp(SmsReceiver(), ForwarderObserver())); + runApp(new MyApp(new BackgroundForwarder(Telephony.instance))); } class MyApp extends StatelessWidget { - final SmsReceiver receiver; - final ForwarderObserver obs; + final BackgroundForwarder fwd; - MyApp(this.receiver, this.obs) { - // Set up the sms listener - receiver.onSmsReceived.listen(obs.forward); - } + MyApp(this.fwd); @override Widget build(BuildContext context) { @@ -28,25 +24,28 @@ class MyApp extends StatelessWidget { theme: new ThemeData( primarySwatch: Colors.green, ), - home: new HomePage(title: 'SMS Forwarder (v1.3.0)', obs: this.obs), + home: new HomePage(title: 'SMS Forwarder (v1.4.0)', fwd: this.fwd), ); } } class HomePage extends StatefulWidget { - HomePage({Key key, this.title, this.obs}) : super(key: key); + HomePage({Key key, this.title, this.fwd}) : super(key: key); final String title; - final ForwarderObserver obs; + final BackgroundForwarder fwd; @override _HomePageState createState() => new _HomePageState(); } class _HomePageState extends State { - ColorSwatch _deployedBotBtnState = Colors.yellow; - ColorSwatch _tgBotBtnState = Colors.yellow; - ColorSwatch _callbackBtnState = Colors.yellow; + static final Color _greenColor = Colors.green[500]; + static final Color _yellowColor = Colors.yellow[500]; + + Color _deployedBotBtnState = _yellowColor; + Color _tgBotBtnState = _yellowColor; + Color _callbackBtnState = _yellowColor; @override void initState() { @@ -58,23 +57,29 @@ class _HomePageState extends State { /// Loads forwarders' settings and updates the buttons. void _loadForwarders() async { - var map = await widget.obs.loadFromPrefs(); + var map = await widget.fwd.loadFromPrefs(); setState(() => _setForwardersColors(map)); } void _setForwardersColors(Map map) { setState(() { - _deployedBotBtnState = map['DeployedTelegramBotForwarder'] - ? Colors.lightGreenAccent - : Colors.yellow; - _tgBotBtnState = - map['TelegramBotForwarder'] ? Colors.lightGreenAccent : Colors.yellow; - _callbackBtnState = map['HttpCallbackForwarder'] - ? Colors.lightGreenAccent - : Colors.yellow; + _deployedBotBtnState = + map['DeployedTelegramBotForwarder'] ? _greenColor : _yellowColor; + _tgBotBtnState = map['TelegramBotForwarder'] ? _greenColor : _yellowColor; + _callbackBtnState = + map['HttpCallbackForwarder'] ? _greenColor : _yellowColor; }); } + ButtonStyle _forwarderButtonStyle(Color color) { + return TextButton.styleFrom( + primary: Colors.black, + backgroundColor: color, + padding: EdgeInsets.all(12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(1)))); + } + @override Widget build(BuildContext context) { return new Scaffold( @@ -89,15 +94,15 @@ class _HomePageState extends State { new ButtonTheme( minWidth: 320, height: 50, - child: new FlatButton( + child: new TextButton( onPressed: () => Navigator.push( context, MaterialPageRoute( builder: (context) => ForwarderScreen( - obs: widget.obs))).then( - (_) => _setForwardersColors(widget.obs.reportReadiness())), - color: _deployedBotBtnState, + fwd: widget.fwd))).then( + (_) => _setForwardersColors(widget.fwd.reportReadiness())), + style: _forwarderButtonStyle(_deployedBotBtnState), child: Text( "Deployed Telegram Bot Forwarder", style: new TextStyle(fontSize: 20), @@ -109,15 +114,15 @@ class _HomePageState extends State { new ButtonTheme( minWidth: 320, height: 50, - child: new FlatButton( + child: new TextButton( onPressed: () => Navigator.push( context, MaterialPageRoute( builder: (context) => ForwarderScreen( - obs: widget.obs))).then( - (_) => _setForwardersColors(widget.obs.reportReadiness())), - color: _tgBotBtnState, + fwd: widget.fwd))).then( + (_) => _setForwardersColors(widget.fwd.reportReadiness())), + style: _forwarderButtonStyle(_tgBotBtnState), child: Text( "Your Telegram Bot Forwarder", style: new TextStyle(fontSize: 20), @@ -129,15 +134,15 @@ class _HomePageState extends State { new ButtonTheme( minWidth: 320, height: 50, - child: new FlatButton( + child: new TextButton( onPressed: () => Navigator.push( context, MaterialPageRoute( builder: (context) => ForwarderScreen( - obs: widget.obs))).then( - (_) => _setForwardersColors(widget.obs.reportReadiness())), - color: _callbackBtnState, + fwd: widget.fwd))).then( + (_) => _setForwardersColors(widget.fwd.reportReadiness())), + style: _forwarderButtonStyle(_callbackBtnState), child: Text( "HTTP Callback Forwarder", style: new TextStyle(fontSize: 20), @@ -152,9 +157,9 @@ class _HomePageState extends State { } class ForwarderScreen extends StatefulWidget { - const ForwarderScreen({Key key, this.obs}) : super(key: key); + const ForwarderScreen({Key key, this.fwd}) : super(key: key); - final ForwarderObserver obs; + final BackgroundForwarder fwd; /// Returns the state for the provided forwarder. static _ForwarderScreenState @@ -194,11 +199,11 @@ abstract class _ForwarderScreenState title: Text("You're about to reset the settings"), content: Text("Are you sure?"), actions: [ - FlatButton( + TextButton( child: Text("No, I'd like to keep the existing settings"), onPressed: () => Navigator.of(context).pop(), ), - FlatButton( + TextButton( child: Text("Yes", style: TextStyle(color: Colors.redAccent)), onPressed: () { _resetSettings(); @@ -245,7 +250,7 @@ class _HttpCallbackForwarderState @override void initState() { super.initState(); - final fwd = widget.obs?.httpCallbackForwarder; + final fwd = widget.fwd?.httpCallbackForwarder; _controller = TextEditingController(text: fwd?.callbackUrl); _method = fwd?.method ?? HttpMethod.POST; _uriParams = Map.from(fwd?.uriPayload ?? {}); @@ -318,28 +323,28 @@ class _HttpCallbackForwarderState ]), Padding(padding: EdgeInsets.symmetric(vertical: 5)), Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - RaisedButton( + ElevatedButton( child: Text('URI Params'), onPressed: () => showDialog( context: context, - child: KeyValuePairSettingsScreen( + builder: (_) => KeyValuePairSettingsScreen( "URI Params", _uriParams))), Padding(padding: EdgeInsets.symmetric(horizontal: 5)), - RaisedButton( + ElevatedButton( child: Text('JSON Payload'), onPressed: () => showDialog( context: context, - child: KeyValuePairSettingsScreen( + builder: (_) => KeyValuePairSettingsScreen( "JSON Payload", _jsonParams))) ]), Padding(padding: EdgeInsets.symmetric(vertical: 2)), - RaisedButton( + ElevatedButton( child: Text('Save'), onPressed: !_checkValidUrl(_controller.text) ? null : () { _saveSettings(); - Scaffold.of(context).showSnackBar(new SnackBar( + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( content: new Text("Saved"), )); }), @@ -349,7 +354,7 @@ class _HttpCallbackForwarderState floatingActionButton: FloatingActionButton( onPressed: () => _showResetDialogAndUpdate(() { _controller.text = - widget.obs.httpCallbackForwarder?.callbackUrl ?? ""; + widget.fwd.httpCallbackForwarder?.callbackUrl ?? ""; }), tooltip: "Reset Settings", child: Icon(Icons.clear), @@ -359,19 +364,19 @@ class _HttpCallbackForwarderState /// Updates the settings of the forwarder and dumps all forwarders to disk. @override - void _saveSettings() { - widget?.obs?.httpCallbackForwarder = HttpCallbackForwarder(_controller.text, + void _saveSettings() async { + widget?.fwd?.httpCallbackForwarder = HttpCallbackForwarder(_controller.text, method: _method, uriPayload: _uriParams, jsonPayload: _jsonParams); - widget?.obs?.dumpToPrefs(); + widget?.fwd?.dumpToPrefs(); } /// Removes the forwarder and dumps the rest of the forwarders to disk. @override - void _resetSettings() { + void _resetSettings() async { _uriParams.clear(); _jsonParams.clear(); - widget?.obs?.httpCallbackForwarder = null; - widget?.obs?.dumpToPrefs(); + widget?.fwd?.httpCallbackForwarder = null; + widget?.fwd?.dumpToPrefs(); } } @@ -402,9 +407,9 @@ class _TelegramBotForwarderScreen void initState() { super.initState(); _tokenController = TextEditingController( - text: widget.obs?.telegramBotForwarder?.token ?? ""); + text: widget.fwd?.telegramBotForwarder?.token ?? ""); _chatIdController = TextEditingController( - text: widget.obs?.telegramBotForwarder?.chatId?.toString() ?? ""); + text: widget.fwd?.telegramBotForwarder?.chatId?.toString() ?? ""); _tokenController.addListener(_onTokenTextChanged); _chatIdController.addListener(_onChatIdTextChanged); @@ -473,13 +478,13 @@ class _TelegramBotForwarderScreen controller: _tokenController, ), ), - RaisedButton( + ElevatedButton( child: Text('Save'), onPressed: !_checkAllIsValid() ? null : () { _saveSettings(); - Scaffold.of(context).showSnackBar(new SnackBar( + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( content: new Text("Saved"), )); }), @@ -488,9 +493,9 @@ class _TelegramBotForwarderScreen }), floatingActionButton: FloatingActionButton( onPressed: () => _showResetDialogAndUpdate(() { - _tokenController.text = widget.obs?.telegramBotForwarder?.token ?? ""; + _tokenController.text = widget.fwd?.telegramBotForwarder?.token ?? ""; _chatIdController.text = - widget.obs?.telegramBotForwarder?.chatId?.toString() ?? ""; + widget.fwd?.telegramBotForwarder?.chatId?.toString() ?? ""; }), tooltip: "Reset settings", child: Icon(Icons.clear), @@ -500,17 +505,17 @@ class _TelegramBotForwarderScreen /// Updates the settings of the forwarder and dumps all forwarders to disk @override - void _saveSettings() { - widget?.obs?.telegramBotForwarder = TelegramBotForwarder( + void _saveSettings() async { + widget?.fwd?.telegramBotForwarder = TelegramBotForwarder( _tokenController.text, int.tryParse(_chatIdController.text)); - widget?.obs?.dumpToPrefs(); + widget?.fwd?.dumpToPrefs(); } /// Sets the values of the forwarder to null @override - void _resetSettings() { - widget?.obs?.telegramBotForwarder = null; - widget?.obs?.dumpToPrefs(); + void _resetSettings() async { + widget?.fwd?.telegramBotForwarder = null; + widget?.fwd?.dumpToPrefs(); } } @@ -551,12 +556,12 @@ class _DeployedTelegramBotForwarderScreen void initState() { super.initState(); _tgHandleController = TextEditingController( - text: widget.obs?.deployedTelegramBotForwarder?.tgHandle ?? ""); + text: widget.fwd?.deployedTelegramBotForwarder?.tgHandle ?? ""); _baseUrlController = TextEditingController( - text: widget.obs?.deployedTelegramBotForwarder?.baseUrl ?? + text: widget.fwd?.deployedTelegramBotForwarder?.baseUrl ?? "https://forwarder.whatever.team"); _botHandleController = TextEditingController( - text: widget.obs?.deployedTelegramBotForwarder?.botHandle ?? + text: widget.fwd?.deployedTelegramBotForwarder?.botHandle ?? "smsforwarderrobot"); _tgHandleController.addListener(_onTgHandleTextChanged); _baseUrlController.addListener(_onBaseUrlTextChanged); @@ -668,13 +673,13 @@ class _DeployedTelegramBotForwarderScreen controller: _botHandleController, ), ), - RaisedButton( + ElevatedButton( child: Text('Save'), onPressed: !_checkAllIsValid() ? null : () { _saveSettings(); - Scaffold.of(context).showSnackBar(new SnackBar( + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( content: new Text("Saved"), )); _openTelegramUrlInBrowser(); @@ -685,9 +690,9 @@ class _DeployedTelegramBotForwarderScreen floatingActionButton: FloatingActionButton( onPressed: () => _showResetDialogAndUpdate(() { _tgHandleController.text = - widget.obs.deployedTelegramBotForwarder?.tgHandle ?? ""; + widget.fwd.deployedTelegramBotForwarder?.tgHandle ?? ""; _baseUrlController.text = - widget.obs.deployedTelegramBotForwarder?.baseUrl ?? ""; + widget.fwd.deployedTelegramBotForwarder?.baseUrl ?? ""; }), tooltip: "Reset Settings", child: Icon(Icons.clear), @@ -696,7 +701,7 @@ class _DeployedTelegramBotForwarderScreen } void _openTelegramUrlInBrowser() async { - String url = widget.obs?.deployedTelegramBotForwarder?.getUrl(); + String url = widget.fwd?.deployedTelegramBotForwarder?.getUrl(); bool _canLaunch = await canLaunch(url); showDialog( context: context, @@ -705,7 +710,7 @@ class _DeployedTelegramBotForwarderScreen title: Text("Open the link in the browser or copy to the clipboard:"), content: Text(url), actions: [ - FlatButton( + TextButton( child: Text("Open in Browser"), onPressed: _canLaunch ? () { @@ -713,7 +718,7 @@ class _DeployedTelegramBotForwarderScreen Navigator.of(context).pop(); } : null), - FlatButton( + TextButton( child: Text("Copy", style: TextStyle(color: Colors.green)), onPressed: () { Clipboard.setData(new ClipboardData(text: url)); @@ -728,19 +733,19 @@ class _DeployedTelegramBotForwarderScreen /// Updates the settings of the forwarder and dumps all forwarders to disk @override - void _saveSettings() { - widget?.obs?.deployedTelegramBotForwarder = DeployedTelegramBotForwarder( + void _saveSettings() async { + widget?.fwd?.deployedTelegramBotForwarder = DeployedTelegramBotForwarder( _tgHandleController.text, baseUrl: _baseUrlController.text, botHandle: _botHandleController.text, ); - widget?.obs?.dumpToPrefs(); + widget?.fwd?.dumpToPrefs(); } /// Sets the value of the forwarder to null @override - void _resetSettings() { - widget?.obs?.deployedTelegramBotForwarder = null; - widget?.obs?.dumpToPrefs(); + void _resetSettings() async { + widget?.fwd?.deployedTelegramBotForwarder = null; + widget?.fwd?.dumpToPrefs(); } } diff --git a/lib/observer.dart b/lib/manager.dart similarity index 89% rename from lib/observer.dart rename to lib/manager.dart index ce0876d..8fdf328 100755 --- a/lib/observer.dart +++ b/lib/manager.dart @@ -1,13 +1,13 @@ import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:sms_maintained/sms.dart'; +import 'package:telephony/telephony.dart'; import 'forwarding.dart'; import 'dart:core'; import 'package:flutter/foundation.dart'; -class ForwarderObserver { +class ForwarderManager { // Supported forwarders HttpCallbackForwarder httpCallbackForwarder; TelegramBotForwarder telegramBotForwarder; @@ -54,12 +54,30 @@ class ForwarderObserver { Future loadFromPrefs() async { final prefs = await SharedPreferences.getInstance(); String jsonString = prefs.getString("forwarders") ?? "{}"; + loadFromJson(jsonString); + return Future(() => reportReadiness()); + } + + /// Loads the forwarders from a json. + Map loadFromJson(String jsonString) { var map = json.decode(jsonString); httpCallbackForwarder = _tryLoad(() => HttpCallbackForwarder.fromJson(map)); telegramBotForwarder = _tryLoad(() => TelegramBotForwarder.fromJson(map)); deployedTelegramBotForwarder = _tryLoad(() => DeployedTelegramBotForwarder.fromJson(map)); - return Future(() => reportReadiness()); + return reportReadiness(); + } + + /// Dumps the forwarder settings to json. + String dumpToJson() { + List serialized = []; + for (var fwd in asList()) { + if (fwd == null) continue; + String json = fwd.toJson(); + // Remove the trailing '{' and '}' + serialized.add(json.substring(1, json.length - 1)); + } + return "{${serialized.join(', ')}}"; } /// Attempts to load a forwarder of type [T] using the provided closure [fromJson]. @@ -74,14 +92,7 @@ class ForwarderObserver { /// Dumps the forwarders to shared preferences. void dumpToPrefs() async { final prefs = await SharedPreferences.getInstance(); - List serialized = []; - for (var fwd in asList()) { - if (fwd == null) continue; - String json = fwd.toJson(); - // Remove the trailing '{' and '}' - serialized.add(json.substring(1, json.length - 1)); - } - var jsonStr = "{${serialized.join(', ')}}"; + var jsonStr = dumpToJson(); prefs.setString("forwarders", jsonStr); } } diff --git a/pubspec.yaml b/pubspec.yaml index 568571e..734d403 100755 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,15 @@ name: sms_forwarder description: An SMS forwarding application. -version: 1.3.0 +version: 1.4.0 + +environment: + sdk: '>=2.10.0 <3.0.0' dependencies: flutter: sdk: flutter - sms_maintained: ^0.2.5 + telephony: ^0.1.0 http: ^0.12.0 shared_preferences: ^0.4.3 url_launcher: ^4.0.1