[Chat][Feature] add chat library structure (#404)
This commit is contained in:
Родитель
e51c43ec9f
Коммит
ae6fdc63af
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -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"
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.azure.android.communication.ui.chat"
|
||||
>
|
||||
|
||||
</manifest>
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<T>(Class<T> clazz) to get/build the instance
|
||||
Usage:
|
||||
addTypedBuilder {
|
||||
BasicObjectHello()
|
||||
}
|
||||
|
||||
addTypedBuilder {
|
||||
BasicObjectWorld()
|
||||
}
|
||||
|
||||
addTypedBuilder {
|
||||
BasicObjectHelloWorld(
|
||||
locate(),
|
||||
locate()
|
||||
)
|
||||
}
|
||||
val basicObjectHello = locate<BasicObjectHelloWorld>()
|
||||
*/
|
||||
|
||||
internal typealias TypedBuilder<T> = () -> 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 <T>
|
||||
// This lets us register typed builders and locate them simple.
|
||||
//
|
||||
// E.g.
|
||||
// ```
|
||||
// addTypedBuilder() { MyClassImpl() as MyClass }
|
||||
// locate<MyClass>()
|
||||
// ```
|
||||
@PublishedApi
|
||||
internal val builders = HashMap<Any, TypedBuilder<*>>()
|
||||
|
||||
@PublishedApi
|
||||
internal val implementations = HashMap<Any, Any>()
|
||||
|
||||
// Adds a typed builder
|
||||
// Note: For core services, use Constructor Injection
|
||||
// This will allow us to "initializeAll" and validate the tree
|
||||
|
||||
inline fun <reified T> addTypedBuilder(noinline builder: TypedBuilder<T>) {
|
||||
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<MyClass()
|
||||
//
|
||||
// Will initialize the class if it doesn't exist
|
||||
inline fun <reified T> 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<Int, ServiceLocator>()
|
||||
fun getInstance(instanceId: Int): ServiceLocator {
|
||||
if (locatorMap.containsKey(instanceId)) {
|
||||
return locatorMap[instanceId]!!
|
||||
}
|
||||
locatorMap[instanceId] = ServiceLocator()
|
||||
return locatorMap[instanceId]!!
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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?)
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <pre>
|
||||
*
|
||||
* // 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)
|
||||
* </pre>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* // 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);
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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()
|
|
@ -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<S>(
|
||||
initialState: S,
|
||||
private val reducer: Reducer<S>,
|
||||
middlewares: MutableList<Middleware<S>>,
|
||||
dispatcher: CoroutineContext,
|
||||
) : Store<S> {
|
||||
// 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<S> {
|
||||
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) }
|
||||
}
|
||||
}
|
|
@ -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<State> = (store: Store<State>) -> (next: Dispatch) -> Dispatch
|
|
@ -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<S> {
|
||||
fun dispatch(action: Action)
|
||||
fun getStateFlow(): MutableStateFlow<S>
|
||||
fun getCurrentState(): S
|
||||
fun end()
|
||||
}
|
|
@ -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
|
|
@ -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<ReduxState>,
|
||||
ChatMiddleware {
|
||||
override fun invoke(store: Store<ReduxState>): (next: Dispatch) -> Dispatch {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
|
@ -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<S> {
|
||||
fun reduce(state: S, action: Action): S
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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() {
|
||||
}
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
include ':calling'
|
||||
include ':azure-communication-ui-demo-app'
|
||||
|
||||
include ':chat'
|
||||
include ':azure-communication-ui-demo-app'
|
Загрузка…
Ссылка в новой задаче