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
|
||||
*.db
|
||||
*.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 {
|
||||
viewBinding true
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion "1.0.4"
|
||||
kotlinCompilerVersion "1.5.31"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.3.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
testImplementation 'junit:junit:4.+'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation "androidx.compose.ui:ui:1.0.4"
|
||||
implementation "androidx.compose.runtime:runtime-livedata:1.0.4"
|
||||
implementation "androidx.compose.material:material:1.0.4"
|
||||
implementation "androidx.compose.animation:animation:1.0.4"
|
||||
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">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -9,6 +9,10 @@ cmake_minimum_required(VERSION 3.10.2)
|
||||
|
||||
project("app")
|
||||
|
||||
include_directories(include)
|
||||
|
||||
add_subdirectory( ../../../../../chat/src build/src )
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# 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
|
||||
# included in the NDK.
|
||||
${log-lib})
|
||||
${log-lib}
|
||||
|
||||
SimpleXChatLib)
|
@ -1,10 +1,15 @@
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
#include "../../../../../chat/include/protocol.h"
|
||||
|
||||
extern "C" JNIEXPORT jstring JNICALL
|
||||
Java_chat_simplex_app_MainActivity_stringFromJNI(
|
||||
Java_chat_simplex_app_Protocol_executeCommand(
|
||||
JNIEnv* env,
|
||||
jobject /* this */) {
|
||||
std::string hello = "Hello from C++";
|
||||
return env->NewStringUTF(hello.c_str());
|
||||
jclass clazz,
|
||||
jstring command) {
|
||||
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
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.widget.TextView
|
||||
import chat.simplex.app.databinding.ActivityMainBinding
|
||||
import androidx.activity.ComponentActivity
|
||||
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() {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setContent {
|
||||
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
|
||||
binding.sampleText.text = stringFromJNI()
|
||||
}
|
||||
fun sendMessage() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A native method that is implemented by the 'app' native library,
|
||||
* which is packaged with this application.
|
||||
*/
|
||||
external fun stringFromJNI(): String
|
||||
|
||||
companion object {
|
||||
// Used to load the 'app' library on application startup.
|
||||
init {
|
||||
System.loadLibrary("app")
|
||||
MaterialTheme(colors = lightColors()) {
|
||||
Surface(color = Color.White) {
|
||||
Column {
|
||||
LazyColumn(Modifier.weight(1.0f).fillMaxWidth()) {
|
||||
itemsIndexed(history) { index: Int, message: String ->
|
||||
if (index == 0) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
MessageView(message = message)
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
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"
|
||||
|
||||
// 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 */; };
|
||||
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 */; };
|
||||
5CBF96D3272DA0520021E76D /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96D2272DA0520021E76D /* Messages.swift */; };
|
||||
5CBF96D9272DA0CD0021E76D /* protocol.c in Sources */ = {isa = PBXBuildFile; fileRef = 5CBF96D8272DA0CD0021E76D /* protocol.c */; };
|
||||
843E324A272EB3B800348BAB /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843E3249272EB3B800348BAB /* MessageView.swift */; };
|
||||
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 */
|
||||
|
||||
/* 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; };
|
||||
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>"; };
|
||||
5CBF96D2272DA0520021E76D /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = "<group>"; };
|
||||
5CBF96D7272DA0CD0021E76D /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protocol.h; sourceTree = "<group>"; };
|
||||
5CBF96D8272DA0CD0021E76D /* protocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = protocol.c; sourceTree = "<group>"; };
|
||||
843E3243272EADA200348BAB /* SimpleX Chat-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX Chat-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
843E3249272EB3B800348BAB /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; 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 */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -83,6 +85,7 @@
|
||||
5CBF96B8272D9CAA0021E76D /* SimpleX ChatTests */,
|
||||
5CBF96C2272D9CAA0021E76D /* SimpleX ChatUITests */,
|
||||
5CBF96A6272D9CA60021E76D /* Products */,
|
||||
843E3205272EA78D00348BAB /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@ -101,10 +104,11 @@
|
||||
children = (
|
||||
5CBF96A8272D9CA60021E76D /* SimpleX_ChatApp.swift */,
|
||||
5CBF96AA272D9CA60021E76D /* ContentView.swift */,
|
||||
843E3249272EB3B800348BAB /* MessageView.swift */,
|
||||
5CBF96AC272D9CA90021E76D /* Assets.xcassets */,
|
||||
5CBF96AE272D9CA90021E76D /* Preview Content */,
|
||||
5CBF96D2272DA0520021E76D /* Messages.swift */,
|
||||
5CBF96D4272DA0CD0021E76D /* chat */,
|
||||
843E3246272EAEA900348BAB /* ChatLib */,
|
||||
843E3243272EADA200348BAB /* SimpleX Chat-Bridging-Header.h */,
|
||||
);
|
||||
path = "SimpleX Chat";
|
||||
sourceTree = "<group>";
|
||||
@ -134,39 +138,41 @@
|
||||
path = "SimpleX ChatUITests";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CBF96D4272DA0CD0021E76D /* chat */ = {
|
||||
843E3205272EA78D00348BAB /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CBF96D5272DA0CD0021E76D /* tests */,
|
||||
5CBF96D6272DA0CD0021E76D /* src */,
|
||||
);
|
||||
name = chat;
|
||||
path = ../../chat;
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CBF96D5272DA0CD0021E76D /* tests */ = {
|
||||
843E3246272EAEA900348BAB /* ChatLib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
843E324B272F04F100348BAB /* protocol.h */,
|
||||
843E324D272F04FA00348BAB /* protocol.cpp */,
|
||||
);
|
||||
path = tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5CBF96D6272DA0CD0021E76D /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5CBF96D7272DA0CD0021E76D /* protocol.h */,
|
||||
5CBF96D8272DA0CD0021E76D /* protocol.c */,
|
||||
);
|
||||
path = src;
|
||||
path = ChatLib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* 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 */
|
||||
5CBF96A4272D9CA60021E76D /* SimpleX Chat */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5CBF96C9272D9CAA0021E76D /* Build configuration list for PBXNativeTarget "SimpleX Chat" */;
|
||||
buildPhases = (
|
||||
843E31EA272DA43500348BAB /* Headers */,
|
||||
5CBF96A1272D9CA60021E76D /* Sources */,
|
||||
5CBF96A2272D9CA60021E76D /* Frameworks */,
|
||||
5CBF96A3272D9CA60021E76D /* Resources */,
|
||||
@ -223,11 +229,12 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1310;
|
||||
LastSwiftUpdateCheck = 1300;
|
||||
LastUpgradeCheck = 1310;
|
||||
TargetAttributes = {
|
||||
5CBF96A4272D9CA60021E76D = {
|
||||
CreatedOnToolsVersion = 13.1;
|
||||
LastSwiftMigration = 1300;
|
||||
};
|
||||
5CBF96B4272D9CAA0021E76D = {
|
||||
CreatedOnToolsVersion = 13.1;
|
||||
@ -290,10 +297,10 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
843E324A272EB3B800348BAB /* MessageView.swift in Sources */,
|
||||
5CBF96AB272D9CA60021E76D /* ContentView.swift in Sources */,
|
||||
5CBF96D9272DA0CD0021E76D /* protocol.c in Sources */,
|
||||
5CBF96D3272DA0520021E76D /* Messages.swift in Sources */,
|
||||
5CBF96A9272D9CA60021E76D /* SimpleX_ChatApp.swift in Sources */,
|
||||
843E324E272F04FA00348BAB /* protocol.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -451,6 +458,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
||||
@ -470,6 +478,8 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SimpleX Chat/SimpleX Chat-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@ -480,6 +490,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"SimpleX Chat/Preview Content\"";
|
||||
@ -499,6 +510,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.SimpleX-Chat";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "SimpleX Chat/SimpleX Chat-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
@ -8,9 +8,56 @@
|
||||
import SwiftUI
|
||||
|
||||
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 {
|
||||
Text("Hello, world!")
|
||||
.padding()
|
||||
VStack {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
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