diff --git a/.github/workflows/chat-lib-tests.yml b/.github/workflows/chat-lib-tests.yml new file mode 100644 index 000000000..077d53721 --- /dev/null +++ b/.github/workflows/chat-lib-tests.yml @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2d0711a4a..c7babd89f 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/packages/android/.idea/gradle.xml b/packages/android/.idea/gradle.xml deleted file mode 100644 index 939f082ff..000000000 --- a/packages/android/.idea/gradle.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/packages/android/.idea/misc.xml b/packages/android/.idea/misc.xml deleted file mode 100644 index 2a4d5b521..000000000 --- a/packages/android/.idea/misc.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/packages/android/app/build.gradle b/packages/android/app/build.gradle index 11a522ca9..c273b87fe 100644 --- a/packages/android/app/build.gradle +++ b/packages/android/app/build.gradle @@ -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' } \ No newline at end of file diff --git a/packages/android/app/src/main/AndroidManifest.xml b/packages/android/app/src/main/AndroidManifest.xml index cded1e033..db937e59c 100644 --- a/packages/android/app/src/main/AndroidManifest.xml +++ b/packages/android/app/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ android:theme="@style/Theme.SimpleXChat"> diff --git a/packages/android/app/src/main/cpp/CMakeLists.txt b/packages/android/app/src/main/cpp/CMakeLists.txt index 362916c26..7c5377e46 100644 --- a/packages/android/app/src/main/cpp/CMakeLists.txt +++ b/packages/android/app/src/main/cpp/CMakeLists.txt @@ -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}) \ No newline at end of file + ${log-lib} + + SimpleXChatLib) \ No newline at end of file diff --git a/packages/android/app/src/main/cpp/native-lib.cpp b/packages/android/app/src/main/cpp/native-lib.cpp index 4c78ae521..2546d931b 100644 --- a/packages/android/app/src/main/cpp/native-lib.cpp +++ b/packages/android/app/src/main/cpp/native-lib.cpp @@ -1,10 +1,15 @@ #include #include +#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; } \ No newline at end of file diff --git a/packages/android/app/src/main/java/chat/simplex/app/MainActivity.kt b/packages/android/app/src/main/java/chat/simplex/app/MainActivity.kt index bb4a523b4..a9a85d58e 100644 --- a/packages/android/app/src/main/java/chat/simplex/app/MainActivity.kt +++ b/packages/android/app/src/main/java/chat/simplex/app/MainActivity.kt @@ -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() + 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" + ) + } + } + } + } + } + } } } } \ No newline at end of file diff --git a/packages/android/app/src/main/java/chat/simplex/app/MessageView.kt b/packages/android/app/src/main/java/chat/simplex/app/MessageView.kt new file mode 100644 index 000000000..c578bc128 --- /dev/null +++ b/packages/android/app/src/main/java/chat/simplex/app/MessageView.kt @@ -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!") + } +} \ No newline at end of file diff --git a/packages/android/app/src/main/java/chat/simplex/app/Protocol.kt b/packages/android/app/src/main/java/chat/simplex/app/Protocol.kt new file mode 100644 index 000000000..6191ead68 --- /dev/null +++ b/packages/android/app/src/main/java/chat/simplex/app/Protocol.kt @@ -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 + } +} \ No newline at end of file diff --git a/packages/android/build.gradle b/packages/android/build.gradle index 9db2bf12c..d4efb6264 100644 --- a/packages/android/build.gradle +++ b/packages/android/build.gradle @@ -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 diff --git a/packages/chat/CMakeLists.txt b/packages/chat/CMakeLists.txt new file mode 100644 index 000000000..5022b0bec --- /dev/null +++ b/packages/chat/CMakeLists.txt @@ -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 ) \ No newline at end of file diff --git a/packages/chat/include/protocol.h b/packages/chat/include/protocol.h new file mode 100644 index 000000000..1ef9547c9 --- /dev/null +++ b/packages/chat/include/protocol.h @@ -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 */ diff --git a/packages/chat/src/CMakeLists.txt b/packages/chat/src/CMakeLists.txt new file mode 100644 index 000000000..e8aa463cd --- /dev/null +++ b/packages/chat/src/CMakeLists.txt @@ -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}) diff --git a/packages/chat/src/protocol.c b/packages/chat/src/protocol.c deleted file mode 100644 index d6c0aa46d..000000000 --- a/packages/chat/src/protocol.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "protocol.h" - -extern void commandSend(Message m) { - -} - -Message getMessage() { - Message m; - m.message = "123"; - m.date = 1000; - return m; -} - diff --git a/packages/chat/src/protocol.cpp b/packages/chat/src/protocol.cpp new file mode 100644 index 000000000..17eb1d636 --- /dev/null +++ b/packages/chat/src/protocol.cpp @@ -0,0 +1,16 @@ +#include "protocol.h" + +#include + +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(); +} \ No newline at end of file diff --git a/packages/chat/src/protocol.h b/packages/chat/src/protocol.h deleted file mode 100644 index 8fc093f82..000000000 --- a/packages/chat/src/protocol.h +++ /dev/null @@ -1,9 +0,0 @@ - -struct Message { - char* message; - long date; -} - -void commandSend(Message m); - -Message getMessage(); diff --git a/packages/chat/test/CMakeLists.txt b/packages/chat/test/CMakeLists.txt new file mode 100644 index 000000000..45768cb43 --- /dev/null +++ b/packages/chat/test/CMakeLists.txt @@ -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) diff --git a/packages/chat/test/protocol_test.cpp b/packages/chat/test/protocol_test.cpp new file mode 100644 index 000000000..6b252ce73 --- /dev/null +++ b/packages/chat/test/protocol_test.cpp @@ -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 \ No newline at end of file diff --git a/packages/ios/SimpleX Chat.xcodeproj/project.pbxproj b/packages/ios/SimpleX Chat.xcodeproj/project.pbxproj index 5676eb78c..d5c52cdaa 100644 --- a/packages/ios/SimpleX Chat.xcodeproj/project.pbxproj +++ b/packages/ios/SimpleX Chat.xcodeproj/project.pbxproj @@ -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 = ""; }; 5CBF96C5272D9CAA0021E76D /* SimpleX_ChatUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleX_ChatUITestsLaunchTests.swift; sourceTree = ""; }; - 5CBF96D2272DA0520021E76D /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = ""; }; - 5CBF96D7272DA0CD0021E76D /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protocol.h; sourceTree = ""; }; - 5CBF96D8272DA0CD0021E76D /* protocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = protocol.c; sourceTree = ""; }; + 843E3243272EADA200348BAB /* SimpleX Chat-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleX Chat-Bridging-Header.h"; sourceTree = ""; }; + 843E3249272EB3B800348BAB /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = ""; }; + 843E324B272F04F100348BAB /* protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = protocol.h; path = ../../../chat/include/protocol.h; sourceTree = ""; }; + 843E324D272F04FA00348BAB /* protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = protocol.cpp; path = ../../../chat/src/protocol.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -83,6 +85,7 @@ 5CBF96B8272D9CAA0021E76D /* SimpleX ChatTests */, 5CBF96C2272D9CAA0021E76D /* SimpleX ChatUITests */, 5CBF96A6272D9CA60021E76D /* Products */, + 843E3205272EA78D00348BAB /* Frameworks */, ); sourceTree = ""; }; @@ -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 = ""; @@ -134,39 +138,41 @@ path = "SimpleX ChatUITests"; sourceTree = ""; }; - 5CBF96D4272DA0CD0021E76D /* chat */ = { + 843E3205272EA78D00348BAB /* Frameworks */ = { isa = PBXGroup; children = ( - 5CBF96D5272DA0CD0021E76D /* tests */, - 5CBF96D6272DA0CD0021E76D /* src */, ); - name = chat; - path = ../../chat; + name = Frameworks; sourceTree = ""; }; - 5CBF96D5272DA0CD0021E76D /* tests */ = { + 843E3246272EAEA900348BAB /* ChatLib */ = { isa = PBXGroup; children = ( + 843E324B272F04F100348BAB /* protocol.h */, + 843E324D272F04FA00348BAB /* protocol.cpp */, ); - path = tests; - sourceTree = ""; - }; - 5CBF96D6272DA0CD0021E76D /* src */ = { - isa = PBXGroup; - children = ( - 5CBF96D7272DA0CD0021E76D /* protocol.h */, - 5CBF96D8272DA0CD0021E76D /* protocol.c */, - ); - path = src; + path = ChatLib; sourceTree = ""; }; /* 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"; }; diff --git a/packages/ios/SimpleX Chat/ContentView.swift b/packages/ios/SimpleX Chat/ContentView.swift index b46c92edd..d58705c55 100644 --- a/packages/ios/SimpleX Chat/ContentView.swift +++ b/packages/ios/SimpleX Chat/ContentView.swift @@ -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() } } + diff --git a/packages/ios/SimpleX Chat/MessageView.swift b/packages/ios/SimpleX Chat/MessageView.swift new file mode 100644 index 000000000..1fb38c0bb --- /dev/null +++ b/packages/ios/SimpleX Chat/MessageView.swift @@ -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) + } +} diff --git a/packages/ios/SimpleX Chat/SimpleX Chat-Bridging-Header.h b/packages/ios/SimpleX Chat/SimpleX Chat-Bridging-Header.h new file mode 100644 index 000000000..e79d01431 --- /dev/null +++ b/packages/ios/SimpleX Chat/SimpleX Chat-Bridging-Header.h @@ -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"