Add simple C binding for iOS and Android projects (#120)
* Dev: add simple C binding for iOS and Android projects * System: add ci script
This commit is contained in:
parent
7eea1a6178
commit
6d2d7fbf50
17
.github/workflows/chat-lib-tests.yml
vendored
Normal file
17
.github/workflows/chat-lib-tests.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: Chat Lib Tests
|
||||||
|
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Test
|
||||||
|
run: cd packages/chat;
|
||||||
|
cmake . -Bbuild;
|
||||||
|
cd build;
|
||||||
|
cmake --build .;
|
||||||
|
ctest --verbose
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -49,3 +49,9 @@ stack.yaml.lock
|
|||||||
# chat database
|
# chat database
|
||||||
*.db
|
*.db
|
||||||
*.db.bak
|
*.db.bak
|
||||||
|
packages/android/.idea
|
||||||
|
packages/chat/.idea
|
||||||
|
packages/chat/build
|
||||||
|
packages/chat/Testing
|
||||||
|
packages/ios/SimpleX Chat.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
|
packages/ios/SimpleX Chat.xcodeproj/xcuserdata
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleHome" value="/usr/local/Cellar/gradle/7.2/libexec" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
@ -41,17 +41,29 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding true
|
compose true
|
||||||
|
}
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion "1.0.4"
|
||||||
|
kotlinCompilerVersion "1.5.31"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation 'androidx.core:core-ktx:1.3.2'
|
implementation 'androidx.core:core-ktx:1.6.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'com.google.android.material:material:1.3.0'
|
implementation "androidx.compose.ui:ui:1.0.4"
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation "androidx.compose.runtime:runtime-livedata:1.0.4"
|
||||||
testImplementation 'junit:junit:4.+'
|
implementation "androidx.compose.material:material:1.0.4"
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
implementation "androidx.compose.animation:animation:1.0.4"
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
implementation "androidx.compose.animation:animation-core:1.0.4"
|
||||||
|
implementation 'androidx.activity:activity-compose:1.4.0-rc01'
|
||||||
|
|
||||||
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||||
|
implementation 'androidx.compose.ui:ui-tooling-preview:1.0.4'
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
}
|
}
|
@ -11,6 +11,7 @@
|
|||||||
android:theme="@style/Theme.SimpleXChat">
|
android:theme="@style/Theme.SimpleXChat">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -9,6 +9,10 @@ cmake_minimum_required(VERSION 3.10.2)
|
|||||||
|
|
||||||
project("app")
|
project("app")
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
|
add_subdirectory( ../../../../../chat/src build/src )
|
||||||
|
|
||||||
# Creates and names a library, sets it as either STATIC
|
# Creates and names a library, sets it as either STATIC
|
||||||
# or SHARED, and provides the relative paths to its source code.
|
# or SHARED, and provides the relative paths to its source code.
|
||||||
# You can define multiple libraries, and CMake builds them for you.
|
# You can define multiple libraries, and CMake builds them for you.
|
||||||
@ -45,4 +49,6 @@ target_link_libraries( # Specifies the target library.
|
|||||||
|
|
||||||
# Links the target library to the log library
|
# Links the target library to the log library
|
||||||
# included in the NDK.
|
# included in the NDK.
|
||||||
${log-lib})
|
${log-lib}
|
||||||
|
|
||||||
|
SimpleXChatLib)
|
@ -1,10 +1,15 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "../../../../../chat/include/protocol.h"
|
||||||
|
|
||||||
extern "C" JNIEXPORT jstring JNICALL
|
extern "C" JNIEXPORT jstring JNICALL
|
||||||
Java_chat_simplex_app_MainActivity_stringFromJNI(
|
Java_chat_simplex_app_Protocol_executeCommand(
|
||||||
JNIEnv* env,
|
JNIEnv* env,
|
||||||
jobject /* this */) {
|
jclass clazz,
|
||||||
std::string hello = "Hello from C++";
|
jstring command) {
|
||||||
return env->NewStringUTF(hello.c_str());
|
const char *utf8command = env->GetStringUTFChars(command, JNI_FALSE);
|
||||||
|
jstring result = env->NewStringUTF(executeCommand(utf8command));
|
||||||
|
env->ReleaseStringUTFChars(command, utf8command);
|
||||||
|
return result;
|
||||||
}
|
}
|
@ -1,34 +1,91 @@
|
|||||||
package chat.simplex.app
|
package chat.simplex.app
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.TextView
|
import androidx.activity.ComponentActivity
|
||||||
import chat.simplex.app.databinding.ActivityMainBinding
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Send
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment.Companion.Center
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
setContent {
|
||||||
setContentView(binding.root)
|
var history by remember { mutableStateOf(mutableListOf("Session started:")) }
|
||||||
|
var inputValue by remember { mutableStateOf("") }
|
||||||
|
var inProgress by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
// Example of a call to a native method
|
fun sendMessage() {
|
||||||
binding.sampleText.text = stringFromJNI()
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
}
|
inProgress = true
|
||||||
|
val str = Protocol.executeCommand(inputValue)
|
||||||
|
inputValue = ""
|
||||||
|
val newList = mutableListOf<String>()
|
||||||
|
newList.addAll(history)
|
||||||
|
newList.add(str)
|
||||||
|
Thread.sleep(1000); // emulate work
|
||||||
|
history = newList
|
||||||
|
inProgress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
MaterialTheme(colors = lightColors()) {
|
||||||
* A native method that is implemented by the 'app' native library,
|
Surface(color = Color.White) {
|
||||||
* which is packaged with this application.
|
Column {
|
||||||
*/
|
LazyColumn(Modifier.weight(1.0f).fillMaxWidth()) {
|
||||||
external fun stringFromJNI(): String
|
itemsIndexed(history) { index: Int, message: String ->
|
||||||
|
if (index == 0) {
|
||||||
companion object {
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
// Used to load the 'app' library on application startup.
|
}
|
||||||
init {
|
MessageView(message = message)
|
||||||
System.loadLibrary("app")
|
}
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
TextField(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
value = inputValue,
|
||||||
|
onValueChange = { inputValue = it },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = androidx.compose.ui.text.input.ImeAction.Send),
|
||||||
|
keyboardActions = KeyboardActions { sendMessage() },
|
||||||
|
singleLine = true
|
||||||
|
)
|
||||||
|
if (inProgress) {
|
||||||
|
Box(Modifier.height(56.dp).width(56.dp)) {
|
||||||
|
CircularProgressIndicator(modifier = Modifier.align(Center))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.height(56.dp),
|
||||||
|
onClick = { sendMessage() },
|
||||||
|
enabled = inputValue.isNotBlank(),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Send,
|
||||||
|
contentDescription = "Send"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package chat.simplex.app
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MessageView(message: String) {
|
||||||
|
Box(Modifier.padding(4.dp)) {
|
||||||
|
Surface(color = Color.LightGray, modifier = Modifier.clip(shape = RoundedCornerShape(8.dp))) {
|
||||||
|
Box(Modifier.padding(8.dp)) {
|
||||||
|
Text(text = message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true,
|
||||||
|
widthDp = 200,
|
||||||
|
heightDp = 50,
|
||||||
|
backgroundColor = android.graphics.Color.BLACK.toLong())
|
||||||
|
@Composable
|
||||||
|
fun DefaultMessageView() {
|
||||||
|
// A surface container using the 'background' color from the theme
|
||||||
|
Surface(color = Color.White, modifier = Modifier.padding(16.dp)) {
|
||||||
|
MessageView(message = "Hello world!")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package chat.simplex.app
|
||||||
|
|
||||||
|
class Protocol {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Used to load the 'app' library on application startup.
|
||||||
|
init {
|
||||||
|
System.loadLibrary("app")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A native method that is implemented by the 'app' native library,
|
||||||
|
* which is packaged with this application.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
external fun executeCommand(command: String): String
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.android.tools.build:gradle:7.0.2"
|
classpath "com.android.tools.build:gradle:7.0.3"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
10
packages/chat/CMakeLists.txt
Normal file
10
packages/chat/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.11) # set min version of cmake
|
||||||
|
|
||||||
|
project(SimpleXChat)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
include_directories(include)
|
||||||
|
|
||||||
|
add_subdirectory( src build/src )
|
||||||
|
add_subdirectory( test build/test )
|
17
packages/chat/include/protocol.h
Normal file
17
packages/chat/include/protocol.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Public API: Protocol.h
|
||||||
|
|
||||||
|
#ifndef protocol_h
|
||||||
|
#define protocol_h
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" { // only need to export C interface if
|
||||||
|
// used by C++ source code
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* executeCommand(const char* command);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* protocol_h */
|
10
packages/chat/src/CMakeLists.txt
Normal file
10
packages/chat/src/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10) # set min version of cmake
|
||||||
|
|
||||||
|
project(SimpleXChatLib) # create chat lib
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
# set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-header-filter=../include;-checks=*;")
|
||||||
|
|
||||||
|
include_directories ("${PROJECT_SOURCE_DIR}/../include")
|
||||||
|
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
|
||||||
|
add_library(SimpleXChatLib STATIC ${SRC_FILES})
|
@ -1,13 +0,0 @@
|
|||||||
#include "protocol.h"
|
|
||||||
|
|
||||||
extern void commandSend(Message m) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Message getMessage() {
|
|
||||||
Message m;
|
|
||||||
m.message = "123";
|
|
||||||
m.date = 1000;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
16
packages/chat/src/protocol.cpp
Normal file
16
packages/chat/src/protocol.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include "protocol.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using ::std::string;
|
||||||
|
|
||||||
|
const char* executeCommand(const char *command) {
|
||||||
|
if (command == nullptr) {
|
||||||
|
auto *output = new string("> \nFailed");
|
||||||
|
return output->c_str();
|
||||||
|
}
|
||||||
|
string cmd(command);
|
||||||
|
string result = "Successful";
|
||||||
|
auto *output = new string("> " + cmd + "\n" + result);
|
||||||
|
return output->c_str();
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
struct Message {
|
|
||||||
char* message;
|
|
||||||
long date;
|
|
||||||
}
|
|
||||||
|
|
||||||
void commandSend(Message m);
|
|
||||||
|
|
||||||
Message getMessage();
|
|
17
packages/chat/test/CMakeLists.txt
Normal file
17
packages/chat/test/CMakeLists.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.11)
|
||||||
|
project(SimpleXChatTest)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
# Specify the commit you depend on and update it regularly.
|
||||||
|
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
# Now simply link against gtest or gtest_main as needed. Eg
|
||||||
|
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
|
||||||
|
add_executable(SimpleXChatTest ${SRC_FILES})
|
||||||
|
|
||||||
|
target_link_libraries(SimpleXChatTest gtest_main SimpleXChatLib)
|
||||||
|
add_test(NAME SimpleXChatTest COMMAND SimpleXChatTest)
|
18
packages/chat/test/protocol_test.cpp
Normal file
18
packages/chat/test/protocol_test.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
#include "protocol.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(ProtocolTest, SuccessfulCommand) {
|
||||||
|
|
||||||
|
EXPECT_STREQ(executeCommand("Test1"), "> Test1\nSuccessful");
|
||||||
|
EXPECT_STREQ(executeCommand("Test2"), "> Test2\nSuccessful");
|
||||||
|
EXPECT_STREQ(executeCommand("Test3"), "> Test3\nSuccessful");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ProtocolTest, NullCommand) {
|
||||||
|
EXPECT_STREQ(executeCommand(nullptr), "> \nFailed");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
@ -14,8 +14,9 @@
|
|||||||
5CBF96BA272D9CAA0021E76D /* SimpleX_ChatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96B9272D9CAA0021E76D /* SimpleX_ChatTests.swift */; };
|
5CBF96BA272D9CAA0021E76D /* SimpleX_ChatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96B9272D9CAA0021E76D /* SimpleX_ChatTests.swift */; };
|
||||||
5CBF96C4272D9CAA0021E76D /* SimpleX_ChatUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96C3272D9CAA0021E76D /* SimpleX_ChatUITests.swift */; };
|
5CBF96C4272D9CAA0021E76D /* SimpleX_ChatUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96C3272D9CAA0021E76D /* SimpleX_ChatUITests.swift */; };
|
||||||
5CBF96C6272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96C5272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift */; };
|
5CBF96C6272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96C5272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift */; };
|
||||||
5CBF96D3272DA0520021E76D /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96D2272DA0520021E76D /* Messages.swift */; };
|
843E324A272EB3B800348BAB /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843E3249272EB3B800348BAB /* MessageView.swift */; };
|
||||||
5CBF96D9272DA0CD0021E76D /* protocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96D8272DA0CD0021E76D /* protocol.c */; };
|
843E324C272F04F100348BAB /* protocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 843E324B272F04F100348BAB /* protocol.h */; };
|
||||||
|
843E324E272F04FA00348BAB /* protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 843E324D272F04FA00348BAB /* protocol.cpp */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -46,9 +47,10 @@
|
|||||||
5CBF96BF272D9CAA0021E76D /* SimpleX ChatUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SimpleX ChatUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
5CBF96BF272D9CAA0021E76D /* SimpleX ChatUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SimpleX ChatUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
5CBF96C3272D9CAA0021E76D /* SimpleX_ChatUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleX_ChatUITests.swift; sourceTree = "<group>"; };
|
5CBF96C3272D9CAA0021E76D /* SimpleX_ChatUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleX_ChatUITests.swift; sourceTree = "<group>"; };
|
||||||
5CBF96C5272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleX_ChatUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
5CBF96C5272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleX_ChatUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||||
5CBF96D2272DA0520021E76D /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = "<group>"; };
|
843E3243272EADA200348BAB /* SimpleX Chat-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX Chat-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
5CBF96D7272DA0CD0021E76D /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protocol.h; sourceTree = "<group>"; };
|
843E3249272EB3B800348BAB /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = "<group>"; };
|
||||||
5CBF96D8272DA0CD0021E76D /* protocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = protocol.c; sourceTree = "<group>"; };
|
843E324B272F04F100348BAB /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = protocol.h; path = ../../../chat/include/protocol.h; sourceTree = "<group>"; };
|
||||||
|
843E324D272F04FA00348BAB /* protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = protocol.cpp; path = ../../../chat/src/protocol.cpp; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -83,6 +85,7 @@
|
|||||||
5CBF96B8272D9CAA0021E76D /* SimpleX ChatTests */,
|
5CBF96B8272D9CAA0021E76D /* SimpleX ChatTests */,
|
||||||
5CBF96C2272D9CAA0021E76D /* SimpleX ChatUITests */,
|
5CBF96C2272D9CAA0021E76D /* SimpleX ChatUITests */,
|
||||||
5CBF96A6272D9CA60021E76D /* Products */,
|
5CBF96A6272D9CA60021E76D /* Products */,
|
||||||
|
843E3205272EA78D00348BAB /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -101,10 +104,11 @@
|
|||||||
children = (
|
children = (
|
||||||
5CBF96A8272D9CA60021E76D /* SimpleX_ChatApp.swift */,
|
5CBF96A8272D9CA60021E76D /* SimpleX_ChatApp.swift */,
|
||||||
5CBF96AA272D9CA60021E76D /* ContentView.swift */,
|
5CBF96AA272D9CA60021E76D /* ContentView.swift */,
|
||||||
|
843E3249272EB3B800348BAB /* MessageView.swift */,
|
||||||
5CBF96AC272D9CA90021E76D /* Assets.xcassets */,
|
5CBF96AC272D9CA90021E76D /* Assets.xcassets */,
|
||||||
5CBF96AE272D9CA90021E76D /* Preview Content */,
|
5CBF96AE272D9CA90021E76D /* Preview Content */,
|
||||||
5CBF96D2272DA0520021E76D /* Messages.swift */,
|
843E3246272EAEA900348BAB /* ChatLib */,
|
||||||
5CBF96D4272DA0CD0021E76D /* chat */,
|
843E3243272EADA200348BAB /* SimpleX Chat-Bridging-Header.h */,
|
||||||
);
|
);
|
||||||
path = "SimpleX Chat";
|
path = "SimpleX Chat";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -134,39 +138,41 @@
|
|||||||
path = "SimpleX ChatUITests";
|
path = "SimpleX ChatUITests";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
5CBF96D4272DA0CD0021E76D /* chat */ = {
|
843E3205272EA78D00348BAB /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
5CBF96D5272DA0CD0021E76D /* tests */,
|
|
||||||
5CBF96D6272DA0CD0021E76D /* src */,
|
|
||||||
);
|
);
|
||||||
name = chat;
|
name = Frameworks;
|
||||||
path = ../../chat;
|
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
5CBF96D5272DA0CD0021E76D /* tests */ = {
|
843E3246272EAEA900348BAB /* ChatLib */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
843E324B272F04F100348BAB /* protocol.h */,
|
||||||
|
843E324D272F04FA00348BAB /* protocol.cpp */,
|
||||||
);
|
);
|
||||||
path = tests;
|
path = ChatLib;
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
5CBF96D6272DA0CD0021E76D /* src */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
5CBF96D7272DA0CD0021E76D /* protocol.h */,
|
|
||||||
5CBF96D8272DA0CD0021E76D /* protocol.c */,
|
|
||||||
);
|
|
||||||
path = src;
|
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
843E31EA272DA43500348BAB /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
843E324C272F04F100348BAB /* protocol.h in Headers */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
5CBF96A4272D9CA60021E76D /* SimpleX Chat */ = {
|
5CBF96A4272D9CA60021E76D /* SimpleX Chat */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 5CBF96C9272D9CAA0021E76D /* Build configuration list for PBXNativeTarget "SimpleX Chat" */;
|
buildConfigurationList = 5CBF96C9272D9CAA0021E76D /* Build configuration list for PBXNativeTarget "SimpleX Chat" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
843E31EA272DA43500348BAB /* Headers */,
|
||||||
5CBF96A1272D9CA60021E76D /* Sources */,
|
5CBF96A1272D9CA60021E76D /* Sources */,
|
||||||
5CBF96A2272D9CA60021E76D /* Frameworks */,
|
5CBF96A2272D9CA60021E76D /* Frameworks */,
|
||||||
5CBF96A3272D9CA60021E76D /* Resources */,
|
5CBF96A3272D9CA60021E76D /* Resources */,
|
||||||
@ -223,11 +229,12 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1310;
|
LastSwiftUpdateCheck = 1300;
|
||||||
LastUpgradeCheck = 1310;
|
LastUpgradeCheck = 1310;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
5CBF96A4272D9CA60021E76D = {
|
5CBF96A4272D9CA60021E76D = {
|
||||||
CreatedOnToolsVersion = 13.1;
|
CreatedOnToolsVersion = 13.1;
|
||||||
|
LastSwiftMigration = 1300;
|
||||||
};
|
};
|
||||||
5CBF96B4272D9CAA0021E76D = {
|
5CBF96B4272D9CAA0021E76D = {
|
||||||
CreatedOnToolsVersion = 13.1;
|
CreatedOnToolsVersion = 13.1;
|
||||||
@ -290,10 +297,10 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
843E324A272EB3B800348BAB /* MessageView.swift in Sources */,
|
||||||
5CBF96AB272D9CA60021E76D /* ContentView.swift in Sources */,
|
5CBF96AB272D9CA60021E76D /* ContentView.swift in Sources */,
|
||||||
5CBF96D9272DA0CD0021E76D /* protocol.c in Sources */,
|
|
||||||
5CBF96D3272DA0520021E76D /* Messages.swift in Sources */,
|
|
||||||
5CBF96A9272D9CA60021E76D /* SimpleX_ChatApp.swift in Sources */,
|
5CBF96A9272D9CA60021E76D /* SimpleX_ChatApp.swift in Sources */,
|
||||||
|
843E324E272F04FA00348BAB /* protocol.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -451,6 +458,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
||||||
@ -470,6 +478,8 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "SimpleX Chat/SimpleX Chat-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
@ -480,6 +490,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
||||||
@ -499,6 +510,7 @@
|
|||||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "SimpleX Chat/SimpleX Chat-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
};
|
};
|
||||||
|
@ -8,9 +8,56 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct ContentView: View {
|
struct ContentView: View {
|
||||||
|
@State var history: [String] = ["Start session:"]
|
||||||
|
@State var text: String = ""
|
||||||
|
@State var inProgress: Bool = false
|
||||||
|
|
||||||
|
func sendMessage() {
|
||||||
|
DispatchQueue.global().async {
|
||||||
|
let string: String = self.$text.wrappedValue
|
||||||
|
inProgress = true
|
||||||
|
text = ""
|
||||||
|
if let result = executeCommand(string),
|
||||||
|
let stringResult = String(utf8String: result) {
|
||||||
|
sleep(1) // emulate work
|
||||||
|
history += [stringResult]
|
||||||
|
}
|
||||||
|
inProgress = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text("Hello, world!")
|
VStack {
|
||||||
.padding()
|
ScrollView {
|
||||||
|
LazyVStack {
|
||||||
|
ForEach(history, id: \.self) { msg in
|
||||||
|
MessageView(message: msg, isCurrentUser: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
.frame(minWidth: 0,
|
||||||
|
maxWidth: .infinity,
|
||||||
|
minHeight: 0,
|
||||||
|
maxHeight: .infinity,
|
||||||
|
alignment: .topLeading)
|
||||||
|
HStack {
|
||||||
|
TextField("Message...", text: $text)
|
||||||
|
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||||
|
.frame(minHeight: CGFloat(30))
|
||||||
|
if (inProgress) {
|
||||||
|
ProgressView()
|
||||||
|
.frame(width: 40,
|
||||||
|
height: 20,
|
||||||
|
alignment: .center)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Button(action: sendMessage) {
|
||||||
|
Text("Send")
|
||||||
|
}.disabled(text.isEmpty)
|
||||||
|
}
|
||||||
|
}.frame(minHeight: CGFloat(30)).padding()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,3 +66,4 @@ struct ContentView_Previews: PreviewProvider {
|
|||||||
ContentView()
|
ContentView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
packages/ios/SimpleX Chat/MessageView.swift
Normal file
32
packages/ios/SimpleX Chat/MessageView.swift
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// SimpleX Chat
|
||||||
|
//
|
||||||
|
// Created by Evgeny on 30/10/2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MessageView: View {
|
||||||
|
var message: String
|
||||||
|
var isCurrentUser: Bool
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Text(message)
|
||||||
|
.padding(10)
|
||||||
|
.foregroundColor(isCurrentUser ? Color.white : Color.black)
|
||||||
|
.background(isCurrentUser ? Color.blue : Color(UIColor(red: 240/255, green: 240/255, blue: 240/255, alpha: 1.0)))
|
||||||
|
.cornerRadius(10)
|
||||||
|
.frame(minWidth: 100,
|
||||||
|
maxWidth: .infinity,
|
||||||
|
minHeight: 0,
|
||||||
|
maxHeight: .infinity,
|
||||||
|
alignment: .leading)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MessageView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
MessageView(message: "> Send message: \"Hello world!\"\nSuccessful", isCurrentUser: false)
|
||||||
|
}
|
||||||
|
}
|
5
packages/ios/SimpleX Chat/SimpleX Chat-Bridging-Header.h
Normal file
5
packages/ios/SimpleX Chat/SimpleX Chat-Bridging-Header.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "protocol.h"
|
Loading…
Reference in New Issue
Block a user