android-notify 1.3__py3-none-any.whl → 1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of android-notify might be problematic. Click here for more details.
- android_notify/__init__.py +2 -1
- android_notify/core.py +1 -1
- android_notify/sword.py +237 -65
- {android_notify-1.3.dist-info → android_notify-1.5.dist-info}/METADATA +147 -45
- android_notify-1.5.dist-info/RECORD +9 -0
- {android_notify-1.3.dist-info → android_notify-1.5.dist-info}/WHEEL +1 -1
- android_notify-1.3.dist-info/RECORD +0 -9
- {android_notify-1.3.dist-info → android_notify-1.5.dist-info}/top_level.txt +0 -0
android_notify/__init__.py
CHANGED
android_notify/core.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
""" Non-Advanced Stuff """
|
|
2
2
|
import random
|
|
3
3
|
import os
|
|
4
|
-
from jnius import autoclass,cast
|
|
5
4
|
|
|
6
5
|
ON_ANDROID = False
|
|
7
6
|
try:
|
|
7
|
+
from jnius import autoclass,cast # Needs Java to be installed
|
|
8
8
|
# Get the required Java classes
|
|
9
9
|
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
|
10
10
|
NotificationChannel = autoclass('android.app.NotificationChannel')
|
android_notify/sword.py
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"""This Module Contain Class for creating Notification With Java"""
|
|
2
2
|
import difflib
|
|
3
|
-
import
|
|
3
|
+
import traceback
|
|
4
4
|
import os
|
|
5
5
|
import re
|
|
6
|
-
from jnius import autoclass,cast # pylint: disable=W0611, C0114
|
|
7
6
|
|
|
8
7
|
DEV=0
|
|
9
8
|
ON_ANDROID = False
|
|
10
9
|
|
|
11
10
|
try:
|
|
11
|
+
from jnius import autoclass,cast # Needs Java to be installed pylint: disable=W0611, C0114
|
|
12
|
+
from android import activity # pylint: disable=import-error
|
|
13
|
+
from android.config import ACTIVITY_CLASS_NAME # pylint: disable=import-error
|
|
14
|
+
|
|
12
15
|
# Get the required Java classes
|
|
16
|
+
Bundle = autoclass('android.os.Bundle')
|
|
13
17
|
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
|
14
18
|
String = autoclass('java.lang.String')
|
|
15
19
|
Intent = autoclass('android.content.Intent')
|
|
@@ -56,17 +60,21 @@ class Notification:
|
|
|
56
60
|
:param style: Style of the notification
|
|
57
61
|
('simple', 'progress', 'big_text', 'inbox', 'big_picture', 'large_icon', 'both_imgs').
|
|
58
62
|
both_imgs == using lager icon and big picture
|
|
59
|
-
:param big_picture_path: Path to the image resource.
|
|
60
|
-
:param large_icon_path: Path to the image resource.
|
|
63
|
+
:param big_picture_path: Relative Path to the image resource.
|
|
64
|
+
:param large_icon_path: Relative Path to the image resource.
|
|
65
|
+
:param callback: Function for notification Click.
|
|
61
66
|
---
|
|
62
67
|
(Advance Options)
|
|
63
|
-
:param channel_name: Defaults to "Default Channel"
|
|
64
|
-
:param channel_id: Defaults to "default_channel"
|
|
68
|
+
:param channel_name: - str Defaults to "Default Channel"
|
|
69
|
+
:param channel_id: - str Defaults to "default_channel"
|
|
65
70
|
---
|
|
66
71
|
(Options during Dev On PC)
|
|
67
|
-
:param logs: Defaults to True
|
|
72
|
+
:param logs: - Bool Defaults to True
|
|
68
73
|
"""
|
|
69
|
-
notification_ids=[]
|
|
74
|
+
notification_ids=[0]
|
|
75
|
+
button_ids=[0]
|
|
76
|
+
btns_box={}
|
|
77
|
+
main_functions={}
|
|
70
78
|
style_values=[
|
|
71
79
|
'','simple',
|
|
72
80
|
'progress','big_text',
|
|
@@ -80,11 +88,13 @@ class Notification:
|
|
|
80
88
|
'style':'simple',
|
|
81
89
|
'big_picture_path':'',
|
|
82
90
|
'large_icon_path':'',
|
|
83
|
-
'progress_max_value':
|
|
91
|
+
'progress_max_value': 0,
|
|
84
92
|
'progress_current_value': 0,
|
|
85
93
|
'channel_name':'Default Channel',
|
|
86
94
|
'channel_id':'default_channel',
|
|
87
95
|
'logs':True,
|
|
96
|
+
"identifer": '',
|
|
97
|
+
'callback': None
|
|
88
98
|
}
|
|
89
99
|
# During Development (When running on PC)
|
|
90
100
|
logs=not ON_ANDROID
|
|
@@ -97,22 +107,30 @@ class Notification:
|
|
|
97
107
|
self.large_icon_path=''
|
|
98
108
|
self.big_picture_path=''
|
|
99
109
|
self.progress_current_value=0
|
|
100
|
-
self.progress_max_value=
|
|
110
|
+
self.progress_max_value=0
|
|
111
|
+
|
|
112
|
+
# For Nofitication Functions
|
|
113
|
+
self.identifer=''
|
|
114
|
+
self.callback = None
|
|
115
|
+
|
|
101
116
|
# Advance Options
|
|
102
|
-
self.channel_name=''
|
|
103
|
-
self.channel_id=''
|
|
117
|
+
self.channel_name='Default Channel'
|
|
118
|
+
self.channel_id='default_channel'
|
|
104
119
|
self.silent=False
|
|
120
|
+
|
|
105
121
|
# During Dev on PC
|
|
106
122
|
self.logs=self.logs
|
|
123
|
+
|
|
107
124
|
# Private (Don't Touch)
|
|
108
125
|
self.__id = self.__getUniqueID()
|
|
109
126
|
self.__setArgs(kwargs)
|
|
110
|
-
|
|
127
|
+
|
|
111
128
|
if not ON_ANDROID:
|
|
112
129
|
return
|
|
113
130
|
# TODO make send method wait for __asks_permission_if_needed method
|
|
114
131
|
self.__asks_permission_if_needed()
|
|
115
132
|
self.notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
|
|
133
|
+
self.__builder=NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
|
|
116
134
|
|
|
117
135
|
def updateTitle(self,new_title):
|
|
118
136
|
"""Changes Old Title
|
|
@@ -136,6 +154,11 @@ class Notification:
|
|
|
136
154
|
|
|
137
155
|
def updateProgressBar(self,current_value,message:str=''):
|
|
138
156
|
"""message defaults to last message"""
|
|
157
|
+
if not ON_ANDROID:
|
|
158
|
+
return
|
|
159
|
+
|
|
160
|
+
if self.logs:
|
|
161
|
+
print(f'Progress Bar Update value: {current_value}')
|
|
139
162
|
self.__builder.setProgress(self.progress_max_value, current_value, False)
|
|
140
163
|
if message:
|
|
141
164
|
self.__builder.setContentText(String(message))
|
|
@@ -159,16 +182,12 @@ class Notification:
|
|
|
159
182
|
self.__startNotificationBuild()
|
|
160
183
|
self.notification_manager.notify(self.__id, self.__builder.build())
|
|
161
184
|
elif self.logs:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
style: '{self.style}'
|
|
169
|
-
Silent: '{self.silent}'
|
|
170
|
-
(Won't Print Logs When Complied,except if selected `Notification.logs=True`
|
|
171
|
-
""")
|
|
185
|
+
string_to_display=''
|
|
186
|
+
for name,value in vars(self).items():
|
|
187
|
+
if value and name not in ['logs','_Notification__id']:
|
|
188
|
+
string_to_display += f'\n {name}: {value}'
|
|
189
|
+
string_to_display +="\n (Won't Print Logs When Complied,except if selected `Notification.logs=True`)"
|
|
190
|
+
print(string_to_display)
|
|
172
191
|
if DEV:
|
|
173
192
|
print(f'channel_name: {self.channel_name}, Channel ID: {self.channel_id}, id: {self.__id}')
|
|
174
193
|
print('Can\'t Send Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.\n' if DEV else '\n') # pylint: disable=C0301
|
|
@@ -202,14 +221,14 @@ class Notification:
|
|
|
202
221
|
|
|
203
222
|
def __setArgs(self,options_dict:dict):
|
|
204
223
|
for key,value in options_dict.items():
|
|
205
|
-
if key == 'channel_name':
|
|
206
|
-
setattr(self,key, value[:40]
|
|
207
|
-
elif key == 'channel_id' and value:
|
|
208
|
-
setattr(self,key, self.__generate_channel_id(value)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if "channel_id" not in options_dict and 'channel_name' in options_dict:
|
|
224
|
+
if key == 'channel_name' and value.strip():
|
|
225
|
+
setattr(self,key, value[:40])
|
|
226
|
+
elif key == 'channel_id' and value.strip(): # If user input's a channel id (i format properly)
|
|
227
|
+
setattr(self,key, self.__generate_channel_id(value))
|
|
228
|
+
else:
|
|
229
|
+
setattr(self,key, value if value else self.defaults[key])
|
|
230
|
+
|
|
231
|
+
if "channel_id" not in options_dict and 'channel_name' in options_dict: # if User doesn't input channel id but inputs channel_name
|
|
213
232
|
setattr(self,'channel_id', self.__generate_channel_id(options_dict['channel_name']))
|
|
214
233
|
|
|
215
234
|
def __startNotificationBuild(self):
|
|
@@ -219,8 +238,10 @@ class Notification:
|
|
|
219
238
|
|
|
220
239
|
def __createBasicNotification(self):
|
|
221
240
|
# Notification Channel (Required for Android 8.0+)
|
|
241
|
+
# print("THis is cchannel is ",self.channel_id) #"BLAH"
|
|
222
242
|
if BuildVersion.SDK_INT >= 26 and self.notification_manager.getNotificationChannel(self.channel_id) is None:
|
|
223
243
|
importance=NotificationManagerCompat.IMPORTANCE_DEFAULT if self.silent else NotificationManagerCompat.IMPORTANCE_HIGH # pylint: disable=possibly-used-before-assignment
|
|
244
|
+
# importance = 3 or 4
|
|
224
245
|
channel = NotificationChannel(
|
|
225
246
|
self.channel_id,
|
|
226
247
|
self.channel_name,
|
|
@@ -229,14 +250,13 @@ class Notification:
|
|
|
229
250
|
self.notification_manager.createNotificationChannel(channel)
|
|
230
251
|
|
|
231
252
|
# Build the notification
|
|
232
|
-
self.__builder = NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
|
|
233
|
-
self.__builder.setContentTitle(self.title)
|
|
234
|
-
self.__builder.setContentText(self.message)
|
|
253
|
+
# self.__builder = NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
|
|
254
|
+
self.__builder.setContentTitle(str(self.title))
|
|
255
|
+
self.__builder.setContentText(str(self.message))
|
|
235
256
|
self.__builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
236
257
|
self.__builder.setDefaults(NotificationCompat.DEFAULT_ALL) # pylint: disable=E0606
|
|
237
|
-
if
|
|
238
|
-
|
|
239
|
-
|
|
258
|
+
self.__builder.setPriority(NotificationCompat.PRIORITY_DEFAULT if self.silent else NotificationCompat.PRIORITY_HIGH)
|
|
259
|
+
self.__addIntentToOpenApp()
|
|
240
260
|
def __addNotificationStyle(self):
|
|
241
261
|
# pylint: disable=trailing-whitespace
|
|
242
262
|
|
|
@@ -280,7 +300,7 @@ class Notification:
|
|
|
280
300
|
big_pic_bitmap = self.__getBitmap(big_pic_javapath)
|
|
281
301
|
big_picture_style = NotificationCompatBigPictureStyle().bigPicture(big_pic_bitmap)
|
|
282
302
|
self.__builder.setStyle(big_picture_style)
|
|
283
|
-
|
|
303
|
+
if large_icon_javapath:
|
|
284
304
|
large_icon_bitmap = self.__getBitmap(large_icon_javapath)
|
|
285
305
|
self.__builder.setLargeIcon(large_icon_bitmap)
|
|
286
306
|
elif self.style == 'progress':
|
|
@@ -295,10 +315,7 @@ class Notification:
|
|
|
295
315
|
# return self.__builder
|
|
296
316
|
|
|
297
317
|
def __getUniqueID(self):
|
|
298
|
-
|
|
299
|
-
notification_id = random.randint(1, reasonable_amount_of_notifications)
|
|
300
|
-
while notification_id in self.notification_ids:
|
|
301
|
-
notification_id = random.randint(1, 100)
|
|
318
|
+
notification_id = self.notification_ids[-1] + 1
|
|
302
319
|
self.notification_ids.append(notification_id)
|
|
303
320
|
return notification_id
|
|
304
321
|
|
|
@@ -350,26 +367,181 @@ class Notification:
|
|
|
350
367
|
channel_id = channel_id.strip('_')
|
|
351
368
|
return channel_id[:50]
|
|
352
369
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
370
|
+
def __addIntentToOpenApp(self):
|
|
371
|
+
intent = Intent(context, PythonActivity)
|
|
372
|
+
action = str(self.identifer) or f"ACTION_{self.__id}"
|
|
373
|
+
intent.setAction(action)
|
|
374
|
+
self.__addDataToIntent(intent)
|
|
375
|
+
self.main_functions[action]=self.callback
|
|
376
|
+
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
|
377
|
+
|
|
378
|
+
pending_intent = PendingIntent.getActivity(
|
|
379
|
+
context, 0,
|
|
380
|
+
intent, PendingIntent.FLAG_IMMUTABLE if BuildVersion.SDK_INT >= 31 else PendingIntent.FLAG_UPDATE_CURRENT
|
|
381
|
+
)
|
|
382
|
+
self.__builder.setContentIntent(pending_intent)
|
|
383
|
+
self.__builder.setAutoCancel(True)
|
|
384
|
+
|
|
385
|
+
def __addDataToIntent(self,intent):
|
|
386
|
+
"""Persit Some data to notification object for later use"""
|
|
387
|
+
bundle = Bundle()
|
|
388
|
+
bundle.putString("title", self.title or 'Title Placeholder')
|
|
389
|
+
bundle.putInt("notify_id", self.__id)
|
|
390
|
+
intent.putExtras(bundle)
|
|
391
|
+
|
|
392
|
+
def __getIDForButton(self):
|
|
393
|
+
btn_id = self.button_ids[-1] + 1
|
|
394
|
+
self.button_ids.append(btn_id)
|
|
395
|
+
return btn_id
|
|
396
|
+
|
|
397
|
+
def addButton(self, text:str,on_release):
|
|
398
|
+
"""For adding action buttons
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
text (str): Text For Button
|
|
402
|
+
"""
|
|
403
|
+
if self.logs:
|
|
404
|
+
print('Added Button: ', text)
|
|
405
|
+
|
|
406
|
+
if not ON_ANDROID:
|
|
407
|
+
return
|
|
408
|
+
|
|
409
|
+
btn_id= self.__getIDForButton()
|
|
410
|
+
action = f"BTN_ACTION_{btn_id}"
|
|
411
|
+
|
|
412
|
+
action_intent = Intent(context, PythonActivity)
|
|
413
|
+
action_intent.setAction(action)
|
|
414
|
+
action_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
|
415
|
+
bundle = Bundle()
|
|
416
|
+
bundle.putString("title", self.title or 'Title Placeholder')
|
|
417
|
+
bundle.putInt("key_int", 123)
|
|
418
|
+
action_intent.putExtras(bundle)
|
|
419
|
+
action_intent.putExtra("button_id", btn_id)
|
|
420
|
+
|
|
421
|
+
self.btns_box[action] = on_release
|
|
422
|
+
# action_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
|
423
|
+
|
|
424
|
+
if self.logs:
|
|
425
|
+
print('Button id: ',btn_id)
|
|
426
|
+
pending_action_intent = PendingIntent.getActivity(
|
|
427
|
+
context,
|
|
428
|
+
0,
|
|
429
|
+
action_intent,
|
|
430
|
+
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
|
431
|
+
)
|
|
432
|
+
# Convert text to CharSequence
|
|
433
|
+
action_text = cast('java.lang.CharSequence', String(text))
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
# Add action with proper types
|
|
438
|
+
self.__builder.addAction(
|
|
439
|
+
int(context.getApplicationInfo().icon), # Cast icon to int
|
|
440
|
+
action_text, # CharSequence text
|
|
441
|
+
pending_action_intent # PendingIntent
|
|
442
|
+
)
|
|
443
|
+
# Set content intent for notification tap
|
|
444
|
+
self.__builder.setContentIntent(pending_action_intent)
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class NotificationHandler:
|
|
448
|
+
"""For Notification Operations """
|
|
449
|
+
__identifer = None
|
|
450
|
+
|
|
451
|
+
@classmethod
|
|
452
|
+
def getIdentifer(cls):
|
|
453
|
+
"""Returns identifer for Clicked Notification."""
|
|
454
|
+
if not cls.is_on_android():
|
|
455
|
+
return "Not on Android"
|
|
456
|
+
|
|
457
|
+
saved_intent = cls.__identifer
|
|
458
|
+
if not saved_intent or (isinstance(saved_intent, str) and saved_intent.startswith("android.intent")):
|
|
459
|
+
# All other notifications are not None after First notification opens app
|
|
460
|
+
# NOTE these notifications are also from Last time app was opened and they Still Give Value after first one opens App
|
|
461
|
+
# TODO Find a way to get intent when App if Swiped From recents
|
|
462
|
+
__PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
|
|
463
|
+
__mactivity = __PythonActivity.mActivity
|
|
464
|
+
__context = cast('android.content.Context', __mactivity)
|
|
465
|
+
__Intent = autoclass('android.content.Intent')
|
|
466
|
+
__intent = __Intent(__context, __PythonActivity)
|
|
467
|
+
action = __intent.getAction()
|
|
468
|
+
print('Start up Intent ----', action)
|
|
469
|
+
print('start Up Title --->',__intent.getStringExtra("title"))
|
|
470
|
+
|
|
471
|
+
return saved_intent
|
|
472
|
+
|
|
473
|
+
@classmethod
|
|
474
|
+
def __notificationHandler(cls,intent):
|
|
475
|
+
"""Calls Function Attached to notification on click.
|
|
476
|
+
Don't Call this function manual, it's Already Attach to Notification.
|
|
477
|
+
|
|
478
|
+
Returns:
|
|
479
|
+
str: The Identiter of Nofication that was clicked.
|
|
480
|
+
"""
|
|
481
|
+
if not cls.is_on_android():
|
|
482
|
+
return "Not on Android"
|
|
483
|
+
buttons_object=Notification.btns_box
|
|
484
|
+
notifty_functions=Notification.main_functions
|
|
485
|
+
if DEV:
|
|
486
|
+
print("notifty_functions ",notifty_functions)
|
|
487
|
+
print("buttons_object", buttons_object)
|
|
488
|
+
action = None
|
|
489
|
+
try:
|
|
490
|
+
action = intent.getAction()
|
|
491
|
+
cls.__identifer = action
|
|
492
|
+
|
|
493
|
+
print("The Action --> ",action)
|
|
494
|
+
if action == "android.intent.action.MAIN": # Not Open From Notification
|
|
495
|
+
return 'Not notification'
|
|
496
|
+
|
|
497
|
+
print(intent.getStringExtra("title"))
|
|
498
|
+
try:
|
|
499
|
+
if action in notifty_functions and notifty_functions[action]:
|
|
500
|
+
notifty_functions[action]()
|
|
501
|
+
elif action in buttons_object:
|
|
502
|
+
buttons_object[action]()
|
|
503
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
504
|
+
print('Failed to run function: ', traceback.format_exc())
|
|
505
|
+
print("Error Type ",e)
|
|
506
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
507
|
+
print('Notify Hanlder Failed ',e)
|
|
508
|
+
return action
|
|
509
|
+
|
|
510
|
+
@classmethod
|
|
511
|
+
def bindNotifyListener(cls):
|
|
512
|
+
"""Binds the notification listener.\n\n
|
|
513
|
+
```
|
|
514
|
+
from kivy.app import App
|
|
515
|
+
from android_notify import bindNotifyListener
|
|
516
|
+
class Myapp(App):
|
|
517
|
+
def on_start(self):
|
|
518
|
+
bindNotifyListener() # if successfull returns True
|
|
519
|
+
```
|
|
520
|
+
"""
|
|
521
|
+
if not cls.is_on_android():
|
|
522
|
+
return "Not on Android"
|
|
523
|
+
#Beta TODO Automatic bind when Notification object is called the first time use keep trying BroadcastReceiver
|
|
524
|
+
try:
|
|
525
|
+
activity.bind(on_new_intent=cls.__notificationHandler)
|
|
526
|
+
return True
|
|
527
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
528
|
+
print('Failed to bin notitfications listener',e)
|
|
529
|
+
return False
|
|
530
|
+
@classmethod
|
|
531
|
+
def unbindNotifyListener(cls):
|
|
532
|
+
"""Removes Listener for Notifications Click"""
|
|
533
|
+
if not cls.is_on_android():
|
|
534
|
+
return "Not on Android"
|
|
535
|
+
|
|
536
|
+
#Beta TODO use BroadcastReceiver
|
|
537
|
+
try:
|
|
538
|
+
activity.unbind(on_new_intent=cls.__notificationHandler)
|
|
539
|
+
return True
|
|
540
|
+
except Exception as e: # pylint: disable=broad-exception-caught
|
|
541
|
+
print("Failed to unbind notifications listener: ",e)
|
|
542
|
+
return False
|
|
543
|
+
|
|
544
|
+
@staticmethod
|
|
545
|
+
def is_on_android():
|
|
546
|
+
"""Utility to check if the app is running on Android."""
|
|
547
|
+
return ON_ANDROID
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: android-notify
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary: A Python package that simpilfies creating Android
|
|
3
|
+
Version: 1.5
|
|
4
|
+
Summary: A Python package that simpilfies creating Android notifications in Kivy apps.
|
|
5
5
|
Home-page: https://github.com/fector101/android-notify
|
|
6
6
|
Author: Fabian
|
|
7
7
|
Author-email: fector101@yahoo.com
|
|
@@ -21,22 +21,41 @@ Requires-Python: >=3.6
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
Requires-Dist: kivy>=2.0.0
|
|
23
23
|
Requires-Dist: pyjnius>=1.4.2
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: author-email
|
|
26
|
+
Dynamic: classifier
|
|
27
|
+
Dynamic: description
|
|
28
|
+
Dynamic: description-content-type
|
|
29
|
+
Dynamic: home-page
|
|
30
|
+
Dynamic: keywords
|
|
31
|
+
Dynamic: license
|
|
32
|
+
Dynamic: project-url
|
|
33
|
+
Dynamic: requires-dist
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
<div align="center">
|
|
38
|
+
<br>
|
|
39
|
+
<h1> Android-Notifiy </h1>
|
|
40
|
+
<p> A Python library for effortlessly creating and managing Android notifications in Kivy android apps.</p>
|
|
41
|
+
<p>Supports various styles and ensures seamless integration and customization.</p>
|
|
42
|
+
<!-- <br> -->
|
|
43
|
+
<!-- <img src="https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/democollage.jpg"> -->
|
|
44
|
+
</div>
|
|
29
45
|
|
|
30
46
|
## Features
|
|
31
47
|
|
|
32
|
-
- Compatible with Android 8.0+.
|
|
48
|
+
- Also Compatible with Android 8.0+.
|
|
33
49
|
- Supports including images in notifications.
|
|
50
|
+
- All Notifications can take Functions (version 1.5+) [functions docs](#functions).
|
|
34
51
|
- Support for multiple notification styles:
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
- Large Icon
|
|
52
|
+
- [Simple](#basic-usage)
|
|
53
|
+
- [Progress](#progress-bar-notification)
|
|
54
|
+
- [Big Picture](#notification-with-an-image-big-picture-style)
|
|
55
|
+
- [Inbox](#inbox-notification-style)
|
|
56
|
+
- [Large Icon](#notification-with-an-image-large-icon-style)
|
|
57
|
+
- [Buttons](#notification-with-buttons)
|
|
58
|
+
- [Big Text](#big-text-notification-will-display-as-simple-text-if-device-dosent-support)
|
|
40
59
|
|
|
41
60
|
This module automatically handles:
|
|
42
61
|
|
|
@@ -60,7 +79,7 @@ pip install android-notify
|
|
|
60
79
|
In your **`buildozer.spec`** file, ensure you include the following:
|
|
61
80
|
|
|
62
81
|
```ini
|
|
63
|
-
# Add pyjnius so it's packaged with the build
|
|
82
|
+
# Add pyjnius so ensure it's packaged with the build
|
|
64
83
|
requirements = python3, kivy, pyjnius, android-notify
|
|
65
84
|
|
|
66
85
|
# Add permission for notifications
|
|
@@ -81,7 +100,7 @@ from android_notify import Notification
|
|
|
81
100
|
# Create a simple notification
|
|
82
101
|
notification = Notification(
|
|
83
102
|
title="Hello",
|
|
84
|
-
message="This is a basic notification"
|
|
103
|
+
message="This is a basic notification."
|
|
85
104
|
)
|
|
86
105
|
notification.send()
|
|
87
106
|
```
|
|
@@ -104,6 +123,25 @@ The library supports multiple notification styles:
|
|
|
104
123
|
|
|
105
124
|
### Style Examples
|
|
106
125
|
|
|
126
|
+
#### Progress Bar notification
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from kivy.clock import Clock
|
|
130
|
+
|
|
131
|
+
notification = Notification(
|
|
132
|
+
title="Downloading...",
|
|
133
|
+
message="0% downloaded",
|
|
134
|
+
style="progress",
|
|
135
|
+
progress_max_value=100,
|
|
136
|
+
progress_current_value=0
|
|
137
|
+
)
|
|
138
|
+
notification.send()
|
|
139
|
+
Clock.schedule_once(lambda dt: notification.updateProgressBar(30, "30% downloaded"), 350)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Sample Image:**
|
|
143
|
+

|
|
144
|
+
|
|
107
145
|
#### Notification with an Image (Big Picture Style)
|
|
108
146
|
|
|
109
147
|
```python
|
|
@@ -114,6 +152,8 @@ notification = Notification(
|
|
|
114
152
|
style="big_picture",
|
|
115
153
|
big_picture_path="assets/imgs/photo.png"
|
|
116
154
|
)
|
|
155
|
+
notification.send()
|
|
156
|
+
|
|
117
157
|
```
|
|
118
158
|
|
|
119
159
|
**Sample Image:**
|
|
@@ -128,52 +168,60 @@ notification = Notification(
|
|
|
128
168
|
message='Line 1\nLine 2\nLine 3',
|
|
129
169
|
style='inbox'
|
|
130
170
|
)
|
|
171
|
+
notification.send()
|
|
172
|
+
|
|
131
173
|
```
|
|
132
174
|
|
|
133
175
|
**Sample Image:**
|
|
134
176
|

|
|
135
177
|
|
|
136
|
-
####
|
|
178
|
+
#### Notification with an Image (Large Icon Style)
|
|
137
179
|
|
|
138
180
|
```python
|
|
139
181
|
notification = Notification(
|
|
140
|
-
title="
|
|
141
|
-
message="
|
|
142
|
-
style="
|
|
182
|
+
title="FabianDev_",
|
|
183
|
+
message="A twitter about some programming stuff",
|
|
184
|
+
style="large_icon",
|
|
185
|
+
large_icon_path="assets/imgs/profile.png"
|
|
143
186
|
)
|
|
187
|
+
|
|
144
188
|
```
|
|
145
189
|
|
|
146
|
-
|
|
190
|
+
**Sample Image:**
|
|
191
|
+

|
|
192
|
+
|
|
193
|
+
#### Notification with Buttons
|
|
147
194
|
|
|
148
195
|
```python
|
|
149
|
-
notification = Notification(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
196
|
+
notification = Notification(title="Jane Dough", message="How to use android-notify #coding #purepython")
|
|
197
|
+
def playVideo():
|
|
198
|
+
print('Playing Video')
|
|
199
|
+
|
|
200
|
+
def turnOffNoti():
|
|
201
|
+
print('Please Turn OFf Noti')
|
|
202
|
+
|
|
203
|
+
def watchLater():
|
|
204
|
+
print('Add to Watch Later')
|
|
156
205
|
|
|
206
|
+
notification.addButton(text="Play",on_release=playVideo)
|
|
207
|
+
notification.addButton(text="Turn Off",on_release=turnOffNoti)
|
|
208
|
+
notification.addButton(text="Watch Later",on_release=watchLater)
|
|
209
|
+
notification.send()
|
|
157
210
|
```
|
|
158
211
|
|
|
159
|
-
**Sample Image:**
|
|
160
|
-

|
|
161
214
|
|
|
162
|
-
####
|
|
215
|
+
#### Big text notification (Will Display as normal text if Device dosen't support)
|
|
163
216
|
|
|
164
217
|
```python
|
|
165
218
|
notification = Notification(
|
|
166
|
-
title="
|
|
167
|
-
message="
|
|
168
|
-
style="
|
|
169
|
-
large_icon_path="assets/imgs/profile.png"
|
|
219
|
+
title="Article",
|
|
220
|
+
message="Long article content...",
|
|
221
|
+
style="big_text"
|
|
170
222
|
)
|
|
171
|
-
|
|
172
223
|
```
|
|
173
224
|
|
|
174
|
-
**Sample Image:**
|
|
175
|
-

|
|
176
|
-
|
|
177
225
|
## Advanced Features
|
|
178
226
|
|
|
179
227
|
### Updating Notifications
|
|
@@ -193,12 +241,12 @@ notification.updateMessage("New Message")
|
|
|
193
241
|
|
|
194
242
|
```python
|
|
195
243
|
notification = Notification(
|
|
196
|
-
title="Download
|
|
244
|
+
title="Download..",
|
|
197
245
|
style="progress"
|
|
198
246
|
)
|
|
199
247
|
|
|
200
248
|
# Update progress
|
|
201
|
-
notification.updateProgressBar(
|
|
249
|
+
notification.updateProgressBar(30, "30% downloaded")
|
|
202
250
|
|
|
203
251
|
# Remove progress bar
|
|
204
252
|
notification.removeProgressBar("Download Complete")
|
|
@@ -214,8 +262,8 @@ Notifications are organized into channels. You can customize the channel name an
|
|
|
214
262
|
notification = Notification(
|
|
215
263
|
title="Download finished",
|
|
216
264
|
message="How to Catch a Fish.mp4",
|
|
217
|
-
channel_name="Download Notifications", # Will create User-visible name "
|
|
218
|
-
channel_id="
|
|
265
|
+
channel_name="Download Notifications", # Will create User-visible name "Download Notifications"
|
|
266
|
+
channel_id="downloads_notifications" # Optional: specify custom channel ID
|
|
219
267
|
)
|
|
220
268
|
```
|
|
221
269
|
|
|
@@ -231,6 +279,60 @@ notification = Notification(title="Silent Update")
|
|
|
231
279
|
notification.send(silent=True)
|
|
232
280
|
```
|
|
233
281
|
|
|
282
|
+
## Functions
|
|
283
|
+
|
|
284
|
+
### NotificationHandler - To Attach Listener
|
|
285
|
+
|
|
286
|
+
Add this to your main.py App Class so it runs Once, In later Versions It'll be Attached Automatical
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
from kivymd.app import MDApp
|
|
290
|
+
from android_notify import Notification, NotificationHandler
|
|
291
|
+
|
|
292
|
+
class Myapp(MDApp):
|
|
293
|
+
|
|
294
|
+
def on_start(self):
|
|
295
|
+
# Is called Once when app is Starts up
|
|
296
|
+
NotificationHandler.bindNotifyListener() # if successfull returns True
|
|
297
|
+
Notification(title="Hello", message="This is a basic notification.",callback=self.doSomething).send()
|
|
298
|
+
|
|
299
|
+
def doSomething(self):
|
|
300
|
+
print("print in Debug Console")
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Get Which Notification was used to Open App - identifer (str)
|
|
304
|
+
|
|
305
|
+
If you just want to get the Exact Notification Clicked to Open App, you can use NotificationHandler to get unique identifer
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
from kivymd.app import MDApp
|
|
309
|
+
from android_notify import Notification, NotificationHandler
|
|
310
|
+
|
|
311
|
+
class Myapp(MDApp):
|
|
312
|
+
|
|
313
|
+
def on_start(self):
|
|
314
|
+
|
|
315
|
+
notify = Notification(title="Change Page", message="Click to change App page.", identifer='change_app_page')
|
|
316
|
+
notify.send()
|
|
317
|
+
|
|
318
|
+
notify1 = Notification(title="Change Colour", message="Click to change App Colour", identifer='change_app_color')
|
|
319
|
+
notify1.send()
|
|
320
|
+
|
|
321
|
+
NotificationHandler.bindNotifyListener()
|
|
322
|
+
|
|
323
|
+
def on_resume(self):
|
|
324
|
+
# Is called everytime app is reopened
|
|
325
|
+
notify_identifer = NotificationHandler.getIdentifer()
|
|
326
|
+
if notify_identifer == 'change_app_page':
|
|
327
|
+
# Code to change Screen
|
|
328
|
+
pass
|
|
329
|
+
elif notify_identifer == 'change_app_color':
|
|
330
|
+
# Code to change Screen Color
|
|
331
|
+
pass
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
234
336
|
### Assist
|
|
235
337
|
|
|
236
338
|
- How to Copy image to app folder
|
|
@@ -249,7 +351,7 @@ shutil.copy(image_path, os.path.join(app_path, "profile.png"))
|
|
|
249
351
|
|
|
250
352
|
```python
|
|
251
353
|
from android_notify import Notification, NotificationStyles
|
|
252
|
-
|
|
354
|
+
Notification(
|
|
253
355
|
title="New Photo",
|
|
254
356
|
message="Check out this image",
|
|
255
357
|
style=NotificationStyles.BIG_PICTURE,
|
|
@@ -273,7 +375,7 @@ notification.send()
|
|
|
273
375
|
|
|
274
376
|
## Image Requirements
|
|
275
377
|
|
|
276
|
-
- Images must be located within your app's
|
|
378
|
+
- Images must be located within your app's folder
|
|
277
379
|
- Supported paths are relative to your app's storage path
|
|
278
380
|
- Example: `assets/imgs/icon.png`
|
|
279
381
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
android_notify/__init__.py,sha256=lcLjyfegXgU7cyGhfSphAOBipXwemrVkdYy3mcF6X5Y,172
|
|
2
|
+
android_notify/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
android_notify/core.py,sha256=B3gOgbLGGI6tz-Q_T2wmk74oggOSDX0Qz4lqj00vaFo,6114
|
|
4
|
+
android_notify/styles.py,sha256=I2p31qStg9DaML9U4nXRvdpGzpppK6RS-qlDKuOv_Tk,328
|
|
5
|
+
android_notify/sword.py,sha256=6dmlTQRYtuhHUyO8E4fh3YlnLJC1FCvkLtgBKGvJnmI,23252
|
|
6
|
+
android_notify-1.5.dist-info/METADATA,sha256=D-xTAAdOyVgeK_kqcZL1cU_HAbwcFvJkwi6smOIE41Y,13161
|
|
7
|
+
android_notify-1.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
8
|
+
android_notify-1.5.dist-info/top_level.txt,sha256=IR1ONMrRSRINZpWn2X0dL5gbWwWINsK7PW8Jy2p4fU8,15
|
|
9
|
+
android_notify-1.5.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
android_notify/__init__.py,sha256=dAcsj7M_KHBOira9AVk4LtFFXRHTYsn6tza4Oz7T1MM,107
|
|
2
|
-
android_notify/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
android_notify/core.py,sha256=hHzBnVw25x_WpMHp_HPKCuHEL2mQ7IHC_I3EqQZylas,6081
|
|
4
|
-
android_notify/styles.py,sha256=I2p31qStg9DaML9U4nXRvdpGzpppK6RS-qlDKuOv_Tk,328
|
|
5
|
-
android_notify/sword.py,sha256=8v28Q9x3CRRa3xDbHUd8629S5KvLy7xnjSygbqT-coQ,16271
|
|
6
|
-
android_notify-1.3.dist-info/METADATA,sha256=fA2YdjiuZKnEWirQdnzci1l4di-EXmphkdlp41I0FzU,9831
|
|
7
|
-
android_notify-1.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
8
|
-
android_notify-1.3.dist-info/top_level.txt,sha256=IR1ONMrRSRINZpWn2X0dL5gbWwWINsK7PW8Jy2p4fU8,15
|
|
9
|
-
android_notify-1.3.dist-info/RECORD,,
|
|
File without changes
|