android-notify 1.2__py3-none-any.whl → 1.3__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.

@@ -0,0 +1,3 @@
1
+ from .core import send_notification
2
+ from .styles import NotificationStyles
3
+ from .sword import Notification
android_notify/core.py CHANGED
@@ -1,7 +1,7 @@
1
-
2
- from jnius import autoclass,cast
1
+ """ Non-Advanced Stuff """
3
2
  import random
4
3
  import os
4
+ from jnius import autoclass,cast
5
5
 
6
6
  ON_ANDROID = False
7
7
  try:
@@ -20,13 +20,12 @@ except Exception as e:
20
20
 
21
21
  if ON_ANDROID:
22
22
  try:
23
- # NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
23
+ NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
24
24
  NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
25
25
 
26
26
  # Notification Design
27
27
  NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
28
28
  NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
29
- # NotificationCompatBigTextStyle = autoclass('android.app.Notification$BigTextStyle')
30
29
  NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
31
30
  NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
32
31
  except Exception as e:
@@ -65,7 +64,14 @@ def get_image_uri(relative_path):
65
64
  return Uri.parse(f"file://{output_path}")
66
65
 
67
66
 
68
- def send_notification(title:str, message:str, style=None, img_path=None, channel_id:str="default_channel"):
67
+ def send_notification(
68
+ title:str,
69
+ message:str,
70
+ style=None,
71
+ img_path=None,
72
+ channel_name="Default Channel",
73
+ channel_id:str="default_channel"
74
+ ):
69
75
  """
70
76
  Send a notification on Android.
71
77
 
@@ -73,21 +79,22 @@ def send_notification(title:str, message:str, style=None, img_path=None, channel
73
79
  :param message: Message body.
74
80
  :param style: Style of the notification ('big_text', 'big_picture', 'inbox', 'large_icon').
75
81
  :param img_path: Path to the image resource.
76
- :param channel_id: Notification channel ID.
82
+ :param channel_id: Notification channel ID.(Default is lowercase channel name arg in lowercase)
77
83
  """
78
84
  if not ON_ANDROID:
79
85
  print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.')
80
86
  return
81
-
87
+ asks_permission_if_needed()
88
+ channel_id=channel_name.replace(' ','_').lower().lower() if not channel_id else channel_id
82
89
  # Get notification manager
83
90
  notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
84
91
 
85
- importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
86
- # importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
92
+ # importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
93
+ importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
87
94
 
88
95
  # Notification Channel (Required for Android 8.0+)
89
96
  if BuildVersion.SDK_INT >= 26:
90
- channel = NotificationChannel(channel_id, "Default Channel",importance)
97
+ channel = NotificationChannel(channel_id, channel_name,importance)
91
98
  notification_manager.createNotificationChannel(channel)
92
99
 
93
100
  # Build the notification
@@ -98,7 +105,6 @@ def send_notification(title:str, message:str, style=None, img_path=None, channel
98
105
  builder.setDefaults(NotificationCompat.DEFAULT_ALL)
99
106
  builder.setPriority(NotificationCompat.PRIORITY_HIGH)
100
107
 
101
- # Get Image
102
108
  img=None
103
109
  if img_path:
104
110
  try:
@@ -112,8 +118,6 @@ def send_notification(title:str, message:str, style=None, img_path=None, channel
112
118
  big_text_style = NotificationCompatBigTextStyle()
113
119
  big_text_style.bigText(message)
114
120
  builder.setStyle(big_text_style)
115
-
116
-
117
121
  elif style == "big_picture" and img_path:
118
122
  bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(img))
119
123
  builder.setLargeIcon(bitmap)
@@ -132,4 +136,5 @@ def send_notification(title:str, message:str, style=None, img_path=None, channel
132
136
  # Display the notification
133
137
  notification_id = random.randint(0, 100)
134
138
  notification_manager.notify(notification_id, builder.build())
135
- return notification_id
139
+ return notification_id
140
+
android_notify/styles.py CHANGED
@@ -1,5 +1,15 @@
1
- class NotificationStyles:
2
- BIG_TEXT = "big_text"
3
- BIG_PICTURE = "big_picture"
1
+ class NotificationStyles():
2
+ """ Safely Adding Styles"""
3
+ DEFAULT = "simple"
4
+
5
+ PROGRESS = "progress"
4
6
  INBOX = "inbox"
7
+ BIG_TEXT = "big_text"
8
+
5
9
  LARGE_ICON = "large_icon"
10
+ BIG_PICTURE = "big_picture"
11
+ BOTH_IMGS = "both_imgs"
12
+
13
+ MESSAGING = "messaging" # TODO
14
+ CUSTOM = "custom" # TODO
15
+
@@ -0,0 +1,375 @@
1
+ """This Module Contain Class for creating Notification With Java"""
2
+ import difflib
3
+ import random
4
+ import os
5
+ import re
6
+ from jnius import autoclass,cast # pylint: disable=W0611, C0114
7
+
8
+ DEV=0
9
+ ON_ANDROID = False
10
+
11
+ try:
12
+ # Get the required Java classes
13
+ PythonActivity = autoclass('org.kivy.android.PythonActivity')
14
+ String = autoclass('java.lang.String')
15
+ Intent = autoclass('android.content.Intent')
16
+ PendingIntent = autoclass('android.app.PendingIntent')
17
+ context = PythonActivity.mActivity # Get the app's context
18
+ BitmapFactory = autoclass('android.graphics.BitmapFactory')
19
+ BuildVersion = autoclass('android.os.Build$VERSION')
20
+ NotificationManager = autoclass('android.app.NotificationManager')
21
+ NotificationChannel = autoclass('android.app.NotificationChannel')
22
+ ON_ANDROID = True
23
+ except Exception as e:# pylint: disable=W0718
24
+ MESSAGE='This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.' # pylint: disable=C0301
25
+ print(MESSAGE if DEV else '')
26
+
27
+ if ON_ANDROID:
28
+ try:
29
+ from android.permissions import request_permissions, Permission,check_permission # pylint: disable=E0401
30
+ from android.storage import app_storage_path # pylint: disable=E0401
31
+
32
+ NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
33
+ NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
34
+
35
+ # Notification Design
36
+ NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder') # pylint: disable=C0301
37
+ NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle') # pylint: disable=C0301
38
+ NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle') # pylint: disable=C0301
39
+ NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
40
+ except Exception as e:# pylint: disable=W0718
41
+ print(e if DEV else '','Import Fector101')
42
+ # print(e if DEV else '')
43
+ print("""
44
+ Dependency Error: Add the following in buildozer.spec:
45
+ * android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
46
+ * android.enable_androidx = True
47
+ * android.permissions = POST_NOTIFICATIONS
48
+ """)
49
+
50
+ class Notification:
51
+ """
52
+ Send a notification on Android.
53
+
54
+ :param title: Title of the notification.
55
+ :param message: Message body.
56
+ :param style: Style of the notification
57
+ ('simple', 'progress', 'big_text', 'inbox', 'big_picture', 'large_icon', 'both_imgs').
58
+ 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.
61
+ ---
62
+ (Advance Options)
63
+ :param channel_name: Defaults to "Default Channel"
64
+ :param channel_id: Defaults to "default_channel"
65
+ ---
66
+ (Options during Dev On PC)
67
+ :param logs: Defaults to True
68
+ """
69
+ notification_ids=[]
70
+ style_values=[
71
+ '','simple',
72
+ 'progress','big_text',
73
+ 'inbox', 'big_picture',
74
+ 'large_icon','both_imgs',
75
+ 'custom'
76
+ ] # TODO make pattern for non-android Notifications
77
+ defaults={
78
+ 'title':'Default Title',
79
+ 'message':'Default Message', # TODO Might change message para to list if style set to inbox
80
+ 'style':'simple',
81
+ 'big_picture_path':'',
82
+ 'large_icon_path':'',
83
+ 'progress_max_value': 100,
84
+ 'progress_current_value': 0,
85
+ 'channel_name':'Default Channel',
86
+ 'channel_id':'default_channel',
87
+ 'logs':True,
88
+ }
89
+ # During Development (When running on PC)
90
+ logs=not ON_ANDROID
91
+ def __init__(self,**kwargs):
92
+ self.__validateArgs(kwargs)
93
+ # Basic options
94
+ self.title=''
95
+ self.message=''
96
+ self.style=''
97
+ self.large_icon_path=''
98
+ self.big_picture_path=''
99
+ self.progress_current_value=0
100
+ self.progress_max_value=100
101
+ # Advance Options
102
+ self.channel_name=''
103
+ self.channel_id=''
104
+ self.silent=False
105
+ # During Dev on PC
106
+ self.logs=self.logs
107
+ # Private (Don't Touch)
108
+ self.__id = self.__getUniqueID()
109
+ self.__setArgs(kwargs)
110
+ self.__builder=None
111
+ if not ON_ANDROID:
112
+ return
113
+ # TODO make send method wait for __asks_permission_if_needed method
114
+ self.__asks_permission_if_needed()
115
+ self.notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
116
+
117
+ def updateTitle(self,new_title):
118
+ """Changes Old Title
119
+
120
+ Args:
121
+ new_title (str): New Notification Title
122
+ """
123
+ self.title=new_title
124
+ if ON_ANDROID:
125
+ self.__builder.setContentTitle(new_title)
126
+
127
+ def updateMessage(self,new_message):
128
+ """Changes Old Message
129
+
130
+ Args:
131
+ new_message (str): New Notification Message
132
+ """
133
+ self.message=new_message
134
+ if ON_ANDROID:
135
+ self.__builder.setContentText(new_message)
136
+
137
+ def updateProgressBar(self,current_value,message:str=''):
138
+ """message defaults to last message"""
139
+ self.__builder.setProgress(self.progress_max_value, current_value, False)
140
+ if message:
141
+ self.__builder.setContentText(String(message))
142
+ self.notification_manager.notify(self.__id, self.__builder.build())
143
+
144
+ def removeProgressBar(self,message=''):
145
+ """message defaults to last message"""
146
+ if message:
147
+ self.__builder.setContentText(String(message))
148
+ self.__builder.setProgress(0, 0, False)
149
+ self.notification_manager.notify(self.__id, self.__builder.build())
150
+
151
+ def send(self,silent:bool=False):
152
+ """Sends notification
153
+
154
+ Args:
155
+ silent (bool): True if you don't want to show briefly on screen
156
+ """
157
+ self.silent=self.silent or silent
158
+ if ON_ANDROID:
159
+ self.__startNotificationBuild()
160
+ self.notification_manager.notify(self.__id, self.__builder.build())
161
+ elif self.logs:
162
+ print(f"""
163
+ Dev Notification Properties:
164
+ title: '{self.title}'
165
+ message: '{self.message}'
166
+ large_icon_path: '{self.large_icon_path}'
167
+ big_picture_path: '{self.big_picture_path}'
168
+ style: '{self.style}'
169
+ Silent: '{self.silent}'
170
+ (Won't Print Logs When Complied,except if selected `Notification.logs=True`
171
+ """)
172
+ if DEV:
173
+ print(f'channel_name: {self.channel_name}, Channel ID: {self.channel_id}, id: {self.__id}')
174
+ 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
175
+
176
+ def __validateArgs(self,inputted_kwargs):
177
+
178
+ def checkInReference(inputted_keywords,accepteable_inputs,input_type):
179
+ def singularForm(plural_form):
180
+ return plural_form[:-1]
181
+ invalid_args= set(inputted_keywords) - set(accepteable_inputs)
182
+ if invalid_args:
183
+ suggestions=[]
184
+ for arg in invalid_args:
185
+ closest_match = difflib.get_close_matches(arg,accepteable_inputs,n=2,cutoff=0.6)
186
+ if closest_match:
187
+ suggestions.append(f"* '{arg}' Invalid -> Did you mean '{closest_match[0]}'? ") # pylint: disable=C0301
188
+ else:
189
+ suggestions.append(f"* {arg} is not a valid {singularForm(input_type)}.")
190
+ suggestion_text='\n'.join(suggestions)
191
+ hint_msg=singularForm(input_type) if len(invalid_args) < 2 else input_type
192
+
193
+ raise ValueError(f"Invalid {hint_msg} provided: \n\t{suggestion_text}\n\t* list of valid {input_type}: [{', '.join(accepteable_inputs)}]")
194
+
195
+ allowed_keywords=self.defaults.keys()
196
+ inputted_keywords_=inputted_kwargs.keys()
197
+ checkInReference(inputted_keywords_,allowed_keywords,'arguments')
198
+
199
+ # Validate style values
200
+ if 'style' in inputted_keywords_ and inputted_kwargs['style'] not in self.style_values:
201
+ checkInReference([inputted_kwargs['style']],self.style_values,'values')
202
+
203
+ def __setArgs(self,options_dict:dict):
204
+ for key,value in options_dict.items():
205
+ if key == 'channel_name':
206
+ setattr(self,key, value[:40] if value else self.defaults[key])
207
+ elif key == 'channel_id' and value:
208
+ setattr(self,key, self.__generate_channel_id(value) if value else self.defaults[key])
209
+
210
+ setattr(self,key, value if value else self.defaults[key])
211
+
212
+ if "channel_id" not in options_dict and 'channel_name' in options_dict:
213
+ setattr(self,'channel_id', self.__generate_channel_id(options_dict['channel_name']))
214
+
215
+ def __startNotificationBuild(self):
216
+ self.__createBasicNotification()
217
+ if self.style not in ['simple','']:
218
+ self.__addNotificationStyle()
219
+
220
+ def __createBasicNotification(self):
221
+ # Notification Channel (Required for Android 8.0+)
222
+ if BuildVersion.SDK_INT >= 26 and self.notification_manager.getNotificationChannel(self.channel_id) is None:
223
+ importance=NotificationManagerCompat.IMPORTANCE_DEFAULT if self.silent else NotificationManagerCompat.IMPORTANCE_HIGH # pylint: disable=possibly-used-before-assignment
224
+ channel = NotificationChannel(
225
+ self.channel_id,
226
+ self.channel_name,
227
+ importance
228
+ )
229
+ self.notification_manager.createNotificationChannel(channel)
230
+
231
+ # 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)
235
+ self.__builder.setSmallIcon(context.getApplicationInfo().icon)
236
+ self.__builder.setDefaults(NotificationCompat.DEFAULT_ALL) # pylint: disable=E0606
237
+ if not self.silent:
238
+ self.__builder.setPriority(NotificationCompat.PRIORITY_DEFAULT if self.silent else NotificationCompat.PRIORITY_HIGH)
239
+
240
+ def __addNotificationStyle(self):
241
+ # pylint: disable=trailing-whitespace
242
+
243
+ large_icon_javapath=None
244
+ if self.large_icon_path:
245
+ try:
246
+ large_icon_javapath = self.__get_image_uri(self.large_icon_path)
247
+ except FileNotFoundError as e:
248
+ print('Failed Adding Big Picture Bitmap: ',e)
249
+
250
+ big_pic_javapath=None
251
+ if self.big_picture_path:
252
+ try:
253
+ big_pic_javapath = self.__get_image_uri(self.big_picture_path)
254
+ except FileNotFoundError as e:
255
+ print('Failed Adding Lagre Icon Bitmap: ',e)
256
+
257
+
258
+ if self.style == "big_text":
259
+ big_text_style = NotificationCompatBigTextStyle() # pylint: disable=E0606
260
+ big_text_style.bigText(self.message)
261
+ self.__builder.setStyle(big_text_style)
262
+
263
+ elif self.style == "inbox":
264
+ inbox_style = NotificationCompatInboxStyle() # pylint: disable=E0606
265
+ for line in self.message.split("\n"):
266
+ inbox_style.addLine(line)
267
+ self.__builder.setStyle(inbox_style)
268
+
269
+ elif self.style == "big_picture" and big_pic_javapath:
270
+ big_pic_bitmap = self.__getBitmap(big_pic_javapath)
271
+ big_picture_style = NotificationCompatBigPictureStyle().bigPicture(big_pic_bitmap) # pylint: disable=E0606
272
+ self.__builder.setStyle(big_picture_style)
273
+
274
+ elif self.style == "large_icon" and large_icon_javapath:
275
+ large_icon_bitmap = self.__getBitmap(large_icon_javapath)
276
+ self.__builder.setLargeIcon(large_icon_bitmap)
277
+
278
+ elif self.style == 'both_imgs' and (large_icon_javapath or big_pic_javapath):
279
+ if big_pic_javapath:
280
+ big_pic_bitmap = self.__getBitmap(big_pic_javapath)
281
+ big_picture_style = NotificationCompatBigPictureStyle().bigPicture(big_pic_bitmap)
282
+ self.__builder.setStyle(big_picture_style)
283
+ elif large_icon_javapath:
284
+ large_icon_bitmap = self.__getBitmap(large_icon_javapath)
285
+ self.__builder.setLargeIcon(large_icon_bitmap)
286
+ elif self.style == 'progress':
287
+ self.__builder.setContentTitle(String(self.title))
288
+ self.__builder.setContentText(String(self.message))
289
+ self.__builder.setProgress(self.progress_max_value, self.progress_current_value, False)
290
+ # elif self.style == 'custom':
291
+ # self.__builder = self.__doCustomStyle()
292
+
293
+ # def __doCustomStyle(self):
294
+ # # TODO Will implement when needed
295
+ # return self.__builder
296
+
297
+ def __getUniqueID(self):
298
+ reasonable_amount_of_notifications=101
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)
302
+ self.notification_ids.append(notification_id)
303
+ return notification_id
304
+
305
+ def __asks_permission_if_needed(self):
306
+ """
307
+ Ask for permission to send notifications if needed.
308
+ """
309
+ def on_permissions_result(permissions, grant): # pylint: disable=unused-argument
310
+ if self.logs:
311
+ print("Permission Grant State: ",grant)
312
+
313
+ permissions=[Permission.POST_NOTIFICATIONS] # pylint: disable=E0606
314
+ if not all(check_permission(p) for p in permissions):
315
+ request_permissions(permissions,on_permissions_result) # pylint: disable=E0606
316
+
317
+ def __get_image_uri(self,relative_path):
318
+ """
319
+ Get the absolute URI for an image in the assets folder.
320
+ :param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
321
+ :return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
322
+ """
323
+
324
+ output_path = os.path.join(app_storage_path(),'app', relative_path) # pylint: disable=possibly-used-before-assignment
325
+ # print(output_path) # /data/user/0/(package.domain+package.name)/files/app/assets/imgs/icon.png | pylint: disable=:line-too-long
326
+
327
+ if not os.path.exists(output_path):
328
+ # TODO Use images From Any where even Web
329
+ raise FileNotFoundError(f"Image not found at path: {output_path}, (Can Only Use Images in App Path)")
330
+ Uri = autoclass('android.net.Uri')
331
+ return Uri.parse(f"file://{output_path}")
332
+ def __getBitmap(self,img_path):
333
+ return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(img_path))
334
+
335
+ def __generate_channel_id(self,channel_name: str) -> str:
336
+ """
337
+ Generate a readable and consistent channel ID from a channel name.
338
+
339
+ Args:
340
+ channel_name (str): The name of the notification channel.
341
+
342
+ Returns:
343
+ str: A sanitized channel ID.
344
+ """
345
+ # Normalize the channel name
346
+ channel_id = channel_name.strip().lower()
347
+ # Replace spaces and special characters with underscores
348
+ channel_id = re.sub(r'[^a-z0-9]+', '_', channel_id)
349
+ # Remove leading/trailing underscores
350
+ channel_id = channel_id.strip('_')
351
+ return channel_id[:50]
352
+
353
+ # try:
354
+ # notify=Notification(titl='My Title',channel_name='Go')#,logs=False)
355
+ # # notify.channel_name='Downloads'
356
+ # notify.message="Blah"
357
+ # notify.send()
358
+ # notify.updateTitle('New Title')
359
+ # notify.updateMessage('New Message')
360
+ # notify.send(True)
361
+ # except Exception as e:
362
+ # print(e)
363
+
364
+ # notify=Notification(title='My Title1')
365
+ # # notify.updateTitle('New Title1')
366
+ # notify.send()
367
+
368
+
369
+ # Notification.logs=False # Add in Readme
370
+ # notify=Notification(style='large_icon',title='My Title',channel_name='Some thing about a thing ')#,logs=False)
371
+ # # notify.channel_name='Downloads'
372
+ # notify.message="Blah"
373
+ # notify.send()
374
+ # notify.updateTitle('New Title')
375
+ # notify.updateMessage('New Message')
@@ -0,0 +1,350 @@
1
+ Metadata-Version: 2.1
2
+ Name: android-notify
3
+ Version: 1.3
4
+ Summary: A Python package that simpilfies creating Android Post notifications using PyJNIus in Kivy apps.
5
+ Home-page: https://github.com/fector101/android-notify
6
+ Author: Fabian
7
+ Author-email: fector101@yahoo.com
8
+ License: MIT
9
+ Project-URL: Documentation, https://github.com/fector101/android-notify/
10
+ Project-URL: Source, https://github.com/fector101/android-notify
11
+ Project-URL: Tracker, https://github.com/fector101/android-notify/issues
12
+ Project-URL: Funding, https://www.buymeacoffee.com/fector101
13
+ Keywords: android,notifications,kivy,mobile,post-notifications,pyjnius,android-notifications,kivy-notifications,python-android,mobile-development,push-notifications,mobile-app,kivy-application
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: Android
17
+ Classifier: Development Status :: 5 - Production/Stable
18
+ Classifier: Intended Audience :: Developers
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.6
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: kivy>=2.0.0
23
+ Requires-Dist: pyjnius>=1.4.2
24
+
25
+ # Android-Notifiy
26
+
27
+ A Python library for effortlessly creating and managing Android notifications in Kivy android apps.
28
+ Supports various styles and ensures seamless integration and customization.
29
+
30
+ ## Features
31
+
32
+ - Compatible with Android 8.0+.
33
+ - Supports including images in notifications.
34
+ - Support for multiple notification styles:
35
+ - Progress
36
+ - Big Picture
37
+ - Inbox
38
+ - Big Text
39
+ - Large Icon
40
+
41
+ This module automatically handles:
42
+
43
+ - Permission requests for notifications
44
+ - Customizable notification channels.
45
+
46
+ ## Installation
47
+
48
+ This package is available on PyPI and can be installed via pip:
49
+
50
+ ```bash
51
+ pip install android-notify
52
+ ```
53
+
54
+ ## **Dependencies**
55
+
56
+ **Prerequisites:**
57
+
58
+ - Kivy
59
+
60
+ In your **`buildozer.spec`** file, ensure you include the following:
61
+
62
+ ```ini
63
+ # Add pyjnius so it's packaged with the build
64
+ requirements = python3, kivy, pyjnius, android-notify
65
+
66
+ # Add permission for notifications
67
+ android.permissions = POST_NOTIFICATIONS
68
+
69
+ # Required dependencies (write exactly as shown, no quotation marks)
70
+ android.gradle_dependencies = androidx.core:core:1.6.0, androidx.core:core-ktx:1.15.0
71
+ android.enable_androidx = True
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Basic Usage
77
+
78
+ ```python
79
+ from android_notify import Notification
80
+
81
+ # Create a simple notification
82
+ notification = Notification(
83
+ title="Hello",
84
+ message="This is a basic notification"
85
+ )
86
+ notification.send()
87
+ ```
88
+
89
+ **Sample Image:**
90
+ ![basic notification img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/basicnoti.jpg)
91
+
92
+ ## Notification Styles
93
+
94
+ The library supports multiple notification styles:
95
+
96
+ 1. `simple` - Basic notification with title and message
97
+ 2. `progress` - Shows a progress bar
98
+ 3. `big_text` - Expandable notification with long text
99
+ 4. `inbox` - List-style notification
100
+ 5. `big_picture` - Notification with a large image
101
+ 6. `large_icon` - Notification with a custom icon
102
+ 7. `both_imgs` - Combines big picture and large icon
103
+ 8. `custom` - For custom notification styles
104
+
105
+ ### Style Examples
106
+
107
+ #### Notification with an Image (Big Picture Style)
108
+
109
+ ```python
110
+ # Image notification
111
+ notification = Notification(
112
+ title='Picture Alert!',
113
+ message='This notification includes an image.',
114
+ style="big_picture",
115
+ big_picture_path="assets/imgs/photo.png"
116
+ )
117
+ ```
118
+
119
+ **Sample Image:**
120
+ ![big_picture img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/bigpicturenoti.jpg)
121
+
122
+ #### Inbox Notification Style
123
+
124
+ ```python
125
+ # Send a notification with inbox style
126
+ notification = Notification(
127
+ title='Inbox Notification',
128
+ message='Line 1\nLine 2\nLine 3',
129
+ style='inbox'
130
+ )
131
+ ```
132
+
133
+ **Sample Image:**
134
+ ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
135
+
136
+ #### Big text notification (Will Display as simple text if Device dosen't support)
137
+
138
+ ```python
139
+ notification = Notification(
140
+ title="Article",
141
+ message="Long article content...",
142
+ style="big_text"
143
+ )
144
+ ```
145
+
146
+ #### Progress bar notification
147
+
148
+ ```python
149
+ notification = Notification(
150
+ title="Download",
151
+ message="Downloading file...",
152
+ style="progress",
153
+ progress_max_value=100,
154
+ progress_current_value=0
155
+ )
156
+
157
+ ```
158
+
159
+ **Sample Image:**
160
+ ![progress img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/progress.jpg)
161
+
162
+ #### Notification with an Image (Large Icon Style)
163
+
164
+ ```python
165
+ notification = Notification(
166
+ title="Completed download",
167
+ message="profile.jpg",
168
+ style="large_icon",
169
+ large_icon_path="assets/imgs/profile.png"
170
+ )
171
+
172
+ ```
173
+
174
+ **Sample Image:**
175
+ ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
176
+
177
+ ## Advanced Features
178
+
179
+ ### Updating Notifications
180
+
181
+ ```python
182
+ notification = Notification(title="Initial Title")
183
+ notification.send()
184
+
185
+ # Update title
186
+ notification.updateTitle("New Title")
187
+
188
+ # Update message
189
+ notification.updateMessage("New Message")
190
+ ```
191
+
192
+ ### Progress Bar Management
193
+
194
+ ```python
195
+ notification = Notification(
196
+ title="Download Progress",
197
+ style="progress"
198
+ )
199
+
200
+ # Update progress
201
+ notification.updateProgressBar(50, "50% Complete")
202
+
203
+ # Remove progress bar
204
+ notification.removeProgressBar("Download Complete")
205
+ ```
206
+
207
+ ### Channel Management
208
+
209
+ Notifications are organized into channels. You can customize the channel name and ID:
210
+
211
+ - Custom Channel Name's Gives User ability to turn on/off specific
212
+
213
+ ```python
214
+ notification = Notification(
215
+ title="Download finished",
216
+ message="How to Catch a Fish.mp4",
217
+ channel_name="Download Notifications", # Will create User-visible name "downloads"
218
+ channel_id="custom_downloads" # Optional: specify custom channel ID
219
+ )
220
+ ```
221
+
222
+ **Sample Image:**
223
+ ![channels img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/channel_name.jpg)
224
+
225
+ ### Silent Notifications
226
+
227
+ To send a notification without sound or heads-up display:
228
+
229
+ ```python
230
+ notification = Notification(title="Silent Update")
231
+ notification.send(silent=True)
232
+ ```
233
+
234
+ ### Assist
235
+
236
+ - How to Copy image to app folder
237
+
238
+ ```python
239
+ import shutil,os # These modules come packaged with python
240
+ from android.storage import app_storage_path # type: ignore -- This works only on android
241
+
242
+ app_path = os.path.join(app_storage_path(),'app')
243
+ image_path= "/storage/emulated/0/Download/profile.png"
244
+
245
+ shutil.copy(image_path, os.path.join(app_path, "profile.png"))
246
+ ```
247
+
248
+ - Avoiding Human Error when using different notification styles
249
+
250
+ ```python
251
+ from android_notify import Notification, NotificationStyles
252
+ notification = Notification(
253
+ title="New Photo",
254
+ message="Check out this image",
255
+ style=NotificationStyles.BIG_PICTURE,
256
+ big_picture_path="assets/imgs/photo.png"
257
+ ).send()
258
+ ```
259
+
260
+ ## Development Mode
261
+
262
+ When developing on non-Android platforms, the library provides debugging output:
263
+
264
+ ```python
265
+ # Enable logs (default is True when not on Android)
266
+ Notification.logs = True
267
+
268
+ # Create notification for testing
269
+ notification = Notification(title="Test")
270
+ notification.send()
271
+ # Will print notification properties instead of sending
272
+ ```
273
+
274
+ ## Image Requirements
275
+
276
+ - Images must be located within your app's asset folder
277
+ - Supported paths are relative to your app's storage path
278
+ - Example: `assets/imgs/icon.png`
279
+
280
+ ## Error Handling
281
+
282
+ The library validates arguments and provides helpful error messages:
283
+
284
+ - Invalid style names will suggest the closest matching style
285
+ - Invalid arguments will list all valid options
286
+ - Missing image files will raise FileNotFoundError with the attempted path
287
+
288
+ ## Limitations
289
+
290
+ 1. Only works on Android devices
291
+ 2. Images must be within the app's storage path
292
+ 3. Channel names are limited to 40 characters
293
+ 4. Channel IDs are limited to 50 characters
294
+
295
+ ## Best Practices
296
+
297
+ 1. Always handle permissions appropriately
298
+ 2. Use meaningful channel names for organization
299
+ 3. Keep progress bar updates reasonable (don't update too frequently)
300
+ 4. Test notifications on different Android versions
301
+ 5. Consider using silent notifications for frequent updates
302
+
303
+ ## Debugging Tips
304
+
305
+ 1. Enable logs during development: `Notification.logs = True`
306
+ 2. Check channel creation with Android's notification settings
307
+ 3. Verify image paths before sending notifications
308
+ 4. Test different styles to ensure proper display
309
+
310
+ Remember to check Android's notification documentation for best practices and guidelines regarding notification frequency and content.
311
+
312
+ ## Contribution
313
+
314
+ Feel free to open issues or submit pull requests for improvements!
315
+
316
+ ## Reporting Issues
317
+
318
+ Found a bug? Please open an issue on our [GitHub Issues](https://github.com/Fector101/android_notify/issues) page.
319
+
320
+ ## Author
321
+
322
+ - Fabian - <fector101@yahoo.com>
323
+ - GitHub: [Android Notify Repo](https://github.com/Fector101/android_notify)
324
+ - Twitter: [FabianDev_](https://twitter.com/intent/user?user_id=1246911115319263233)
325
+
326
+ For feedback or contributions, feel free to reach out!
327
+
328
+ ---
329
+
330
+ ## ☕ Support the Project
331
+
332
+ If you find this project helpful, consider buying me a coffee! 😊 Or Giving it a star on 🌟 [GitHub](https://github.com/Fector101/android_notify/) Your support helps maintain and improve the project.
333
+
334
+ <a href="https://www.buymeacoffee.com/fector101" target="_blank">
335
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
336
+ </a>
337
+
338
+ ---
339
+
340
+ ## Acknowledgments
341
+
342
+ - This Project was thoroughly Tested by the [Laner Project](https://github.com/Fector101/Laner/) - A application for Securely Transfering Files Wirelessly between your PC and Phone.
343
+ - Thanks to the Kivy and Pyjnius communities.
344
+
345
+ ---
346
+
347
+ ## 🌐 **Links**
348
+
349
+ - **PyPI:** [android-notify on PyPI](https://pypi.org/project/android-notify/)
350
+ - **GitHub:** [Source Code Repository](https://github.com/Fector101/android_notify/)
@@ -0,0 +1,9 @@
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,,
@@ -1,210 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: android_notify
3
- Version: 1.2
4
- Summary: A Python package for sending Android notifications.
5
- Home-page: https://github.com/Fector101/android_notify/
6
- Author: Fabian
7
- Author-email: fabianjoseph063@gmail.com
8
- Project-URL: Funding, https://buymeacoffee.com/fector101
9
- Project-URL: Source, https://github.com/Fector101/android_notify/
10
- Requires-Python: >=3.6
11
- Description-Content-Type: text/markdown
12
- Requires-Dist: pyjnius
13
-
14
- # Android Notify
15
-
16
- `android_notify` is a Python module designed to simplify sending Android notifications using Kivy and Pyjnius. It supports multiple notification styles, including text, images, and inbox layouts.
17
-
18
- ## Features
19
-
20
- - Send Android notifications with custom titles and messages.
21
- - Support for multiple notification styles:
22
- - Big Text
23
- - Big Picture
24
- - Large Icon
25
- - Inbox
26
- - Supports including images in notifications.
27
- - Compatible with Android 8.0+ (Notification Channels).
28
- - Customizable notification channels.
29
-
30
- ## Installation
31
-
32
- This package is available on PyPI and can be installed via pip:
33
-
34
- ```bash
35
- pip install android-notify
36
- ```
37
-
38
- ## **Dependencies**
39
-
40
- **Prerequisites:**
41
-
42
- - Buildozer
43
- - Kivy
44
-
45
- In your **`buildozer.spec`** file, ensure you include the following:
46
-
47
- ```ini
48
- # Add pyjnius so it's packaged with the build
49
- requirements = python3,kivy,pyjnius
50
-
51
- # Add permission for notifications
52
- android.permissions = POST_NOTIFICATIONS
53
-
54
- # Required dependencies (write exactly as shown, no quotation marks)
55
- android.gradle_dependencies = androidx.core:core:1.6.0, androidx.core:core-ktx:1.15.0
56
- android.enable_androidx = True
57
- ```
58
-
59
- ---
60
-
61
- ### Example Notification
62
-
63
- ```python
64
- from android_notify.core import send_notification
65
-
66
- # Send a basic notification
67
- send_notification("Hello", "This is a basic notification.")
68
-
69
- # Send a notification with an image
70
- send_notification(
71
- title='Picture Alert!',
72
- message='This notification includes an image.',
73
- style='big_picture',
74
- img_path='assets/imgs/icon.png'
75
- )
76
-
77
- # Send a notification with inbox style
78
- send_notification(
79
- title='Inbox Notification',
80
- message='Line 1\nLine 2\nLine 3',
81
- style='inbox'
82
- )
83
-
84
- # Send a Big Text notification (Note this send as a normal notification if not supported on said device)
85
- send_notification(
86
- title='Hello!',
87
- message='This is a sample notification.',
88
- style='big_text'
89
- )
90
- ```
91
-
92
- ---
93
-
94
- ### **Assist** -- How to Copy image to app folder
95
-
96
- ```python
97
- import shutil # This module comes packaged with python
98
- from android.storage import app_storage_path # type: ignore -- This works only on android
99
-
100
- app_path = os.path.join(app_storage_path(),'app')
101
- image_path= "/storage/emulated/0/Download/profile.png"
102
-
103
- shutil.copy(image_path, os.path.join(app_path, "profile.png"))
104
- ```
105
-
106
- ---
107
-
108
- ### **Functions Reference**
109
-
110
- ### 1. `asks_permission_if_needed()`
111
-
112
- **Description:**
113
-
114
- - Checks if notification permissions are granted and requests them if missing.
115
-
116
- **Usage:**
117
-
118
- ```python
119
- asks_permission_if_needed()
120
- ```
121
-
122
- ---
123
-
124
- ### 2. `get_image_uri(relative_path)`
125
-
126
- **Description:**
127
-
128
- - Resolves the absolute URI for an image in the app's storage.
129
-
130
- **Parameters:**
131
-
132
- - `relative_path` *(str)*: Path to the image (e.g., `assets/imgs/icon.png`).
133
-
134
- **Returns:**
135
-
136
- - `Uri`: Android URI object for the image.
137
-
138
- **Usage:**
139
-
140
- ```python
141
- uri = get_image_uri('assets/imgs/icon.png')
142
- ```
143
-
144
- ---
145
-
146
- ### 3. `send_notification(title, message, style=None, img_path=None, channel_id='default_channel')`
147
-
148
- **Description:**
149
-
150
- - Sends an Android notification with optional styles and images.
151
-
152
- **Parameters:**
153
-
154
- - `title` *(str)*: Notification title.
155
- - `message` *(str)*: Notification message.
156
- - `style` *(str, optional)*: Notification style (`big_text`, `big_picture`, `inbox`, `large_icon`).
157
- - `img_path` *(str, optional)*: Path to the image resource.(for `big_picture` or `large_icon` styles).
158
- - `channel_id` *(str, optional)*: Notification channel ID.
159
-
160
- Returns - notification id
161
-
162
- ### Advanced Usage
163
-
164
- You can customize notification channels for different types of notifications.
165
-
166
- ```python
167
- send_notification(
168
- title='Custom Channel Notification',
169
- message='This uses a custom notification channel.',
170
- channel_id='custom_channel'
171
- )
172
- ```
173
-
174
- ## Contribution
175
-
176
- Feel free to open issues or submit pull requests for improvements!
177
-
178
- ## 🐛 Reporting Issues
179
-
180
- Found a bug? Please open an issue on our [GitHub Issues](https://github.com/Fector101/android_notify/issues) page.
181
-
182
- ## Author
183
-
184
- - Fabian - <fector101@yahoo.com>
185
- - GitHub: <https://github.com/Fector101/android_notify>
186
-
187
- For feedback or contributions, feel free to reach out!
188
-
189
- ---
190
-
191
- ## ☕ Support the Project
192
-
193
- If you find this project helpful, consider buying me a coffee! Your support helps maintain and improve the project.
194
-
195
- <a href="https://www.buymeacoffee.com/fector101" target="_blank">
196
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
197
- </a>
198
-
199
- ---
200
-
201
- ## Acknowledgments
202
-
203
- - Thanks to the Kivy and Pyjnius communities for their support.
204
-
205
- ---
206
-
207
- ## 🌐 **Links**
208
-
209
- - **PyPI:** [android-notify on PyPI](https://pypi.org/project/android-notify/)
210
- - **GitHub:** [Source Code Repository](hhttps://github.com/Fector101/android_notify/)
@@ -1,8 +0,0 @@
1
- android_notify/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- android_notify/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- android_notify/core.py,sha256=P80jtB4Dim9c10ibgVPioEDJOKgjcoetl7rHAHEZEAI,5960
4
- android_notify/styles.py,sha256=P_8sAqb3Hbf_vbhqSoCVjKeqJ05Fr_CksO-HX5pj8pU,134
5
- android_notify-1.2.dist-info/METADATA,sha256=pkhzt6TaEZ1gTTEShVpXrATujLqcsVA-GQn3g7X65Qg,5125
6
- android_notify-1.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
7
- android_notify-1.2.dist-info/top_level.txt,sha256=IR1ONMrRSRINZpWn2X0dL5gbWwWINsK7PW8Jy2p4fU8,15
8
- android_notify-1.2.dist-info/RECORD,,