notifications pass
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
erinn 2021-06-24 17:59:54 -07:00
parent 537f340504
commit a1e1176e90
6 changed files with 104 additions and 85 deletions

View File

@ -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)

View File

@ -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) {

View File

@ -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++;
}

View File

@ -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) {

View File

@ -63,6 +63,7 @@ class ProfileListState extends ChangeNotifier {
class AppState extends ChangeNotifier {
bool cwtchInit = false;
bool cwtchIsClosing = false;
String appError = "";
String? _selectedProfile;
String? _selectedConversation;

View File

@ -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() {