android-notify 1.50.1__tar.gz → 1.51__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: android-notify
3
- Version: 1.50.1
3
+ Version: 1.51
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
@@ -144,6 +144,9 @@ Clock.schedule_once(lambda dt: notification.updateProgressBar(30, "30% downloade
144
144
 
145
145
  #### Notification with an Image (Big Picture Style)
146
146
 
147
+ > [!NOTE]
148
+ > Online Images should start with `http://` or `https://`
149
+
147
150
  ```python
148
151
  # Image notification
149
152
  notification = Notification(
@@ -159,36 +162,39 @@ notification.send()
159
162
  **Sample Image:**
160
163
  ![big_picture img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/bigpicturenoti.jpg)
161
164
 
162
- #### Inbox Notification Style
165
+ #### Notification with an Image (Large Icon Style)
166
+
167
+ > [!NOTE]
168
+ > Online Images should start with `http://` or `https://`
163
169
 
164
170
  ```python
165
- # Send a notification with inbox style
166
171
  notification = Notification(
167
- title='Inbox Notification',
168
- message='Line 1\nLine 2\nLine 3',
169
- style='inbox'
172
+ title="FabianDev_",
173
+ message="A twitter about some programming stuff",
174
+ style="large_icon",
175
+ large_icon_path="assets/imgs/profile.png"
170
176
  )
171
- notification.send()
172
177
 
173
178
  ```
174
179
 
175
- **Sample Image:**
176
- ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
180
+ **Sample Image:**
181
+ ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
177
182
 
178
- #### Notification with an Image (Large Icon Style)
183
+ #### Inbox Notification Style
179
184
 
180
185
  ```python
186
+ # Send a notification with inbox style
181
187
  notification = Notification(
182
- title="FabianDev_",
183
- message="A twitter about some programming stuff",
184
- style="large_icon",
185
- large_icon_path="assets/imgs/profile.png"
188
+ title='Inbox Notification',
189
+ message='Line 1\nLine 2\nLine 3',
190
+ style='inbox'
186
191
  )
192
+ notification.send()
187
193
 
188
194
  ```
189
195
 
190
- **Sample Image:**
191
- ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
196
+ **Sample Image:**
197
+ ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
192
198
 
193
199
  #### Notification with Buttons
194
200
 
@@ -212,16 +218,19 @@ notification.send()
212
218
  **Sample Image:**
213
219
  ![btns img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/btns.jpg)
214
220
 
215
- #### Big text notification (Will Display as normal text if Device dosen't support)
221
+ #### Big text notification
216
222
 
217
223
  ```python
218
224
  notification = Notification(
219
225
  title="Article",
220
- message="Long article content...",
226
+ subject="Histroy of Loerm Ipsuim"
227
+ message="Lorem Ipsum is simply dummy text of the printing and ...",
221
228
  style="big_text"
222
229
  )
223
230
  ```
224
231
 
232
+ ![big_text img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/big_text.jpg)
233
+
225
234
  ## Advanced Features
226
235
 
227
236
  ### Updating Notifications
@@ -281,19 +290,13 @@ notification.send(silent=True)
281
290
 
282
291
  ## Functions
283
292
 
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
293
  ```python
289
294
  from kivymd.app import MDApp
290
- from android_notify import Notification, NotificationHandler
295
+ from android_notify import Notification
291
296
 
292
297
  class Myapp(MDApp):
293
298
 
294
299
  def on_start(self):
295
- # Is called Once when app is Starts up
296
- NotificationHandler.bindNotifyListener() # if successfull returns True
297
300
  Notification(title="Hello", message="This is a basic notification.",callback=self.doSomething).send()
298
301
 
299
302
  def doSomething(self):
@@ -318,8 +321,6 @@ class Myapp(MDApp):
318
321
  notify1 = Notification(title="Change Colour", message="Click to change App Colour", identifer='change_app_color')
319
322
  notify1.send()
320
323
 
321
- NotificationHandler.bindNotifyListener()
322
-
323
324
  def on_resume(self):
324
325
  # Is called everytime app is reopened
325
326
  notify_identifer = NotificationHandler.getIdentifer()
@@ -331,22 +332,8 @@ class Myapp(MDApp):
331
332
  pass
332
333
  ```
333
334
 
334
-
335
-
336
335
  ### Assist
337
336
 
338
- - How to Copy image to app folder
339
-
340
- ```python
341
- import shutil,os # These modules come packaged with python
342
- from android.storage import app_storage_path # type: ignore -- This works only on android
343
-
344
- app_path = os.path.join(app_storage_path(),'app')
345
- image_path= "/storage/emulated/0/Download/profile.png"
346
-
347
- shutil.copy(image_path, os.path.join(app_path, "profile.png"))
348
- ```
349
-
350
337
  - Avoiding Human Error when using different notification styles
351
338
 
352
339
  ```python
@@ -375,9 +362,8 @@ notification.send()
375
362
 
376
363
  ## Image Requirements
377
364
 
378
- - Images must be located within your app's folder
379
- - Supported paths are relative to your app's storage path
380
- - Example: `assets/imgs/icon.png`
365
+ - Online Images should start with `http://` or `https://`
366
+ - Local Images must be located within your app's folder
381
367
 
382
368
  ## Error Handling
383
369
 
@@ -385,22 +371,20 @@ The library validates arguments and provides helpful error messages:
385
371
 
386
372
  - Invalid style names will suggest the closest matching style
387
373
  - Invalid arguments will list all valid options
388
- - Missing image files will raise FileNotFoundError with the attempted path
374
+ - Missing image files will list all files in App Directory
389
375
 
390
- ## Limitations
376
+ ## Limitation
391
377
 
392
378
  1. Only works on Android devices
393
- 2. Images must be within the app's storage path
394
- 3. Channel names are limited to 40 characters
395
- 4. Channel IDs are limited to 50 characters
396
379
 
397
380
  ## Best Practices
398
381
 
399
382
  1. Always handle permissions appropriately
400
- 2. Use meaningful channel names for organization
401
- 3. Keep progress bar updates reasonable (don't update too frequently)
402
- 4. Test notifications on different Android versions
403
- 5. Consider using silent notifications for frequent updates
383
+ 2. use `NotificationStyles` to set `style`, use `style=NotificationStyles.LARGE_ICON` instead of `style="large_icon"`
384
+ 3. Use meaningful channel names for organization
385
+ 4. Keep progress bar updates reasonable (don't update too frequently)
386
+ 5. Test notifications on different Android versions
387
+ 6. Consider using silent notifications for frequent updates
404
388
 
405
389
  ## Debugging Tips
406
390
 
@@ -108,6 +108,9 @@ Clock.schedule_once(lambda dt: notification.updateProgressBar(30, "30% downloade
108
108
 
109
109
  #### Notification with an Image (Big Picture Style)
110
110
 
111
+ > [!NOTE]
112
+ > Online Images should start with `http://` or `https://`
113
+
111
114
  ```python
112
115
  # Image notification
113
116
  notification = Notification(
@@ -123,36 +126,39 @@ notification.send()
123
126
  **Sample Image:**
124
127
  ![big_picture img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/bigpicturenoti.jpg)
125
128
 
126
- #### Inbox Notification Style
129
+ #### Notification with an Image (Large Icon Style)
130
+
131
+ > [!NOTE]
132
+ > Online Images should start with `http://` or `https://`
127
133
 
128
134
  ```python
129
- # Send a notification with inbox style
130
135
  notification = Notification(
131
- title='Inbox Notification',
132
- message='Line 1\nLine 2\nLine 3',
133
- style='inbox'
136
+ title="FabianDev_",
137
+ message="A twitter about some programming stuff",
138
+ style="large_icon",
139
+ large_icon_path="assets/imgs/profile.png"
134
140
  )
135
- notification.send()
136
141
 
137
142
  ```
138
143
 
139
- **Sample Image:**
140
- ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
144
+ **Sample Image:**
145
+ ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
141
146
 
142
- #### Notification with an Image (Large Icon Style)
147
+ #### Inbox Notification Style
143
148
 
144
149
  ```python
150
+ # Send a notification with inbox style
145
151
  notification = Notification(
146
- title="FabianDev_",
147
- message="A twitter about some programming stuff",
148
- style="large_icon",
149
- large_icon_path="assets/imgs/profile.png"
152
+ title='Inbox Notification',
153
+ message='Line 1\nLine 2\nLine 3',
154
+ style='inbox'
150
155
  )
156
+ notification.send()
151
157
 
152
158
  ```
153
159
 
154
- **Sample Image:**
155
- ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
160
+ **Sample Image:**
161
+ ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
156
162
 
157
163
  #### Notification with Buttons
158
164
 
@@ -176,16 +182,19 @@ notification.send()
176
182
  **Sample Image:**
177
183
  ![btns img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/btns.jpg)
178
184
 
179
- #### Big text notification (Will Display as normal text if Device dosen't support)
185
+ #### Big text notification
180
186
 
181
187
  ```python
182
188
  notification = Notification(
183
189
  title="Article",
184
- message="Long article content...",
190
+ subject="Histroy of Loerm Ipsuim"
191
+ message="Lorem Ipsum is simply dummy text of the printing and ...",
185
192
  style="big_text"
186
193
  )
187
194
  ```
188
195
 
196
+ ![big_text img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/big_text.jpg)
197
+
189
198
  ## Advanced Features
190
199
 
191
200
  ### Updating Notifications
@@ -245,19 +254,13 @@ notification.send(silent=True)
245
254
 
246
255
  ## Functions
247
256
 
248
- ### NotificationHandler - To Attach Listener
249
-
250
- Add this to your main.py App Class so it runs Once, In later Versions It'll be Attached Automatical
251
-
252
257
  ```python
253
258
  from kivymd.app import MDApp
254
- from android_notify import Notification, NotificationHandler
259
+ from android_notify import Notification
255
260
 
256
261
  class Myapp(MDApp):
257
262
 
258
263
  def on_start(self):
259
- # Is called Once when app is Starts up
260
- NotificationHandler.bindNotifyListener() # if successfull returns True
261
264
  Notification(title="Hello", message="This is a basic notification.",callback=self.doSomething).send()
262
265
 
263
266
  def doSomething(self):
@@ -282,8 +285,6 @@ class Myapp(MDApp):
282
285
  notify1 = Notification(title="Change Colour", message="Click to change App Colour", identifer='change_app_color')
283
286
  notify1.send()
284
287
 
285
- NotificationHandler.bindNotifyListener()
286
-
287
288
  def on_resume(self):
288
289
  # Is called everytime app is reopened
289
290
  notify_identifer = NotificationHandler.getIdentifer()
@@ -295,22 +296,8 @@ class Myapp(MDApp):
295
296
  pass
296
297
  ```
297
298
 
298
-
299
-
300
299
  ### Assist
301
300
 
302
- - How to Copy image to app folder
303
-
304
- ```python
305
- import shutil,os # These modules come packaged with python
306
- from android.storage import app_storage_path # type: ignore -- This works only on android
307
-
308
- app_path = os.path.join(app_storage_path(),'app')
309
- image_path= "/storage/emulated/0/Download/profile.png"
310
-
311
- shutil.copy(image_path, os.path.join(app_path, "profile.png"))
312
- ```
313
-
314
301
  - Avoiding Human Error when using different notification styles
315
302
 
316
303
  ```python
@@ -339,9 +326,8 @@ notification.send()
339
326
 
340
327
  ## Image Requirements
341
328
 
342
- - Images must be located within your app's folder
343
- - Supported paths are relative to your app's storage path
344
- - Example: `assets/imgs/icon.png`
329
+ - Online Images should start with `http://` or `https://`
330
+ - Local Images must be located within your app's folder
345
331
 
346
332
  ## Error Handling
347
333
 
@@ -349,22 +335,20 @@ The library validates arguments and provides helpful error messages:
349
335
 
350
336
  - Invalid style names will suggest the closest matching style
351
337
  - Invalid arguments will list all valid options
352
- - Missing image files will raise FileNotFoundError with the attempted path
338
+ - Missing image files will list all files in App Directory
353
339
 
354
- ## Limitations
340
+ ## Limitation
355
341
 
356
342
  1. Only works on Android devices
357
- 2. Images must be within the app's storage path
358
- 3. Channel names are limited to 40 characters
359
- 4. Channel IDs are limited to 50 characters
360
343
 
361
344
  ## Best Practices
362
345
 
363
346
  1. Always handle permissions appropriately
364
- 2. Use meaningful channel names for organization
365
- 3. Keep progress bar updates reasonable (don't update too frequently)
366
- 4. Test notifications on different Android versions
367
- 5. Consider using silent notifications for frequent updates
347
+ 2. use `NotificationStyles` to set `style`, use `style=NotificationStyles.LARGE_ICON` instead of `style="large_icon"`
348
+ 3. Use meaningful channel names for organization
349
+ 4. Keep progress bar updates reasonable (don't update too frequently)
350
+ 5. Test notifications on different Android versions
351
+ 6. Consider using silent notifications for frequent updates
368
352
 
369
353
  ## Debugging Tips
370
354
 
@@ -1,15 +1,16 @@
1
+ """Contains Safe way to call Styles"""
2
+
1
3
  class NotificationStyles():
2
4
  """ Safely Adding Styles"""
3
5
  DEFAULT = "simple"
4
-
6
+
5
7
  PROGRESS = "progress"
6
8
  INBOX = "inbox"
7
9
  BIG_TEXT = "big_text"
8
-
10
+
9
11
  LARGE_ICON = "large_icon"
10
12
  BIG_PICTURE = "big_picture"
11
13
  BOTH_IMGS = "both_imgs"
12
-
14
+
13
15
  MESSAGING = "messaging" # TODO
14
16
  CUSTOM = "custom" # TODO
15
-
@@ -2,15 +2,19 @@
2
2
  import difflib
3
3
  import traceback
4
4
  import os
5
+ import threading
5
6
  import re
7
+ from .styles import NotificationStyles
6
8
 
7
9
  DEV=0
8
10
  ON_ANDROID = False
9
11
 
10
12
  try:
13
+ # Android Imports
11
14
  from jnius import autoclass,cast # Needs Java to be installed pylint: disable=W0611, C0114
12
15
  from android import activity # pylint: disable=import-error
13
16
  from android.config import ACTIVITY_CLASS_NAME # pylint: disable=import-error
17
+ from android.runnable import run_on_ui_thread # pylint: disable=import-error
14
18
 
15
19
  # Get the required Java classes
16
20
  Bundle = autoclass('android.os.Bundle')
@@ -28,6 +32,14 @@ except Exception as e:# pylint: disable=W0718
28
32
  MESSAGE='This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.' # pylint: disable=C0301
29
33
  print(MESSAGE if DEV else '')
30
34
 
35
+ # This is so no crashes when developing on PC
36
+ def run_on_ui_thread(func):
37
+ """Fallback for Developing on PC"""
38
+ def wrapper(*args, **kwargs):
39
+ print("Simulating run on UI thread")
40
+ return func(*args, **kwargs)
41
+ return wrapper
42
+
31
43
  if ON_ANDROID:
32
44
  try:
33
45
  from android.permissions import request_permissions, Permission,check_permission # pylint: disable=E0401
@@ -62,9 +74,12 @@ class Notification:
62
74
  both_imgs == using lager icon and big picture
63
75
  :param big_picture_path: Relative Path to the image resource.
64
76
  :param large_icon_path: Relative Path to the image resource.
65
- :param callback: Function for notification Click.
77
+ :param progress_current_value: interger To set progress bar current value.
78
+ :param progress_max_value: interger To set Max range for progress bar.
79
+ :param subject: Preview text For `big_Text` style `message`.
66
80
  ---
67
81
  (Advance Options)
82
+ :param callback: Function for notification Click.
68
83
  :param channel_name: - str Defaults to "Default Channel"
69
84
  :param channel_id: - str Defaults to "default_channel"
70
85
  ---
@@ -84,18 +99,23 @@ class Notification:
84
99
  ] # TODO make pattern for non-android Notifications
85
100
  defaults={
86
101
  'title':'Default Title',
87
- 'message':'Default Message', # TODO Might change message para to list if style set to inbox
102
+ 'message':'Default Message',
88
103
  'style':'simple',
89
104
  'big_picture_path':'',
90
105
  'large_icon_path':'',
91
106
  'progress_max_value': 0,
92
107
  'progress_current_value': 0,
108
+ 'subject':'',
93
109
  'channel_name':'Default Channel',
94
110
  'channel_id':'default_channel',
95
111
  'logs':True,
96
112
  "identifer": '',
97
113
  'callback': None
98
114
  }
115
+ # TODO specify types in a better way instead of using
116
+ # if key not in non_string_keys: value = str(value) to fix
117
+ #non_string_keys=['progress_max_value','progress_current_value','callback','logs']
118
+ # TODO using default values to check types
99
119
  # During Development (When running on PC)
100
120
  logs=not ON_ANDROID
101
121
  def __init__(self,**kwargs):
@@ -108,6 +128,7 @@ class Notification:
108
128
  self.big_picture_path=''
109
129
  self.progress_current_value=0
110
130
  self.progress_max_value=0
131
+ self.subject= ''
111
132
 
112
133
  # For Nofitication Functions
113
134
  self.identifer=''
@@ -151,14 +172,17 @@ class Notification:
151
172
  self.message=new_message
152
173
  if ON_ANDROID:
153
174
  self.__builder.setContentText(new_message)
154
-
175
+ return True
176
+ return 'Updated'
155
177
  def updateProgressBar(self,current_value,message:str=''):
156
- """message defaults to last message"""
157
- if not ON_ANDROID:
158
- return
178
+ """current_value is the value to set progressbar, message defaults to last message"""
159
179
 
160
180
  if self.logs:
161
181
  print(f'Progress Bar Update value: {current_value}')
182
+
183
+ if not ON_ANDROID:
184
+ return
185
+
162
186
  self.__builder.setProgress(self.progress_max_value, current_value, False)
163
187
  if message:
164
188
  self.__builder.setContentText(String(message))
@@ -166,8 +190,16 @@ class Notification:
166
190
 
167
191
  def removeProgressBar(self,message=''):
168
192
  """message defaults to last message"""
193
+
194
+ if self.logs:
195
+ print('removed')
196
+
197
+ if not ON_ANDROID:
198
+ return True
199
+
169
200
  if message:
170
201
  self.__builder.setContentText(String(message))
202
+ return True
171
203
  self.__builder.setProgress(0, 0, False)
172
204
  self.notification_manager.notify(self.__id, self.__builder.build())
173
205
 
@@ -183,8 +215,9 @@ class Notification:
183
215
  self.notification_manager.notify(self.__id, self.__builder.build())
184
216
  elif self.logs:
185
217
  string_to_display=''
218
+ print("\n Sent Notification!!!")
186
219
  for name,value in vars(self).items():
187
- if value and name not in ['logs','_Notification__id']:
220
+ if value and name in ["title", "message", "style", "subject", "large_icon_path", "big_picture_path", "progress_current_value", "progress_max_value", "channel_name"]:
188
221
  string_to_display += f'\n {name}: {value}'
189
222
  string_to_display +="\n (Won't Print Logs When Complied,except if selected `Notification.logs=True`)"
190
223
  print(string_to_display)
@@ -254,63 +287,48 @@ class Notification:
254
287
  self.notification_manager.createNotificationChannel(channel)
255
288
 
256
289
  # Build the notification
257
- # self.__builder = NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
290
+ # str() This is to prevent Error When user does Notification.title='blah' instead of Notification(title='blah'
291
+ # TODO fix this by creating a on_Title method in other versions
258
292
  self.__builder.setContentTitle(str(self.title))
259
- self.__builder.setContentText(str(self.message))
293
+ if self.style == NotificationStyles.BIG_TEXT:
294
+ self.__builder.setContentText(str(self.subject))
295
+ else:
296
+ self.__builder.setContentText(str(self.message))
260
297
  self.__builder.setSmallIcon(context.getApplicationInfo().icon)
261
298
  self.__builder.setDefaults(NotificationCompat.DEFAULT_ALL) # pylint: disable=E0606
262
299
  self.__builder.setPriority(NotificationCompat.PRIORITY_DEFAULT if self.silent else NotificationCompat.PRIORITY_HIGH)
300
+ self.__builder.setOnlyAlertOnce(True)
263
301
  self.__addIntentToOpenApp()
302
+
264
303
  def __addNotificationStyle(self):
265
- # pylint: disable=trailing-whitespace
266
-
267
- large_icon_javapath=None
268
- if self.large_icon_path:
269
- try:
270
- large_icon_javapath = self.__get_image_uri(self.large_icon_path)
271
- except FileNotFoundError as e:
272
- print('Failed Adding Big Picture Bitmap: ',e)
273
-
274
- big_pic_javapath=None
275
- if self.big_picture_path:
276
- try:
277
- big_pic_javapath = self.__get_image_uri(self.big_picture_path)
278
- except FileNotFoundError as e:
279
- print('Failed Adding Lagre Icon Bitmap: ',e)
280
-
281
-
282
- if self.style == "big_text":
304
+ if self.style == NotificationStyles.BIG_TEXT:
283
305
  big_text_style = NotificationCompatBigTextStyle() # pylint: disable=E0606
284
306
  big_text_style.bigText(self.message)
285
307
  self.__builder.setStyle(big_text_style)
286
-
287
- elif self.style == "inbox":
308
+
309
+ elif self.style == NotificationStyles.INBOX:
288
310
  inbox_style = NotificationCompatInboxStyle() # pylint: disable=E0606
289
311
  for line in self.message.split("\n"):
290
312
  inbox_style.addLine(line)
291
313
  self.__builder.setStyle(inbox_style)
292
-
293
- elif self.style == "big_picture" and big_pic_javapath:
294
- big_pic_bitmap = self.__getBitmap(big_pic_javapath)
295
- big_picture_style = NotificationCompatBigPictureStyle().bigPicture(big_pic_bitmap) # pylint: disable=E0606
296
- self.__builder.setStyle(big_picture_style)
297
-
298
- elif self.style == "large_icon" and large_icon_javapath:
299
- large_icon_bitmap = self.__getBitmap(large_icon_javapath)
300
- self.__builder.setLargeIcon(large_icon_bitmap)
301
-
302
- elif self.style == 'both_imgs' and (large_icon_javapath or big_pic_javapath):
303
- if big_pic_javapath:
304
- big_pic_bitmap = self.__getBitmap(big_pic_javapath)
305
- big_picture_style = NotificationCompatBigPictureStyle().bigPicture(big_pic_bitmap)
306
- self.__builder.setStyle(big_picture_style)
307
- if large_icon_javapath:
308
- large_icon_bitmap = self.__getBitmap(large_icon_javapath)
309
- self.__builder.setLargeIcon(large_icon_bitmap)
314
+
315
+ elif self.style == NotificationStyles.BIG_PICTURE and self.big_picture_path:
316
+ self.__buildImg(self.big_picture_path, self.style)
317
+
318
+ elif self.style == NotificationStyles.LARGE_ICON and self.large_icon_path:
319
+ self.__buildImg(self.large_icon_path, self.style)
320
+
321
+ elif self.style == NotificationStyles.BOTH_IMGS and (self.big_picture_path or self.large_icon_path):
322
+ if self.big_picture_path:
323
+ self.__buildImg(self.big_picture_path, NotificationStyles.BIG_PICTURE)
324
+ if self.large_icon_path:
325
+ self.__buildImg(self.large_icon_path, NotificationStyles.LARGE_ICON)
326
+
310
327
  elif self.style == 'progress':
311
328
  self.__builder.setContentTitle(String(self.title))
312
329
  self.__builder.setContentText(String(self.message))
313
330
  self.__builder.setProgress(self.progress_max_value, self.progress_current_value, False)
331
+
314
332
  # elif self.style == 'custom':
315
333
  # self.__builder = self.__doCustomStyle()
316
334
 
@@ -318,6 +336,67 @@ class Notification:
318
336
  # # TODO Will implement when needed
319
337
  # return self.__builder
320
338
 
339
+ def __buildImg(self, user_img,img_style):
340
+ if user_img.startswith('http://') or user_img.startswith('https://'):
341
+ thread = threading.Thread(
342
+ target=self.__getImgFromURL,
343
+ args=(user_img,img_style,)
344
+ )
345
+ thread.start()
346
+ else:
347
+ if NotificationStyles.BIG_PICTURE:
348
+ bitmap = self.__getImgFromPath(user_img)
349
+ if bitmap:
350
+ big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap) # pylint: disable=E0606
351
+ self.__builder.setStyle(big_picture_style)
352
+ elif NotificationStyles.LARGE_ICON:
353
+ bitmap = self.__getImgFromPath(user_img)
354
+ if bitmap:
355
+ self.__builder.setLargeIcon(bitmap)
356
+
357
+ def __getImgFromPath(self, relative_path):
358
+ app_folder=os.path.join(app_storage_path(),'app') # pylint: disable=possibly-used-before-assignment
359
+ output_path = os.path.join(app_folder, relative_path)
360
+ if not os.path.exists(output_path):
361
+ print(f"\nImage not found at path: {output_path}, (Local images gotten from App Path)")
362
+ print("These are the existing files in your app Folder:")
363
+ print('['+', '.join(os.listdir(app_folder)) + ']')
364
+ return None
365
+ Uri = autoclass('android.net.Uri')
366
+ uri = Uri.parse(f"file://{output_path}")
367
+ return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
368
+
369
+ def __getImgFromURL(self,url,img_style):
370
+ print("getting image from URL---")
371
+ try:
372
+ URL = autoclass('java.net.URL')
373
+ url = URL(url)
374
+ connection = url.openConnection()
375
+ connection.connect()
376
+ input_stream = connection.getInputStream()
377
+ bitmap = BitmapFactory.decodeStream(input_stream)
378
+ input_stream.close()
379
+ self.__applyNotificationImage(bitmap,img_style)
380
+ except Exception as e:
381
+ # TODO get type of JAVA Error
382
+ print('Error Type ',e)
383
+ print('Failed to get Img from URL ',traceback.format_exc())
384
+
385
+ @run_on_ui_thread
386
+ def __applyNotificationImage(self,bitmap,img_style):
387
+ print('appying notification image thread ', bitmap)
388
+ try:
389
+ if img_style == NotificationStyles.BIG_PICTURE:
390
+ big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap) # pylint: disable=E0606
391
+ self.__builder.setStyle(big_picture_style)
392
+ elif img_style == NotificationStyles.LARGE_ICON:
393
+ self.__builder.setLargeIcon(bitmap)
394
+ self.notification_manager.notify(self.__id, self.__builder.build())
395
+ print('added notification image done-------')
396
+ except Exception as e:
397
+ print('I could stop ',e)
398
+ print('could stop get Img from URL ',traceback.format_exc())
399
+
321
400
  def __getUniqueID(self):
322
401
  notification_id = self.notification_ids[-1] + 1
323
402
  self.notification_ids.append(notification_id)
@@ -335,24 +414,6 @@ class Notification:
335
414
  if not all(check_permission(p) for p in permissions):
336
415
  request_permissions(permissions,on_permissions_result) # pylint: disable=E0606
337
416
 
338
- def __get_image_uri(self,relative_path):
339
- """
340
- Get the absolute URI for an image in the assets folder.
341
- :param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
342
- :return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
343
- """
344
-
345
- output_path = os.path.join(app_storage_path(),'app', relative_path) # pylint: disable=possibly-used-before-assignment
346
- # print(output_path) # /data/user/0/(package.domain+package.name)/files/app/assets/imgs/icon.png | pylint: disable=:line-too-long
347
-
348
- if not os.path.exists(output_path):
349
- # TODO Use images From Any where even Web
350
- raise FileNotFoundError(f"Image not found at path: {output_path}, (Can Only Use Images in App Path)")
351
- Uri = autoclass('android.net.Uri')
352
- return Uri.parse(f"file://{output_path}")
353
- def __getBitmap(self,img_path):
354
- return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(img_path))
355
-
356
417
  def __generate_channel_id(self,channel_name: str) -> str:
357
418
  """
358
419
  Generate a readable and consistent channel ID from a channel name.
@@ -451,6 +512,7 @@ class Notification:
451
512
  class NotificationHandler:
452
513
  """For Notification Operations """
453
514
  __identifer = None
515
+ __bound = False
454
516
 
455
517
  @classmethod
456
518
  def getIdentifer(cls):
@@ -516,9 +578,13 @@ class NotificationHandler:
516
578
  """This Creates a Listener for All Notification Clicks and Functions"""
517
579
  if not cls.is_on_android():
518
580
  return "Not on Android"
519
- #Beta TODO Automatic bind when Notification object is called the first time use keep trying BroadcastReceiver
581
+ #TODO keep trying BroadcastReceiver
582
+ if cls.__bound:
583
+ print("bounding done already ")
584
+ return True
520
585
  try:
521
586
  activity.bind(on_new_intent=cls.__notificationHandler)
587
+ cls.__bound = True
522
588
  return True
523
589
  except Exception as e: # pylint: disable=broad-exception-caught
524
590
  print('Failed to bin notitfications listener',e)
@@ -541,3 +607,5 @@ class NotificationHandler:
541
607
  def is_on_android():
542
608
  """Utility to check if the app is running on Android."""
543
609
  return ON_ANDROID
610
+
611
+ NotificationHandler.bindNotifyListener()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: android-notify
3
- Version: 1.50.1
3
+ Version: 1.51
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
@@ -144,6 +144,9 @@ Clock.schedule_once(lambda dt: notification.updateProgressBar(30, "30% downloade
144
144
 
145
145
  #### Notification with an Image (Big Picture Style)
146
146
 
147
+ > [!NOTE]
148
+ > Online Images should start with `http://` or `https://`
149
+
147
150
  ```python
148
151
  # Image notification
149
152
  notification = Notification(
@@ -159,36 +162,39 @@ notification.send()
159
162
  **Sample Image:**
160
163
  ![big_picture img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/bigpicturenoti.jpg)
161
164
 
162
- #### Inbox Notification Style
165
+ #### Notification with an Image (Large Icon Style)
166
+
167
+ > [!NOTE]
168
+ > Online Images should start with `http://` or `https://`
163
169
 
164
170
  ```python
165
- # Send a notification with inbox style
166
171
  notification = Notification(
167
- title='Inbox Notification',
168
- message='Line 1\nLine 2\nLine 3',
169
- style='inbox'
172
+ title="FabianDev_",
173
+ message="A twitter about some programming stuff",
174
+ style="large_icon",
175
+ large_icon_path="assets/imgs/profile.png"
170
176
  )
171
- notification.send()
172
177
 
173
178
  ```
174
179
 
175
- **Sample Image:**
176
- ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
180
+ **Sample Image:**
181
+ ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
177
182
 
178
- #### Notification with an Image (Large Icon Style)
183
+ #### Inbox Notification Style
179
184
 
180
185
  ```python
186
+ # Send a notification with inbox style
181
187
  notification = Notification(
182
- title="FabianDev_",
183
- message="A twitter about some programming stuff",
184
- style="large_icon",
185
- large_icon_path="assets/imgs/profile.png"
188
+ title='Inbox Notification',
189
+ message='Line 1\nLine 2\nLine 3',
190
+ style='inbox'
186
191
  )
192
+ notification.send()
187
193
 
188
194
  ```
189
195
 
190
- **Sample Image:**
191
- ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
196
+ **Sample Image:**
197
+ ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
192
198
 
193
199
  #### Notification with Buttons
194
200
 
@@ -212,16 +218,19 @@ notification.send()
212
218
  **Sample Image:**
213
219
  ![btns img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/btns.jpg)
214
220
 
215
- #### Big text notification (Will Display as normal text if Device dosen't support)
221
+ #### Big text notification
216
222
 
217
223
  ```python
218
224
  notification = Notification(
219
225
  title="Article",
220
- message="Long article content...",
226
+ subject="Histroy of Loerm Ipsuim"
227
+ message="Lorem Ipsum is simply dummy text of the printing and ...",
221
228
  style="big_text"
222
229
  )
223
230
  ```
224
231
 
232
+ ![big_text img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/big_text.jpg)
233
+
225
234
  ## Advanced Features
226
235
 
227
236
  ### Updating Notifications
@@ -281,19 +290,13 @@ notification.send(silent=True)
281
290
 
282
291
  ## Functions
283
292
 
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
293
  ```python
289
294
  from kivymd.app import MDApp
290
- from android_notify import Notification, NotificationHandler
295
+ from android_notify import Notification
291
296
 
292
297
  class Myapp(MDApp):
293
298
 
294
299
  def on_start(self):
295
- # Is called Once when app is Starts up
296
- NotificationHandler.bindNotifyListener() # if successfull returns True
297
300
  Notification(title="Hello", message="This is a basic notification.",callback=self.doSomething).send()
298
301
 
299
302
  def doSomething(self):
@@ -318,8 +321,6 @@ class Myapp(MDApp):
318
321
  notify1 = Notification(title="Change Colour", message="Click to change App Colour", identifer='change_app_color')
319
322
  notify1.send()
320
323
 
321
- NotificationHandler.bindNotifyListener()
322
-
323
324
  def on_resume(self):
324
325
  # Is called everytime app is reopened
325
326
  notify_identifer = NotificationHandler.getIdentifer()
@@ -331,22 +332,8 @@ class Myapp(MDApp):
331
332
  pass
332
333
  ```
333
334
 
334
-
335
-
336
335
  ### Assist
337
336
 
338
- - How to Copy image to app folder
339
-
340
- ```python
341
- import shutil,os # These modules come packaged with python
342
- from android.storage import app_storage_path # type: ignore -- This works only on android
343
-
344
- app_path = os.path.join(app_storage_path(),'app')
345
- image_path= "/storage/emulated/0/Download/profile.png"
346
-
347
- shutil.copy(image_path, os.path.join(app_path, "profile.png"))
348
- ```
349
-
350
337
  - Avoiding Human Error when using different notification styles
351
338
 
352
339
  ```python
@@ -375,9 +362,8 @@ notification.send()
375
362
 
376
363
  ## Image Requirements
377
364
 
378
- - Images must be located within your app's folder
379
- - Supported paths are relative to your app's storage path
380
- - Example: `assets/imgs/icon.png`
365
+ - Online Images should start with `http://` or `https://`
366
+ - Local Images must be located within your app's folder
381
367
 
382
368
  ## Error Handling
383
369
 
@@ -385,22 +371,20 @@ The library validates arguments and provides helpful error messages:
385
371
 
386
372
  - Invalid style names will suggest the closest matching style
387
373
  - Invalid arguments will list all valid options
388
- - Missing image files will raise FileNotFoundError with the attempted path
374
+ - Missing image files will list all files in App Directory
389
375
 
390
- ## Limitations
376
+ ## Limitation
391
377
 
392
378
  1. Only works on Android devices
393
- 2. Images must be within the app's storage path
394
- 3. Channel names are limited to 40 characters
395
- 4. Channel IDs are limited to 50 characters
396
379
 
397
380
  ## Best Practices
398
381
 
399
382
  1. Always handle permissions appropriately
400
- 2. Use meaningful channel names for organization
401
- 3. Keep progress bar updates reasonable (don't update too frequently)
402
- 4. Test notifications on different Android versions
403
- 5. Consider using silent notifications for frequent updates
383
+ 2. use `NotificationStyles` to set `style`, use `style=NotificationStyles.LARGE_ICON` instead of `style="large_icon"`
384
+ 3. Use meaningful channel names for organization
385
+ 4. Keep progress bar updates reasonable (don't update too frequently)
386
+ 5. Test notifications on different Android versions
387
+ 6. Consider using silent notifications for frequent updates
404
388
 
405
389
  ## Debugging Tips
406
390
 
@@ -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.50.1",
9
+ version="1.51",
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.",
File without changes