android-notify 1.55__tar.gz → 1.57__tar.gz
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-1.55 → android_notify-1.57}/PKG-INFO +5 -1
- {android_notify-1.55 → android_notify-1.57}/README.md +4 -0
- android_notify-1.57/android_notify/base.py +82 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify/styles.py +3 -3
- {android_notify-1.55 → android_notify-1.57}/android_notify/sword.py +80 -143
- android_notify-1.57/android_notify/types_idea.py +72 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify.egg-info/PKG-INFO +5 -1
- {android_notify-1.55 → android_notify-1.57}/android_notify.egg-info/SOURCES.txt +2 -1
- {android_notify-1.55 → android_notify-1.57}/setup.py +1 -1
- android_notify-1.55/android_notify/facade.py +0 -28
- {android_notify-1.55 → android_notify-1.57}/android_notify/__init__.py +0 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify/__main__.py +0 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify/core.py +0 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify.egg-info/dependency_links.txt +0 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify.egg-info/requires.txt +0 -0
- {android_notify-1.55 → android_notify-1.57}/android_notify.egg-info/top_level.txt +0 -0
- {android_notify-1.55 → android_notify-1.57}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: android-notify
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.57
|
|
4
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
|
|
@@ -464,6 +464,10 @@ args
|
|
|
464
464
|
|
|
465
465
|
- new_message : String to be set as New notification Message
|
|
466
466
|
|
|
467
|
+
### Instance.showInfiniteProgressBar
|
|
468
|
+
|
|
469
|
+
Displays an Infinite Progress Bar in Notification, Can be Removed using `removeProgressBar` and updated using `updateProgressBar` method
|
|
470
|
+
|
|
467
471
|
### Instance.updateProgressBar
|
|
468
472
|
|
|
469
473
|
if updating title,msg with progressbar frequenlty pass them in too to avoid update issues.
|
|
@@ -428,6 +428,10 @@ args
|
|
|
428
428
|
|
|
429
429
|
- new_message : String to be set as New notification Message
|
|
430
430
|
|
|
431
|
+
### Instance.showInfiniteProgressBar
|
|
432
|
+
|
|
433
|
+
Displays an Infinite Progress Bar in Notification, Can be Removed using `removeProgressBar` and updated using `updateProgressBar` method
|
|
434
|
+
|
|
431
435
|
### Instance.updateProgressBar
|
|
432
436
|
|
|
433
437
|
if updating title,msg with progressbar frequenlty pass them in too to avoid update issues.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Assists Notification Class with Args keeps sub class cleaner"""
|
|
2
|
+
from dataclasses import dataclass, fields
|
|
3
|
+
import difflib
|
|
4
|
+
from .styles import NotificationStyles
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class BaseNotification:
|
|
8
|
+
"""Encapsulator"""
|
|
9
|
+
|
|
10
|
+
# Basic options
|
|
11
|
+
title: str = ''
|
|
12
|
+
message: str = ''
|
|
13
|
+
style: str = 'simple'
|
|
14
|
+
|
|
15
|
+
# Style-specific attributes
|
|
16
|
+
big_picture_path: str = ''
|
|
17
|
+
large_icon_path: str = ''
|
|
18
|
+
progress_max_value: int = 100
|
|
19
|
+
progress_current_value: float = 0.0 # Also Takes in Ints
|
|
20
|
+
body: str = ''
|
|
21
|
+
|
|
22
|
+
# Notification Functions
|
|
23
|
+
identifer: str = ''
|
|
24
|
+
callback: object = None
|
|
25
|
+
|
|
26
|
+
# Advanced Options
|
|
27
|
+
app_icon: str = 'Defaults to package app icon'
|
|
28
|
+
channel_name: str = 'Default Channel'
|
|
29
|
+
channel_id: str = 'default_channel'
|
|
30
|
+
silent: bool = False
|
|
31
|
+
logs: bool = False
|
|
32
|
+
|
|
33
|
+
def __init__(self, **kwargs):
|
|
34
|
+
"""Custom init to handle validation before dataclass assigns values"""
|
|
35
|
+
# Validate provided arguments
|
|
36
|
+
self.validate_args(kwargs)
|
|
37
|
+
|
|
38
|
+
# Assign validated values using the normal dataclass behavior
|
|
39
|
+
for field_ in fields(self):
|
|
40
|
+
field_name = field_.name
|
|
41
|
+
setattr(self, field_name, kwargs.get(field_name, getattr(self, field_name)))
|
|
42
|
+
|
|
43
|
+
def validate_args(self, inputted_kwargs):
|
|
44
|
+
"""Check for unexpected arguments and suggest corrections before Python validation"""
|
|
45
|
+
default_fields = {field.name : field.type for field in fields(self)} #{'title': <class 'str'>, 'message': <class 'str'>,...
|
|
46
|
+
allowed_fields_keys = set(default_fields.keys())
|
|
47
|
+
|
|
48
|
+
# Identify invalid arguments
|
|
49
|
+
invalid_args = set(inputted_kwargs) - allowed_fields_keys
|
|
50
|
+
if invalid_args:
|
|
51
|
+
suggestions = []
|
|
52
|
+
for arg in invalid_args:
|
|
53
|
+
closest_match = difflib.get_close_matches(arg, allowed_fields_keys, n=1, cutoff=0.6)
|
|
54
|
+
if closest_match:
|
|
55
|
+
suggestions.append(f"* '{arg}' is invalid -> Did you mean '{closest_match[0]}'?")
|
|
56
|
+
else:
|
|
57
|
+
suggestions.append(f"* '{arg}' is not a valid argument.")
|
|
58
|
+
|
|
59
|
+
suggestion_text = '\n'.join(suggestions)
|
|
60
|
+
raise ValueError(f"Invalid arguments provided:\n{suggestion_text}")
|
|
61
|
+
|
|
62
|
+
# Validating types
|
|
63
|
+
for each_arg in inputted_kwargs.keys():
|
|
64
|
+
expected_type = default_fields[each_arg]
|
|
65
|
+
actual_value = inputted_kwargs[each_arg]
|
|
66
|
+
|
|
67
|
+
# Allow both int and float for progress_current_value
|
|
68
|
+
if each_arg == "progress_current_value":
|
|
69
|
+
if not isinstance(actual_value, (int, float)):
|
|
70
|
+
raise TypeError(f"Expected '{each_arg}' to be int or float, got {type(actual_value)} instead.")
|
|
71
|
+
else:
|
|
72
|
+
if not isinstance(actual_value, expected_type):
|
|
73
|
+
raise TypeError(f"Expected '{each_arg}' to be {expected_type}, got {type(actual_value)} instead.")
|
|
74
|
+
|
|
75
|
+
# Validate `style` values
|
|
76
|
+
style_values = [value for key, value in vars(NotificationStyles).items() if not key.startswith("__")]
|
|
77
|
+
if 'style' in inputted_kwargs and inputted_kwargs['style'] not in ['',*style_values]:
|
|
78
|
+
inputted_style=inputted_kwargs['style']
|
|
79
|
+
allowed_styles=', '.join(style_values)
|
|
80
|
+
raise ValueError(
|
|
81
|
+
f"Invalid style '{inputted_style}'. Allowed styles: {allowed_styles}"
|
|
82
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Contains Safe way to call Styles"""
|
|
2
2
|
|
|
3
|
-
class NotificationStyles
|
|
3
|
+
class NotificationStyles:
|
|
4
4
|
""" Safely Adding Styles"""
|
|
5
5
|
DEFAULT = "simple"
|
|
6
6
|
|
|
@@ -12,5 +12,5 @@ class NotificationStyles():
|
|
|
12
12
|
BIG_PICTURE = "big_picture"
|
|
13
13
|
BOTH_IMGS = "both_imgs"
|
|
14
14
|
|
|
15
|
-
MESSAGING = "messaging" # TODO
|
|
16
|
-
CUSTOM = "custom" # TODO
|
|
15
|
+
# MESSAGING = "messaging" # TODO
|
|
16
|
+
# CUSTOM = "custom" # TODO
|
|
@@ -5,7 +5,7 @@ import os
|
|
|
5
5
|
import threading
|
|
6
6
|
import re
|
|
7
7
|
from .styles import NotificationStyles
|
|
8
|
-
from .
|
|
8
|
+
from .base import BaseNotification
|
|
9
9
|
DEV=0
|
|
10
10
|
ON_ANDROID = False
|
|
11
11
|
|
|
@@ -31,7 +31,8 @@ try:
|
|
|
31
31
|
ON_ANDROID = True
|
|
32
32
|
except Exception as e:# pylint: disable=W0718
|
|
33
33
|
MESSAGE='This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.' # pylint: disable=C0301
|
|
34
|
-
|
|
34
|
+
# from .types_idea import *
|
|
35
|
+
# print(MESSAGE) Already Printing in core.py
|
|
35
36
|
|
|
36
37
|
# This is so no crashes when developing on PC
|
|
37
38
|
def run_on_ui_thread(func):
|
|
@@ -55,8 +56,7 @@ if ON_ANDROID:
|
|
|
55
56
|
NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle') # pylint: disable=C0301
|
|
56
57
|
NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
|
|
57
58
|
except Exception as e:# pylint: disable=W0718
|
|
58
|
-
print(e)
|
|
59
|
-
# print(e if DEV else '')
|
|
59
|
+
print(e)
|
|
60
60
|
print("""
|
|
61
61
|
Dependency Error: Add the following in buildozer.spec:
|
|
62
62
|
* android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
|
|
@@ -91,46 +91,28 @@ class Notification(BaseNotification):
|
|
|
91
91
|
button_ids=[0]
|
|
92
92
|
btns_box={}
|
|
93
93
|
main_functions={}
|
|
94
|
-
style_values=[
|
|
95
|
-
'','simple',
|
|
96
|
-
'progress','big_text',
|
|
97
|
-
'inbox', 'big_picture',
|
|
98
|
-
'large_icon','both_imgs',
|
|
99
|
-
'custom'
|
|
100
|
-
] # TODO make pattern for non-android Notifications
|
|
101
|
-
defaults={
|
|
102
|
-
'title':'Default Title',
|
|
103
|
-
'message':'Default Message',
|
|
104
|
-
'style':'simple',
|
|
105
|
-
'big_picture_path':'',
|
|
106
|
-
'large_icon_path':'',
|
|
107
|
-
'progress_max_value': 0.5,
|
|
108
|
-
'progress_current_value': 0.5,
|
|
109
|
-
'body':'',
|
|
110
|
-
'channel_name':'Default Channel',
|
|
111
|
-
'channel_id':'default_channel',
|
|
112
|
-
'logs':True,
|
|
113
|
-
"identifer": '',
|
|
114
|
-
'callback': None,
|
|
115
|
-
'app_icon': 'Defaults to package app icon'
|
|
116
|
-
}
|
|
117
94
|
|
|
118
95
|
# During Development (When running on PC)
|
|
119
|
-
logs=not ON_ANDROID
|
|
96
|
+
BaseNotification.logs=not ON_ANDROID
|
|
120
97
|
def __init__(self,**kwargs): #pylint: disable=W0231 #@dataclass already does work
|
|
121
|
-
|
|
122
|
-
|
|
98
|
+
super().__init__(**kwargs)
|
|
99
|
+
|
|
123
100
|
self.__id = self.__getUniqueID()
|
|
124
|
-
self.__setArgs(kwargs)
|
|
125
101
|
self.__update_timer = None # To Track progressbar last update (According to Android Docs Don't update bar to often, I also faced so issues when doing that)
|
|
126
|
-
|
|
102
|
+
self.__formatChannel(kwargs)
|
|
127
103
|
if not ON_ANDROID:
|
|
128
104
|
return
|
|
129
105
|
# TODO make send method wait for __asks_permission_if_needed method
|
|
130
106
|
self.__asks_permission_if_needed()
|
|
131
107
|
self.notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
|
|
132
108
|
self.__builder=NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
|
|
133
|
-
|
|
109
|
+
def showInfiniteProgressBar(self):
|
|
110
|
+
"""Displays an (Infinite) progress Bar in Notification, that continues loading indefinitely.
|
|
111
|
+
Can be Removed By `removeProgressBar` Method
|
|
112
|
+
"""
|
|
113
|
+
self.__builder.setProgress(0,0, True)
|
|
114
|
+
self.__dispatchNotification()
|
|
115
|
+
|
|
134
116
|
def updateTitle(self,new_title):
|
|
135
117
|
"""Changes Old Title
|
|
136
118
|
|
|
@@ -142,7 +124,7 @@ class Notification(BaseNotification):
|
|
|
142
124
|
print(f'new notification title: {self.title}')
|
|
143
125
|
if ON_ANDROID:
|
|
144
126
|
self.__builder.setContentTitle(String(self.title))
|
|
145
|
-
self.
|
|
127
|
+
self.__dispatchNotification()
|
|
146
128
|
|
|
147
129
|
def updateMessage(self,new_message):
|
|
148
130
|
"""Changes Old Message
|
|
@@ -155,49 +137,49 @@ class Notification(BaseNotification):
|
|
|
155
137
|
print(f'new notification message: {self.message}')
|
|
156
138
|
if ON_ANDROID:
|
|
157
139
|
self.__builder.setContentText(String(self.message))
|
|
158
|
-
self.
|
|
140
|
+
self.__dispatchNotification()
|
|
159
141
|
|
|
160
|
-
def updateProgressBar(self,current_value:int,message:str='',title:str=''):
|
|
142
|
+
def updateProgressBar(self,current_value:int,message:str='',title:str='',buffer=0.5):
|
|
161
143
|
"""Updates progress bar current value
|
|
162
144
|
|
|
163
145
|
Args:
|
|
164
146
|
current_value (int): the value from progressbar current progress
|
|
165
147
|
message (str): defaults to last message
|
|
166
148
|
title (str): defaults to last title
|
|
167
|
-
|
|
168
|
-
NOTE: There is a 0.5sec delay, if updating title,msg with progressbar frequenlty pass them in too to avoid update issues
|
|
149
|
+
buffer (float, optional): Avoid Updating progressbar value too frequently Defaults to 0.5secs
|
|
150
|
+
NOTE: There is a 0.5sec delay for value change, if updating title,msg with progressbar frequenlty pass them in too to avoid update issues
|
|
169
151
|
"""
|
|
152
|
+
# replacing new value for when timer is called
|
|
153
|
+
self.progress_current_value = current_value
|
|
170
154
|
|
|
171
|
-
# Cancel any existing timer before setting a new one
|
|
172
155
|
if self.__update_timer:
|
|
173
|
-
self.
|
|
174
|
-
|
|
175
|
-
|
|
156
|
+
if self.logs:
|
|
157
|
+
print('Progressbar update too soon Doing bounce 0.5sec')
|
|
158
|
+
return
|
|
159
|
+
|
|
176
160
|
def delayed_update():
|
|
177
161
|
if self.__update_timer is None:
|
|
178
162
|
# Ensure we are not executing an old timer
|
|
179
163
|
return
|
|
180
164
|
if self.logs:
|
|
181
|
-
print(f'Progress Bar Update value: {
|
|
165
|
+
print(f'Progress Bar Update value: {self.progress_current_value}')
|
|
182
166
|
|
|
183
|
-
self.progress_current_value = current_value
|
|
184
|
-
|
|
185
167
|
if not ON_ANDROID:
|
|
186
168
|
return
|
|
187
|
-
self.__builder.setProgress(self.progress_max_value,
|
|
169
|
+
self.__builder.setProgress(self.progress_max_value, self.progress_current_value, False)
|
|
188
170
|
if message:
|
|
189
171
|
self.updateMessage(message)
|
|
190
172
|
if title:
|
|
191
173
|
self.updateTitle(title)
|
|
192
|
-
self.
|
|
174
|
+
self.__dispatchNotification()
|
|
193
175
|
self.__update_timer = None
|
|
194
176
|
|
|
195
177
|
|
|
196
178
|
# Start a new timer that runs after 0.5 seconds
|
|
197
179
|
self.__update_timer = threading.Timer(0.5, delayed_update)
|
|
198
180
|
self.__update_timer.start()
|
|
199
|
-
|
|
200
|
-
def removeProgressBar(self,message='',show_on_update=True, title:str='') ->
|
|
181
|
+
|
|
182
|
+
def removeProgressBar(self,message='',show_on_update=True, title:str='') -> bool:
|
|
201
183
|
"""Removes Progress Bar from Notification
|
|
202
184
|
|
|
203
185
|
Args:
|
|
@@ -223,7 +205,7 @@ class Notification(BaseNotification):
|
|
|
223
205
|
if title:
|
|
224
206
|
self.updateTitle(title)
|
|
225
207
|
self.__builder.setProgress(0, 0, False)
|
|
226
|
-
self.
|
|
208
|
+
self.__dispatchNotification()
|
|
227
209
|
return True
|
|
228
210
|
|
|
229
211
|
def send(self,silent:bool=False,persistent=False,close_on_click=True):
|
|
@@ -237,13 +219,18 @@ class Notification(BaseNotification):
|
|
|
237
219
|
self.silent=self.silent or silent
|
|
238
220
|
if ON_ANDROID:
|
|
239
221
|
self.__startNotificationBuild(persistent,close_on_click)
|
|
240
|
-
self.
|
|
241
|
-
|
|
222
|
+
self.__dispatchNotification()
|
|
223
|
+
if self.logs:
|
|
242
224
|
string_to_display=''
|
|
243
225
|
print("\n Sent Notification!!!")
|
|
244
226
|
for name,value in vars(self).items():
|
|
245
227
|
if value and name in ["title", "message", "style", "body", "large_icon_path", "big_picture_path", "progress_current_value", "progress_max_value", "channel_name"]:
|
|
246
|
-
|
|
228
|
+
if name == "progress_max_value":
|
|
229
|
+
if self.style == NotificationStyles.PROGRESS:
|
|
230
|
+
string_to_display += f'\n {name}: {value}'
|
|
231
|
+
else:
|
|
232
|
+
string_to_display += f'\n {name}: {value}'
|
|
233
|
+
|
|
247
234
|
string_to_display +="\n (Won't Print Logs When Complied,except if selected `Notification.logs=True`)"
|
|
248
235
|
print(string_to_display)
|
|
249
236
|
if DEV:
|
|
@@ -304,7 +291,7 @@ class Notification(BaseNotification):
|
|
|
304
291
|
"""
|
|
305
292
|
if ON_ANDROID:
|
|
306
293
|
self.__builder.mActions.clear()
|
|
307
|
-
self.
|
|
294
|
+
self.__dispatchNotification()
|
|
308
295
|
if self.logs:
|
|
309
296
|
print('Removed Notication Buttons')
|
|
310
297
|
|
|
@@ -315,6 +302,7 @@ class Notification(BaseNotification):
|
|
|
315
302
|
|
|
316
303
|
Args:
|
|
317
304
|
style (str): required style
|
|
305
|
+
already_sent (bool,False): If notification was already sent
|
|
318
306
|
"""
|
|
319
307
|
|
|
320
308
|
if not ON_ANDROID:
|
|
@@ -343,60 +331,17 @@ class Notification(BaseNotification):
|
|
|
343
331
|
self.__buildImg(self.large_icon_path, NotificationStyles.LARGE_ICON)
|
|
344
332
|
|
|
345
333
|
elif style == NotificationStyles.PROGRESS:
|
|
346
|
-
self.__builder.setContentTitle(String(self.title))
|
|
347
|
-
self.__builder.setContentText(String(self.message))
|
|
348
334
|
self.__builder.setProgress(self.progress_max_value, self.progress_current_value, False)
|
|
349
335
|
|
|
350
336
|
if already_sent:
|
|
351
|
-
self.
|
|
337
|
+
self.__dispatchNotification()
|
|
352
338
|
|
|
353
339
|
return True
|
|
354
340
|
# elif style == 'custom':
|
|
355
341
|
# self.__builder = self.__doCustomStyle()
|
|
356
342
|
|
|
357
|
-
def
|
|
358
|
-
|
|
359
|
-
def checkInReference(inputted_keywords,accepteable_inputs,input_type):
|
|
360
|
-
def singularForm(plural_form):
|
|
361
|
-
return plural_form[:-1]
|
|
362
|
-
invalid_args= set(inputted_keywords) - set(accepteable_inputs)
|
|
363
|
-
if invalid_args:
|
|
364
|
-
suggestions=[]
|
|
365
|
-
for arg in invalid_args:
|
|
366
|
-
closest_match = difflib.get_close_matches(arg,accepteable_inputs,n=2,cutoff=0.6)
|
|
367
|
-
if closest_match:
|
|
368
|
-
suggestions.append(f"* '{arg}' Invalid -> Did you mean '{closest_match[0]}'? ") # pylint: disable=C0301
|
|
369
|
-
else:
|
|
370
|
-
suggestions.append(f"* {arg} is not a valid {singularForm(input_type)}.")
|
|
371
|
-
suggestion_text='\n'.join(suggestions)
|
|
372
|
-
hint_msg=singularForm(input_type) if len(invalid_args) < 2 else input_type
|
|
373
|
-
|
|
374
|
-
raise ValueError(f"Invalid {hint_msg} provided: \n\t{suggestion_text}\n\t* list of valid {input_type}: [{', '.join(accepteable_inputs)}]")
|
|
375
|
-
|
|
376
|
-
allowed_keywords=self.defaults.keys()
|
|
377
|
-
inputted_keywords_=inputted_kwargs.keys()
|
|
378
|
-
checkInReference(inputted_keywords_,allowed_keywords,'arguments')
|
|
379
|
-
|
|
380
|
-
# Validate style values
|
|
381
|
-
if 'style' in inputted_keywords_ and inputted_kwargs['style'] not in self.style_values:
|
|
382
|
-
checkInReference([inputted_kwargs['style']],self.style_values,'values')
|
|
383
|
-
|
|
384
|
-
def __setArgs(self,options_dict:dict):
|
|
385
|
-
non_string_keys=['progress_max_value','progress_current_value','callback','logs']
|
|
386
|
-
|
|
387
|
-
for key,value in options_dict.items():
|
|
388
|
-
if key not in non_string_keys: # Fixing Types
|
|
389
|
-
value = str(value)
|
|
390
|
-
if key == 'channel_name' and value.strip():
|
|
391
|
-
setattr(self,key, value[:40])
|
|
392
|
-
elif key == 'channel_id' and value.strip(): # If user input's a channel id (i format properly)
|
|
393
|
-
setattr(self,key, self.__generate_channel_id(value))
|
|
394
|
-
else:
|
|
395
|
-
setattr(self,key, value if value or isinstance(value, bool) else self.defaults[key])
|
|
396
|
-
|
|
397
|
-
if "channel_id" not in options_dict and 'channel_name' in options_dict: # if User doesn't input channel id but inputs channel_name
|
|
398
|
-
setattr(self,'channel_id', self.__generate_channel_id(options_dict['channel_name']))
|
|
399
|
-
|
|
343
|
+
def __dispatchNotification(self):
|
|
344
|
+
self.notification_manager.notify(self.__id, self.__builder.build())
|
|
400
345
|
def __startNotificationBuild(self,persistent,close_on_click):
|
|
401
346
|
self.__createBasicNotification(persistent,close_on_click)
|
|
402
347
|
if self.style not in ['simple','']:
|
|
@@ -427,7 +372,7 @@ class Notification(BaseNotification):
|
|
|
427
372
|
self.__builder.setOngoing(persistent)
|
|
428
373
|
self.__builder.setAutoCancel(close_on_click)
|
|
429
374
|
self.__addIntentToOpenApp()
|
|
430
|
-
|
|
375
|
+
|
|
431
376
|
# def __doCustomStyle(self):
|
|
432
377
|
# # TODO Will implement when needed
|
|
433
378
|
# return self.__builder
|
|
@@ -436,7 +381,7 @@ class Notification(BaseNotification):
|
|
|
436
381
|
self.__setIconFromBitmap(self.app_icon)
|
|
437
382
|
else:
|
|
438
383
|
self.__builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
439
|
-
|
|
384
|
+
|
|
440
385
|
def __buildImg(self, user_img,img_style):
|
|
441
386
|
if user_img.startswith('http://') or user_img.startswith('https://'):
|
|
442
387
|
def callback(bitmap):
|
|
@@ -450,7 +395,7 @@ class Notification(BaseNotification):
|
|
|
450
395
|
bitmap = self.__getImgFromPath(user_img)
|
|
451
396
|
if bitmap:
|
|
452
397
|
self.__applyNotificationImage(bitmap,img_style)
|
|
453
|
-
|
|
398
|
+
|
|
454
399
|
def __setIconFromBitmap(self,img_path):
|
|
455
400
|
"""Path can be link or relative path"""
|
|
456
401
|
if img_path.startswith('http://') or img_path.startswith('https://'):
|
|
@@ -470,8 +415,7 @@ class Notification(BaseNotification):
|
|
|
470
415
|
if self.logs:
|
|
471
416
|
print('Failed getting img for custom notification icon defaulting to app icon')
|
|
472
417
|
self.__builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
473
|
-
|
|
474
|
-
|
|
418
|
+
|
|
475
419
|
def __getImgFromPath(self, relative_path):
|
|
476
420
|
app_folder=os.path.join(app_storage_path(),'app') # pylint: disable=possibly-used-before-assignment
|
|
477
421
|
output_path = os.path.join(app_folder, relative_path)
|
|
@@ -511,25 +455,6 @@ class Notification(BaseNotification):
|
|
|
511
455
|
print('Error Type ',e)
|
|
512
456
|
print('Failed to get Bitmap from URL ',traceback.format_exc())
|
|
513
457
|
|
|
514
|
-
# def __getImgFromURL(self,url,img_style):
|
|
515
|
-
# if self.logs:
|
|
516
|
-
# print("getting image from URL---")
|
|
517
|
-
# try:
|
|
518
|
-
# URL = autoclass('java.net.URL')
|
|
519
|
-
# url = URL(url)
|
|
520
|
-
# connection = url.openConnection()
|
|
521
|
-
# connection.connect()
|
|
522
|
-
# input_stream = connection.getInputStream()
|
|
523
|
-
# bitmap = BitmapFactory.decodeStream(input_stream)
|
|
524
|
-
# input_stream.close()
|
|
525
|
-
# if bitmap:
|
|
526
|
-
# self.__applyNotificationImage(bitmap,img_style)
|
|
527
|
-
|
|
528
|
-
# except Exception as e:
|
|
529
|
-
# # TODO get type of JAVA Error
|
|
530
|
-
# print('Error Type ',e)
|
|
531
|
-
# print('Failed to get Img from URL ',traceback.format_exc())
|
|
532
|
-
|
|
533
458
|
@run_on_ui_thread
|
|
534
459
|
def __applyNotificationImage(self,bitmap,img_style):
|
|
535
460
|
if self.logs:
|
|
@@ -540,7 +465,7 @@ class Notification(BaseNotification):
|
|
|
540
465
|
self.__builder.setStyle(big_picture_style)
|
|
541
466
|
elif img_style == NotificationStyles.LARGE_ICON:
|
|
542
467
|
self.__builder.setLargeIcon(bitmap)
|
|
543
|
-
self.
|
|
468
|
+
self.__dispatchNotification()
|
|
544
469
|
if self.logs:
|
|
545
470
|
print('Done adding image to notification-------')
|
|
546
471
|
except Exception as e:
|
|
@@ -565,24 +490,6 @@ class Notification(BaseNotification):
|
|
|
565
490
|
if not all(check_permission(p) for p in permissions):
|
|
566
491
|
request_permissions(permissions,on_permissions_result) # pylint: disable=E0606
|
|
567
492
|
|
|
568
|
-
def __generate_channel_id(self,channel_name: str) -> str:
|
|
569
|
-
"""
|
|
570
|
-
Generate a readable and consistent channel ID from a channel name.
|
|
571
|
-
|
|
572
|
-
Args:
|
|
573
|
-
channel_name (str): The name of the notification channel.
|
|
574
|
-
|
|
575
|
-
Returns:
|
|
576
|
-
str: A sanitized channel ID.
|
|
577
|
-
"""
|
|
578
|
-
# Normalize the channel name
|
|
579
|
-
channel_id = channel_name.strip().lower()
|
|
580
|
-
# Replace spaces and special characters with underscores
|
|
581
|
-
channel_id = re.sub(r'[^a-z0-9]+', '_', channel_id)
|
|
582
|
-
# Remove leading/trailing underscores
|
|
583
|
-
channel_id = channel_id.strip('_')
|
|
584
|
-
return channel_id[:50]
|
|
585
|
-
|
|
586
493
|
def __addIntentToOpenApp(self):
|
|
587
494
|
intent = Intent(context, PythonActivity)
|
|
588
495
|
action = str(self.identifer) or f"ACTION_{self.__id}"
|
|
@@ -609,6 +516,36 @@ class Notification(BaseNotification):
|
|
|
609
516
|
self.button_ids.append(btn_id)
|
|
610
517
|
return btn_id
|
|
611
518
|
|
|
519
|
+
def __formatChannel(self, inputted_kwargs):
|
|
520
|
+
if 'channel_name' in inputted_kwargs:
|
|
521
|
+
cleaned_name = inputted_kwargs['channel_name'].strip()
|
|
522
|
+
self.channel_name = cleaned_name[:40] if cleaned_name else 'Default Channel'
|
|
523
|
+
|
|
524
|
+
if 'channel_id' in inputted_kwargs:
|
|
525
|
+
cleaned_id = inputted_kwargs['channel_id'].strip()
|
|
526
|
+
self.channel_id = self.__generate_channel_id(cleaned_id) if cleaned_id else 'default_channel'
|
|
527
|
+
elif 'channel_name' in inputted_kwargs:
|
|
528
|
+
# Generate channel_id from channel_name if only channel_name is provided
|
|
529
|
+
generated_id = self.__generate_channel_id(inputted_kwargs['channel_name'])
|
|
530
|
+
self.channel_id = generated_id
|
|
531
|
+
|
|
532
|
+
def __generate_channel_id(self,channel_name: str) -> str:
|
|
533
|
+
"""
|
|
534
|
+
Generate a readable and consistent channel ID from a channel name.
|
|
535
|
+
|
|
536
|
+
Args:
|
|
537
|
+
channel_name (str): The name of the notification channel.
|
|
538
|
+
|
|
539
|
+
Returns:
|
|
540
|
+
str: A sanitized channel ID.
|
|
541
|
+
"""
|
|
542
|
+
# Normalize the channel name
|
|
543
|
+
channel_id = channel_name.strip().lower()
|
|
544
|
+
# Replace spaces and special characters with underscores
|
|
545
|
+
channel_id = re.sub(r'[^a-z0-9]+', '_', channel_id)
|
|
546
|
+
# Remove leading/trailing underscores
|
|
547
|
+
channel_id = channel_id.strip('_')
|
|
548
|
+
return channel_id[:50]
|
|
612
549
|
|
|
613
550
|
class NotificationHandler:
|
|
614
551
|
"""For Notification Operations """
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# class Bundle:
|
|
2
|
+
# pass
|
|
3
|
+
# class PythonActivity:
|
|
4
|
+
# mActivity=''# Get the app's context
|
|
5
|
+
# pass
|
|
6
|
+
# class String(str):
|
|
7
|
+
# pass
|
|
8
|
+
# class Intent:
|
|
9
|
+
# def __init__(self,context,activity):
|
|
10
|
+
# pass
|
|
11
|
+
# class PendingIntent:
|
|
12
|
+
# FLAG_IMMUTABLE=''
|
|
13
|
+
# FLAG_UPDATE_CURRENT=''
|
|
14
|
+
# def getActivity(self,context,value,action_intent,pending_intent_type):
|
|
15
|
+
# pass
|
|
16
|
+
# class BitmapFactory:
|
|
17
|
+
# def decodeStream(self,stream):
|
|
18
|
+
# pass
|
|
19
|
+
# class BuildVersion:
|
|
20
|
+
# SDK_INT=0
|
|
21
|
+
# class NotificationManager:
|
|
22
|
+
# pass
|
|
23
|
+
# class NotificationChannel:
|
|
24
|
+
# def __init__(self,channel_id,channel_name,importance):
|
|
25
|
+
# pass
|
|
26
|
+
# def createNotificationChannel(self, channel):
|
|
27
|
+
# pass
|
|
28
|
+
#
|
|
29
|
+
# def getNotificationChannel(self, channel_id):
|
|
30
|
+
# pass
|
|
31
|
+
# class IconCompat:
|
|
32
|
+
# def createWithBitmap(self,bitmap):
|
|
33
|
+
# pass
|
|
34
|
+
#
|
|
35
|
+
# class NotificationManagerCompat:
|
|
36
|
+
# IMPORTANCE_DEFAULT=3
|
|
37
|
+
# IMPORTANCE_HIGH=4
|
|
38
|
+
#
|
|
39
|
+
#
|
|
40
|
+
# class NotificationCompat:
|
|
41
|
+
# DEFAULT_ALL=3
|
|
42
|
+
# PRIORITY_HIGH=4
|
|
43
|
+
#
|
|
44
|
+
# def __init__(self,context):
|
|
45
|
+
# pass
|
|
46
|
+
# def Builder(self,context,channel_id):
|
|
47
|
+
# pass
|
|
48
|
+
# class NotificationCompatBuilder:
|
|
49
|
+
# def __init__(self,context,channel_id):
|
|
50
|
+
# pass
|
|
51
|
+
# def setContentTitle(self,title):
|
|
52
|
+
# pass
|
|
53
|
+
# def setContentText(self,text):
|
|
54
|
+
# pass
|
|
55
|
+
# def setSmallIcon(self,icon):
|
|
56
|
+
# pass
|
|
57
|
+
# def setLargeIcon(self,icon):
|
|
58
|
+
# pass
|
|
59
|
+
# def setAutoCancel(self,auto_cancel):
|
|
60
|
+
# pass
|
|
61
|
+
# def setPriority(self,priority):
|
|
62
|
+
# pass
|
|
63
|
+
# def setDefaults(self,defaults):
|
|
64
|
+
# pass
|
|
65
|
+
# def build(self):
|
|
66
|
+
# pass
|
|
67
|
+
# class NotificationCompatBigTextStyle:
|
|
68
|
+
# pass
|
|
69
|
+
# class NotificationCompatBigPictureStyle:
|
|
70
|
+
# pass
|
|
71
|
+
# class NotificationCompatInboxStyle:
|
|
72
|
+
# pass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: android-notify
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.57
|
|
4
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
|
|
@@ -464,6 +464,10 @@ args
|
|
|
464
464
|
|
|
465
465
|
- new_message : String to be set as New notification Message
|
|
466
466
|
|
|
467
|
+
### Instance.showInfiniteProgressBar
|
|
468
|
+
|
|
469
|
+
Displays an Infinite Progress Bar in Notification, Can be Removed using `removeProgressBar` and updated using `updateProgressBar` method
|
|
470
|
+
|
|
467
471
|
### Instance.updateProgressBar
|
|
468
472
|
|
|
469
473
|
if updating title,msg with progressbar frequenlty pass them in too to avoid update issues.
|
|
@@ -2,10 +2,11 @@ README.md
|
|
|
2
2
|
setup.py
|
|
3
3
|
android_notify/__init__.py
|
|
4
4
|
android_notify/__main__.py
|
|
5
|
+
android_notify/base.py
|
|
5
6
|
android_notify/core.py
|
|
6
|
-
android_notify/facade.py
|
|
7
7
|
android_notify/styles.py
|
|
8
8
|
android_notify/sword.py
|
|
9
|
+
android_notify/types_idea.py
|
|
9
10
|
android_notify.egg-info/PKG-INFO
|
|
10
11
|
android_notify.egg-info/SOURCES.txt
|
|
11
12
|
android_notify.egg-info/dependency_links.txt
|
|
@@ -6,7 +6,7 @@ with open("README.md", "r", encoding="utf-8") as readme_data:
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name="android-notify",
|
|
9
|
-
version="1.
|
|
9
|
+
version="1.57",
|
|
10
10
|
author="Fabian",
|
|
11
11
|
author_email='fector101@yahoo.com',
|
|
12
12
|
description="A Python package that simpilfies creating Android notifications in Kivy apps.",
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"""Assists Notification Class with Args auto-complete: keeps sub class cleaner"""
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
|
|
4
|
-
@dataclass
|
|
5
|
-
class BaseNotification:
|
|
6
|
-
"""Encapsulator"""
|
|
7
|
-
|
|
8
|
-
# Basic options
|
|
9
|
-
title: str = ''
|
|
10
|
-
message: str = ''
|
|
11
|
-
style: str = 'simple'
|
|
12
|
-
|
|
13
|
-
# Style specfic attributes
|
|
14
|
-
big_picture_path: str = ''
|
|
15
|
-
large_icon_path: str = ''
|
|
16
|
-
progress_max_value: int = 100
|
|
17
|
-
progress_current_value: int = 0
|
|
18
|
-
body: str = ''
|
|
19
|
-
|
|
20
|
-
# For Nofitication Functions
|
|
21
|
-
identifer: str = ''
|
|
22
|
-
callback: object = None
|
|
23
|
-
|
|
24
|
-
# Advance Options
|
|
25
|
-
channel_name: str = 'Default Channel'
|
|
26
|
-
channel_id: str = 'default_channel'
|
|
27
|
-
silent: bool = False
|
|
28
|
-
app_icon: str = 'Defaults to package app icon'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|