Skip to content

Commit 27d1af9

Browse files
API: add defaults handling to SharedPreferences and only save non-defaults
1 parent 00d0cb1 commit 27d1af9

File tree

5 files changed

+320
-18
lines changed

5 files changed

+320
-18
lines changed

CLAUDE.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ Current stable version: 0.3.3 (as of latest CHANGELOG entry)
410410
```python
411411
from mpos.config import SharedPreferences
412412

413-
# Load preferences
413+
# Basic usage
414414
prefs = SharedPreferences("com.example.myapp")
415415
value = prefs.get_string("key", "default_value")
416416
number = prefs.get_int("count", 0)
@@ -422,6 +422,28 @@ editor.put_string("key", "value")
422422
editor.put_int("count", 42)
423423
editor.put_dict("data", {"key": "value"})
424424
editor.commit()
425+
426+
# Using constructor defaults (reduces config file size)
427+
# Values matching defaults are not saved to disk
428+
prefs = SharedPreferences("com.example.myapp", defaults={
429+
"brightness": -1,
430+
"volume": 50,
431+
"theme": "dark"
432+
})
433+
434+
# Returns constructor default (-1) if not stored
435+
brightness = prefs.get_int("brightness") # Returns -1
436+
437+
# Method defaults override constructor defaults
438+
brightness = prefs.get_int("brightness", 100) # Returns 100
439+
440+
# Stored values override all defaults
441+
prefs.edit().put_int("brightness", 75).commit()
442+
brightness = prefs.get_int("brightness") # Returns 75
443+
444+
# Setting to default value removes it from storage (auto-cleanup)
445+
prefs.edit().put_int("brightness", -1).commit()
446+
# brightness is no longer stored in config.json, saves space
425447
```
426448

427449
**Intent system**: Launch activities and pass data

internal_filesystem/apps/com.micropythonos.camera/assets/camera_app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ def apply_camera_settings(self, prefs, cam, use_webcam):
467467

468468
try:
469469
# Basic image adjustments
470-
brightness = prefs.get_int("brightness", 0)
470+
brightness = prefs.get_int("brightness", CameraSettingsActivity.DEFAULTS.get("brightness"))
471471
cam.set_brightness(brightness)
472472

473473
contrast = prefs.get_int("contrast", 0)

internal_filesystem/apps/com.micropythonos.camera/assets/camera_settings.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class CameraSettingsActivity(Activity):
1010
"""Settings activity for comprehensive camera configuration."""
1111

12-
DEFAULT_WIDTH = 320 # 240 would be better but webcam doesn't support this (yet)
12+
DEFAULT_WIDTH = 240 # 240 would be better but webcam doesn't support this (yet)
1313
DEFAULT_HEIGHT = 240
1414
DEFAULT_COLORMODE = True
1515
DEFAULT_SCANQR_WIDTH = 960
@@ -31,6 +31,10 @@ class CameraSettingsActivity(Activity):
3131
scale_default=False
3232
binning_default=False
3333

34+
DEFAULTS = {
35+
"brightness": 1,
36+
}
37+
3438
# Resolution options for desktop/webcam
3539
WEBCAM_RESOLUTIONS = [
3640
("160x120", "160x120"),
@@ -291,7 +295,7 @@ def create_basic_tab(self, tab, prefs):
291295
self.ui_controls["resolution"] = dropdown
292296

293297
# Brightness
294-
brightness = prefs.get_int("brightness", 0)
298+
brightness = prefs.get_int("brightness", self.DEFAULTS.get("brightness"))
295299
slider, label, cont = self.create_slider(tab, "Brightness", -2, 2, brightness, "brightness")
296300
self.ui_controls["brightness"] = slider
297301

internal_filesystem/lib/mpos/config.py

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import os
33

44
class SharedPreferences:
5-
def __init__(self, appname, filename="config.json"):
6-
"""Initialize with appname and filename for preferences."""
5+
def __init__(self, appname, filename="config.json", defaults=None):
6+
"""Initialize with appname, filename, and optional defaults for preferences."""
77
self.appname = appname
88
self.filename = filename
9+
self.defaults = defaults if defaults is not None else {}
910
self.filepath = f"data/{self.appname}/{self.filename}"
1011
self.data = {}
1112
self.load()
@@ -36,31 +37,80 @@ def load(self):
3637
def get_string(self, key, default=None):
3738
"""Retrieve a string value for the given key, with a default if not found."""
3839
to_return = self.data.get(key)
39-
if to_return is None and default is not None:
40-
to_return = default
40+
if to_return is None:
41+
# Method default takes precedence
42+
if default is not None:
43+
to_return = default
44+
# Fall back to constructor default
45+
elif key in self.defaults:
46+
to_return = self.defaults[key]
4147
return to_return
4248

4349
def get_int(self, key, default=0):
4450
"""Retrieve an integer value for the given key, with a default if not found."""
45-
try:
46-
return int(self.data.get(key, default))
47-
except (TypeError, ValueError):
51+
if key in self.data:
52+
try:
53+
return int(self.data[key])
54+
except (TypeError, ValueError):
55+
return default
56+
# Key not in stored data, check defaults
57+
# Method default takes precedence if explicitly provided (not the hardcoded 0)
58+
# Otherwise use constructor default if exists
59+
if default != 0:
4860
return default
61+
if key in self.defaults:
62+
try:
63+
return int(self.defaults[key])
64+
except (TypeError, ValueError):
65+
return 0
66+
return 0
4967

5068
def get_bool(self, key, default=False):
5169
"""Retrieve a boolean value for the given key, with a default if not found."""
52-
try:
53-
return bool(self.data.get(key, default))
54-
except (TypeError, ValueError):
70+
if key in self.data:
71+
try:
72+
return bool(self.data[key])
73+
except (TypeError, ValueError):
74+
return default
75+
# Key not in stored data, check defaults
76+
# Method default takes precedence if explicitly provided (not the hardcoded False)
77+
# Otherwise use constructor default if exists
78+
if default != False:
5579
return default
80+
if key in self.defaults:
81+
try:
82+
return bool(self.defaults[key])
83+
except (TypeError, ValueError):
84+
return False
85+
return False
5686

5787
def get_list(self, key, default=None):
5888
"""Retrieve a list for the given key, with a default if not found."""
59-
return self.data.get(key, default if default is not None else [])
89+
if key in self.data:
90+
return self.data[key]
91+
# Key not in stored data, check defaults
92+
# Method default takes precedence if provided
93+
if default is not None:
94+
return default
95+
# Fall back to constructor default
96+
if key in self.defaults:
97+
return self.defaults[key]
98+
# Return empty list as hardcoded fallback
99+
return []
60100

61101
def get_dict(self, key, default=None):
62102
"""Retrieve a dictionary for the given key, with a default if not found."""
63-
return self.data.get(key, default if default is not None else {})
103+
if key in self.data:
104+
return self.data[key]
105+
# Key not in stored data, check defaults
106+
# Method default takes precedence if provided
107+
if default is not None:
108+
return default
109+
# Fall back to constructor default
110+
if key in self.defaults:
111+
return self.defaults[key]
112+
# Return empty dict as hardcoded fallback
113+
return {}
64114

65115
def edit(self):
66116
"""Return an Editor object to modify preferences."""
@@ -197,14 +247,31 @@ def remove_all(self):
197247
self.temp_data = {}
198248
return self
199249

250+
def _filter_defaults(self, data):
251+
"""Remove keys from data that match constructor defaults."""
252+
if not self.preferences.defaults:
253+
return data
254+
255+
filtered = {}
256+
for key, value in data.items():
257+
if key in self.preferences.defaults:
258+
if value != self.preferences.defaults[key]:
259+
filtered[key] = value
260+
# else: skip saving, matches default
261+
else:
262+
filtered[key] = value # No default, always save
263+
return filtered
264+
200265
def apply(self):
201266
"""Save changes to the file asynchronously (emulated)."""
202-
self.preferences.data = self.temp_data.copy()
267+
filtered_data = self._filter_defaults(self.temp_data)
268+
self.preferences.data = filtered_data
203269
self.preferences.save_config()
204270

205271
def commit(self):
206272
"""Save changes to the file synchronously."""
207-
self.preferences.data = self.temp_data.copy()
273+
filtered_data = self._filter_defaults(self.temp_data)
274+
self.preferences.data = filtered_data
208275
self.preferences.save_config()
209276
return True
210277

0 commit comments

Comments
 (0)