diff --git a/.gitignore b/.gitignore
index 9877009..16c26fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ do-test*
.DS_Store
emb64.kt
.gradle
+*.hprof
.idea
ignore.*
kd.kt
@@ -14,3 +15,4 @@ local.properties
ver-windows-x64/src/*.h
ver-windows-x64/src/*.cpp
ver-windows-x64/src/*.qml
+*.xcodeproj
diff --git a/README.md b/README.md
index caec89e..5bad61d 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,12 @@ application looks like
* [Hello world](#hw)
* [Android](#hw_android)
+ * [iOS](#hw_ios)
* [Linux](#hw_linux)
* [macOS](#hw_macos)
* [Windows](#hw_windows)
+* [Hello list](#hl)
+ * [Android](#hl_android)
@@ -72,6 +75,15 @@ Instructions:
| 5 | Open `helloworld/ver-android` project | |
| 6 | Press Run | |
+
+
+### iOS
+
+Fill local.properties with sdk path (it's gitignored)
+
+TODO
+
+
### Linux
@@ -136,3 +148,19 @@ Instructions:
| 2 | Go to `helloworld` directory | `cd helloworld` |
| 3 | Build the application | `./util/build-windows-x64` |
| 4 | Launch the application | `./util/launch-windows-x64`|
+
+
+
+## Hello list
+
+`helloworld` example depicts how to alter text on button click
+
+TODO Structure
+
+
+
+### Android
+
+TODO Video
+
+TODO Instructions
diff --git a/hellolist/components/other/android/MainActivity.kt b/hellolist/components/other/android/MainActivity.kt
new file mode 100644
index 0000000..4a11cba
--- /dev/null
+++ b/hellolist/components/other/android/MainActivity.kt
@@ -0,0 +1,32 @@
+package org.opengamestudio
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.*
+import androidx.compose.ui.*
+import org.opengamestudio.ui.theme.MyApplicationTheme
+
+class MainActivity: ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+
+ VM.androidContext = this
+ // Launch components once VM has Android Context
+ RootComponent.setup()
+
+ setContent {
+ MyApplicationTheme {
+ Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
+ RootView(
+ modifier = Modifier.padding(innerPadding),
+ VM
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/hellolist/components/other/android/VM.kt b/hellolist/components/other/android/VM.kt
new file mode 100644
index 0000000..90e45a6
--- /dev/null
+++ b/hellolist/components/other/android/VM.kt
@@ -0,0 +1,11 @@
+package org.opengamestudio
+
+import android.content.Context
+import androidx.compose.runtime.*
+
+object VM {
+ var androidContext: Context? = null
+
+ var rootIsVisible = mutableStateOf(false)
+ var rootItems = mutableStateListOf- ()
+}
diff --git a/hellolist/components/other/desktop/App.cpp b/hellolist/components/other/desktop/App.cpp
new file mode 100644
index 0000000..25dbb93
--- /dev/null
+++ b/hellolist/components/other/desktop/App.cpp
@@ -0,0 +1,36 @@
+#include
+#include
+#include
+#include
+
+#include "ignore.kd.h"
+#include "root.h"
+#include "VM.h"
+
+int main(int argc, char *argv[]) {
+ // Create Qt application
+ QQuickStyle::setStyle("Fusion");
+ QApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+ QObject::connect(
+ &engine,
+ &QQmlApplicationEngine::objectCreationFailed,
+ &app,
+ []() { QCoreApplication::exit(-1); },
+ Qt::QueuedConnection
+ );
+
+ API api;
+ FObj fobj;
+ // Create and launch components
+ RootComponent r;
+ r.setup();
+
+ // Configure and load QML
+ engine.rootContext()->setContextProperty("api", &api);
+ engine.rootContext()->setContextProperty("F", &fobj);
+ engine.rootContext()->setContextProperty("vm", &VM::singleton());
+ engine.loadFromModule("hellolist", "AppView");
+
+ return app.exec();
+}
diff --git a/hellolist/components/other/desktop/KT.h b/hellolist/components/other/desktop/KT.h
new file mode 100644
index 0000000..9510da3
--- /dev/null
+++ b/hellolist/components/other/desktop/KT.h
@@ -0,0 +1,10 @@
+#ifndef HL_KT_H
+#define HL_KT_H
+
+#include "libhl_api.h"
+#define KT libhl_symbols()->kotlin.root.org.opengamestudio
+#define KTLibRef(NAME) libhl_kref_kotlin_##NAME
+#define KTRef(NAME) libhl_kref_org_opengamestudio_##NAME
+#define KTSym libhl_symbols()
+
+#endif // HL_KT_H
diff --git a/hellolist/components/other/desktop/VM.cpp b/hellolist/components/other/desktop/VM.cpp
new file mode 100644
index 0000000..00c4ca0
--- /dev/null
+++ b/hellolist/components/other/desktop/VM.cpp
@@ -0,0 +1,49 @@
+#include "KT.h"
+#include "VM.h"
+
+VM::VM() : QObject() {
+ _rootIsVisible = false;
+}
+
+VM::~VM() {
+ qDeleteAll(_rootItems);
+}
+
+bool VM::rootIsVisible() const {
+ return _rootIsVisible;
+}
+
+QQmlListProperty
- VM::rootItems() const {
+ return QQmlListProperty
- (
+ const_cast(this),
+ nullptr,
+ &VM::rootItemsCount,
+ &VM::rootItemsAt
+ );
+}
+
+Item *VM::rootItemsAt(
+ QQmlListProperty
- *list,
+ qsizetype index
+) {
+ auto *vm = qobject_cast(list->object);
+ return vm ? vm->_rootItems.at(index) : nullptr;
+}
+
+qsizetype VM::rootItemsCount(QQmlListProperty
- *list) {
+ auto *vm = qobject_cast(list->object);
+ return vm ? vm->_rootItems.size() : 0;
+}
+
+void VM::rootSetIsVisible(bool value) {
+ _rootIsVisible = value;
+ emit rootDidChangeIsVisible(value);
+}
+
+void VM::rootSetItems(QList
- items) {
+ for (auto *item : _rootItems) {
+ item->deleteLater();
+ }
+ _rootItems = items;
+ emit rootDidChangeItems();
+}
diff --git a/hellolist/components/other/desktop/VM.h b/hellolist/components/other/desktop/VM.h
new file mode 100644
index 0000000..bae69c4
--- /dev/null
+++ b/hellolist/components/other/desktop/VM.h
@@ -0,0 +1,59 @@
+#ifndef HL_VM_H
+#define HL_VM_H
+
+#include
+#include
+#include
+
+#include "ignore.kd.h"
+#include "KT.h"
+
+class VM: public QObject {
+ Q_OBJECT
+
+ Q_PROPERTY(
+ bool rootIsVisible
+ READ rootIsVisible
+ WRITE rootSetIsVisible
+ NOTIFY rootDidChangeIsVisible
+ )
+
+ Q_PROPERTY(
+ QQmlListProperty
- rootItems
+ READ rootItems
+ NOTIFY rootDidChangeItems
+ )
+
+ private:
+ VM();
+
+ public:
+ VM(VM const &) = delete;
+ void operator=(VM const &) = delete;
+ virtual ~VM();
+ static VM &singleton() {
+ static VM instance;
+ return instance;
+ }
+
+ public:
+ bool rootIsVisible() const;
+
+ QQmlListProperty
- rootItems() const;
+ static Item *rootItemsAt(QQmlListProperty
- *list, qsizetype index);
+ static qsizetype rootItemsCount(QQmlListProperty
- *list);
+
+ public slots:
+ void rootSetIsVisible(bool value);
+ void rootSetItems(QList
- items);
+
+ signals:
+ void rootDidChangeIsVisible(bool value);
+ void rootDidChangeItems();
+
+ private:
+ bool _rootIsVisible;
+ QList
- _rootItems;
+};
+
+#endif // HL_VM_H
diff --git a/hellolist/components/other/desktop/view/AppView.qml b/hellolist/components/other/desktop/view/AppView.qml
new file mode 100644
index 0000000..ab3f315
--- /dev/null
+++ b/hellolist/components/other/desktop/view/AppView.qml
@@ -0,0 +1,15 @@
+import QtQuick
+import QtQuick.Controls
+import hellolist
+
+Window {
+ height: 480
+ id: wnd
+ title: qsTr("Hello List")
+ visible: true
+ width: 640
+
+ RootView {
+ anchors.fill: parent
+ }
+}
diff --git a/hellolist/components/other/sdk/other.kt b/hellolist/components/other/sdk/other.kt
new file mode 100644
index 0000000..85ef0e8
--- /dev/null
+++ b/hellolist/components/other/sdk/other.kt
@@ -0,0 +1,51 @@
+package org.opengamestudio
+
+// TODO Generate for Item
+fun anyAsItem(item: Any?) = item as Item
+
+// Debug representation of a value
+fun debugString(v: Any): String {
+ // Prepend a string with its length
+ if (v is String) {
+ return "S(${v.length})$v"
+ }
+
+ // Prepend an array with its size
+ if (v is Array<*>) {
+ var out = ""
+ for (item in v) {
+ if (!out.isEmpty()) {
+ out += ","
+ }
+ out += debugString(item!!)
+ }
+ return "A(${v.size})$out"
+ }
+
+ // Prepend a dictionary with its size
+ if (v is Map<*, *>) {
+ var out = ""
+ for ((key, value) in v) {
+ if (!out.isEmpty()) {
+ out += ","
+ }
+ out += debugString(key!!) + ":" + debugString(value!!)
+ }
+ return "D(${v.size})$out"
+ }
+
+ // Otherwise just print by default
+ return "$v"
+}
+
+// Print each key/value processed by a component into console
+fun setupComponentDebugging(
+ ctrl: KDController,
+ prefix: String
+) {
+ ctrl.registerCallback { c ->
+ val anyval = c.fieldAny(c.recentField)
+ val strval = debugString(anyval)
+ println("ИГР $prefix k/v: '${c.recentField}'/'$strval'")
+ }
+}
diff --git a/hellolist/components/root/android/root.kt b/hellolist/components/root/android/root.kt
new file mode 100644
index 0000000..bde7038
--- /dev/null
+++ b/hellolist/components/root/android/root.kt
@@ -0,0 +1,18 @@
+package org.opengamestudio
+
+typealias RC = RootContext
+
+object RootComponent {
+ init {
+ val vm = VM
+ val oneliners = arrayOf(
+ F.isVisible, { c: RC -> vm.rootIsVisible.value = c.isVisible },
+ F.items, { c: RC -> rootResetItems(vm, c.items) },
+ )
+ registerOneliners(rootCtrl(), oneliners)
+ }
+
+ fun setup() {
+ rootSet(F.didSetup, true)
+ }
+}
diff --git a/hellolist/components/root/android/rootEffect.kt b/hellolist/components/root/android/rootEffect.kt
new file mode 100644
index 0000000..fdb6449
--- /dev/null
+++ b/hellolist/components/root/android/rootEffect.kt
@@ -0,0 +1,9 @@
+package org.opengamestudio
+
+fun rootResetItems(
+ vm: VM,
+ items: Array
-
+) {
+ vm.rootItems.clear()
+ vm.rootItems.addAll(items)
+}
diff --git a/hellolist/components/root/android/view/RootView.kt b/hellolist/components/root/android/view/RootView.kt
new file mode 100644
index 0000000..925f76f
--- /dev/null
+++ b/hellolist/components/root/android/view/RootView.kt
@@ -0,0 +1,52 @@
+package org.opengamestudio
+
+import androidx.compose.animation.*
+import androidx.compose.foundation.background
+import androidx.compose.foundation.lazy.*
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.*
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.*
+
+@Composable
+fun RootView(
+ modifier: Modifier,
+ vm: VM
+) {
+ AnimatedVisibility(
+ enter = fadeIn(),
+ exit = fadeOut(),
+ modifier = modifier,
+ visible = vm.rootIsVisible.value,
+ ) {
+ Box(
+ contentAlignment = Alignment.TopCenter,
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color(0xFFFAFAFA))
+ ) {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ Text("TODO list")
+ Spacer(modifier = Modifier.height(10.dp))
+ OutlinedButton(
+ onClick = { rootSet(F.didClickAddItem, true) },
+ ) {
+ Text("Add item")
+ }
+ Spacer(modifier = Modifier.height(10.dp))
+ LazyColumn(
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ modifier = Modifier.padding(horizontal = 16.dp)
+ ) {
+ items(vm.rootItems) { item ->
+ Box(modifier = Modifier.padding(vertical = 4.dp)) {
+ RootViewItem(item)
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/hellolist/components/root/android/view/RootViewItem.kt b/hellolist/components/root/android/view/RootViewItem.kt
new file mode 100644
index 0000000..53c5f77
--- /dev/null
+++ b/hellolist/components/root/android/view/RootViewItem.kt
@@ -0,0 +1,44 @@
+package org.opengamestudio
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.*
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.*
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.*
+
+@Composable
+fun RootViewItem(item: Item) {
+ Surface(
+ shape = RoundedCornerShape(12.dp),
+ color = Color.White,
+ border = BorderStroke(1.dp, Color(0xFFEEEEEE)),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 4.dp)
+ ) {
+ Row(
+ modifier = Modifier
+ .padding(20.dp)
+ .fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = item.id.toString().padStart(2, '0'),
+ style = MaterialTheme.typography.labelSmall,
+ color = Color.Gray,
+ modifier = Modifier.width(28.dp)
+ )
+
+ Text(
+ text = item.title,
+ style = MaterialTheme.typography.bodyLarge,
+ fontWeight = FontWeight.Medium,
+ letterSpacing = 0.5.sp
+ )
+ }
+ }
+}
diff --git a/hellolist/components/root/desktop/root.cpp b/hellolist/components/root/desktop/root.cpp
new file mode 100644
index 0000000..14f1aae
--- /dev/null
+++ b/hellolist/components/root/desktop/root.cpp
@@ -0,0 +1,22 @@
+#include
+#include
+#include
+
+#include "ignore.kd.h"
+#include "root.h"
+#include "rootEffect.h"
+
+#define CB(code) std::make_any>([&](RootContext c) { code })
+#define VM VM::singleton()
+
+RootComponent::RootComponent() {
+ std::vector oneliners = {
+ F.isVisible, CB( VM.rootSetIsVisible(c.isVisible()); ),
+ F.items, CB( rootResetItems(VM, c.items()); ),
+ };
+ RootEffectRegistry::registerOneliners(KT.rootCtrl(), oneliners);
+}
+
+void RootComponent::setup() {
+ rootSet(F.didSetup, true);
+}
diff --git a/hellolist/components/root/desktop/root.h b/hellolist/components/root/desktop/root.h
new file mode 100644
index 0000000..b892960
--- /dev/null
+++ b/hellolist/components/root/desktop/root.h
@@ -0,0 +1,13 @@
+#ifndef HL_ROOT_H
+#define HL_ROOT_H
+
+#include "KT.h"
+#include "VM.h"
+
+class RootComponent {
+ public:
+ RootComponent();
+ void setup();
+};
+
+#endif // HL_ROOT_H
diff --git a/hellolist/components/root/desktop/rootEffect.cpp b/hellolist/components/root/desktop/rootEffect.cpp
new file mode 100644
index 0000000..7723487
--- /dev/null
+++ b/hellolist/components/root/desktop/rootEffect.cpp
@@ -0,0 +1,12 @@
+#include
+
+#include "ignore.kd.h"
+#include "rootEffect.h"
+
+void rootResetItems(
+ VM &vm,
+ const Items &items
+) {
+ vm.rootSetItems(items);
+}
+
diff --git a/hellolist/components/root/desktop/rootEffect.h b/hellolist/components/root/desktop/rootEffect.h
new file mode 100644
index 0000000..4186255
--- /dev/null
+++ b/hellolist/components/root/desktop/rootEffect.h
@@ -0,0 +1,9 @@
+#ifndef HL_ROOT_EFFECT_H
+#define HL_ROOT_EFFECT_H
+
+#include "KT.h"
+#include "VM.h"
+
+void rootResetItems(VM &vm, const Items &items);
+
+#endif // HL_ROOT_EFFECT_H
diff --git a/hellolist/components/root/desktop/view/RootView.qml b/hellolist/components/root/desktop/view/RootView.qml
new file mode 100644
index 0000000..8dc71ea
--- /dev/null
+++ b/hellolist/components/root/desktop/view/RootView.qml
@@ -0,0 +1,54 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Rectangle {
+ id: rootView
+ visible: vm.rootIsVisible
+ color: "#FAFAFA"
+
+ // Use a Column for the static header items to size naturally
+ Column {
+ id: header
+ anchors.top: parent.top
+ anchors.topMargin: 30
+ anchors.horizontalCenter: parent.horizontalCenter
+ spacing: 10
+ width: parent.width
+
+ Text {
+ text: "TODO list"
+ font.bold: true
+ font.pointSize: 24
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Button {
+ text: "Add item"
+ onClicked: api.rootSet(F.didClickAddItem, true)
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ // Anchor the ListView to cleanly fill the remaining space of the screen
+ ListView {
+ id: listView
+ anchors.top: header.bottom
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.topMargin: 10
+ anchors.leftMargin: 16
+ anchors.rightMargin: 16
+ model: vm.rootItems
+ spacing: 8
+ clip: true // Prevents items from overflowing visually when scrolled
+ delegate: RootViewItem {
+ width: listView.width
+ }
+ footer: Item {
+ width: listView.width
+ height: 16
+ }
+ }
+}
\ No newline at end of file
diff --git a/hellolist/components/root/desktop/view/RootViewItem.qml b/hellolist/components/root/desktop/view/RootViewItem.qml
new file mode 100644
index 0000000..572eca6
--- /dev/null
+++ b/hellolist/components/root/desktop/view/RootViewItem.qml
@@ -0,0 +1,37 @@
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Rectangle {
+ id: rootViewItem
+ required property var model
+ height: contentLayout.implicitHeight + 40 // Calculated cleanly from content
+ radius: 12
+ color: "white"
+ border.color: "#EEEEEE"
+ border.width: 1
+
+ RowLayout {
+ id: contentLayout
+ // Safely anchor without causing height circular dependencies
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 20
+ spacing: 8
+
+ Text {
+ text: model.id.toString().padStart(2, "0")
+ font.pointSize: 12
+ color: "gray"
+ Layout.preferredWidth: 28
+ }
+
+ Text {
+ text: model.title
+ font.pointSize: 16
+ font.weight: Font.Medium
+ Layout.fillWidth: true
+ }
+ }
+}
\ No newline at end of file
diff --git a/hellolist/components/root/sdk/rootProto.kt b/hellolist/components/root/sdk/rootProto.kt
new file mode 100644
index 0000000..fcd9e68
--- /dev/null
+++ b/hellolist/components/root/sdk/rootProto.kt
@@ -0,0 +1,33 @@
+package org.opengamestudio
+
+object RootProto {
+ val ctrl: KDController
+
+ init {
+ ctrl = KDController(RootContext())
+ setupComponentDebugging(ctrl, "Root")
+ arrayOf(
+ ::rootShouldLaunch,
+ ::rootShouldResetItems,
+ ::rootShouldResetVisibility,
+ ).forEach { f ->
+ ctrl.registerFunction { c -> f(c as RootContext) }
+ }
+ }
+}
+
+fun rootCtrl(): KDController {
+ return RootProto.ctrl
+}
+
+fun rootCtrlCtx(): RootContext {
+ return RootProto.ctrl.context as RootContext
+}
+
+fun rootCtrlCtxField(): String {
+ return RootProto.ctrl.context.recentField
+}
+
+fun rootSet(k: String, v: Any) {
+ RootProto.ctrl.set(k, v)
+}
diff --git a/hellolist/components/root/sdk/rootShould.kt b/hellolist/components/root/sdk/rootShould.kt
new file mode 100644
index 0000000..0564e86
--- /dev/null
+++ b/hellolist/components/root/sdk/rootShould.kt
@@ -0,0 +1,54 @@
+package org.opengamestudio
+
+// Launch only once
+//
+// Purpose: Work around Android's activity restart
+//
+// Conditions:
+// 1. UI has been created the first time
+fun rootShouldLaunch(c: RootContext): RootContext {
+ /* 1 */ if (
+ c.recentField == F.didSetup &&
+ !c.didLaunch
+ ) {
+ c.didLaunch = true
+ c.recentField = F.didLaunch
+ return c
+ }
+
+ c.recentField = F.none
+ return c
+}
+
+// Reset items
+//
+// Conditions:
+// 1. User did click `Add item` button
+fun rootShouldResetItems(c: RootContext): RootContext {
+ /* 1 */ if (c.recentField == F.didClickAddItem) {
+ val item = Item()
+ item.id = c.items.size
+ item.title = "Item-${item.id}"
+ c.items += item
+ c.recentField = F.items
+ return c
+ }
+
+ c.recentField = F.none
+ return c
+}
+
+// Set main window visible
+//
+// Conditions:
+// 1. Did launch
+fun rootShouldResetVisibility(c: RootContext): RootContext {
+ /* 1 */ if (c.recentField == F.didLaunch) {
+ c.isVisible = true
+ c.recentField = F.isVisible
+ return c
+ }
+
+ c.recentField = F.none
+ return c
+}
diff --git a/hellolist/kd.yml b/hellolist/kd.yml
new file mode 100644
index 0000000..a43497d
--- /dev/null
+++ b/hellolist/kd.yml
@@ -0,0 +1,30 @@
+version: 3
+
+output:
+ ver-android/app/src/main/kotlin/org/opengamestudio/ignore.kd.kt:
+ type: kotlin
+ sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/ignore.kd.kt:
+ type: c++sdk
+ ver-mac-x64/src/ignore.kd.h:
+ type: c++hdr
+ ver-mac-x64/src/ignore.kd.cpp:
+ type: c++src
+
+c++sdk: package org.opengamestudio
+c++sdk: import kotlinx.cinterop.*
+kotlin: package org.opengamestudio
+
+Item:
+ type: struct
+ fields:
+ id: Int
+ title: String
+
+RootContext:
+ type: context
+ fields:
+ didClickAddItem: Bool
+ didLaunch: Bool
+ didSetup: Bool
+ isVisible: Bool
+ items: [Item]
diff --git a/hellolist/sdk-mac-x64/gradle.properties b/hellolist/sdk-mac-x64/gradle.properties
new file mode 100644
index 0000000..cb1b133
--- /dev/null
+++ b/hellolist/sdk-mac-x64/gradle.properties
@@ -0,0 +1,4 @@
+# Verbose build log
+org.gradle.console=verbose
+# Cache artifacts
+org.gradle.caching=true
diff --git a/hellolist/sdk-mac-x64/gradle/libs.versions.toml b/hellolist/sdk-mac-x64/gradle/libs.versions.toml
new file mode 100644
index 0000000..57fe338
--- /dev/null
+++ b/hellolist/sdk-mac-x64/gradle/libs.versions.toml
@@ -0,0 +1,7 @@
+[versions]
+kotlin = "2.2.0"
+
+[libraries]
+
+[plugins]
+kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
diff --git a/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.jar b/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..a4b76b9
Binary files /dev/null and b/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.properties b/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..37f78a6
--- /dev/null
+++ b/hellolist/sdk-mac-x64/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/hellolist/sdk-mac-x64/gradlew b/hellolist/sdk-mac-x64/gradlew
new file mode 100755
index 0000000..f3b75f3
--- /dev/null
+++ b/hellolist/sdk-mac-x64/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/hellolist/sdk-mac-x64/hl/build.gradle.kts b/hellolist/sdk-mac-x64/hl/build.gradle.kts
new file mode 100644
index 0000000..d07a480
--- /dev/null
+++ b/hellolist/sdk-mac-x64/hl/build.gradle.kts
@@ -0,0 +1,21 @@
+plugins {
+ alias(libs.plugins.kotlin.multiplatform)
+}
+
+kotlin {
+ macosX64("native") {
+ binaries {
+ sharedLib {
+ baseName = "hl"
+ }
+ }
+ }
+ sourceSets {
+ nativeMain.dependencies {
+ }
+ }
+}
+
+tasks.withType {
+ distributionType = Wrapper.DistributionType.ALL
+}
diff --git a/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/other/other.kt b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/other/other.kt
new file mode 120000
index 0000000..4c4de9a
--- /dev/null
+++ b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/other/other.kt
@@ -0,0 +1 @@
+../../../../../../../../components/other/sdk/other.kt
\ No newline at end of file
diff --git a/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootProto.kt b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootProto.kt
new file mode 120000
index 0000000..0989fa1
--- /dev/null
+++ b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootProto.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/sdk/rootProto.kt
\ No newline at end of file
diff --git a/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootShould.kt b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootShould.kt
new file mode 120000
index 0000000..c6549db
--- /dev/null
+++ b/hellolist/sdk-mac-x64/hl/src/nativeMain/kotlin/org/opengamestudio/root/rootShould.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/sdk/rootShould.kt
\ No newline at end of file
diff --git a/hellolist/sdk-mac-x64/settings.gradle.kts b/hellolist/sdk-mac-x64/settings.gradle.kts
new file mode 100644
index 0000000..0104745
--- /dev/null
+++ b/hellolist/sdk-mac-x64/settings.gradle.kts
@@ -0,0 +1,17 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "sdk-mac-x64"
+include("hl")
diff --git a/hellolist/util/build-android b/hellolist/util/build-android
new file mode 120000
index 0000000..dda1be0
--- /dev/null
+++ b/hellolist/util/build-android
@@ -0,0 +1 @@
+../../helloworld/util/build-android
\ No newline at end of file
diff --git a/hellolist/util/build-mac-x64 b/hellolist/util/build-mac-x64
new file mode 120000
index 0000000..e2bfc79
--- /dev/null
+++ b/hellolist/util/build-mac-x64
@@ -0,0 +1 @@
+../../helloworld/util/build-mac-x64
\ No newline at end of file
diff --git a/hellolist/util/launch-mac-x64 b/hellolist/util/launch-mac-x64
new file mode 100755
index 0000000..fe8f697
--- /dev/null
+++ b/hellolist/util/launch-mac-x64
@@ -0,0 +1,3 @@
+#!/bin/bash -e
+SDIR=$(cd "$(dirname "$0")" ; pwd -P)
+$SDIR/../ver-mac-x64/build/hlM64
diff --git a/hellolist/util/other b/hellolist/util/other
new file mode 120000
index 0000000..ac0a757
--- /dev/null
+++ b/hellolist/util/other
@@ -0,0 +1 @@
+../../helloworld/util/other
\ No newline at end of file
diff --git a/hellolist/util/step b/hellolist/util/step
new file mode 120000
index 0000000..733d7a2
--- /dev/null
+++ b/hellolist/util/step
@@ -0,0 +1 @@
+../../helloworld/util/step
\ No newline at end of file
diff --git a/hellolist/ver-android/app/build.gradle.kts b/hellolist/ver-android/app/build.gradle.kts
new file mode 100644
index 0000000..73a75c8
--- /dev/null
+++ b/hellolist/ver-android/app/build.gradle.kts
@@ -0,0 +1,48 @@
+plugins {
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.kotlin.compose)
+}
+
+android {
+ namespace = "org.opengamestudio"
+ compileSdk = 35
+
+ buildFeatures {
+ compose = true
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ defaultConfig {
+ applicationId = "org.opengamestudio.kdexample"
+ minSdk = 24
+ targetSdk = 35
+ versionCode = 1
+ versionName = "0.0.1"
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.lifecycle.runtime.ktx)
+ implementation(libs.androidx.activity.compose)
+ implementation(platform(libs.androidx.compose.bom))
+ implementation(libs.androidx.ui)
+ implementation(libs.androidx.ui.graphics)
+ implementation(libs.androidx.ui.tooling.preview)
+ implementation(libs.androidx.material3)
+}
+
+kotlin {
+ sourceSets {
+ val main by getting {
+ dependencies {
+ }
+ }
+ }
+}
diff --git a/hellolist/ver-android/app/src/main/AndroidManifest.xml b/hellolist/ver-android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..709e2cc
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/MainActivity.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/MainActivity.kt
new file mode 120000
index 0000000..d52e306
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/MainActivity.kt
@@ -0,0 +1 @@
+../../../../../../../../components/other/android/MainActivity.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/VM.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/VM.kt
new file mode 120000
index 0000000..71f6231
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/VM.kt
@@ -0,0 +1 @@
+../../../../../../../../components/other/android/VM.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/other.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/other.kt
new file mode 120000
index 0000000..4c4de9a
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/other/other.kt
@@ -0,0 +1 @@
+../../../../../../../../components/other/sdk/other.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/root.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/root.kt
new file mode 120000
index 0000000..cad1fe8
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/root.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/android/root.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootEffect.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootEffect.kt
new file mode 120000
index 0000000..6a9aa97
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootEffect.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/android/rootEffect.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootProto.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootProto.kt
new file mode 120000
index 0000000..0989fa1
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootProto.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/sdk/rootProto.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootShould.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootShould.kt
new file mode 120000
index 0000000..c6549db
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/rootShould.kt
@@ -0,0 +1 @@
+../../../../../../../../components/root/sdk/rootShould.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootView.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootView.kt
new file mode 120000
index 0000000..a558af7
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootView.kt
@@ -0,0 +1 @@
+../../../../../../../../../components/root/android/view/RootView.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootViewItem.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootViewItem.kt
new file mode 120000
index 0000000..204ed09
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/root/view/RootViewItem.kt
@@ -0,0 +1 @@
+../../../../../../../../../components/root/android/view/RootViewItem.kt
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Color.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Color.kt
new file mode 100644
index 0000000..9f267e0
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Color.kt
@@ -0,0 +1,13 @@
+package org.opengamestudio.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val MainSmth = Color(0xFFD0BCFF)
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Theme.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Theme.kt
new file mode 100644
index 0000000..3a25e99
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Theme.kt
@@ -0,0 +1,51 @@
+package org.opengamestudio.ui.theme
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun MyApplicationTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ // Dynamic color is available on Android 12+
+ dynamicColor: Boolean = true,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = if (
+ dynamicColor &&
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
+ ) {
+ dynamicLightColorScheme(LocalContext.current)
+ } else {
+ LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography,
+ content = content
+ )
+}
diff --git a/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Type.kt b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Type.kt
new file mode 100644
index 0000000..6dd0751
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/kotlin/org/opengamestudio/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package org.opengamestudio.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
diff --git a/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_background.xml b/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_foreground.xml b/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/hellolist/ver-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/hellolist/ver-android/app/src/main/res/values/colors.xml b/hellolist/ver-android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/values/themes.xml b/hellolist/ver-android/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..e48770a
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/values/themes.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/xml/backup_rules.xml b/hellolist/ver-android/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/app/src/main/res/xml/data_extraction_rules.xml b/hellolist/ver-android/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/hellolist/ver-android/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hellolist/ver-android/build.gradle.kts b/hellolist/ver-android/build.gradle.kts
new file mode 100644
index 0000000..2440ca2
--- /dev/null
+++ b/hellolist/ver-android/build.gradle.kts
@@ -0,0 +1,7 @@
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.android.library) apply false
+ alias(libs.plugins.kotlin.android) apply false
+ alias(libs.plugins.kotlin.compose) apply false
+}
+
diff --git a/hellolist/ver-android/gradle.properties b/hellolist/ver-android/gradle.properties
new file mode 100644
index 0000000..b4fc37f
--- /dev/null
+++ b/hellolist/ver-android/gradle.properties
@@ -0,0 +1,6 @@
+# Use Compose for Android
+android.useAndroidX=true
+# Verbose build log
+org.gradle.console=verbose
+# Cache artifacts
+org.gradle.caching=true
diff --git a/hellolist/ver-android/gradle/libs.versions.toml b/hellolist/ver-android/gradle/libs.versions.toml
new file mode 100644
index 0000000..0954b98
--- /dev/null
+++ b/hellolist/ver-android/gradle/libs.versions.toml
@@ -0,0 +1,24 @@
+[versions]
+activityCompose = "1.8.0"
+agp = "8.10.1"
+composeBom = "2024.09.00"
+coreKtx = "1.10.1"
+kotlin = "2.2.0"
+lifecycleRuntimeKtx = "2.6.1"
+
+[libraries]
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
+androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
+androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
+androidx-ui = { group = "androidx.compose.ui", name = "ui" }
+androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
+androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
+androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
+androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+android-library= { id = "com.android.library", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
diff --git a/hellolist/ver-android/gradle/wrapper/gradle-wrapper.jar b/hellolist/ver-android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..a4b76b9
Binary files /dev/null and b/hellolist/ver-android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/hellolist/ver-android/gradle/wrapper/gradle-wrapper.properties b/hellolist/ver-android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..37f78a6
--- /dev/null
+++ b/hellolist/ver-android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/hellolist/ver-android/gradlew b/hellolist/ver-android/gradlew
new file mode 100755
index 0000000..f3b75f3
--- /dev/null
+++ b/hellolist/ver-android/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/hellolist/ver-android/settings.gradle.kts b/hellolist/ver-android/settings.gradle.kts
new file mode 100644
index 0000000..1719bc5
--- /dev/null
+++ b/hellolist/ver-android/settings.gradle.kts
@@ -0,0 +1,23 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "ver-android"
+include("app")
diff --git a/hellolist/ver-mac-x64/CMakeLists.txt b/hellolist/ver-mac-x64/CMakeLists.txt
new file mode 100644
index 0000000..d6f0843
--- /dev/null
+++ b/hellolist/ver-mac-x64/CMakeLists.txt
@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 3.16)
+project(hellolist)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED True)
+find_package(
+ Qt6
+ REQUIRED
+ COMPONENTS
+ Quick
+ QuickControls2
+ Widgets
+)
+qt_standard_project_setup(REQUIRES 6.5)
+
+# Application
+set(
+ SOURCES
+ src/ignore.kd.cpp
+ src/root/root.cpp
+ src/root/rootEffect.cpp
+ src/other/App.cpp
+ src/other/VM.cpp
+)
+qt_wrap_cpp(
+ SOURCES
+ src/ignore.kd.h
+ src/other/VM.h
+)
+qt_add_executable(hlM64 ${SOURCES})
+qt_add_qml_module(
+ hlM64
+ URI hellolist
+ QML_FILES
+ src/root/view/RootView.qml
+ src/root/view/RootViewItem.qml
+ src/other/view/AppView.qml
+)
+
+# SDK
+add_library(hl SHARED IMPORTED)
+set_target_properties(hl PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../sdk-mac-x64/hl/build/bin/native/releaseShared/libhl.dylib)
+target_include_directories(
+ hlM64
+ PRIVATE
+ ${CMAKE_SOURCE_DIR}/../sdk-mac-x64/hl/build/bin/native/releaseShared
+ src
+ src/root
+ src/other
+)
+
+# Link
+target_link_libraries(
+ hlM64
+ PRIVATE
+ hl
+ Qt6::Quick
+ Qt6::QuickControls2
+ Qt6::Widgets
+)
diff --git a/hellolist/ver-mac-x64/src/.gitkeep b/hellolist/ver-mac-x64/src/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/hellolist/ver-mac-x64/src/other/App.cpp b/hellolist/ver-mac-x64/src/other/App.cpp
new file mode 120000
index 0000000..a3bb26c
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/other/App.cpp
@@ -0,0 +1 @@
+../../../components/other/desktop/App.cpp
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/other/KT.h b/hellolist/ver-mac-x64/src/other/KT.h
new file mode 120000
index 0000000..ad7d23e
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/other/KT.h
@@ -0,0 +1 @@
+../../../components/other/desktop/KT.h
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/other/VM.cpp b/hellolist/ver-mac-x64/src/other/VM.cpp
new file mode 120000
index 0000000..8e81d58
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/other/VM.cpp
@@ -0,0 +1 @@
+../../../components/other/desktop/VM.cpp
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/other/VM.h b/hellolist/ver-mac-x64/src/other/VM.h
new file mode 120000
index 0000000..09b2b3b
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/other/VM.h
@@ -0,0 +1 @@
+../../../components/other/desktop/VM.h
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/other/view/AppView.qml b/hellolist/ver-mac-x64/src/other/view/AppView.qml
new file mode 120000
index 0000000..ed01cea
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/other/view/AppView.qml
@@ -0,0 +1 @@
+../../../../components/other/desktop/view/AppView.qml
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/root.cpp b/hellolist/ver-mac-x64/src/root/root.cpp
new file mode 120000
index 0000000..22a84c7
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/root.cpp
@@ -0,0 +1 @@
+../../../components/root/desktop/root.cpp
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/root.h b/hellolist/ver-mac-x64/src/root/root.h
new file mode 120000
index 0000000..60234aa
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/root.h
@@ -0,0 +1 @@
+../../../components/root/desktop/root.h
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/rootEffect.cpp b/hellolist/ver-mac-x64/src/root/rootEffect.cpp
new file mode 120000
index 0000000..cb7a2fe
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/rootEffect.cpp
@@ -0,0 +1 @@
+../../../components/root/desktop/rootEffect.cpp
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/rootEffect.h b/hellolist/ver-mac-x64/src/root/rootEffect.h
new file mode 120000
index 0000000..045c429
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/rootEffect.h
@@ -0,0 +1 @@
+../../../components/root/desktop/rootEffect.h
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/view/RootView.qml b/hellolist/ver-mac-x64/src/root/view/RootView.qml
new file mode 120000
index 0000000..65ef524
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/view/RootView.qml
@@ -0,0 +1 @@
+../../../../components/root/desktop/view/RootView.qml
\ No newline at end of file
diff --git a/hellolist/ver-mac-x64/src/root/view/RootViewItem.qml b/hellolist/ver-mac-x64/src/root/view/RootViewItem.qml
new file mode 120000
index 0000000..e434302
--- /dev/null
+++ b/hellolist/ver-mac-x64/src/root/view/RootViewItem.qml
@@ -0,0 +1 @@
+../../../../components/root/desktop/view/RootViewItem.qml
\ No newline at end of file
diff --git a/helloworld/components/main/android/view/MainView.kt b/helloworld/components/main/android/view/MainView.kt
index 362b5cf..2e929b6 100644
--- a/helloworld/components/main/android/view/MainView.kt
+++ b/helloworld/components/main/android/view/MainView.kt
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.*
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
@Composable
@@ -20,12 +21,12 @@ fun MainView(vm: VM) {
modifier = Modifier.fillMaxSize()
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
- Text(vm.mainGreetingText.value)
+ Text(vm.mainGreetingText.value, modifier = Modifier.testTag("greeting_text"))
Spacer(modifier = Modifier.height(10.dp))
OutlinedButton(
onClick = { mainSet(F.didClickChangeText, true) },
) {
- Text("Change text")
+ Text("Change text", modifier = Modifier.testTag("change_text_button"))
}
}
}
diff --git a/helloworld/components/main/desktop/view/MainView.qml b/helloworld/components/main/desktop/view/MainView.qml
index aad2c5c..fb61991 100644
--- a/helloworld/components/main/desktop/view/MainView.qml
+++ b/helloworld/components/main/desktop/view/MainView.qml
@@ -11,6 +11,9 @@ Rectangle {
font.pointSize: 24
text: vm.mainGreetingText
y: 30
+ Accessible.role: Accessible.StaticText
+ Accessible.name: vm.mainGreetingText
+ objectName: "greeting_text"
}
Button {
@@ -18,5 +21,8 @@ Rectangle {
onClicked: api.mainSet(F.didClickChangeText, true)
text: "Change text"
y: 100
+ Accessible.role: Accessible.Button
+ Accessible.name: "change_text_button"
+ objectName: "change_text_button"
}
}
diff --git a/helloworld/components/main/ios/mainProto.swift b/helloworld/components/main/ios/mainProto.swift
new file mode 100644
index 0000000..66b80e9
--- /dev/null
+++ b/helloworld/components/main/ios/mainProto.swift
@@ -0,0 +1,9 @@
+import hw
+
+func mainCtrl() -> KDController {
+ MainProtoKt.mainCtrl()
+}
+
+func mainSet(_ k: String, _ v: Any) {
+ MainProtoKt.mainSet(k: k, v: v)
+}
diff --git a/helloworld/components/main/ios/main_.swift b/helloworld/components/main/ios/main_.swift
new file mode 100644
index 0000000..b600016
--- /dev/null
+++ b/helloworld/components/main/ios/main_.swift
@@ -0,0 +1,19 @@
+import hw
+
+typealias MC = MainContext
+
+class MainComponent {
+ init() {
+ var vm = { VM.singleton! }
+
+ let effects: [Any] = [
+ F.greetingText, { (c: MC) in vm().greetingText = c.greetingText },
+ F.isVisible, { (c: MC) in vm().isVisible = c.isVisible },
+ ]
+ var r: MC? = registerOneliners(mainCtrl(), effects)
+ }
+
+ func setup() {
+ mainSet(F.didSetup, true)
+ }
+}
diff --git a/helloworld/components/main/ios/view/MainView.swift b/helloworld/components/main/ios/view/MainView.swift
new file mode 100644
index 0000000..5857762
--- /dev/null
+++ b/helloworld/components/main/ios/view/MainView.swift
@@ -0,0 +1,25 @@
+import SwiftUI
+
+struct MainView: View {
+ @ObservedObject var vm: VM
+
+ init(_ vm: VM) {
+ self.vm = vm
+ }
+
+ var body: some View {
+ if vm.isVisible {
+ VStack(spacing: 10) {
+ Spacer()
+ Text(vm.greetingText)
+ .accessibilityIdentifier("greeting_text")
+ Button(action: { mainSet(F.didClickChangeText, true) }) {
+ Text("Change text")
+ }
+ .accessibilityIdentifier("change_text_button")
+ .buttonStyle(.borderedProminent)
+ Spacer()
+ }
+ }
+ }
+}
diff --git a/helloworld/kd.yml b/helloworld/kd.yml
index d3aa6b6..7ec4974 100644
--- a/helloworld/kd.yml
+++ b/helloworld/kd.yml
@@ -3,6 +3,10 @@ version: 3
output:
ver-android/app/src/main/kotlin/org/opengamestudio/ignore.kd.kt:
type: kotlin
+ sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/ignore.kd.kt:
+ type: kotlin
+ ver-ios/src/ignore.kd.swift:
+ type: swift
sdk-linux-x64/hw/src/nativeMain/kotlin/org/opengamestudio/ignore.kd.kt:
type: c++sdk
ver-linux-x64/src/ignore.kd.h:
@@ -25,6 +29,7 @@ output:
c++sdk: package org.opengamestudio
c++sdk: import kotlinx.cinterop.*
kotlin: package org.opengamestudio
+swift: import hw
MainContext:
type: context
diff --git a/helloworld/sdk-ios/gradle b/helloworld/sdk-ios/gradle
new file mode 120000
index 0000000..3879155
--- /dev/null
+++ b/helloworld/sdk-ios/gradle
@@ -0,0 +1 @@
+../ver-android/gradle
\ No newline at end of file
diff --git a/helloworld/sdk-ios/gradle.properties b/helloworld/sdk-ios/gradle.properties
new file mode 120000
index 0000000..c380dbb
--- /dev/null
+++ b/helloworld/sdk-ios/gradle.properties
@@ -0,0 +1 @@
+../ver-android/gradle.properties
\ No newline at end of file
diff --git a/helloworld/sdk-ios/gradlew b/helloworld/sdk-ios/gradlew
new file mode 120000
index 0000000..ca842a7
--- /dev/null
+++ b/helloworld/sdk-ios/gradlew
@@ -0,0 +1 @@
+../ver-android/gradlew
\ No newline at end of file
diff --git a/helloworld/sdk-ios/hw/build.gradle.kts b/helloworld/sdk-ios/hw/build.gradle.kts
new file mode 100644
index 0000000..c4a640e
--- /dev/null
+++ b/helloworld/sdk-ios/hw/build.gradle.kts
@@ -0,0 +1,37 @@
+import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
+
+plugins {
+ alias(libs.plugins.kotlin.multiplatform)
+ alias(libs.plugins.android.library)
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ }
+ }
+}
+
+kotlin {
+ androidTarget {
+ }
+}
+
+android {
+ namespace = "org.opengamestudio"
+ compileSdk = 35
+}
+
+kotlin {
+ val xcf = XCFramework()
+ arrayOf(
+ iosArm64(),
+ iosSimulatorArm64(),
+ iosX64(),
+ ).forEach {
+ it.binaries.framework {
+ xcf.add(this)
+ isStatic = false
+ }
+ }
+}
diff --git a/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainProto.kt b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainProto.kt
new file mode 120000
index 0000000..2464248
--- /dev/null
+++ b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainProto.kt
@@ -0,0 +1 @@
+../../../../../../../components/main/sdk/mainProto.kt
\ No newline at end of file
diff --git a/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainShould.kt b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainShould.kt
new file mode 120000
index 0000000..10ea775
--- /dev/null
+++ b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/mainShould.kt
@@ -0,0 +1 @@
+../../../../../../../components/main/sdk/mainShould.kt
\ No newline at end of file
diff --git a/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/other.kt b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/other.kt
new file mode 120000
index 0000000..6d0c49d
--- /dev/null
+++ b/helloworld/sdk-ios/hw/src/commonMain/kotlin/org/opengamestudio/other.kt
@@ -0,0 +1 @@
+../../../../../../../components/other/sdk/other.kt
\ No newline at end of file
diff --git a/helloworld/sdk-ios/settings.gradle.kts b/helloworld/sdk-ios/settings.gradle.kts
new file mode 100644
index 0000000..1fb3827
--- /dev/null
+++ b/helloworld/sdk-ios/settings.gradle.kts
@@ -0,0 +1,23 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "sdk-ios"
+include("hw")
diff --git a/helloworld/util/build-ios b/helloworld/util/build-ios
new file mode 100755
index 0000000..c3d0997
--- /dev/null
+++ b/helloworld/util/build-ios
@@ -0,0 +1,10 @@
+#!/bin/bash -e
+SDIR=$(cd "$(dirname "$0")" ; pwd -P)
+T=$SDIR/step
+source $SDIR/other
+
+STEP=0
+source $T/cloneKD
+source $T/genKD
+source $T/buildIOSSDK
+source $T/genIOSProject
diff --git a/helloworld/util/step/buildIOSSDK b/helloworld/util/step/buildIOSSDK
new file mode 100755
index 0000000..f72034b
--- /dev/null
+++ b/helloworld/util/step/buildIOSSDK
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+STEP=$((STEP+1))
+echo -e "\n> > > > Step №$STEP. Build SDK for iOS"
+
+BUILD_DIR=$SDIR/../sdk-ios/hw/build/XCFrameworks/release
+
+cd $SDIR/../sdk-ios
+./gradlew assembleHwReleaseXCFramework
+cd $BUILD_DIR
+zip -r hw.xcframework.zip hw.xcframework
+ln -sf $BUILD_DIR/hw.xcframework.zip $SDIR/../ver-ios/app/local/hw/hw.xcframework.zip
diff --git a/helloworld/util/step/cloneKD b/helloworld/util/step/cloneKD
index 368ce8b..442b577 100644
--- a/helloworld/util/step/cloneKD
+++ b/helloworld/util/step/cloneKD
@@ -6,5 +6,6 @@ if [ ! -d "$KD_DIR" ]; then
git clone $KD_URL $KD_DIR
fi
cd $KD_DIR
-git fetch
-git checkout -f 3.1
+#git checkout -f 3.2
+git checkout -f cpparr
+git pull
diff --git a/helloworld/util/step/genIOSProject b/helloworld/util/step/genIOSProject
new file mode 100755
index 0000000..33d0c9f
--- /dev/null
+++ b/helloworld/util/step/genIOSProject
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+STEP=$((STEP+1))
+echo -e "\n> > > > Step №$STEP. Generate iOS project"
+
+cd $SDIR/../ver-ios/app
+xcodegen
diff --git a/helloworld/ver-android/gradle/libs.versions.toml b/helloworld/ver-android/gradle/libs.versions.toml
index 0954b98..02e211f 100644
--- a/helloworld/ver-android/gradle/libs.versions.toml
+++ b/helloworld/ver-android/gradle/libs.versions.toml
@@ -22,3 +22,4 @@ android-application = { id = "com.android.application", version.ref = "agp" }
android-library= { id = "com.android.library", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
+kotlin-multiplatform= { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
diff --git a/helloworld/ver-ios/app/Info.plist b/helloworld/ver-ios/app/Info.plist
new file mode 100644
index 0000000..2b31af3
--- /dev/null
+++ b/helloworld/ver-ios/app/Info.plist
@@ -0,0 +1,58 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Hello World
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ org.opengamestudio.kdexample
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIRequiresFullScreen
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/helloworld/ver-ios/app/local/hw/Package.swift b/helloworld/ver-ios/app/local/hw/Package.swift
new file mode 100644
index 0000000..0f69c31
--- /dev/null
+++ b/helloworld/ver-ios/app/local/hw/Package.swift
@@ -0,0 +1,16 @@
+// swift-tools-version: 5.9
+
+import PackageDescription
+
+let package = Package(
+ name: "hw",
+ products: [
+ .library(
+ name: "hw",
+ targets: ["hw"]
+ ),
+ ],
+ targets: [
+ .binaryTarget(name: "hw", path: "hw.xcframework.zip")
+ ]
+)
diff --git a/helloworld/ver-ios/app/local/hw/hw.xcframework.zip b/helloworld/ver-ios/app/local/hw/hw.xcframework.zip
new file mode 120000
index 0000000..aa3a983
--- /dev/null
+++ b/helloworld/ver-ios/app/local/hw/hw.xcframework.zip
@@ -0,0 +1 @@
+/Volumes/MOE/p/kotlin-dialect-example/helloworld/util/../sdk-ios/hw/build/XCFrameworks/release/hw.xcframework.zip
\ No newline at end of file
diff --git a/helloworld/ver-ios/app/project.yml b/helloworld/ver-ios/app/project.yml
new file mode 100644
index 0000000..e6856f0
--- /dev/null
+++ b/helloworld/ver-ios/app/project.yml
@@ -0,0 +1,19 @@
+name: HelloWorld
+packages:
+ hw:
+ path: local/hw
+options:
+ bundleIdPrefix: org.opengamestudio
+targets:
+ helloworld:
+ type: application
+ platform: iOS
+ deploymentTarget: "15.0"
+ dependencies:
+ - package: hw
+ sources:
+ - path: "../src"
+ settings:
+ base:
+ DEVELOPMENT_TEAM: S3NW8F382K
+ INFOPLIST_FILE: Info.plist
diff --git a/helloworld/ver-ios/src/AppDelegate.swift b/helloworld/ver-ios/src/AppDelegate.swift
new file mode 100644
index 0000000..f69a31f
--- /dev/null
+++ b/helloworld/ver-ios/src/AppDelegate.swift
@@ -0,0 +1,15 @@
+import UIKit
+
+class AppDelegate: UIResponder, UIApplicationDelegate {
+ let mainCmp = MainComponent()
+ let vm = VM()
+
+ func application(
+ _: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
+ ) -> Bool {
+ mainCmp.setup()
+
+ return true
+ }
+}
diff --git a/helloworld/ver-ios/src/AppView.swift b/helloworld/ver-ios/src/AppView.swift
new file mode 100644
index 0000000..8994b18
--- /dev/null
+++ b/helloworld/ver-ios/src/AppView.swift
@@ -0,0 +1,12 @@
+import SwiftUI
+
+@main
+struct AppView: App {
+ @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
+
+ var body: some Scene {
+ WindowGroup {
+ MainView(appDelegate.vm)
+ }
+ }
+}
diff --git a/helloworld/ver-ios/src/LaunchScreen.storyboard b/helloworld/ver-ios/src/LaunchScreen.storyboard
new file mode 100644
index 0000000..a9fa267
--- /dev/null
+++ b/helloworld/ver-ios/src/LaunchScreen.storyboard
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/helloworld/ver-ios/src/VM.swift b/helloworld/ver-ios/src/VM.swift
new file mode 100644
index 0000000..7a367ec
--- /dev/null
+++ b/helloworld/ver-ios/src/VM.swift
@@ -0,0 +1,12 @@
+import Combine
+
+class VM: ObservableObject {
+ @Published var greetingText = "TODO-Text"
+ @Published var isVisible = false
+
+ static private(set) weak var singleton: VM?
+
+ init() {
+ Self.singleton = self
+ }
+}
diff --git a/helloworld/ver-ios/src/main/mainProto.swift b/helloworld/ver-ios/src/main/mainProto.swift
new file mode 120000
index 0000000..1176b21
--- /dev/null
+++ b/helloworld/ver-ios/src/main/mainProto.swift
@@ -0,0 +1 @@
+../../../components/main/ios/mainProto.swift
\ No newline at end of file
diff --git a/helloworld/ver-ios/src/main/main_.swift b/helloworld/ver-ios/src/main/main_.swift
new file mode 120000
index 0000000..3863d3c
--- /dev/null
+++ b/helloworld/ver-ios/src/main/main_.swift
@@ -0,0 +1 @@
+../../../components/main/ios/main_.swift
\ No newline at end of file
diff --git a/helloworld/ver-ios/src/main/view/MainView.swift b/helloworld/ver-ios/src/main/view/MainView.swift
new file mode 120000
index 0000000..941d174
--- /dev/null
+++ b/helloworld/ver-ios/src/main/view/MainView.swift
@@ -0,0 +1 @@
+../../../../components/main/ios/view/MainView.swift
\ No newline at end of file
diff --git a/helloworld/ver-mac-x64/CMakeLists.txt b/helloworld/ver-mac-x64/CMakeLists.txt
index ef1042d..be1a836 100644
--- a/helloworld/ver-mac-x64/CMakeLists.txt
+++ b/helloworld/ver-mac-x64/CMakeLists.txt
@@ -12,7 +12,7 @@ find_package(
)
qt_standard_project_setup(REQUIRES 6.8)
-# Приложение
+# Application
set(
SOURCES
src/ignore.kd.cpp
diff --git a/sample_gb b/sample_gb
new file mode 120000
index 0000000..e3ee193
--- /dev/null
+++ b/sample_gb
@@ -0,0 +1 @@
+../git-budget
\ No newline at end of file