move checking if a layout needs a toggle to server side
subiquity inherits this behavior from d-i where if a the user selects a layout that does not allow typing latin characters, the user is prompted to choose a key to toggle between the one they selected and a related one that does allow latin characters. This change moves the handling of this to the server side, so the client just sees the keyboard layout the user selects, and calls an API method to know if to ask the user about a toggle key.
This commit is contained in:
parent
7d98a77434
commit
744e53b76b
|
@ -68,6 +68,10 @@ class KeyboardController(SubiquityTuiController):
|
||||||
async def get_step(self, index):
|
async def get_step(self, index):
|
||||||
return await self.endpoint.steps.GET(index)
|
return await self.endpoint.steps.GET(index)
|
||||||
|
|
||||||
|
async def needs_toggle(self, setting):
|
||||||
|
return await self.endpoint.needs_toggle.GET(
|
||||||
|
layout_code=setting.layout, variant_code=setting.variant)
|
||||||
|
|
||||||
def done(self, setting, apply):
|
def done(self, setting, apply):
|
||||||
log.debug("KeyboardController.done %s next_screen", setting)
|
log.debug("KeyboardController.done %s next_screen", setting)
|
||||||
if apply:
|
if apply:
|
||||||
|
|
|
@ -18,95 +18,9 @@ import os
|
||||||
from subiquity.common.serialize import Serializer
|
from subiquity.common.serialize import Serializer
|
||||||
from subiquity.common.types import (
|
from subiquity.common.types import (
|
||||||
KeyboardLayout,
|
KeyboardLayout,
|
||||||
KeyboardSetting,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Non-latin keyboard layouts that are handled in a uniform way
|
|
||||||
standard_non_latin_layouts = set(
|
|
||||||
('af', 'am', 'ara', 'ben', 'bd', 'bg', 'bt', 'by', 'et', 'ge',
|
|
||||||
'gh', 'gr', 'guj', 'guru', 'il', 'in', 'iq', 'ir', 'iku', 'kan',
|
|
||||||
'kh', 'kz', 'la', 'lao', 'lk', 'kg', 'ma', 'mk', 'mm', 'mn', 'mv',
|
|
||||||
'mal', 'np', 'ori', 'pk', 'ru', 'scc', 'sy', 'syr', 'tel', 'th',
|
|
||||||
'tj', 'tam', 'tib', 'ua', 'ug', 'uz')
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def latinizable(setting):
|
|
||||||
"""
|
|
||||||
If this setting does not allow the typing of latin characters,
|
|
||||||
return a setting that can be switched to one that can.
|
|
||||||
"""
|
|
||||||
if setting.layout == 'rs':
|
|
||||||
if setting.variant.startswith('latin'):
|
|
||||||
return setting
|
|
||||||
else:
|
|
||||||
if setting.variant == 'yz':
|
|
||||||
new_variant = 'latinyz'
|
|
||||||
elif setting.variant == 'alternatequotes':
|
|
||||||
new_variant = 'latinalternatequotes'
|
|
||||||
else:
|
|
||||||
new_variant = 'latin'
|
|
||||||
return KeyboardSetting(layout='rs,rs',
|
|
||||||
variant=(new_variant +
|
|
||||||
',' + setting.variant))
|
|
||||||
elif setting.layout == 'jp':
|
|
||||||
if setting.variant in ('106', 'common', 'OADG109A',
|
|
||||||
'nicola_f_bs', ''):
|
|
||||||
return setting
|
|
||||||
else:
|
|
||||||
return KeyboardSetting(layout='jp,jp',
|
|
||||||
variant=',' + setting.variant)
|
|
||||||
elif setting.layout == 'lt':
|
|
||||||
if setting.variant == 'us':
|
|
||||||
return KeyboardSetting(layout='lt,lt', variant='us,')
|
|
||||||
else:
|
|
||||||
return KeyboardSetting(layout='lt,lt',
|
|
||||||
variant=setting.variant + ',us')
|
|
||||||
elif setting.layout == 'me':
|
|
||||||
if setting.variant == 'basic' or setting.variant.startswith('latin'):
|
|
||||||
return setting
|
|
||||||
else:
|
|
||||||
return KeyboardSetting(layout='me,me',
|
|
||||||
variant=setting.variant + ',us')
|
|
||||||
elif setting.layout in standard_non_latin_layouts:
|
|
||||||
return KeyboardSetting(layout='us,' + setting.layout,
|
|
||||||
variant=',' + setting.variant)
|
|
||||||
else:
|
|
||||||
return setting
|
|
||||||
|
|
||||||
|
|
||||||
def for_ui(setting):
|
|
||||||
"""
|
|
||||||
Attempt to guess a setting the user chose which resulted in the
|
|
||||||
current config. Basically the inverse of latinizable().
|
|
||||||
"""
|
|
||||||
if ',' in setting.layout:
|
|
||||||
layout1, layout2 = setting.layout.split(',', 1)
|
|
||||||
else:
|
|
||||||
layout1, layout2 = setting.layout, ''
|
|
||||||
if ',' in setting.variant:
|
|
||||||
variant1, variant2 = setting.variant.split(',', 1)
|
|
||||||
else:
|
|
||||||
variant1, variant2 = setting.variant, ''
|
|
||||||
if setting.layout == 'lt,lt':
|
|
||||||
layout = layout1
|
|
||||||
variant = variant1
|
|
||||||
elif setting.layout in ('rs,rs', 'us,rs', 'jp,jp', 'us,jp'):
|
|
||||||
layout = layout2
|
|
||||||
variant = variant2
|
|
||||||
elif layout1 == 'us' and layout2 in standard_non_latin_layouts:
|
|
||||||
layout = layout2
|
|
||||||
variant = variant2
|
|
||||||
elif ',' in setting.layout:
|
|
||||||
# Something unrecognized
|
|
||||||
layout = 'us'
|
|
||||||
variant = ''
|
|
||||||
else:
|
|
||||||
return setting
|
|
||||||
return KeyboardSetting(layout=layout, variant=variant)
|
|
||||||
|
|
||||||
|
|
||||||
class KeyboardList:
|
class KeyboardList:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -94,6 +94,9 @@ class API:
|
||||||
def GET() -> KeyboardSetting: ...
|
def GET() -> KeyboardSetting: ...
|
||||||
def POST(data: Payload[KeyboardSetting]): ...
|
def POST(data: Payload[KeyboardSetting]): ...
|
||||||
|
|
||||||
|
class needs_toggle:
|
||||||
|
def GET(layout_code: str, variant_code: str) -> bool: ...
|
||||||
|
|
||||||
class steps:
|
class steps:
|
||||||
def GET(index: Optional[str]) -> AnyStep: ...
|
def GET(index: Optional[str]) -> AnyStep: ...
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,85 @@ from subiquity.server.controller import SubiquityController
|
||||||
log = logging.getLogger('subiquity.server.controllers.keyboard')
|
log = logging.getLogger('subiquity.server.controllers.keyboard')
|
||||||
|
|
||||||
|
|
||||||
|
# Non-latin keyboard layouts that are handled in a uniform way
|
||||||
|
standard_non_latin_layouts = set(
|
||||||
|
('af', 'am', 'ara', 'ben', 'bd', 'bg', 'bt', 'by', 'et', 'ge',
|
||||||
|
'gh', 'gr', 'guj', 'guru', 'il', 'in', 'iq', 'ir', 'iku', 'kan',
|
||||||
|
'kh', 'kz', 'la', 'lao', 'lk', 'kg', 'ma', 'mk', 'mm', 'mn', 'mv',
|
||||||
|
'mal', 'np', 'ori', 'pk', 'ru', 'scc', 'sy', 'syr', 'tel', 'th',
|
||||||
|
'tj', 'tam', 'tib', 'ua', 'ug', 'uz')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def latinizable(layout_code, variant_code):
|
||||||
|
"""
|
||||||
|
If this setting does not allow the typing of latin characters,
|
||||||
|
return a setting that can be switched to one that can.
|
||||||
|
"""
|
||||||
|
if layout_code == 'rs':
|
||||||
|
if variant_code.startswith('latin'):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
if variant_code == 'yz':
|
||||||
|
new_variant_code = 'latinyz'
|
||||||
|
elif variant_code == 'alternatequotes':
|
||||||
|
new_variant_code = 'latinalternatequotes'
|
||||||
|
else:
|
||||||
|
new_variant_code = 'latin'
|
||||||
|
return 'rs,rs', new_variant_code + ',' + variant_code
|
||||||
|
elif layout_code == 'jp':
|
||||||
|
if variant_code in ('106', 'common', 'OADG109A', 'nicola_f_bs', ''):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return 'jp,jp', ',' + variant_code
|
||||||
|
elif layout_code == 'lt':
|
||||||
|
if variant_code == 'us':
|
||||||
|
return 'lt,lt', 'us,'
|
||||||
|
else:
|
||||||
|
return 'lt,lt', variant_code + ',us'
|
||||||
|
elif layout_code == 'me':
|
||||||
|
if variant_code == 'basic' or variant_code.startswith('latin'):
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return 'me,me', variant_code + ',us'
|
||||||
|
elif layout_code in standard_non_latin_layouts:
|
||||||
|
return 'us,' + layout_code, ',' + variant_code
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def for_ui(setting):
|
||||||
|
"""
|
||||||
|
Attempt to guess a setting the user chose which resulted in the
|
||||||
|
current config. Basically the inverse of latinizable().
|
||||||
|
"""
|
||||||
|
if ',' in setting.layout:
|
||||||
|
layout1, layout2 = setting.layout.split(',', 1)
|
||||||
|
else:
|
||||||
|
layout1, layout2 = setting.layout, ''
|
||||||
|
if ',' in setting.variant:
|
||||||
|
variant1, variant2 = setting.variant.split(',', 1)
|
||||||
|
else:
|
||||||
|
variant1, variant2 = setting.variant, ''
|
||||||
|
if setting.layout == 'lt,lt':
|
||||||
|
layout = layout1
|
||||||
|
variant = variant1
|
||||||
|
elif setting.layout in ('rs,rs', 'us,rs', 'jp,jp', 'us,jp'):
|
||||||
|
layout = layout2
|
||||||
|
variant = variant2
|
||||||
|
elif layout1 == 'us' and layout2 in standard_non_latin_layouts:
|
||||||
|
layout = layout2
|
||||||
|
variant = variant2
|
||||||
|
elif ',' in setting.layout:
|
||||||
|
# Something unrecognized
|
||||||
|
layout = 'us'
|
||||||
|
variant = ''
|
||||||
|
else:
|
||||||
|
return setting
|
||||||
|
return KeyboardSetting(
|
||||||
|
layout=layout, variant=variant, toggle=setting.toggle)
|
||||||
|
|
||||||
|
|
||||||
class KeyboardController(SubiquityController):
|
class KeyboardController(SubiquityController):
|
||||||
|
|
||||||
endpoint = API.keyboard
|
endpoint = API.keyboard
|
||||||
|
@ -74,12 +153,19 @@ class KeyboardController(SubiquityController):
|
||||||
return attr.asdict(self.model.setting)
|
return attr.asdict(self.model.setting)
|
||||||
|
|
||||||
async def GET(self) -> KeyboardSetting:
|
async def GET(self) -> KeyboardSetting:
|
||||||
return self.model.setting
|
return for_ui(self.model.setting)
|
||||||
|
|
||||||
async def POST(self, data: KeyboardSetting):
|
async def POST(self, data: KeyboardSetting):
|
||||||
|
new = latinizable(data.layout, data.variant)
|
||||||
|
if new is not None:
|
||||||
|
data = KeyboardSetting(new[0], new[1], data.toggle)
|
||||||
self.model.setting = data
|
self.model.setting = data
|
||||||
self.configured()
|
self.configured()
|
||||||
|
|
||||||
|
async def needs_toggle_GET(self, layout_code: str,
|
||||||
|
variant_code: str) -> bool:
|
||||||
|
return latinizable(layout_code, variant_code) is not None
|
||||||
|
|
||||||
async def steps_GET(self, index: Optional[str]) -> AnyStep:
|
async def steps_GET(self, index: Optional[str]) -> AnyStep:
|
||||||
if self.pc105_steps is None:
|
if self.pc105_steps is None:
|
||||||
path = os.path.join(self._kbds_dir, 'pc105.json')
|
path = os.path.join(self._kbds_dir, 'pc105.json')
|
||||||
|
|
|
@ -45,7 +45,6 @@ from subiquitycore.ui.stretchy import (
|
||||||
from subiquitycore.ui.utils import button_pile, Color, Padding, screen
|
from subiquitycore.ui.utils import button_pile, Color, Padding, screen
|
||||||
from subiquitycore.view import BaseView
|
from subiquitycore.view import BaseView
|
||||||
|
|
||||||
from subiquity.client.keyboard import for_ui, latinizable
|
|
||||||
from subiquity.common.types import (
|
from subiquity.common.types import (
|
||||||
KeyboardSetting,
|
KeyboardSetting,
|
||||||
StepKeyPresent,
|
StepKeyPresent,
|
||||||
|
@ -378,10 +377,10 @@ class KeyboardView(BaseView):
|
||||||
|
|
||||||
title = _("Keyboard configuration")
|
title = _("Keyboard configuration")
|
||||||
|
|
||||||
def __init__(self, controller, initial_setting):
|
def __init__(self, controller, setting):
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.keyboard_list = controller.keyboard_list
|
self.keyboard_list = controller.keyboard_list
|
||||||
self.initial_setting = initial_setting
|
self.initial_setting = setting
|
||||||
|
|
||||||
self.form = KeyboardForm()
|
self.form = KeyboardForm()
|
||||||
opts = []
|
opts = []
|
||||||
|
@ -392,7 +391,6 @@ class KeyboardView(BaseView):
|
||||||
connect_signal(self.form, 'cancel', self.cancel)
|
connect_signal(self.form, 'cancel', self.cancel)
|
||||||
connect_signal(self.form.layout.widget, "select", self.select_layout)
|
connect_signal(self.form.layout.widget, "select", self.select_layout)
|
||||||
self.form.layout.widget.options = opts
|
self.form.layout.widget.options = opts
|
||||||
setting = for_ui(initial_setting)
|
|
||||||
layout, variant = self.lookup(setting.layout, setting.variant)
|
layout, variant = self.lookup(setting.layout, setting.variant)
|
||||||
self.set_values(layout, variant)
|
self.set_values(layout, variant)
|
||||||
|
|
||||||
|
@ -427,16 +425,20 @@ class KeyboardView(BaseView):
|
||||||
self.set_values(layout, variant)
|
self.set_values(layout, variant)
|
||||||
self._w.base_widget.focus_position = 4
|
self._w.base_widget.focus_position = 4
|
||||||
|
|
||||||
|
async def _check_toggle(self, setting):
|
||||||
|
needs_toggle = await self.controller.app.wait_with_text_dialog(
|
||||||
|
self.controller.needs_toggle(setting), "...")
|
||||||
|
if needs_toggle:
|
||||||
|
self.show_stretchy_overlay(ToggleQuestion(self, setting))
|
||||||
|
else:
|
||||||
|
self.really_done(setting)
|
||||||
|
|
||||||
def done(self, result):
|
def done(self, result):
|
||||||
data = result.as_data()
|
data = result.as_data()
|
||||||
layout = data['layout']
|
layout = data['layout']
|
||||||
variant = data.get('variant', layout.variants[0])
|
variant = data.get('variant', layout.variants[0])
|
||||||
setting = KeyboardSetting(layout=layout.code, variant=variant.code)
|
setting = KeyboardSetting(layout=layout.code, variant=variant.code)
|
||||||
other = latinizable(setting)
|
self.controller.app.aio_loop.create_task(self._check_toggle(setting))
|
||||||
if setting != other:
|
|
||||||
self.show_stretchy_overlay(ToggleQuestion(self, other))
|
|
||||||
else:
|
|
||||||
self.really_done(setting)
|
|
||||||
|
|
||||||
def really_done(self, setting):
|
def really_done(self, setting):
|
||||||
apply = False
|
apply = False
|
||||||
|
|
Loading…
Reference in New Issue