diff --git a/db/notification.go b/db/notification.go index 7bf8f62..2757248 100644 --- a/db/notification.go +++ b/db/notification.go @@ -71,6 +71,8 @@ func toNotificationClient(cl *ent.NotificationClient) (*NotificationClient, erro settings = notifier.DingTalkConfig{} case "telegram": settings = notifier.TelegramConfig{} + case "bark": + settings = notifier.BarkConfig{} } err := json.Unmarshal([]byte(cl.Settings), &settings) if err != nil { diff --git a/pkg/notifier/clients.go b/pkg/notifier/clients.go index 019be1a..13b90b4 100644 --- a/pkg/notifier/clients.go +++ b/pkg/notifier/clients.go @@ -3,6 +3,7 @@ package notifier import ( "encoding/json" + "github.com/nikoksr/notify/service/bark" "github.com/nikoksr/notify/service/dingding" po "github.com/nikoksr/notify/service/pushover" "github.com/nikoksr/notify/service/telegram" @@ -68,3 +69,22 @@ func NewTelegramClient(s string) (NotificationClient, error) { svc.AddReceivers(cfg.ChatID) return &Notifier{service: svc}, nil } + + +type BarkConfig struct { + DeviceKey string `json:"device_key"` + URL string `json:"url"` +} + +func NewbarkClient(s string) (NotificationClient, error) { + var cfg BarkConfig + if err := json.Unmarshal([]byte(s), &cfg); err != nil { + return nil, errors.Wrap(err, "json") + } + url := cfg.URL + if url == "" { + url = bark.DefaultServerURL + } + b := bark.NewWithServers(cfg.DeviceKey, url) + return &Notifier{service: b}, nil +} \ No newline at end of file diff --git a/pkg/notifier/doc.go b/pkg/notifier/doc.go index e64d721..7673d65 100644 --- a/pkg/notifier/doc.go +++ b/pkg/notifier/doc.go @@ -20,7 +20,7 @@ type Notifier struct { func (s *Notifier) SendMsg(msg string) error { notifier := notify.New() notifier.UseServices(s.service) - return notifier.Send(context.TODO(), "polaris", msg) + return notifier.Send(context.TODO(), "Polaris", msg) } var handler = utils.Map[string, HandlerFunc]{} @@ -29,6 +29,7 @@ func init() { handler.Store("pushover", NewPushoverClient) handler.Store("dingtalk", NewDingTalkClient) handler.Store("telegram", NewTelegramClient) + handler.Store("bark", NewbarkClient) } func Gethandler(name string) (HandlerFunc, bool) { diff --git a/ui/lib/settings/notifier.dart b/ui/lib/settings/notifier.dart index 5d31198..4e14b13 100644 --- a/ui/lib/settings/notifier.dart +++ b/ui/lib/settings/notifier.dart @@ -27,12 +27,24 @@ class _NotifierState extends ConsumerState { if (i < v.length) { final client = v[i]; return SettingsCard( - child: Text("${client.name!} (${client.service})"), - onTap: () => showNotifierDetails(client), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + client.name!, + style: TextStyle(fontSize: 20, height: 3), + ), + Opacity( + opacity: 0.5, + child: Text(client.service!), + ) + ], + ), + onTap: () => showNotifierAccordingToService(client), ); } return SettingsCard( - onTap: () => showNotifierDetails(NotifierData()), + onTap: () => showSelections(), child: const Icon(Icons.add)); }), ), @@ -40,14 +52,122 @@ class _NotifierState extends ConsumerState { loading: () => const MyProgressIndicator()); } - Future showNotifierDetails(NotifierData notifier) { + Future showSelections() { + return showDialog( + context: context, + barrierDismissible: true, + builder: (BuildContext context) { + return AlertDialog( + content: SizedBox( + height: 500, + width: 500, + child: Wrap( + children: [ + SettingsCard( + child: InkWell( + child: const Center( + child: Text("Pushover"), + ), + onTap: () { + Navigator.of(context).pop(); + showPushoverNotifierDetails(NotifierData()); + }, + ), + ), + SettingsCard( + child: InkWell( + child: const Center( + child: Text("Bark"), + ), + onTap: () { + Navigator.of(context).pop(); + showBarkNotifierDetails(NotifierData()); + }, + ), + ) + ], + ), + ), + ); + }); + } + + Future showNotifierAccordingToService(NotifierData notifier) { + switch (notifier.service) { + case "bark": + return showBarkNotifierDetails(notifier); + case "pushover": + return showPushoverNotifierDetails(notifier); + } + return Future.value(); + } + + Future showBarkNotifierDetails(NotifierData notifier) { + final _formKey = GlobalKey(); + + var body = FormBuilder( + key: _formKey, + initialValue: { + "name": notifier.name, + "enabled": notifier.enabled ?? true, + "device_key": + notifier.settings != null ? notifier.settings!["device_key"] : "", + "url": notifier.settings != null ? notifier.settings!["url"] : "", + }, + child: Column( + children: [ + FormBuilderTextField( + name: "name", + decoration: Commons.requiredTextFieldStyle(text: "名称"), + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: FormBuilderValidators.required(), + ), + FormBuilderTextField( + name: "url", + decoration: const InputDecoration( + labelText: "服务器地址", helperText: "留空使用默认地址"), + ), + FormBuilderTextField( + name: "device_key", + decoration: Commons.requiredTextFieldStyle(text: "Device Key"), + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: FormBuilderValidators.required(), + ), + FormBuilderSwitch(name: "enabled", title: const Text("启用")) + ], + ), + ); + onDelete() async { + return ref.read(notifiersDataProvider.notifier).delete(notifier.id!); + } + + onSubmit() async { + if (_formKey.currentState!.saveAndValidate()) { + var values = _formKey.currentState!.value; + return ref.read(notifiersDataProvider.notifier).add(NotifierData( + name: values["name"], + service: "bark", + enabled: values["enabled"], + settings: { + "device_key": values["device_key"], + "url": values["url"] + })); + } else { + throw "validation_error"; + } + } + + return showSettingDialog( + context, "Bark", notifier.id != null, body, onSubmit, onDelete); + } + + Future showPushoverNotifierDetails(NotifierData notifier) { final _formKey = GlobalKey(); var body = FormBuilder( key: _formKey, initialValue: { "name": notifier.name, - "service": notifier.service, "enabled": notifier.enabled ?? true, "app_token": notifier.settings != null ? notifier.settings!["app_token"] : "", @@ -56,13 +176,6 @@ class _NotifierState extends ConsumerState { }, child: Column( children: [ - FormBuilderDropdown( - name: "service", - decoration: const InputDecoration(labelText: "类型"), - items: const [ - DropdownMenuItem(value: "pushover", child: Text("Pushover")), - ], - ), FormBuilderTextField( name: "name", decoration: Commons.requiredTextFieldStyle(text: "名称"), @@ -94,7 +207,7 @@ class _NotifierState extends ConsumerState { var values = _formKey.currentState!.value; return ref.read(notifiersDataProvider.notifier).add(NotifierData( name: values["name"], - service: values["service"], + service: "pushover", enabled: values["enabled"], settings: { "app_token": values["app_token"], @@ -105,9 +218,7 @@ class _NotifierState extends ConsumerState { } } - return showSettingDialog(context, - "通知客户端", notifier.id != null, body, onSubmit, onDelete); + return showSettingDialog( + context, "Pushover", notifier.id != null, body, onSubmit, onDelete); } - - -} \ No newline at end of file +}