Move layout definitions into srcs/layouts

This separates the layout definitions from the special layouts
(bottom_row, greekmath) and other unrelated files (method, settings).

This is also a more intuitive location for layouts and make the resource
directory easier to navigate.

Under the hood, layouts are copied back into
build/generated-resources/xml.
This commit is contained in:
Jules Aguillon 2024-01-21 16:34:49 +01:00
parent bef29da3de
commit ad7314a016
49 changed files with 26 additions and 27 deletions

View File

@ -88,14 +88,15 @@ Github secret named `DEBUG_KEYSTORE`.
### Adding a layout ### Adding a layout
Layouts are defined in XML, see `res/xml/latn_qwerty_us.xml`. Layouts are defined in XML, see `srcs/layouts/latn_qwerty_us.xml`.
An online tool for editing layout files written by @Lixquid is available An online tool for editing layout files written by @Lixquid is available
[here](https://unexpected-keyboard-layout-editor.lixquid.com/). [here](https://unexpected-keyboard-layout-editor.lixquid.com/).
Makes sure to specify the `name` attribute like in `latn_qwerty_us.xml`, Makes sure to specify the `name` attribute like in `latn_qwerty_us.xml`,
otherwise the layout won't be added to the app. otherwise the layout won't be added to the app.
The layout file must be placed in the `res/xml/` directory and named according to: The layout file must be placed in the `srcs/layouts` directory and named
according to:
- script (`latn` for latin, etc..) - script (`latn` for latin, etc..)
- layout name (eg. the name of a standard) - layout name (eg. the name of a standard)
- country code (or language code if more adequate) - country code (or language code if more adequate)

View File

@ -115,17 +115,13 @@ tasks.register('genLayoutsList') {
tasks.register('checkKeyboardLayouts') { tasks.register('checkKeyboardLayouts') {
println "\nChecking layouts" println "\nChecking layouts"
new ByteArrayOutputStream().withStream { bos -> exec {
exec { def layouts = new File(projectDir, "srcs/layouts").listFiles().findAll {
def layouts = new File(projectDir, "res/xml").listFiles().findAll { it.name.endsWith(".xml")
it.isFile() && it.name.endsWith(".xml")
}
workingDir = projectDir
commandLine("python", "check_layout.py", *layouts)
standardOutput = bos
} }
workingDir = projectDir
new File(projectDir, "check_layout.output").write(bos.toString()) commandLine("python", "check_layout.py", *layouts)
standardOutput = new FileOutputStream("${projectDir}/check_layout.output")
} }
} }
@ -140,6 +136,7 @@ tasks.register('syncTranslations') {
tasks.named("preBuild") { tasks.named("preBuild") {
dependsOn += "initDebugKeystore" dependsOn += "initDebugKeystore"
dependsOn += "copyRawQwertyUS" dependsOn += "copyRawQwertyUS"
dependsOn += "copyLayoutDefinitions"
} }
tasks.register('initDebugKeystore') { tasks.register('initDebugKeystore') {
@ -156,7 +153,15 @@ tasks.register('initDebugKeystore') {
tasks.register('copyRawQwertyUS') tasks.register('copyRawQwertyUS')
{ {
copy { copy {
from "res/xml/latn_qwerty_us.xml" from "srcs/layouts/latn_qwerty_us.xml"
into "build/generated-resources/raw" into "build/generated-resources/raw"
} }
} }
tasks.register('copyLayoutDefinitions')
{
copy {
from "srcs/layouts"
into "build/generated-resources/xml"
}
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# Generates the list of layouts in res/values/layouts.xml from the layout files # Generates the list of layouts in res/values/layouts.xml from the layout files
# in res/xml. Every layouts must have a 'name' attribute to be listed. # in srcs/layouts. Every layouts must have a 'name' attribute to be listed.
import itertools as it import itertools as it
import sys, os, glob import sys, os, glob
@ -11,11 +11,6 @@ import xml.etree.ElementTree as XML
# are sorted alphabetically. # are sorted alphabetically.
FIRST_LAYOUTS = [ "latn_qwerty_us", "latn_colemak", "latn_dvorak" ] FIRST_LAYOUTS = [ "latn_qwerty_us", "latn_colemak", "latn_dvorak" ]
# File names that are known not to be layouts. Avoid warning about them.
KNOWN_NOT_LAYOUT = set([
"number_row", "numpad", "pin", "bottom_row", "settings", "method",
"greekmath", "numeric" ])
# Read a layout from a file. Returns [None] if [fname] is not a layout. # Read a layout from a file. Returns [None] if [fname] is not a layout.
def read_layout(fname): def read_layout(fname):
root = XML.parse(fname).getroot() root = XML.parse(fname).getroot()
@ -28,9 +23,7 @@ def read_layouts(files):
for layout_file in files: for layout_file in files:
layout_id, _ = os.path.splitext(os.path.basename(layout_file)) layout_id, _ = os.path.splitext(os.path.basename(layout_file))
layout = read_layout(layout_file) layout = read_layout(layout_file)
if layout_id in KNOWN_NOT_LAYOUT: if layout == None:
continue
elif layout == None:
print("Not a layout file: %s" % layout_file) print("Not a layout file: %s" % layout_file)
elif layout["name"] == None: elif layout["name"] == None:
print("Layout doesn't have a name: %s" % layout_id) print("Layout doesn't have a name: %s" % layout_id)
@ -66,6 +59,6 @@ def generate_arrays(out, layouts):
XML.indent(root) XML.indent(root)
XML.ElementTree(element=root).write(out, encoding="unicode", xml_declaration=True) XML.ElementTree(element=root).write(out, encoding="unicode", xml_declaration=True)
layouts = sort_layouts(read_layouts(glob.glob("res/xml/*.xml"))) layouts = sort_layouts(read_layouts(glob.glob("srcs/layouts/*.xml")))
with open("res/values/layouts.xml", "w") as out: with open("res/values/layouts.xml", "w") as out:
generate_arrays(out, layouts) generate_arrays(out, layouts)

View File

@ -317,9 +317,9 @@ public final class KeyValue
{ {
switch (name) switch (name)
{ {
/* These symbols have special meaning when in `res/xml` and are escaped in /* These symbols have special meaning when in `srcs/layouts` and are
standard layouts. The backslash is not stripped when parsed from the escaped in standard layouts. The backslash is not stripped when parsed
custom layout option. */ from the custom layout option. */
case "\\?": return makeStringKey("?"); case "\\?": return makeStringKey("?");
case "\\#": return makeStringKey("#"); case "\\#": return makeStringKey("#");
case "\\@": return makeStringKey("@"); case "\\@": return makeStringKey("@");

View File

@ -245,7 +245,7 @@ public class LayoutsPreference extends ListGroupPreference<LayoutsPreference.Lay
public SystemLayout() {} public SystemLayout() {}
} }
/** The name of a layout defined in [res/xml]. */ /** The name of a layout defined in [srcs/layouts]. */
public static final class NamedLayout implements Layout public static final class NamedLayout implements Layout
{ {
public final String name; public final String name;