notifications pass #3
|
@ -61,35 +61,37 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
val evt = MainActivity.AppbusEvent(Cwtch.getAppBusEvent())
|
||||
if (evt.EventType == "NewMessageFromPeer" || evt.EventType == "NewMessageFromGroup") {
|
||||
val data = JSONObject(evt.Data)
|
||||
val channelId =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createMessageNotificationChannel(data.getString("RemotePeer"), data.getString("RemotePeer"))
|
||||
} else {
|
||||
// If earlier version channel ID is not used
|
||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||
""
|
||||
}
|
||||
if (data["RemotePeer"] != data["ProfileOnion"]) {
|
||||
val channelId =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createMessageNotificationChannel(data.getString("RemotePeer"), data.getString("RemotePeer"))
|
||||
} else {
|
||||
// If earlier version channel ID is not used
|
||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||
""
|
||||
}
|
||||
|
||||
val loader = FlutterInjector.instance().flutterLoader()
|
||||
val key = loader.getLookupKeyForAsset("assets/"+data.getString("Picture"))//"assets/profiles/001-centaur.png")
|
||||
val fh = applicationContext.assets.open(key)
|
||||
val loader = FlutterInjector.instance().flutterLoader()
|
||||
val key = loader.getLookupKeyForAsset("assets/" + data.getString("Picture"))//"assets/profiles/001-centaur.png")
|
||||
val fh = applicationContext.assets.open(key)
|
||||
|
||||
val clickIntent = Intent(applicationContext, MainActivity::class.java).also { intent ->
|
||||
intent.action = Intent.ACTION_RUN
|
||||
intent.putExtra("EventType", "NotificationClicked")
|
||||
intent.putExtra("ProfileOnion", data.getString("ProfileOnion"))
|
||||
intent.putExtra("RemotePeer", if (evt.EventType == "NewMessageFromPeer") data.getString("RemotePeer") else data.getString("GroupID"))
|
||||
val clickIntent = Intent(applicationContext, MainActivity::class.java).also { intent ->
|
||||
intent.action = Intent.ACTION_RUN
|
||||
intent.putExtra("EventType", "NotificationClicked")
|
||||
intent.putExtra("ProfileOnion", data.getString("ProfileOnion"))
|
||||
intent.putExtra("RemotePeer", if (evt.EventType == "NewMessageFromPeer") data.getString("RemotePeer") else data.getString("GroupID"))
|
||||
}
|
||||
|
||||
val newNotification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle(data.getString("Nick"))
|
||||
.setContentText("New message")//todo: translate
|
||||
.setLargeIcon(BitmapFactory.decodeStream(fh))
|
||||
.setSmallIcon(R.mipmap.knott)
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
notificationManager.notify(getNotificationID(data.getString("ProfileOnion"), data.getString("RemotePeer")), newNotification)
|
||||
}
|
||||
|
||||
val newNotification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle(data.getString("Nick"))
|
||||
.setContentText("New message")//todo: translate
|
||||
.setLargeIcon(BitmapFactory.decodeStream(fh))
|
||||
.setSmallIcon(R.mipmap.knott)
|
||||
.setContentIntent(PendingIntent.getActivity(applicationContext, 1, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
notificationManager.notify(getNotificationID(data.getString("ProfileOnion"), data.getString("RemotePeer")), newNotification)
|
||||
}
|
||||
|
||||
Intent().also { intent ->
|
||||
|
@ -223,9 +225,10 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
""
|
||||
}
|
||||
|
||||
// This PendingIntent can be used to cancel the worker
|
||||
val intent = WorkManager.getInstance(applicationContext)
|
||||
.createCancelPendingIntent(getId())
|
||||
val cancelIntent = Intent(applicationContext, MainActivity::class.java).also { intent ->
|
||||
intent.action = Intent.ACTION_RUN
|
||||
intent.putExtra("EventType", "ShutdownClicked")
|
||||
}
|
||||
|
||||
val notification = NotificationCompat.Builder(applicationContext, channelId)
|
||||
.setContentTitle(title)
|
||||
|
@ -235,7 +238,7 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) :
|
|||
.setOngoing(true)
|
||||
// Add the cancel action to the notification which can
|
||||
// be used to cancel the worker
|
||||
.addAction(android.R.drawable.ic_delete, cancel, intent)
|
||||
.addAction(android.R.drawable.ic_delete, cancel, PendingIntent.getActivity(applicationContext, 1, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.build()
|
||||
|
||||
return ForegroundInfo(101, notification)
|
||||
|
|
|
@ -36,27 +36,36 @@ class MainActivity: FlutterActivity() {
|
|||
// Channel to send eventbus events on
|
||||
private val CWTCH_EVENTBUS = "test.flutter.dev/eventBus"
|
||||
|
||||
// Channel to trigger contactview when an external notification is clicked
|
||||
// Channels to trigger actions when an external notification is clicked
|
||||
private val CHANNEL_NOTIF_CLICK = "im.cwtch.flwtch/notificationClickHandler"
|
||||
private val CHANNEL_SHUTDOWN_CLICK = "im.cwtch.flwtch/shutdownClickHandler"
|
||||
|
||||
// WorkManager tag applied to all Start() infinite coroutines
|
||||
val WORKER_TAG = "cwtchEventBusWorker"
|
||||
|
||||
private var myReceiver: MyBroadcastReceiver? = null
|
||||
private var methodChan: MethodChannel? = null
|
||||
private var notificationClickChannel: MethodChannel? = null
|
||||
private var shutdownClickChannel: MethodChannel? = null
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
if (methodChan == null || intent.extras == null) return
|
||||
if (!intent.extras!!.containsKey("ProfileOnion") || !intent.extras!!.containsKey("RemotePeer")) {
|
||||
Log.i("onNewIntent", "got intent with no onions")
|
||||
return
|
||||
if (notificationClickChannel == null || intent.extras == null) return
|
||||
|
||||
if (intent.extras!!.getString("EventType") == "NotificationClicked") {
|
||||
if (!intent.extras!!.containsKey("ProfileOnion") || !intent.extras!!.containsKey("RemotePeer")) {
|
||||
Log.i("onNewIntent", "got notification clicked intent with no onions")
|
||||
return
|
||||
}
|
||||
val profile = intent.extras!!.getString("ProfileOnion")
|
||||
val handle = intent.extras!!.getString("RemotePeer")
|
||||
val mappo = mapOf("ProfileOnion" to profile, "RemotePeer" to handle)
|
||||
val j = JSONObject(mappo)
|
||||
notificationClickChannel!!.invokeMethod("NotificationClicked", j.toString())
|
||||
} else if (intent.extras!!.getString("EventType") == "ShutdownClicked") {
|
||||
shutdownClickChannel!!.invokeMethod("ShutdownClicked", "")
|
||||
} else {
|
||||
print("warning: received intent with unknown method; ignoring")
|
||||
}
|
||||
val profile = intent.extras!!.getString("ProfileOnion")
|
||||
val handle = intent.extras!!.getString("RemotePeer")
|
||||
val mappo = mapOf("ProfileOnion" to profile, "RemotePeer" to handle)
|
||||
val j = JSONObject(mappo)
|
||||
methodChan!!.invokeMethod("NotificationClicked", j.toString())
|
||||
}
|
||||
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
|
@ -66,7 +75,8 @@ class MainActivity: FlutterActivity() {
|
|||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_APP_INFO).setMethodCallHandler { call, result -> handleAppInfo(call, result) }
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_CWTCH).setMethodCallHandler { call, result -> handleCwtch(call, result) }
|
||||
methodChan = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NOTIF_CLICK)
|
||||
notificationClickChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_NOTIF_CLICK)
|
||||
shutdownClickChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL_SHUTDOWN_CLICK)
|
||||
}
|
||||
|
||||
private fun handleAppInfo(@NonNull call: MethodCall, @NonNull result: Result) {
|
||||
|
|
|
@ -124,7 +124,7 @@ class CwtchNotifier {
|
|||
break;
|
||||
case "NewMessageFromGroup":
|
||||
if (data["ProfileOnion"] != data["RemotePeer"]) {
|
||||
//not from me
|
||||
//if not currently open
|
||||
if (appState.selectedProfile != data["ProfileOnion"] || appState.selectedConversation != data["GroupID"]) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"])!.unreadMessages++;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
late Cwtch cwtch;
|
||||
late ProfileListState profs;
|
||||
final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler');
|
||||
final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdown');
|
||||
final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler');
|
||||
final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
|
||||
|
||||
@override
|
||||
|
@ -58,7 +58,7 @@ class FlwtchState extends State<Flwtch> {
|
|||
print("initState: registering notification, shutdown handlers...");
|
||||
profs = ProfileListState();
|
||||
notificationClickChannel.setMethodCallHandler(_externalNotificationClicked);
|
||||
shutdownMethodChannel.setMethodCallHandler(shutdown);
|
||||
shutdownMethodChannel.setMethodCallHandler(modalShutdown);
|
||||
print("initState: creating cwtchnotifier, ffi");
|
||||
if (Platform.isAndroid) {
|
||||
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
||||
|
@ -111,7 +111,45 @@ class FlwtchState extends State<Flwtch> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> shutdown(MethodCall call) async {
|
||||
// invoked from either ProfileManagerView's appbar close button, or a ShutdownClicked event on
|
||||
// the MyBroadcastReceiver method channel
|
||||
Future<void> modalShutdown(MethodCall mc) async {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text(AppLocalizations.of(navKey.currentContext!)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(navKey.currentContext!).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
Widget continueButton = TextButton(
|
||||
child: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchAction),
|
||||
onPressed: () {
|
||||
// Directly call the shutdown command, Android will do this for us...
|
||||
Provider.of<FlwtchState>(navKey.currentContext!, listen: false).shutdown();
|
||||
Provider.of<AppState>(navKey.currentContext!, listen: false).cwtchIsClosing = true;
|
||||
});
|
||||
|
||||
// set up the AlertDialog
|
||||
AlertDialog alert = AlertDialog(
|
||||
title: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchDialogTitle),
|
||||
content: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchDialog),
|
||||
actions: [
|
||||
cancelButton,
|
||||
continueButton,
|
||||
],
|
||||
);
|
||||
|
||||
// show the dialog
|
||||
showDialog(
|
||||
context: navKey.currentContext!,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shutdown() async {
|
||||
cwtch.Shutdown();
|
||||
// Wait a few seconds as shutting down things takes a little time..
|
||||
Future.delayed(Duration(seconds: 2)).then((value) {
|
||||
|
|
|
@ -63,6 +63,7 @@ class ProfileListState extends ChangeNotifier {
|
|||
|
||||
class AppState extends ChangeNotifier {
|
||||
bool cwtchInit = false;
|
||||
bool cwtchIsClosing = false;
|
||||
String appError = "";
|
||||
String? _selectedProfile;
|
||||
String? _selectedConversation;
|
||||
|
|
|
@ -28,8 +28,6 @@ class ProfileMgrView extends StatefulWidget {
|
|||
class _ProfileMgrViewState extends State<ProfileMgrView> {
|
||||
final ctrlrPassword = TextEditingController();
|
||||
|
||||
bool closeApp = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
ctrlrPassword.dispose();
|
||||
|
@ -45,8 +43,8 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
builder: (context, settings, child) =>
|
||||
WillPopScope(
|
||||
onWillPop: () async {
|
||||
_showShutdown();
|
||||
return closeApp;
|
||||
_modalShutdown();
|
||||
return Provider.of<AppState>(context, listen: false).cwtchIsClosing;
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: settings.theme.backgroundMainColor(),
|
||||
|
@ -108,45 +106,14 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
|
|||
// Global Settings
|
||||
actions.add(IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings));
|
||||
|
||||
actions.add(IconButton(icon: Icon(Icons.close), tooltip: AppLocalizations.of(context)!.shutdownCwtchTooltip, onPressed: _showShutdown));
|
||||
// shutdown cwtch
|
||||
actions.add(IconButton(icon: Icon(Icons.close), tooltip: AppLocalizations.of(context)!.shutdownCwtchTooltip, onPressed: _modalShutdown));
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
_showShutdown() {
|
||||
// set up the buttons
|
||||
Widget cancelButton = TextButton(
|
||||
child: Text(AppLocalizations.of(context)!.cancel),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(); // dismiss dialog
|
||||
},
|
||||
);
|
||||
Widget continueButton = TextButton(
|
||||
child: Text(AppLocalizations.of(context)!.shutdownCwtchAction),
|
||||
onPressed: () {
|
||||
// Directly call the shutdown command, Android will do this for us...
|
||||
Provider.of<FlwtchState>(context, listen: false).shutdown(MethodCall(""));
|
||||
closeApp = true;
|
||||
});
|
||||
|
||||
// set up the AlertDialog
|
||||
AlertDialog alert = AlertDialog(
|
||||
title: Text(AppLocalizations.of(context)!.shutdownCwtchDialogTitle),
|
||||
content: Text(AppLocalizations.of(context)!.shutdownCwtchDialog),
|
||||
actions: [
|
||||
cancelButton,
|
||||
continueButton,
|
||||
],
|
||||
);
|
||||
|
||||
// show the dialog
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return alert;
|
||||
},
|
||||
);
|
||||
void _modalShutdown() {
|
||||
Provider.of<FlwtchState>(context, listen: false).modalShutdown(MethodCall(""));
|
||||
}
|
||||
|
||||
void _pushGlobalSettings() {
|
||||
|
|
Loading…
Reference in New Issue