mousefox.app.adminframe
Home of AdminFrame
.
1"""Home of `AdminFrame`.""" 2 3import arrow 4import functools 5import json 6import kvex as kx 7import pgnet 8import pprint 9 10 11_STATUSES = {s.value: s for s in pgnet.Status} 12_STATUS_COLORS = { 13 pgnet.Status.OK.value: kx.XColor.from_hex("00ff00"), 14 pgnet.Status.UNEXPECTED.value: kx.XColor.from_hex("bbbb00"), 15 pgnet.Status.BAD.value: kx.XColor.from_hex("ff0000"), 16} 17 18 19class AdminFrame(kx.XFrame): 20 """Widget for admin controls.""" 21 22 _conpath = "client.user.admin" 23 24 def __init__(self, client: pgnet.Client): 25 """Initialize the class with a client.""" 26 super().__init__() 27 self._client = client 28 self._make_widgets() 29 self.app.controller.set_active_callback(self._conpath, self.set_focus) 30 self.app.controller.bind(f"{self._conpath}.focus", self.set_focus) 31 self.app.controller.bind(f"{self._conpath}.debug", self._request_debug) 32 33 def _make_widgets(self): 34 with self.app.subtheme_context("accent"): 35 title = kx.fwrap(kx.XLabel(text="Admin Panel", bold=True, font_size="36sp")) 36 title.set_size(y="40sp") 37 # Requests frame 38 requests_placeholder = kx.XPlaceholder( 39 button_text="Get requests", 40 callback=self._refresh_requests, 41 ) 42 self.requests_frame = kx.XContainer(requests_placeholder) 43 custom_input_label = kx.XLabel( 44 text="Custom packet builder", 45 bold=True, 46 underline=True, 47 font_size="18dp", 48 ) 49 custom_input_title = kx.wrap(custom_input_label) 50 custom_input_title.set_size(y="40dp") 51 packet_input_widgets = dict( 52 message=kx.XInputPanelWidget( 53 label="Message:", 54 label_hint=0.2, 55 orientation="vertical", 56 ), 57 payload=kx.XInputPanelWidget( 58 label="Payload JSON:", 59 label_hint=0.2, 60 orientation="vertical", 61 ), 62 ) 63 self.packet_input = kx.XInputPanel( 64 packet_input_widgets, 65 reset_text="", 66 invoke_text="Send packet", 67 ) 68 self.packet_input.bind(on_invoke=self._on_packet_input) 69 self.packet_input.set_size(y="100dp") 70 self.custom_packet_frame = kx.XDBox() 71 self.custom_packet_frame.add_widgets(custom_input_title, self.packet_input) 72 # Response labels 73 self.response_label = kx.XLabel( 74 font_name="RobotoMono-Regular", 75 padding=(10, 10), 76 halign="left", 77 valign="top", 78 fixed_width=True, 79 ) 80 response_label_frame = kx.XScroll(view=self.response_label) 81 self.debug_label = kx.XLabel( 82 font_name="RobotoMono-Regular", 83 padding=(10, 10), 84 halign="left", 85 valign="top", 86 fixed_width=True, 87 ) 88 debug_label_frame = kx.fwrap(kx.XScroll(view=self.debug_label)) 89 debug_label_frame.set_size(x="300dp") 90 # Assemble 91 self.requests_frame.set_size(x="300dp") 92 bottom_frame = kx.XBox() 93 bottom_frame.add_widgets( 94 debug_label_frame, 95 response_label_frame, 96 self.requests_frame, 97 ) 98 main_frame = kx.XBox(orientation="vertical") 99 main_frame.add_widgets(title, kx.pwrap(bottom_frame)) 100 self.add_widget(kx.pwrap(main_frame)) 101 102 def _refresh_requests(self): 103 self._client.send(pgnet.Packet(pgnet.util.Request.HELP), self._on_help_response) 104 105 def _on_help_response(self, response: pgnet.Response): 106 main_stack = kx.XDBox() 107 for request, params in response.payload.items(): 108 panel_widgets = { 109 name: kx.XInputPanelWidget(label=f"{name}:", widget=ptype) 110 for name, ptype in params.items() 111 } 112 with self.app.subtheme_context("secondary"): 113 panel = kx.XInputPanel( 114 panel_widgets, 115 reset_text="", 116 invoke_text=request, 117 fill_button=True, 118 ) 119 panel.on_invoke = functools.partial(self._on_request_invoke, request) 120 panel = panel 121 with self.app.subtheme_context("accent"): 122 text = request.removeprefix("__pgnet__.") 123 text = text.replace("_", " ").capitalize() 124 lbl = kx.XLabel(text=text, bold=True, font_size="18dp") 125 lbl = kx.pwrap(kx.fwrap(lbl)) 126 lbl.set_size(y="40dp") 127 main_stack.add_widgets(lbl, panel) 128 if self.custom_packet_frame.parent: 129 self.custom_packet_frame.parent.remove_widget(self.custom_packet_frame) 130 main_stack.add_widget(self.custom_packet_frame) 131 scroll = kx.XScroll(view=main_stack) 132 self.requests_frame.content = kx.fpwrap(scroll, subtheme_name="secondary") 133 134 def _request_debug(self, *args): 135 self._client.send( 136 pgnet.Packet(pgnet.util.Request.DEBUG), 137 self._response_callback, 138 ) 139 140 def _on_request_invoke(self, request: str, values: dict): 141 self._client.send(pgnet.Packet(request, values), self._response_callback) 142 143 def _on_packet_input(self, w, values): 144 message = values["message"] 145 payload_text = values["payload"] 146 try: 147 payload = json.loads(payload_text) 148 except Exception: 149 payload = dict() 150 packet = pgnet.Packet(message, payload) 151 self._client.send(packet, self._response_callback) 152 self.packet_input.set_focus("message") 153 154 def _response_callback(self, response: pgnet.Response): 155 sb = self.subtheme 156 status = _STATUSES[response.status] 157 status_color = _STATUS_COLORS[status] 158 statusstr = status_color.markup(status.name) 159 timestr = arrow.get(response.created_on).to("local").format("HH:mm:ss MMM DD") 160 debug_strs = [ 161 f"{sb.fg2.markup('Status:')} {status.value} ({statusstr})", 162 f"{sb.fg2.markup('Created:')} {timestr}", 163 response.debug_repr, 164 ] 165 self.debug_label.text = "\n\n".join(debug_strs) 166 response_strs = [ 167 f"{sb.fg2.markup('Response:')} {response.message}", 168 ] 169 for k, v in response.payload.items(): 170 vstr = v if isinstance(v, str) else pprint.pformat(v, width=10_000) 171 response_strs.append(f"\n[u]{sb.fg2.markup(k)}[/u]\n{vstr}") 172 self.response_label.text = "\n".join(response_strs) 173 174 def set_focus(self, *args): 175 """Refresh requests frame on focus if empty.""" 176 if not self.requests_frame.content: 177 self._refresh_requests()
20class AdminFrame(kx.XFrame): 21 """Widget for admin controls.""" 22 23 _conpath = "client.user.admin" 24 25 def __init__(self, client: pgnet.Client): 26 """Initialize the class with a client.""" 27 super().__init__() 28 self._client = client 29 self._make_widgets() 30 self.app.controller.set_active_callback(self._conpath, self.set_focus) 31 self.app.controller.bind(f"{self._conpath}.focus", self.set_focus) 32 self.app.controller.bind(f"{self._conpath}.debug", self._request_debug) 33 34 def _make_widgets(self): 35 with self.app.subtheme_context("accent"): 36 title = kx.fwrap(kx.XLabel(text="Admin Panel", bold=True, font_size="36sp")) 37 title.set_size(y="40sp") 38 # Requests frame 39 requests_placeholder = kx.XPlaceholder( 40 button_text="Get requests", 41 callback=self._refresh_requests, 42 ) 43 self.requests_frame = kx.XContainer(requests_placeholder) 44 custom_input_label = kx.XLabel( 45 text="Custom packet builder", 46 bold=True, 47 underline=True, 48 font_size="18dp", 49 ) 50 custom_input_title = kx.wrap(custom_input_label) 51 custom_input_title.set_size(y="40dp") 52 packet_input_widgets = dict( 53 message=kx.XInputPanelWidget( 54 label="Message:", 55 label_hint=0.2, 56 orientation="vertical", 57 ), 58 payload=kx.XInputPanelWidget( 59 label="Payload JSON:", 60 label_hint=0.2, 61 orientation="vertical", 62 ), 63 ) 64 self.packet_input = kx.XInputPanel( 65 packet_input_widgets, 66 reset_text="", 67 invoke_text="Send packet", 68 ) 69 self.packet_input.bind(on_invoke=self._on_packet_input) 70 self.packet_input.set_size(y="100dp") 71 self.custom_packet_frame = kx.XDBox() 72 self.custom_packet_frame.add_widgets(custom_input_title, self.packet_input) 73 # Response labels 74 self.response_label = kx.XLabel( 75 font_name="RobotoMono-Regular", 76 padding=(10, 10), 77 halign="left", 78 valign="top", 79 fixed_width=True, 80 ) 81 response_label_frame = kx.XScroll(view=self.response_label) 82 self.debug_label = kx.XLabel( 83 font_name="RobotoMono-Regular", 84 padding=(10, 10), 85 halign="left", 86 valign="top", 87 fixed_width=True, 88 ) 89 debug_label_frame = kx.fwrap(kx.XScroll(view=self.debug_label)) 90 debug_label_frame.set_size(x="300dp") 91 # Assemble 92 self.requests_frame.set_size(x="300dp") 93 bottom_frame = kx.XBox() 94 bottom_frame.add_widgets( 95 debug_label_frame, 96 response_label_frame, 97 self.requests_frame, 98 ) 99 main_frame = kx.XBox(orientation="vertical") 100 main_frame.add_widgets(title, kx.pwrap(bottom_frame)) 101 self.add_widget(kx.pwrap(main_frame)) 102 103 def _refresh_requests(self): 104 self._client.send(pgnet.Packet(pgnet.util.Request.HELP), self._on_help_response) 105 106 def _on_help_response(self, response: pgnet.Response): 107 main_stack = kx.XDBox() 108 for request, params in response.payload.items(): 109 panel_widgets = { 110 name: kx.XInputPanelWidget(label=f"{name}:", widget=ptype) 111 for name, ptype in params.items() 112 } 113 with self.app.subtheme_context("secondary"): 114 panel = kx.XInputPanel( 115 panel_widgets, 116 reset_text="", 117 invoke_text=request, 118 fill_button=True, 119 ) 120 panel.on_invoke = functools.partial(self._on_request_invoke, request) 121 panel = panel 122 with self.app.subtheme_context("accent"): 123 text = request.removeprefix("__pgnet__.") 124 text = text.replace("_", " ").capitalize() 125 lbl = kx.XLabel(text=text, bold=True, font_size="18dp") 126 lbl = kx.pwrap(kx.fwrap(lbl)) 127 lbl.set_size(y="40dp") 128 main_stack.add_widgets(lbl, panel) 129 if self.custom_packet_frame.parent: 130 self.custom_packet_frame.parent.remove_widget(self.custom_packet_frame) 131 main_stack.add_widget(self.custom_packet_frame) 132 scroll = kx.XScroll(view=main_stack) 133 self.requests_frame.content = kx.fpwrap(scroll, subtheme_name="secondary") 134 135 def _request_debug(self, *args): 136 self._client.send( 137 pgnet.Packet(pgnet.util.Request.DEBUG), 138 self._response_callback, 139 ) 140 141 def _on_request_invoke(self, request: str, values: dict): 142 self._client.send(pgnet.Packet(request, values), self._response_callback) 143 144 def _on_packet_input(self, w, values): 145 message = values["message"] 146 payload_text = values["payload"] 147 try: 148 payload = json.loads(payload_text) 149 except Exception: 150 payload = dict() 151 packet = pgnet.Packet(message, payload) 152 self._client.send(packet, self._response_callback) 153 self.packet_input.set_focus("message") 154 155 def _response_callback(self, response: pgnet.Response): 156 sb = self.subtheme 157 status = _STATUSES[response.status] 158 status_color = _STATUS_COLORS[status] 159 statusstr = status_color.markup(status.name) 160 timestr = arrow.get(response.created_on).to("local").format("HH:mm:ss MMM DD") 161 debug_strs = [ 162 f"{sb.fg2.markup('Status:')} {status.value} ({statusstr})", 163 f"{sb.fg2.markup('Created:')} {timestr}", 164 response.debug_repr, 165 ] 166 self.debug_label.text = "\n\n".join(debug_strs) 167 response_strs = [ 168 f"{sb.fg2.markup('Response:')} {response.message}", 169 ] 170 for k, v in response.payload.items(): 171 vstr = v if isinstance(v, str) else pprint.pformat(v, width=10_000) 172 response_strs.append(f"\n[u]{sb.fg2.markup(k)}[/u]\n{vstr}") 173 self.response_label.text = "\n".join(response_strs) 174 175 def set_focus(self, *args): 176 """Refresh requests frame on focus if empty.""" 177 if not self.requests_frame.content: 178 self._refresh_requests()
Widget for admin controls.
AdminFrame(client: pgnet.client.Client)
25 def __init__(self, client: pgnet.Client): 26 """Initialize the class with a client.""" 27 super().__init__() 28 self._client = client 29 self._make_widgets() 30 self.app.controller.set_active_callback(self._conpath, self.set_focus) 31 self.app.controller.bind(f"{self._conpath}.focus", self.set_focus) 32 self.app.controller.bind(f"{self._conpath}.debug", self._request_debug)
Initialize the class with a client.
def
set_focus(self, *args):
175 def set_focus(self, *args): 176 """Refresh requests frame on focus if empty.""" 177 if not self.requests_frame.content: 178 self._refresh_requests()
Refresh requests frame on focus if empty.
Inherited Members
- kivy.uix.anchorlayout.AnchorLayout
- padding
- anchor_x
- anchor_y
- do_layout
- kivy.uix.layout.Layout
- add_widget
- remove_widget
- layout_hint_with_bounds
- kivy.uix.widget.Widget
- proxy_ref
- apply_class_lang_rules
- collide_point
- collide_widget
- on_motion
- on_touch_down
- on_touch_move
- on_touch_up
- on_kv_post
- clear_widgets
- register_for_motion_event
- unregister_for_motion_event
- export_to_png
- export_as_image
- get_root_window
- get_parent_window
- walk
- walk_reverse
- to_widget
- to_window
- to_parent
- to_local
- get_window_matrix
- x
- y
- width
- height
- pos
- size
- get_right
- set_right
- right
- get_top
- set_top
- top
- get_center_x
- set_center_x
- center_x
- get_center_y
- set_center_y
- center_y
- center
- cls
- children
- parent
- size_hint_x
- size_hint_y
- size_hint
- pos_hint
- size_hint_min_x
- size_hint_min_y
- size_hint_min
- size_hint_max_x
- size_hint_max_y
- size_hint_max
- ids
- opacity
- on_opacity
- canvas
- get_disabled
- set_disabled
- inc_disabled
- dec_disabled
- disabled
- motion_filter
- kivy._event.EventDispatcher
- register_event_type
- unregister_event_types
- unregister_event_type
- is_event_type
- bind
- unbind
- fbind
- funbind
- unbind_uid
- get_property_observers
- events
- dispatch
- dispatch_generic
- dispatch_children
- setter
- getter
- property
- properties
- create_property
- apply_property