android-notify 1.60.3__tar.gz → 1.60.4.dev0__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.
Files changed (31) hide show
  1. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/PKG-INFO +18 -88
  2. android_notify-1.60.4.dev0/README.md +110 -0
  3. android_notify-1.60.4.dev0/android_notify/an_types.py +251 -0
  4. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/an_utils.py +34 -14
  5. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/config.py +18 -26
  6. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/core.py +24 -29
  7. android_notify-1.60.4.dev0/android_notify/fallback-icons/flet-appicon.png +0 -0
  8. android_notify-1.60.4.dev0/android_notify/fallback-icons/pydroid3-appicon.png +0 -0
  9. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/sword.py +115 -48
  10. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/PKG-INFO +18 -88
  11. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/SOURCES.txt +2 -0
  12. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/pyproject.toml +4 -1
  13. android_notify-1.60.3/README.md +0 -180
  14. android_notify-1.60.3/android_notify/an_types.py +0 -226
  15. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/__init__.py +0 -0
  16. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/__main__.py +0 -0
  17. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/base.py +0 -0
  18. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify/styles.py +0 -0
  19. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/dependency_links.txt +0 -0
  20. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/entry_points.txt +0 -0
  21. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/requires.txt +0 -0
  22. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/android_notify.egg-info/top_level.txt +0 -0
  23. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/examples/flet-working/src/core.py +0 -0
  24. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/examples/flet-working/src/main.py +0 -0
  25. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/tests/flet/adv/main.py +0 -0
  26. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/tests/flet/adv/tests/__init__.py +0 -0
  27. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/tests/flet/adv/tests/test_android_notify_full.py +0 -0
  28. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/tests/flet/basic/src/core.py +0 -0
  29. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/tests/flet/basic/src/main.py +0 -0
  30. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/docs/website/src/pages/data/laner_Sent.py +0 -0
  31. {android_notify-1.60.3 → android_notify-1.60.4.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: android-notify
3
- Version: 1.60.3
3
+ Version: 1.60.4.dev0
4
4
  Summary: A Python package that simplifies creating Android notifications in Kivy and Flet apps.
5
5
  Author-email: Fabian <fector101@yahoo.com>
6
6
  License-Expression: MIT
@@ -79,81 +79,32 @@ In your **`buildozer.spec`** file, ensure you include the following:
79
79
 
80
80
  ```ini
81
81
  # Add pyjnius so ensure it's packaged with the build
82
- requirements = python3, kivy, pyjnius, android-notify
82
+ requirements = python3, kivy, pyjnius, android-notify==1.60.4.dev0
83
83
  # Add permission for notifications
84
84
  android.permissions = POST_NOTIFICATIONS
85
-
86
- # Required dependencies (write exactly as shown, no quotation marks)
87
- android.gradle_dependencies = androidx.core:core:1.6.0, androidx.core:core-ktx:1.15.0
88
- android.enable_androidx = True
89
- android.api = 35
90
85
  ```
91
86
 
92
87
  ### Flet apps:
93
- In your `pyproject.toml` file, ensure you include the following:
88
+
89
+ In your `pyproject.toml` file, ensure you include the following:
90
+
94
91
  ```toml
95
92
  [tool.flet.android]
96
93
  dependencies = [
97
- "pyjnius","https://github.com/Fector101/android_notify/archive/without-androidx.zip"
94
+ "pyjnius","android-notify==1.60.4.dev0"
98
95
  ]
99
96
 
100
97
  [tool.flet.android.permission]
101
98
  "android.permission.POST_NOTIFICATIONS" = true
102
99
  ```
103
- - example of [complete flet pyproject.toml](https://github.com/Fector101/flet-app/blob/main/pyproject.toml)
104
- ------
105
- ## Installing without Androidx
106
- How to use without `gradle_dependencies`
107
- Use `https://github.com/Fector101/android_notify/archive/without-androidx.zip` to install via `pip`
108
- ### In Kivy
109
- ```ini
110
- # buildozer.spec
111
- requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
112
- ```
113
100
 
114
- ### On Pydroid 3
115
- On the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
116
- - In pip section where you're asked to insert `Libary name` paste `https://github.com/Fector101/android_notify/archive/without-androidx.zip`
117
- - Minimal working example
118
- ```py
119
- # Testing with `https://github.com/Fector101/android_notify/archive/without-androidx.zip` on pydroid
120
- from kivy.app import App
121
- from kivy.uix.boxlayout import BoxLayout
122
- from kivy.uix.button import Button
123
- from android_notify import Notification
124
- from android_notify.core import asks_permission_if_needed
125
-
126
-
127
- class AndroidNotifyDemoApp(App):
128
- def build(self):
129
- layout = BoxLayout(orientation='vertical', spacing=10, padding=20)
130
- layout.add_widget(Button(
131
- text="Ask Notification Permission",
132
- on_release=self.request_permission
133
- ))
134
- layout.add_widget(Button(
135
- text="Send Notification",
136
- on_release=self.send_notification
137
- ))
138
- return layout
139
-
140
- def request_permission(self, *args):
141
- asks_permission_if_needed(no_androidx=True)
142
-
143
- def send_notification(self, *args):
144
- Notification(
145
- title="Hello from Android Notify",
146
- message="This is a basic notification.",
147
- channel_id="android_notify_demo",
148
- channel_name="Android Notify Demo"
149
- ).send()
150
-
151
-
152
- if __name__ == "__main__":
153
- AndroidNotifyDemoApp().run()
154
- ```
101
+ ### Pydroid 3
102
+ In the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
103
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.4.dev0`
104
+
155
105
 
156
- For IDE IntelliSense Can be installed via `pip install`:
106
+ ### Testing
107
+ Can be installed via `pip` For testing purposes:
157
108
 
158
109
  ```bash
159
110
  pip install android_notify
@@ -162,7 +113,7 @@ android-notify -v
162
113
 
163
114
  ## Documentation
164
115
  For Dev Version use
165
- ```requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/main.zip```
116
+ ```requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip```
166
117
 
167
118
 
168
119
  To use colored text in your notifications:
@@ -170,34 +121,13 @@ To use colored text in your notifications:
170
121
  Lastly in your `buildozer.spec` file
171
122
  - Add `source.include_exts = xml` and `android.add_resources = ./res`
172
123
 
173
- To use Custom Sounds
174
- - Put audio files in `res/raw` folder,
175
- - Then from `buildozer.spec` point to res folder `android.add_resources = res`
176
- - and includes it's format `source.include_exts = wav`.
177
-
178
- Lastly From the code
179
- ```py
180
- # Create a custom notification channel with a unique sound resource for android 8+
181
- Notification.createChannel(
182
- id="weird_sound_tester",
183
- name="Weird Sound Tester",
184
- description="A test channel used to verify custom notification sounds from the res/raw folder.",
185
- res_sound_name="sneeze" # file name without .wav or .mp3
186
- )
187
-
188
- # Send a notification through the created channel
189
- n=Notification(
190
- title="Custom Sound Notification",
191
- message="This tests playback of a custom sound (sneeze.wav) stored in res/raw.",
192
- channel_id="weird_sound_tester" # important tells notification to use right channel
193
- )
194
- n.setSound("sneeze")# for android 7 below
195
- n.send()
196
- ```
197
124
  For full documentation, examples, and advanced usage, API reference visit the
198
125
  [documentation](https://android-notify.vercel.app)
199
126
 
200
127
  ## ☕ Support the Project
201
128
 
202
- If you find this project helpful, any support would help me continue working on open-source projects. I’m currently saving for a laptop to keep developing and improving my skills.
203
- [donate](https://www.buymeacoffee.com/fector101)
129
+ 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.
130
+
131
+ <a href="https://www.buymeacoffee.com/fector101" target="_blank">
132
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
133
+ </a>
@@ -0,0 +1,110 @@
1
+ <div align="center">
2
+ <br>
3
+ <h1> Android-Notify </h1>
4
+ <p><a href='https://android-notify.vercel.app'>Android Notify</a> is a Python library for effortlessly creating and managing Android notifications in Kivy and Flet apps.</p>
5
+ <p>Supports various styles and ensures seamless integration, customization and Pythonic APIs.</p>
6
+ <!-- <br> -->
7
+ <!-- <img src="https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/democollage.jpg"> -->
8
+ </div>
9
+ <!-- Channel [CRUD]
10
+ The Android Notify package provides a simple yet comprehensive way to create and manage rich notifications on Android devices directly from your Python code. This library bridges the gap between Python and Android's notification system, giving you full control over notifications with a clean, Pythonic API. -->
11
+
12
+ ## Features
13
+
14
+ - **Multiple Notification Styles**: Support for various notification styles including:
15
+ - Simple text notifications
16
+ - [Progress bar notifications](https://android-notify.vercel.app/components#progress-bars) (determinate and indeterminate)
17
+ - Large icon notifications
18
+ - Big picture notifications
19
+ - Combined image styles
20
+ - Custom notification Icon - [images section](https://android-notify.vercel.app/components#images)
21
+ - Big text notifications
22
+ - Inbox-style notifications
23
+ - Colored texts and Icons
24
+
25
+ - **Rich Functionality**:
26
+ - Add action buttons with custom callbacks
27
+ - [Update notification](https://android-notify.vercel.app/advanced-methods#updating-notification) content dynamically
28
+ - Manage progress bars with fine-grained control
29
+ - [Custom notification channels](https://android-notify.vercel.app/advanced-methods#channel-management) for Android 8.0+ (Creating and Deleting)
30
+ - Silent notifications
31
+ - Persistent notifications
32
+ - Click handlers and callbacks
33
+ - Cancel Notifications
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ from android_notify import Notification
39
+
40
+ # Simple notification
41
+ Notification(
42
+ title="Hello",
43
+ message="This is a basic notification."
44
+ ).send()
45
+
46
+ ```
47
+
48
+ **Sample Image:**
49
+ ![basic notification img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/basicnoti.jpg)
50
+
51
+ ## Installation
52
+
53
+ ### Kivy apps:
54
+
55
+ In your **`buildozer.spec`** file, ensure you include the following:
56
+
57
+ ```ini
58
+ # Add pyjnius so ensure it's packaged with the build
59
+ requirements = python3, kivy, pyjnius, android-notify==1.60.4.dev0
60
+ # Add permission for notifications
61
+ android.permissions = POST_NOTIFICATIONS
62
+ ```
63
+
64
+ ### Flet apps:
65
+
66
+ In your `pyproject.toml` file, ensure you include the following:
67
+
68
+ ```toml
69
+ [tool.flet.android]
70
+ dependencies = [
71
+ "pyjnius","android-notify==1.60.4.dev0"
72
+ ]
73
+
74
+ [tool.flet.android.permission]
75
+ "android.permission.POST_NOTIFICATIONS" = true
76
+ ```
77
+
78
+ ### Pydroid 3
79
+ In the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
80
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.4.dev0`
81
+
82
+
83
+ ### Testing
84
+ Can be installed via `pip` For testing purposes:
85
+
86
+ ```bash
87
+ pip install android_notify
88
+ android-notify -v
89
+ ```
90
+
91
+ ## Documentation
92
+ For Dev Version use
93
+ ```requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip```
94
+
95
+
96
+ To use colored text in your notifications:
97
+ - Copy the [res](https://github.com/Fector101/android_notify/tree/main/android_notify/res) folder to your app path.
98
+ Lastly in your `buildozer.spec` file
99
+ - Add `source.include_exts = xml` and `android.add_resources = ./res`
100
+
101
+ For full documentation, examples, and advanced usage, API reference visit the
102
+ [documentation](https://android-notify.vercel.app)
103
+
104
+ ## ☕ Support the Project
105
+
106
+ 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.
107
+
108
+ <a href="https://www.buymeacoffee.com/fector101" target="_blank">
109
+ <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
110
+ </a>
@@ -0,0 +1,251 @@
1
+ """For autocomplete Storing Reference to Available Methods"""
2
+ from typing import Literal
3
+ Importance = Literal['urgent','high','medium','low','none']
4
+ """
5
+ :argument urgent - Makes a sound and appears as a heads-up notification.
6
+
7
+ :argument high - Makes a sound.
8
+
9
+ :argument urgent - Makes no sound.
10
+
11
+ :argument urgent - Makes no sound and doesn't appear in the status bar.
12
+
13
+ :argument urgent - Makes no sound and doesn't in the status bar or shade.
14
+ """
15
+
16
+ # For Dev
17
+ # Idea for typing autocompletion and reference
18
+ class Bundle:
19
+ def putString(self,key,value):
20
+ print(f"[MOCK] Bundle.putString called with key={key}, value={value}")
21
+
22
+ def putInt(self,key,value):
23
+ print(f"[MOCK] Bundle.putInt called with key={key}, value={value}")
24
+
25
+ class String(str):
26
+ def __new__(cls, value):
27
+ print(f"[MOCK] String created with value={value}")
28
+ return str.__new__(cls, value)
29
+
30
+ class Intent:
31
+ def __init__(self,context,activity):
32
+ self.obj={}
33
+ print(f"[MOCK] Intent initialized with context={context}, activity={activity}")
34
+
35
+ def setAction(self,action):
36
+ print(f"[MOCK] Intent.setAction called with: {action}")
37
+ return self
38
+
39
+ def setFlags(self,intent_flag):
40
+ print(f"[MOCK] Intent.setFlags called with: {intent_flag}")
41
+ return self
42
+
43
+ def getAction(self):
44
+ print("[MOCK] Intent.getAction called")
45
+ return self
46
+
47
+ def getStringExtra(self,key):
48
+ print(f"[MOCK] Intent.getStringExtra called with key={key}")
49
+ return self
50
+
51
+ def putExtra(self,key,value):
52
+ self.obj[key] = value
53
+ print(f"[MOCK] Intent.putExtra called with key={key}, value={value}")
54
+
55
+ def putExtras(self,bundle:Bundle):
56
+ self.obj['bundle'] = bundle
57
+ print(f"[MOCK] Intent.putExtras called with bundle={bundle}")
58
+
59
+ class PendingIntent:
60
+ FLAG_IMMUTABLE=''
61
+ FLAG_UPDATE_CURRENT=''
62
+
63
+ def getActivity(self,context,value,action_intent,pending_intent_type):
64
+ print(f"[MOCK] PendingIntent.getActivity called with context={context}, value={value}, action_intent={action_intent}, type={pending_intent_type}")
65
+
66
+ class BitmapFactory:
67
+ def decodeStream(self,stream):
68
+ print(f"[MOCK] BitmapFactory.decodeStream called with stream={stream}")
69
+
70
+ class BuildVersion:
71
+ SDK_INT=0
72
+
73
+ class NotificationManager:
74
+ pass
75
+
76
+ class NotificationChannel:
77
+ def __init__(self,channel_id,channel_name,importance):
78
+ self.description = None
79
+ self.channel_id = channel_id
80
+ self.channel = None
81
+ print(f"[MOCK] NotificationChannel initialized with id={channel_id}, name={channel_name}, importance={importance}")
82
+
83
+ def createNotificationChannel(self, channel):
84
+ self.channel=channel
85
+ print(f"[MOCK] NotificationChannel.createNotificationChannel called with channel={channel}")
86
+
87
+ def getNotificationChannel(self, channel_id):
88
+ self.channel_id=channel_id
89
+ print(f"[MOCK] NotificationChannel.getNotificationChannel called with id={channel_id}")
90
+
91
+ def setDescription(self, description):
92
+ self.description=description
93
+ print(f"[MOCK] NotificationChannel.setDescription called with description={description}")
94
+
95
+ def getId(self):
96
+ print(f"[MOCK] NotificationChannel.getId called, returning {self.channel_id}")
97
+ return self.channel_id
98
+
99
+ class IconCompat:
100
+ def createWithBitmap(self,bitmap):
101
+ print(f"[MOCK] IconCompat.createWithBitmap called with bitmap={bitmap}")
102
+
103
+ class Color:
104
+ def __init__(self):
105
+ print("[MOCK] Color initialized")
106
+ def parseColor(self,color:str):
107
+ print(f"[MOCK] Color.parseColor called with color={color}")
108
+ return self
109
+
110
+ class RemoteViews:
111
+ def __init__(self, package_name, small_layout_id):
112
+ print(f"[MOCK] RemoteViews initialized with package_name={package_name}, layout_id={small_layout_id}")
113
+ def createWithBitmap(self,bitmap):
114
+ print(f"[MOCK] RemoteViews.createWithBitmap called with bitmap={bitmap}")
115
+ def setTextViewText(self,id, text):
116
+ print(f"[MOCK] RemoteViews.setTextViewText called with id={id}, text={text}")
117
+ def setTextColor(self,id, color:Color):
118
+ print(f"[MOCK] RemoteViews.setTextColor called with id={id}, color={color}")
119
+
120
+ class NotificationManagerCompat:
121
+ IMPORTANCE_HIGH=4
122
+ IMPORTANCE_DEFAULT=3
123
+ IMPORTANCE_LOW=''
124
+ IMPORTANCE_MIN=''
125
+ IMPORTANCE_NONE=''
126
+
127
+ class NotificationCompat:
128
+ DEFAULT_ALL=3
129
+ PRIORITY_HIGH=4
130
+ PRIORITY_DEFAULT = ''
131
+ PRIORITY_LOW=''
132
+ PRIORITY_MIN=''
133
+
134
+ class MActions:
135
+ def clear(self):
136
+ """This Removes all buttons"""
137
+ print('[MOCK] MActions.clear called')
138
+
139
+ class NotificationCompatBuilder:
140
+ def __init__(self,context,channel_id):
141
+ self.mActions = MActions()
142
+ print(f"[MOCK] NotificationCompatBuilder initialized with context={context}, channel_id={channel_id}")
143
+ def setProgress(self,max_value,current_value,endless):
144
+ print(f"[MOCK] setProgress called with max={max_value}, current={current_value}, endless={endless}")
145
+ def setStyle(self,style):
146
+ print(f"[MOCK] setStyle called with style={style}")
147
+ def setContentTitle(self,title):
148
+ print(f"[MOCK] setContentTitle called with title={title}")
149
+ def setContentText(self,text):
150
+ print(f"[MOCK] setContentText called with text={text}")
151
+ def setSmallIcon(self,icon):
152
+ print(f"[MOCK] setSmallIcon called with icon={icon}")
153
+ def setLargeIcon(self,icon):
154
+ print(f"[MOCK] setLargeIcon called with icon={icon}")
155
+ def setAutoCancel(self,auto_cancel:bool):
156
+ print(f"[MOCK] setAutoCancel called with auto_cancel={auto_cancel}")
157
+ def setPriority(self,priority):
158
+ print(f"[MOCK] setPriority called with priority={priority}")
159
+ def setDefaults(self,defaults):
160
+ print(f"[MOCK] setDefaults called with defaults={defaults}")
161
+ def setOngoing(self,persistent:bool):
162
+ print(f"[MOCK] setOngoing called with persistent={persistent}")
163
+ def setOnlyAlertOnce(self,state):
164
+ print(f"[MOCK] setOnlyAlertOnce called with state={state}")
165
+ def build(self):
166
+ print("[MOCK] build called")
167
+ def setContentIntent(self,pending_action_intent:PendingIntent):
168
+ print(f"[MOCK] setContentIntent called with {pending_action_intent}")
169
+ def addAction(self,icon_int,action_text,pending_action_intent):
170
+ print(f"[MOCK] addAction called with icon={icon_int}, text={action_text}, intent={pending_action_intent}")
171
+ def setShowWhen(self,state):
172
+ print(f"[MOCK] setShowWhen called with state={state}")
173
+ def setWhen(self,time_ms):
174
+ print(f"[MOCK] setWhen called with time_ms={time_ms}")
175
+ def setCustomContentView(self,layout):
176
+ print(f"[MOCK] setCustomContentView called with layout={layout}")
177
+ def setCustomBigContentView(self,layout):
178
+ print(f"[MOCK] setCustomBigContentView called with layout={layout}")
179
+ def setSubText(self,text):
180
+ print(f"[MOCK] setSubText called with text={text}")
181
+ def setColor(self, color:Color) -> None:
182
+ print(f"[MOCK] setColor called with color={color}")
183
+
184
+ class NotificationCompatBigTextStyle:
185
+ def bigText(self,body):
186
+ print(f"[MOCK] NotificationCompatBigTextStyle.bigText called with body={body}")
187
+ return self
188
+
189
+ class NotificationCompatBigPictureStyle:
190
+ def bigPicture(self,bitmap):
191
+ print(f"[MOCK] NotificationCompatBigPictureStyle.bigPicture called with bitmap={bitmap}")
192
+ return self
193
+
194
+ class NotificationCompatInboxStyle:
195
+ def addLine(self,line):
196
+ print(f"[MOCK] NotificationCompatInboxStyle.addLine called with line={line}")
197
+ return self
198
+
199
+ class NotificationCompatDecoratedCustomViewStyle:
200
+ def __init__(self):
201
+ print("[MOCK] NotificationCompatDecoratedCustomViewStyle initialized")
202
+
203
+ class Permission:
204
+ POST_NOTIFICATIONS=''
205
+
206
+ def check_permission(permission:Permission.POST_NOTIFICATIONS):
207
+ print(f"[MOCK] check_permission called with {permission}")
208
+ print(permission)
209
+
210
+ def request_permissions(_list: [], _callback):
211
+ print(f"[MOCK] request_permissions called with {_list}")
212
+ _callback()
213
+
214
+ class AndroidActivity:
215
+ def bind(self,on_new_intent):
216
+ print(f"[MOCK] AndroidActivity.bind called with {on_new_intent}")
217
+ def unbind(self,on_new_intent):
218
+ print(f"[MOCK] AndroidActivity.unbind called with {on_new_intent}")
219
+
220
+ class PythonActivity:
221
+ def __init__(self):
222
+ print("[MOCK] PythonActivity initialized")
223
+
224
+
225
+ class DummyIcon:
226
+ icon = 101
227
+ def __init__(self):
228
+ print("[MOCK] DummyIcon initialized")
229
+
230
+ class Context:
231
+ def __init__(self):
232
+ print("[MOCK] Context initialized")
233
+ pass
234
+
235
+ @staticmethod
236
+ def getApplicationInfo():
237
+ print("[MOCK] Context.getApplicationInfo called")
238
+ return DummyIcon
239
+
240
+ @staticmethod
241
+ def getResources():
242
+ print("[MOCK] Context.getResources called")
243
+ return None
244
+
245
+ @staticmethod
246
+ def getPackageName():
247
+ print("[MOCK] Context.getPackageName called")
248
+ return None # TODO get package name from buildozer.spec file
249
+
250
+ #Now writing Knowledge from errors
251
+ # notify.(int, Builder.build()) # must be int
@@ -6,7 +6,7 @@ from .an_types import Importance
6
6
  from .config import (
7
7
  get_python_activity_context, app_storage_path,ON_ANDROID,
8
8
  BitmapFactory, BuildVersion, Bundle,
9
- NotificationManagerCompat,NotificationCompat
9
+ NotificationManagerClass,AndroidNotification
10
10
  )
11
11
 
12
12
  if ON_ANDROID:
@@ -37,15 +37,15 @@ def get_android_importance(importance: Importance):
37
37
  return None
38
38
  value = ''
39
39
  if importance == 'urgent':
40
- value = NotificationCompat.PRIORITY_HIGH if BuildVersion.SDK_INT <= 25 else NotificationManagerCompat.IMPORTANCE_HIGH
40
+ value = AndroidNotification.PRIORITY_HIGH if BuildVersion.SDK_INT <= 25 else NotificationManagerClass.IMPORTANCE_HIGH
41
41
  elif importance == 'high':
42
- value = NotificationCompat.PRIORITY_DEFAULT if BuildVersion.SDK_INT <= 25 else NotificationManagerCompat.IMPORTANCE_DEFAULT
42
+ value = AndroidNotification.PRIORITY_DEFAULT if BuildVersion.SDK_INT <= 25 else NotificationManagerClass.IMPORTANCE_DEFAULT
43
43
  elif importance == 'medium':
44
- value = NotificationCompat.PRIORITY_LOW if BuildVersion.SDK_INT <= 25 else NotificationManagerCompat.IMPORTANCE_LOW
44
+ value = AndroidNotification.PRIORITY_LOW if BuildVersion.SDK_INT <= 25 else NotificationManagerClass.IMPORTANCE_LOW
45
45
  elif importance == 'low':
46
- value = NotificationCompat.PRIORITY_MIN if BuildVersion.SDK_INT <= 25 else NotificationManagerCompat.IMPORTANCE_MIN
46
+ value = AndroidNotification.PRIORITY_MIN if BuildVersion.SDK_INT <= 25 else NotificationManagerClass.IMPORTANCE_MIN
47
47
  elif importance == 'none':
48
- value = '' if BuildVersion.SDK_INT <= 25 else NotificationManagerCompat.IMPORTANCE_NONE
48
+ value = '' if BuildVersion.SDK_INT <= 25 else NotificationManagerClass.IMPORTANCE_NONE
49
49
 
50
50
  return value
51
51
  # side-note 'medium' = NotificationCompat.PRIORITY_LOW and 'low' = NotificationCompat.PRIORITY_MIN # weird but from docs
@@ -69,10 +69,11 @@ def generate_channel_id(channel_name: str) -> str:
69
69
  return channel_id[:50]
70
70
 
71
71
  def get_img_from_path(relative_path):
72
- app_folder = os.path.join(app_storage_path(), 'app')
73
- output_path = os.path.join(app_folder, relative_path)
74
- if not os.path.exists(output_path):
75
- print(f"\nImage not found at path: {app_folder}, (Local images gotten from App Path)")
72
+ app_folder = os.path.join(app_storage_path(), 'app')
73
+ img_full_path = os.path.join(app_folder, relative_path)
74
+ img_name = os.path.basename(img_full_path)
75
+ if not os.path.exists(img_full_path):
76
+ print(f"\nImage - {img_name} not found at path: {app_folder}, (Local images gotten from App Path)")
76
77
  try:
77
78
  print("- These are the existing files in your app Folder:")
78
79
  print('[' + ', '.join(os.listdir(app_folder)) + ']')
@@ -80,10 +81,8 @@ def get_img_from_path(relative_path):
80
81
  print('Exception: ', could_not_get_files_in_path_error)
81
82
  print("Couldn't get Files in App Folder")
82
83
  return None
84
+ return get_bitmap_from_path(img_full_path)
83
85
  # TODO test with a badly written Image and catch error
84
- Uri = autoclass('android.net.Uri')
85
- uri = Uri.parse(f"file://{output_path}")
86
- return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
87
86
 
88
87
  def setLayoutText(layout, id, text, color):
89
88
  # checked if self.title_color available before entering method
@@ -128,7 +127,6 @@ def add_data_to_intent(intent, title):
128
127
  bundle.putInt("notify_id", 101)
129
128
  intent.putExtras(bundle)
130
129
 
131
-
132
130
  def get_sound_uri(res_sound_name):
133
131
  if not res_sound_name:
134
132
  return None
@@ -136,3 +134,25 @@ def get_sound_uri(res_sound_name):
136
134
  package_name = context.getPackageName()
137
135
  Uri = autoclass('android.net.Uri')
138
136
  return Uri.parse(f"android.resource://{package_name}/raw/{res_sound_name}")
137
+
138
+ def get_package_path():
139
+ """
140
+ Returns the directory path of this Python package.
141
+ Works on Android, Windows, Linux, macOS.
142
+ """
143
+ return os.path.dirname(os.path.abspath(__file__))
144
+
145
+ def get_bitmap_from_path(img_full_path):
146
+ Uri = autoclass('android.net.Uri')
147
+ uri = Uri.parse(f"file://{img_full_path}")
148
+ return BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
149
+
150
+ def icon_finder(icon_name):
151
+ """Get the full path to an icon file."""
152
+ try:
153
+ import pkg_resources
154
+ return pkg_resources.resource_filename(__name__, f"fallback-icons/{icon_name}")
155
+ except Exception:
156
+ # Fallback if pkg_resources not available
157
+ package_dir = get_package_path()
158
+ return os.path.join(package_dir, "fallback-icons", icon_name)