diff --git a/azure-communication-ui/chat/.gitignore b/azure-communication-ui/chat/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/azure-communication-ui/chat/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/azure-communication-ui/chat/build.gradle b/azure-communication-ui/chat/build.gradle new file mode 100644 index 000000000..f5b6146f6 --- /dev/null +++ b/azure-communication-ui/chat/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.library' + id 'org.jetbrains.kotlin.android' +} + +android { + compileSdk 31 + resourcePrefix 'azure_communication_ui_call_' + + defaultConfig { + minSdk 21 + targetSdk 31 + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation "androidx.core:core-ktx:$androidx_core_ktx_version" + implementation "androidx.appcompat:appcompat:$androidx_appcompat_version" + implementation "androidx.fragment:fragment-ktx:$androidx_fragment_ktx_version" + implementation "androidx.navigation:navigation-fragment-ktx:$androidx_navigation_fragment_ktx_version" + + testImplementation "junit:junit:$junit_version" + androidTestImplementation "androidx.test.ext:junit:$androidx_junit_version" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidx_espresso_core_version" +} \ No newline at end of file diff --git a/azure-communication-ui/chat/consumer-rules.pro b/azure-communication-ui/chat/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/azure-communication-ui/chat/proguard-rules.pro b/azure-communication-ui/chat/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/azure-communication-ui/chat/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/azure-communication-ui/chat/src/androidTest/java/com/azure/android/communication/ui/chat/ExampleInstrumentedTest.kt b/azure-communication-ui/chat/src/androidTest/java/com/azure/android/communication/ui/chat/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..3a82123d8 --- /dev/null +++ b/azure-communication-ui/chat/src/androidTest/java/com/azure/android/communication/ui/chat/ExampleInstrumentedTest.kt @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + } +} diff --git a/azure-communication-ui/chat/src/main/AndroidManifest.xml b/azure-communication-ui/chat/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a3d06108d --- /dev/null +++ b/azure-communication-ui/chat/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatComposite.java b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatComposite.java new file mode 100644 index 000000000..458e590fa --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatComposite.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat; + +public class ChatComposite { +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatCompositeException.java b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatCompositeException.java new file mode 100644 index 000000000..bee3a6356 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/ChatCompositeException.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat; + +import androidx.annotation.NonNull; + +/** + * Defines the base type of custom Exception that can be thrown by this Library. + */ +public final class ChatCompositeException extends RuntimeException { + + /** + * Constructs a new Chat Composite exception with the specified error message and cause. Note + * that the error message associated with "cause" is not automatically incorporated into this + * exception's error message. + * + * @param errorMessage - the error message. The error message can be retrieved by the + * getMessage() method + * @param cause - the cause (which is saved for later retrieval by the getCause() method). A + * null value is permitted, and indicates that the cause is non-existent or unknown. + */ + public ChatCompositeException(final String errorMessage, @NonNull final Throwable cause) { + super(errorMessage, cause); + } + /** + * Constructs a new Chat Composite exception with the specified cause and message of + * (cause==null ? null : cause.toString()) (which typically contains the class and detail message + * of cause). This constructor is useful for exceptions that are little more than wrappers for + * other throwables. + * + * @param cause - the cause (which is saved for later retrieval by the Throwable.getCause() method). + * A null value is permitted, and indicates that the cause is nonexistent or unknown. + */ + public ChatCompositeException(final Throwable cause) { + super(cause); + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/locator/ServiceLocator.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/locator/ServiceLocator.kt new file mode 100644 index 000000000..f6c405c1a --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/locator/ServiceLocator.kt @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.locator + +import java.util.HashMap + +/* Heterogeneous Service Locator +Will lazily construct objects as the graph requires. +Register TypedBuilders for each class you want +Use locate(Class clazz) to get/build the instance + Usage: + addTypedBuilder { + BasicObjectHello() + } + + addTypedBuilder { + BasicObjectWorld() + } + + addTypedBuilder { + BasicObjectHelloWorld( + locate(), + locate() + ) + } + val basicObjectHello = locate() + */ + +internal typealias TypedBuilder = () -> T + +internal class ServiceLocator { + internal interface Disposable { + fun dispose() + } + + // @PublishedApi on internal will expose the value, but obfuscate it. + // + // This has the effect of "hiding" api that must be public + // The reason for this "reified" type parameters. Reify is to "make more real/concrete" + // + // Reify only works on inline functions. inline functions can't use private member variable + // because they are "inlined" to the calling code and can't see private scope. + // + // We Reify our types, because it lets us have much nicer syntax. + // Instead of having to pass Class objects as parameters, we can get Class from + // This lets us register typed builders and locate them simple. + // + // E.g. + // ``` + // addTypedBuilder() { MyClassImpl() as MyClass } + // locate() + // ``` + @PublishedApi + internal val builders = HashMap>() + + @PublishedApi + internal val implementations = HashMap() + + // Adds a typed builder + // Note: For core services, use Constructor Injection + // This will allow us to "initializeAll" and validate the tree + + inline fun addTypedBuilder(noinline builder: TypedBuilder) { + builders[T::class.java] = builder + } + + // This resets the Service Locator to Initial + // All Implementations are cleared + // All Builders are removed + fun clear() { + for (implementation in implementations.values) { + if (implementation is Disposable) { + implementation.dispose() + } + } + builders.clear() + implementations.clear() + } + + // Locate a class + // locate locate(): T { + require(builders.containsKey(T::class.java)) { "Builder for ${T::class.java} Does not exist" } + return if (implementations.containsKey(T::class.java)) { + implementations[T::class.java] as T + } else { + val instance = builders[T::class.java]!!()!! + implementations[T::class.java] = instance + instance as T + } + } + + // Initialize the entire tree + // This will allow us to crash-fast and cache-fast + inline fun initializeAll() { + builders.keys.filter { !implementations.containsKey(it) }.forEach { + implementations[it] = builders[it]?.invoke() as Any + } + } + + companion object { + private val locatorMap = HashMap() + fun getInstance(instanceId: Int): ServiceLocator { + if (locatorMap.containsKey(instanceId)) { + return locatorMap[instanceId]!! + } + locatorMap[instanceId] = ServiceLocator() + return locatorMap[instanceId]!! + } + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/DefaultLogger.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/DefaultLogger.kt new file mode 100644 index 000000000..d5d2bf2cb --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/DefaultLogger.kt @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.logger + +import android.util.Log + +internal class DefaultLogger : Logger { + + private val tag = "communication.ui" + + override fun info(message: String) { + Log.i(tag, message) + } + + override fun debug(message: String) { + Log.d(tag, message) + } + + override fun warning(message: String) { + Log.w(tag, message) + } + + override fun error(message: String, error: Throwable?) { + Log.e(tag, message, error) + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/Logger.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/Logger.kt new file mode 100644 index 000000000..15e11fd58 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/logger/Logger.kt @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.logger + +internal interface Logger { + fun info(message: String) + fun debug(message: String) + fun warning(message: String) + fun error(message: String, error: Throwable?) +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeLocalOptions.java b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeLocalOptions.java new file mode 100644 index 000000000..a6155793a --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeLocalOptions.java @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.models; + +import com.azure.android.communication.ui.chat.ChatComposite; + +/** + * ChatCompositeLocalOptions for ChatComposite.launch. + * + *

+ * Local Options for the Chat Composite. These options are not shared with the server and impact local views only. + * E.g. The Local Participant Name if it differs from the display name you'd like to share with the server. + *

+ *
+ *
+ * // Initialize the chat composite builder
+ * final ChatCompositeBuilder builder = new ChatCompositeBuilder();
+ *
+ * // Build the chat composite
+ * ChatComposite chatComposite = builder.build();
+ *
+ * // Build the ChatCompositeLocalOptions with {@link ChatCompositeParticipantViewData}
+ * ChatCompositeLocalOptions localOptions = new ChatCompositeLocalOptions(
+ *     new ChatCompositeParticipantViewData(...));
+ *
+ * // Launch chat
+ * chatComposite.launch(.., .., localOptions)
+ * 
+ * + * @see ChatComposite + */ +public final class ChatCompositeLocalOptions { + private final ChatCompositeParticipantViewData participantViewData; + + /** + * Create Local Options. + * + * @param participantViewData The {@link ChatCompositeParticipantViewData}; + * @see ChatCompositeParticipantViewData + */ + public ChatCompositeLocalOptions(final ChatCompositeParticipantViewData participantViewData) { + this.participantViewData = participantViewData; + } + + /** + * Get {@link ChatCompositeParticipantViewData}. + * + * @return The {@link ChatCompositeParticipantViewData}; + */ + public ChatCompositeParticipantViewData getParticipantViewData() { + return participantViewData; + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeParticipantViewData.java b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeParticipantViewData.java new file mode 100644 index 000000000..577418c4c --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/models/ChatCompositeParticipantViewData.java @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.models; + +import android.graphics.Bitmap; +import android.widget.ImageView; + +import com.azure.android.communication.ui.chat.ChatComposite; + +/** + * ChatCompositeParticipantViewData for participant. + * + *
+ *
+ * // Initialize the chat composite builder
+ * final ChatCompositeBuilder builder = new ChatCompositeBuilder();
+ *
+ * // Build the chat composite
+ * ChatComposite chatComposite = builder.build();
+ *
+ * // Build the ChatCompositeLocalOptions with {@link ChatCompositeParticipantViewData}
+ * ChatCompositeLocalOptions localOptions = new ChatCompositeLocalOptions(
+ *     new ChatCompositeParticipantViewData(...));
+ *
+ * chatComposite.launch(..., ..., localOptions);
+ *
+ * 
+ * + * @see ChatCompositeLocalOptions + */ +public final class ChatCompositeParticipantViewData { + private Bitmap avatarBitmap; + private String displayName; + private ImageView.ScaleType scaleType = ImageView.ScaleType.FIT_XY; + + /** + * Set scaleType. + * + * Will not take affect if called after {@link ChatCompositeParticipantViewData} passed to {@link ChatComposite} + * + * @return The {@link ChatCompositeParticipantViewData}; + */ + public ChatCompositeParticipantViewData setScaleType(final ImageView.ScaleType scaleType) { + this.scaleType = scaleType; + return this; + } + + /** + * Get scaleType. + * + * Will not take affect if called after {@link ChatCompositeParticipantViewData} passed to {@link ChatComposite} + * + * @return The {@link ImageView.ScaleType}; + */ + public ImageView.ScaleType getScaleType() { + return scaleType; + } + + /** + * Set display name. + * + * @return The {@link ChatCompositeParticipantViewData}; + */ + public ChatCompositeParticipantViewData setDisplayName(final String displayName) { + this.displayName = displayName; + return this; + } + + /** + * Get display name. + * + * @return The {@link String}; + */ + public String getDisplayName() { + return displayName; + } + + /** + * Get avatar Bitmap. + * + * @return The {@link Bitmap}; + */ + public Bitmap getAvatarBitmap() { + return avatarBitmap; + } + + /** + * Set avatar Bitmap. + * + * Will not take affect if called after {@link ChatCompositeParticipantViewData} passed to {@link ChatComposite} + * + * @return The {@link ChatCompositeParticipantViewData}; + */ + public ChatCompositeParticipantViewData setAvatarBitmap(final Bitmap avatarBitmap) { + this.avatarBitmap = avatarBitmap; + return this; + } + +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/package-info.java b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/package-info.java new file mode 100644 index 000000000..dd7382ae8 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * Package containing the classes for chat-composite. Azure android communication chat composite. + */ +package com.azure.android.communication.ui.chat; diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/presentation/ChatCompositeActivity.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/presentation/ChatCompositeActivity.kt new file mode 100644 index 000000000..19b848ecd --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/presentation/ChatCompositeActivity.kt @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.presentation + +import androidx.appcompat.app.AppCompatActivity + +internal class ChatCompositeActivity : AppCompatActivity() diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/AppStore.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/AppStore.kt new file mode 100644 index 000000000..217ac1eb4 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/AppStore.kt @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux + +import android.os.Handler +import android.os.Looper +import com.azure.android.communication.ui.chat.ChatCompositeException +import com.azure.android.communication.ui.chat.redux.action.Action +import com.azure.android.communication.ui.chat.redux.reducer.Reducer +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext + +internal class AppStore( + initialState: S, + private val reducer: Reducer, + middlewares: MutableList>, + dispatcher: CoroutineContext, +) : Store { + // Any exceptions encountered in the reducer are rethrown to crash the app and not get silently ignored. + private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> + Handler(Looper.getMainLooper()).postAtFrontOfQueue { + throw ChatCompositeException("App store exception while reducing state", throwable) + } + // At this point (after an exception) we don't want to accept any more work. + scope.cancel() + } + private val dispatcherWithExceptionHandler = dispatcher + exceptionHandler + private val scope = CoroutineScope(dispatcher) + private val stateFlow = MutableStateFlow(initialState) + private var middlewareMap: List<(Dispatch) -> Dispatch> = + middlewares.map { m -> m.invoke(this) } + + private var middlewareDispatch = compose(middlewareMap)(::reduce) + + override fun end() { + scope.cancel() + middlewareMap = emptyList() + middlewareDispatch = compose(middlewareMap)(::reduce) + } + + override fun dispatch(action: Action) { + scope.launch(dispatcherWithExceptionHandler) { + middlewareDispatch(action) + } + } + + override fun getStateFlow(): MutableStateFlow { + return stateFlow + } + + override fun getCurrentState(): S { + return stateFlow.value + } + + private fun reduce(action: Action) { + stateFlow.value = reducer.reduce(stateFlow.value, action) + } + + private fun compose(functions: List<(Dispatch) -> Dispatch>): (Dispatch) -> Dispatch = + { dispatch -> + functions.foldRight( + dispatch + ) { nextDispatch, composed -> nextDispatch(composed) } + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/CommonTypes.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/CommonTypes.kt new file mode 100644 index 000000000..4f5b5ab56 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/CommonTypes.kt @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux + +import com.azure.android.communication.ui.chat.redux.action.Action + +internal typealias Dispatch = (Action) -> Unit +internal typealias Middleware = (store: Store) -> (next: Dispatch) -> Dispatch diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/Store.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/Store.kt new file mode 100644 index 000000000..ba2e66cb5 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/Store.kt @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux + +import com.azure.android.communication.ui.chat.redux.action.Action +import kotlinx.coroutines.flow.MutableStateFlow + +internal interface Store { + fun dispatch(action: Action) + fun getStateFlow(): MutableStateFlow + fun getCurrentState(): S + fun end() +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/action/Action.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/action/Action.kt new file mode 100644 index 000000000..b95f0623a --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/action/Action.kt @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux.action + +internal interface Action diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/middleware/ChatMiddleware.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/middleware/ChatMiddleware.kt new file mode 100644 index 000000000..4d9e1d783 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/middleware/ChatMiddleware.kt @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux.middleware + +import com.azure.android.communication.ui.chat.redux.Dispatch +import com.azure.android.communication.ui.chat.redux.Middleware +import com.azure.android.communication.ui.chat.redux.Store +import com.azure.android.communication.ui.chat.redux.state.ReduxState + +internal interface ChatMiddleware + +internal class ChatMiddlewareImpl : + Middleware, + ChatMiddleware { + override fun invoke(store: Store): (next: Dispatch) -> Dispatch { + TODO("Not yet implemented") + } +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/reducer/Reducer.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/reducer/Reducer.kt new file mode 100644 index 000000000..c7fa2b4a7 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/reducer/Reducer.kt @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux.reducer + +import com.azure.android.communication.ui.chat.redux.action.Action + +internal interface Reducer { + fun reduce(state: S, action: Action): S +} diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/state/ReduxState.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/state/ReduxState.kt new file mode 100644 index 000000000..7e3a123ee --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/redux/state/ReduxState.kt @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.redux.state + +internal interface ReduxState diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/ChatService.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/ChatService.kt new file mode 100644 index 000000000..a72169d97 --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/ChatService.kt @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.service + +internal class ChatService diff --git a/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/sdk/ChatSDKWrapper.kt b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/sdk/ChatSDKWrapper.kt new file mode 100644 index 000000000..928e511fc --- /dev/null +++ b/azure-communication-ui/chat/src/main/java/com/azure/android/communication/ui/chat/service/sdk/ChatSDKWrapper.kt @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat.service.sdk + +internal class ChatSDKWrapper diff --git a/azure-communication-ui/chat/src/test/java/com/azure/android/communication/ui/chat/ExampleUnitTest.kt b/azure-communication-ui/chat/src/test/java/com/azure/android/communication/ui/chat/ExampleUnitTest.kt new file mode 100644 index 000000000..a224ea159 --- /dev/null +++ b/azure-communication-ui/chat/src/test/java/com/azure/android/communication/ui/chat/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.android.communication.ui.chat + +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + } +} diff --git a/azure-communication-ui/settings.gradle b/azure-communication-ui/settings.gradle index 91017e4d0..75712a1d5 100644 --- a/azure-communication-ui/settings.gradle +++ b/azure-communication-ui/settings.gradle @@ -1,3 +1,3 @@ include ':calling' -include ':azure-communication-ui-demo-app' - +include ':chat' +include ':azure-communication-ui-demo-app' \ No newline at end of file