diff --git a/demo/build.gradle b/demo/build.gradle deleted file mode 100755 index 6c0fac55..00000000 --- a/demo/build.gradle +++ /dev/null @@ -1,60 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' - -repositories { - maven { url 'https://jitpack.io' } -} - -android { - compileSdkVersion versions.compileSdkVersion - defaultConfig { - applicationId "com.tinder.scarlet" - minSdkVersion versions.minSdkVersion - targetSdkVersion versions.targetSdkVersion - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } - packagingOptions { - exclude 'META-INF/rxjava.properties' - } -} - -dependencies { - implementation project(':scarlet') - implementation project(':scarlet-websocket-okhttp') - implementation project(':scarlet-lifecycle-android') - implementation project(':scarlet-message-adapter-moshi') - implementation project(':scarlet-message-adapter-protobuf') - implementation project(':scarlet-stream-adapter-rxjava2') - implementation project(':scarlet-stream-adapter-coroutines') - - implementation libs.appCompat - implementation libs.material - implementation libs.constraintLayout - implementation libs.swipeToRefresh - implementation libs.rxJava - implementation libs.rxAndroid - implementation libs.rxKotlin - implementation libs.okHttpLoggingInterceptor - implementation libs.stetho - implementation libs.stethoOkHttp - implementation libs.timber - implementation libs.jodaTime - implementation libs.dagger - kapt libs.daggerCompiler - compileOnly libs.jsr250Annotations - implementation libs.kotlin.stdlib - implementation libs.mpAndroidChart - implementation libs.chatMessageView - implementation libs.filePicker - implementation libs.glide - - testImplementation libs.junit -} diff --git a/demo/proguard-rules.pro b/demo/proguard-rules.pro deleted file mode 100755 index 13c511fd..00000000 --- a/demo/proguard-rules.pro +++ /dev/null @@ -1,40 +0,0 @@ -# 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 - -# Glide --keep public class * implements com.bumptech.glide.module.GlideModule --keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { - **[] $VALUES; - public *; -} -# support-v7-appcompat --keep public class android.support.v7.widget.** { *; } --keep public class android.support.v7.internal.widget.** { *; } --keep public class android.support.v7.internal.view.menu.** { *; } --keep public class * extends android.support.v4.view.ActionProvider { - public (android.content.Context); -} -# support-design --dontwarn android.support.design.** --keep class android.support.design.** { *; } --keep interface android.support.design.** { *; } --keep public class android.support.design.R$* { *; } diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml deleted file mode 100755 index b6cadabd..00000000 --- a/demo/src/main/AndroidManifest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/src/main/java/com/tinder/app/echo/api/BitmapMessageAdapter.kt b/demo/src/main/java/com/tinder/app/echo/api/BitmapMessageAdapter.kt deleted file mode 100644 index bd9c43ca..00000000 --- a/demo/src/main/java/com/tinder/app/echo/api/BitmapMessageAdapter.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.api - -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import com.tinder.scarlet.Message -import com.tinder.scarlet.MessageAdapter -import java.io.ByteArrayOutputStream -import java.lang.reflect.Type - -class BitmapMessageAdapter : MessageAdapter { - override fun fromMessage(message: Message): Bitmap { - val (bytes) = message as Message.Bytes - return BitmapFactory.decodeByteArray(bytes, 0, bytes.size) - } - - override fun toMessage(data: Bitmap): Message { - val outputStream = ByteArrayOutputStream() - data.compress(Bitmap.CompressFormat.PNG, 90, outputStream) - return Message.Bytes(outputStream.toByteArray()) - } - - class Factory : MessageAdapter.Factory { - override fun create(type: Type, annotations: Array): MessageAdapter<*> { - if (type == Bitmap::class.java) { - return BitmapMessageAdapter() - } - throw IllegalArgumentException() - } - } -} diff --git a/demo/src/main/java/com/tinder/app/echo/api/EchoService.kt b/demo/src/main/java/com/tinder/app/echo/api/EchoService.kt deleted file mode 100755 index 4cc84e47..00000000 --- a/demo/src/main/java/com/tinder/app/echo/api/EchoService.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.api - -import android.graphics.Bitmap -import com.tinder.scarlet.Event -import com.tinder.scarlet.State -import com.tinder.scarlet.ws.Receive -import com.tinder.scarlet.ws.Send -import kotlinx.coroutines.flow.Flow - -interface EchoService { - @Receive - fun observeState(): Flow - - @Receive - fun observeEvent(): Flow - - @Receive - fun observeText(): Flow - - @Receive - fun observeBitmap(): Flow - - @Send - fun sendText(message: String): Boolean - - @Send - fun sendBitmap(message: Bitmap): Boolean -} diff --git a/demo/src/main/java/com/tinder/app/echo/domain/AuthStatus.kt b/demo/src/main/java/com/tinder/app/echo/domain/AuthStatus.kt deleted file mode 100644 index 2e5d8d6b..00000000 --- a/demo/src/main/java/com/tinder/app/echo/domain/AuthStatus.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.domain - -enum class AuthStatus { - LOGGED_IN, LOGGED_OUT -} diff --git a/demo/src/main/java/com/tinder/app/echo/domain/AuthStatusRepository.kt b/demo/src/main/java/com/tinder/app/echo/domain/AuthStatusRepository.kt deleted file mode 100644 index 4ec16515..00000000 --- a/demo/src/main/java/com/tinder/app/echo/domain/AuthStatusRepository.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.domain - -import com.tinder.app.echo.inject.EchoBotScope -import io.reactivex.Flowable -import io.reactivex.processors.BehaviorProcessor -import javax.inject.Inject - -@EchoBotScope -class AuthStatusRepository @Inject constructor() { - - private val authStatusProcessor = BehaviorProcessor.createDefault(AuthStatus.LOGGED_IN) - - fun getAuthStatus(): AuthStatus = authStatusProcessor.value!! - - fun observeAuthStatus(): Flowable = authStatusProcessor - - fun updateAuthStatus(authStatus: AuthStatus) = authStatusProcessor.onNext(authStatus) -} diff --git a/demo/src/main/java/com/tinder/app/echo/domain/ChatMessage.kt b/demo/src/main/java/com/tinder/app/echo/domain/ChatMessage.kt deleted file mode 100644 index 828a616d..00000000 --- a/demo/src/main/java/com/tinder/app/echo/domain/ChatMessage.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.domain - -import android.graphics.Bitmap -import org.joda.time.DateTime - -sealed class ChatMessage { - abstract val id: Int - abstract val source: Source - abstract val timestamp: DateTime - - data class Text( - override val id: Int, - val value: String, - override val source: Source, - override val timestamp: DateTime = DateTime.now() - ) : ChatMessage() - - data class Image( - override val id: Int, - val bitmap: Bitmap, - override val source: Source, - override val timestamp: DateTime = DateTime.now() - ) : ChatMessage() - - enum class Source { - SENT, RECEIVED - } -} diff --git a/demo/src/main/java/com/tinder/app/echo/domain/ChatMessageRepository.kt b/demo/src/main/java/com/tinder/app/echo/domain/ChatMessageRepository.kt deleted file mode 100644 index e8e2a321..00000000 --- a/demo/src/main/java/com/tinder/app/echo/domain/ChatMessageRepository.kt +++ /dev/null @@ -1,126 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.domain - -import android.graphics.Bitmap -import com.tinder.app.echo.api.EchoService -import com.tinder.app.echo.inject.EchoBotScope -import com.tinder.scarlet.Event -import com.tinder.scarlet.Lifecycle -import com.tinder.scarlet.State -import com.tinder.scarlet.WebSocket -import io.reactivex.Flowable -import io.reactivex.processors.BehaviorProcessor -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import org.joda.time.DateTime -import timber.log.Timber -import java.util.concurrent.atomic.AtomicInteger -import java.util.concurrent.atomic.AtomicReference -import javax.inject.Inject - -@EchoBotScope -class ChatMessageRepository @Inject constructor( - private val echoService: EchoService, - private val coroutineScope: CoroutineScope -) { - private val messageCount = AtomicInteger() - private val messagesRef = AtomicReference>() - private val messagesProcessor = BehaviorProcessor.create>() - - init { - echoService.observeEvent() - .onEach { event -> - val description = when (event) { - is Event.OnLifecycle.StateChange<*> -> when (event.state) { - Lifecycle.State.Started -> "\uD83C\uDF1D On Lifecycle Start" - is Lifecycle.State.Stopped -> "\uD83C\uDF1A On Lifecycle Stop" - Lifecycle.State.Destroyed -> "\uD83D\uDCA5 On Lifecycle Terminate" - } - Event.OnLifecycle.Terminate -> "\uD83D\uDCA5 On Lifecycle Terminate" - is Event.OnWebSocket.Event<*> -> when (event.event) { - is WebSocket.Event.OnConnectionOpened<*> -> "\uD83D\uDEF0️ On WebSocket Connection Opened" - is WebSocket.Event.OnMessageReceived -> "\uD83D\uDEF0️ On WebSocket Message Received" - is WebSocket.Event.OnConnectionClosing -> "\uD83D\uDEF0️ On WebSocket Connection Closing" - is WebSocket.Event.OnConnectionClosed -> "\uD83D\uDEF0️ On WebSocket Connection Closed" - is WebSocket.Event.OnConnectionFailed -> "\uD83D\uDEF0️ On WebSocket Connection Failed" - } - Event.OnWebSocket.Terminate -> "\uD83D\uDEF0️ On WebSocket Terminate" - is Event.OnStateChange<*> -> when (event.state) { - is State.WaitingToRetry -> "\uD83D\uDCA4 WaitingToRetry" - is State.Connecting -> "⏳ Connecting" - is State.Connected -> "\uD83D\uDEEB Connected" - State.Disconnecting -> "⏳ Disconnecting" - State.Disconnected -> "\uD83D\uDEEC Disconnected" - State.Destroyed -> "\uD83D\uDCA5 Destroyed" - } - Event.OnRetry -> "⏰ On Retry" - } - val chatMessage = - ChatMessage.Text(generateMessageId(), description, ChatMessage.Source.RECEIVED) - addChatMessage(chatMessage) - }.catch { e -> - Timber.e(e) - }.launchIn(coroutineScope) - - echoService.observeText() - .onEach { text -> - val chatMessage = ChatMessage.Text( - generateMessageId(), - text, - ChatMessage.Source.RECEIVED, - DateTime.now().plusMillis(50) - ) - addChatMessage(chatMessage) - }.catch { e -> - Timber.e(e) - }.launchIn(coroutineScope) - - echoService.observeBitmap() - .onEach { bitmap -> - val chatMessage = ChatMessage.Image( - generateMessageId(), - bitmap, - ChatMessage.Source.RECEIVED, - DateTime.now().plusMillis(50) - ) - addChatMessage(chatMessage) - }.catch { e -> - Timber.e(e) - }.launchIn(coroutineScope) - } - - fun observeChatMessage(): Flowable> = messagesProcessor - - fun addTextMessage(text: String) { - val chatMessage = ChatMessage.Text(generateMessageId(), text, ChatMessage.Source.SENT) - addChatMessage(chatMessage) - - echoService.sendText(text) - } - - fun addImageMessage(bitmap: Bitmap) { - val chatMessage = ChatMessage.Image(generateMessageId(), bitmap, ChatMessage.Source.SENT) - addChatMessage(chatMessage) - - echoService.sendBitmap(bitmap) - } - - fun clearAllMessages() { - messagesRef.set(listOf()) - messagesProcessor.onNext(listOf()) - } - - private fun addChatMessage(chatMessage: ChatMessage) { - val existingMessages = messagesRef.get() ?: listOf() - val messages = existingMessages + chatMessage - messagesRef.set(messages) - messagesProcessor.onNext(messages) - } - - private fun generateMessageId(): Int = messageCount.getAndIncrement() -} diff --git a/demo/src/main/java/com/tinder/app/echo/domain/LoggedInLifecycle.kt b/demo/src/main/java/com/tinder/app/echo/domain/LoggedInLifecycle.kt deleted file mode 100644 index 4e26c82c..00000000 --- a/demo/src/main/java/com/tinder/app/echo/domain/LoggedInLifecycle.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.domain - -import com.tinder.app.echo.inject.EchoBotScope -import com.tinder.scarlet.Lifecycle -import com.tinder.scarlet.lifecycle.LifecycleRegistry -import javax.inject.Inject - -@EchoBotScope -class LoggedInLifecycle constructor( - authStatusRepository: AuthStatusRepository, - private val lifecycleRegistry: LifecycleRegistry -) : Lifecycle by lifecycleRegistry { - - @Inject constructor(authStatusRepository: AuthStatusRepository) : this(authStatusRepository, LifecycleRegistry()) - - init { - authStatusRepository.observeAuthStatus() - .map { - when (it) { - AuthStatus.LOGGED_IN -> Lifecycle.State.Started - AuthStatus.LOGGED_OUT -> Lifecycle.State.Stopped.WithReason() - } - } - .subscribe(lifecycleRegistry) - } -} diff --git a/demo/src/main/java/com/tinder/app/echo/inject/EchoBotComponent.kt b/demo/src/main/java/com/tinder/app/echo/inject/EchoBotComponent.kt deleted file mode 100644 index 20401357..00000000 --- a/demo/src/main/java/com/tinder/app/echo/inject/EchoBotComponent.kt +++ /dev/null @@ -1,80 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.inject - -import android.app.Application -import com.tinder.app.echo.api.BitmapMessageAdapter -import com.tinder.app.echo.api.EchoService -import com.tinder.app.echo.domain.LoggedInLifecycle -import com.tinder.app.echo.view.EchoBotFragment -import com.tinder.scarlet.Lifecycle -import com.tinder.scarlet.Scarlet -import com.tinder.scarlet.lifecycle.android.AndroidLifecycle -import com.tinder.scarlet.streamadapter.rxjava2.RxJava2StreamAdapterFactory -import com.tinder.scarlet.websocket.okhttp.newWebSocketFactory -import com.tinder.streamadapter.coroutines.CoroutinesStreamAdapterFactory -import dagger.Component -import dagger.Module -import dagger.Provides -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor - -@EchoBotScope -@Component(modules = [(EchoBotComponent.EchoBotModule::class)], dependencies = [(EchoBotComponent.Dependency::class)]) -interface EchoBotComponent { - - fun inject(echoBotFragment: EchoBotFragment) - - interface Dependency { - fun application(): Application - } - - @Component.Builder - interface Builder { - fun dependency(dependency: Dependency): Builder - - fun build(): EchoBotComponent - } - - @Module - class EchoBotModule { - @Provides - @EchoBotScope - fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() - .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)) - .build() - - @Provides - @EchoBotScope - fun provideLifecycle(application: Application, loggedInLifecycle: LoggedInLifecycle): Lifecycle = - AndroidLifecycle.ofApplicationForeground(application) - .combineWith(loggedInLifecycle) - - @Provides - @EchoBotScope - fun provideEchoService(client: OkHttpClient, lifecycle: Lifecycle): EchoService { - val scarlet = Scarlet.Builder() - .webSocketFactory(client.newWebSocketFactory("wss://demos.kaazing.com/echo")) - .lifecycle(lifecycle) - .addMessageAdapterFactory(BitmapMessageAdapter.Factory()) - .addStreamAdapterFactory(RxJava2StreamAdapterFactory()) - .addStreamAdapterFactory(CoroutinesStreamAdapterFactory()) - .build() - return scarlet.create() - } - - @Provides - @EchoBotScope - fun provideCoroutineScopeToRunIn(): CoroutineScope { - return CoroutineScope(SupervisorJob()) - } - } - - interface ComponentProvider { - val echoBotComponent: EchoBotComponent - } -} diff --git a/demo/src/main/java/com/tinder/app/echo/inject/EchoBotScope.kt b/demo/src/main/java/com/tinder/app/echo/inject/EchoBotScope.kt deleted file mode 100644 index cfe38d51..00000000 --- a/demo/src/main/java/com/tinder/app/echo/inject/EchoBotScope.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.inject - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class EchoBotScope diff --git a/demo/src/main/java/com/tinder/app/echo/presenter/EchoBotPresenter.kt b/demo/src/main/java/com/tinder/app/echo/presenter/EchoBotPresenter.kt deleted file mode 100755 index 80a33290..00000000 --- a/demo/src/main/java/com/tinder/app/echo/presenter/EchoBotPresenter.kt +++ /dev/null @@ -1,121 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.presenter - -import android.graphics.BitmapFactory -import android.media.ThumbnailUtils -import com.tinder.app.echo.domain.AuthStatus -import com.tinder.app.echo.domain.AuthStatusRepository -import com.tinder.app.echo.domain.ChatMessageRepository -import com.tinder.app.echo.target.EchoBotTarget -import io.reactivex.Completable -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject - -class EchoBotPresenter @Inject constructor( - private val chatMessageRepository: ChatMessageRepository, - private val authStatusRepository: AuthStatusRepository -) { - - private var targetState: TargetState = TargetState.MightBeBehind(0) - private lateinit var target: EchoBotTarget - - private val compositeDisposable = CompositeDisposable() - - fun takeTarget(target: EchoBotTarget, displayingMessageCount: Int) { - this.target = target - this.targetState = TargetState.MightBeBehind(displayingMessageCount) - setup() - } - - fun dropTarget() { - compositeDisposable.clear() - } - - private fun setup() { - val chatMessageSubscription = chatMessageRepository.observeChatMessage() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ chatMessages -> - val targetState = targetState - when (targetState) { - is TargetState.MightBeBehind -> { - if (targetState.messageCount == 0) { - target.setMessages(chatMessages) - } else { - for (i in targetState.messageCount until chatMessages.size) { - target.addMessage(chatMessages[i]) - } - } - this.targetState = TargetState.UpToDate - } - TargetState.UpToDate -> { - if (chatMessages.isEmpty()) { - target.clearAllMessages() - } else { - target.addMessage(chatMessages.last()) - } - } - } - }, { e -> - Timber.e(e) - }) - - val authStatusSubscription = authStatusRepository.observeAuthStatus() - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - @Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA") - when (it) { - AuthStatus.LOGGED_IN -> target.showLoggedIn() - AuthStatus.LOGGED_OUT -> target.showLoggedOut() - } - }, { e -> - Timber.e(e) - }) - - compositeDisposable.addAll(chatMessageSubscription, authStatusSubscription) - } - - fun sendText(text: String) { - Completable.fromAction { chatMessageRepository.addTextMessage(text) } - .subscribeOn(Schedulers.computation()) - .subscribe() - } - - fun sendImage(imagePath: String) { - Completable.fromAction { - val bitmap = BitmapFactory.decodeFile(imagePath) - val ratio = IMAGE_MAX_WIDTH.toFloat() / Math.max(bitmap.width, bitmap.height) - val (targetWidth, targetHeight) = (bitmap.width * ratio).toInt() to (bitmap.height * ratio).toInt() - val thumbnail = ThumbnailUtils.extractThumbnail(bitmap, targetWidth, targetHeight) - chatMessageRepository.addImageMessage(thumbnail) - } - .subscribeOn(Schedulers.computation()) - .subscribe() - } - - fun clearAllMessages() { - chatMessageRepository.clearAllMessages() - } - - fun toggleAuthStatus() { - val newAuthStatus = when (authStatusRepository.getAuthStatus()) { - AuthStatus.LOGGED_IN -> AuthStatus.LOGGED_OUT - AuthStatus.LOGGED_OUT -> AuthStatus.LOGGED_IN - } - authStatusRepository.updateAuthStatus(newAuthStatus) - } - - sealed class TargetState { - data class MightBeBehind(val messageCount: Int) : TargetState() - object UpToDate : TargetState() - } - - private companion object { - private const val IMAGE_MAX_WIDTH = 200 - } -} diff --git a/demo/src/main/java/com/tinder/app/echo/target/EchoBotTarget.kt b/demo/src/main/java/com/tinder/app/echo/target/EchoBotTarget.kt deleted file mode 100755 index 25372695..00000000 --- a/demo/src/main/java/com/tinder/app/echo/target/EchoBotTarget.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.target - -import com.tinder.app.echo.domain.ChatMessage - -interface EchoBotTarget { - fun setMessages(chatMessages: List) - - fun addMessage(chatMessage: ChatMessage) - - fun clearAllMessages() - - fun showLoggedIn() - - fun showLoggedOut() -} diff --git a/demo/src/main/java/com/tinder/app/echo/view/EchoBotFragment.kt b/demo/src/main/java/com/tinder/app/echo/view/EchoBotFragment.kt deleted file mode 100755 index 3cb43438..00000000 --- a/demo/src/main/java/com/tinder/app/echo/view/EchoBotFragment.kt +++ /dev/null @@ -1,199 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.echo.view - -import android.app.Activity -import android.content.Intent -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Color -import android.os.Bundle -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.github.bassaer.chatmessageview.model.ChatUser -import com.github.bassaer.chatmessageview.model.Message -import com.github.bassaer.chatmessageview.view.ChatView -import com.tinder.R -import com.tinder.app.echo.domain.ChatMessage -import com.tinder.app.echo.inject.EchoBotComponent -import com.tinder.app.echo.presenter.EchoBotPresenter -import com.tinder.app.echo.target.EchoBotTarget -import droidninja.filepicker.FilePickerBuilder -import droidninja.filepicker.FilePickerConst -import java.util.Locale -import javax.inject.Inject - -class EchoBotFragment : Fragment(), EchoBotTarget { - - @Inject - lateinit var presenter: EchoBotPresenter - private lateinit var chatView: ChatView - private var menu: Menu? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - (context!!.applicationContext as EchoBotComponent.ComponentProvider).echoBotComponent - .inject(this) - - val view = inflater.inflate(R.layout.fragment_echo_bot, container, false) as View - - chatView = view.findViewById(R.id.chat_view) - with(chatView) { - setOnClickSendButtonListener(View.OnClickListener { sendMessage() }) - setOnClickOptionButtonListener(View.OnClickListener { showImagePicker() }) - setOnIconClickListener(object : Message.OnIconClickListener { - override fun onIconClick(message: Message) { - } - }) - setOnIconLongClickListener(object : Message.OnIconLongClickListener { - override fun onIconLongClick(message: Message) { - } - }) - setOnBubbleClickListener(object : Message.OnBubbleClickListener { - override fun onClick(message: Message) { - } - }) - setOnBubbleLongClickListener(object : Message.OnBubbleLongClickListener { - override fun onLongClick(message: Message) { - } - }) - } - - return view - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - with(menu) { - val authMenuItem = add(Menu.NONE, AUTH_MENU_ITEM_ID, Menu.NONE, LOGOUT_MENU_ITEM_TITLE) - authMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - - val clearAllMenuItem = add(Menu.NONE, CLEAR_ALL_MENU_ITEM_ID, Menu.NONE, CLEAR_ALL_MENU_ITEM_TITLE) - clearAllMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - } - this.menu = menu - super.onCreateOptionsMenu(menu, inflater) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - AUTH_MENU_ITEM_ID -> presenter.toggleAuthStatus() - CLEAR_ALL_MENU_ITEM_ID -> presenter.clearAllMessages() - } - return super.onOptionsItemSelected(item) - } - - override fun onResume() { - super.onResume() - presenter.takeTarget(this, chatView.getMessageView().messageList.size) - } - - override fun onPause() { - super.onPause() - presenter.dropTarget() - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - FilePickerConst.REQUEST_CODE_PHOTO -> { - if (resultCode != Activity.RESULT_OK || data == null) { - return - } - val photoPaths = mutableListOf() - photoPaths.addAll( - requireNotNull(data.getStringArrayListExtra(FilePickerConst.KEY_SELECTED_MEDIA)) - ) - if (photoPaths.isEmpty()) { - return - } - presenter.sendImage(photoPaths[0]) - } - } - } - - override fun addMessage(chatMessage: ChatMessage) { - val message = chatMessage.toMessage() - with(chatView) { - when (chatMessage.source) { - ChatMessage.Source.SENT -> send(message) - ChatMessage.Source.RECEIVED -> receive(message) - } - } - } - - override fun setMessages(chatMessages: List) { - chatView.getMessageView().init(chatMessages.map { it.toMessage() }) - } - - override fun clearAllMessages() { - chatView.getMessageView().removeAll() - } - - override fun showLoggedIn() { - val menu = menu ?: return - val menuItem = menu.findItem(AUTH_MENU_ITEM_ID) - menuItem.title = LOGOUT_MENU_ITEM_TITLE - } - - override fun showLoggedOut() { - val menu = menu ?: return - val menuItem = menu.findItem(AUTH_MENU_ITEM_ID) - menuItem.title = LOGIN_MENU_ITEM_TITLE - } - - private fun sendMessage() { - presenter.sendText(chatView.inputText) - chatView.inputText = "" - } - - private fun showImagePicker() { - FilePickerBuilder.instance.setMaxCount(1) - .setActivityTheme(R.style.AppTheme) - .pickPhoto(this) - } - - companion object { - private const val AUTH_MENU_ITEM_ID = 200 - private const val LOGIN_MENU_ITEM_TITLE = "Log in" - private const val LOGOUT_MENU_ITEM_TITLE = "Log out" - private const val CLEAR_ALL_MENU_ITEM_ID = 201 - private const val CLEAR_ALL_MENU_ITEM_TITLE = "Clear All" - - private val AVATAR = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888) - .apply { - val canvas = Canvas(this) - canvas.drawColor(Color.rgb(255, 36, 0)) - } - - private val DEMO_USER = ChatUser(0, "Me", AVATAR) - private val SCARLET_USER = ChatUser(1, "Scarlet", AVATAR) - - private fun ChatMessage.toMessage(): Message = Message.Builder() - .setSendTime(timestamp.toCalendar(Locale.getDefault())) - .apply { - when (this@toMessage) { - is ChatMessage.Text -> setText(value) - is ChatMessage.Image -> setPicture(bitmap) - .setType(Message.Type.PICTURE) - } - when (source) { - ChatMessage.Source.SENT -> setUser(DEMO_USER) - .setRight(true) - .hideIcon(true) - ChatMessage.Source.RECEIVED -> setUser(SCARLET_USER) - .setRight(false) - } - } - .build() - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/api/GdaxService.kt b/demo/src/main/java/com/tinder/app/gdax/api/GdaxService.kt deleted file mode 100644 index 598da288..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/api/GdaxService.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.api - -import com.tinder.app.gdax.api.model.Subscribe -import com.tinder.app.gdax.api.model.Ticker -import com.tinder.scarlet.WebSocket -import com.tinder.scarlet.ws.Receive -import com.tinder.scarlet.ws.Send -import io.reactivex.Flowable - -interface GdaxService { - @Receive - fun observeWebSocketEvent(): Flowable - - @Send - fun sendSubscribe(subscribe: Subscribe) - - @Receive - fun observeTicker(): Flowable -} diff --git a/demo/src/main/java/com/tinder/app/gdax/api/MoshiAdapters.kt b/demo/src/main/java/com/tinder/app/gdax/api/MoshiAdapters.kt deleted file mode 100644 index 530aa330..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/api/MoshiAdapters.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.api - -import com.squareup.moshi.FromJson -import com.squareup.moshi.ToJson -import com.tinder.app.gdax.api.model.ProductId -import com.tinder.app.gdax.api.model.Subscribe - -class MoshiAdapters { - - @FromJson - fun productIdFromJson(string: String): ProductId { - return ProductId.values().find { it.text == string }!! - } - - @ToJson - fun productIdToJson(data: ProductId): String { - return data.text - } - - @FromJson - fun subscribeTypeFromJson(string: String): Subscribe.Type { - return Subscribe.Type.values().find { it.text == string }!! - } - - @ToJson - fun subscribeTypeToJson(data: Subscribe.Type): String { - return data.text - } - - @FromJson - fun subscribeChannelFromJson(string: String): Subscribe.Channel { - return Subscribe.Channel.values().find { it.text == string }!! - } - - @ToJson - fun subscribeChanneloJson(data: Subscribe.Channel): String { - return data.text - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/api/model/ProductId.kt b/demo/src/main/java/com/tinder/app/gdax/api/model/ProductId.kt deleted file mode 100644 index a56cce29..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/api/model/ProductId.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.api.model - -enum class ProductId(val text: String) { - BTC_USD("BTC-USD"), - ETH_USD("ETH-USD"), - LTC_USD("LTC-USD") -} diff --git a/demo/src/main/java/com/tinder/app/gdax/api/model/Subscribe.kt b/demo/src/main/java/com/tinder/app/gdax/api/model/Subscribe.kt deleted file mode 100644 index df872131..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/api/model/Subscribe.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.api.model - -import com.squareup.moshi.Json - -data class Subscribe( - val type: Type, - @Json(name = "product_ids") - val productIds: List, - val channels: List -) { - enum class Type(val text: String) { - SUBSCRIBE("subscribe"), - UNSUBSCRIBE("unsubscribe") - } - - enum class Channel(val text: String) { - TICKER("ticker"), - LEVEL2("level2"), - HEARTBEAT("heartbeat") - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/api/model/Ticker.kt b/demo/src/main/java/com/tinder/app/gdax/api/model/Ticker.kt deleted file mode 100644 index d30f313c..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/api/model/Ticker.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.api.model - -import com.squareup.moshi.Json - -data class Ticker( - val type: String, - @Json(name = "product_id") - val product: ProductId, - val sequence: Long, - val time: String, - val price: String, - val side: String, - @Json(name = "last_size") - val size: String, - @Json(name = "best_bid") - val bestBid: String, - @Json(name = "best_ask") - val bestAsk: String -) diff --git a/demo/src/main/java/com/tinder/app/gdax/domain/Product.kt b/demo/src/main/java/com/tinder/app/gdax/domain/Product.kt deleted file mode 100644 index dfadc6d5..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/domain/Product.kt +++ /dev/null @@ -1,9 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.domain - -enum class Product { - BTC, ETH, LTC -} diff --git a/demo/src/main/java/com/tinder/app/gdax/domain/Transaction.kt b/demo/src/main/java/com/tinder/app/gdax/domain/Transaction.kt deleted file mode 100644 index 78e909d4..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/domain/Transaction.kt +++ /dev/null @@ -1,12 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.domain - -import org.joda.time.DateTime - -data class Transaction( - val price: Float, - val timestamp: DateTime -) diff --git a/demo/src/main/java/com/tinder/app/gdax/domain/TransactionBook.kt b/demo/src/main/java/com/tinder/app/gdax/domain/TransactionBook.kt deleted file mode 100644 index 853707f7..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/domain/TransactionBook.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.domain - -class TransactionBook( - transactions: Map> = emptyMap() -) { - private val transactions = transactions.toMutableMap() - - fun getTransactions(product: Product): List = transactions[product] ?: emptyList() - - fun addingTransaction(product: Product, transaction: Transaction): TransactionBook { - val newHistory = TransactionBook(transactions) - newHistory.transactions[product] = (newHistory.transactions[product] ?: emptyList()) + transaction - return newHistory - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/domain/TransactionRepository.kt b/demo/src/main/java/com/tinder/app/gdax/domain/TransactionRepository.kt deleted file mode 100644 index ef125afc..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/domain/TransactionRepository.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.domain - -import com.tinder.app.gdax.api.GdaxService -import com.tinder.app.gdax.api.model.ProductId -import com.tinder.app.gdax.api.model.Subscribe -import com.tinder.app.gdax.inject.GdaxScope -import com.tinder.scarlet.WebSocket -import io.reactivex.Flowable -import io.reactivex.processors.BehaviorProcessor -import org.joda.time.format.ISODateTimeFormat -import timber.log.Timber -import java.util.concurrent.atomic.AtomicReference -import javax.inject.Inject - -@GdaxScope -class TransactionRepository @Inject constructor( - private val gdaxService: GdaxService -) { - - private val transactionBookRef = AtomicReference(TransactionBook()) - private val transactionBookProcessor = BehaviorProcessor.create() - - init { - gdaxService.observeWebSocketEvent() - .filter { it is WebSocket.Event.OnConnectionOpened<*> } - .subscribe({ - val subscribe = Subscribe( - type = Subscribe.Type.SUBSCRIBE, - productIds = listOf(ProductId.BTC_USD, ProductId.ETH_USD, ProductId.LTC_USD), - channels = listOf(Subscribe.Channel.TICKER) - ) - - gdaxService.sendSubscribe(subscribe) - }, { e -> - Timber.e(e) - }) - - gdaxService.observeTicker() - .filter { it.type == "ticker" } - .map { ticker -> - val product = when (ticker.product) { - ProductId.BTC_USD -> Product.BTC - ProductId.ETH_USD -> Product.ETH - ProductId.LTC_USD -> Product.LTC - } - val price = ticker.price.toFloat() - val time = ISODateTimeFormat.dateTime().parseDateTime(ticker.time) - product to Transaction(price, time) - } - .subscribe({ (product, transaction) -> - addTransaction(product, transaction) - }, { e -> - Timber.e(e) - }) - } - - fun observeTransactionBook(): Flowable { - return transactionBookProcessor - } - - private fun addTransaction(product: Product, transaction: Transaction) { - val transactionBook = transactionBookRef.get() - .addingTransaction(product, transaction) - transactionBookRef.set(transactionBook) - transactionBookProcessor.onNext(transactionBook) - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/inject/GdaxComponent.kt b/demo/src/main/java/com/tinder/app/gdax/inject/GdaxComponent.kt deleted file mode 100644 index ba670eea..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/inject/GdaxComponent.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.inject - -import android.app.Application -import com.squareup.moshi.KotlinJsonAdapterFactory -import com.squareup.moshi.Moshi -import com.tinder.app.gdax.api.GdaxService -import com.tinder.app.gdax.api.MoshiAdapters -import com.tinder.app.gdax.view.GdaxFragment -import com.tinder.scarlet.Lifecycle -import com.tinder.scarlet.Scarlet -import com.tinder.scarlet.lifecycle.android.AndroidLifecycle -import com.tinder.scarlet.messageadapter.moshi.MoshiMessageAdapter -import com.tinder.scarlet.streamadapter.rxjava2.RxJava2StreamAdapterFactory -import com.tinder.scarlet.websocket.okhttp.newWebSocketFactory -import dagger.Component -import dagger.Module -import dagger.Provides -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor - -@GdaxScope -@Component(modules = [(GdaxComponent.GdaxModule::class)], dependencies = [(GdaxComponent.Dependency::class)]) -interface GdaxComponent { - - fun inject(gdaxFragment: GdaxFragment) - - interface Dependency { - fun application(): Application - } - - @Component.Builder - interface Builder { - fun dependency(dependency: Dependency): Builder - - fun build(): GdaxComponent - } - - @Module - class GdaxModule { - @Provides - @GdaxScope - fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder() - .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) - .build() - - @Provides - @GdaxScope - fun provideLifecycle(application: Application): Lifecycle { - return AndroidLifecycle.ofApplicationForeground(application) - } - - @Provides - @GdaxScope - fun provideGdaxService(client: OkHttpClient, lifecycle: Lifecycle): GdaxService { - val moshi = Moshi.Builder() - .add(MoshiAdapters()) - .add(KotlinJsonAdapterFactory()) - .build() - val scarlet = Scarlet.Builder() - .webSocketFactory(client.newWebSocketFactory("wss://ws-feed.gdax.com")) - .lifecycle(lifecycle) - .addMessageAdapterFactory(MoshiMessageAdapter.Factory(moshi)) - .addStreamAdapterFactory(RxJava2StreamAdapterFactory()) - .build() - return scarlet.create() - } - } - - interface ComponentProvider { - val gdaxComponent: GdaxComponent - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/inject/GdaxScope.kt b/demo/src/main/java/com/tinder/app/gdax/inject/GdaxScope.kt deleted file mode 100644 index a1d6ef47..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/inject/GdaxScope.kt +++ /dev/null @@ -1,11 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.inject - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class GdaxScope diff --git a/demo/src/main/java/com/tinder/app/gdax/presenter/GdaxPresenter.kt b/demo/src/main/java/com/tinder/app/gdax/presenter/GdaxPresenter.kt deleted file mode 100644 index fdfe789e..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/presenter/GdaxPresenter.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.presenter - -import com.tinder.app.gdax.domain.Product -import com.tinder.app.gdax.domain.TransactionBook -import com.tinder.app.gdax.domain.TransactionRepository -import com.tinder.app.gdax.target.GdaxTarget -import io.reactivex.Flowable -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.rxkotlin.Flowables -import timber.log.Timber -import java.util.concurrent.TimeUnit -import javax.inject.Inject - -class GdaxPresenter @Inject constructor( - private val transactionRepository: TransactionRepository -) { - - private lateinit var target: GdaxTarget - private var currentProduct = Product.BTC - private var transactionBook = TransactionBook() - private val compositeDisposable = CompositeDisposable() - - fun takeTarget(target: GdaxTarget) { - this.target = target - - val transactionBookSubscription = Flowables.combineLatest( - Flowable.interval(UPDATE_INTERVAL_SECONDS, TimeUnit.SECONDS), - transactionRepository.observeTransactionBook() - ) - .map { (_, transactionBook) -> transactionBook } - .observeOn(AndroidSchedulers.mainThread()) - .subscribe({ - transactionBook = it - showTransactionBook() - }, Timber::e) - showTransactionBook() - - compositeDisposable.addAll(transactionBookSubscription) - } - - fun dropTarget() { - compositeDisposable.clear() - } - - fun handleShowBTC() { - currentProduct = Product.BTC - showTransactionBook() - } - - fun handleShowETH() { - currentProduct = Product.ETH - showTransactionBook() - } - - fun handleShowLTC() { - currentProduct = Product.LTC - showTransactionBook() - } - - private fun showTransactionBook() { - val transactions = transactionBook.getTransactions(currentProduct) - target.showTransactions(currentProduct, transactions) - } - - private companion object { - private const val UPDATE_INTERVAL_SECONDS = 1L - } -} diff --git a/demo/src/main/java/com/tinder/app/gdax/target/GdaxTarget.kt b/demo/src/main/java/com/tinder/app/gdax/target/GdaxTarget.kt deleted file mode 100644 index 06470a35..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/target/GdaxTarget.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.target - -import com.tinder.app.gdax.domain.Product -import com.tinder.app.gdax.domain.Transaction - -interface GdaxTarget { - - fun showTransactions(product: Product, transactions: List) -} diff --git a/demo/src/main/java/com/tinder/app/gdax/view/GdaxFragment.kt b/demo/src/main/java/com/tinder/app/gdax/view/GdaxFragment.kt deleted file mode 100644 index a8bc4039..00000000 --- a/demo/src/main/java/com/tinder/app/gdax/view/GdaxFragment.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.gdax.view - -import android.graphics.Color -import android.os.Bundle -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.github.mikephil.charting.charts.LineChart -import com.github.mikephil.charting.components.XAxis -import com.github.mikephil.charting.data.Entry -import com.github.mikephil.charting.data.LineData -import com.github.mikephil.charting.data.LineDataSet -import com.tinder.R -import com.tinder.app.gdax.domain.Product -import com.tinder.app.gdax.domain.Transaction -import com.tinder.app.gdax.inject.GdaxComponent -import com.tinder.app.gdax.presenter.GdaxPresenter -import com.tinder.app.gdax.target.GdaxTarget -import org.joda.time.DateTime -import org.joda.time.LocalTime -import org.joda.time.format.DateTimeFormat -import java.text.DecimalFormat -import javax.inject.Inject - -class GdaxFragment : Fragment(), GdaxTarget { - - @Inject - lateinit var presenter: GdaxPresenter - private lateinit var chart: LineChart - private var menu: Menu? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - (context!!.applicationContext as GdaxComponent.ComponentProvider).gdaxComponent - .inject(this) - - val view = inflater.inflate(R.layout.fragment_gdax, container, false) as View - - chart = view.findViewById(R.id.chart) - - return view - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - with(menu) { - val subMenu = addSubMenu(Menu.NONE, CURRENCIES_SUB_MENU_ID, Menu.NONE, CURRENCIES_SUB_MENU_TITLE) - subMenu.item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - with(subMenu) { - add(BTC_USD_MENU_ITEM_TITLE) - add(ETH_USD_MENU_ITEM_TITLE) - add(LTC_USD_MENU_ITEM_TITLE) - } - } - this.menu = menu - super.onCreateOptionsMenu(menu, inflater) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.title) { - BTC_USD_MENU_ITEM_TITLE -> presenter.handleShowBTC() - ETH_USD_MENU_ITEM_TITLE -> presenter.handleShowETH() - LTC_USD_MENU_ITEM_TITLE -> presenter.handleShowLTC() - } - return super.onOptionsItemSelected(item) - } - - override fun showTransactions(product: Product, transactions: List) { - val chartTitle = "$product-USD" - menu?.findItem(CURRENCIES_SUB_MENU_ID)?.title = chartTitle - - val now = DateTime.now() - val minutesAgo = now.minusMinutes(DISPLAYED_HISTORY_DURATION_MINUTES) - - val priceEntries = transactions - .filter { it.timestamp.isAfter(minutesAgo) } - .map { Entry(it.timestamp.millisOfDay.toFloat(), it.price) } - .toMutableList() - .apply { - add( - 0, - Entry(minutesAgo.millisOfDay.toFloat(), if (isEmpty()) 0F else this[0].y) - ) - } - val priceLineDataSet = LineDataSet(priceEntries, chartTitle) - .apply { - mode = LineDataSet.Mode.LINEAR - setDrawFilled(true) - isHighlightEnabled = false - setDrawValues(false) - } - - val minPrice = priceEntries.minByOrNull { it.y }?.y ?: 0F - val minPriceEntries = listOf( - Entry(minutesAgo.millisOfDay.toFloat(), minPrice), - Entry(now.millisOfDay.toFloat(), minPrice) - ) - val minPriceLineDataSet = LineDataSet(minPriceEntries, MIN_DATA_SET_LABEL) - .apply { - val minPriceColor = MIN_PRICE_COLOR - mode = LineDataSet.Mode.STEPPED - setCircleColorHole(Color.TRANSPARENT) - color = minPriceColor - setCircleColor(minPriceColor) - isHighlightEnabled = false - setDrawValues(false) - } - - with(chart) { - axisRight.isEnabled = false - with(xAxis) { - setValueFormatter { value, _ -> - LocalTime.fromMillisOfDay(value.toLong()).toString(DateTimeFormat.shortTime()) - } - position = XAxis.XAxisPosition.BOTTOM - setDrawGridLines(false) - granularity = 10000F - } - - with(axisLeft) { - granularity = 0.01F - setDrawGridLines(false) - setValueFormatter { value, _ -> - PRICE_FORMAT.format(value) - } - } - - description.isEnabled = false - - setTouchEnabled(false) - - data = LineData(priceLineDataSet, minPriceLineDataSet) - invalidate() - } - } - - override fun onResume() { - super.onResume() - presenter.takeTarget(this) - } - - override fun onPause() { - super.onPause() - presenter.dropTarget() - } - - companion object { - private const val DISPLAYED_HISTORY_DURATION_MINUTES = 3 - - private const val MIN_DATA_SET_LABEL = "Min" - private val MIN_PRICE_COLOR = Color.argb(50, 140, 234, 255) - - private val PRICE_FORMAT = DecimalFormat("\$##.00") - - private const val CURRENCIES_SUB_MENU_TITLE = "" - private const val CURRENCIES_SUB_MENU_ID = 300 - private const val BTC_USD_MENU_ITEM_TITLE = "BTC-USD" - private const val ETH_USD_MENU_ITEM_TITLE = "ETH-USD" - private const val LTC_USD_MENU_ITEM_TITLE = "LTC-USD" - } -} diff --git a/demo/src/main/java/com/tinder/app/root/ScarletDemoApplication.kt b/demo/src/main/java/com/tinder/app/root/ScarletDemoApplication.kt deleted file mode 100755 index 220e7683..00000000 --- a/demo/src/main/java/com/tinder/app/root/ScarletDemoApplication.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.root - -import android.app.Application -import com.facebook.stetho.Stetho -import com.tinder.app.echo.inject.DaggerEchoBotComponent -import com.tinder.app.echo.inject.EchoBotComponent -import com.tinder.app.gdax.inject.DaggerGdaxComponent -import com.tinder.app.gdax.inject.GdaxComponent -import com.tinder.app.root.inject.ApplicationComponent -import com.tinder.app.root.inject.DaggerApplicationComponent -import timber.log.Timber -import javax.inject.Inject - -class ScarletDemoApplication : Application(), - ApplicationComponent.ComponentProvider, - GdaxComponent.ComponentProvider, - EchoBotComponent.ComponentProvider { - override lateinit var applicationComponent: ApplicationComponent - override lateinit var echoBotComponent: EchoBotComponent - override lateinit var gdaxComponent: GdaxComponent - - @Inject - lateinit var stethoInitializer: Stetho.Initializer - - override fun onCreate() { - super.onCreate() - applicationComponent = DaggerApplicationComponent.builder() - .application(this) - .build() - applicationComponent.inject(this) - - echoBotComponent = DaggerEchoBotComponent.builder() - .dependency(applicationComponent) - .build() - - gdaxComponent = DaggerGdaxComponent.builder() - .dependency(applicationComponent) - .build() - - Timber.plant(Timber.DebugTree()) - Stetho.initialize(stethoInitializer) - } -} diff --git a/demo/src/main/java/com/tinder/app/root/inject/ApplicationComponent.kt b/demo/src/main/java/com/tinder/app/root/inject/ApplicationComponent.kt deleted file mode 100755 index ee84c0d9..00000000 --- a/demo/src/main/java/com/tinder/app/root/inject/ApplicationComponent.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.root.inject - -import android.app.Application -import com.tinder.app.echo.inject.EchoBotComponent -import com.tinder.app.gdax.inject.GdaxComponent -import com.tinder.app.root.ScarletDemoApplication -import dagger.BindsInstance -import dagger.Component -import javax.inject.Singleton - -@Singleton -@Component(modules = [(CommonModule::class), (StethoModule::class)]) -interface ApplicationComponent : GdaxComponent.Dependency, EchoBotComponent.Dependency { - - fun inject(application: ScarletDemoApplication) - - @Component.Builder - interface Builder { - @BindsInstance - fun application(application: Application): Builder - - fun build(): ApplicationComponent - } - - interface ComponentProvider { - val applicationComponent: ApplicationComponent - } -} diff --git a/demo/src/main/java/com/tinder/app/root/inject/CommonModule.kt b/demo/src/main/java/com/tinder/app/root/inject/CommonModule.kt deleted file mode 100755 index e62992aa..00000000 --- a/demo/src/main/java/com/tinder/app/root/inject/CommonModule.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.root.inject - -import android.app.Application -import android.content.Context -import dagger.Module -import dagger.Provides - -@Module -class CommonModule { - - @Provides - fun provideApplicationContext(application: Application): Context { - return application - } -} diff --git a/demo/src/main/java/com/tinder/app/root/inject/StethoModule.kt b/demo/src/main/java/com/tinder/app/root/inject/StethoModule.kt deleted file mode 100755 index 460a673d..00000000 --- a/demo/src/main/java/com/tinder/app/root/inject/StethoModule.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.root.inject - -import android.app.Application -import com.facebook.stetho.DumperPluginsProvider -import com.facebook.stetho.InspectorModulesProvider -import com.facebook.stetho.Stetho -import dagger.Module -import dagger.Provides - -@Module -class StethoModule { - - @Provides - internal fun provideStethoInitializer( - initializerBuilder: Stetho.InitializerBuilder, - inspectorModulesProvider: InspectorModulesProvider, - dumperPluginsProvider: DumperPluginsProvider - ): Stetho.Initializer { - return initializerBuilder - .enableDumpapp(dumperPluginsProvider) - .enableWebKitInspector(inspectorModulesProvider) - .build() - } - - @Provides - internal fun provideStethoInitializerBuilder(application: Application): Stetho.InitializerBuilder { - return Stetho.newInitializerBuilder(application) - } - - @Provides - internal fun provideStethoDumperPluginsProvider( - application: Application - ): DumperPluginsProvider { - val plugins = Stetho.DefaultDumperPluginsBuilder(application).finish() - return DumperPluginsProvider { plugins } - } - - @Provides - internal fun provideInspectorModulesProvider(application: Application): InspectorModulesProvider { - return Stetho.defaultInspectorModulesProvider(application) - } -} diff --git a/demo/src/main/java/com/tinder/app/root/view/DemoActivity.kt b/demo/src/main/java/com/tinder/app/root/view/DemoActivity.kt deleted file mode 100755 index 5edc707c..00000000 --- a/demo/src/main/java/com/tinder/app/root/view/DemoActivity.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * © 2018 Match Group, LLC. - */ - -package com.tinder.app.root.view - -import android.os.Bundle -import androidx.fragment.app.Fragment -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentStatePagerAdapter -import androidx.viewpager.widget.ViewPager -import com.google.android.material.tabs.TabLayout -import com.tinder.R -import com.tinder.app.echo.view.EchoBotFragment -import com.tinder.app.gdax.view.GdaxFragment - -class DemoActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContentView(R.layout.activity_demo) - - val toolbar = findViewById(R.id.toolbar) - setSupportActionBar(toolbar) - - val tabLayout = findViewById(R.id.tab_layout) - TAB_ITEMS.forEach { (name, _) -> tabLayout.addTab(tabLayout.newTab().setText(name)) } - tabLayout.tabGravity = TabLayout.GRAVITY_CENTER - - val viewPager = findViewById(R.id.view_pager) - val viewPagerAdapter = ViewPagerAdapter(supportFragmentManager, tabLayout.tabCount) - viewPager.adapter = viewPagerAdapter - - viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabLayout)) - tabLayout.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewPager)) - } - - private class ViewPagerAdapter constructor(fm: FragmentManager, private val pageCount: Int) : - FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int): Fragment { - val (_, createFragment) = TAB_ITEMS[position] - return createFragment() - } - - override fun getCount(): Int { - return pageCount - } - } - - companion object { - private val TAB_ITEMS = listOf( - "Echo Bot" to { EchoBotFragment() }, - "GDAX" to { GdaxFragment() } - ) - } -} diff --git a/demo/src/main/res/drawable/ic_launcher_background.xml b/demo/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100755 index 1eca8a79..00000000 --- a/demo/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/demo/src/main/res/layout/activity_demo.xml b/demo/src/main/res/layout/activity_demo.xml deleted file mode 100755 index ad1f6d45..00000000 --- a/demo/src/main/res/layout/activity_demo.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/demo/src/main/res/layout/fragment_echo_bot.xml b/demo/src/main/res/layout/fragment_echo_bot.xml deleted file mode 100755 index 0a70ab4d..00000000 --- a/demo/src/main/res/layout/fragment_echo_bot.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - diff --git a/demo/src/main/res/layout/fragment_gdax.xml b/demo/src/main/res/layout/fragment_gdax.xml deleted file mode 100644 index 7d8046f3..00000000 --- a/demo/src/main/res/layout/fragment_gdax.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/demo/src/main/res/layout/view_event_log.xml b/demo/src/main/res/layout/view_event_log.xml deleted file mode 100644 index 782eb431..00000000 --- a/demo/src/main/res/layout/view_event_log.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100755 index 176e2843..00000000 --- a/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100755 index 176e2843..00000000 --- a/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher.png b/demo/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100755 index 55073031..00000000 Binary files a/demo/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/demo/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100755 index 4e526c95..00000000 Binary files a/demo/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100755 index 8fab6a3a..00000000 Binary files a/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher.png b/demo/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100755 index 6bc7fcd6..00000000 Binary files a/demo/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/demo/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100755 index 2c38c719..00000000 Binary files a/demo/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100755 index 1eecc0e7..00000000 Binary files a/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100755 index ec87dceb..00000000 Binary files a/demo/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/demo/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100755 index 072467ea..00000000 Binary files a/demo/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100755 index 05ca079c..00000000 Binary files a/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100755 index 6f67f21b..00000000 Binary files a/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100755 index 78a6b7a3..00000000 Binary files a/demo/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100755 index 8bac0f27..00000000 Binary files a/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100755 index 0327e13f..00000000 Binary files a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100755 index 68ebe33f..00000000 Binary files a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100755 index bacd3e75..00000000 Binary files a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml deleted file mode 100755 index eab0c52a..00000000 --- a/demo/src/main/res/values/colors.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - #3F51B5 - #303F9F - #FF4081 - diff --git a/demo/src/main/res/values/dimens.xml b/demo/src/main/res/values/dimens.xml deleted file mode 100644 index 3e761681..00000000 --- a/demo/src/main/res/values/dimens.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - 1dp - 2dp - 4dp - 8dp - 16dp - 20dp - 24dp - 36dp - 48dp - 56dp - 96dp - - - 8sp - - 10sp - 12sp - 14sp - 16sp - 18sp - 20sp - 24sp - 34sp - 45sp - 56sp - diff --git a/demo/src/main/res/values/strings.xml b/demo/src/main/res/values/strings.xml deleted file mode 100755 index 8e09dfe4..00000000 --- a/demo/src/main/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Scarlet - diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml deleted file mode 100755 index 34343ba1..00000000 --- a/demo/src/main/res/values/styles.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - diff --git a/settings.gradle b/settings.gradle index 530ac097..e4a56526 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,4 +14,3 @@ include ':scarlet-stream-adapter-rxjava' include ':scarlet-stream-adapter-rxjava2' include ':scarlet-stream-adapter-coroutines' include ':scarlet-lifecycle-android' -include ':demo'