- """.format(
- id=self.id, classes=self.input_classes(), checked="checked" if value else "", checkboxText=self.checkboxText
- )
-
- def input_classes(self):
- return " ".join(["form-check", "form-control-sm"])
-
- def parse(self, data):
- return {self.id: self.id in data and data[self.id][0] == "on"}
-
-
-class Option(object):
- # used for both MultiCheckboxInput and DropdownInput
- def __init__(self, value, text):
- self.value = value
- self.text = text
-
-
-class MultiCheckboxInput(Input):
- def __init__(self, id, label, options, infotext=None):
- super().__init__(id, label, infotext=infotext)
- self.options = options
-
- def render_input(self, value):
- return "".join(self.render_checkbox(o, value) for o in self.options)
-
- def checkbox_id(self, option):
- return "{0}-{1}".format(self.id, option.value)
-
- def render_checkbox(self, option, value):
- return """
-
-
-
-
- """.format(
- id=self.checkbox_id(option),
- classes=self.input_classes(),
- checked="checked" if option.value in value else "",
- checkboxText=option.text
- )
-
- def parse(self, data):
- def in_response(option):
- boxid = self.checkbox_id(option)
- return boxid in data and data[boxid][0] == "on"
- return {self.id: [o.value for o in self.options if in_response(o)]}
-
- def input_classes(self):
- return " ".join(["form-check", "form-control-sm"])
-
-
-class ServicesCheckboxInput(MultiCheckboxInput):
- def __init__(self, id, label, infotext=None):
- services = [Option(s, s.upper()) for s in ServiceDetector.getAvailableServices()]
- super().__init__(id, label, services, infotext)
-
-
-class DropdownInput(Input):
- def __init__(self, id, label, options, infotext = None):
- super().__init__(id, label, infotext=infotext)
- self.options = options
-
- def render_input(self, value):
- return """
-
- """.format(classes=self.input_classes(), id=self.id, options=self.render_options(value))
-
- def render_options(self, value):
- options = [
- """
-
- """.format(
- text=o.text, value=o.value, selected="selected" if o.value == value else ""
- ) for o in self.options
- ]
- return "".join(options)
-
-
class Section(object):
def __init__(self, title, *inputs):
self.title = title
@@ -211,7 +48,11 @@ class SettingsController(AdminController):
"General settings",
TextInput("receiver_name", "Receiver name"),
TextInput("receiver_location", "Receiver location"),
- NumberInput("receiver_asl", "Receiver elevation", infotext="Elevation in meters above mean see level"),
+ NumberInput(
+ "receiver_asl",
+ "Receiver elevation",
+ infotext="Elevation in meters above mean see level",
+ ),
TextInput("receiver_admin", "Receiver admin"),
LocationInput("receiver_gps", "Receiver coordinates"),
TextInput("photo_title", "Photo title"),
@@ -237,14 +78,16 @@ class SettingsController(AdminController):
),
Section(
"Compression",
- DropdownInput("audio_compression", "Audio compression", options=[
- Option("adpcm", "ADPCM"),
- Option("none", "None"),
- ]),
- DropdownInput("fft_compression", "Waterfall compression", options=[
- Option("adpcm", "ADPCM"),
- Option("none", "None"),
- ]),
+ DropdownInput(
+ "audio_compression",
+ "Audio compression",
+ options=[Option("adpcm", "ADPCM"), Option("none", "None"),],
+ ),
+ DropdownInput(
+ "fft_compression",
+ "Waterfall compression",
+ options=[Option("adpcm", "ADPCM"), Option("none", "None"),],
+ ),
),
Section(
"Digimodes",
@@ -257,12 +100,12 @@ class SettingsController(AdminController):
"digital_voice_unvoiced_quality",
"Quality of unvoiced sounds in synthesized voice",
infotext="Determines the quality, and thus the cpu usage, for the ambe codec used by digital voice"
- + "modes. If you're running on a Raspi (up to 3B+) you should leave this set at 1"
+ + "modes. If you're running on a Raspi (up to 3B+) you should leave this set at 1",
),
CheckboxInput(
"digital_voice_dmr_id_lookup",
"DMR id lookup",
- checkboxText="Enable lookup of DMR ids in the radioid database to show callsigns and names"
+ checkboxText="Enable lookup of DMR ids in the radioid database to show callsigns and names",
),
),
Section(
@@ -271,19 +114,19 @@ class SettingsController(AdminController):
"csdr_dynamic_bufsize",
"",
checkboxText="Enable dynamic buffer sizes",
- infotext="This allows you to change the buffering mode of csdr."
+ infotext="This allows you to change the buffering mode of csdr.",
),
CheckboxInput(
"csdr_print_bufsizes",
"",
checkboxText="Print buffer sizez",
- infotext="This prints the buffer sizes used for csdr processes."
+ infotext="This prints the buffer sizes used for csdr processes.",
),
CheckboxInput(
"csdr_through",
"",
checkboxText="Print throughput",
- infotext="Enabling this will print out how much data is going into the DSP chains."
+ infotext="Enabling this will print out how much data is going into the DSP chains.",
),
),
Section(
@@ -293,12 +136,12 @@ class SettingsController(AdminController):
"Google Maps API key",
infotext="Google Maps requires an API key, check out "
+ ''
- + "their documentation on how to obtain one."
+ + "their documentation on how to obtain one.",
),
NumberInput(
"map_position_retention_time",
"Map retention time",
- infotext="Unit is seconds Specifies how log markers / grids will remain visible on the map"
+ infotext="Unit is seconds Specifies how log markers / grids will remain visible on the map",
),
),
Section(
@@ -308,25 +151,29 @@ class SettingsController(AdminController):
NumberInput(
"wsjt_decoding_depth",
"WSJT decoding depth",
- infotext="A higher decoding depth will allow more results, but will also consume more cpu"
- )
+ infotext="A higher decoding depth will allow more results, but will also consume more cpu",
+ ),
),
Section(
"Background decoding",
- CheckboxInput("services_enabled", "Service", checkboxText="Enable background decoding services"),
- ServicesCheckboxInput("services_decoders", "Enabled services")
+ CheckboxInput(
+ "services_enabled",
+ "Service",
+ checkboxText="Enable background decoding services",
+ ),
+ ServicesCheckboxInput("services_decoders", "Enabled services"),
),
Section(
"APRS settings",
TextInput(
"aprs_callsign",
"APRS callsign",
- infotext="This callsign will be used to send data to the APRS-IS network"
+ infotext="This callsign will be used to send data to the APRS-IS network",
),
CheckboxInput(
"aprs_igate_enabled",
"APRS I-Gate",
- checkboxText="Enable APRS receive-only I-Gate"
+ checkboxText="Enable APRS receive-only I-Gate",
),
TextInput("aprs_igate_server", "APRS-IS server"),
TextInput("aprs_igate_password", "APRS-IS network password"),
@@ -334,16 +181,20 @@ class SettingsController(AdminController):
"aprs_igate_beacon",
"APRS beacon",
checkboxText="Send the receiver position to the APRS-IS network",
- infotext="Please check that your receiver location is setup correctly"
+ infotext="Please check that your receiver location is setup correctly",
),
),
Section(
"pskreporter settings",
- CheckboxInput("pskreporter_enabled", "Reporting", checkboxText="Enable sending spots to pskreporter.info"),
+ CheckboxInput(
+ "pskreporter_enabled",
+ "Reporting",
+ checkboxText="Enable sending spots to pskreporter.info",
+ ),
TextInput(
"pskreporter_callsign",
"pskreporter callsign",
- infotext="This callsign will be used to send spots to pskreporter.info"
+ infotext="This callsign will be used to send spots to pskreporter.info",
),
),
Section(
@@ -353,7 +204,9 @@ class SettingsController(AdminController):
"sdr.hu key",
infotext='Please obtain your personal key on sdr.hu',
),
- CheckboxInput("sdrhu_public_listing", "List on sdr.hu", "List my receiver on sdr.hu"),
+ CheckboxInput(
+ "sdrhu_public_listing", "List on sdr.hu", "List my receiver on sdr.hu"
+ ),
TextInput("server_hostname", "Hostname"),
),
]
@@ -381,7 +234,9 @@ class SettingsController(AdminController):
def processFormData(self):
data = parse_qs(self.get_body().decode("utf-8"))
- data = {k: v for i in SettingsController.sections for k, v in i.parse(data).items()}
+ data = {
+ k: v for i in SettingsController.sections for k, v in i.parse(data).items()
+ }
config = Config.get()
for k, v in data.items():
config[k] = v
diff --git a/owrx/form/__init__.py b/owrx/form/__init__.py
new file mode 100644
index 0000000..2ba65ea
--- /dev/null
+++ b/owrx/form/__init__.py
@@ -0,0 +1,187 @@
+from abc import ABC, abstractmethod
+from owrx.service import ServiceDetector
+
+
+class Input(ABC):
+ def __init__(self, id, label, infotext=None):
+ self.id = id
+ self.label = label
+ self.infotext = infotext
+
+ def bootstrap_decorate(self, input):
+ infotext = (
+ "{text}".format(text=self.infotext) if self.infotext else ""
+ )
+ return """
+