~whereswaldon/niotify

6f7f0970e57c20df2f35c65ae8006d0278361f72 — Chris Waldon a month ago 313361d main
chore: redirect users to x repo

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
21 files changed, 1 insertions(+), 1201 deletions(-)

D LICENSE
M README.md
D android/NotificationHelper.jar
D android/NotificationHelper.java
D android/notify_android.go
D cmd/png2bmp/main.go
D example/example.app/Contents/Info.plist
D example/example.app/Contents/PkgInfo
D example/example.app/Contents/_CodeSignature/CodeResources
D example/hello.go
D example/hello_macos.go
D go.mod
D go.sum
D macos/niotify_test.go
D macos/notify_macos.go
D niotify_android.go
D niotify_darwin.go
D niotify_dbus.go
D niotify_unsupported.go
D notification_manager.go
D tools.go
D LICENSE => LICENSE +0 -63
@@ 1,63 0,0 @@
This project is dual-licensed under the UNLICENSE or
the MIT license with the SPDX identifier:

SPDX-License-Identifier: Unlicense OR MIT

You may use the project under the terms of either license.

Both licenses are reproduced below.

----
The MIT License (MIT)

Copyright (c) 2019 The niotify authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---



---
The UNLICENSE

This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <https://unlicense.org/>
---

M README.md => README.md +1 -51
@@ 1,51 1,1 @@
## niotify

[![GoDoc](https://godoc.org/git.sr.ht/~whereswaldon/niotify?status.svg)](https://godoc.org/git.sr.ht/~whereswaldon/niotify)

Cross platform notifications for [Gio](https://gioui.org) applications.

## Status

This repo is experimental, and does not have a stable interface. Currently niotify
only supports the following OSes:

- linux (x11/wayland doesn't matter so long as dbus is used for notifications)
- android
- macOS (support is preliminary; some code-signing-related issues)
- iOS (support is preliminary; some code-signing-related issues)

Contributions of support for other platforms are welcome! Send inquiries and patches
to [my public inbox](https://lists.sr.ht/~whereswaldon/public-inbox) for now.

### macOS/iOS Support

We've had mixed success with this platform, as sending notifications requires your
"app bundle" to authenticate with the system. This is only possible with a signed
app bundle. To see a way to get a signed app bundle for local devleopment see
`./example/hello_macos.go`, which uses `go generate` to create one. To run the
example on macOS, do the following:

```sh
cd ./example/
go generate -x
./example.app/Contents/MacOS/example
```

Depending on your settings, you may need to reveal the notification center in order
to actually see the notifications.

The above uses ad-hoc code signing, which doesn't work well for redistribution.
However, it *should* be possible to sign the bundle with a real apple signing
key to eliminate this problem.

Please report issues with this to [this mailing list](https://lists.sr.ht/~whereswaldon/public-inbox)!

## Use

See the package documentation of `./notification_manager.go` for usage information.

## Name

go => gio

notify => niotify
This package has been moved. You can find the up-to-date code as the `notify` package [here](https://git.sr.ht/~whereswaldon/gio-x).

D android/NotificationHelper.jar => android/NotificationHelper.jar +0 -0
D android/NotificationHelper.java => android/NotificationHelper.java +0 -44
@@ 1,44 0,0 @@
package ht.sr.git.whereswaldon.niotify;

import android.content.Context;
import android.content.Intent;
import android.app.PendingIntent;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.util.Log;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;

public class NotificationHelper {
    private final static String tag = "NotificationHelper";
    public static void newChannel(Context ctx, int importance, String channelID, String name, String description) {
        NotificationChannel channel = new NotificationChannel(channelID, name, importance);
        channel.setDescription(description);

        NotificationManager notificationManager = ctx.getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
    public static void sendNotification(Context ctx, String channelID, int notificationID, String title, String text) throws ClassNotFoundException{
        Intent resultIntent = new Intent(ctx, Class.forName("org.gioui.GioActivity"));
        PendingIntent pending = PendingIntent.getActivity(ctx, notificationID, resultIntent, Intent.FLAG_ACTIVITY_CLEAR_TASK);
        Bitmap bitmap = Bitmap.createBitmap(data, 0, width, width, height, Bitmap.Config.ARGB_8888);
        Notification.Builder builder = new Notification.Builder(ctx, channelID)
                .setContentTitle(title)
                .setSmallIcon(Icon.createWithBitmap(bitmap))
                .setContentText(text)
                .setContentIntent(pending)
                .setPriority(Notification.PRIORITY_DEFAULT);

        NotificationManager notificationManager = ctx.getSystemService(NotificationManager.class);
        notificationManager.notify(notificationID, builder.build());
    }
    public static void cancelNotification(Context ctx, int notificationID) {
        NotificationManager notificationManager = ctx.getSystemService(NotificationManager.class);
        notificationManager.cancel(notificationID);
    }
    // Gio logo image data
	private static int height = 64;
	private static int width = 57;
	private static int[] data = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,520093696,2063597568,-738197504,-251658240,2013265920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,268435456,1677721600,-1056964608,-33554432,-16777216,-16777216,-16777216,-33554432,402653184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,989855744,-1476395008,-150994944,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-335544320,150994944,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83886080,1509949440,-905969664,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-100663296,-1358954496,721420288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100663296,1761607680,-503316480,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-33554432,-1056964608,1744830464,318767104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83886080,1577058304,-603979776,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-268435456,-1728053248,721420288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1308622848,-620756992,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-587202560,1744830464,167772160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,671088640,-1207959552,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-704643072,1543503872,67108864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117440512,-2046820352,-100663296,-16777216,-16777216,-16777216,-16777216,-16777216,-452984832,1677721600,50331648,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,822083584,-771751936,-16777216,-16777216,-16777216,-16777216,-16777216,-167772160,2113929216,184549376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50331648,2097152000,-100663296,-16777216,-16777216,-16777216,-16777216,-16777216,-1191182336,603979776,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352321536,-1157627904,-16777216,-16777216,-16777216,-16777216,-16777216,-268435456,1543503872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,922746880,-503316480,-16777216,-16777216,-16777216,-16777216,-16777216,-1040187392,520093696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1342177280,-167772160,-16777216,-16777216,-16777216,-16777216,-33554432,-2113929216,50331648,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1644167168,-83886080,-16777216,-16777216,-16777216,-16777216,-150994944,1543503872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1996488704,-16777216,-16777216,-16777216,-16777216,-16777216,-452984832,889192448,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1828716544,-16777216,-16777216,-16777216,-16777216,-16777216,-603979776,486539264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1627389952,-33554432,-16777216,-16777216,-16777216,-16777216,-553648128,520093696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,973078528,-117440512,-16777216,-16777216,-16777216,-16777216,-486539264,570425344,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,452984832,-419430400,-16777216,-16777216,-16777216,-16777216,-268435456,637534208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67108864,-973078528,-16777216,-16777216,-16777216,-16777216,-33554432,1358954496,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2063597568,-16777216,-16777216,-16777216,-16777216,-16777216,-1962934272,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,637534208,-134217728,-16777216,-16777216,-16777216,-16777216,-1006632960,83886080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1308622848,-16777216,-16777216,-16777216,-16777216,-117440512,687865856,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1023410176,-16777216,-16777216,-16777216,-16777216,-16777216,-2030043136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1191182336,-16777216,-16777216,-16777216,-16777216,-268435456,285212672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,822083584,-16777216,-16777216,-16777216,-16777216,-16777216,-2097152000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1711276032,-16777216,-16777216,-16777216,-16777216,-33554432,570425344,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,201326592,-218103808,-16777216,-16777216,-16777216,-16777216,-1090519040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1476395008,-16777216,-16777216,-16777216,-16777216,-16777216,1610612736,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1426063360,-16777216,-16777216,-16777216,-16777216,-33554432,301989888,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50331648,-268435456,-16777216,-16777216,-16777216,-16777216,-603979776,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,889192448,-16777216,-16777216,-16777216,-16777216,-16777216,-1476395008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1862270976,-16777216,-16777216,-16777216,-16777216,-16777216,1979711488,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1694498816,-16777216,-16777216,-16777216,-16777216,-16777216,1493172224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-989855744,-16777216,-16777216,-16777216,-16777216,-16777216,1191182336,0,0,0,0,0,0,0,0,0,0,0,0,0,1157627904,-1258291200,1023410176,0,0,0,0,0,0,0,0,0,402653184,-2147483648,-1056964608,-738197504,-855638016,-1593835520,1275068416,16777216,0,0,0,0,436207616,-889192448,-100663296,-1107296256,1493172224,67108864,0,0,0,0,0,0,0,-570425344,-16777216,-16777216,-16777216,-16777216,-16777216,939524096,0,0,0,0,0,0,0,0,0,0,0,0,0,-637534208,-16777216,-637534208,16777216,0,0,0,0,0,0,0,1056964608,-352321536,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-1107296256,335544320,0,0,0,-2147483648,-16777216,-16777216,-16777216,-16777216,-687865856,1191182336,0,0,0,0,0,0,-251658240,-16777216,-16777216,-16777216,-16777216,-16777216,1073741824,0,0,0,0,0,0,0,0,0,0,0,0,0,-134217728,-16777216,-16777216,905969664,0,0,0,0,0,0,637534208,-234881024,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-1023410176,33554432,0,0,1593835520,-16777216,-16777216,-16777216,-16777216,-16777216,-33554432,-1744830464,201326592,0,0,0,0,-150994944,-16777216,-16777216,-16777216,-16777216,-16777216,1308622848,0,0,0,0,0,0,0,0,0,0,0,0,117440512,-16777216,-16777216,-16777216,-2030043136,0,0,0,0,0,0,-1258291200,-16777216,-16777216,-184549376,1442840576,-905969664,-16777216,-16777216,-16777216,-16777216,-16777216,1342177280,0,0,16777216,1761607680,-671088640,-16777216,-16777216,-16777216,-16777216,-16777216,-922746880,268435456,0,0,0,-385875968,-16777216,-16777216,-16777216,-16777216,-16777216,1677721600,0,0,0,0,0,0,0,0,0,0,0,0,335544320,-16777216,-16777216,-16777216,-671088640,0,0,0,0,0,536870912,-50331648,-16777216,-16777216,-2097152000,0,855638016,-16777216,-16777216,-16777216,-16777216,-16777216,-1879048192,0,0,0,0,16777216,1476395008,-369098752,-16777216,-16777216,-16777216,-16777216,-872415232,218103808,0,0,-620756992,-16777216,-16777216,-16777216,-16777216,-16777216,-1744830464,0,0,0,0,0,0,0,0,0,0,0,0,620756992,-16777216,-16777216,-16777216,-16777216,822083584,0,0,0,0,1543503872,-16777216,-16777216,-16777216,1023410176,0,16777216,-201326592,-16777216,-16777216,-16777216,-16777216,-1711276032,0,0,0,0,0,0,536870912,-754974720,-16777216,-16777216,-16777216,-16777216,-1694498816,0,0,-905969664,-16777216,-16777216,-16777216,-16777216,-16777216,-805306368,0,0,0,0,0,0,0,0,0,0,0,0,1006632960,-16777216,-16777216,-16777216,-16777216,-1996488704,0,0,0,0,1946157056,-16777216,-16777216,-16777216,1291845632,0,167772160,-67108864,-16777216,-16777216,-16777216,-16777216,-2097152000,0,0,0,0,0,0,0,436207616,-486539264,-16777216,-16777216,-16777216,-33554432,1241513984,0,-1694498816,-16777216,-16777216,-16777216,-16777216,-16777216,-67108864,352321536,0,0,0,0,0,0,0,0,0,0,0,1258291200,-16777216,-16777216,-16777216,-16777216,-587202560,0,0,0,0,1610612736,-16777216,-16777216,-16777216,-251658240,-1174405120,-637534208,-16777216,-16777216,-16777216,-16777216,-16777216,1191182336,0,0,0,0,0,0,0,0,1241513984,-16777216,-16777216,-16777216,-16777216,-738197504,16777216,1677721600,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,1895825408,0,0,0,0,0,0,0,0,0,0,0,1375731712,-16777216,-16777216,-16777216,-16777216,-16777216,419430400,0,0,0,369098752,-83886080,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-671088640,33554432,0,0,0,0,0,0,0,0,0,-872415232,-16777216,-16777216,-16777216,-16777216,1090519040,771751936,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-486539264,134217728,0,0,0,0,0,0,0,0,0,0,1006632960,-16777216,-16777216,-16777216,-16777216,-436207616,100663296,0,0,0,0,-2030043136,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-67108864,1124073472,0,0,0,0,0,0,0,0,0,0,-2013265920,-16777216,-16777216,-16777216,-16777216,-1593835520,50331648,-335544320,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-2080374784,0,0,0,0,0,0,0,0,0,0,0,-2046820352,-16777216,-16777216,-16777216,1577058304,0,0,0,0,0,50331648,-1962934272,-33554432,-16777216,-16777216,-16777216,-16777216,-16777216,-167772160,1577058304,0,0,0,0,0,0,0,0,0,0,0,1778384896,-16777216,-16777216,-16777216,-16777216,-754974720,0,-1711276032,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-83886080,939524096,0,0,0,0,0,0,0,0,0,0,0,1795162112,-67108864,-1207959552,0,0,0,0,0,0,0,0,687865856,-1929379840,-905969664,-587202560,-922746880,-1962934272,570425344,0,0,0,0,0,0,0,0,0,0,0,0,-1962934272,-16777216,-16777216,-16777216,-16777216,-218103808,0,973078528,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-419430400,637534208,0,0,0,0,0,0,0,0,0,0,0,1090519040,285212672,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67108864,-570425344,-16777216,-16777216,-16777216,-16777216,-234881024,0,0,-905969664,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-469762048,721420288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1912602624,-16777216,-16777216,-16777216,-16777216,-16777216,-570425344,0,0,1241513984,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-201326592,1560281088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1375731712,-117440512,-16777216,-16777216,-16777216,-16777216,-16777216,-1392508928,0,0,0,-1191182336,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-1258291200,570425344,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33554432,1979711488,-83886080,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,1627389952,0,0,0,503316480,-268435456,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-117440512,-1761607680,520093696,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1174405120,-922746880,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-251658240,201326592,0,0,0,0,1342177280,-50331648,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-67108864,-1291845632,1375731712,201326592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16777216,805306368,1996488704,-721420288,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,1946157056,0,0,0,0,0,0,1845493760,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-134217728,-1157627904,1912602624,721420288,67108864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,167772160,973078528,1845493760,-1526726656,-385875968,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-822083584,83886080,0,0,0,0,0,0,0,2080374784,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-117440512,-805306368,-1526726656,2097152000,1728053248,1375731712,1140850688,1140850688,1140850688,1157627904,1509949440,1845493760,-2013265920,-1358954496,-671088640,-83886080,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-301989888,587202560,0,0,0,0,0,0,0,0,0,1728053248,-67108864,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-184549376,1073741824,0,0,0,0,0,0,0,0,0,0,0,1174405120,-402653184,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-234881024,1140850688,0,0,0,0,0,0,0,0,0,0,0,0,0,402653184,-1224736768,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-587202560,771751936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1291845632,-553648128,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-33554432,-1728053248,218103808,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,167772160,1862270976,-553648128,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-704643072,973078528,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67108864,1476395008,-855638016,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-452984832,1795162112,100663296,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,822083584,-2063597568,-637534208,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-67108864,-1090519040,1509949440,117440512,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,805306368,-2130706432,-1124073472,-234881024,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-16777216,-352321536,-1375731712,1627389952,335544320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50331648,738197504,1677721600,-1778384896,-1241513984,-721420288,-402653184,-150994944,-83886080,-301989888,-452984832,-822083584,-1409286144,-1979711488,1593835520,654311424,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
}

D android/notify_android.go => android/notify_android.go +0 -189
@@ 1,189 0,0 @@
package android

import (
	"fmt"
	"sync"

	"gioui.org/app"
	"git.wow.st/gmp/jni"
)

//go:generate javac -target 1.8 -source 1.8 -bootclasspath $ANDROID_HOME/platforms/android-26/android.jar ./NotificationHelper.java
//go:generate jar cf NotificationHelper.jar ./NotificationHelper.class
//go:generate rm ./NotificationHelper.class

// Importance represents the priority of notifications sent over a particular NotificationChannel.
// You MUST use one of the constants defined here when specifying an importance for a channel.
// These constants map to different values within the JVM.
type Importance int

const (
	ImportanceDefault Importance = iota
	ImportanceHigh
	ImportanceLow
	ImportanceMax
	ImportanceMin
	ImportanceNone
	ImportanceUnspecified
	importanceEnd // compile-time hack to track the number of importance constants and size the
	// array holding their values correctly. If new constants need to be added, add them above
	// this.
)

// value returns the JVM value for this importance constant. It must not be invoked before the
// importances have been resolved.
func (i Importance) value() int32 {
	return importances[i]
}

const (
	helperClass               = "ht/sr/git/whereswaldon/niotify/NotificationHelper"
	importanceDefaultName     = "IMPORTANCE_DEFAULT"
	importanceHighName        = "IMPORTANCE_HIGH"
	importanceLowName         = "IMPORTANCE_LOW"
	importanceMaxName         = "IMPORTANCE_MAX"
	importanceMinName         = "IMPORTANCE_MIN"
	importanceNoneName        = "IMPORTANCE_NONE"
	importanceUnspecifiedName = "IMPORTANCE_UNSPECIFIED"
)

var (
	// idlock protects the nextNotificationID to ensure that no notification is ever
	// sent with a duplicate id.
	//
	// BUG(whereswaldon): Notification ID generation does not handle 32 bit integer
	// overflow. Sending more than 2 billion notifications results in undefined
	// behavior.
	idlock             sync.Mutex
	nextNotificationID int32

	// jvmConstLock protects the mapping of JVM constants that must be resolved at runtime
	jvmConstLock sync.Once
	// importances tracks the IMPORTANCE_* constants from the JVM's values. Since they must
	// be resolved at runtime, this array tracks their actual runtime values and the exported
	// constants are simply indicies into this array.
	importances [importanceEnd]int32
	// map the JVM constant name to the index in the array
	importancesMap = map[string]Importance{
		importanceDefaultName:     ImportanceDefault,
		importanceHighName:        ImportanceHigh,
		importanceLowName:         ImportanceLow,
		importanceMaxName:         ImportanceMax,
		importanceMinName:         ImportanceMin,
		importanceNoneName:        ImportanceNone,
		importanceUnspecifiedName: ImportanceUnspecified,
	}
)

// nextID safely returns the next unused notification id number. This function should
// always be used to get a notificationID.
func nextID() int32 {
	idlock.Lock()
	defer idlock.Unlock()
	id := nextNotificationID
	nextNotificationID++
	return id
}

// NotificationChannel represents a stream of notifications that an application
// provisions on android. Such streams can be selectively enabled and disabled
// by the user, and should be used for different purposes.
type NotificationChannel struct {
	id string
}

// NewChannel creates a new notification channel identified by the provided id
// and with the given user-visible name and description. The importance field
// specifies how the android system should prioritize notifications sent over this
// channel, and the value provided MUST be one of the constants declared by this
// package. The actual value of the importance constant is translated into the
// java value at runtime.
func NewChannel(importance Importance, id, name, description string) (*NotificationChannel, error) {
	if err := jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error {
		appCtx := jni.Object(app.AppContext())
		classLoader := jni.ClassLoaderFor(env, appCtx)
		notifyClass, err := jni.LoadClass(env, classLoader, helperClass)
		if err != nil {
			return err
		}
		jvmConstLock.Do(func() {
			var managerClass jni.Class
			managerClass, err = jni.LoadClass(env, classLoader, "android/app/NotificationManager")
			if err != nil {
				return
			}
			for name, index := range importancesMap {
				fieldID := jni.GetStaticFieldID(env, managerClass, name, "I")
				importances[index] = jni.GetStaticIntField(env, managerClass, fieldID)
			}

		})
		newChannelMethod := jni.GetStaticMethodID(env, notifyClass, "newChannel", "(Landroid/content/Context;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")
		jname := jni.Value(jni.JavaString(env, name))
		jdescription := jni.Value(jni.JavaString(env, description))
		jID := jni.Value(jni.JavaString(env, id))
		jimportance := jni.Value(importance.value())
		err = jni.CallStaticVoidMethod(env, notifyClass, newChannelMethod, jni.Value(app.AppContext()), jimportance, jID, jname, jdescription)
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return nil, fmt.Errorf("failed creating notification channel: %w", err)
	}
	nc := &NotificationChannel{
		id: id,
	}
	return nc, nil
}

// Notification represents a notification that has been requested to be shown to the user.
// This type provides methods to cancel or update the contents of the notification.
type Notification struct {
	id int32
}

// Send creates a new Notification and requests that it be displayed on this channel.
func (nc *NotificationChannel) Send(title, text string) (*Notification, error) {
	notificationID := nextID()
	if err := jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error {
		appCtx := jni.Object(app.AppContext())
		classLoader := jni.ClassLoaderFor(env, appCtx)
		notifyClass, err := jni.LoadClass(env, classLoader, helperClass)
		if err != nil {
			return err
		}
		newChannelMethod := jni.GetStaticMethodID(env, notifyClass, "sendNotification", "(Landroid/content/Context;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V")
		jtitle := jni.Value(jni.JavaString(env, title))
		jtext := jni.Value(jni.JavaString(env, text))
		jID := jni.Value(jni.JavaString(env, nc.id))
		err = jni.CallStaticVoidMethod(env, notifyClass, newChannelMethod, jni.Value(app.AppContext()), jID, jni.Value(notificationID), jtitle, jtext)
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return nil, fmt.Errorf("failed sending notification: %w", err)
	}
	return &Notification{
		id: notificationID,
	}, nil
}

// Cancel removes a previously created notification from display.
func (n *Notification) Cancel() error {
	notificationID := n.id
	if err := jni.Do(jni.JVMFor(app.JavaVM()), func(env jni.Env) error {
		appCtx := jni.Object(app.AppContext())
		classLoader := jni.ClassLoaderFor(env, appCtx)
		notifyClass, err := jni.LoadClass(env, classLoader, helperClass)
		if err != nil {
			return err
		}
		newChannelMethod := jni.GetStaticMethodID(env, notifyClass, "cancelNotification", "(Landroid/content/Context;I)V")
		return jni.CallStaticVoidMethod(env, notifyClass, newChannelMethod, jni.Value(app.AppContext()), jni.Value(notificationID))
	}); err != nil {
		return fmt.Errorf("failed cancelling notification: %w", err)
	}
	return nil
}

D cmd/png2bmp/main.go => cmd/png2bmp/main.go +0 -79
@@ 1,79 0,0 @@
package main

import (
	"flag"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"log"
	"os"
)

func max(ints ...uint32) uint32 {
	max := uint32(0)
	for _, i := range ints {
		if i > max {
			max = i
		}
	}
	return max
}

func main() {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), `%s converts a black and white png image into a java int array.
It is suitable for embedding simple bitmap images, but hits limits
on the length of java source code when used with larger images.

NOTE: this program only examines the alpha of each pixel in the image.

Use: %s [file.png] >> SomeClass.java

You'll then need to tweak the java file so that these fields are
declared inside of a class definition.

Additionally, this program will create a preview of the embedded image
in the file out.png in the current working directory.
`, os.Args[0], os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()
	imgFile, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatalf("Failed reading file: %v", err)
	}
	defer imgFile.Close()
	pngData, err := png.Decode(imgFile)
	if err != nil {
		log.Fatalf("Failed decoding image: %v", err)
	}
	bounds := pngData.Bounds()
	fmt.Printf("\tprivate static int height = %d;\n", bounds.Dy())
	fmt.Printf("\tprivate static int width = %d;\n", bounds.Dx())
	fmt.Printf("\tprivate static int[] data = {")
	out := image.NewRGBA(bounds)
	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
		for x := bounds.Min.X; x < bounds.Max.X; x++ {
			c := pngData.At(x, y)
			_, _, _, a := c.RGBA()
			ratio := (float64(a) / 0xffff)
			asByte := uint8(256 * ratio)
			scaled := int32(asByte) << 24 // ARGB, so alpha needs to be first
			fmt.Printf("%d", scaled)
			if x != bounds.Max.X-1 || y != bounds.Max.Y-1 {
				fmt.Printf(",")
			}
			out.SetRGBA(x, y, color.RGBA{A: asByte})
		}
	}
	fmt.Printf("};")
	outFile, err := os.Create("out.png")
	if err != nil {
		log.Fatalf("failed opening output file: %v", err)
	}
	defer outFile.Close()
	if err := png.Encode(outFile, out); err != nil {
		log.Fatalf("failed encoding output image: %v", err)
	}
}

D example/example.app/Contents/Info.plist => example/example.app/Contents/Info.plist +0 -50
@@ 1,50 0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>BuildMachineOSBuild</key>
	<string>18G103</string>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>example</string>
	<key>CFBundleIdentifier</key>
	<string>org.gioui</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>example</string>
	<key>CFBundlePackageType</key>
	<string>APPL</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSupportedPlatforms</key>
	<array>
		<string>MacOSX</string>
	</array>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>DTCompiler</key>
	<string>com.apple.compilers.llvm.clang.1_0</string>
	<key>DTPlatformBuild</key>
	<string>11C505</string>
	<key>DTPlatformVersion</key>
	<string>GM</string>
	<key>DTSDKBuild</key>
	<string>19B90</string>
	<key>DTSDKName</key>
	<string>macosx10.15</string>
	<key>DTXcode</key>
	<string>1130</string>
	<key>DTXcodeBuild</key>
	<string>11C505</string>
	<key>LSMinimumSystemVersion</key>
	<string>10.14</string>
	<key>NSPrincipalClass</key>
	<string>NSApplication</string>
	<key>NSSupportsAutomaticTermination</key>
	<true/>
	<key>NSSupportsSuddenTermination</key>
	<true/>
</dict>
</plist>

D example/example.app/Contents/PkgInfo => example/example.app/Contents/PkgInfo +0 -1
@@ 1,1 0,0 @@
APPL????
\ No newline at end of file

D example/example.app/Contents/_CodeSignature/CodeResources => example/example.app/Contents/_CodeSignature/CodeResources +0 -115
@@ 1,115 0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>files</key>
	<dict/>
	<key>files2</key>
	<dict/>
	<key>rules</key>
	<dict>
		<key>^Resources/</key>
		<true/>
		<key>^Resources/.*\.lproj/</key>
		<dict>
			<key>optional</key>
			<true/>
			<key>weight</key>
			<real>1000</real>
		</dict>
		<key>^Resources/.*\.lproj/locversion.plist$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>1100</real>
		</dict>
		<key>^Resources/Base\.lproj/</key>
		<dict>
			<key>weight</key>
			<real>1010</real>
		</dict>
		<key>^version.plist$</key>
		<true/>
	</dict>
	<key>rules2</key>
	<dict>
		<key>.*\.dSYM($|/)</key>
		<dict>
			<key>weight</key>
			<real>11</real>
		</dict>
		<key>^(.*/)?\.DS_Store$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>2000</real>
		</dict>
		<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
		<dict>
			<key>nested</key>
			<true/>
			<key>weight</key>
			<real>10</real>
		</dict>
		<key>^.*</key>
		<true/>
		<key>^Info\.plist$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>20</real>
		</dict>
		<key>^PkgInfo$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>20</real>
		</dict>
		<key>^Resources/</key>
		<dict>
			<key>weight</key>
			<real>20</real>
		</dict>
		<key>^Resources/.*\.lproj/</key>
		<dict>
			<key>optional</key>
			<true/>
			<key>weight</key>
			<real>1000</real>
		</dict>
		<key>^Resources/.*\.lproj/locversion.plist$</key>
		<dict>
			<key>omit</key>
			<true/>
			<key>weight</key>
			<real>1100</real>
		</dict>
		<key>^Resources/Base\.lproj/</key>
		<dict>
			<key>weight</key>
			<real>1010</real>
		</dict>
		<key>^[^/]+$</key>
		<dict>
			<key>nested</key>
			<true/>
			<key>weight</key>
			<real>10</real>
		</dict>
		<key>^embedded\.provisionprofile$</key>
		<dict>
			<key>weight</key>
			<real>20</real>
		</dict>
		<key>^version\.plist$</key>
		<dict>
			<key>weight</key>
			<real>20</real>
		</dict>
	</dict>
</dict>
</plist>

D example/hello.go => example/hello.go +0 -100
@@ 1,100 0,0 @@
// SPDX-License-Identifier: Unlicense OR MIT

package main

// A simple Gio program. See https://gioui.org for more information.

import (
	//	"image/color"
	"log"
	"time"

	"gioui.org/app"
	"gioui.org/io/system"
	"gioui.org/layout"
	"gioui.org/op"

	//	"gioui.org/text"
	"gioui.org/widget"
	"gioui.org/widget/material"
	"git.sr.ht/~whereswaldon/niotify"

	"gioui.org/font/gofont"
)

func main() {
	go func() {
		w := app.NewWindow()
		if err := loop(w); err != nil {
			log.Fatal(err)
		}
	}()
	app.Main()
}

func loop(w *app.Window) error {
	th := material.NewTheme(gofont.Collection())
	var ops op.Ops
	first := true
	notificationRequests := make(chan struct{})
	var button widget.Clickable
	var err error
	for {
		e := <-w.Events()
		switch e := e.(type) {
		case system.DestroyEvent:
			return e.Err
		case system.FrameEvent:
			if button.Clicked() {
				notificationRequests <- struct{}{}
			}
			gtx := layout.NewContext(&ops, e)
			layout.Inset{
    			Top: e.Insets.Top,
    			Bottom: e.Insets.Bottom,
    			Left: e.Insets.Left,
    			Right: e.Insets.Right,
			}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {

			return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
                              layout.Rigid(func(gtx layout.Context) layout.Dimensions {
                                           text := "notification errors will appear here"
                                           if err != nil {
                                               text = err.Error()
                                           }
                                   return material.Body1(th, text).Layout(gtx)
                              }),
                              layout.Flexed(1,func(gtx layout.Context) layout.Dimensions {
                                    return material.Button(th, &button, "Send Notification").Layout(gtx)
                              }),
                          )
			})
			e.Frame(gtx.Ops)
			if first {
				first = false
				go func() {
					mgr, e := niotify.NewManager()
					if e != nil {
						log.Printf("manager creation failed: %v", e)
						err = e
					}
					for _ = range notificationRequests {
    						log.Println("trying to send notification")
						notif, e := mgr.CreateNotification("hello!", "IS GIO OUT THERE?")
						if e != nil {
							log.Printf("notification send failed: %v", e)
							err = e
							continue
						}
						go func() {
							time.Sleep(time.Second * 10)
							if err = notif.Cancel(); err != nil {
								log.Printf("failed cancelling: %v", err)
							}
						}()
					}
				}()
			}
		}
	}
}

D example/hello_macos.go => example/hello_macos.go +0 -7
@@ 1,7 0,0 @@
//+build darwin

//go:generate mkdir -p example.app/Contents/MacOS
//go:generate go build -o example.app/Contents/MacOS/example
//go:generate codesign -s - example.app

package main

D go.mod => go.mod +0 -16
@@ 1,16 0,0 @@
module git.sr.ht/~whereswaldon/niotify

go 1.14

require (
	gioui.org v0.0.0-20201206220452-acc3f704e478
	gioui.org/cmd v0.0.0-20201206220452-acc3f704e478
	git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0
	github.com/esiqveland/notify v0.9.1
	github.com/godbus/dbus/v5 v5.0.3
	golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
	golang.org/x/mod v0.4.0 // indirect
	golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect
	golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d // indirect
	golang.org/x/tools v0.0.0-20201208002638-66f931576d67 // indirect
)

D go.sum => go.sum +0 -80
@@ 1,80 0,0 @@
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gioui.org v0.0.0-20201206220230-a87a520ae825/go.mod h1:Y+uS7hHMvku1Q+ooaoq6fYD5B2LGoT8JtFgvmYmRzTw=
gioui.org v0.0.0-20201206220452-acc3f704e478 h1:BOuNQF8yZHQUGhL1G93akbzJ2+G9EJySzPssDic9acY=
gioui.org v0.0.0-20201206220452-acc3f704e478/go.mod h1:Y+uS7hHMvku1Q+ooaoq6fYD5B2LGoT8JtFgvmYmRzTw=
gioui.org/cmd v0.0.0-20201206220452-acc3f704e478 h1:GUVrZ1xUV4BKCY5kvaqQQUnclzdfnX72pzpIEpl7xVQ=
gioui.org/cmd v0.0.0-20201206220452-acc3f704e478/go.mod h1:sV4dgOzB0wbwYQVdvHezVizVHM+Xp7VMFN9++VJe51M=
git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0 h1:Ynp3h+TC8k1clvf45D28VFQlmy0bPx8M/MG5bB24Vj8=
git.wow.st/gmp/jni v0.0.0-20200827154156-014cd5c7c4c0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4 h1:QD3KxSJ59L2lxG6MXBjNHxiQO2RmxTQ3XcK+wO44WOg=
github.com/chromedp/cdproto v0.0.0-20191114225735-6626966fbae4/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
github.com/chromedp/chromedp v0.5.2 h1:W8xBXQuUnd2dZK0SN/lyVwsQM7KgW+kY5HGnntms194=
github.com/chromedp/chromedp v0.5.2/go.mod h1:rsTo/xRo23KZZwFmWk2Ui79rBaVRRATCjLzNQlOFSiA=
github.com/esiqveland/notify v0.9.1 h1:hX6ZD3FCQJXI46AzUM/iWekcMfnZ9TPE4uIu9Hrn1D4=
github.com/esiqveland/notify v0.9.1/go.mod h1:63UbVSaeJwF0LVJARHFuPgUAoM7o1BEvCZyknsuonBc=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 h1:n9HxLrNxWWtEb1cA950nuEEj3QnKbtsCJ6KjcgisNUs=
golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200618115811-c13761719519 h1:1e2ufUJNM3lCHEY5jIgac/7UTjd6cgJNdatjPdFWf34=
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e h1:1xWUkZQQ9Z9UuZgNaIR6OQOE7rUFglXUUBZlO+dGg6I=
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201208002638-66f931576d67 h1:m/pavz5iHQjTS53xz7jWmXK6qZIJaGy7rQwODcna+cs=
golang.org/x/tools v0.0.0-20201208002638-66f931576d67/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

D macos/niotify_test.go => macos/niotify_test.go +0 -14
@@ 1,14 0,0 @@
//+build darwin,cgo

package macos

import (
	"testing"
)

func TestCancelNonexistent(t *testing.T) {
	var notif *Notification
	if err := notif.Cancel(); err == nil {
		t.Fatalf("should fail to cancel nonexistent notification id")
	}
}

D macos/notify_macos.go => macos/notify_macos.go +0 -192
@@ 1,192 0,0 @@
//+build darwin,cgo

package macos

//#cgo LDFLAGS: -framework Foundation -framework UserNotifications

/*
#cgo CFLAGS: -x objective-c -fno-objc-arc -fmodules
#pragma clang diagnostic ignored "-Wformat-security"

#import <stdlib.h>

@import Foundation;
@import UserNotifications;

const unsigned char NIOTIFY_SUCCESS = 0;
const unsigned char NIOTIFY_NO_PERMISSION = 1;
const unsigned char NIOTIFY_NO_BUNDLE = 2;
const unsigned char NIOTIFY_UKNOWN_ERR = 3;

@interface UNDelegate : NSObject <UNUserNotificationCenterDelegate>
{ }
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler;
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler;
- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(UNNotification *)notification;
@end

@implementation UNDelegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
	NSLog(@"didReceiveNotificationResponse");
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
	NSLog(@"willPresentNotification");
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(UNNotification *)notification {
	NSLog(@"openSettingsForNotification");
}
@end

UNUserNotificationCenter *nc;
BOOL enabled;
BOOL hasBundle;
UNDelegate *del;

void setup() {
	@autoreleasepool {
		NSLog(@"Getting application bundle");
		enabled = NO;
		hasBundle = NO;
		NSBundle *main = [NSBundle mainBundle];
		if (main.bundleIdentifier == nil) {
			NSLog(@"No app bundle.");
			return;
		}
		hasBundle = YES;
		NSLog(@"Bundle ID: %@", main.bundleIdentifier);
		NSLog(@"Getting notification center");
		nc = [UNUserNotificationCenter currentNotificationCenter];
		del = [[UNDelegate alloc] init];
		nc.delegate = del;
	}
}

NSString*
notify(char *id, char *title, char *content, unsigned char *errorCode) {
	NSString *ret;

	if (!hasBundle) {
    		*errorCode = NIOTIFY_NO_BUNDLE;
    		return ret;
	}

	@autoreleasepool {
		dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
		NSLog(@"Creating notification");
		UNMutableNotificationContent *note = [[UNMutableNotificationContent alloc] init];
		note.title = [[NSString alloc] initWithUTF8String: title];
		note.body = [[NSString alloc] initWithUTF8String: content];
		NSString *identifier = [[NSUUID UUID] UUIDString];

		NSLog(@"Creating request");
		UNNotificationRequest *req = [UNNotificationRequest requestWithIdentifier:identifier content: note trigger:nil];
		ret = req.identifier;
		[ret retain];
		NSLog(@"Requesting authorization");
		[nc requestAuthorizationWithOptions: UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionCriticalAlert completionHandler: ^(BOOL granted, NSError *error){
			NSLog(@"Granted = %s", granted?"true":"false");
			NSLog(@"Error = %@", error);
			enabled = granted;
			if (enabled == YES) {
                		NSLog(@"Adding notification request");
                		[nc addNotificationRequest:req withCompletionHandler: ^(NSError *error) {
                			NSLog(@"added notification. Error: %@", error);
                			*errorCode=NIOTIFY_SUCCESS;
                			dispatch_semaphore_signal(semaphore);
                		}];
			} else {
    				*errorCode=NIOTIFY_NO_PERMISSION;
    				dispatch_semaphore_signal(semaphore);
			}
		}];
		dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
	}
	return ret;
}

void
cancel(void *nid, unsigned char *errorCode) {
	if (!hasBundle) {
    		*errorCode = NIOTIFY_NO_BUNDLE;
    		return;
	}

    @try {
	[nc removePendingNotificationRequestsWithIdentifiers: @[(NSString*)nid]];
	[nc removeDeliveredNotificationsWithIdentifiers: @[(NSString*)nid]];
    }
    @catch(NSException *ne) {
        NSLog(@"caught exception when cancelling notification %@: %@", nid, ne);
        *errorCode=NIOTIFY_UKNOWN_ERR;
    }
}

*/
import "C"

import (
	"fmt"
	"runtime"
	"unsafe"
)

func init() {
	runtime.LockOSThread()
	C.setup()
}

type NotificationChannel struct {
	id *C.char
}

func NewNotificationChannel(id string) NotificationChannel {
	return NotificationChannel{id: C.CString(id)}
}

func (c NotificationChannel) Send(title, text string) (*Notification, error) {
	return notify(c.id, title, text)
}

type Notification C.NSString

// toErr converts C integer error codes into Go errors with semi-useful string
// messages.
func toErr(errCode C.uchar) error {
	switch errCode {
	case C.NIOTIFY_SUCCESS:
		return nil
	case C.NIOTIFY_NO_PERMISSION:
		return fmt.Errorf("permission denied")
	case C.NIOTIFY_NO_BUNDLE:
		return fmt.Errorf("no app bundle detected")
	default:
		return fmt.Errorf("unknown error: %v", errCode)
	}
}

func notify(cid *C.char, title, content string) (*Notification, error) {
	ct := C.CString(title)
	defer C.free(unsafe.Pointer(ct))
	cc := C.CString(content)
	defer C.free(unsafe.Pointer(cc))
	var errCode C.uchar

	id := C.notify(cid, ct, cc, &errCode)
	err := toErr(errCode)
	if err != nil {
		return nil, err
	}

	return (*Notification)(id), nil
}

func (n *Notification) Cancel() error {
	if n == nil {
		return fmt.Errorf("attempted to cancel nil notification")
	}
	var errCode C.uchar
	C.cancel(unsafe.Pointer(n), &errCode)
	return toErr(errCode)
}

D niotify_android.go => niotify_android.go +0 -33
@@ 1,33 0,0 @@
//+build android

package niotify

import (
	"git.sr.ht/~whereswaldon/niotify/android"
)

type androidManager struct {
	channel *android.NotificationChannel
}

var _ managerInterface = &androidManager{}

func newManager() (Manager, error) {
	channel, err := android.NewChannel(android.ImportanceDefault, "DEFAULT", "niotify", "background notifications")
	if err != nil {
		return Manager{}, err
	}
	return Manager{
		&androidManager{
			channel: channel,
		},
	}, nil
}

func (a *androidManager) CreateNotification(title, text string) (*Notification, error) {
	notification, err := a.channel.Send(title, text)
	if err != nil {
		return nil, err
	}
	return &Notification{notification}, nil
}

D niotify_darwin.go => niotify_darwin.go +0 -27
@@ 1,27 0,0 @@
//+build darwin

package niotify

import (
	"git.sr.ht/~whereswaldon/niotify/macos"
)

type macosManager struct {
	channel macos.NotificationChannel
}

func newManager() (Manager, error) {
	c := macos.NewNotificationChannel("Gio App")

	return Manager{
		&macosManager{channel: c},
	}, nil
}

func (a *macosManager) CreateNotification(title, text string) (*Notification, error) {
	notification, err := a.channel.Send(title, text)
	if err != nil {
		return nil, err
	}
	return &Notification{notification}, nil
}

D niotify_dbus.go => niotify_dbus.go +0 -60
@@ 1,60 0,0 @@
//+build linux,!android openbsd freebsd netbsd

package niotify

import (
	"fmt"

	"github.com/esiqveland/notify"
	dbus "github.com/godbus/dbus/v5"
)

type linuxManager struct {
	notify.Notifier
}

var _ managerInterface = &linuxManager{}

func newManager() (Manager, error) {
	conn, err := dbus.SessionBus()
	if err != nil {
		return Manager{}, fmt.Errorf("failed connecting to dbus: %w", err)
	}
	notifier, err := notify.New(conn)
	if err != nil {
		return Manager{}, fmt.Errorf("failed creating notifier: %w", err)
	}
	return Manager{
		impl: &linuxManager{
			Notifier: notifier,
		},
	}, nil
}

type linuxNotification struct {
	id uint32
	*linuxManager
}

var _ notificationInterface = linuxNotification{}

func (l *linuxManager) CreateNotification(title, text string) (*Notification, error) {
	id, err := l.Notifier.SendNotification(notify.Notification{
		Summary: title,
		Body:    text,
	})
	if err != nil {
		return nil, err
	}
	return &Notification{
		linuxNotification{
			id:           id,
			linuxManager: l,
		},
	}, nil
}

func (l linuxNotification) Cancel() error {
	_, err := l.linuxManager.CloseNotification(l.id)
	return err
}

D niotify_unsupported.go => niotify_unsupported.go +0 -19
@@ 1,19 0,0 @@
//+build !linux,!android,!openbsd,!freebsd,!dragonfly,!netbsd,!darwin

package niotify

type unsupportedManager struct{}

func newManager() (Manager, error) {
	return Manager{unsupportedManager{}}, nil
}

func (u unsupportedManager) CreateNotification(title, text string) (*Notification, error) {
	return &Notification{unsupportedNotification{}}, nil
}

type unsupportedNotification struct{}

func (u unsupportedNotification) Cancel() error {
	return nil
}

D notification_manager.go => notification_manager.go +0 -56
@@ 1,56 0,0 @@
/*
Package niotify provides cross-platform notifications for Gio applications. https://gioui.org

It aims to eventually support all Gio target platforms, but currently only supports
android and linux.

Sending a notification is easy:

    // NOTE: error handling omitted
    // construct a manager
    manager, _ := NewManager()
    // send notification
    notification, _ := manager.CreateNotification("hello!", "I was sent from Gio!")

    // you can also cancel notifications
    notification.Cancel()
*/
package niotify

// Manager provides methods for creating and managing notifications.
type Manager struct {
	impl managerInterface
}

// NewManager creates a new Manager tailored to the current operating system.
func NewManager() (Manager, error) {
	return newManager()
}

// CreateNotification creates and sends a notification on the current platform.
// NOTE: it currently only supports Android and Linux. All other platforms are a
// no-op.
func (m Manager) CreateNotification(title, text string) (*Notification, error) {
	return m.impl.CreateNotification(title, text)
}

// managerInterface is the set of methods required for a cross-platform notification manager.
type managerInterface interface {
	CreateNotification(title, text string) (*Notification, error)
}

// notificationInterface is the set of methods required for a cross-platform notification.
type notificationInterface interface {
	Cancel() error
}

// Notification provides a cross-platform set of methods to manage a sent Notification.
type Notification struct {
	impl notificationInterface
}

// Cancel attempts to remove a previously-created notification from view on the current
// platform.
func (n *Notification) Cancel() error {
	return n.impl.Cancel()
}

D tools.go => tools.go +0 -5
@@ 1,5 0,0 @@
//+build tools

package niotify

import _ "gioui.org/cmd/gogio"