diff --git a/.gitignore b/.gitignore index 26c4834..5dc177e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ out/* target settings.xml + +.gradle/ +build/ +out/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..89f97a9 --- /dev/null +++ b/build.gradle @@ -0,0 +1,43 @@ +project.version = "0.0.1" +project.group = "com.github.insanusmokrassar" + +buildscript { + repositories { + mavenLocal() + jcenter() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version" + } +} + +apply plugin: 'java-library' +apply plugin: 'kotlin' +apply plugin: 'kotlinx-serialization' + +repositories { + mavenLocal() + jcenter() + mavenCentral() + maven { url "https://kotlin.bintray.com/kotlinx" } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialisation_runtime_version" + implementation "joda-time:joda-time:$joda_time_version" + + // Use JUnit test framework + testImplementation 'junit:junit:4.12' +} + +compileKotlin { + kotlinOptions { + freeCompilerArgs = [ disableImplicitReflectionSerializerAnnotation ] + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..30d76e6 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,10 @@ +kotlin.code.style=official +kotlin_version=1.3.21 +kotlin_coroutines_version=1.1.1 +kotlin_serialisation_runtime_version=0.10.0 +joda_time_version=2.10.1 +ktor_version=1.1.2 + +gradle_bintray_plugin_version=1.8.4 + +disableImplicitReflectionSerializerAnnotation=-Xexperimental=kotlinx.serialization.ImplicitReflectionSerializer diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..37837ba Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..19c6ad2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Mar 15 10:26:54 HKT 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4453cce --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/old.pom.xml similarity index 100% rename from pom.xml rename to old.pom.xml diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..09f9ee6 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,18 @@ +/* + * This settings file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/3.4.1/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'PsychomatrixBase' diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/HistoryDatesRepository.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/HistoryDatesRepository.kt index 06bb863..b2cdc81 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/HistoryDatesRepository.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/HistoryDatesRepository.kt @@ -1,7 +1,7 @@ package com.github.insanusmokrassar.PsychomatrixBase.data.repository -import kotlinx.coroutines.experimental.Deferred -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime interface HistoryDatesRepository { diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/realisations/HistoryDatesRepositoryImpl.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/realisations/HistoryDatesRepositoryImpl.kt index 743aa22..64feb7e 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/realisations/HistoryDatesRepositoryImpl.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/data/repository/realisations/HistoryDatesRepositoryImpl.kt @@ -2,21 +2,21 @@ package com.github.insanusmokrassar.PsychomatrixBase.data.repository.realisation import com.github.insanusmokrassar.PsychomatrixBase.data.repository.HistoryDatesRepository import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.CalculatePsychomatrixByDateUseCase -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_EXTRA_SMALL import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.subscribe -import kotlinx.coroutines.experimental.* -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime abstract class HistoryDatesRepositoryImpl( calculatePsychomatrixByDateUseCase: CalculatePsychomatrixByDateUseCase ) : HistoryDatesRepository { - private val dateAddedBroadcast = BroadcastChannel(SUBSCRIPTIONS_EXTRA_SMALL) - private val dateRemovedBroadcast = BroadcastChannel(SUBSCRIPTIONS_EXTRA_SMALL) + private val scope = CoroutineScope(Dispatchers.Default) + private val dateAddedBroadcast = BroadcastChannel(8) + private val dateRemovedBroadcast = BroadcastChannel(8) init { - launch { + scope.launch { calculatePsychomatrixByDateUseCase.openPsychomatrixCreatedSubscription().subscribe { it.date.also { date -> @@ -41,7 +41,7 @@ abstract class HistoryDatesRepositoryImpl( protected abstract fun onDateCalculated(dateTime: DateTime) override suspend fun removeDate(date: DateTime): Deferred { - return async { + return scope.async { internalRemoveDate(date).also { if (it) { dateRemovedBroadcast.send(date) diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CalculatePsychomatrixByDateUseCase.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CalculatePsychomatrixByDateUseCase.kt index be7f5bc..7dc9693 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CalculatePsychomatrixByDateUseCase.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CalculatePsychomatrixByDateUseCase.kt @@ -1,8 +1,8 @@ package com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix -import kotlinx.coroutines.experimental.Deferred -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime import java.util.* diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CeilDescriptionUseCase.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CeilDescriptionUseCase.kt index 352c67d..e1eb018 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CeilDescriptionUseCase.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/CeilDescriptionUseCase.kt @@ -2,7 +2,7 @@ package com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilInfo import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilState -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.channels.ReceiveChannel typealias CeilDescriptionReady = Pair diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/ModifyPsychomatrixUseCase.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/ModifyPsychomatrixUseCase.kt index b7d9f2d..2f75164 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/ModifyPsychomatrixUseCase.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/UseCases/ModifyPsychomatrixUseCase.kt @@ -3,7 +3,7 @@ package com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.MutablePsychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.operations.Operation -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.channels.ReceiveChannel typealias PsychomatrixOperationIsConvert = Pair> diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CalculatePsychomatrixByDateUseCaseInteractor.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CalculatePsychomatrixByDateUseCaseInteractor.kt index 3c14b89..c16f937 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CalculatePsychomatrixByDateUseCaseInteractor.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CalculatePsychomatrixByDateUseCaseInteractor.kt @@ -2,23 +2,22 @@ package com.github.insanusmokrassar.PsychomatrixBase.domain.interactors import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.CalculatePsychomatrixByDateUseCase import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_MEDIUM -import kotlinx.coroutines.experimental.Deferred -import kotlinx.coroutines.experimental.async -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime import java.util.* class CalculatePsychomatrixByDateUseCaseInteractor : CalculatePsychomatrixByDateUseCase { - private val psychomatrixCreatedBroadcast = BroadcastChannel(SUBSCRIPTIONS_MEDIUM) + private val scope = CoroutineScope(Dispatchers.Default) + private val psychomatrixCreatedBroadcast = BroadcastChannel(16) override suspend fun calculate(date: Long): Deferred { return calculate(DateTime(date)) } override suspend fun calculate(date: DateTime): Deferred { - return async { + return scope.async { Psychomatrix(date).also { psychomatrixCreatedBroadcast.send(it) } diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CeilDescriptionInteractor.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CeilDescriptionInteractor.kt index 678964f..379c1fd 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CeilDescriptionInteractor.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/CeilDescriptionInteractor.kt @@ -4,18 +4,17 @@ import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.CeilDescript import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.CeilDescriptionUseCase import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilInfo import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilState -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_EXTRA_SMALL -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_SMALL -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel class CeilDescriptionInteractor : CeilDescriptionUseCase { + private val scope = CoroutineScope(Dispatchers.Default) private val ceilDescriptionReadyBroadcastChannel = BroadcastChannel( - SUBSCRIPTIONS_SMALL + 16 ) private val ceilDescriptionRequestedBroadcastChannel = BroadcastChannel( - SUBSCRIPTIONS_EXTRA_SMALL + 8 ) override fun openCeilDescriptionReadySubscription(): ReceiveChannel { @@ -27,13 +26,13 @@ class CeilDescriptionInteractor : CeilDescriptionUseCase { } override fun descriptionReady(ceilState: CeilState, ceilInfo: CeilInfo) { - launch { + scope.launch { ceilDescriptionReadyBroadcastChannel.send(ceilState to ceilInfo) } } override fun requestDescription(ceilState: CeilState) { - launch { + scope.launch { ceilDescriptionRequestedBroadcastChannel.send( ceilState ) diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/ModifyPsychomatrixUseCaseInteractor.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/ModifyPsychomatrixUseCaseInteractor.kt index 0b9e871..18b0c7f 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/ModifyPsychomatrixUseCaseInteractor.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/domain/interactors/ModifyPsychomatrixUseCaseInteractor.kt @@ -5,15 +5,15 @@ import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.MutablePsychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.operations.Operation -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_MEDIUM -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel class ModifyPsychomatrixUseCaseInteractor : ModifyPsychomatrixUseCase { + private val scope = CoroutineScope(Dispatchers.Default) private val currentPsychomatrixes: MutableList = ArrayList() - private val psychomatrixChangedBroadcastChannel = BroadcastChannel(SUBSCRIPTIONS_MEDIUM) + private val psychomatrixChangedBroadcastChannel = BroadcastChannel(16) override fun openPsychomatrixChangedSubscription(): ReceiveChannel { return psychomatrixChangedBroadcastChannel.openSubscription() @@ -22,7 +22,7 @@ class ModifyPsychomatrixUseCaseInteractor : ModifyPsychomatrixUseCase { override fun makeConvert(psychomatrix: MutablePsychomatrix, operation: Operation): Boolean { return asMutablePsychomatrix(psychomatrix).applyConvert(operation).also { if (it) { - launch { + scope.launch { psychomatrixChangedBroadcastChannel.send(psychomatrix to (operation to true)) } } @@ -31,7 +31,7 @@ class ModifyPsychomatrixUseCaseInteractor : ModifyPsychomatrixUseCase { override fun makeInvert(psychomatrix: MutablePsychomatrix, operation: Operation): Boolean { return asMutablePsychomatrix(psychomatrix).applyInvert(operation).also { - launch { + scope.launch { psychomatrixChangedBroadcastChannel.send(psychomatrix to (operation to false)) } } diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/CeilDescriptionPresenter.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/CeilDescriptionPresenter.kt index b17ab22..179e1ad 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/CeilDescriptionPresenter.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/CeilDescriptionPresenter.kt @@ -2,7 +2,7 @@ package com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilInfo import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilState -import kotlinx.coroutines.experimental.Deferred +import kotlinx.coroutines.Deferred interface CeilDescriptionPresenter { fun onUserChooseCeil(ceilState: CeilState): Deferred diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DatePickerPresenter.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DatePickerPresenter.kt index 9ff49e6..5e04e2b 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DatePickerPresenter.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DatePickerPresenter.kt @@ -1,7 +1,7 @@ package com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime interface DatePickerPresenter { diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/CeilDescriptionPresenterImpl.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/CeilDescriptionPresenterImpl.kt index 960c150..c56d4a5 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/CeilDescriptionPresenterImpl.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/CeilDescriptionPresenterImpl.kt @@ -6,13 +6,15 @@ import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilState import com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters.CeilDescriptionPresenter import com.github.insanusmokrassar.PsychomatrixBase.utils.Container import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.subscribeChecking -import kotlinx.coroutines.experimental.* +import kotlinx.coroutines.* class CeilDescriptionPresenterImpl( private val ceilDescriptionUseCase: CeilDescriptionUseCase ) : CeilDescriptionPresenter { + private val scope = CoroutineScope(Dispatchers.Default) + override fun onUserChooseCeil(ceilState: CeilState): Deferred { - return async { + return scope.async { val container = Container() val subscription = ceilDescriptionUseCase.openCeilDescriptionReadySubscription().subscribeChecking( { diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/DatePickerPresenterImpl.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/DatePickerPresenterImpl.kt index e564115..7e9b306 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/DatePickerPresenterImpl.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/DatePickerPresenterImpl.kt @@ -3,16 +3,17 @@ package com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters.Def import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.CalculatePsychomatrixByDateUseCase import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters.DatePickerPresenter -import com.github.insanusmokrassar.PsychomatrixBase.utils.extensions.SUBSCRIPTIONS_MEDIUM -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel -import kotlinx.coroutines.experimental.launch +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.BroadcastChannel +import kotlinx.coroutines.channels.ReceiveChannel import org.joda.time.DateTime class DatePickerPresenterImpl( - private val CalculatePsychomatrixByDateUseCase: CalculatePsychomatrixByDateUseCase + private val CalculatePsychomatrixByDateUseCase: CalculatePsychomatrixByDateUseCase, + broadcastChannelCapacity: Int = 4 ) : DatePickerPresenter { - private val psychomatrixCreateBroadcastChannel = BroadcastChannel(SUBSCRIPTIONS_MEDIUM) + private val scope = CoroutineScope(Dispatchers.Default) + private val psychomatrixCreateBroadcastChannel = BroadcastChannel(broadcastChannelCapacity) override suspend fun openPsychomatrixCreatedSubscription(): ReceiveChannel { return psychomatrixCreateBroadcastChannel.openSubscription() @@ -23,7 +24,7 @@ class DatePickerPresenterImpl( } override fun userPickDate(date: DateTime) { - launch { + scope.launch { CalculatePsychomatrixByDateUseCase.calculate(date).await().also { psychomatrixCreateBroadcastChannel.send(it) } diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/ModifyPsychomatrixPresenterImpl.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/ModifyPsychomatrixPresenterImpl.kt index 6c4211e..42a94f4 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/ModifyPsychomatrixPresenterImpl.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/DefaultRealisations/ModifyPsychomatrixPresenterImpl.kt @@ -6,7 +6,7 @@ import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.MutablePsych import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.operations.Operation import com.github.insanusmokrassar.PsychomatrixBase.presentation.presenters.ModifyPsychomatrixPresenter -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.channels.ReceiveChannel class ModifyPsychomatrixPresenterImpl( private val modifyPsychomatrixUseCase: ModifyPsychomatrixUseCase diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/ModifyPsychomatrixPresenter.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/ModifyPsychomatrixPresenter.kt index 62fb555..5419be1 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/ModifyPsychomatrixPresenter.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/presentation/presenters/ModifyPsychomatrixPresenter.kt @@ -4,7 +4,7 @@ import com.github.insanusmokrassar.PsychomatrixBase.domain.UseCases.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.MutablePsychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.Psychomatrix import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.operations.Operation -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.channels.ReceiveChannel interface ModifyPsychomatrixPresenter { diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/CeilInfoResolver.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/CeilInfoResolver.kt index 44c2438..c20e2b0 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/CeilInfoResolver.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/CeilInfoResolver.kt @@ -2,14 +2,11 @@ package com.github.insanusmokrassar.PsychomatrixBase.utils.CeilDescriptions import com.github.insanusmokrassar.PsychomatrixBase.utils.CeilDescriptions.models.CeilsInfosRoot import com.github.insanusmokrassar.PsychomatrixBase.utils.FilesLoader.load -import com.google.gson.Gson -import com.google.gson.GsonBuilder +import kotlinx.serialization.json.Json import java.io.InputStreamReader const val characteristicsFolder = "characteristics" -private val gson: Gson = GsonBuilder().create() - val availableTranslations = listOf( "en_US", "ru_RU" @@ -30,6 +27,6 @@ private fun findSubTranslation(language: String): String { fun resolveCeilsDescriptionsByLanguage(language: String = "en_US"): CeilsInfosRoot { return load("$characteristicsFolder/${findSubTranslation(language)}.json").let { - gson.fromJson(InputStreamReader(it), CeilsInfosRoot::class.java) + Json.nonstrict.parse(CeilsInfosRoot.serializer(), InputStreamReader(it).readText()) } } diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilInfoConfig.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilInfoConfig.kt index 354d2c6..8fb7775 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilInfoConfig.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilInfoConfig.kt @@ -1,7 +1,9 @@ package com.github.insanusmokrassar.PsychomatrixBase.utils.CeilDescriptions.models import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilInfo +import kotlinx.serialization.Serializable +@Serializable data class CeilInfoConfig( val title: String = "", val description: String = "", diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilsInfosRoot.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilsInfosRoot.kt index e1babb5..0968a55 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilsInfosRoot.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/CeilDescriptions/models/CeilsInfosRoot.kt @@ -2,7 +2,9 @@ package com.github.insanusmokrassar.PsychomatrixBase.utils.CeilDescriptions.mode import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilInfo import com.github.insanusmokrassar.PsychomatrixBase.domain.entities.CeilState +import kotlinx.serialization.Serializable +@Serializable data class CeilsInfosRoot( val language: String? = "en_US", private val descriptionsList: List> = emptyList() diff --git a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/extensions/ReceiveChannel.kt b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/extensions/ReceiveChannel.kt index a4aa951..f0cd065 100644 --- a/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/extensions/ReceiveChannel.kt +++ b/src/main/kotlin/com/github/insanusmokrassar/PsychomatrixBase/utils/extensions/ReceiveChannel.kt @@ -1,44 +1,128 @@ package com.github.insanusmokrassar.PsychomatrixBase.utils.extensions -import kotlinx.coroutines.experimental.* -import kotlinx.coroutines.experimental.channels.BroadcastChannel -import kotlinx.coroutines.experimental.channels.ReceiveChannel +import kotlinx.coroutines.* +import kotlinx.coroutines.channels.* import java.util.concurrent.TimeUnit -const val SUBSCRIPTIONS_LARGE = 256 -const val SUBSCRIPTIONS_MEDIUM = 128 -const val SUBSCRIPTIONS_SMALL = 64 -const val SUBSCRIPTIONS_EXTRA_SMALL = 32 -const val SUBSCRIPTIONS_SINGLE = 1 +private sealed class DebounceAction { + abstract val value: T +} + +private data class AddValue(override val value: T) : DebounceAction() +private data class RemoveJob(override val value: T, val job: Job) : DebounceAction() + +fun ReceiveChannel.debounceByValue( + delayMillis: Long, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + resultBroadcastChannelCapacity: Int = 32 +): ReceiveChannel { + val outChannel = Channel(resultBroadcastChannelCapacity) + val values = HashMap() + + val channel = Channel>(Channel.UNLIMITED) + scope.launch { + for (action in channel) { + when (action) { + is AddValue -> { + val msg = action.value + values[msg] ?.cancel() + lateinit var job: Job + job = launch { + delay(delayMillis) + + outChannel.send(msg) + channel.send(RemoveJob(msg, job)) + } + values[msg] = job + } + is RemoveJob -> if (values[action.value] == action.job) { + values.remove(action.value) + } + } + + } + } + + scope.launch { + for (msg in this@debounceByValue) { + channel.send(AddValue(msg)) + } + } + + return outChannel +} + +typealias AccumulatedValues = Pair> + +fun ReceiveChannel>.accumulateByKey( + delayMillis: Long, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + resultBroadcastChannelCapacity: Int = 32 +): ReceiveChannel> { + val outChannel = Channel>(resultBroadcastChannelCapacity) + val values = HashMap>() + val jobs = HashMap() + + val channel = Channel>>(Channel.UNLIMITED) + scope.launch { + for (action in channel) { + val (key, value) = action.value + when (action) { + is AddValue -> { + jobs[key] ?.cancel() + (values[key] ?: mutableListOf().also { values[key] = it }).add(value) + lateinit var job: Job + job = launch { + delay(delayMillis) + + values[key] ?.let { + outChannel.send(key to it) + channel.send(RemoveJob(key to value, job)) + } + } + jobs[key] = job + } + is RemoveJob -> if (values[key] == action.job) { + values.remove(key) + jobs.remove(key) + } + } + + } + } + + scope.launch { + for (msg in this@accumulateByKey) { + channel.send(AddValue(msg)) + } + } + + return outChannel +} fun ReceiveChannel.subscribeChecking( throwableHandler: (Throwable) -> Boolean = { it.printStackTrace() true }, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), by: suspend (T) -> Boolean ): Job { - return launch { - while (isActive && !isClosedForReceive) { - try { - val received = receive() - - launch { - try { - if (!by(received)) { - cancel() - } - } catch (e: Throwable) { - if (!throwableHandler(e)) { - cancel() - } + val channel = this + return scope.launch { + for (data in channel) { + launch { + try { + if (!by(data)) { + channel.cancel() + } + } catch (e: Throwable) { + if (!throwableHandler(e)) { + channel.cancel() } } - } catch (e: CancellationException) { - break } } - cancel() } } @@ -47,45 +131,30 @@ fun ReceiveChannel.subscribe( it.printStackTrace() true }, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), by: suspend (T) -> Unit ): Job { - return subscribeChecking(throwableHandler) { + return subscribeChecking(throwableHandler, scope) { by(it) true } } -fun ReceiveChannel.debounce(delayMs: Long, awaitedSubscriptions: Int = 256): BroadcastChannel { - val channel = BroadcastChannel(awaitedSubscriptions) - var lastReceived: Pair? = null - var job: Job? = null - launch { - while (isActive && !isClosedForReceive) { - val received = receive() +fun ReceiveChannel.debounce( + delay: Long, + timeUnit: TimeUnit = TimeUnit.MILLISECONDS, + scope: CoroutineScope = CoroutineScope(Dispatchers.Default), + resultBroadcastChannelCapacity: Int = 1 +): BroadcastChannel { + return BroadcastChannel(resultBroadcastChannelCapacity).also { outBroadcast -> + var lastReceived: Job? = null + subscribe(scope = scope) { + lastReceived ?.cancel() + lastReceived = scope.launch { + delay(timeUnit.toMillis(delay)) - lastReceived = Pair(System.currentTimeMillis() + delayMs, received) - - job ?:let { - job = launch { - try { - var now = System.currentTimeMillis() - while (isActive && lastReceived?.first ?: now >= now) { - delay((lastReceived ?.first ?: now) - now, TimeUnit.MILLISECONDS) - now = System.currentTimeMillis() - } - - lastReceived?.second?.also { - channel.send(it) - } - } catch (e: Exception) { - e.printStackTrace() - } finally { - job = null - } - } + outBroadcast.send(it) } } - cancel() } - return channel } diff --git a/src/main/res/PsychomatrixDescriptions.json b/src/main/resources/PsychomatrixDescriptions.json similarity index 100% rename from src/main/res/PsychomatrixDescriptions.json rename to src/main/resources/PsychomatrixDescriptions.json diff --git a/src/main/res/characteristics/en_US.json b/src/main/resources/characteristics/en_US.json similarity index 100% rename from src/main/res/characteristics/en_US.json rename to src/main/resources/characteristics/en_US.json diff --git a/src/main/res/characteristics/ru_RU.json b/src/main/resources/characteristics/ru_RU.json similarity index 100% rename from src/main/res/characteristics/ru_RU.json rename to src/main/resources/characteristics/ru_RU.json