Intro `app_files`, an annotation to specify where to find more Android and iOS specific files. This effectively associates resources to a specific Nit module. It can be used to have different icons per branding, or to package graphical assets with a module from the lib.
It is used in the calculator to assign a different icon to the scientific calculator variant.
Pull-Request: #2228
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Romain Chanoir <romain.chanoir@viacesi.fr>
mkdir -p bin
${NITC} -o $@ src/calculator.nit -m linux
-bin/scientific_calculator: $(shell ${NITLS} -M src/scientific_calculator.nit linux) ${NITC}
+bin/scientific: $(shell ${NITLS} -M scientific linux) ${NITC}
mkdir -p bin
- ${NITC} -o $@ src/scientific_calculator.nit -m linux
+ ${NITC} -o $@ src/scientific -m linux
# ---
# Android
-android: bin/calculator.apk
+android: bin/calculator.apk bin/scientific.apk
-bin/calculator.apk: $(shell ${NITLS} -M src/scientific_calculator.nit src/android_calculator.nit) ${NITC} android/res/
+bin/calculator.apk: $(shell ${NITLS} -M src/android_calculator.nit) ${NITC} android/res/drawable-hdpi/icon.png
mkdir -p bin
- ${NITC} -o $@ src/scientific_calculator.nit -m src/android_calculator.nit -D debug
+ ${NITC} -o $@ src/android_calculator.nit -D debug
-android-release: $(shell ${NITLS} -M src/scientific_calculator.nit src/android_calculator.nit) ${NITC} android/res/
+bin/scientific.apk: $(shell ${NITLS} -M src/scientific src/android_calculator.nit) ${NITC} src/scientific/android/res/drawable-hdpi/icon.png
mkdir -p bin
- ${NITC} -o bin/calculator.apk src/scientific_calculator.nit -m src/android_calculator.nit --release
+ ${NITC} -o $@ src/scientific -m src/android_calculator.nit -D debug
-android/res/: art/icon.svg ../../contrib/inkscape_tools/bin/svg_to_icons
+android-release: $(shell ${NITLS} -M src/scientific src/android_calculator.nit) ${NITC} android/res/drawable-hdpi/icon.png
+ mkdir -p bin
+ ${NITC} -o bin/calculator.apk src/scientific -m src/android_calculator.nit --release
+
+android/res/drawable-hdpi/icon.png: art/icon.svg ../../contrib/inkscape_tools/bin/svg_to_icons
mkdir -p android/res
../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out android/res/
+src/scientific/android/res/drawable-hdpi/icon.png: art/icon_sci.svg ../../contrib/inkscape_tools/bin/svg_to_icons
+ mkdir -p src/scientific/android/res
+ ../../contrib/inkscape_tools/bin/svg_to_icons art/icon-sci.svg --android --out src/scientific/android/res/
+
../../contrib/inkscape_tools/bin/svg_to_icons:
make -C ../../contrib/inkscape_tools/
# ---
# iOS
-bin/calculator.app: $(shell ${NITLS} -M src/scientific_calculator.nit src/ios_calculator.nit) ${NITC} ios/AppIcon.appiconset/Contents.json
+ios: bin/calculator.app bin/scientific.app
+
+bin/calculator.app: $(shell ${NITLS} -M src/ios_calculator.nit) ${NITC} ios/AppIcon.appiconset/Contents.json
mkdir -p bin
- ${NITC} -o $@ src/scientific_calculator.nit -m src/ios_calculator.nit -D debug
+ ${NITC} -o $@ src/ios_calculator.nit -D debug
+
+bin/scientific.app: $(shell ${NITLS} -M src/scientific src/ios_calculator.nit) ${NITC} src/scientific/ios/AppIcon.appiconset/Contents.json
+ mkdir -p bin
+ ${NITC} -o $@ src/scientific -m src/ios_calculator.nit -D debug
ios/AppIcon.appiconset/Contents.json: art/icon-ios.svg
mkdir -p ios
../../contrib/inkscape_tools/bin/svg_to_icons art/icon-ios.svg --ios --out ios/AppIcon.appiconset/
+src/scientific/ios/AppIcon.appiconset/Contents.json: art/icon-ios.svg
+ mkdir -p ios
+ ../../contrib/inkscape_tools/bin/svg_to_icons art/icon-ios-sci.svg --ios --out src/scientific/ios/AppIcon.appiconset/
+
# ---
# Tests
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="icon-ios-sci.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="388.94406"
+ inkscape:cy="238.25989"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1724"
+ inkscape:window-height="1103"
+ inkscape:window-x="242"
+ inkscape:window-y="23"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:190.84666443px;line-height:125%;font-family:Sathu;-inkscape-font-specification:Sathu;letter-spacing:0px;word-spacing:0px;fill:#008bff;fill-opacity:1;stroke:none"
+ x="285.77982"
+ y="961.64594"
+ id="text3014"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3016"
+ x="285.77982"
+ y="961.64594">x²</tspan></text>
+ <g
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:269.1137085px;line-height:125%;font-family:'Droid Sans';-inkscape-font-specification:'Droid Sans';letter-spacing:0px;word-spacing:0px;fill:#008bff;fill-opacity:1;stroke:none"
+ id="text3013"
+ transform="translate(4,-4)">
+ <path
+ d="m 77.43458,894.9284 0,-19.57907 121.41654,0 0,19.57907 -121.41654,0 m 0,53.87531 0,-19.71048 121.41654,0 0,19.71048 -121.41654,0"
+ style="fill:#008bff;fill-opacity:1"
+ id="path2999"
+ inkscape:connector-curvature="0" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:183.57151794px;line-height:125%;font-family:Sathu;-inkscape-font-specification:Sathu;letter-spacing:0px;word-spacing:0px;fill:#008bff;fill-opacity:1;stroke:none"
+ x="269.98895"
+ y="720.69153"
+ id="text2994"
+ sodipodi:linespacing="125%"
+ transform="scale(0.99205729,1.0080063)"><tspan
+ sodipodi:role="line"
+ id="tspan2996"
+ x="269.98895"
+ y="720.69153">√</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:190.84666443000000413px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#008bff;fill-opacity:1;stroke:none;font-family:Sathu;-inkscape-font-specification:Sathu;"
+ x="67.883858"
+ y="734.41699"
+ id="text2998"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3000"
+ x="67.883858"
+ y="734.41699">π</tspan></text>
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="icon_sci.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="164.13268"
+ inkscape:cy="278.8294"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1598"
+ inkscape:window-height="1316"
+ inkscape:window-x="2649"
+ inkscape:window-y="84"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <rect
+ style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2987"
+ width="500"
+ height="500"
+ x="5.9999847"
+ y="546.36218"
+ rx="64"
+ ry="64" />
+ <rect
+ ry="48"
+ rx="48"
+ y="569.2193"
+ x="32.42857"
+ height="211.42856"
+ width="211.42856"
+ id="rect2989"
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+ <rect
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2991"
+ width="211.42856"
+ height="211.42856"
+ x="268.14285"
+ y="569.2193"
+ rx="48"
+ ry="48" />
+ <rect
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2993"
+ width="211.42856"
+ height="211.42856"
+ x="32.42857"
+ y="806.36218"
+ rx="48"
+ ry="48" />
+ <rect
+ ry="48"
+ rx="48"
+ y="806.36218"
+ x="268.14285"
+ height="211.42856"
+ width="211.42856"
+ id="rect2995"
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+ <g
+ style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ id="text3013">
+ <path
+ d="m 77.43458,894.9284 0,-19.57907 121.41654,0 0,19.57907 -121.41654,0 m 0,53.87531 0,-19.71048 121.41654,0 0,19.71048 -121.41654,0"
+ id="path2999"
+ style="" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:190.84666443px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ x="318.1875"
+ y="744.69647"
+ id="text2994"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2996"
+ x="318.1875"
+ y="744.69647">√</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:190.84666443px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ x="72.978729"
+ y="725.84735"
+ id="text2998"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3000"
+ x="72.978729"
+ y="725.84735">π</tspan></text>
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3002"
+ style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:New Shape;font-style:normal;font-weight:normal;font-size:16px;line-height:125%;letter-spacing:0px;word-spacing:0px;-inkscape-font-specification:New Shape;font-stretch:normal;font-variant:normal"><flowRegion
+ id="flowRegion3004"><rect
+ id="rect3006"
+ width="104.28571"
+ height="282.85715"
+ x="-225"
+ y="-62.285713" /></flowRegion><flowPara
+ id="flowPara3008"></flowPara></flowRoot> <text
+ xml:space="preserve"
+ style="font-size:190.84666443px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ x="303.01755"
+ y="973.79059"
+ id="text3014"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3016"
+ x="303.01755"
+ y="973.79059">x²</tspan></text>
+ </g>
+</svg>
# Portable calculator UI
module calculator is
- app_name "app.nit Calc."
- app_version(0, 1, git_revision)
+ app_name "app.nit Calc"
+ app_version(0, 2, git_revision)
app_namespace "org.nitlanguage.calculator"
# Lock in portrait mode
# limitations under the License.
# Extends the portable calculator app with scientific operations
-module scientific_calculator
+module scientific is
+ app_name "app.nit Calc Sci"
+ app_namespace "org.nitlanguage.scientific_calculator"
+ app_files
+end
import calculator
The special function `git_revision` will use the prefix of the hash of the latest git commit.
By default, the version is 0.1.
+* `app_files` tells the compiler where to find platform specific resource files associated to a module.
+ By default, only the root of the project is searched for the folders `android` and `ios`.
+ The `android` folder is used as base for the generated Android project,
+ it can be used to specify the resource files, libs and even Java source files.
+ The `ios` folder is searched for icons only.
+
+ Each argument of `app_files` is a relative path to a folder containing extra `android` or `ios` folders.
+ If there is no arguments, the parent folder of the annotated module is used.
+ In case of name conflicts in the resource files, the files from the project root have the lowest priority,
+ those associated to modules lower in the importation hierarchy have higher priority.
+
## Usage Example
~~~
new_annotation app_name
new_annotation app_namespace
new_annotation app_version
+ new_annotation app_files
end
# App subclasses are cross-platform applications
if f isa ExternCFile then cfiles.add(f.filename.basename)
end
- # Is there an icon?
var project_root = "."
var mpackage = compiler.mainmodule.first_real_mmodule.mpackage
if mpackage != null then
end
end
+ # Set the default pretty application name
+"""<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">{{{app_name}}}</string>
+</resources>""".write_to_file "{android_project_root}/res/values/strings.xml"
+
+ # Copy assets, resources and libs where expected by the SDK
+
+ ## Collect path to all possible folder where we can find the `android` folder
+ var app_files = [project_root]
+ app_files.add_all project.files
+
+ for path in app_files do
+ # Copy the assets folder
+ var assets_dir = path / "assets"
+ if assets_dir.file_exists then
+ assets_dir = assets_dir.realpath
+ toolcontext.exec_and_check(["cp", "-r", assets_dir, android_project_root], "Android project error")
+ end
+
+ # Copy the whole `android` folder
+ var android_dir = path / "android"
+ if android_dir.file_exists then
+ android_dir = android_dir.realpath
+ toolcontext.exec_and_check(["cp", "-r", android_dir, root_compile_dir], "Android project error")
+ end
+ end
+
+ # Is there an icon?
var resolutions = ["ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"]
var icon_available = false
for res in resolutions do
toolcontext.exec_and_check(["ln", "-s", "{share_dir}/libgc/arm/include/gc/",
"{compile_dir}/gc"], "Android project error")
-
- # Copy assets, resources and libs where expected by the SDK
-
- # Link to assets (for mnit and others)
- var assets_dir = project_root / "assets"
- if assets_dir.file_exists then
- assets_dir = assets_dir.realpath
- var target_assets_dir = "{android_project_root}/assets"
- if not target_assets_dir.file_exists then
- toolcontext.exec_and_check(["ln", "-s", assets_dir, target_assets_dir], "Android project error")
- end
- end
-
- # Copy the res folder
- var res_dir = project_root / "android/res"
- if res_dir.file_exists then
- # copy the res folder to the compile dir
- res_dir = res_dir.realpath
- toolcontext.exec_and_check(["cp", "-R", res_dir, android_project_root], "Android project error")
- end
-
- if not res_dir.file_exists or not "{res_dir}/values/strings.xml".file_exists then
- # Create our own custom `res/values/string.xml` with the App name
-"""<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="app_name">{{{app_name}}}</string>
-</resources>""".write_to_file "{android_project_root}/res/values/strings.xml"
- end
-
- # Copy the libs folder
- var libs_dir = project_root / "android/libs"
- if libs_dir.file_exists then
- toolcontext.exec_and_check(["cp", "-r", libs_dir, android_project_root], "Android project error")
- end
end
redef fun write_makefile(compile_dir, cfiles)
return local_time_s.to_i
end
+ # Extra folders where to find platform specific resource files
+ var files = new Array[String]
+
private var modelbuilder: ModelBuilder
private var mainmodule: MModule
if val != null then namespace = val
end
+ var annots = modelbuilder.collect_annotations_on_modules("app_files", mainmodule)
+ for a in annots do files.add_all a.as_relative_paths(modelbuilder)
+
modelbuilder.toolcontext.check_errors
end
return version_fields.join(".")
end
+
+ # Parse all arguments as paths relative to the declaring module
+ #
+ # If no arguments are given, then use the parent directory of the module.
+ private fun as_relative_paths(modelbuilder: ModelBuilder): Array[String]
+ do
+ var paths = new Array[String]
+
+ var file = location.file
+ if file == null then return paths
+
+ var args = n_args
+ if args.is_empty then
+ paths.add file.filename.dirname
+ else
+ for arg in args do
+ var val = arg.as_string
+ if val != null then
+ paths.add file.filename.dirname/val
+ else modelbuilder.error(arg, "Syntax Error: `app_files` expects String literals as arguments.")
+ end
+ end
+
+ return paths
+ end
end
end
end
- var icon_dir = project_root / "ios" / "AppIcon.appiconset"
- var icons_found = icon_dir.file_exists
- if icons_found then
+ # Copy all resources
+ var app_files = [project_root]
+ app_files.add_all app_project.files
+
+ var icons_found = false
- # Prepare the `Assets.xcassets` folder
- var target_assets_dir = compile_dir / "Assets.xcassets"
- if not target_assets_dir.file_exists then target_assets_dir.mkdir
+ for path in app_files do
+ var icon_dir = path / "ios" / "AppIcon.appiconset"
+ if icon_dir.file_exists then
+ icons_found = true
- """
+ # Prepare the `Assets.xcassets` folder
+ var target_assets_dir = compile_dir / "Assets.xcassets"
+ if not target_assets_dir.file_exists then target_assets_dir.mkdir
+
+ """
{
"info" : {
"version" : 1,
}
}""".write_to_file target_assets_dir / "Contents.json"
- # copy the res folder to the compile dir
- icon_dir = icon_dir.realpath
- toolcontext.exec_and_check(["cp", "-R", icon_dir, target_assets_dir], "iOS project error")
+ # copy the res folder to the compile dir
+ icon_dir = icon_dir.realpath
+ toolcontext.exec_and_check(["cp", "-R", icon_dir, target_assets_dir], "iOS project error")
+ end
end
# TODO Register asset files