bauiv1lib.account.v2proxy
V2 account ui bits.
1# Released under the MIT License. See LICENSE for details. 2# 3"""V2 account ui bits.""" 4 5from __future__ import annotations 6 7import logging 8 9from efro.error import CommunicationError 10import bacommon.cloud 11import bauiv1 as bui 12 13STATUS_CHECK_INTERVAL_SECONDS = 2.0 14 15 16class V2ProxySignInWindow(bui.Window): 17 """A window allowing signing in to a v2 account.""" 18 19 def __init__(self, origin_widget: bui.Widget): 20 self._width = 600 21 self._height = 550 22 self._proxyid: str | None = None 23 self._proxykey: str | None = None 24 25 assert bui.app.classic is not None 26 uiscale = bui.app.ui_v1.uiscale 27 super().__init__( 28 root_widget=bui.containerwidget( 29 size=(self._width, self._height), 30 transition='in_scale', 31 scale_origin_stack_offset=( 32 origin_widget.get_screen_space_center() 33 ), 34 scale=( 35 1.25 36 if uiscale is bui.UIScale.SMALL 37 else 1.05 38 if uiscale is bui.UIScale.MEDIUM 39 else 0.9 40 ), 41 ) 42 ) 43 44 self._loading_text = bui.textwidget( 45 parent=self._root_widget, 46 position=(self._width * 0.5, self._height * 0.5), 47 h_align='center', 48 v_align='center', 49 size=(0, 0), 50 maxwidth=0.9 * self._width, 51 text=bui.Lstr( 52 value='${A}...', 53 subs=[('${A}', bui.Lstr(resource='loadingText'))], 54 ), 55 ) 56 57 self._cancel_button = bui.buttonwidget( 58 parent=self._root_widget, 59 position=(30, self._height - 65), 60 size=(130, 50), 61 scale=0.8, 62 label=bui.Lstr(resource='cancelText'), 63 on_activate_call=self._done, 64 autoselect=True, 65 color=(0.55, 0.5, 0.6), 66 textcolor=(0.75, 0.7, 0.8), 67 ) 68 69 if bool(False): 70 bui.containerwidget( 71 edit=self._root_widget, cancel_button=self._cancel_button 72 ) 73 74 self._update_timer: bui.AppTimer | None = None 75 76 # Ask the cloud for a proxy login id. 77 assert bui.app.plus is not None 78 bui.app.plus.cloud.send_message_cb( 79 bacommon.cloud.LoginProxyRequestMessage(), 80 on_response=bui.WeakCall(self._on_proxy_request_response), 81 ) 82 83 def _on_proxy_request_response( 84 self, response: bacommon.cloud.LoginProxyRequestResponse | Exception 85 ) -> None: 86 plus = bui.app.plus 87 assert plus is not None 88 89 # Something went wrong. Show an error message and that's it. 90 if isinstance(response, Exception): 91 bui.textwidget( 92 edit=self._loading_text, 93 text=bui.Lstr(resource='internal.unavailableNoConnectionText'), 94 color=(1, 0, 0), 95 ) 96 return 97 98 # Show link(s) the user can use to sign in. 99 address = plus.get_master_server_address(version=2) + response.url 100 address_pretty = address.removeprefix('https://') 101 102 assert bui.app.classic is not None 103 bui.textwidget( 104 parent=self._root_widget, 105 position=(self._width * 0.5, self._height - 95), 106 size=(0, 0), 107 text=bui.Lstr( 108 resource='accountSettingsWindow.v2LinkInstructionsText' 109 ), 110 color=bui.app.ui_v1.title_color, 111 maxwidth=self._width * 0.9, 112 h_align='center', 113 v_align='center', 114 ) 115 button_width = 450 116 if bui.is_browser_likely_available(): 117 bui.buttonwidget( 118 parent=self._root_widget, 119 position=( 120 (self._width * 0.5 - button_width * 0.5), 121 self._height - 185, 122 ), 123 autoselect=True, 124 size=(button_width, 60), 125 label=bui.Lstr(value=address_pretty), 126 color=(0.55, 0.5, 0.6), 127 textcolor=(0.75, 0.7, 0.8), 128 on_activate_call=lambda: bui.open_url(address), 129 ) 130 qroffs = 0.0 131 else: 132 bui.textwidget( 133 parent=self._root_widget, 134 position=(self._width * 0.5, self._height - 145), 135 size=(0, 0), 136 text=bui.Lstr(value=address_pretty), 137 flatness=1.0, 138 maxwidth=self._width, 139 scale=0.75, 140 h_align='center', 141 v_align='center', 142 ) 143 qroffs = 20.0 144 145 qr_size = 270 146 bui.imagewidget( 147 parent=self._root_widget, 148 position=( 149 self._width * 0.5 - qr_size * 0.5, 150 self._height * 0.36 + qroffs - qr_size * 0.5, 151 ), 152 size=(qr_size, qr_size), 153 texture=bui.get_qrcode_texture(address), 154 ) 155 156 # Start querying for results. 157 self._proxyid = response.proxyid 158 self._proxykey = response.proxykey 159 bui.apptimer( 160 STATUS_CHECK_INTERVAL_SECONDS, bui.WeakCall(self._ask_for_status) 161 ) 162 163 def _ask_for_status(self) -> None: 164 assert self._proxyid is not None 165 assert self._proxykey is not None 166 assert bui.app.plus is not None 167 bui.app.plus.cloud.send_message_cb( 168 bacommon.cloud.LoginProxyStateQueryMessage( 169 proxyid=self._proxyid, proxykey=self._proxykey 170 ), 171 on_response=bui.WeakCall(self._got_status), 172 ) 173 174 def _got_status( 175 self, response: bacommon.cloud.LoginProxyStateQueryResponse | Exception 176 ) -> None: 177 # For now, if anything goes wrong on the server-side, just abort 178 # with a vague error message. Can be more verbose later if need be. 179 if ( 180 isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) 181 and response.state is response.State.FAIL 182 ): 183 bui.getsound('error').play() 184 bui.screenmessage(bui.Lstr(resource='errorText'), color=(1, 0, 0)) 185 self._done() 186 return 187 188 # If we got a token, set ourself as signed in. Hooray! 189 if ( 190 isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) 191 and response.state is response.State.SUCCESS 192 ): 193 plus = bui.app.plus 194 assert plus is not None 195 assert response.credentials is not None 196 plus.accounts.set_primary_credentials(response.credentials) 197 198 # As a courtesy, tell the server we're done with this proxy 199 # so it can clean up (not a huge deal if this fails) 200 assert self._proxyid is not None 201 try: 202 plus.cloud.send_message_cb( 203 bacommon.cloud.LoginProxyCompleteMessage( 204 proxyid=self._proxyid 205 ), 206 on_response=bui.WeakCall(self._proxy_complete_response), 207 ) 208 except CommunicationError: 209 pass 210 except Exception: 211 logging.warning( 212 'Unexpected error sending login-proxy-complete message', 213 exc_info=True, 214 ) 215 216 self._done() 217 return 218 219 # If we're still waiting, ask again soon. 220 if ( 221 isinstance(response, Exception) 222 or response.state is response.State.WAITING 223 ): 224 bui.apptimer( 225 STATUS_CHECK_INTERVAL_SECONDS, 226 bui.WeakCall(self._ask_for_status), 227 ) 228 229 def _proxy_complete_response(self, response: None | Exception) -> None: 230 del response # Not used. 231 # We could do something smart like retry on exceptions here, but 232 # this isn't critical so we'll just let anything slide. 233 234 def _done(self) -> None: 235 bui.containerwidget(edit=self._root_widget, transition='out_scale')
STATUS_CHECK_INTERVAL_SECONDS =
2.0
class
V2ProxySignInWindow(bauiv1._uitypes.Window):
17class V2ProxySignInWindow(bui.Window): 18 """A window allowing signing in to a v2 account.""" 19 20 def __init__(self, origin_widget: bui.Widget): 21 self._width = 600 22 self._height = 550 23 self._proxyid: str | None = None 24 self._proxykey: str | None = None 25 26 assert bui.app.classic is not None 27 uiscale = bui.app.ui_v1.uiscale 28 super().__init__( 29 root_widget=bui.containerwidget( 30 size=(self._width, self._height), 31 transition='in_scale', 32 scale_origin_stack_offset=( 33 origin_widget.get_screen_space_center() 34 ), 35 scale=( 36 1.25 37 if uiscale is bui.UIScale.SMALL 38 else 1.05 39 if uiscale is bui.UIScale.MEDIUM 40 else 0.9 41 ), 42 ) 43 ) 44 45 self._loading_text = bui.textwidget( 46 parent=self._root_widget, 47 position=(self._width * 0.5, self._height * 0.5), 48 h_align='center', 49 v_align='center', 50 size=(0, 0), 51 maxwidth=0.9 * self._width, 52 text=bui.Lstr( 53 value='${A}...', 54 subs=[('${A}', bui.Lstr(resource='loadingText'))], 55 ), 56 ) 57 58 self._cancel_button = bui.buttonwidget( 59 parent=self._root_widget, 60 position=(30, self._height - 65), 61 size=(130, 50), 62 scale=0.8, 63 label=bui.Lstr(resource='cancelText'), 64 on_activate_call=self._done, 65 autoselect=True, 66 color=(0.55, 0.5, 0.6), 67 textcolor=(0.75, 0.7, 0.8), 68 ) 69 70 if bool(False): 71 bui.containerwidget( 72 edit=self._root_widget, cancel_button=self._cancel_button 73 ) 74 75 self._update_timer: bui.AppTimer | None = None 76 77 # Ask the cloud for a proxy login id. 78 assert bui.app.plus is not None 79 bui.app.plus.cloud.send_message_cb( 80 bacommon.cloud.LoginProxyRequestMessage(), 81 on_response=bui.WeakCall(self._on_proxy_request_response), 82 ) 83 84 def _on_proxy_request_response( 85 self, response: bacommon.cloud.LoginProxyRequestResponse | Exception 86 ) -> None: 87 plus = bui.app.plus 88 assert plus is not None 89 90 # Something went wrong. Show an error message and that's it. 91 if isinstance(response, Exception): 92 bui.textwidget( 93 edit=self._loading_text, 94 text=bui.Lstr(resource='internal.unavailableNoConnectionText'), 95 color=(1, 0, 0), 96 ) 97 return 98 99 # Show link(s) the user can use to sign in. 100 address = plus.get_master_server_address(version=2) + response.url 101 address_pretty = address.removeprefix('https://') 102 103 assert bui.app.classic is not None 104 bui.textwidget( 105 parent=self._root_widget, 106 position=(self._width * 0.5, self._height - 95), 107 size=(0, 0), 108 text=bui.Lstr( 109 resource='accountSettingsWindow.v2LinkInstructionsText' 110 ), 111 color=bui.app.ui_v1.title_color, 112 maxwidth=self._width * 0.9, 113 h_align='center', 114 v_align='center', 115 ) 116 button_width = 450 117 if bui.is_browser_likely_available(): 118 bui.buttonwidget( 119 parent=self._root_widget, 120 position=( 121 (self._width * 0.5 - button_width * 0.5), 122 self._height - 185, 123 ), 124 autoselect=True, 125 size=(button_width, 60), 126 label=bui.Lstr(value=address_pretty), 127 color=(0.55, 0.5, 0.6), 128 textcolor=(0.75, 0.7, 0.8), 129 on_activate_call=lambda: bui.open_url(address), 130 ) 131 qroffs = 0.0 132 else: 133 bui.textwidget( 134 parent=self._root_widget, 135 position=(self._width * 0.5, self._height - 145), 136 size=(0, 0), 137 text=bui.Lstr(value=address_pretty), 138 flatness=1.0, 139 maxwidth=self._width, 140 scale=0.75, 141 h_align='center', 142 v_align='center', 143 ) 144 qroffs = 20.0 145 146 qr_size = 270 147 bui.imagewidget( 148 parent=self._root_widget, 149 position=( 150 self._width * 0.5 - qr_size * 0.5, 151 self._height * 0.36 + qroffs - qr_size * 0.5, 152 ), 153 size=(qr_size, qr_size), 154 texture=bui.get_qrcode_texture(address), 155 ) 156 157 # Start querying for results. 158 self._proxyid = response.proxyid 159 self._proxykey = response.proxykey 160 bui.apptimer( 161 STATUS_CHECK_INTERVAL_SECONDS, bui.WeakCall(self._ask_for_status) 162 ) 163 164 def _ask_for_status(self) -> None: 165 assert self._proxyid is not None 166 assert self._proxykey is not None 167 assert bui.app.plus is not None 168 bui.app.plus.cloud.send_message_cb( 169 bacommon.cloud.LoginProxyStateQueryMessage( 170 proxyid=self._proxyid, proxykey=self._proxykey 171 ), 172 on_response=bui.WeakCall(self._got_status), 173 ) 174 175 def _got_status( 176 self, response: bacommon.cloud.LoginProxyStateQueryResponse | Exception 177 ) -> None: 178 # For now, if anything goes wrong on the server-side, just abort 179 # with a vague error message. Can be more verbose later if need be. 180 if ( 181 isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) 182 and response.state is response.State.FAIL 183 ): 184 bui.getsound('error').play() 185 bui.screenmessage(bui.Lstr(resource='errorText'), color=(1, 0, 0)) 186 self._done() 187 return 188 189 # If we got a token, set ourself as signed in. Hooray! 190 if ( 191 isinstance(response, bacommon.cloud.LoginProxyStateQueryResponse) 192 and response.state is response.State.SUCCESS 193 ): 194 plus = bui.app.plus 195 assert plus is not None 196 assert response.credentials is not None 197 plus.accounts.set_primary_credentials(response.credentials) 198 199 # As a courtesy, tell the server we're done with this proxy 200 # so it can clean up (not a huge deal if this fails) 201 assert self._proxyid is not None 202 try: 203 plus.cloud.send_message_cb( 204 bacommon.cloud.LoginProxyCompleteMessage( 205 proxyid=self._proxyid 206 ), 207 on_response=bui.WeakCall(self._proxy_complete_response), 208 ) 209 except CommunicationError: 210 pass 211 except Exception: 212 logging.warning( 213 'Unexpected error sending login-proxy-complete message', 214 exc_info=True, 215 ) 216 217 self._done() 218 return 219 220 # If we're still waiting, ask again soon. 221 if ( 222 isinstance(response, Exception) 223 or response.state is response.State.WAITING 224 ): 225 bui.apptimer( 226 STATUS_CHECK_INTERVAL_SECONDS, 227 bui.WeakCall(self._ask_for_status), 228 ) 229 230 def _proxy_complete_response(self, response: None | Exception) -> None: 231 del response # Not used. 232 # We could do something smart like retry on exceptions here, but 233 # this isn't critical so we'll just let anything slide. 234 235 def _done(self) -> None: 236 bui.containerwidget(edit=self._root_widget, transition='out_scale')
A window allowing signing in to a v2 account.
V2ProxySignInWindow(origin_widget: _bauiv1.Widget)
20 def __init__(self, origin_widget: bui.Widget): 21 self._width = 600 22 self._height = 550 23 self._proxyid: str | None = None 24 self._proxykey: str | None = None 25 26 assert bui.app.classic is not None 27 uiscale = bui.app.ui_v1.uiscale 28 super().__init__( 29 root_widget=bui.containerwidget( 30 size=(self._width, self._height), 31 transition='in_scale', 32 scale_origin_stack_offset=( 33 origin_widget.get_screen_space_center() 34 ), 35 scale=( 36 1.25 37 if uiscale is bui.UIScale.SMALL 38 else 1.05 39 if uiscale is bui.UIScale.MEDIUM 40 else 0.9 41 ), 42 ) 43 ) 44 45 self._loading_text = bui.textwidget( 46 parent=self._root_widget, 47 position=(self._width * 0.5, self._height * 0.5), 48 h_align='center', 49 v_align='center', 50 size=(0, 0), 51 maxwidth=0.9 * self._width, 52 text=bui.Lstr( 53 value='${A}...', 54 subs=[('${A}', bui.Lstr(resource='loadingText'))], 55 ), 56 ) 57 58 self._cancel_button = bui.buttonwidget( 59 parent=self._root_widget, 60 position=(30, self._height - 65), 61 size=(130, 50), 62 scale=0.8, 63 label=bui.Lstr(resource='cancelText'), 64 on_activate_call=self._done, 65 autoselect=True, 66 color=(0.55, 0.5, 0.6), 67 textcolor=(0.75, 0.7, 0.8), 68 ) 69 70 if bool(False): 71 bui.containerwidget( 72 edit=self._root_widget, cancel_button=self._cancel_button 73 ) 74 75 self._update_timer: bui.AppTimer | None = None 76 77 # Ask the cloud for a proxy login id. 78 assert bui.app.plus is not None 79 bui.app.plus.cloud.send_message_cb( 80 bacommon.cloud.LoginProxyRequestMessage(), 81 on_response=bui.WeakCall(self._on_proxy_request_response), 82 )
Inherited Members
- bauiv1._uitypes.Window
- get_root_widget