android-notify 1.55__tar.gz → 1.56__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.55
3
+ Version: 1.56
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 .facade import BaseNotification
8
+ from .base import BaseNotification
9
9
  DEV=0
10
10
  ON_ANDROID = False
11
11
 
@@ -31,7 +31,7 @@ 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
- print(MESSAGE)
34
+ # print(MESSAGE) Already Printing in core.py
35
35
 
36
36
  # This is so no crashes when developing on PC
37
37
  def run_on_ui_thread(func):
@@ -55,8 +55,7 @@ if ON_ANDROID:
55
55
  NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle') # pylint: disable=C0301
56
56
  NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
57
57
  except Exception as e:# pylint: disable=W0718
58
- print(e)# if DEV else '','Import Fector101')
59
- # print(e if DEV else '')
58
+ print(e)
60
59
  print("""
61
60
  Dependency Error: Add the following in buildozer.spec:
62
61
  * android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
@@ -91,46 +90,28 @@ class Notification(BaseNotification):
91
90
  button_ids=[0]
92
91
  btns_box={}
93
92
  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
93
 
118
94
  # During Development (When running on PC)
119
- logs=not ON_ANDROID
95
+ BaseNotification.logs=not ON_ANDROID
120
96
  def __init__(self,**kwargs): #pylint: disable=W0231 #@dataclass already does work
121
- self.__validateArgs(kwargs)
122
- # Private (Don't Touch)
97
+ super().__init__(**kwargs)
98
+
123
99
  self.__id = self.__getUniqueID()
124
- self.__setArgs(kwargs)
125
100
  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
-
101
+ self.__formatChannel(kwargs)
127
102
  if not ON_ANDROID:
128
103
  return
129
104
  # TODO make send method wait for __asks_permission_if_needed method
130
105
  self.__asks_permission_if_needed()
131
106
  self.notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
132
107
  self.__builder=NotificationCompatBuilder(context, self.channel_id)# pylint: disable=E0606
133
-
108
+ def showInfiniteProgressBar(self):
109
+ """Displays an (Infinite) progress Bar in Notification, that continues loading indefinitely.
110
+ Can be Removed By `removeProgressBar` Method
111
+ """
112
+ self.__builder.setProgress(0,0, True)
113
+ self.__dispatchNotification()
114
+
134
115
  def updateTitle(self,new_title):
135
116
  """Changes Old Title
136
117
 
@@ -142,7 +123,7 @@ class Notification(BaseNotification):
142
123
  print(f'new notification title: {self.title}')
143
124
  if ON_ANDROID:
144
125
  self.__builder.setContentTitle(String(self.title))
145
- self.notification_manager.notify(self.__id, self.__builder.build())
126
+ self.__dispatchNotification()
146
127
 
147
128
  def updateMessage(self,new_message):
148
129
  """Changes Old Message
@@ -155,7 +136,7 @@ class Notification(BaseNotification):
155
136
  print(f'new notification message: {self.message}')
156
137
  if ON_ANDROID:
157
138
  self.__builder.setContentText(String(self.message))
158
- self.notification_manager.notify(self.__id, self.__builder.build())
139
+ self.__dispatchNotification()
159
140
 
160
141
  def updateProgressBar(self,current_value:int,message:str='',title:str=''):
161
142
  """Updates progress bar current value
@@ -189,14 +170,14 @@ class Notification(BaseNotification):
189
170
  self.updateMessage(message)
190
171
  if title:
191
172
  self.updateTitle(title)
192
- self.notification_manager.notify(self.__id, self.__builder.build())
173
+ self.__dispatchNotification()
193
174
  self.__update_timer = None
194
175
 
195
176
 
196
177
  # Start a new timer that runs after 0.5 seconds
197
178
  self.__update_timer = threading.Timer(0.5, delayed_update)
198
179
  self.__update_timer.start()
199
-
180
+
200
181
  def removeProgressBar(self,message='',show_on_update=True, title:str='') -> None:
201
182
  """Removes Progress Bar from Notification
202
183
 
@@ -223,7 +204,7 @@ class Notification(BaseNotification):
223
204
  if title:
224
205
  self.updateTitle(title)
225
206
  self.__builder.setProgress(0, 0, False)
226
- self.notification_manager.notify(self.__id, self.__builder.build())
207
+ self.__dispatchNotification()
227
208
  return True
228
209
 
229
210
  def send(self,silent:bool=False,persistent=False,close_on_click=True):
@@ -237,13 +218,18 @@ class Notification(BaseNotification):
237
218
  self.silent=self.silent or silent
238
219
  if ON_ANDROID:
239
220
  self.__startNotificationBuild(persistent,close_on_click)
240
- self.notification_manager.notify(self.__id, self.__builder.build())
241
- elif self.logs:
221
+ self.__dispatchNotification()
222
+ if self.logs:
242
223
  string_to_display=''
243
224
  print("\n Sent Notification!!!")
244
225
  for name,value in vars(self).items():
245
226
  if value and name in ["title", "message", "style", "body", "large_icon_path", "big_picture_path", "progress_current_value", "progress_max_value", "channel_name"]:
246
- string_to_display += f'\n {name}: {value}'
227
+ if name == "progress_max_value":
228
+ if self.style == NotificationStyles.PROGRESS:
229
+ string_to_display += f'\n {name}: {value}'
230
+ else:
231
+ string_to_display += f'\n {name}: {value}'
232
+
247
233
  string_to_display +="\n (Won't Print Logs When Complied,except if selected `Notification.logs=True`)"
248
234
  print(string_to_display)
249
235
  if DEV:
@@ -304,7 +290,7 @@ class Notification(BaseNotification):
304
290
  """
305
291
  if ON_ANDROID:
306
292
  self.__builder.mActions.clear()
307
- self.notification_manager.notify(self.__id, self.__builder.build())
293
+ self.__dispatchNotification()
308
294
  if self.logs:
309
295
  print('Removed Notication Buttons')
310
296
 
@@ -343,60 +329,17 @@ class Notification(BaseNotification):
343
329
  self.__buildImg(self.large_icon_path, NotificationStyles.LARGE_ICON)
344
330
 
345
331
  elif style == NotificationStyles.PROGRESS:
346
- self.__builder.setContentTitle(String(self.title))
347
- self.__builder.setContentText(String(self.message))
348
332
  self.__builder.setProgress(self.progress_max_value, self.progress_current_value, False)
349
333
 
350
334
  if already_sent:
351
- self.notification_manager.notify(self.__id, self.__builder.build())
335
+ self.__dispatchNotification()
352
336
 
353
337
  return True
354
338
  # elif style == 'custom':
355
339
  # self.__builder = self.__doCustomStyle()
356
340
 
357
- def __validateArgs(self,inputted_kwargs):
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
-
341
+ def __dispatchNotification(self):
342
+ self.notification_manager.notify(self.__id, self.__builder.build())
400
343
  def __startNotificationBuild(self,persistent,close_on_click):
401
344
  self.__createBasicNotification(persistent,close_on_click)
402
345
  if self.style not in ['simple','']:
@@ -427,7 +370,7 @@ class Notification(BaseNotification):
427
370
  self.__builder.setOngoing(persistent)
428
371
  self.__builder.setAutoCancel(close_on_click)
429
372
  self.__addIntentToOpenApp()
430
-
373
+
431
374
  # def __doCustomStyle(self):
432
375
  # # TODO Will implement when needed
433
376
  # return self.__builder
@@ -436,7 +379,7 @@ class Notification(BaseNotification):
436
379
  self.__setIconFromBitmap(self.app_icon)
437
380
  else:
438
381
  self.__builder.setSmallIcon(context.getApplicationInfo().icon)
439
-
382
+
440
383
  def __buildImg(self, user_img,img_style):
441
384
  if user_img.startswith('http://') or user_img.startswith('https://'):
442
385
  def callback(bitmap):
@@ -450,7 +393,7 @@ class Notification(BaseNotification):
450
393
  bitmap = self.__getImgFromPath(user_img)
451
394
  if bitmap:
452
395
  self.__applyNotificationImage(bitmap,img_style)
453
-
396
+
454
397
  def __setIconFromBitmap(self,img_path):
455
398
  """Path can be link or relative path"""
456
399
  if img_path.startswith('http://') or img_path.startswith('https://'):
@@ -470,8 +413,7 @@ class Notification(BaseNotification):
470
413
  if self.logs:
471
414
  print('Failed getting img for custom notification icon defaulting to app icon')
472
415
  self.__builder.setSmallIcon(context.getApplicationInfo().icon)
473
-
474
-
416
+
475
417
  def __getImgFromPath(self, relative_path):
476
418
  app_folder=os.path.join(app_storage_path(),'app') # pylint: disable=possibly-used-before-assignment
477
419
  output_path = os.path.join(app_folder, relative_path)
@@ -511,25 +453,6 @@ class Notification(BaseNotification):
511
453
  print('Error Type ',e)
512
454
  print('Failed to get Bitmap from URL ',traceback.format_exc())
513
455
 
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
456
  @run_on_ui_thread
534
457
  def __applyNotificationImage(self,bitmap,img_style):
535
458
  if self.logs:
@@ -540,7 +463,7 @@ class Notification(BaseNotification):
540
463
  self.__builder.setStyle(big_picture_style)
541
464
  elif img_style == NotificationStyles.LARGE_ICON:
542
465
  self.__builder.setLargeIcon(bitmap)
543
- self.notification_manager.notify(self.__id, self.__builder.build())
466
+ self.__dispatchNotification()
544
467
  if self.logs:
545
468
  print('Done adding image to notification-------')
546
469
  except Exception as e:
@@ -565,24 +488,6 @@ class Notification(BaseNotification):
565
488
  if not all(check_permission(p) for p in permissions):
566
489
  request_permissions(permissions,on_permissions_result) # pylint: disable=E0606
567
490
 
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
491
  def __addIntentToOpenApp(self):
587
492
  intent = Intent(context, PythonActivity)
588
493
  action = str(self.identifer) or f"ACTION_{self.__id}"
@@ -609,6 +514,36 @@ class Notification(BaseNotification):
609
514
  self.button_ids.append(btn_id)
610
515
  return btn_id
611
516
 
517
+ def __formatChannel(self, inputted_kwargs):
518
+ if 'channel_name' in inputted_kwargs:
519
+ cleaned_name = inputted_kwargs['channel_name'].strip()
520
+ self.channel_name = cleaned_name[:40] if cleaned_name else 'Default Channel'
521
+
522
+ if 'channel_id' in inputted_kwargs:
523
+ cleaned_id = inputted_kwargs['channel_id'].strip()
524
+ self.channel_id = self.__generate_channel_id(cleaned_id) if cleaned_id else 'default_channel'
525
+ elif 'channel_name' in inputted_kwargs:
526
+ # Generate channel_id from channel_name if only channel_name is provided
527
+ generated_id = self.__generate_channel_id(inputted_kwargs['channel_name'])
528
+ self.channel_id = generated_id
529
+
530
+ def __generate_channel_id(self,channel_name: str) -> str:
531
+ """
532
+ Generate a readable and consistent channel ID from a channel name.
533
+
534
+ Args:
535
+ channel_name (str): The name of the notification channel.
536
+
537
+ Returns:
538
+ str: A sanitized channel ID.
539
+ """
540
+ # Normalize the channel name
541
+ channel_id = channel_name.strip().lower()
542
+ # Replace spaces and special characters with underscores
543
+ channel_id = re.sub(r'[^a-z0-9]+', '_', channel_id)
544
+ # Remove leading/trailing underscores
545
+ channel_id = channel_id.strip('_')
546
+ return channel_id[:50]
612
547
 
613
548
  class NotificationHandler:
614
549
  """For Notification Operations """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: android-notify
3
- Version: 1.55
3
+ Version: 1.56
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,8 +2,8 @@ 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
9
  android_notify.egg-info/PKG-INFO
@@ -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.55",
9
+ version="1.56",
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