diff --git a/.travis.yml b/.travis.yml index 909f1c69..94978353 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,8 @@ cache: - $HOME/.gradle/native #Cache library downloaded from the gradle dependency env: global: - - ANDROID_API=27 - - EMULATOR_API=26 - - ANDROID_BUILD_TOOLS=27.0.3 + - ANDROID_API=28 + - ANDROID_BUILD_TOOLS=28.0.2 - ADB_INSTALL_TIMEOUT=5 - secure: UH6Td9+MFk1nsYYMKN9t6/XcMmSZtB+L4sWMUmYBMaK1Q6YnGCnyHmU5RWkP+9a3AiZQ+n9XK+9TV+azMxJzyOoPMEzvBYtienvI1ZwTg+gqVOsMGG8TKubdgBfYQKm+mtdc3ctgucqjRg0yb4aUDp4CeNwwCuX1zuzIaAYp8IgRElkJzhJMeTcrCUWTBNk2F9ix0eRyOKOCIwgiAa6wNn1zMRvpbPh3esJ7CcnC0xesBtWriFtJDKFhPPWowPrWhGerLe3y5oNySqPpjxfBDIU9HPThNLNwBgp25Ww2c4Ib4Im0p59dPyKBU8mv3eoHvWtrSYW0bZQfKuJD6JsI0wg7Afx2hOxhPWw2evwjmhYWEfspSTUDUZIV/BhLhR2WbeZgAgd1gBh1ulxe79kne1FLsojVr+wZXA5Cn1TF2R4pnTj8EYLctbz/J1/sbcKwut6+I4z7FgbLDOEvaHTJZiscotR0ofML6OoYkKba8LznCES8RqYc3oyCKJvRD5oiVyHhMScAptMeignnPCGmhzm2evpclZfjoZ6vGyI/MgZML4as7WWz1FuiaNV+vJx6PyuNzBjYyNpKJ7O/G4yUT6EITrw3UPVCaSJr6eM3o8eAjy8XTkFsuRJ4iEhMAGiDRlvIlAMrUQyp8PxxvKB9YS6skFfAXXAUp59m/PLbRc0= - secure: b9RwM5JGKpo0axCpeqDx9WZfZppiJWKF6d1zxTpO6cIiUmsgpL2GQy1fK/jHzKA1mlFIgq87pu11M696PqPJq7RadkeqlhKAq0zw8lBphg5Tn50wZUglusvIbMPC4VnsFLNeBd3elZIepglbh994sQxxpCpc8IF29x8cj//xrR6Z+EvyWYjnLgtbQjjdql6K0JRhGyTn+FXe5qLxmgu2lc4QL/RBcpnF+gpLrFfzBf/M/ruSyLjjpLZLCtzz90dAD/Ewb+sLvlfM0SUbXvFg+P2YoSo7rbDum+l45S6meIs6ygqcpb/3ByL9pSK3XEzrqLFQFggST8Puy8pHkwL8IVLuOtTPiO2HUtyzbTJLbEmupwEr6nXF2xtQE4vqgCNCLd63JxldRf3D2nrLG9OXJMlQRzkAfYtXj15tqyDfiLlCzIocfASsj/MF8XKzeR45+6GC9KLULpR0s1MdxYYhhb+Ss4sV8VElC3C4mlQiCA6G5AOJtPcnUshGNXbw3oWotJgY76IEJG2gSnb2SSI94VuXCI/39DLxXoTF1knixdaFJOO2QvBU2b8eZKrU4w1+rUrSfIMnBdn27hdqs+uKYNuJIwtMMCcrFtZmZnKjXcBwjgQdm51gWuMiJN5S8xM8turo23jL2Cak7rXn8RUmLHbhu3Jpl8iQzQOPFm1zmkg= @@ -24,31 +23,32 @@ android: - platform-tools - build-tools-$ANDROID_BUILD_TOOLS - android-$ANDROID_API - - android-$EMULATOR_API_LEVEL - extra-google-m2repository - extra-android-m2repository - addon-google_apis-google-19 - sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL - - sys-img-armeabi-v7a-addon-google_apis-google-$EMULATOR_API_LEVEL licenses: - android-sdk-preview-license-.+ - android-sdk-license-.+ - google-gdk-license-.+ + - android-googletv-license-.+ before_install: -- yes | sdkmanager "platforms;android-27" +- yes | sdkmanager "platform-tools" "platforms;android-28" - openssl aes-256-cbc -K $encrypted_c5c67234e863_key -iv $encrypted_c5c67234e863_iv -in android/DartsScorecard/scripts/dsc_keystore.enc -out android/DartsScorecard/scripts/dsc_keystore -d - openssl aes-256-cbc -K $encrypted_60401f83f63b_key -iv $encrypted_60401f83f63b_iv -in android/DartsScorecard/app/google-services.json.enc -out android/DartsScorecard/app/google-services.json -d - mkdir "$ANDROID_HOME/licenses" || true -- echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license" +- echo -e "\nd56f5187479451eabf01fb78af6dfcb131a6481e" > "$ANDROID_HOME/licenses/android-sdk-license" - echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license" +- echo -e "\n601085b94cd77f0b54ff86406957099ebe79c4d6" > "$ANDROID_HOME/licenses/android-googletv-license" +- echo -e "\n33b6a2b64607f11b759f320ef9dff4ae5c47d97a" > "$ANDROID_HOME/licenses/google-gdk-license" - cd android/DartsScorecard/ - chmod +x gradlew - ./gradlew dependencies || true script: -- ./gradlew clean build checkDebug -PdisablePreDex --stacktrace +- ./gradlew clean build -PdisablePreDex --stacktrace after_success: - ./gradlew jacocoFullReport coveralls before_deploy: @@ -59,6 +59,7 @@ before_deploy: - ${ANDROID_HOME}/build-tools/${ANDROID_BUILD_TOOLS}/apksigner sign --ks $HOME/dsc_keystore --ks-key-alias Entreco --ks-pass pass:$storepass --key-pass pass:$keypass --in _${APP_NAME} --out $APP_NAME - ${ANDROID_HOME}/build-tools/${ANDROID_BUILD_TOOLS}/apksigner verify $APP_NAME + deploy: provider: releases file: diff --git a/android/DartsScorecard/app/build.gradle b/android/DartsScorecard/app/build.gradle index 0bdf919c..c324fcbc 100644 --- a/android/DartsScorecard/app/build.gradle +++ b/android/DartsScorecard/app/build.gradle @@ -1,18 +1,21 @@ apply plugin: 'com.android.application' -apply plugin: 'io.fabric' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' +apply plugin: 'io.fabric' apply plugin: 'com.getkeepsafe.dexcount' -apply from: '../scripts/versioning.gradle' apply from: '../scripts/coverage.gradle' apply from: '../scripts/android_common.gradle' +apply from: '../scripts/versioning.gradle' android { + def config = rootProject.extensions.getByName("ext") defaultConfig { applicationId "nl.entreco.dartsscorecard" resValue "string", "version", "${config.versionName}" + + ndk {abiFilters "armeabi", "armeabi-v7a", "x86", "mips"} } buildTypes { debug { @@ -22,34 +25,48 @@ android { shrinkResources true } } - dataBinding { - enabled = true + + sourceSets.main { + jniLibs.srcDir 'libs' + jni.srcDirs = [] //disable automatic ndk-build call + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { + + implementation project(":shared") implementation project(':domain') implementation project(':data') + // Annotation Processing kapt "com.google.dagger:dagger-compiler:$daggerVersion" kapt "android.arch.persistence.room:compiler:$room" - kapt "com.github.bumptech.glide:compiler:$glide" // Implementation - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" implementation "com.google.dagger:dagger:$daggerVersion" - implementation "com.android.support:appcompat-v7:$support" implementation "com.android.support:design:$support" + implementation "com.android.support:appcompat-v7:$support" + implementation "com.android.support:leanback-v17:$support" implementation "com.android.support.constraint:constraint-layout:$constraint" - implementation "com.google.firebase:firebase-ads:$firebase" - implementation "com.google.firebase:firebase-firestore:$firebase" - implementation "com.google.firebase:firebase-config:$firebase" - implementation "android.arch.lifecycle:extensions:$architecture" + implementation "com.google.firebase:firebase-ads:$fbAds" + implementation "com.google.firebase:firebase-core:$fbCore" + implementation "com.google.firebase:firebase-firestore:$fbStore" + implementation "com.google.firebase:firebase-config:$fbConfig" + implementation "com.google.firebase:firebase-database:$fbDatabase" implementation "android.arch.persistence.room:runtime:$room" - implementation "com.github.yalantis:jellytoolbar:$jelly" + implementation "android.arch.lifecycle:extensions:$architecture" + implementation "com.google.code.gson:gson:$gson" implementation "com.github.bumptech.glide:glide:$glide" + implementation "com.github.yalantis:jellytoolbar:$jelly" implementation "de.hdodenhof:circleimageview:$circleImageView" + implementation "org.webrtc:google-webrtc:$webRtc" + implementation("com.crashlytics.sdk.android:crashlytics:$crash") { transitive = true } diff --git a/android/DartsScorecard/app/google-services.json.enc b/android/DartsScorecard/app/google-services.json.enc index 8ba3ff4d..5136a48f 100644 Binary files a/android/DartsScorecard/app/google-services.json.enc and b/android/DartsScorecard/app/google-services.json.enc differ diff --git a/android/DartsScorecard/app/proguard-rules.pro b/android/DartsScorecard/app/proguard-rules.pro index 72027cce..1708def0 100644 --- a/android/DartsScorecard/app/proguard-rules.pro +++ b/android/DartsScorecard/app/proguard-rules.pro @@ -20,18 +20,13 @@ # hide the original source file name. #-renamesourcefileattribute SourceFile --keepattributes Signature +-keepattributes Signature,InnerClasses # Crashlytics -keepattributes *Annotation* -keepattributes SourceFile,LineNumberTable -keep public class * extends java.lang.Exception -# Google Play Services --keep public class com.google.android.gms.* { public *; } --dontwarn com.google.android.gms.** --dontnote com.google.android.gms.** - # Okio -dontwarn okio.** -dontnote okio.** @@ -49,3 +44,7 @@ **[] $VALUES; public *; } + +# WebRtc +-keep class org.webrtc.** { *; } + diff --git a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png b/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 35fcb234..00000000 Binary files a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 964fb6d0..00000000 Binary files a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 00637107..00000000 Binary files a/android/DartsScorecard/app/src/debug/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/android/DartsScorecard/app/src/debug/res/values/keys.xml b/android/DartsScorecard/app/src/debug/res/values/keys.xml index b12fbc00..c6dd737e 100644 --- a/android/DartsScorecard/app/src/debug/res/values/keys.xml +++ b/android/DartsScorecard/app/src/debug/res/values/keys.xml @@ -1,8 +1,8 @@ - ca-app-pub-3793327349392749~1846337901 - ca-app-pub-3940256099942544/6300978111 - ca-app-pub-3940256099942544/6300978111 - ca-app-pub-3940256099942544/1033173712 + ca-app-pub-3793327349392749~1846337901 + ca-app-pub-3940256099942544/6300978111 + ca-app-pub-3940256099942544/6300978111 + ca-app-pub-3940256099942544/1033173712 \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/AndroidManifest.xml b/android/DartsScorecard/app/src/main/AndroidManifest.xml index cb4fe281..b999295d 100644 --- a/android/DartsScorecard/app/src/main/AndroidManifest.xml +++ b/android/DartsScorecard/app/src/main/AndroidManifest.xml @@ -2,11 +2,26 @@ + + + + + + + + + + + + + + + + android:name=".faq.WtfActivity" + android:parentActivityName=".launch.LaunchActivity" + android:windowSoftInputMode="stateHidden" /> @@ -59,6 +89,7 @@ android:windowSoftInputMode="adjustResize" /> + + + + diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/AppLogger.kt similarity index 86% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/AppLogger.kt index 60509514..c5636ea4 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/AppLogger.kt @@ -1,12 +1,12 @@ package nl.entreco.dartsscorecard import android.util.Log -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger /** * Created by Entreco on 27/11/2017. */ -internal class DscLogger(private val tag: String) : Logger { +internal class AppLogger(private val tag: String) : Logger { companion object { private var ENABLED = BuildConfig.DEBUG @@ -89,6 +89,8 @@ internal class DscLogger(private val tag: String) : Logger { } private fun withArgs(message: String, args: Array): String { - return StringBuilder(message).append(SEPARATOR).apply { args.take(args.size - 1).forEach { append(it).append(SEPARATOR) }.apply { append(args.last()) } }.toString() + return StringBuilder(message).append( + SEPARATOR).apply { args.take(args.size - 1).forEach { append(it).append( + SEPARATOR) }.apply { append(args.last()) } }.toString() } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ContextExt.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ContextExt.kt new file mode 100644 index 00000000..fd9c292e --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ContextExt.kt @@ -0,0 +1,25 @@ +package nl.entreco.dartsscorecard + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.provider.Settings +import android.support.annotation.ColorRes +import android.support.v4.content.ContextCompat + +fun Context.getColorCompat(@ColorRes color: Int) = ContextCompat.getColor(this, color) + +fun Context.startAppSettings() { + Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).run { + addCategory(Intent.CATEGORY_DEFAULT) + data = Uri.parse("package:$packageName") + startActivity(this) + } +} + +fun Context.checkIsPermissionGranted(permission: String) = + ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED + +fun Context.areAllPermissionsGranted( + vararg permission: String) = permission.all { checkIsPermissionGranted(it) } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdViewModel.kt index 58767a37..f567efee 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdViewModel.kt @@ -10,7 +10,7 @@ import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.domain.ad.FetchPurchasedItemsResponse import nl.entreco.domain.ad.FetchPurchasedItemsUsecase -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.purchases.connect.ConnectToBillingUsecase import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveJobService.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveJobService.kt index f15d0208..5a5ecc36 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveJobService.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveJobService.kt @@ -27,7 +27,7 @@ class ArchiveJobService : JobService() { } private val app by lazy { application as App } - private val component by lazy { app.appComponent.plus(ServiceModule()) } + private val component by lazy { app.appComponent.plus(ServiceModule(this)) } private val archiveStatsUsecase by lazy { component.plus(ArchiveModule()).archive() } private val isWorking = AtomicBoolean(false) @@ -38,7 +38,7 @@ class ArchiveJobService : JobService() { private val notif by lazy { NotificationCompat.Builder(baseContext, CHANNEL_ID) .setOngoing(true) - .setContentTitle(getString(R.string.notif_title)) + .setContentTitle(getString(R.string.archive_notif_title)) .setSmallIcon(R.drawable.ic_stat_name) .setColor(Color.parseColor(NOTIF_COLOR)) .setBadgeIconType(R.mipmap.ic_launcher_foreground) @@ -57,8 +57,8 @@ class ArchiveJobService : JobService() { private fun registerChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val name = getString(R.string.channel_name) - val desc = getString(R.string.channel_description) + val name = getString(R.string.archive_channel_name) + val desc = getString(R.string.archive_channel_description) val importance = NotificationManager.IMPORTANCE_LOW val channel = NotificationChannel(CHANNEL_ID, name, importance) channel.description = desc diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/BaseFragment.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/BaseFragment.kt new file mode 100644 index 00000000..8b2f1762 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/BaseFragment.kt @@ -0,0 +1,43 @@ +package nl.entreco.dartsscorecard.base + +import android.arch.lifecycle.ViewModel +import android.arch.lifecycle.ViewModelProvider +import android.arch.lifecycle.ViewModelProviders +import android.support.annotation.StringRes +import android.support.design.widget.BaseTransientBottomBar +import android.support.design.widget.Snackbar +import android.support.v4.app.Fragment +import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.di.viewmodel.ViewModelComponent +import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule + +abstract class BaseFragment : Fragment() { + + inline fun componentProvider( + mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, + crossinline provider: (ViewModelComponent) -> VM) = lazy(mode) { + + val app = activity!!.application as App + val component = app.appComponent.plus(ViewModelModule(activity!!)) + provider(component) + } + + @Suppress("UNCHECKED_CAST") + inline fun viewModelProvider( + mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, + crossinline provider: () -> VM) = lazy(mode) { + ViewModelProviders.of(this, object : ViewModelProvider.Factory { + override fun create(aClass: Class) = + provider() as T1 + }).get(VM::class.java) + } + + fun showSnackbarMessage(@StringRes resId: Int, @BaseTransientBottomBar.Duration duration: Int) { + view?.let { + val snackbar = Snackbar.make(it, resId, duration) +// val layout = snackbar.view as Snackbar.SnackbarLayout +// layout.setBackgroundColor(context.getColorCompat(R.color.transparent_black)) + snackbar.show() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/DialogHelper.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/DialogHelper.kt index f8c9e224..a4e4f27e 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/DialogHelper.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/DialogHelper.kt @@ -1,14 +1,28 @@ package nl.entreco.dartsscorecard.base +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.support.design.widget.TextInputEditText import android.support.v7.app.AlertDialog +import android.text.InputType +import android.view.LayoutInflater +import android.view.View +import android.widget.RatingBar import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.di.play.Play01Scope +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.domain.Analytics import nl.entreco.domain.model.players.Team +import nl.entreco.domain.repository.RatingPrefRepository import javax.inject.Inject + /** * Created by entreco on 20/02/2018. */ -class DialogHelper @Inject constructor(private val builder: AlertDialog.Builder) { +class DialogHelper @Inject constructor(private val builder: AlertDialog.Builder, @ActivityScope private val ratingPrefRepository: RatingPrefRepository) { fun revanche(previousIndex: Int, teams: Array, select: (Int) -> Unit) { @@ -18,7 +32,8 @@ class DialogHelper @Inject constructor(private val builder: AlertDialog.Builder) var selectedIndex = previousIndex builder .setTitle(R.string.select_starting_team) - .setSingleChoiceItems(teams.map { it.toString() }.toTypedArray(), previousIndex) { _, which -> + .setSingleChoiceItems(teams.map { it.toString() }.toTypedArray(), + previousIndex) { _, which -> selectedIndex = which } .setPositiveButton(android.R.string.ok) { dialog, _ -> @@ -35,4 +50,68 @@ class DialogHelper @Inject constructor(private val builder: AlertDialog.Builder) private fun onlyOneTeam(teams: Array) = teams.size == 1 private fun moreThanOneTeam(teams: Array) = teams.size > 1 + + fun showStreamDialog(done: (String) -> Unit, cancel: () -> Unit) { + val view = createCodeEditText() + val et = view.findViewById(R.id.enter) + et.maxLines = 1 + et.inputType = InputType.TYPE_CLASS_NUMBER + + builder + .setView(view) + .setPositiveButton(R.string.live_stream_connect) { dialog, _ -> + done(et.text.toString()) + dialog.dismiss() + } + .setNegativeButton(R.string.cancel) { dialog, _ -> + cancel() + dialog.dismiss() + } + .create() + .show() + } + + private fun createCodeEditText(): View { + return LayoutInflater.from(builder.context) + .inflate(R.layout.dialog_connect_stream, null, false) + } + + fun showRatingDialog() { + builder + .setTitle(R.string.rating_title) + .setMessage(R.string.rating_message) + .setPositiveButton(android.R.string.ok) { dialog, _ -> + dialog.dismiss() + ratingPrefRepository.neverAskAgain() + tryLaunchMarket(builder.context) + } + .setNegativeButton(R.string.rating_not_now) { dialog, _ -> + dialog.dismiss() + } + .setNeutralButton(R.string.rating_never_ask_again) { dialog, _ -> + dialog.dismiss() + ratingPrefRepository.neverAskAgain() + } + .create() + .show() + } + + private fun tryLaunchMarket(context: Context) { + val clean = context.packageName.removeSuffix(".dev") + val uri = Uri.parse("market://details?id=$clean") + val goToMarket = Intent(Intent.ACTION_VIEW, uri) + // To count with Play market backstack, After pressing back button, + // to taken back to our application, we need to add following flags to intent. + goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY or + Intent.FLAG_ACTIVITY_NEW_DOCUMENT or + Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + try { + context.startActivity(goToMarket) + } catch (e: ActivityNotFoundException) { + context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse( + "http://play.google.com/store/apps/details?id=$clean"))) + } catch (e: ActivityNotFoundException) { + + } + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/PermissionHelper.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/PermissionHelper.kt new file mode 100644 index 00000000..14ccb80d --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/PermissionHelper.kt @@ -0,0 +1,61 @@ +package nl.entreco.dartsscorecard.base + +import android.Manifest +import android.content.ActivityNotFoundException +import android.content.Context +import android.content.pm.PackageManager +import android.support.design.widget.Snackbar +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.areAllPermissionsGranted +import nl.entreco.dartsscorecard.di.streaming.StreamScope +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.dartsscorecard.play.stream.StreamFragment +import nl.entreco.dartsscorecard.startAppSettings +import javax.inject.Inject + +class PermissionHelper @Inject constructor( + @ActivityScope private val context: Context, + @StreamScope private val streamFragment: StreamFragment +) { + + companion object { + internal const val CHECK_PERMISSIONS_AND_CONNECT_REQUEST_CODE = 1 + private val NECESSARY_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, + Manifest.permission.RECORD_AUDIO) + } + + fun checkStreamingPermissionsAndConnect(done: () -> Unit) { + if (context.areAllPermissionsGranted(*NECESSARY_PERMISSIONS)) { + done() + } else { + streamFragment.requestPermissions( + arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO), + CHECK_PERMISSIONS_AND_CONNECT_REQUEST_CODE) + } + } + + fun onStreamingPermissionResult(grantResults: IntArray, done: () -> Unit) { + val grantResult = grantResults.isNotEmpty() && grantResults.all { it == PackageManager.PERMISSION_GRANTED } + if (grantResult) { + checkStreamingPermissionsAndConnect(done) + } else { + showNoPermissionsSnackbar() + } + } + + private fun showNoPermissionsSnackbar() { + streamFragment.view?.let { view -> + Snackbar.make(view, R.string.msg_permissions, Snackbar.LENGTH_LONG) + .setAction(R.string.action_settings) { + try { + context.startAppSettings() + } catch (e: ActivityNotFoundException) { + streamFragment.showSnackbarMessage( + R.string.error_permissions_couldnt_start_settings, + Snackbar.LENGTH_LONG) + } + } + .show() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/Styler.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/Styler.kt index 941cb988..86fe1c8c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/Styler.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/Styler.kt @@ -11,24 +11,29 @@ import javax.inject.Inject */ class Styler @Inject constructor(private val prefs: SharedPreferences, private val activity: Activity) { - enum class Style(@StyleRes val style: Int) { - PDC_2018(R.style.Pdc_2018), - BDO_2018(R.style.Bdo_2018), - BDO(R.style.Bdo), - PDC(R.style.Pdc); + enum class Style(val style: String) { + PDC_2018("Pdc_2018"), + BDO_2018("Bdo_2018"), + BDO("Bdo"), + PDC("Pdc"); } fun get(): Int { - return prefs.getInt("curStyle", Style.PDC_2018.style) + return when(prefs.getString("curStyle", Style.PDC_2018.style)){ + Style.PDC_2018.style -> R.style.Pdc_2018 + Style.BDO_2018.style -> R.style.Bdo_2018 + Style.PDC.style -> R.style.Pdc + Style.BDO.style -> R.style.Bdo + else -> R.style.Pdc_2018 + } } fun switch() { - val curStyle = prefs.getInt("curStyle", Style.PDC_2018.style) - prefs.edit().putInt("curStyle", swap(curStyle)).apply() + prefs.edit().putString("curStyle", swap(get())).apply() activity.recreate() } - private fun swap(style: Int): Int { + private fun swap(style: Int): String { return when (style) { R.style.Pdc_2018 -> Style.BDO_2018.style R.style.Bdo_2018 -> Style.PDC.style diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallback.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallback.kt index 5e8b46a4..26f64b30 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallback.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallback.kt @@ -22,10 +22,6 @@ abstract class SwipeToDeleteCallback(context: Context) : ItemTouchHelper.SimpleC private val background = ColorDrawable() private val backgroundColor = Color.parseColor("#D9534F") // Pale red - override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, target: RecyclerView.ViewHolder?): Boolean { - return false - } - override fun onChildDraw(canvas: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) { val itemView = viewHolder.itemView val itemHeight = itemView.bottom - itemView.top diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/ViewModelActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/ViewModelActivity.kt index 44413956..b4aaf8ac 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/ViewModelActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/ViewModelActivity.kt @@ -14,7 +14,7 @@ import nl.entreco.dartsscorecard.App import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.di.viewmodel.ViewModelComponent import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule -import nl.entreco.dartsscorecard.wtf.WtfActivity +import nl.entreco.dartsscorecard.faq.WtfActivity /** * Created by Entreco on 14/11/2017. @@ -28,7 +28,7 @@ abstract class ViewModelActivity : AppCompatActivity() { @Suppress("UNCHECKED_CAST") - inline fun ViewModelActivity.viewModelProvider( + inline fun viewModelProvider( mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, crossinline provider: () -> VM) = lazy(mode) { ViewModelProviders.of(this, object : ViewModelProvider.Factory { @@ -37,7 +37,7 @@ abstract class ViewModelActivity : AppCompatActivity() { }).get(VM::class.java) } - inline fun ViewModelActivity.componentProvider( + inline fun componentProvider( mode: LazyThreadSafetyMode = LazyThreadSafetyMode.NONE, crossinline provider: (ViewModelComponent) -> VM) = lazy(mode) { val component = app.appComponent.plus(ViewModelModule(this)) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaActivity.kt index 945e6ff8..092eed29 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaActivity.kt @@ -106,7 +106,6 @@ class BetaActivity : ViewModelActivity(), DonateCallback, BetaAnimator.Swapper { recyclerView.setItemViewCacheSize(20) recyclerView.layoutManager = GridLayoutManager(binding.root.context, 2) recyclerView.itemAnimator = DefaultItemAnimator() - recyclerView.isDrawingCacheEnabled = true recyclerView.adapter = adapter } @@ -131,7 +130,8 @@ class BetaActivity : ViewModelActivity(), DonateCallback, BetaAnimator.Swapper { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when { donateOk(requestCode, resultCode, data) -> donateViewModel.onMakeDonationSuccess(data) - requestCode == REQ_CODE_DONATE -> donateViewModel.onMakeDonationFailed() + resultCode == Activity.RESULT_CANCELED -> donateViewModel.onMakeDonationFailed(true) + requestCode == REQ_CODE_DONATE -> donateViewModel.onMakeDonationFailed(false) else -> super.onActivityResult(requestCode, resultCode, data) } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAdapter.kt index 5e56eeed..74f1b4ae 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAdapter.kt @@ -9,8 +9,8 @@ import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.TestableAdapter import nl.entreco.dartsscorecard.databinding.BetaViewBinding import nl.entreco.domain.beta.Feature -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import java.util.* import javax.inject.Inject diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAnimator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAnimator.kt index 985214bb..0c364cab 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAnimator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaAnimator.kt @@ -28,7 +28,7 @@ class BetaAnimator(binding: ActivityBetaBinding) { } init { - appBar.addOnOffsetChangedListener { appBarLayout, verticalOffset -> animator.onOffsetChanged(appBarLayout, verticalOffset) } + appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, slideOffset -> animator.onOffsetChanged(appBarLayout, slideOffset) }) behaviour.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { animator.onSlide(slideOffset) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaBindings.kt index d5b9ac33..729ec90c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaBindings.kt @@ -2,13 +2,12 @@ package nl.entreco.dartsscorecard.beta import android.databinding.BindingAdapter import android.net.Uri -import android.os.Build import android.text.Html import android.view.View import android.view.animation.AccelerateDecelerateInterpolator import android.widget.ImageView import android.widget.TextView -import nl.entreco.dartsscorecard.di.glide.GlideApp +import nl.entreco.shared.libs.GlideApp /** * Created by entreco on 03/02/2018. @@ -26,13 +25,13 @@ object BetaBindings { } } - @JvmStatic @BindingAdapter("progress") fun animateProgress(view: View, oldProgress: Float, progress: Float) { view.pivotX = 0F view.scaleX = oldProgress - view.animate().scaleX(progress).setDuration(duration).setStartDelay(startDelay).setInterpolator(AccelerateDecelerateInterpolator()).start() + view.animate().scaleX(progress).setDuration(duration).setStartDelay(startDelay) + .setInterpolator(AccelerateDecelerateInterpolator()).start() } @Suppress("DEPRECATION") @@ -40,11 +39,7 @@ object BetaBindings { @BindingAdapter("textWithTags") fun setTextWithTags(view: TextView, message: String?) { if (message != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - view.text = Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT) - } else { - view.text = Html.fromHtml(message) - } + view.text = Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT) } } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaModel.kt index edef2a9f..d0f5fe7a 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaModel.kt @@ -23,7 +23,7 @@ class BetaModel(val feature: Feature) { private fun format(value: Int): String { return when { value < 1000 -> "$value" - else -> "${value / 1000}k" + else -> "%.1f".format(value / 1000.0).removeSuffix(".0") + "k" } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModel.kt index f075aa86..ace10c7f 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModel.kt @@ -92,8 +92,8 @@ class DonateViewModel @Inject constructor( private fun donationWithId(response: ConsumeDonationResponse) = donations.firstOrNull { it.sku == response.productId } - fun onMakeDonationFailed() { - analytics.trackPurchaseFailed(productId, "ActivityResult failed") + fun onMakeDonationFailed(cancelled: Boolean) { + analytics.trackPurchaseFailed(productId, if(cancelled) "Donation ActivityResult cancelled" else "Donation ActivityResult failed") loading.set(false) productId = "" requiresConsumption.set(false) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppModule.kt index f0fbcfaf..3bcaad5b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppModule.kt @@ -1,20 +1,22 @@ package nl.entreco.dartsscorecard.di.application import android.arch.persistence.room.Room +import com.google.firebase.database.FirebaseDatabase import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.remoteconfig.FirebaseRemoteConfig import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.App import nl.entreco.dartsscorecard.BuildConfig -import nl.entreco.dartsscorecard.DscLogger +import nl.entreco.dartsscorecard.AppLogger import nl.entreco.data.analytics.FirebaseAnalytics import nl.entreco.data.db.DscDatabase import nl.entreco.domain.Analytics -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import javax.inject.Named import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings import nl.entreco.dartsscorecard.R +import java.util.* /** @@ -36,7 +38,7 @@ class AppModule(val app: App) { @Provides @ApplicationScope fun provideLogger(): Logger { - return DscLogger("Dsc") + return AppLogger("Dsc") } @Provides @@ -53,6 +55,19 @@ class AppModule(val app: App) { return FirebaseFirestore.getInstance() } + @Provides + @ApplicationScope + fun provideFirebaseDatabase(): FirebaseDatabase { + return FirebaseDatabase.getInstance() + } + + @Provides + @ApplicationScope + @Named("uuid") + fun provideUuid() : String { + return UUID.randomUUID().toString() + } + @Provides @ApplicationScope fun provideRemoteConfig(): FirebaseRemoteConfig { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveModule.kt index 71148b80..46e90dcd 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveModule.kt @@ -5,7 +5,6 @@ import dagger.Provides import nl.entreco.data.db.DscDatabase import nl.entreco.data.db.profile.ArchiveServiceRepository import nl.entreco.data.db.profile.ArchiveStatMapper -import nl.entreco.domain.common.log.Logger import nl.entreco.domain.repository.ArchiveRepository diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfComponent.kt similarity index 55% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfComponent.kt index b3a7698c..11c54b24 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfComponent.kt @@ -1,8 +1,8 @@ -package nl.entreco.dartsscorecard.di.wtf +package nl.entreco.dartsscorecard.di.faq import dagger.Subcomponent -import nl.entreco.dartsscorecard.wtf.WtfAdapter -import nl.entreco.dartsscorecard.wtf.WtfViewModel +import nl.entreco.dartsscorecard.faq.WtfAdapter +import nl.entreco.dartsscorecard.faq.WtfViewModel @WtfScope @Subcomponent(modules = [(WtfModule::class)]) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfModule.kt similarity index 52% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfModule.kt index 60db3918..85aed697 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfModule.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.di.wtf +package nl.entreco.dartsscorecard.di.faq import dagger.Module diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfScope.kt similarity index 70% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfScope.kt index 60b9eb56..bbb8e809 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/faq/WtfScope.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.di.wtf +package nl.entreco.dartsscorecard.di.faq import javax.inject.Scope diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Component.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Component.kt index 491fd0a5..d670a443 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Component.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Component.kt @@ -6,6 +6,7 @@ import nl.entreco.dartsscorecard.play.Play01ViewModel import nl.entreco.dartsscorecard.play.input.InputViewModel import nl.entreco.dartsscorecard.play.score.ScoreViewModel import nl.entreco.dartsscorecard.play.live.LiveStatViewModel +import nl.entreco.dartsscorecard.play.stream.ControlStreamViewModel import nl.entreco.domain.play.finish.GetFinishUsecase /** @@ -17,6 +18,7 @@ interface Play01Component { fun viewModel(): Play01ViewModel fun navigator(): Play01Navigator fun scoreViewModel(): ScoreViewModel + fun streamViewModel(): ControlStreamViewModel fun inputViewModel(): InputViewModel fun statViewModel(): LiveStatViewModel fun finishUsecase(): GetFinishUsecase diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Module.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Module.kt index c86da253..0a5b7296 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Module.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/play/Play01Module.kt @@ -3,7 +3,6 @@ package nl.entreco.dartsscorecard.di.play import android.content.ComponentName import android.content.Context import android.media.SoundPool -import android.support.v7.app.AlertDialog import com.google.firebase.remoteconfig.FirebaseRemoteConfig import dagger.Module import dagger.Provides @@ -14,10 +13,12 @@ import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.dartsscorecard.play.Play01Activity import nl.entreco.data.description.RemoteMatchDescriptionRepository import nl.entreco.data.prefs.SharedAudioPrefRepo +import nl.entreco.data.prefs.SharedRatingPrefRepo import nl.entreco.data.sound.LocalSoundRepository import nl.entreco.data.sound.SoundMapper import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.repository.MatchDescriptionRepository +import nl.entreco.domain.repository.RatingPrefRepository import nl.entreco.domain.repository.SoundRepository /** @@ -34,12 +35,6 @@ class Play01Module(private val activity: Play01Activity) { return activity } - @Provides - @Play01Scope - fun provideAlertDialogBuilder(@ActivityScope context: Context): AlertDialog.Builder { - return AlertDialog.Builder(context) - } - @Provides @Play01Scope fun provideSoundMapper(): SoundMapper { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceComponent.kt index 4eb4dcf5..f4ee5703 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceComponent.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceComponent.kt @@ -3,10 +3,13 @@ package nl.entreco.dartsscorecard.di.service import dagger.Subcomponent import nl.entreco.dartsscorecard.di.archive.ArchiveComponent import nl.entreco.dartsscorecard.di.archive.ArchiveModule +import nl.entreco.dartsscorecard.di.streaming.StreamingComponent +import nl.entreco.dartsscorecard.di.streaming.StreamingModule import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule @ServiceScope @Subcomponent(modules = [(ServiceModule::class), (ThreadingModule::class)]) interface ServiceComponent { fun plus(module: ArchiveModule): ArchiveComponent + fun plus(module: StreamingModule): StreamingComponent } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceModule.kt index c2792561..50b318d7 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceModule.kt @@ -1,6 +1,48 @@ package nl.entreco.dartsscorecard.di.service +import android.app.Service +import android.content.Context +import com.google.firebase.database.FirebaseDatabase import dagger.Module +import dagger.Provides +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.data.stream.FirebaseAnswersRepository +import nl.entreco.data.stream.FirebaseIceRepository +import nl.entreco.data.stream.FirebaseOffersRepository +import nl.entreco.domain.repository.AnswersRepository +import nl.entreco.domain.repository.IceRepository +import nl.entreco.domain.repository.OffersRepository +import nl.entreco.shared.log.Logger +import javax.inject.Named @Module -class ServiceModule \ No newline at end of file +class ServiceModule(private val service: Service) { + + @Provides + @ServiceScope + fun context(): Context = service + + @Provides + @ServiceScope + fun provideIceRepository(@ApplicationScope db: FirebaseDatabase, + @ApplicationScope logger: Logger, + @ApplicationScope @Named("uuid") uuid: String): IceRepository { + return FirebaseIceRepository(db, logger, uuid) + } + + @Provides + @ServiceScope + fun provideOffersRepository(@ApplicationScope db: FirebaseDatabase, + @ApplicationScope logger: Logger, + @ApplicationScope @Named("uuid") uuid: String): OffersRepository { + return FirebaseOffersRepository(db, logger, uuid) + } + + @Provides + @ServiceScope + fun provideAnswersRepository(@ApplicationScope db: FirebaseDatabase, + @ApplicationScope logger: Logger, + @ApplicationScope @Named("uuid") uuid: String): AnswersRepository { + return FirebaseAnswersRepository(db, logger, uuid) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamComponent.kt new file mode 100644 index 00000000..0250374c --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamComponent.kt @@ -0,0 +1,12 @@ +package nl.entreco.dartsscorecard.di.streaming + +import dagger.Subcomponent +import nl.entreco.dartsscorecard.base.PermissionHelper +import nl.entreco.dartsscorecard.play.stream.StreamViewModel + +@StreamScope +@Subcomponent(modules = [(StreamModule::class)]) +interface StreamComponent { + fun viewModel(): StreamViewModel + fun permissionHelper(): PermissionHelper +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamModule.kt new file mode 100644 index 00000000..e13095c3 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamModule.kt @@ -0,0 +1,42 @@ +package nl.entreco.dartsscorecard.di.streaming + +import dagger.Module +import dagger.Provides +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.play.stream.StreamFragment +import nl.entreco.dartsscorecard.streaming.WebRtcController +import nl.entreco.shared.log.Logger +import org.webrtc.CameraVideoCapturer +import org.webrtc.SurfaceViewRenderer +import javax.inject.Named + +@Module +class StreamModule(private val fragment: StreamFragment, + private val listener: StreamFragment.Listener?, + private val localVideoView: SurfaceViewRenderer){ + + @Provides + @StreamScope + fun provideStreamingFragment() : StreamFragment { + return fragment + } + + @Provides + @StreamScope + fun provideCameraSwitchHandler() : CameraVideoCapturer.CameraSwitchHandler { + return fragment + } + + @Provides + @StreamScope + fun provideFragmentListener() : StreamFragment.Listener? { + return listener + } + + @Provides + @StreamScope + @Named("local") + fun provideLocalVideoView() : SurfaceViewRenderer { + return localVideoView + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamScope.kt new file mode 100644 index 00000000..a2def613 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamScope.kt @@ -0,0 +1,7 @@ +package nl.entreco.dartsscorecard.di.streaming + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class StreamScope \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingComponent.kt new file mode 100644 index 00000000..37d82ad2 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingComponent.kt @@ -0,0 +1,12 @@ +package nl.entreco.dartsscorecard.di.streaming + +import dagger.Subcomponent +import nl.entreco.dartsscorecard.streaming.ReceivingController +import nl.entreco.dartsscorecard.streaming.StreamingController + +@StreamingScope +@Subcomponent(modules = [(StreamingModule::class)]) +interface StreamingComponent { + fun streamingController(): StreamingController + fun receivingController(): ReceivingController +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingModule.kt new file mode 100644 index 00000000..1ed726ab --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingModule.kt @@ -0,0 +1,82 @@ +package nl.entreco.dartsscorecard.di.streaming + +import android.content.Context +import dagger.Module +import dagger.Provides +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.service.ServiceScope +import nl.entreco.dartsscorecard.streaming.WebRtcController +import nl.entreco.domain.streaming.ice.FetchIceServerUsecase +import nl.entreco.domain.streaming.ice.ListenForIceCandidatesUsecase +import nl.entreco.domain.streaming.p2p.RemoveIceCandidateUsecase +import nl.entreco.domain.streaming.p2p.SendIceCandidateUsecase +import nl.entreco.shared.log.Logger +import org.webrtc.* +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import java.util.concurrent.atomic.AtomicBoolean + +@Module +class StreamingModule { + + private val factoryInitialized = AtomicBoolean(false) + + @Provides + @StreamingScope + fun provideSingleThreadExecutor(): ExecutorService { + return Executors.newSingleThreadExecutor() + } + + @Provides + @StreamingScope + fun provideWebRtcController(@ApplicationScope logger: Logger, + @StreamingScope singleThread : ExecutorService, + @ServiceScope sendIceCandidateUsecase: SendIceCandidateUsecase, + @ServiceScope removeIceCandidateUsecase: RemoveIceCandidateUsecase, + @ServiceScope fetchIceServersUsecase: FetchIceServerUsecase, + @ServiceScope listenForIceServersUsecase: ListenForIceCandidatesUsecase, + @StreamingScope peerConnectionFactory: PeerConnectionFactory + ): WebRtcController { + return WebRtcController(logger, singleThread, sendIceCandidateUsecase, removeIceCandidateUsecase, + fetchIceServersUsecase, listenForIceServersUsecase, peerConnectionFactory) + } + + @Provides + @StreamingScope + fun providePeerConnectionFactory(@ServiceScope context: Context): PeerConnectionFactory { + if (!factoryInitialized.get()) { + factoryInitialized.set(true) + PeerConnectionFactory.initialize( + PeerConnectionFactory.InitializationOptions.builder(context) + .setEnableInternalTracer(false) // Enabling tracker may cause crashes + .setEnableVideoHwAcceleration(true) + .createInitializationOptions()) + } + + val options = PeerConnectionFactory.Options() + return PeerConnectionFactory.builder().setOptions(options).createPeerConnectionFactory() + } + + @Provides + @StreamingScope + fun provideVideoCameraCapturer(@ServiceScope context: Context): CameraVideoCapturer? { + val enumerator = if (isCamera2Supported(context)) Camera2Enumerator( + context) else Camera1Enumerator() + return createCameraCapturerWithFrontAsDefault(enumerator) + } + + private fun isCamera2Supported(context: Context): Boolean { + return Camera2Enumerator.isSupported(context) + } + + private fun createCameraCapturerWithFrontAsDefault( + enumerator: CameraEnumerator): CameraVideoCapturer? { + val (frontFacingCameras, backFacingAndOtherCameras) = enumerator.deviceNames + .partition { enumerator.isFrontFacing(it) } + + return (frontFacingCameras.firstOrNull() ?: backFacingAndOtherCameras.firstOrNull())?.let { + enumerator.createCapturer(it, null) + } + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingScope.kt new file mode 100644 index 00000000..8da1ee21 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/streaming/StreamingScope.kt @@ -0,0 +1,7 @@ +package nl.entreco.dartsscorecard.di.streaming + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class StreamingScope \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchComponent.kt new file mode 100644 index 00000000..0abbabfe --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchComponent.kt @@ -0,0 +1,12 @@ +package nl.entreco.dartsscorecard.di.tv + +import dagger.Subcomponent +import nl.entreco.dartsscorecard.tv.launch.LaunchTvNavigator +import nl.entreco.dartsscorecard.tv.launch.LaunchTvViewModel + +@TvScope +@Subcomponent(modules = [(TvLaunchModule::class)]) +interface TvLaunchComponent { + fun viewModel(): LaunchTvViewModel + fun navigator(): LaunchTvNavigator +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchModule.kt new file mode 100644 index 00000000..daa3950d --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvLaunchModule.kt @@ -0,0 +1,16 @@ +package nl.entreco.dartsscorecard.di.tv + +import dagger.Module +import dagger.Provides +import org.webrtc.SurfaceViewRenderer +import javax.inject.Named + +@Module +class TvLaunchModule(private val remoteVideoView: SurfaceViewRenderer) { + @Provides + @TvScope + @Named("remote") + fun provideRemoteVideoView(): SurfaceViewRenderer { + return remoteVideoView + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvScope.kt new file mode 100644 index 00000000..660029c4 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/tv/TvScope.kt @@ -0,0 +1,7 @@ +package nl.entreco.dartsscorecard.di.tv + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class TvScope \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelComponent.kt index 433c0374..edd058b0 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelComponent.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelComponent.kt @@ -17,8 +17,13 @@ import nl.entreco.dartsscorecard.di.viewmodel.api.FaqApiModule import nl.entreco.dartsscorecard.di.viewmodel.api.FeatureApiModule import nl.entreco.dartsscorecard.di.viewmodel.db.* import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule -import nl.entreco.dartsscorecard.di.wtf.WtfComponent -import nl.entreco.dartsscorecard.di.wtf.WtfModule +import nl.entreco.dartsscorecard.di.faq.WtfComponent +import nl.entreco.dartsscorecard.di.faq.WtfModule +import nl.entreco.dartsscorecard.di.streaming.StreamComponent +import nl.entreco.dartsscorecard.di.streaming.StreamModule +import nl.entreco.dartsscorecard.di.tv.TvLaunchComponent +import nl.entreco.dartsscorecard.di.tv.TvLaunchModule +import nl.entreco.dartsscorecard.di.viewmodel.tv.TvModule /** * Created by Entreco on 14/11/2017. @@ -26,12 +31,12 @@ import nl.entreco.dartsscorecard.di.wtf.WtfModule @ActivityScope @Subcomponent(modules = [(ViewModelModule::class), (ThreadingModule::class), (AdModule::class), (GameDbModule::class), (PlayerDbModule::class), (TurnDbModule::class), - (MetaDbModule::class), (StatDbModule::class), (FeatureApiModule::class), (FaqApiModule::class)]) + (MetaDbModule::class), (StatDbModule::class), (FeatureApiModule::class), + (FaqApiModule::class), (TvModule::class)]) interface ViewModelComponent { // Where can this be used fun plus(module: LaunchModule): LaunchComponent - fun plus(module: BetaModule): BetaComponent fun plus(module: WtfModule): WtfComponent fun plus(module: Setup01Module): Setup01Component @@ -40,4 +45,6 @@ interface ViewModelComponent { fun plus(module: SelectProfileModule): SelectProfileComponent fun plus(module: ProfileModule): ProfileComponent fun plus(module: EditPlayerNameModule): EditPlayerNameComponent + fun plus(module: TvLaunchModule): TvLaunchComponent + fun plus(module: StreamModule) : StreamComponent } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModule.kt index e80963ee..5293550f 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModule.kt @@ -4,21 +4,39 @@ import android.arch.lifecycle.Lifecycle import android.content.Context import android.content.res.Resources import android.support.v4.app.FragmentActivity +import android.support.v4.app.FragmentManager +import android.support.v7.app.AlertDialog +import com.google.firebase.database.FirebaseDatabase import dagger.Module import dagger.Provides +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.play.Play01Scope import nl.entreco.data.billing.BillingServiceConnection import nl.entreco.data.billing.PlayStoreBillingRepository +import nl.entreco.data.prefs.SharedRatingPrefRepo +import nl.entreco.data.stream.FirebaseSignallingRepository import nl.entreco.domain.repository.BillingRepository +import nl.entreco.domain.repository.RatingPrefRepository +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.log.Logger +import javax.inject.Named /** * Created by Entreco on 14/11/2017. */ @Module class ViewModelModule(private val activity: FragmentActivity) { + + private val prefs = activity.getSharedPreferences("rating", Context.MODE_PRIVATE) + @Provides @ActivityScope fun context(): Context = activity + @Provides + @ActivityScope + fun fragmentManager(): FragmentManager = activity.supportFragmentManager + @Provides @ActivityScope fun resources(): Resources = activity.resources @@ -29,6 +47,18 @@ class ViewModelModule(private val activity: FragmentActivity) { return activity.lifecycle } + @Provides + @ActivityScope + fun provideRatingPreferences(): RatingPrefRepository { + return SharedRatingPrefRepo(prefs) + } + + @Provides + @ActivityScope + fun provideAlertDialogBuilder(@ActivityScope context: Context): AlertDialog.Builder { + return AlertDialog.Builder(context) + } + @Provides @ActivityScope fun provideServiceConnection(): BillingServiceConnection { @@ -40,4 +70,13 @@ class ViewModelModule(private val activity: FragmentActivity) { fun provideBillingRepository(@ActivityScope context: Context, @ActivityScope serviceConnection: BillingServiceConnection): BillingRepository { return PlayStoreBillingRepository(context, serviceConnection) } + + @Provides + @ActivityScope + fun provideSignallingRepository(@ApplicationScope db: FirebaseDatabase, + @ApplicationScope logger: Logger, + @ApplicationScope @Named( + "uuid") uuid: String): SignallingRepository { + return FirebaseSignallingRepository(db, logger, uuid) + } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt index 98147d80..42ac5ac8 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt @@ -4,7 +4,7 @@ import com.google.firebase.firestore.FirebaseFirestore import dagger.Module import dagger.Provides import nl.entreco.data.wtf.RemoteWtfRepository -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.repository.WtfRepository @Module diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModule.kt index 4c779770..8083911c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModule.kt @@ -4,7 +4,7 @@ import com.google.firebase.firestore.FirebaseFirestore import dagger.Module import dagger.Provides import nl.entreco.data.api.beta.RemoteFeatureRepository -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.repository.FeatureRepository /** diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/PlayerDbModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/PlayerDbModule.kt index 4f0ea736..0a9048fb 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/PlayerDbModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/PlayerDbModule.kt @@ -25,5 +25,4 @@ class PlayerDbModule { fun providePlayerRepository(db: DscDatabase, mapper: PlayerMapper): PlayerRepository { return LocalPlayerRepository(db, mapper) } - } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModule.kt index 01950632..86e1c141 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModule.kt @@ -4,10 +4,10 @@ import android.os.Handler import android.os.Looper import dagger.Module import dagger.Provides -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.BgExecutor -import nl.entreco.domain.common.executors.FgExecutor -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.BgExecutor +import nl.entreco.shared.threading.FgExecutor +import nl.entreco.shared.threading.Foreground /** * Created by Entreco on 17/12/2017. diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/tv/TvModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/tv/TvModule.kt new file mode 100644 index 00000000..7c865c10 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/tv/TvModule.kt @@ -0,0 +1,11 @@ +package nl.entreco.dartsscorecard.di.viewmodel.tv + +import dagger.Module +import dagger.Provides +import nl.entreco.dartsscorecard.di.tv.TvScope +import org.webrtc.SurfaceViewRenderer +import javax.inject.Named + + +@Module +class TvModule \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfActivity.kt similarity index 90% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfActivity.kt index 45b473e3..32b6401d 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfActivity.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.content.Context import android.content.Intent @@ -14,10 +14,8 @@ import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.ViewModelActivity import nl.entreco.dartsscorecard.databinding.ActivityWtfBinding import nl.entreco.dartsscorecard.databinding.SearchbarBinding -import nl.entreco.dartsscorecard.di.wtf.WtfComponent -import nl.entreco.dartsscorecard.di.wtf.WtfModule -import android.support.v4.content.ContextCompat -import android.view.WindowManager +import nl.entreco.dartsscorecard.di.faq.WtfComponent +import nl.entreco.dartsscorecard.di.faq.WtfModule import android.view.inputmethod.InputMethodManager @@ -33,12 +31,12 @@ class WtfActivity : ViewModelActivity() { object : JellyListener() { override fun onCancelIconClicked() { val searchField = searchBinding.searchField - if (searchField.text.isEmpty()) { + if (searchField.text?.isEmpty() == true) { binding.includeToolbar.toolbar.collapse() val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(searchField.windowToken, 0) } else { - searchField.text.clear() + searchField.text?.clear() } } } @@ -68,7 +66,6 @@ class WtfActivity : ViewModelActivity() { recyclerView.setItemViewCacheSize(20) recyclerView.layoutManager = GridLayoutManager(binding.root.context, 1) recyclerView.itemAnimator = DefaultItemAnimator() - recyclerView.isDrawingCacheEnabled = true recyclerView.adapter = adapter } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfAdapter.kt similarity index 96% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfAdapter.kt index ba0bc25a..903a2351 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfAdapter.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.arch.lifecycle.Observer import android.databinding.DataBindingUtil @@ -8,8 +8,8 @@ import android.view.ViewGroup import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.TestableAdapter import nl.entreco.dartsscorecard.databinding.WtfViewBinding -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.wtf.SubmitViewedItemRequest import nl.entreco.domain.wtf.SubmitViewedItemUsecase import nl.entreco.domain.wtf.WtfItem diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfDiffCalculator.kt similarity index 94% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfDiffCalculator.kt index 4dfab971..1731d42b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfDiffCalculator.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.support.v7.util.DiffUtil import nl.entreco.domain.wtf.WtfItem diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfModel.kt similarity index 97% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfModel.kt index 1ee12716..d9d74901 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfModel.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.content.ActivityNotFoundException import android.content.Intent diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfSearchable.kt similarity index 62% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfSearchable.kt index 6d7682b1..07a218d6 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfSearchable.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq interface WtfSearchable { fun search(text: CharSequence) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfToggler.kt similarity index 70% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfToggler.kt index a3c1205e..da8396a9 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfToggler.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import nl.entreco.domain.wtf.WtfItem diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfView.kt similarity index 91% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfView.kt index f95da599..1340cf1b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfView.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.support.v7.widget.RecyclerView import nl.entreco.dartsscorecard.databinding.WtfViewBinding diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfViewModel.kt similarity index 86% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfViewModel.kt index 1b2c9c11..e2bba1d8 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/faq/WtfViewModel.kt @@ -1,11 +1,9 @@ -package nl.entreco.dartsscorecard.wtf +package nl.entreco.dartsscorecard.faq import android.arch.lifecycle.LifecycleOwner import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.Observer import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.beta.Feature -import nl.entreco.domain.purchases.connect.SubscribeToFeaturesUsecase import nl.entreco.domain.wtf.SubscribeToWtfsUsecase import nl.entreco.domain.wtf.WtfItem import javax.inject.Inject diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt index 9b6fb7df..683b94d3 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt @@ -7,7 +7,6 @@ import nl.entreco.dartsscorecard.beta.BetaActivity import nl.entreco.dartsscorecard.play.Play01Activity import nl.entreco.dartsscorecard.profile.select.SelectProfileActivity import nl.entreco.dartsscorecard.setup.Setup01Activity -import nl.entreco.dartsscorecard.wtf.WtfActivity import nl.entreco.domain.launch.FetchLatestGameResponse import nl.entreco.domain.launch.RetrieveLatestGameUsecase import nl.entreco.domain.setup.game.CreateGameResponse diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Activity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Activity.kt index 202883ef..eaeceb51 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Activity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Activity.kt @@ -14,33 +14,42 @@ import nl.entreco.dartsscorecard.databinding.ActivityPlay01Binding import nl.entreco.dartsscorecard.di.play.Play01Component import nl.entreco.dartsscorecard.di.play.Play01Module import nl.entreco.dartsscorecard.play.input.InputViewModel -import nl.entreco.dartsscorecard.play.score.ScoreViewModel import nl.entreco.dartsscorecard.play.live.LiveStatViewModel +import nl.entreco.dartsscorecard.play.score.ScoreViewModel +import nl.entreco.dartsscorecard.play.stream.StreamFragment +import nl.entreco.dartsscorecard.play.stream.ControlStreamViewModel import nl.entreco.domain.play.finish.GetFinishUsecase import nl.entreco.domain.play.start.Play01Request import nl.entreco.domain.setup.game.CreateGameResponse +import nl.entreco.domain.streaming.Connected +import nl.entreco.domain.streaming.ConnectionState +import org.webrtc.PeerConnection -class Play01Activity : ViewModelActivity() { +class Play01Activity : ViewModelActivity(), StreamFragment.Listener { + private lateinit var binding: ActivityPlay01Binding private val component: Play01Component by componentProvider { it.plus(Play01Module(this)) } private val viewModel: Play01ViewModel by viewModelProvider { component.viewModel() } private val scoreViewModel: ScoreViewModel by viewModelProvider { component.scoreViewModel() } + private val controlStreamViewModel: ControlStreamViewModel by viewModelProvider { component.streamViewModel() } private val inputViewModel: InputViewModel by viewModelProvider { component.inputViewModel() } private val statViewModel: LiveStatViewModel by viewModelProvider { component.statViewModel() } private val finishUsecase: GetFinishUsecase by componentProvider { component.finishUsecase() } private val navigator: Play01Navigator by lazy { component.navigator() } + private val animator: Play01Animator by lazy { Play01Animator(binding) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - val binding = DataBindingUtil.setContentView(this, R.layout.activity_play_01) + binding = DataBindingUtil.setContentView(this, R.layout.activity_play_01) binding.viewModel = viewModel binding.inputViewModel = inputViewModel binding.statViewModel = statViewModel + binding.controlStreamViewModel = controlStreamViewModel binding.scoreViewModel = scoreViewModel binding.finishUsecase = finishUsecase - binding.animator = Play01Animator(binding) + binding.animator = animator binding.navigator = navigator if (savedInstanceState == null) { @@ -51,9 +60,27 @@ class Play01Activity : ViewModelActivity() { resumeGame() } + override fun onPleaseKillMe() { + controlStreamViewModel.sendDisconnect(navigator) + controlStreamViewModel.toggleStream(navigator, animator) + invalidateOptionsMenu() + } + + override fun onConnectionStateChanged(connectionState: ConnectionState) { + controlStreamViewModel.connectionState(connectionState) + when(connectionState) { + // Add DataMessenger to ScoreViewModel + is Connected -> { + controlStreamViewModel.setStreamController(navigator.streamController()) + viewModel.addRemoteListener(controlStreamViewModel) + } + } + } + override fun onDestroy() { super.onDestroy() viewModel.stop() + navigator.stop() window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) } @@ -66,7 +93,8 @@ class Play01Activity : ViewModelActivity() { } private fun resumeGame() { - viewModel.registerListeners(scoreViewModel, statViewModel, inputViewModel, scoreViewModel, inputViewModel) + viewModel.registerListeners(scoreViewModel, statViewModel, inputViewModel, scoreViewModel, + inputViewModel) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -76,11 +104,17 @@ class Play01Activity : ViewModelActivity() { override fun onPrepareOptionsMenu(menu: Menu?): Boolean { viewModel.initToggleMenuItem(menu) + menu?.findItem(R.id.menu_stream)?.setIcon(controlStreamViewModel.menuIcon()) + menu?.findItem(R.id.menu_stream)?.setTitle(controlStreamViewModel.menuTitle()) return super.onPrepareOptionsMenu(menu) } override fun onOptionsItemSelected(item: MenuItem?): Boolean { when (item?.itemId) { + R.id.menu_stream -> { + controlStreamViewModel.toggleStream(navigator, animator) + invalidateOptionsMenu() + } R.id.menu_play_settings -> { swapStyle() viewModel.loading.set(true) @@ -92,6 +126,11 @@ class Play01Activity : ViewModelActivity() { return super.onOptionsItemSelected(item) } + override fun onBackPressed() { + super.onBackPressed() + finish() + } + companion object { @JvmStatic fun retrieveSetup(intent: Intent): Play01Request { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Animator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Animator.kt index bc07f75f..9f219535 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Animator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Animator.kt @@ -21,8 +21,9 @@ class Play01Animator(binding: ActivityPlay01Binding) { private val pager = binding.includeMain.statPager private val inputSheet = binding.includeInput.inputSheet private val behaviour = BottomSheetBehavior.from(inputSheet) - private val animator = Play01AnimatorHandler(binding.root, binding.includeScore.scoreSheet, binding.includeInput.fab, binding.includeMain.mainSheet, binding.includeMain.version, - binding.includeInput.inputResume, pager, binding.includeScore.teamContainer, inputSheet, binding.root.includeScore.header, binding.root.includeScore.footer, binding.root.includeToolbar) + private val animator = Play01AnimatorHandler(binding.root, binding.includeScore.scoreSheet,binding.includeInput.fab, binding.includeMain.mainSheet, binding.includeMain.version, + binding.includeInput.inputResume, pager, binding.includeScore.teamContainer, inputSheet, binding.root.includeScore.header, + binding.root.includeScore.footer, binding.root.includeToolbar, binding.includeMain.control1, binding.includeMain.control2) init { animator.calculateHeightForScoreView() @@ -53,7 +54,8 @@ class Play01Animator(binding: ActivityPlay01Binding) { internal class Play01AnimatorHandler(private val root: View, private val scoreSheet: View, private val fab: View, private val mainSheet: View, private val version: View, private val inputResume: View, private val pager: ViewPager, private val teamSheet: MaxHeightRecyclerView, private val inputSheet: View, - private val scoreHeader: View, private val scoreFooter: View, private val toolbar: View) { + private val scoreHeader: View, private val scoreFooter: View, private val toolbar: View, + private val control1: View, private val control2: View) { private var animatorPosition: Int = 0 internal var animator: LiveStatSlideAnimator? = null @@ -63,7 +65,6 @@ class Play01Animator(binding: ActivityPlay01Binding) { // Slide Out ScoreViewModel scoreSheet.animate().alpha(slideOffset).translationY(-scoreSheet.height * (1 - slideOffset)).setDuration(0).start() - // Scale Fab Out Bottom/Top fab.animate().scaleY(slideOffset).scaleX(slideOffset).setDuration(0).start() @@ -71,6 +72,10 @@ class Play01Animator(binding: ActivityPlay01Binding) { mainSheet.animate().alpha(1 - sqrt(slideOffset)).setDuration(0).start() mainSheet.animate().translationY((slideOffset) * -100).setDuration(0).start() + // Fly In Stream Controls + animateState(control1.animate(), 1, slideOffset) + animateState(control2.animate(), 1, slideOffset) + // Also, Fly In Version animateState(version.animate(), 8, slideOffset) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Navigator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Navigator.kt index becb07c1..304bd661 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Navigator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Navigator.kt @@ -1,8 +1,11 @@ package nl.entreco.dartsscorecard.play import android.support.design.widget.Snackbar +import android.support.v4.app.FragmentManager import android.view.View import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.play.stream.StreamController +import nl.entreco.dartsscorecard.play.stream.StreamFragment import nl.entreco.dartsscorecard.profile.view.ProfileActivity import nl.entreco.domain.model.players.Team import javax.inject.Inject @@ -12,6 +15,8 @@ import javax.inject.Inject */ class Play01Navigator @Inject constructor(private val activity: Play01Activity) { + private val fm : FragmentManager = activity.supportFragmentManager + fun gotoTeamProfile(view: View, team: Team) { val teams = team.players.map { it.id }.filter { it > 0 }.toLongArray() if (teams.isEmpty()) { @@ -22,4 +27,26 @@ class Play01Navigator @Inject constructor(private val activity: Play01Activity) ProfileActivity.launch(activity, view, teams) } } + + fun attachVideoStream() { + fm.beginTransaction() + .add(R.id.streamContainer, StreamFragment(), StreamFragment.TAG) + .commit() + } + + fun detachVideoStream() { + fm.findFragmentById(R.id.streamContainer)?.apply { + fm.beginTransaction() + .remove(this) + .commit() + } + } + + fun streamController(): StreamController? { + return fm.findFragmentById(R.id.streamContainer) as? StreamController + } + + fun stop() { + streamController()?.apply { sendDisconnect() } + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01ViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01ViewModel.kt index b30d1792..1ca701b8 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01ViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01ViewModel.kt @@ -9,11 +9,11 @@ import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.dartsscorecard.base.DialogHelper +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier import nl.entreco.dartsscorecard.play.score.TeamScoreListener import nl.entreco.dartsscorecard.play.score.UiCallback -import nl.entreco.domain.Analytics -import nl.entreco.domain.common.log.Logger +import nl.entreco.dartsscorecard.play.stream.ControlStreamViewModel import nl.entreco.domain.model.* import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team @@ -31,8 +31,11 @@ import nl.entreco.domain.play.start.Play01Usecase import nl.entreco.domain.play.stats.StoreTurnRequest import nl.entreco.domain.play.stats.UndoTurnRequest import nl.entreco.domain.play.stats.UndoTurnResponse +import nl.entreco.domain.rating.AskForRatingResponse +import nl.entreco.domain.rating.AskForRatingUsecase import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.settings.ScoreSettings +import nl.entreco.shared.log.Logger import javax.inject.Inject /** @@ -42,11 +45,13 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use private val revancheUsecase: RevancheUsecase, private val gameListeners: Play01Listeners, private val masterCaller: MasterCaller, - private val dialogHelper: DialogHelper, + @ActivityScope private val dialogHelper: DialogHelper, private val toggleSoundUsecase: ToggleSoundUsecase, + private val askForRatingUsecase: AskForRatingUsecase, private val audioPrefRepository: AudioPrefRepository, private val adViewModel: AdViewModel, - private val logger: Logger) : BaseViewModel(), UiCallback, InputListener { + @ActivityScope private val logger: Logger) : + BaseViewModel(), UiCallback, InputListener { val loading = ObservableBoolean(true) val finished = ObservableBoolean(false) @@ -57,7 +62,8 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use private var load: GameLoadedNotifier? = null private var loaders: Array>? = null - fun load(request: Play01Request, load: GameLoadedNotifier, vararg loaders: GameLoadedNotifier) { + fun load(request: Play01Request, load: GameLoadedNotifier, + vararg loaders: GameLoadedNotifier) { this.load = load this.loaders = arrayOf(*loaders) this.playGameUsecase.loadGameAndStart(request, @@ -72,13 +78,15 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use val nextTeam = (startIndex) % teams.size revancheUsecase.recreateGameAndStart(RevancheRequest(request, teams, nextTeam), { revenge -> - onGameOk(this.request.copy(gameId = revenge.game.id, startIndex = nextTeam), null, revenge) + onGameOk(this.request.copy(gameId = revenge.game.id, startIndex = nextTeam), + null, revenge) }, onGameFailed(R.string.err_unable_to_revanche)) } } - private fun onGameOk(request: Play01Request, response: Play01Response?, revancheResponse: RevancheResponse?) { + private fun onGameOk(request: Play01Request, response: Play01Response?, + revancheResponse: RevancheResponse?) { this.request = request this.game = response?.game ?: revancheResponse!!.game this.teams = response?.teams ?: revancheResponse!!.teams @@ -86,7 +94,8 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use val settings = response?.settings ?: revancheResponse!!.settings this.load?.onLoaded(teams, game.scores, settings, this) this.loaders?.forEach { - it.onLoaded(teams, game.scores, response ?: Play01Response(game, settings, teams, teamIds), null) + it.onLoaded(teams, game.scores, + response ?: Play01Response(game, settings, teams, teamIds), null) } } @@ -98,8 +107,11 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use } } - fun registerListeners(scoreListener: ScoreListener, statListener: StatListener, specialEventListener: SpecialEventListener<*>, vararg playerListeners: PlayerListener) { - gameListeners.registerListeners(scoreListener, statListener, specialEventListener, *playerListeners) + fun registerListeners(scoreListener: ScoreListener, statListener: StatListener, + specialEventListener: SpecialEventListener<*>, + vararg playerListeners: PlayerListener) { + gameListeners.registerListeners(scoreListener, statListener, specialEventListener, + *playerListeners) } override fun onLetsPlayDarts(listeners: List) { @@ -150,7 +162,7 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use private fun storeTurn(turn: Turn, by: Player, next: Next) { val turnRequest = StoreTurnRequest(by.id, game.id, turn, next.state) val score = game.previousScore() - val started = game.isNewMatchLegOrSet() +// val started = game.isNewMatchLegOrSet() val turnCounter = game.getTurnCount() val breakMade = game.wasBreakMade(by) val turnMeta = TurnMeta(by.id, turnCounter, score, breakMade) @@ -163,11 +175,19 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use val gameFinished = next.state == State.MATCH finished.set(gameFinished) if (gameFinished) { - playGameUsecase.markGameAsFinished(MarkGameAsFinishedRequest(gameId, teams.first { it.contains(winnerId) }.toTeamString())) + askForRatingUsecase.go(onShouldAskForRating(), {}) + playGameUsecase.markGameAsFinished(MarkGameAsFinishedRequest(gameId, + teams.first { it.contains(winnerId) }.toTeamString())) gameListeners.onGameFinished(gameId) } } + private fun onShouldAskForRating(): (AskForRatingResponse) -> Unit = { response -> + if (response.shouldAskForRating) { + dialogHelper.showRatingDialog() + } + } + private fun notifyListeners(next: Next, turn: Turn, by: Player, scores: Array) { gameListeners.onTurnSubmitted(next, turn, by, scores) } @@ -189,7 +209,8 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use State.LEG -> adViewModel.provideInterstitial() State.SET -> adViewModel.provideInterstitial() State.MATCH -> adViewModel.provideInterstitial() - else -> { /* ignore */ } + else -> { /* ignore */ + } } } @@ -198,7 +219,8 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use } fun initToggleMenuItem(menu: Menu?) { - menu?.findItem(R.id.menu_sound_settings)?.isChecked = audioPrefRepository.isMasterCallerEnabled() + menu?.findItem(R.id.menu_sound_settings) + ?.isChecked = audioPrefRepository.isMasterCallerEnabled() } fun toggleMasterCaller(item: MenuItem) { @@ -211,4 +233,9 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use loaders = null super.onCleared() } + + fun addRemoteListener(listener: ControlStreamViewModel) { + gameListeners.playerListeners.add(listener as PlayerListener) + gameListeners.scoreListeners.add(listener as ScoreListener) + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/input/InputViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/input/InputViewModel.kt index f652986a..975b87e7 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/input/InputViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/input/InputViewModel.kt @@ -9,7 +9,7 @@ import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.dartsscorecard.play.Play01Animator import nl.entreco.domain.Analytics -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.NoPlayer import nl.entreco.domain.model.players.Player diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt index fe081f41..069d9d99 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt @@ -6,7 +6,7 @@ import nl.entreco.dartsscorecard.archive.ArchiveServiceLauncher import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier import nl.entreco.dartsscorecard.play.score.UiCallback -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.Score import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.listeners.StatListener diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreBindings.kt index e29752a5..7f927cfe 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreBindings.kt @@ -26,7 +26,6 @@ object ScoreBindings { recyclerView.setHasFixedSize(true) recyclerView.layoutManager = LinearLayoutManager(recyclerView.context) recyclerView.itemAnimator = null - recyclerView.isDrawingCacheEnabled = true recyclerView.adapter = adapter adapter.clear() diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreViewModel.kt index 5f92a373..49ea66f1 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/ScoreViewModel.kt @@ -4,7 +4,6 @@ import android.databinding.ObservableArrayList import android.databinding.ObservableField import android.databinding.ObservableInt import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.Next import nl.entreco.domain.model.Score import nl.entreco.domain.model.Turn diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt index 31da06a2..1232e5e0 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt @@ -1,7 +1,6 @@ package nl.entreco.dartsscorecard.play.score import android.animation.ValueAnimator -import android.app.ProgressDialog.show import android.content.Context import android.databinding.BindingAdapter import android.graphics.Color @@ -51,7 +50,8 @@ object TeamScoreBindings { val diff = oldScore - score when (diff) { 180 -> handle180(view) - 0 -> { /* nothing */ } + 0 -> { /* nothing */ + } else -> clear(view) } } @@ -105,9 +105,12 @@ object TeamScoreBindings { view.setTarget(score.toLong()) view.measure(0, 0) if (score <= 0) { - view.animate().translationX(view.measuredWidth.toFloat() * 3).setInterpolator(AccelerateDecelerateInterpolator()).setDuration(DEFAULT_ANIMATION_TIME).start() + view.animate().translationX(view.measuredWidth.toFloat() * 3) + .setInterpolator(AccelerateDecelerateInterpolator()) + .setDuration(DEFAULT_ANIMATION_TIME).start() } else { - view.animate().translationX(0f).setInterpolator(AccelerateDecelerateInterpolator()).setDuration(DEFAULT_ANIMATION_TIME).start() + view.animate().translationX(0f).setInterpolator(AccelerateDecelerateInterpolator()) + .setDuration(DEFAULT_ANIMATION_TIME).start() view.setTextColor(fromAttr(view.context, R.attr.scoreText)) } } @@ -122,7 +125,8 @@ object TeamScoreBindings { target = if (w == 0F) 50F else w } - view.animate().translationX(target).setInterpolator(AccelerateDecelerateInterpolator()).setDuration(DEFAULT_ANIMATION_TIME).start() + view.animate().translationX(target).setInterpolator(AccelerateDecelerateInterpolator()) + .setDuration(DEFAULT_ANIMATION_TIME).start() } @ColorInt @@ -147,10 +151,12 @@ object TeamScoreBindings { val startColor = colorToHex(view.currentTextColor) val endColor = if (isCurrentTeam) "#FFFFFFFF" else "#aaFFFFFF" if (startColor != endColor) { - val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f).setDuration(DEFAULT_ANIMATION_TIME) + val valueAnimator = ValueAnimator.ofFloat(0.0f, 1.0f) + .setDuration(DEFAULT_ANIMATION_TIME) valueAnimator.addUpdateListener { val fractionAnim = it.animatedValue as Float - view.setTextColor(ColorUtils.blendARGB(Color.parseColor(startColor), Color.parseColor(endColor), fractionAnim)) + view.setTextColor(ColorUtils.blendARGB(Color.parseColor(startColor), + Color.parseColor(endColor), fractionAnim)) } valueAnimator.start() } @@ -171,7 +177,8 @@ object TeamScoreBindings { private fun show(view: TextView) { view.measure(0, 0) - val animator = ValueAnimator.ofInt(view.width, view.measuredWidth).setDuration(DEFAULT_ANIMATION_TIME) + val animator = ValueAnimator.ofInt(view.width, view.measuredWidth) + .setDuration(DEFAULT_ANIMATION_TIME) animator.addUpdateListener { val lp = view.layoutParams lp.width = it.animatedValue as Int diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ControlStreamViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ControlStreamViewModel.kt new file mode 100644 index 00000000..78a73e41 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ControlStreamViewModel.kt @@ -0,0 +1,90 @@ +package nl.entreco.dartsscorecard.play.stream + +import android.databinding.ObservableBoolean +import android.databinding.ObservableField +import android.support.annotation.DrawableRes +import android.support.annotation.StringRes +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.base.BaseViewModel +import nl.entreco.dartsscorecard.di.play.Play01Scope +import nl.entreco.dartsscorecard.play.Play01Animator +import nl.entreco.dartsscorecard.play.Play01Navigator +import nl.entreco.domain.model.Next +import nl.entreco.domain.model.Score +import nl.entreco.domain.model.Turn +import nl.entreco.domain.model.players.Player +import nl.entreco.domain.play.listeners.PlayerListener +import nl.entreco.domain.play.listeners.ScoreListener +import nl.entreco.domain.streaming.ConnectionState +import nl.entreco.domain.streaming.Unknown +import java.util.concurrent.atomic.AtomicBoolean +import javax.inject.Inject + + +class ControlStreamViewModel @Inject constructor() : BaseViewModel(), ScoreListener, PlayerListener { + + private val isStreaming = AtomicBoolean(false) + val micEnabled = ObservableBoolean(true) + val isShowingFront = ObservableBoolean(true) + val state = ObservableField(Unknown) + + fun toggleStream(navigator: Play01Navigator, animator: Play01Animator) { + if (isStreaming.get()) { + isStreaming.set(false) + animator.expand() + navigator.detachVideoStream() + sendDisconnect(navigator) + } else { + isStreaming.set(true) + animator.collapse() + navigator.attachVideoStream() + } + } + + fun sendDisconnect(navigator: Play01Navigator){ + navigator.streamController()?.sendDisconnect() + } + + fun toggleCamera(navigator: Play01Navigator){ + isShowingFront.set(!isShowingFront.get()) + navigator.streamController()?.toggleCamera() + } + + fun toggleMic(navigator: Play01Navigator){ + micEnabled.set(!micEnabled.get()) + navigator.streamController()?.toggleMic() + } + + fun connectionState(connectionState: ConnectionState) { + state.set(connectionState) + } + + @DrawableRes + fun menuIcon(): Int { + return if (isStreaming.get()) R.drawable.ic_live_stop else R.drawable.ic_live_start + } + + @StringRes + fun menuTitle(): Int { + return if (isStreaming.get()) R.string.stream_stop else R.string.stream_start + } + + private var streamController : StreamController? = null + + fun setStreamController(streamController: StreamController?) { + this.streamController = streamController + } + + override fun onDartThrown(turn: Turn, by: Player) { + this.streamController?.sendMessage("turn $turn by $by") + } + + override fun onScoreChange(scores: Array, by: Player) { + this.streamController?.sendMessage("score $scores by $by") + } + + override fun onNext(next: Next) { + this.streamController?.sendMessage("next $next") + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ServiceLauncher.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ServiceLauncher.kt new file mode 100644 index 00000000..72bf677d --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/ServiceLauncher.kt @@ -0,0 +1,40 @@ +package nl.entreco.dartsscorecard.play.stream + +import android.content.Context +import android.content.ServiceConnection +import android.widget.Toast +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.dartsscorecard.streaming.ReceiverService +import nl.entreco.dartsscorecard.streaming.StreamingService +import org.webrtc.PeerConnection +import javax.inject.Inject + +class ServiceLauncher @Inject constructor(@ActivityScope private val context: Context) { + + + fun launchStreamingService(serviceConnection: ServiceConnection) { + StreamingService.startService(context) + StreamingService.bindService(context, serviceConnection) + } + + fun launchReceiverService(serviceConnection: ServiceConnection) { + ReceiverService.startService(context) + ReceiverService.bindService(context, serviceConnection) + } + + fun unbindServiceConnection(serviceConnection: ServiceConnection) { + context.unbindService(serviceConnection) + } + + fun criticalWebRTCServiceException(throwable: Throwable) { + Toast.makeText(context, "Critical error ${throwable.localizedMessage}", Toast.LENGTH_LONG).show() + } + + fun connectionStateChange(iceConnectionState: PeerConnection.IceConnectionState?) { + Toast.makeText(context, "Connection State Change $iceConnectionState", Toast.LENGTH_LONG).show() + } + + fun showError(msg: String){ + Toast.makeText(context, "Error: $msg", Toast.LENGTH_LONG).show() + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamBinding.kt new file mode 100644 index 00000000..10b3d182 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamBinding.kt @@ -0,0 +1,66 @@ +package nl.entreco.dartsscorecard.play.stream + +import android.databinding.BindingAdapter +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import nl.entreco.dartsscorecard.R +import nl.entreco.domain.streaming.* + +object StreamBinding { + + @JvmStatic + @BindingAdapter("streamVisibility") + fun updateStreamVisibility(view: ViewGroup, state: ConnectionState) { + updateVisibility(state, view) + } + + @JvmStatic + @BindingAdapter("streamState") + fun updateStreamState(view: TextView, state: ConnectionState) { + updateText(state, view) + updateDrawable(state, view) + updateVisibility(state, view) + } + + private fun updateVisibility(state: ConnectionState, view: View) { + when (state) { + Unknown -> view.visibility = View.GONE + else -> view.visibility = View.VISIBLE + } + } + + private fun updateText(state: ConnectionState, view: TextView) { + when (state) { + is Unknown -> view.text = "Unknown" + is Initializing -> view.text = "Init" + is ReadyToConnect -> view.text = "Ready to Stream" + is Connecting -> view.text = "Connecting" + is Connected -> view.text = "Streaming" + is Disconnecting -> view.text = "Disconnecting" + is Disconnected -> view.text = "Disconnected" + is Killing -> view.text = "Shutting down" + } + } + + private fun updateDrawable(state: ConnectionState, view: TextView) { + when (state) { + is Unknown -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_connect, 0) + is Initializing -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_connect, 0) + is ReadyToConnect -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_stopped, 0) + is Connecting -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_live, 0) + is Connected -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_live, 0) + is Disconnecting -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_live, 0) + is Disconnected -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_stopped, 0) + is Killing -> view.setCompoundDrawablesWithIntrinsicBounds(0, 0, + R.drawable.stream_state_stopped, 0) + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamController.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamController.kt new file mode 100644 index 00000000..017716d0 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamController.kt @@ -0,0 +1,8 @@ +package nl.entreco.dartsscorecard.play.stream + +interface StreamController { + fun sendDisconnect() + fun toggleCamera() + fun toggleMic() + fun sendMessage(msg: String) +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamFragment.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamFragment.kt new file mode 100644 index 00000000..8db884c7 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamFragment.kt @@ -0,0 +1,140 @@ +package nl.entreco.dartsscorecard.play.stream + +import android.content.Context +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.base.BaseFragment +import nl.entreco.dartsscorecard.base.PermissionHelper +import nl.entreco.dartsscorecard.databinding.FragmentStreamBinding +import nl.entreco.dartsscorecard.di.streaming.StreamModule +import nl.entreco.domain.streaming.ConnectionState +import org.webrtc.CameraVideoCapturer +import java.util.concurrent.atomic.AtomicBoolean + +class StreamFragment : BaseFragment(), StreamController, CameraVideoCapturer.CameraSwitchHandler { + + companion object { + val TAG: String = StreamFragment::class.java.name + } + + interface Listener { + fun onPleaseKillMe() + fun onConnectionStateChanged(connectionState: ConnectionState) + } + + private lateinit var binding: FragmentStreamBinding + private val component by componentProvider { it.plus(StreamModule(this, activityListener, binding.localVideoView)) } + private val viewModel by lazy { component.viewModel() } + private val permissionHelper by lazy { component.permissionHelper() } + + private val isShowingFrontCamera = AtomicBoolean(true) + private var activityListener: StreamFragment.Listener? = null + + override fun onAttach(context: Context?) { + super.onAttach(context) + activityListener = context as Listener + } + + override fun onDetach() { + super.onDetach() + activityListener = null + binding.localVideoView.clearImage() + binding.localVideoView.release() + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + binding = DataBindingUtil.inflate(inflater, R.layout.fragment_stream, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + permissionHelper.checkStreamingPermissionsAndConnect { viewModel.attachService() } + } + + override fun onRequestPermissionsResult(requestCode: Int, + permissions: Array, + grantResults: IntArray) = when (requestCode) { + PermissionHelper.CHECK_PERMISSIONS_AND_CONNECT_REQUEST_CODE -> permissionHelper.onStreamingPermissionResult( + grantResults) { viewModel.attachService() } + else -> error("Unknown permission request code $requestCode") + } + + override fun onStart() { + super.onStart() + viewModel.onStart() + } + + override fun onStop() { + super.onStop() + if (!activity?.isChangingConfigurations!!) { + viewModel.onStop() + viewModel.disconnect() + } + } + + override fun onDestroyView() { + super.onDestroyView() + viewModel.onDestroy() + viewModel.disconnect() + } + +// override fun onSaveInstanceState(outState: Bundle) { +// super.onSaveInstanceState(outState) +// if (remoteVideoView.visibility == View.VISIBLE) { +// outState.putBoolean(KEY_IN_CHAT, true) +// } +// } + + override fun onDestroy() { + super.onDestroy() + if (!activity?.isChangingConfigurations!!) viewModel.disconnect() + } + +// private fun initAlreadyRunningConnection() { +//// showCamViews() +// serviceConnection = object : ServiceConnection { +// override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { +// onWebRtcServiceConnected((iBinder as (StreamingService.LocalBinder)).service) +//// getPresenter().listenForDisconnectOrders() +// // Listen for Disconnects +// } +// +// override fun onServiceDisconnected(componentName: ComponentName) { +// onWebRtcServiceDisconnected() +// } +// } +// startAndBindWebRTCService(serviceConnection) +// } + + override fun sendDisconnect() { + viewModel.sendDisconnect() + } + + override fun toggleCamera() { + viewModel.switchCamera() + } + + override fun toggleMic() { + viewModel.toggleMic() + } + + override fun sendMessage(msg: String) { + viewModel.sendMessage(msg) + } + + override fun onCameraSwitchDone(p0: Boolean) { + isShowingFrontCamera.set(!isShowingFrontCamera.get()) + activity?.invalidateOptionsMenu() + + } + + override fun onCameraSwitchError(p0: String?) { + activity?.invalidateOptionsMenu() + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamViewModel.kt new file mode 100644 index 00000000..16e4db11 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stream/StreamViewModel.kt @@ -0,0 +1,187 @@ +package nl.entreco.dartsscorecard.play.stream + +import android.content.ComponentName +import android.content.ServiceConnection +import android.databinding.Observable +import android.databinding.ObservableField +import android.os.IBinder +import nl.entreco.dartsscorecard.base.DialogHelper +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.streaming.StreamScope +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.dartsscorecard.streaming.StreamingService +import nl.entreco.dartsscorecard.streaming.StreamingServiceListener +import nl.entreco.domain.streaming.* +import nl.entreco.domain.streaming.receive.ListenForDisconnectsUsecase +import nl.entreco.domain.streaming.send.RegisterStreamerRequest +import nl.entreco.domain.streaming.send.RegisterStreamerResponse +import nl.entreco.domain.streaming.send.RegisterStreamerUsecase +import nl.entreco.shared.log.Logger +import org.webrtc.CameraVideoCapturer +import org.webrtc.PeerConnection +import org.webrtc.SurfaceViewRenderer +import javax.inject.Inject +import javax.inject.Named + +class StreamViewModel @Inject constructor( + @ApplicationScope private val logger: Logger, + @ActivityScope private val dialogHelper: DialogHelper, + @StreamScope @Named("local") private val localVideoView: SurfaceViewRenderer, + @ApplicationScope private val serviceLauncher: ServiceLauncher, + private val registerStreamerUsecase: RegisterStreamerUsecase, + private val listenForDisconnectsUsecase: ListenForDisconnectsUsecase, + private val disconnectUsecase: DisconnectUsecase, + private val disconnectFromSignallingUsecase: DisconnectFromSignallingUsecase, + private val cameraSwitchHandler: CameraVideoCapturer.CameraSwitchHandler, + private val listener: StreamFragment.Listener? +) : StreamingServiceListener { + + private var remoteUuid: String? = null + private val connectionState = ObservableField(Unknown) + private val connectionChange = object : Observable.OnPropertyChangedCallback() { + override fun onPropertyChanged(sender: Observable?, propertyId: Int) { + listener?.onConnectionStateChanged(connectionState.get()!!) + } + } + + init { + connectionState.addOnPropertyChangedCallback(connectionChange) + } + + private var service: StreamingService? = null + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { + onWebRtcServiceConnected((iBinder as (StreamingService.LocalBinder)).service) + dialogHelper.showStreamDialog(onCodeEntered(), onStreamCancelled()) + } + + override fun onServiceDisconnected(componentName: ComponentName) { + onWebRtcServiceDisconnected() + } + } + + private fun onStreamCancelled(): () -> Unit = { + connectionState.set(Killing) + listener?.onPleaseKillMe() + } + + private fun onCodeEntered(): (String) -> Unit { + return { code -> + connectionState.set(Connecting) + registerStreamerUsecase.go(RegisterStreamerRequest(code), + onRegisterSuccess(), + onRegisterFailed()) + } + } + + private fun onRegisterSuccess(): (RegisterStreamerResponse) -> Unit = { response -> + remoteUuid = response.uuid + service?.offerDevice(response.uuid) + listenForDisconnectsUsecase.go { + disconnect() + } + } + + private fun onRegisterFailed(): (Throwable) -> Unit = { error -> + serviceLauncher.showError(error.localizedMessage) + connectionState.set(Killing) + listener?.onPleaseKillMe() + } + + fun attachService() { + connectionState.set(Initializing) + serviceLauncher.launchStreamingService(serviceConnection) + } + + private fun onWebRtcServiceConnected(service: StreamingService) { + logger.d("Service connected") + connectionState.set(ReadyToConnect) + this.service = service + service.attachLocalView(localVideoView) + service.attachServiceActionsListener(listener = this) + } + + private fun onWebRtcServiceDisconnected() { + logger.d("Service disconnected") + connectionState.set(Disconnected) + } + + override fun criticalWebRTCServiceException(throwable: Throwable) { + unbindService() + serviceLauncher.criticalWebRTCServiceException(throwable) + } + + override fun connectionStateChange(iceConnectionState: PeerConnection.IceConnectionState?) { + serviceLauncher.connectionStateChange(iceConnectionState) + when (iceConnectionState) { + PeerConnection.IceConnectionState.CONNECTED -> { + connectionState.set(Connected) + } + PeerConnection.IceConnectionState.DISCONNECTED -> { +// getView()?.showWillTryToRestartMsg() + connectionState.set(Disconnected) + disconnect() + } + else -> { + //no-op for now - could show or hide progress bars or messages on given event + } + } + } + + fun onDestroy() { + service?.let { + it.detachViews() + unbindService() + } + } + + private fun unbindService() { + service?.let { + it.detachServiceActionsListener() + serviceLauncher.unbindServiceConnection(serviceConnection) + service = null + localVideoView.clearImage() + localVideoView.release() + connectionState.set(Unknown) + } + } + + fun sendDisconnect() { + connectionState.set(Disconnecting) + disconnectFromSignallingUsecase.go(DisconnectFromSignallingRequest(remoteUuid)) { + disconnect() + } + } + + fun switchCamera() { + service?.switchCamera(cameraSwitchHandler) + } + + fun toggleMic(){ + service?.toggleMicrophone() + } + + fun sendMessage(msg: String) { + service?.sendMessage(msg) + } + + fun onStart() { + service?.hideBackground() + } + + fun onStop() { + service?.showBackground() + } + + fun disconnect() { + connectionState.set(Disconnecting) + disconnectUsecase.go{ + connectionState.set(Disconnected) + connectionState.set(Unknown) + } + service?.let { + it.stopSelf() + unbindService() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt index fbfbf138..dafcda50 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt @@ -51,7 +51,6 @@ class SelectProfileActivity : ViewModelActivity() { recyclerView.itemAnimator = DefaultItemAnimator() recyclerView.setHasFixedSize(true) recyclerView.setItemViewCacheSize(20) - recyclerView.isDrawingCacheEnabled = true addSwipeToDelete(binding, recyclerView) recyclerView.adapter = adapter } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapter.kt index 24115a9d..ad15f30b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapter.kt @@ -34,11 +34,12 @@ class SelectProfileAdapter(private val navigator: SelectProfileNavigator) : List } val diff: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Profile?, newItem: Profile?): Boolean { - return oldItem?.id == newItem?.id + + override fun areItemsTheSame(oldItem: Profile, newItem: Profile): Boolean { + return oldItem.id == newItem.id } - override fun areContentsTheSame(oldItem: Profile?, newItem: Profile?): Boolean { + override fun areContentsTheSame(oldItem: Profile, newItem: Profile): Boolean { return oldItem == newItem } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileSwiper.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileSwiper.kt index 28f60f30..9b932f3f 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileSwiper.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileSwiper.kt @@ -9,7 +9,7 @@ import nl.entreco.dartsscorecard.base.SwipeToDeleteCallback class SelectProfileSwiper(view: View, onSwiped: (Int) -> Unit, deleteAction: () -> Unit, undoAction: () -> Unit) : ItemTouchHelper(object : SwipeToDeleteCallback(view.context) { - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, p1: Int) { onSwiped(viewHolder.adapterPosition) val snack = Snackbar.make(view, R.string.confirm_delete_profile, Snackbar.LENGTH_LONG) @@ -26,4 +26,8 @@ class SelectProfileSwiper(view: View, onSwiped: (Int) -> Unit, deleteAction: () }) snack.show() } + + override fun onMove(p0: RecyclerView, p1: RecyclerView.ViewHolder, p2: RecyclerView.ViewHolder): Boolean { + return false + } }) \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileAnimator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileAnimator.kt index 02d8fa3e..fbf125c0 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileAnimator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileAnimator.kt @@ -22,9 +22,7 @@ class ProfileAnimator(binding: ActivityProfileBinding, inflater: TransitionInfla private val revealAnimator = RevealAnimator(appBarLayout) init { - appBarLayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> - animator.onOffsetChanged(appBarLayout, verticalOffset) - } + appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { p0, p1 -> animator.onOffsetChanged(p0, p1) }) revealAnimator.setupEnterAnimation(inflater, window, true) animator.startAlphaAnimation(title, 0, View.INVISIBLE) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileBinding.kt index ce9f43d2..537191b6 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileBinding.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileBinding.kt @@ -5,7 +5,7 @@ import android.net.Uri import android.widget.ImageView import android.widget.TextView import nl.entreco.dartsscorecard.R -import nl.entreco.dartsscorecard.di.glide.GlideApp +import nl.entreco.shared.libs.GlideApp /** * Created by entreco on 23/02/2018. diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileHeaderBehavior.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileHeaderBehavior.kt index 41d97728..05de5a73 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileHeaderBehavior.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileHeaderBehavior.kt @@ -47,7 +47,7 @@ class ProfileHeaderBehavior(context: Context?, attrs: AttributeSet?) : Coordinat finalLeftAvatarPadding = context.resources.getDimension(R.dimen.large) } - override fun layoutDependsOn(parent: CoordinatorLayout?, child: CircleImageView?, dependency: View?): Boolean { + override fun layoutDependsOn(parent: CoordinatorLayout, child: CircleImageView, dependency: View): Boolean { return dependency is Toolbar || dependency is AppBarLayout } @@ -113,5 +113,4 @@ class ProfileHeaderBehavior(context: Context?, attrs: AttributeSet?) : Coordinat changeBehaviorPoint = (child.height - customFinalHeight) / (2f * (startYPosition - finalYPosition)) } } - } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01ViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01ViewModel.kt index d18e8a8a..8353e304 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01ViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01ViewModel.kt @@ -1,7 +1,7 @@ package nl.entreco.dartsscorecard.setup import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.launch.ExtractTeamsRequest import nl.entreco.domain.launch.ExtractTeamsResponse import nl.entreco.domain.launch.ExtractTeamsUsecase diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/EglProvider.java b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/EglProvider.java new file mode 100644 index 00000000..18155d95 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/EglProvider.java @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard.streaming; + +import org.webrtc.EglBase; + +class EglProvider { + + static EglBase get(){ + return EglBase.create(); + } +} diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceiverService.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceiverService.kt new file mode 100644 index 00000000..f5c714c4 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceiverService.kt @@ -0,0 +1,119 @@ +package nl.entreco.dartsscorecard.streaming + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.graphics.Color +import android.os.Binder +import android.os.Build +import android.os.IBinder +import android.support.v4.app.NotificationCompat +import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.di.service.ServiceModule +import nl.entreco.dartsscorecard.di.streaming.StreamingModule +import org.webrtc.SurfaceViewRenderer + +class ReceiverService: Service() { + + companion object { + private const val CHANNEL_ID = "dsc_receiving_channel" + private const val NOTIF_ID = 301 + private const val NOTIF_COLOR = "#A4B5CE" + + fun startService(packageContext: Context) { + packageContext.startService(Intent(packageContext, ReceiverService::class.java)) + } + + fun bindService(context: Context, connection: ServiceConnection) { + context.bindService(Intent(context, ReceiverService::class.java), connection, 0) + } + } + + private val app by lazy { application as App } + private val component by lazy { app.appComponent.plus(ServiceModule(this)) } + private val receivingController : ReceivingController by lazy { component.plus(StreamingModule()).receivingController()} + private val binder = LocalBinder() + + private val notificationManager: NotificationManager by lazy { + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + + private val notif by lazy { + NotificationCompat.Builder(baseContext, CHANNEL_ID) + .setOngoing(true) + .setContentTitle(getString(R.string.streaming_notif_title)) + .setSmallIcon(R.drawable.ic_stat_name) + .setColor(Color.parseColor(NOTIF_COLOR)) + .setBadgeIconType(R.mipmap.ic_launcher_foreground) + .setLocalOnly(true) + .setWhen(System.currentTimeMillis()) + .setUsesChronometer(true) + .setCategory(Notification.CATEGORY_SERVICE) + .setPriority(NotificationCompat.PRIORITY_LOW) + } + + override fun onBind(intent: Intent?): IBinder = binder + + override fun onCreate() { + super.onCreate() + receivingController.attachService(this) + } + + override fun onDestroy() { + receivingController.detachService() + hideBackground() + super.onDestroy() + } + + fun attachServiceActionsListener(listener: ReceivingServiceListener) { + receivingController.serviceListener = listener + } + + fun detachServiceActionsListener() { + receivingController.serviceListener = null + } + + fun attachRemoteView(remoteView: SurfaceViewRenderer) { + receivingController.attachRemoteView(remoteView) + } + + fun onStop() { + hideBackground() + stopSelf() + } + + fun detachViews() { + receivingController.detachViews() + } + + fun showBackground(){ + registerChannel() + notificationManager.notify(NOTIF_ID, notif.build()) + } + + fun hideBackground(){ + notificationManager.cancel(NOTIF_ID) + } + + private fun registerChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val name = getString(R.string.streaming_channel_name) + val desc = getString(R.string.streaming_channel_description) + val importance = NotificationManager.IMPORTANCE_MIN + val channel = NotificationChannel(CHANNEL_ID, name, importance) + channel.description = desc + // Register channel with the system + notificationManager.createNotificationChannel(channel) + } + } + + inner class LocalBinder : Binder() { + val service: ReceiverService + get() = this@ReceiverService + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingController.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingController.kt new file mode 100644 index 00000000..f68810da --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingController.kt @@ -0,0 +1,146 @@ +package nl.entreco.dartsscorecard.streaming + +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.service.ServiceScope +import nl.entreco.dartsscorecard.di.streaming.StreamingScope +import nl.entreco.dartsscorecard.streaming.constraints.OfferAnswerConstraints +import nl.entreco.dartsscorecard.streaming.constraints.WebRtcConstraints +import nl.entreco.dartsscorecard.streaming.constraints.addConstraints +import nl.entreco.domain.streaming.ice.* +import nl.entreco.shared.log.Logger +import org.webrtc.MediaConstraints +import org.webrtc.SessionDescription +import org.webrtc.SurfaceViewRenderer +import java.util.concurrent.ExecutorService +import javax.inject.Inject + +class ReceivingController @Inject constructor( + @ApplicationScope private val logger: Logger, + @StreamingScope private val singleThreadExecutor: ExecutorService, + @StreamingScope private val webRtcController: WebRtcController, + @ServiceScope private val listenForOfferUsecase: ListenForOfferUsecase, + @ServiceScope private val sendAnswerUsecase: SendAnswerUsecase +) { + + private var service: ReceiverService? = null + var serviceListener: ReceivingServiceListener? = null + private var remoteUuid: String? = null + + private lateinit var answeringPartyHandler: WebRtcAnsweringPartyHandler + + private val offerAnswerConstraints by lazy { + WebRtcConstraints().apply { + addMandatoryConstraint(OfferAnswerConstraints.OFFER_TO_RECEIVE_AUDIO, true) + addMandatoryConstraint(OfferAnswerConstraints.OFFER_TO_RECEIVE_VIDEO, true) + } + } + + init { + singleThreadExecutor.execute { + initialize() + } + } + + private fun initialize() { + webRtcController.initializeReceiver() + } + + fun attachService(service: ReceiverService) { + this.service = service + this.webRtcController.fetchIceServers(onServersRetrieved(), onCriticalError()) + } + + private fun onServersRetrieved(): (FetchIceServerResponse) -> Unit { + return { response -> + listenForOffers() + initializeWebRtcReceiver(response.iceServers, + object : WebRtcAnsweringPartyHandler.Listener { + override fun onError(error: String) { + logger.e("WEBRTC: Error in answering party: $error") + } + + override fun onSuccess(localSessionDescription: SessionDescription) { + logger.w("WEBRTC: onSuccess $localSessionDescription") + sendAnswer(localSessionDescription) + } + }) + } + } + + private fun sendAnswer(localDescription: SessionDescription) { + val recipientUuid = remoteUuid ?: throw IllegalArgumentException( + "Remote uuid should be set first") + val session = DscSessionDescription(localDescription.type.ordinal, + localDescription.description) + sendAnswerUsecase.go(SendAnswerRequest(recipientUuid, session), onCriticalError()) + } + + private fun onCriticalError(): (Throwable) -> Unit = { err -> + serviceListener?.criticalWebRTCServiceException(err) + service?.onStop() + } + + private fun initializeWebRtcReceiver(servers: List, + listener: WebRtcAnsweringPartyHandler.Listener) { + val peerConnection = webRtcController.createReceiverConnection(servers, + connectionChange = { + serviceListener?.connectionStateChange(it) + }) + + answeringPartyHandler = WebRtcAnsweringPartyHandler(logger, peerConnection!!, + getOfferAnswerConstraints(), listener) + } + + private fun listenForOffers() { + listenForOfferUsecase.go({ response -> + + logger.w("WEBRTC: listenForNewOffersWithUuid $response") + + this.remoteUuid = response.senderUuid + webRtcController.listenForIceCandidate(response.senderUuid, onCriticalError()) + + val type = SessionDescription.Type.values()[response.sessionType] + val session = SessionDescription(type, response.sessionDescription) + handleRemoteOffer(session) + + }, onCriticalError()) + } + + private fun handleRemoteOffer(remoteSessionDescription: SessionDescription) { + singleThreadExecutor.execute { + answeringPartyHandler.handleRemoteOffer(remoteSessionDescription) + } + } + + /** + * Attach [SurfaceViewRenderer] to webrtc client used for rendering remote view. + */ + fun attachRemoteView(remoteView: SurfaceViewRenderer) { + webRtcController.attachRemoteView(remoteView) + } + + fun detachService() { + this.service = null + } + + fun detachViews() { + webRtcController.detachViews() + } + + /** + * Safety net in case the owner of an object forgets to call its explicit termination method. + * @see + * https://kotlinlang.org/docs/reference/java-interop.html#finalize + */ + @Suppress("unused", "ProtectedInFinal") + protected fun finalize() { + if (!singleThreadExecutor.isShutdown) { + webRtcController.dispose() + singleThreadExecutor.shutdown() + } + } + + private fun getOfferAnswerConstraints() = MediaConstraints().apply { + addConstraints(offerAnswerConstraints) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingServiceListener.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingServiceListener.kt new file mode 100644 index 00000000..a58ef43d --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/ReceivingServiceListener.kt @@ -0,0 +1,13 @@ +package nl.entreco.dartsscorecard.streaming + +import org.webrtc.PeerConnection + +interface ReceivingServiceListener { + + /** + * When receiving this exception service is in unrecoverable state and will call stopSelf, bound view(if any) should unbind + */ + fun criticalWebRTCServiceException(throwable: Throwable) + + fun connectionStateChange(iceConnectionState: PeerConnection.IceConnectionState?) +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingController.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingController.kt new file mode 100644 index 00000000..79fdaa6c --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingController.kt @@ -0,0 +1,228 @@ +package nl.entreco.dartsscorecard.streaming + +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.service.ServiceScope +import nl.entreco.dartsscorecard.di.streaming.StreamingScope +import nl.entreco.dartsscorecard.streaming.constraints.OfferAnswerConstraints +import nl.entreco.dartsscorecard.streaming.constraints.WebRtcConstraints +import nl.entreco.dartsscorecard.streaming.constraints.addConstraints +import nl.entreco.domain.streaming.ice.* +import nl.entreco.shared.log.Logger +import org.webrtc.* +import java.nio.ByteBuffer +import java.util.concurrent.ExecutorService +import java.util.concurrent.atomic.AtomicBoolean +import javax.inject.Inject + +class StreamingController @Inject constructor( + @ApplicationScope private val logger: Logger, + @StreamingScope private val singleThreadExecutor: ExecutorService, + @StreamingScope private val webRtcController: WebRtcController, + @ServiceScope private val listenForAnswersUsecase: ListenForAnswersUsecase, + @ServiceScope private val createOfferUsecase: CreateOfferUsecase, + @StreamingScope private val videoCameraCapturer: CameraVideoCapturer?) { + + private var service: StreamingService? = null + var serviceListener: StreamingServiceListener? = null + private var remoteUuid: String? = null + + private var dataChannel : DataChannel? = null + + private var finishedInitializing = AtomicBoolean(false) + private var shouldCreateOffer = AtomicBoolean(false) + + private lateinit var offeringPartyHandler: WebRtcOfferingPartyHandler + + private val offerAnswerConstraints by lazy { + WebRtcConstraints().apply { + addMandatoryConstraint(OfferAnswerConstraints.OFFER_TO_RECEIVE_AUDIO, true) + addMandatoryConstraint(OfferAnswerConstraints.OFFER_TO_RECEIVE_VIDEO, true) + } + } + + init { + singleThreadExecutor.execute { + initialize() + } + } + + private fun initialize() { + webRtcController.initializeStreamer(videoCameraCapturer) + if (videoCameraCapturer != null) { + enableVideo(cameraEnabled, videoCameraCapturer) + } + } + + fun attachService(service: StreamingService) { + this.service = service + this.webRtcController.fetchIceServers(onServersRetrieved(), onCriticalError()) + } + + private fun onServersRetrieved(): (FetchIceServerResponse) -> Unit { + return { response -> + initializeWebRtcStreamer(response.iceServers, + object : WebRtcOfferingPartyHandler.Listener { + override fun onError(error: String) { + logger.e("WEBRTC: Error in offering party: $error") + } + + override fun onOfferRemoteDescription( + localSessionDescription: SessionDescription) { + logger.w("WEBRTC: onOfferRemoteDescription $localSessionDescription") + listenForAnswers() + sendOffer(localSessionDescription) + } + }) + } + } + + + private fun initializeWebRtcStreamer(servers: List, + listener: WebRtcOfferingPartyHandler.Listener) { + + val peerConnection = webRtcController.createStreamerConnection(servers, + connectionChange = { + if (it == PeerConnection.IceConnectionState.DISCONNECTED) { + restart() + } + serviceListener?.connectionStateChange(it) + }) + + val init = DataChannel.Init() + init.id = 501 + dataChannel = peerConnection?.createDataChannel("match", init) + offeringPartyHandler = WebRtcOfferingPartyHandler(logger, peerConnection!!, listener) + + if (shouldCreateOffer.get()) createOffer() + finishedInitializing.set(true) + } + + private fun restart() { + singleThreadExecutor.execute { + offeringPartyHandler.createOffer(getOfferAnswerRestartConstraints()) + } + } + + private fun sendOffer(localDescription: SessionDescription) { + val recipientUuid = remoteUuid ?: throw IllegalArgumentException( + "Remote uuid should be set first") + val session = DscSessionDescription(localDescription.type.ordinal, + localDescription.description) + createOfferUsecase.go(CreateOfferRequest(recipientUuid, session), onCriticalError()) + } + + private fun createOffer() { + singleThreadExecutor.execute { + offeringPartyHandler.createOffer(getOfferAnswerConstraints()) + } + } + + private fun onCriticalError(): (Throwable) -> Unit = { err -> + serviceListener?.criticalWebRTCServiceException(err) + service?.onStop() + } + + fun detachService() { + this.service = null + } + + fun detachViews() { + webRtcController.detachViews() + } + + fun offerDevice(deviceUuid: String) { + remoteUuid = deviceUuid + webRtcController.listenForIceCandidate(deviceUuid, onCriticalError()) + + if (finishedInitializing.get()) createOffer() else shouldCreateOffer.set(true) + + } + + fun attachLocalView(localView: SurfaceViewRenderer) { + webRtcController.attachLocalView(localView) + } + + /** + * Safety net in case the owner of an object forgets to call its explicit termination method. + * @see + * https://kotlinlang.org/docs/reference/java-interop.html#finalize + */ + @Suppress("unused", "ProtectedInFinal") + protected fun finalize() { + if (!singleThreadExecutor.isShutdown) { + dataChannel?.dispose() + webRtcController.dispose() + videoCameraCapturer?.dispose() + singleThreadExecutor.shutdown() + } + } + + private val localVideoWidth: Int = 1280 + private val localVideoHeight: Int = 720 + private val localVideoFps: Int = 24 + private var cameraEnabled = true + set(isEnabled) { + field = isEnabled + singleThreadExecutor.execute { + videoCameraCapturer?.let { enableVideo(isEnabled, it) } + } + } + + private fun enableVideo(isEnabled: Boolean, videoCapturer: CameraVideoCapturer) { + if (isEnabled) { + videoCapturer.startCapture(localVideoWidth, localVideoHeight, localVideoFps) + } else { + videoCapturer.stopCapture() + } + } + + private fun listenForAnswers() { + listenForAnswersUsecase.go({ response -> + + logger.w("WEBRTC: Listen for Answers $response") + + val type = SessionDescription.Type.values()[response.sessionType] + val sessionDescription = SessionDescription(type, response.sessionDescription) + handleRemoteAnswer(sessionDescription) + + }, onCriticalError()) + + } + + /** + * Handles received remote answer to our offer. + */ + private fun handleRemoteAnswer(remoteSessionDescription: SessionDescription) { + singleThreadExecutor.execute { + offeringPartyHandler.handleRemoteAnswer(remoteSessionDescription) + } + } + + /** + * Switches the camera to other if there is any available. By default front camera is used. + * @param cameraSwitchHandler allows listening for switch camera event + */ + @JvmOverloads + fun switchCamera(cameraSwitchHandler: CameraVideoCapturer.CameraSwitchHandler? = null) { + singleThreadExecutor.execute { + videoCameraCapturer?.switchCamera(cameraSwitchHandler) + } + } + + fun toggleMic() { + webRtcController.toggleMic() + } + + fun sendMessage(msg: String) { + val buffer = DataChannel.Buffer(ByteBuffer.wrap(msg.toByteArray()), false) + dataChannel?.send(buffer) + } + + private fun getOfferAnswerConstraints() = MediaConstraints().apply { + addConstraints(offerAnswerConstraints) + } + + private fun getOfferAnswerRestartConstraints() = getOfferAnswerConstraints().apply { + mandatory.add(OfferAnswerConstraints.ICE_RESTART.toKeyValuePair(true)) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingService.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingService.kt new file mode 100644 index 00000000..b432cda9 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingService.kt @@ -0,0 +1,134 @@ +package nl.entreco.dartsscorecard.streaming + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.Service +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.graphics.Color +import android.os.Binder +import android.os.Build +import android.os.IBinder +import android.support.v4.app.NotificationCompat +import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.di.service.ServiceModule +import nl.entreco.dartsscorecard.di.streaming.StreamingModule +import org.webrtc.CameraVideoCapturer +import org.webrtc.SurfaceViewRenderer + +class StreamingService : Service() { + + companion object { + private const val CHANNEL_ID = "dsc_streaming_channel" + private const val NOTIF_ID = 501 + private const val NOTIF_COLOR = "#A4B5CE" + + fun startService(packageContext: Context) { + packageContext.startService(Intent(packageContext, StreamingService::class.java)) + } + + fun bindService(context: Context, connection: ServiceConnection) { + context.bindService(Intent(context, StreamingService::class.java), connection, 0) + } + } + + private val app by lazy { application as App } + private val component by lazy { app.appComponent.plus(ServiceModule(this)) } + private val streamingController: StreamingController by lazy { component.plus(StreamingModule()).streamingController() } + private val binder = LocalBinder() + + private val notificationManager: NotificationManager by lazy { + getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + } + + private val notif by lazy { + NotificationCompat.Builder(baseContext, CHANNEL_ID) + .setOngoing(true) + .setContentTitle(getString(R.string.streaming_notif_title)) + .setSmallIcon(R.drawable.ic_stat_name) + .setColor(Color.parseColor(NOTIF_COLOR)) + .setBadgeIconType(R.mipmap.ic_launcher_foreground) + .setLocalOnly(true) + .setWhen(System.currentTimeMillis()) + .setUsesChronometer(true) + .setCategory(Notification.CATEGORY_SERVICE) + .setPriority(NotificationCompat.PRIORITY_LOW) + } + + override fun onBind(intent: Intent?): IBinder = binder + + override fun onCreate() { + super.onCreate() + streamingController.attachService(this) + } + + override fun onDestroy() { + streamingController.detachService() + hideBackground() + super.onDestroy() + } + + fun attachServiceActionsListener(listener: StreamingServiceListener) { + streamingController.serviceListener = listener + } + + fun detachServiceActionsListener() { + streamingController.serviceListener = null + } + + fun offerDevice(deviceUuid: String) { + streamingController.offerDevice(deviceUuid) + } + + fun attachLocalView(localView: SurfaceViewRenderer) { + streamingController.attachLocalView(localView) + } + + fun onStop() { + hideBackground() + stopSelf() + } + + fun detachViews() { + streamingController.detachViews() + } + + fun switchCamera( + handler: CameraVideoCapturer.CameraSwitchHandler? = null) = streamingController.switchCamera( + handler) + + fun toggleMicrophone() = streamingController.toggleMic() + + fun sendMessage(msg: String) { + streamingController.sendMessage(msg) + } + + fun showBackground() { + registerChannel() + notificationManager.notify(NOTIF_ID, notif.build()) + } + + fun hideBackground() { + notificationManager.cancel(NOTIF_ID) + } + + private fun registerChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val name = getString(R.string.streaming_channel_name) + val desc = getString(R.string.streaming_channel_description) + val importance = NotificationManager.IMPORTANCE_MIN + val channel = NotificationChannel(CHANNEL_ID, name, importance) + channel.description = desc + // Register channel with the system + notificationManager.createNotificationChannel(channel) + } + } + + inner class LocalBinder : Binder() { + val service: StreamingService + get() = this@StreamingService + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingServiceListener.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingServiceListener.kt new file mode 100644 index 00000000..fc969a42 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/StreamingServiceListener.kt @@ -0,0 +1,13 @@ +package nl.entreco.dartsscorecard.streaming + +import org.webrtc.PeerConnection + +interface StreamingServiceListener { + + /** + * When receiving this exception service is in unrecoverable state and will call stopSelf, bound view(if any) should unbind + */ + fun criticalWebRTCServiceException(throwable: Throwable) + + fun connectionStateChange(iceConnectionState: PeerConnection.IceConnectionState?) +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcAnsweringPartyHandler.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcAnsweringPartyHandler.kt new file mode 100644 index 00000000..b9027cef --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcAnsweringPartyHandler.kt @@ -0,0 +1,97 @@ +package nl.entreco.dartsscorecard.streaming + +import nl.entreco.shared.log.Logger +import org.webrtc.MediaConstraints +import org.webrtc.PeerConnection +import org.webrtc.SdpObserver +import org.webrtc.SessionDescription + +internal class WebRtcAnsweringPartyHandler( + private val logger: Logger, + private val peer: PeerConnection, + private val offerAnswerConstraints: MediaConstraints, + private val listener: Listener) { + + interface Listener { + /** + * Triggered in case of internal errors. + */ + fun onError(error: String) + + /** + * Triggered when local session description from answering party is created. + * [localSessionDescription] object should be sent to the other party through established connection channel. + */ + fun onSuccess(localSessionDescription: SessionDescription) + } + + fun handleRemoteOffer(remoteSessionDescription: SessionDescription) { + peer.setRemoteDescription(object : SdpObserver{ + override fun onSetFailure(error: String) { + logger.w("onSetFailure") + listener.onError(error) + } + + override fun onSetSuccess() { + logger.w("onSetSuccess") + createAnswer() + } + + override fun onCreateSuccess(p0: SessionDescription?) { + logger.w("onCreateSuccess") + } + + override fun onCreateFailure(p0: String?) { + logger.w("onCreateFailure") + } + }, remoteSessionDescription) + } + + private fun createAnswer() { + + peer.createAnswer(object : SdpObserver { + override fun onSetFailure(p0: String?) { + logger.w("onSetFailure") + } + + override fun onSetSuccess() { + logger.w("onSetSuccess") + } + + override fun onCreateSuccess(sessionDescription: SessionDescription) { + logger.w("onCreateSuccess") + setLocalAnswerDescription(sessionDescription) + } + + override fun onCreateFailure(error: String) { + logger.w("onCreateFailure") + listener.onError(error) + } + + }, offerAnswerConstraints) + } + + private fun setLocalAnswerDescription(sessionDescription: SessionDescription) { + + peer.setLocalDescription(object : SdpObserver { + + override fun onCreateSuccess(p0: SessionDescription?) { + logger.w("onCreateSuccess") + } + + override fun onCreateFailure(p0: String?) { + logger.w("onCreateFailure") + } + + override fun onSetSuccess() { + logger.w("onSetSuccess") + listener.onSuccess(sessionDescription) + } + + override fun onSetFailure(error: String) { + logger.w("onSetFailure") + listener.onError(error) + } + }, sessionDescription) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcController.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcController.kt new file mode 100644 index 00000000..6b529187 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcController.kt @@ -0,0 +1,333 @@ +package nl.entreco.dartsscorecard.streaming + +import android.os.Handler +import android.os.Looper +import android.view.View +import com.google.gson.GsonBuilder +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.service.ServiceScope +import nl.entreco.dartsscorecard.di.streaming.StreamingScope +import nl.entreco.dartsscorecard.streaming.constraints.BooleanAudioConstraints +import nl.entreco.dartsscorecard.streaming.constraints.IntegerAudioConstraints +import nl.entreco.dartsscorecard.streaming.constraints.WebRtcConstraints +import nl.entreco.dartsscorecard.streaming.constraints.addConstraints +import nl.entreco.domain.streaming.ice.* +import nl.entreco.domain.streaming.p2p.RemoveIceCandidateRequest +import nl.entreco.domain.streaming.p2p.RemoveIceCandidateUsecase +import nl.entreco.domain.streaming.p2p.SendIceCandidateRequest +import nl.entreco.domain.streaming.p2p.SendIceCandidateUsecase +import nl.entreco.shared.log.Logger +import org.webrtc.* +import java.nio.ByteBuffer +import java.util.concurrent.ExecutorService +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger +import javax.inject.Inject + +class WebRtcController @Inject constructor( + @ApplicationScope private val logger: Logger, + @StreamingScope private val singleThreadExecutor: ExecutorService, + @ServiceScope private val sendIceCandidateUsecase: SendIceCandidateUsecase, + @ServiceScope private val removeIceCandidateUsecase: RemoveIceCandidateUsecase, + @ServiceScope private val fetchIceServersUsecase: FetchIceServerUsecase, + @ServiceScope private val listenForIceServersUsecase: ListenForIceCandidatesUsecase, + @StreamingScope private val peerConnectionFactory: PeerConnectionFactory +) { + + private val counter = AtomicInteger(0) + private val eglBase = EglProvider.get() + private val mainThreadHandler = Handler(Looper.getMainLooper()) + private val isPeerConnectionInitialized = AtomicBoolean(false) + + private var peerConnection: PeerConnection? = null + private var localView: SurfaceViewRenderer? = null + + private lateinit var audioSource: AudioSource + private lateinit var localAudioTrack: AudioTrack + + private var videoSource: VideoSource? = null + private var localVideoTrack: VideoTrack? = null + + private var remoteView: SurfaceViewRenderer? = null + private var remoteVideoTrack: VideoTrack? = null + + fun initializeReceiver() { + audioSource = peerConnectionFactory.createAudioSource(getAudioMediaConstraints()) + localAudioTrack = peerConnectionFactory.createAudioTrack( + getCounterStringValueAndIncrement(), audioSource) + } + + fun initializeStreamer(videoCameraCapturer: CameraVideoCapturer?) { + if (videoCameraCapturer != null) { + peerConnectionFactory.setVideoHwAccelerationOptions(eglBase.eglBaseContext, eglBase.eglBaseContext) + videoSource = peerConnectionFactory.createVideoSource(videoCameraCapturer) + localVideoTrack = peerConnectionFactory.createVideoTrack( + counter.getAndIncrement().toString(), videoSource) + } + + audioSource = peerConnectionFactory.createAudioSource(getAudioMediaConstraints()) + localAudioTrack = peerConnectionFactory.createAudioTrack( + getCounterStringValueAndIncrement(), audioSource) + } + + private fun getCounterStringValueAndIncrement() = counter.getAndIncrement().toString() + + private val audioBooleanConstraints by lazy { + WebRtcConstraints().apply { + addMandatoryConstraint(BooleanAudioConstraints.DISABLE_AUDIO_PROCESSING, true) + } + } + + private val audioIntegerConstraints by lazy { + WebRtcConstraints() + } + + private fun getAudioMediaConstraints() = MediaConstraints().apply { + addConstraints(audioBooleanConstraints, audioIntegerConstraints) + } + + fun fetchIceServers(done: (FetchIceServerResponse) -> Unit, fail: (Throwable) -> Unit) { + fetchIceServersUsecase.go(done, fail) + } + + fun createReceiverConnection(servers: List, + connectionChange: (PeerConnection.IceConnectionState?) -> Unit): PeerConnection? { + val iceServers = servers.map { PeerConnection.IceServer.builder(it.uri).createIceServer() } + peerConnection = peerConnectionFactory.createPeerConnection(iceServers, + object : PeerConnection.Observer { + override fun onIceCandidate(iceCandidate: IceCandidate?) { + logger.w("PEER: onIceCandidate") + sendIceCandidate(iceCandidate) + } + + override fun onDataChannel(p0: DataChannel?) { + logger.w("PEER: onDataChannel") + p0?.registerObserver(object : DataChannel.Observer{ + override fun onMessage(p0: DataChannel.Buffer?) { + logger.w("PEER: onDataChannel onMessage: $p0") + val msg1 = p0?.data?.toString() + logger.w("PEER: onDataChannel onMessage: $msg1") + val ba = ByteArray(p0?.data?.capacity() ?: 0) + p0?.data?.get(ba) + val msg2 = String(ba) + logger.w("PEER: onDataChannel onMessage: $msg2") + + val msg3 = p0?.data?.array()?.let { + String(it) + } + logger.w("PEER: onDataChannel onMessage: $msg3") + } + + override fun onBufferedAmountChange(p0: Long) { + logger.w("PEER: onDataChannel onBufferedAmountChange: $p0") + } + + override fun onStateChange() { + logger.w("PEER: onDataChannel onStateChange") + } + }) + } + + override fun onIceConnectionReceivingChange(p0: Boolean) { + logger.w("PEER: onIceConnectionReceivingChange") + } + + override fun onIceConnectionChange( + iceConnectionState: PeerConnection.IceConnectionState?) { + logger.w("PEER: onIceConnectionChange") + logger.w("WEBRTC: onIceConnectionChange $iceConnectionState") + // NOTE: Restart is for StreamingController only + mainThreadHandler.post { + connectionChange(iceConnectionState) + } + + } + + override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) { + logger.w("PEER: onIceGatheringChange") + } + + override fun onAddStream(p0: MediaStream?) { + logger.w("PEER: onAddStream $p0") + if (p0?.videoTracks?.isNotEmpty() == true) { + onAddRemoteVideoStream(p0.videoTracks[0]) + } + } + + override fun onSignalingChange(p0: PeerConnection.SignalingState?) { + logger.w("PEER: onSignalingChange") + } + + override fun onIceCandidatesRemoved(iceCandidates: Array?) { + logger.w("PEER: onIceCandidatesRemoved") + removeIceCandidates(iceCandidates) + } + + override fun onRemoveStream(p0: MediaStream?) { + logger.w("PEER: onRemoveStream") + removeVideoStream() + } + + override fun onRenegotiationNeeded() { + logger.w("PEER: onRenegotiationNeeded") + } + + override fun onAddTrack(p0: RtpReceiver?, p1: Array?) { + logger.w("PEER: onAddTrack") + } + }) + + isPeerConnectionInitialized.set(true) + return peerConnection + } + + fun createStreamerConnection(servers: List, + connectionChange: (PeerConnection.IceConnectionState?) -> Unit): PeerConnection? { + peerConnection = createReceiverConnection(servers, connectionChange) + + val localMediaStream = peerConnectionFactory.createLocalMediaStream( + getCounterStringValueAndIncrement()) + localMediaStream.addTrack(localAudioTrack) + localVideoTrack?.let { localMediaStream.addTrack(it) } + peerConnection?.addStream(localMediaStream) + + return peerConnection + } + + fun listenForIceCandidate(deviceUuid: String, fail: (Throwable) -> Unit) { + listenForIceServersUsecase.go(ListenForIceCandidatesRequest(deviceUuid), { response -> + + val candidate = IceCandidate(response.candidate.sdpMid, + response.candidate.sdpMLineIndex, response.candidate.sdp) + if (response.shouldAdd) { + // Add DscIceCandidate to webRtc + addRemoteIceCandidate(candidate) + } else { + // Remove DscIceCandidate from webRtc + removeRemoteIceCandidate(arrayOf(candidate)) + } + + }, fail) + } + + private fun onAddRemoteVideoStream(remoteVideoTrack: VideoTrack) { + singleThreadExecutor.execute { + this.remoteVideoTrack = remoteVideoTrack + remoteVideoTrack.addSink(remoteView) + } + } + + private fun removeVideoStream() { + singleThreadExecutor.execute { + remoteVideoTrack = null + } + } + + + private fun sendIceCandidate(iceCandidate: IceCandidate?) { + iceCandidate?.let { ice -> + val candidate = DscIceCandidate(ice.sdpMid, ice.sdpMLineIndex, ice.sdp) + sendIceCandidateUsecase.go(SendIceCandidateRequest(candidate), + done = { logger.i("Added IceCandidate $candidate") }, + fail = { logger.w("Unable to add IceCandidate $candidate") }) + } + } + + private fun removeIceCandidates(iceCandidates: Array?) { + iceCandidates?.let { ices -> + val candidates = ices.map { DscIceCandidate(it.sdpMid, it.sdpMLineIndex, it.sdp) } + .toTypedArray() + removeIceCandidateUsecase.go(RemoveIceCandidateRequest(candidates), + done = { logger.i("Removed IceCandidate $candidates") }, + fail = { logger.w("Unable to Remove IceCandidates $candidates") }) + } + } + + /** + * Adds ice candidate from remote party to webrtc client + */ + private fun addRemoteIceCandidate(iceCandidate: IceCandidate) { + singleThreadExecutor.execute { + peerConnection?.addIceCandidate(iceCandidate) + } + } + + /** + * Removes ice candidates + */ + private fun removeRemoteIceCandidate(iceCandidates: Array) { + singleThreadExecutor.execute { + peerConnection?.removeIceCandidates(iceCandidates) + } + } + + fun toggleMic(){ + singleThreadExecutor.execute { + localAudioTrack.setEnabled(!localAudioTrack.enabled()) + } + } + + fun attachLocalView(localView: SurfaceViewRenderer) { + mainThreadHandler.post { + localView.init(eglBase.eglBaseContext, null) + this@WebRtcController.localView = localView + singleThreadExecutor.execute { + localVideoTrack?.addSink(localView) + } + } + } + + private fun detachLocalView() { + singleThreadExecutor.execute { + localVideoTrack?.removeSink(localView) + } + mainThreadHandler.post { + localView?.clearImage() + localView?.release() + localView = null + } + } + + fun attachRemoteView(remoteView: SurfaceViewRenderer) { + mainThreadHandler.post { + remoteView.visibility = View.VISIBLE + remoteView.init(eglBase.eglBaseContext, null) + this@WebRtcController.remoteView = remoteView + singleThreadExecutor.execute { + remoteVideoTrack?.addSink(remoteView) + } + } + } + + private fun detachRemoteView() { + mainThreadHandler.post { + remoteView?.clearImage() + remoteView?.release() + remoteView = null + } + singleThreadExecutor.execute { + remoteVideoTrack?.removeSink(remoteView) + } + } + + fun detachViews() { + detachLocalView() + detachRemoteView() + } + + fun dispose() { + singleThreadExecutor.execute { + if (isPeerConnectionInitialized.get()) { + peerConnection?.close() + peerConnection?.dispose() + } + eglBase.release() + audioSource.dispose() + videoSource?.dispose() + peerConnectionFactory.dispose() + } + singleThreadExecutor.shutdown() + } + + +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcOfferingPartyHandler.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcOfferingPartyHandler.kt new file mode 100644 index 00000000..60b9dd02 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/WebRtcOfferingPartyHandler.kt @@ -0,0 +1,84 @@ +package nl.entreco.dartsscorecard.streaming + +import nl.entreco.shared.log.Logger +import org.webrtc.MediaConstraints +import org.webrtc.PeerConnection +import org.webrtc.SdpObserver +import org.webrtc.SessionDescription + +internal class WebRtcOfferingPartyHandler ( + private val logger: Logger, + private val peer: PeerConnection, + private val webRtcActionListener: Listener) { + + interface Listener { + /** + * Triggered in case of internal errors. + */ + fun onError(error: String) + + /** + * Called when local session description from offering party is created. + * [localSessionDescription] object should be sent to the other party through established connection channel. + */ + fun onOfferRemoteDescription(localSessionDescription: SessionDescription) + } + + companion object { + private val TAG = WebRtcOfferingPartyHandler::class.java.simpleName + } + + fun createOffer(offerAnswerConstraints: MediaConstraints) { + logger.d(TAG, "Creating offer with $offerAnswerConstraints") + peer.createOffer(object : SdpObserver { + override fun onCreateSuccess(localSessionDescription: SessionDescription) { + setLocalOfferDescription(localSessionDescription) + } + + override fun onCreateFailure(error: String) { + webRtcActionListener.onError(error) + } + + override fun onSetFailure(p0: String?) {} + + override fun onSetSuccess() {} + }, offerAnswerConstraints) + } + + private fun setLocalOfferDescription(localSessionDescription: SessionDescription) { + peer.setLocalDescription(object : SdpObserver { + + override fun onSetSuccess() { + webRtcActionListener.onOfferRemoteDescription(localSessionDescription) + } + + override fun onSetFailure(error: String) { + webRtcActionListener.onError(error) + } + + override fun onCreateSuccess(p0: SessionDescription?) {} + + override fun onCreateFailure(p0: String?) {} + }, localSessionDescription) + } + + fun handleRemoteAnswer(remoteSessionDescription: SessionDescription) { + peer.setRemoteDescription(object : SdpObserver { + override fun onSetSuccess() { + logger.d(TAG, "Remote description from answer set successfully") + } + + override fun onSetFailure(error: String) { + webRtcActionListener.onError(error) + } + + override fun onCreateSuccess(p0: SessionDescription?) { + logger.w("onCreateSuccess") + } + + override fun onCreateFailure(p0: String?) { + logger.w("onCreateFailure") + } + }, remoteSessionDescription) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/BooleanAudioConstraints.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/BooleanAudioConstraints.kt new file mode 100644 index 00000000..d31d5387 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/BooleanAudioConstraints.kt @@ -0,0 +1,23 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +/** + * Boolean value based audio constraints. + * + * @see + * Available constraints in media constraints interface implementation + */ +enum class BooleanAudioConstraints(override val constraintString: String) : WebRtcConstraint { + DISABLE_AUDIO_PROCESSING("echoCancellation"), + ECHO_CANCELLATION("googEchoCancellation"), + ECHO_CANCELLATION_2("googEchoCancellation2"), + DELAY_AGNOSTIC_ECHO_CANCELLATION("googDAEchoCancellation"), + AUTO_GAIN_CONTROL("googAutoGainControl"), + AUTO_GAIN_CONTROL_2("googAutoGainControl2"), + NOISE_SUPPRESSION("googNoiseSuppression"), + NOISE_SUPPRESSION_2("googNoiseSuppression2"), + INTELLIGIBILITY_ENHANCER("intelligibilityEnhancer"), + LEVEL_CONTROL("levelControl"), + HIGH_PASS_FILTER("googHighpassFilter"), + TYPING_NOISE_DETECTION("googTypingNoiseDetection"), + AUDIO_MIRRORING("googAudioMirroring") +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/IntegerAudioConstraints.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/IntegerAudioConstraints.kt new file mode 100644 index 00000000..9634d5b9 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/IntegerAudioConstraints.kt @@ -0,0 +1,11 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +/** + * Integer value based audio constraints. + * + * @see + * Available constraints in media constraints interface implementation + */ +enum class IntegerAudioConstraints(override val constraintString: String) : WebRtcConstraint { + LEVEL_CONTROL_INITIAL_PEAK_LEVEL_DBFS("levelControlInitialPeakLevelDBFS"), +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/MediaConstraintsExt.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/MediaConstraintsExt.kt new file mode 100644 index 00000000..9922bca5 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/MediaConstraintsExt.kt @@ -0,0 +1,14 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +import org.webrtc.MediaConstraints + +internal fun MediaConstraints.addConstraints(constraints: WebRtcConstraints<*, *>) { + mandatory.addAll(constraints.mandatoryKeyValuePairs) + optional.addAll(constraints.optionalKeyValuePairs) +} + +internal fun MediaConstraints.addConstraints(vararg constraints: WebRtcConstraints<*, *>) { + constraints.forEach { + addConstraints(it) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/OfferAnswerConstraints.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/OfferAnswerConstraints.kt new file mode 100644 index 00000000..b49be13a --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/OfferAnswerConstraints.kt @@ -0,0 +1,25 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +enum class OfferAnswerConstraints(override val constraintString: String) : + WebRtcConstraint { + + OFFER_TO_RECEIVE_AUDIO("OfferToReceiveAudio"), + OFFER_TO_RECEIVE_VIDEO("OfferToReceiveVideo"), + /** + * Many codec's and systems are capable of detecting "silence" and changing their behavior in this + * case by doing things such as not transmitting any media. In many cases, such as when dealing + * with emergency calling or sounds other than spoken voice, it is desirable to be able to turn + * off this behavior. This option allows the application to provide information about whether it + * wishes this type of processing enabled or disabled. + */ + VOICE_ACTIVITY_DETECTION("VoiceActivityDetection"), + /** + * Tries to restart connection after it was in failed or disconnected state + */ + ICE_RESTART("IceRestart"), + /** + * Google specific constraint for BUNDLE enable/disable. + */ + GOOG_USE_RTP_MUX("googUseRtpMUX") + +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/PeerConnectionConstraints.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/PeerConnectionConstraints.kt new file mode 100644 index 00000000..c23eaa31 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/PeerConnectionConstraints.kt @@ -0,0 +1,31 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +/** + * These constraints should be used during PeerConnection construction. + * + * @see + * Available constraints in media constraints interface implementation + */ +enum class PeerConnectionConstraints(override val constraintString: String) : WebRtcConstraint { + /** + * Enabling allows to stream between firefox and chrome + */ + DTLS_SRTP_KEY_AGREEMENT_CONSTRAINT("DtlsSrtpKeyAgreement"), + ENABLE_RTP_DATA_CHANNELS("RtpDataChannels"), + /** + * Differentiated Services Code Point - DiffServ is a coarse-grained, class-based mechanism for traffic management. + * @see DSCP + */ + GOOG_DSCP("googDscp"), + GOOG_IPV6("googIPv6"), + /** + * Video stops as soon as you don't have enough bandwidth for the video. + */ + GOOG_SUSPEND_VIDEO("googSuspendBelowMinBitrate"), + GOOG_COMBINED_AUDIO_VIDEO_BWE("googCombinedAudioVideoBwe"), + /** + * Allow to reduce video quality when cpu usage is high + */ + GOOG_CPU_OVERUSE_DETECTION("googCpuOveruseDetection"), + GOOG_PAYLOAD_PADDING("googPayloadPadding") +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraint.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraint.kt new file mode 100644 index 00000000..d2de5688 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraint.kt @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +import org.webrtc.MediaConstraints + +interface WebRtcConstraint { + + val constraintString: String + + fun toKeyValuePair(value: T) = MediaConstraints.KeyValuePair(constraintString, value.toString()) +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraints.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraints.kt new file mode 100644 index 00000000..cbb052c3 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/streaming/constraints/WebRtcConstraints.kt @@ -0,0 +1,46 @@ +package nl.entreco.dartsscorecard.streaming.constraints + +open class WebRtcConstraints, E> { + + private val mandatory: MutableMap, E> = mutableMapOf() + private val optional: MutableMap, E> = mutableMapOf() + + internal val mandatoryKeyValuePairs + get() = toKeyValuePairs(mandatory) + + internal val optionalKeyValuePairs + get() = toKeyValuePairs(optional) + + + /** + * Adds all constraints. If constraints are duplicated value from inserted collection will be used. + * @see [addAll] + */ + operator fun plusAssign(other: WebRtcConstraints) = addAll(other) + + /** + * Adds mandatory constraint. If constraint is already present new value will be used. + */ + fun addMandatoryConstraint(constraint: T, value: E) { + mandatory[constraint] = value + } + + /** + * Adds optional constraint. If constraint is already present new value will be used. + */ + fun addOptionalConstraint(constraint: T, value: E) { + optional[constraint] = value + } + + /** + * Adds all constraints. If constraints are duplicated value from inserted collection will be used. + */ + fun addAll(other: WebRtcConstraints) { + mandatory.putAll(other.mandatory) + optional.putAll(other.optional) + } + + private fun toKeyValuePairs(constraintsMap: Map, E>) = constraintsMap.map { (constraint, enabled) -> + constraint.toKeyValuePair(enabled) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/TvBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/TvBinding.kt new file mode 100644 index 00000000..530154df --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/TvBinding.kt @@ -0,0 +1,14 @@ +package nl.entreco.dartsscorecard.tv + +import android.databinding.BindingAdapter +import android.view.View +import android.view.ViewGroup + +object TvBinding { + + @JvmStatic + @BindingAdapter("showIf") + fun doShowViewIf(view: View, show: Boolean){ + view.visibility = if(show) View.VISIBLE else View.GONE + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvActivity.kt new file mode 100644 index 00000000..7e5f9408 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvActivity.kt @@ -0,0 +1,45 @@ +package nl.entreco.dartsscorecard.tv.launch + +import android.content.Context +import android.content.Intent +import android.databinding.DataBindingUtil +import android.os.Bundle +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.base.ViewModelActivity +import nl.entreco.dartsscorecard.databinding.ActivityTvLaunchBinding +import nl.entreco.dartsscorecard.di.tv.TvLaunchModule + +class LaunchTvActivity : ViewModelActivity() { + + private lateinit var binding: ActivityTvLaunchBinding + private val component by componentProvider { it.plus(TvLaunchModule(binding.remoteView)) } + private val viewModel by lazy { component.viewModel() } + private val navigator by lazy { component.navigator() } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = DataBindingUtil.setContentView(this, R.layout.activity_tv_launch) + binding.animator = LaunchTvAnimator(binding) + binding.viewModel = viewModel + binding.navigator = navigator + } + + override fun onStart() { + super.onStart() + viewModel.onStart() + } + + override fun onStop() { + viewModel.onStop() + viewModel.disconnect() + super.onStop() + } + + companion object { + @JvmStatic + fun launch(context: Context) { + val intent = Intent(context, LaunchTvActivity::class.java) + context.startActivity(intent) + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvAnimator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvAnimator.kt new file mode 100644 index 00000000..337bfc31 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvAnimator.kt @@ -0,0 +1,43 @@ +package nl.entreco.dartsscorecard.tv.launch + +import android.view.View +import android.view.animation.AccelerateDecelerateInterpolator +import nl.entreco.dartsscorecard.databinding.ActivityTvLaunchBinding + +class LaunchTvAnimator(binding: ActivityTvLaunchBinding) { + + private val animator = LaunchAnimatorHandler( + binding.includeLaunchHeader.lets, + binding.includeLaunchHeader.play, + binding.includeLaunchHeader.dart) + + init { + animator.init() + } + + internal class LaunchAnimatorHandler(private val lets: View, private val play: View, + private val darts: View) { + + private val horizontalTranslation: Float = 800F + private val duration: Long = 250 + private val durationTwice: Long = 500 + + init { + lets.also { it.translationX = -horizontalTranslation } + play.also { it.translationX = horizontalTranslation } + darts.also { it.translationX = -horizontalTranslation } + } + + + fun init() { + lets.animate().translationX(0F).setDuration(duration).setInterpolator( + AccelerateDecelerateInterpolator()).start() + play.animate().translationX(0F).setStartDelay(duration).setDuration(duration) + .setInterpolator( + AccelerateDecelerateInterpolator()).start() + darts.animate().translationX(0F).setStartDelay(durationTwice).setDuration(duration) + .setInterpolator( + AccelerateDecelerateInterpolator()).start() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvBinding.kt new file mode 100644 index 00000000..05ccce81 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvBinding.kt @@ -0,0 +1,18 @@ +package nl.entreco.dartsscorecard.tv.launch + +import android.databinding.BindingAdapter +import android.view.View +import android.view.ViewGroup + +object LaunchTvBinding { + + @JvmStatic + @BindingAdapter("attachMatch", "launchNavigator") + fun attachMatchFragmentToContainer(view: ViewGroup, attach: Boolean, navigator: LaunchTvNavigator){ + if(attach){ + navigator.attach() + } else { + navigator.detach() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvNavigator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvNavigator.kt new file mode 100644 index 00000000..1e897562 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvNavigator.kt @@ -0,0 +1,22 @@ +package nl.entreco.dartsscorecard.tv.launch + +import android.support.v4.app.FragmentManager +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.dartsscorecard.tv.match.MatchFragment +import javax.inject.Inject + +class LaunchTvNavigator @Inject constructor(@ActivityScope private val fm: FragmentManager) { + fun attach() { +// fm.beginTransaction() +// .add(R.id.matchContainer, MatchFragment(), MatchFragment.TAG) +// .commit() + } + + fun detach() { +// val frag = fm.findFragmentByTag(MatchFragment.TAG) +// fm.beginTransaction() +// .remove(frag) +// .commit() + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvViewModel.kt new file mode 100644 index 00000000..150221e7 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/launch/LaunchTvViewModel.kt @@ -0,0 +1,150 @@ +package nl.entreco.dartsscorecard.tv.launch + +import android.content.ComponentName +import android.content.ServiceConnection +import android.databinding.ObservableBoolean +import android.databinding.ObservableField +import android.os.IBinder +import nl.entreco.dartsscorecard.di.application.ApplicationScope +import nl.entreco.dartsscorecard.di.tv.TvScope +import nl.entreco.dartsscorecard.play.stream.ServiceLauncher +import nl.entreco.dartsscorecard.streaming.ReceiverService +import nl.entreco.dartsscorecard.streaming.ReceivingServiceListener +import nl.entreco.domain.streaming.* +import nl.entreco.domain.streaming.receive.ListenForDisconnectsUsecase +import nl.entreco.domain.streaming.receive.RegisterReceiverRequest +import nl.entreco.domain.streaming.receive.RegisterReceiverResponse +import nl.entreco.domain.streaming.receive.RegisterReceiverUsecase +import nl.entreco.shared.log.Logger +import org.webrtc.PeerConnection +import org.webrtc.SurfaceViewRenderer +import javax.inject.Inject +import javax.inject.Named + +class LaunchTvViewModel @Inject constructor( + @ApplicationScope private val logger: Logger, + @TvScope @Named("remote") private val remoteVideoView: SurfaceViewRenderer, + private val disconnectUsecase: DisconnectUsecase, + private val listenForDisconnectsUsecase: ListenForDisconnectsUsecase, + private val registerReceiverUsecase: RegisterReceiverUsecase, + @ApplicationScope private val serviceLauncher: ServiceLauncher +) : ReceivingServiceListener { + + val isLoading = ObservableBoolean(false) + val isStreaming = ObservableBoolean(false) + val registrationCode = ObservableField("") + val connectionState = ObservableField(Unknown) + + init { + isLoading.set(true) + registerReceiverUsecase.go(RegisterReceiverRequest("todo -> maybe tv or some identifier"), + registrationOk(), registrationFailed()) + } + + private fun registrationOk(): (RegisterReceiverResponse) -> Unit = { response -> + listenForDisconnectOrders() + registrationCode.set(response.code) + isLoading.set(false) + attachService() + } + + private fun registrationFailed(): (Throwable) -> Unit = { + isLoading.set(false) + connectionState.set(Killing) + } + + private var service: ReceiverService? = null + private val serviceConnection = object : ServiceConnection { + override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { + onWebRtcServiceConnected((iBinder as (ReceiverService.LocalBinder)).service) + } + + override fun onServiceDisconnected(componentName: ComponentName) { + onWebRtcServiceDisconnected() + } + } + + private fun listenForDisconnectOrders() { + listenForDisconnectsUsecase.go { + disconnect() + isLoading.set(true) + registerReceiverUsecase.go(RegisterReceiverRequest("todo -> maybe tv or some identifier"), + registrationOk(), registrationFailed()) + } + } + + private fun attachService() { + serviceLauncher.launchReceiverService(serviceConnection) + } + + private fun onWebRtcServiceConnected(service: ReceiverService) { + logger.d("Service connected") + connectionState.set(ReadyToConnect) + this.service = service + service.attachRemoteView(remoteVideoView) + service.attachServiceActionsListener(listener = this) + } + + private fun onWebRtcServiceDisconnected() { + logger.d("Service disconnected") + connectionState.set(Disconnected) + isStreaming.set(false) + } + + override fun criticalWebRTCServiceException(throwable: Throwable) { + unbindService() + serviceLauncher.criticalWebRTCServiceException(throwable) + } + + override fun connectionStateChange(iceConnectionState: PeerConnection.IceConnectionState?) { + serviceLauncher.connectionStateChange(iceConnectionState) + when (iceConnectionState) { + PeerConnection.IceConnectionState.CONNECTED -> { + connectionState.set(Connected) + isStreaming.set(true) + } + PeerConnection.IceConnectionState.DISCONNECTED -> { +// getView()?.showWillTryToRestartMsg() + isStreaming.set(false) + connectionState.set(Disconnected) + service?.detachViews() + + isLoading.set(true) + registerReceiverUsecase.go(RegisterReceiverRequest("todo -> maybe tv or some identifier"), + registrationOk(), registrationFailed()) + } + else -> { + //no-op for now - could show or hide progress bars or messages on given event + } + } + } + + private fun unbindService() { + service?.let { + it.detachServiceActionsListener() + serviceLauncher.unbindServiceConnection(serviceConnection) + service = null + connectionState.set(Unknown) + } + } + + fun onStart() { + service?.hideBackground() + } + + fun onStop() { + service?.showBackground() + } + + fun disconnect() { + connectionState.set(Disconnecting) + disconnectUsecase.go{ + connectionState.set(Disconnected) + } + service?.let { + it.stopSelf() + it.detachViews() + unbindService() + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchFragment.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchFragment.kt new file mode 100644 index 00000000..a9ac1418 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchFragment.kt @@ -0,0 +1,24 @@ +package nl.entreco.dartsscorecard.tv.match + +import android.databinding.DataBindingUtil +import android.os.Bundle +import android.support.v17.leanback.app.BrandedSupportFragment +import android.support.v4.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.databinding.FragmentMatchBinding + +class MatchFragment : BrandedSupportFragment() { + + companion object { + const val TAG : String = "MatchFragment" + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle?): View? { + val binding = DataBindingUtil.inflate(inflater, R.layout.fragment_match, container, false) + return binding.root + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchViewModel.kt new file mode 100644 index 00000000..93b4c0d7 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/match/MatchViewModel.kt @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard.tv.match + +import android.databinding.ObservableField +import android.databinding.ObservableInt + +class MatchViewModel { + + val numSets = ObservableInt(3) + val description = ObservableField("This is description on the TV") +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/splash/SplashTvActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/splash/SplashTvActivity.kt new file mode 100644 index 00000000..90ddbbd6 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/tv/splash/SplashTvActivity.kt @@ -0,0 +1,13 @@ +package nl.entreco.dartsscorecard.tv.splash + +import android.os.Bundle +import android.support.v4.app.FragmentActivity +import nl.entreco.dartsscorecard.tv.launch.LaunchTvActivity + +class SplashTvActivity : FragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + LaunchTvActivity.launch(this) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable-television/splash.xml b/android/DartsScorecard/app/src/main/res/drawable-television/splash.xml new file mode 100644 index 00000000..eee198f1 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable-television/splash.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable-television/splash_bg.png b/android/DartsScorecard/app/src/main/res/drawable-television/splash_bg.png new file mode 100644 index 00000000..71da8f29 Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-television/splash_bg.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable-television/tv_promo.png b/android/DartsScorecard/app/src/main/res/drawable-television/tv_promo.png new file mode 100644 index 00000000..4675a788 Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-television/tv_promo.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_camera_front.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_camera_front.xml new file mode 100644 index 00000000..9a9f2ab0 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_camera_front.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_camera_rear.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_camera_rear.xml new file mode 100644 index 00000000..073b4e79 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_camera_rear.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_launcher_background.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index d5fccc53..00000000 --- a/android/DartsScorecard/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_live_start.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_live_start.xml new file mode 100644 index 00000000..c461273d --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_live_start.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_live_stop.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_live_stop.xml new file mode 100644 index 00000000..5a131a3c --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_live_stop.xml @@ -0,0 +1,12 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_mute.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_mute.xml new file mode 100644 index 00000000..2092ea89 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_mute.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_unmute.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_unmute.xml new file mode 100644 index 00000000..eb6feedb --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_unmute.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/stream_state_connect.xml b/android/DartsScorecard/app/src/main/res/drawable/stream_state_connect.xml new file mode 100644 index 00000000..6430e530 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/stream_state_connect.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable/stream_state_live.xml b/android/DartsScorecard/app/src/main/res/drawable/stream_state_live.xml new file mode 100644 index 00000000..a7bfd0d4 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/stream_state_live.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable/stream_state_stopped.xml b/android/DartsScorecard/app/src/main/res/drawable/stream_state_stopped.xml new file mode 100644 index 00000000..3894a1eb --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/stream_state_stopped.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable/tv_promo.png b/android/DartsScorecard/app/src/main/res/drawable/tv_promo.png new file mode 100644 index 00000000..4675a788 Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable/tv_promo.png differ diff --git a/android/DartsScorecard/app/src/main/res/layout-television/activity_tv_launch.xml b/android/DartsScorecard/app/src/main/res/layout-television/activity_tv_launch.xml new file mode 100644 index 00000000..b2b9051b --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout-television/activity_tv_launch.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout-television/fragment_match.xml b/android/DartsScorecard/app/src/main/res/layout-television/fragment_match.xml new file mode 100644 index 00000000..cdc3c79a --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout-television/fragment_match.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout-television/play_tv_score.xml b/android/DartsScorecard/app/src/main/res/layout-television/play_tv_score.xml new file mode 100644 index 00000000..a84b8ced --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout-television/play_tv_score.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout-television/tv_score_view.xml b/android/DartsScorecard/app/src/main/res/layout-television/tv_score_view.xml new file mode 100644 index 00000000..39cd60f3 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout-television/tv_score_view.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/activity_launch.xml b/android/DartsScorecard/app/src/main/res/layout/activity_launch.xml index 3b7e5db7..469ffd7a 100644 --- a/android/DartsScorecard/app/src/main/res/layout/activity_launch.xml +++ b/android/DartsScorecard/app/src/main/res/layout/activity_launch.xml @@ -23,7 +23,8 @@ + android:layout_weight="1" + android:layout_gravity="center"> diff --git a/android/DartsScorecard/app/src/main/res/layout/activity_play_01.xml b/android/DartsScorecard/app/src/main/res/layout/activity_play_01.xml index 948369bf..5ca48cf9 100644 --- a/android/DartsScorecard/app/src/main/res/layout/activity_play_01.xml +++ b/android/DartsScorecard/app/src/main/res/layout/activity_play_01.xml @@ -16,6 +16,10 @@ name="statViewModel" type="nl.entreco.dartsscorecard.play.live.LiveStatViewModel" /> + + @@ -38,9 +42,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" app:animator="@{animator}" - app:snack="@{viewModel.errorMsg}" app:finished="@{viewModel.finished}" - app:loading="@{viewModel.loading}"> + app:loading="@{viewModel.loading}" + app:snack="@{viewModel.errorMsg}"> + + @@ -63,12 +73,14 @@ android:layout_marginStart="@dimen/def" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:navigator="@{navigator}" - app:viewModel="@{statViewModel}" /> + app:viewModel="@{statViewModel}" + app:controlStreamViewModel="@{controlStreamViewModel}"/> + type="nl.entreco.dartsscorecard.faq.WtfViewModel" /> + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/fragment_stream.xml b/android/DartsScorecard/app/src/main/res/layout/fragment_stream.xml new file mode 100644 index 00000000..b1b61afa --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout/fragment_stream.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/play_01_main.xml b/android/DartsScorecard/app/src/main/res/layout/play_01_main.xml index f415af64..9f1e103c 100644 --- a/android/DartsScorecard/app/src/main/res/layout/play_01_main.xml +++ b/android/DartsScorecard/app/src/main/res/layout/play_01_main.xml @@ -9,6 +9,10 @@ name="viewModel" type="nl.entreco.dartsscorecard.play.live.LiveStatViewModel" /> + + @@ -26,28 +30,72 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" + android:animateLayoutChanges="true" android:background="@drawable/stats_bg" android:clipChildren="false" android:clipToPadding="false" tools:alpha="1"> + + + + + + + + + + + + type="nl.entreco.dartsscorecard.faq.WtfSearchable" /> + type="nl.entreco.dartsscorecard.faq.WtfModel" /> @@ -19,6 +19,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="@dimen/small" + android:padding="@dimen/small" android:elevation="4dp"> - + android:id="@+id/menu_stream" + android:icon="@drawable/ic_live_start" + android:title="@string/stream_start" + android:visible="false" + app:showAsAction="always" /> - + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/values-nl/strings.xml b/android/DartsScorecard/app/src/main/res/values-nl/strings.xml new file mode 100644 index 00000000..47b006f7 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/values-nl/strings.xml @@ -0,0 +1,173 @@ + + + + + First to %1$s + individueel + totaal + Set + Leg + No Score + Bust + Undo + Klik om te hervatten + Hervatten + + + Profiel Maken + Profiel selecteren + Speler selecteren + Profiel wijzigen + 01 Match instellen + Beta Features + @string/wtf + + + @string/resume + Start new 01 + Profielen beheren + Beta + What the FAQ + Start Stream + Stop Stream + Camera and audio toegang is vereist om te Streamen + Kan app settings niet openen. Om permissies toe te kennen, ga je naar de instellingen van deze app. + Instellingen + + + STEM + %1$s STEMMEN + %1$s %2$s + You are AWESOME & will no longer see those annoying ads ;) + THNX + <p>Zodra deze feature <b>%1$s</b> stemmen heeft, zullen we de implementatie starten.</p><p>Alle donaties <b>verwijderen ook alle advertenties</b> in de app</p> + <b>Bekijk de video</b> + + + Selecteer spelers + Kies spelersnaam + Of kies een bestaande speler + Team + Kies x01 score + Start score + Aantal sets + Aantal legs + Annuleren + - + + + Doorgaan + Sponsored by + Powered by + + + + Geniet je van Darts Scorecard? + Heb je even om de app te beoordelen?\nDat zouden we enorm waarderen + Nee + Nu ff niet + + + to throw + to throw first + Game on + Revanche? + Kies Team dat eerst mag gooien + + + Favoriete dubbel: %1$s + Spelersnaam + Favoriete dubbel + Profiel verwijderd + + + Hoeveel Darts heb je gebruikt? + + + Match Statistieken + Breaks Made + Dubbel Success + Hoogste Score + Hoogste Out + 180\'s + 140+ + 100+ + 60+ + 20+ + gemiddelde + + + Code invoeren + Streaming Service + Receiving Service + Start Streaming + Verbinden… + Connect + Live Stream + Enter code + + + Streaming + Uw camera beelden worden naar de tv gestreamed + Streaming to Television + + + Nog geen statistieken beschikbaar + Speel een volledige wedstrijd en check daana hier hoe je het doet + Matches Gespeeld + Totale gemiddelde + 1e 9 gemiddelde + Win % + Checkout % + #180\'s + #140+ + #100+ + #60+ + #20+ + #Bust/ Bounce/ NoScore + + + F.A.Q. doorzoeken + + + Statistieken archiveer Service + Archiveer statistieken + Bereken je stats en gemiddeldes + Nieuwe stats, gemiddeldes en hiscores aan het berekenen + + + BDO World Cup - halve finales + PDC World Cup - halve finales + + + Profielen van spelers die zijn verwijderd, kunnen niet worden bekeken + Kan match niet ophalen. + Je kunt je momenteel niet revancheren. + Speler niet aangemaakt. + Momenteel kun je geen donaties maken. + Kan de spelers lijst niet ophalen. + Kan momenteel de statistieken niet ophalen + Een speler met dezelfde naam bestaat al. Kies een andere naam + Ongeldige spelersnaam + Kies de gewenste spelersnaam + Nog geen profielen. Speel een Match, of voeg profielen toe met de + button + Deze speler doet al mee aan deze wedstrijd + + + delete + Submit darts + Add player + Enter Player name + Existing Players + Add profile picture + Vote for this feature + @string/number_of_sets + @string/number_of_legs + Plus 1 set + Minus 1 set + Plus 1 leg + Minus 1 leg + Player Profiles + FAQ items + Which features would you like to see added to the app + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/values-television/strings_tv.xml b/android/DartsScorecard/app/src/main/res/values-television/strings_tv.xml new file mode 100644 index 00000000..85687bec --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/values-television/strings_tv.xml @@ -0,0 +1,4 @@ + + + Enter this code on your phone + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/values-television/styles_tv.xml b/android/DartsScorecard/app/src/main/res/values-television/styles_tv.xml new file mode 100644 index 00000000..9ea93a84 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/values-television/styles_tv.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/values/keys.xml b/android/DartsScorecard/app/src/main/res/values/keys.xml index 37d1ef74..37a4d464 100644 --- a/android/DartsScorecard/app/src/main/res/values/keys.xml +++ b/android/DartsScorecard/app/src/main/res/values/keys.xml @@ -1,8 +1,8 @@ - ca-app-pub-3793327349392749~1846337901 - ca-app-pub-3793327349392749/2238054293 - ca-app-pub-3793327349392749/3337437992 - ca-app-pub-3793327349392749/9019610403 + ca-app-pub-3793327349392749~1846337901 + ca-app-pub-3793327349392749/2238054293 + ca-app-pub-3793327349392749/3337437992 + ca-app-pub-3793327349392749/9019610403 \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/values/strings.xml b/android/DartsScorecard/app/src/main/res/values/strings.xml index 55acdb22..98bb951a 100644 --- a/android/DartsScorecard/app/src/main/res/values/strings.xml +++ b/android/DartsScorecard/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - Darts Scorecard + Darts Scorecard First to %1$s @@ -28,6 +28,11 @@ Manage Profiles Beta What the FAQ + Start Stream + Stop Stream + Camera and audio access is needed to Stream + Couldn\'t open app settings. To grant permissions please visit settings of this app. + Settings VOTE @@ -54,6 +59,12 @@ Sponsored by Powered by + + Enjoying Darts Scorecard? + Do you have a second to rate our app?\nWe would really appreciate that + Nope + Not now + to throw to throw first @@ -62,7 +73,7 @@ Select Team to throw first - Favourite double %1$s + Favourite double: %1$s Player name Favourite double Profile deleted @@ -83,6 +94,21 @@ 20+ average + + Enter Code + Streaming Service + Receiving Service + Start Streaming + Connecting… + Connect + Live Stream + Enter code + + + Streaming + Your camera output is being streamed to the TV + Streaming to Television + No stats available yet Complete a game and come back here to see how you\'re doing @@ -103,9 +129,9 @@ Archive Stats Service - Archive stats - Calculating stats & averages - Calculating new stats, averages & hiscores + Archive stats + Calculating stats & averages + Calculating new stats, averages & hiscores BDO World Cup - semi finals diff --git a/android/DartsScorecard/app/src/main/res/values/strings_menu.xml b/android/DartsScorecard/app/src/main/res/values/strings_menu.xml index 14a54790..c8d90b20 100644 --- a/android/DartsScorecard/app/src/main/res/values/strings_menu.xml +++ b/android/DartsScorecard/app/src/main/res/values/strings_menu.xml @@ -1,7 +1,7 @@ - Swap Theme - Master Caller - Done - Edit + Swap Theme + Master Caller + Done + Edit \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscLoggerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/AppLoggerTest.kt similarity index 92% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscLoggerTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/AppLoggerTest.kt index 85cee757..0f3c1a80 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscLoggerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/AppLoggerTest.kt @@ -5,13 +5,13 @@ import org.junit.Test /** * Created by Entreco on 17/12/2017. */ -class DscLoggerTest { +class AppLoggerTest { init { - DscLogger.setEnabled(true) + AppLogger.setEnabled(true) } - private val subject = DscLogger("tag") + private val subject = AppLogger("tag") @Test fun `it should log 'd(msg)'`() { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscNotLoggerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscNotLoggerTest.kt index 26639b71..36ebf4a0 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscNotLoggerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/DscNotLoggerTest.kt @@ -8,10 +8,10 @@ import org.junit.Test class DscNotLoggerTest { init { - DscLogger.setEnabled(false) + AppLogger.setEnabled(false) } - private val subject = DscLogger("tag") + private val subject = AppLogger("tag") @Test fun `it should NOT log 'd(msg)' (and hence NOT crash)`() { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestBackground.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestBackground.kt index b49e867b..3d655962 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestBackground.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestBackground.kt @@ -1,6 +1,6 @@ package nl.entreco.dartsscorecard -import nl.entreco.domain.common.executors.Background +import nl.entreco.shared.threading.Background import java.util.concurrent.Future import java.util.concurrent.FutureTask diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestForeground.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestForeground.kt index 07f10be8..c33d9cd1 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestForeground.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestForeground.kt @@ -1,6 +1,6 @@ package nl.entreco.dartsscorecard -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Foreground class TestForeground : Foreground { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/AdViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/AdViewModelTest.kt index b79bc164..9b20f160 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/AdViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/AdViewModelTest.kt @@ -3,7 +3,7 @@ package nl.entreco.dartsscorecard.ad import android.arch.lifecycle.Lifecycle import com.google.android.gms.ads.AdView import com.nhaarman.mockito_kotlin.* -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.ad.FetchPurchasedItemsResponse import nl.entreco.domain.ad.FetchPurchasedItemsUsecase import nl.entreco.domain.purchases.connect.ConnectToBillingUsecase diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/DialogHelperTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/DialogHelperTest.kt index e2a11536..f0ae14da 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/DialogHelperTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/DialogHelperTest.kt @@ -3,6 +3,7 @@ package nl.entreco.dartsscorecard.base import android.support.v7.app.AlertDialog import com.nhaarman.mockito_kotlin.* import nl.entreco.domain.model.players.Team +import nl.entreco.domain.repository.RatingPrefRepository import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -18,10 +19,12 @@ class DialogHelperTest { @Mock private lateinit var mockDialog: AlertDialog @Mock private lateinit var mockBuilder: AlertDialog.Builder @Mock private lateinit var mockSelect: (Int) -> Unit + @Mock private lateinit var mockRatingPrefs: RatingPrefRepository private lateinit var subject: DialogHelper private var givenTeams: MutableList = mutableListOf() + @Before fun setUp() { whenever(mockBuilder.create()).thenReturn(mockDialog) @@ -29,7 +32,7 @@ class DialogHelperTest { whenever(mockBuilder.setPositiveButton(any(), any())).thenReturn(mockBuilder) whenever(mockBuilder.setSingleChoiceItems(anyArray(), any(), any())).thenReturn(mockBuilder) whenever(mockBuilder.setTitle(any())).thenReturn(mockBuilder) - subject = DialogHelper(mockBuilder) + subject = DialogHelper(mockBuilder, mockRatingPrefs) } @Test diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/StylerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/StylerTest.kt index 2e11c5eb..9c4de12e 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/StylerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/StylerTest.kt @@ -28,7 +28,7 @@ class StylerTest { @Mock private lateinit var mockActivity: Activity @InjectMocks private lateinit var subject: Styler - @Captor private lateinit var styleCaptor: ArgumentCaptor + @Captor private lateinit var styleCaptor: ArgumentCaptor @Test fun `it should return 'PDC' style`() { @@ -82,16 +82,16 @@ class StylerTest { assertEquals(R.style.Bdo, actualStyle) } - private fun givenStyle(@StyleRes style: Int) { - whenever(mockPrefs.getInt("curStyle", Styler.Style.PDC_2018.style)).thenReturn(style) + private fun givenStyle(style: String) { + whenever(mockPrefs.getString("curStyle", Styler.Style.PDC_2018.style)).thenReturn(style) } private fun whenSwapping(): Int { whenever(mockPrefs.edit()).thenReturn(mockEditor) - whenever(mockEditor.putInt(eq("curStyle"), any())).thenReturn(mockEditor) + whenever(mockEditor.putString(eq("curStyle"), any())).thenReturn(mockEditor) subject.switch() - verify(mockEditor).putInt(eq("curStyle"), styleCaptor.capture()) + verify(mockEditor).putString(eq("curStyle"), styleCaptor.capture()) givenStyle(styleCaptor.value) verify(mockActivity).recreate() diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallbackTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallbackTest.kt index 01dad547..166f9705 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallbackTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/base/SwipeToDeleteCallbackTest.kt @@ -59,7 +59,13 @@ class SwipeToDeleteCallbackTest { class TestSwipeToDeleteCallback(context: Context) : SwipeToDeleteCallback(context){ val swiped = AtomicBoolean(false) val drawed = AtomicBoolean(false) - override fun onSwiped(viewHolder: RecyclerView.ViewHolder?, direction: Int) { + + override fun onMove(p0: RecyclerView, p1: RecyclerView.ViewHolder, + p2: RecyclerView.ViewHolder): Boolean { + return false + } + + override fun onSwiped(p0: RecyclerView.ViewHolder, p1: Int) { swiped.set(true) } diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaModelTest.kt index 4ee31bd6..cf97405a 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaModelTest.kt @@ -8,7 +8,17 @@ import org.junit.Test * Created by entreco on 06/02/2018. */ class BetaModelTest { - private val feature = Feature("reference", "title", "description", "http://url.com", "remarks", 10000, 500, "") + private val feat1 = Feature("reference", "title", "description", "http://url.com", "remarks", 10, 150, "") + private val feat2 = Feature("reference", "title", "description", "http://url.com", "remarks", 100, 150, "") + private val feat3 = Feature("reference", "title", "description", "http://url.com", "remarks", 500, 150, "") + private val feat4 = Feature("reference", "title", "description", "http://url.com", "remarks", 1000, 150, "") + private val feat5 = Feature("reference", "title", "description", "http://url.com", "remarks", 1500, 150, "") + private val feat6 = Feature("reference", "title", "description", "http://url.com", "remarks", 5555, 150, "") + private val feat7 = Feature("reference", "title", "description", "http://url.com", "remarks", 10000, 150, "") + private val feat8 = Feature("reference", "title", "description", "http://url.com", "remarks", 12000, 150, "") + private val feat9 = Feature("reference", "title", "description", "http://url.com", "remarks", 12345, 150, "") + + private val feature = Feature("reference", "title", "description", "http://url.com", "remarks", 1500, 150, "") private val subject = BetaModel(feature) @Test @@ -18,30 +28,47 @@ class BetaModelTest { @Test fun `it should set total`() { - assertEquals("10k", subject.total) + assertEquals("1.5k", subject.total) + } + + @Test + fun `it should set total (without decimals)`() { + assertEquals("10", BetaModel(feat1).total) + assertEquals("100", BetaModel(feat2).total) + assertEquals("500", BetaModel(feat3).total) + assertEquals("1k", BetaModel(feat4).total) + assertEquals("1.5k", BetaModel(feat5).total) + assertEquals("5.6k", BetaModel(feat6).total) + assertEquals("10k", BetaModel(feat7).total) + assertEquals("12k", BetaModel(feat8).total) + assertEquals("12.3k", BetaModel(feat9).total) } @Test fun `it should set progress`() { - assertEquals(0.05F, subject.progress.get()) + assertEquals(0.1F, subject.progress.get()) } @Test fun `it should format remarks`() { assertEquals("remarks", subject.remarks.get()) } + @Test fun `it should set votable`() { assertEquals(true, subject.votable.get()) } + @Test fun `it should set description`() { assertEquals("description", subject.description.get()) } + @Test fun `it should set goal`() { - assertEquals("500 / 10k", subject.goal.get()) + assertEquals("150 / 1.5k", subject.goal.get()) } + @Test fun `it should set image`() { assertEquals("http://url.com", subject.image.get()) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModelTest.kt index d405ff36..29a4c448 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateViewModelTest.kt @@ -135,7 +135,7 @@ class DonateViewModelTest { fun `it should track Purchase Failed when make donation fails`() { givenSubject() whenMakingDonationFails() - thenPurchaseFailedIstracked("ActivityResult failed") + thenPurchaseFailedIstracked("Donation ActivityResult failed") } @Test @@ -253,7 +253,7 @@ class DonateViewModelTest { } private fun whenMakingDonationFails() { - subject.onMakeDonationFailed() + subject.onMakeDonationFailed(false) } private fun whenConsumingDonationSucceeds(productId: String, responseCode: Int) { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/application/AppModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/application/AppModuleTest.kt index d17d6946..e91f784a 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/application/AppModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/application/AppModuleTest.kt @@ -4,7 +4,7 @@ import android.content.Context import com.nhaarman.mockito_kotlin.whenever import nl.entreco.dartsscorecard.App import nl.entreco.dartsscorecard.BuildConfig -import nl.entreco.dartsscorecard.DscLogger +import nl.entreco.dartsscorecard.AppLogger import nl.entreco.data.analytics.FirebaseAnalytics import org.junit.Assert.* import org.junit.Before @@ -40,7 +40,7 @@ class AppModuleTest { @Test fun provideLogger() { - assertTrue(subject.provideLogger() is DscLogger) + assertTrue(subject.provideLogger() is AppLogger) } @Test diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/archive/ArchiveModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/archive/ArchiveModuleTest.kt index aac040e7..b7968ed1 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/archive/ArchiveModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/archive/ArchiveModuleTest.kt @@ -2,7 +2,6 @@ package nl.entreco.dartsscorecard.di.archive import nl.entreco.data.db.DscDatabase import nl.entreco.data.db.profile.ArchiveStatMapper -import nl.entreco.domain.common.log.Logger import org.junit.Assert.assertNotNull import org.junit.Test import org.junit.runner.RunWith diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/play/Play01ModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/play/Play01ModuleTest.kt index c29601e8..7f434f83 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/play/Play01ModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/play/Play01ModuleTest.kt @@ -37,11 +37,6 @@ class Play01ModuleTest { assertEquals(mockActivity, subject().provide01Activity()) } - @Test(expected = NullPointerException::class) - fun `it should provide AlertDialogBuilder`() { - subject().provideAlertDialogBuilder(mockContext) - } - @Test fun `it should provide SoundRepository`() { assertNotNull(subject().provideSoundRepository(mockContext, mockSoundPool, mockMapper, mockAudioPrefs)) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/service/ServiceModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/service/ServiceModuleTest.kt index 1f0f49f4..783266b1 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/service/ServiceModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/service/ServiceModuleTest.kt @@ -1,12 +1,19 @@ package nl.entreco.dartsscorecard.di.service +import android.app.Service import org.junit.Assert.* import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner +@RunWith(MockitoJUnitRunner::class) class ServiceModuleTest{ + @Mock private lateinit var mockService: Service + @Test fun `can be created`() { - assertNotNull(ServiceModule()) + assertNotNull(ServiceModule(mockService)) } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModuleTest.kt index d43ccb86..1e21dae0 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ViewModelModuleTest.kt @@ -36,6 +36,12 @@ class ViewModelModuleTest { assertEquals(mockActivity, subject.context()) } + + @Test(expected = NullPointerException::class) + fun `it should provide AlertDialogBuilder`() { + subject.provideAlertDialogBuilder(mockContext) + } + @Test fun `it should provide lifecycle`() { whenever(mockActivity.lifecycle).thenReturn(mockLifeCycle) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModuleTest.kt index 1c36d26e..59d7ab2b 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/api/FeatureApiModuleTest.kt @@ -4,7 +4,7 @@ import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.FirebaseFirestore import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.whenever -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import org.junit.Assert.assertNotNull import org.junit.Test import org.junit.runner.RunWith diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModuleTest.kt index e1abdb71..50cefe96 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/threading/ThreadingModuleTest.kt @@ -1,8 +1,8 @@ package nl.entreco.dartsscorecard.di.viewmodel.threading import android.os.Handler -import nl.entreco.domain.common.executors.BgExecutor -import nl.entreco.domain.common.executors.FgExecutor +import nl.entreco.shared.threading.BgExecutor +import nl.entreco.shared.threading.FgExecutor import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Before diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01AnimatorHandlerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01AnimatorHandlerTest.kt index 92104d80..81b971ff 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01AnimatorHandlerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01AnimatorHandlerTest.kt @@ -36,7 +36,7 @@ class Play01AnimatorHandlerTest { whenever(mockAnimator.scaleY(any())).thenReturn(mockAnimator) whenever(mockAnimator.scaleX(any())).thenReturn(mockAnimator) whenever(mockAnimator.setDuration(any())).thenReturn(mockAnimator) - subject = Play01Animator.Play01AnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockViewPager, mockMaxHeightView, mockView, mockView, mockView, mockView) + subject = Play01Animator.Play01AnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockViewPager, mockMaxHeightView, mockView, mockView, mockView, mockView, mockView, mockView) } @Test(expected = KotlinNullPointerException::class) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01NavigatorTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01NavigatorTest.kt index 9acd369a..272d2511 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01NavigatorTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01NavigatorTest.kt @@ -1,8 +1,10 @@ package nl.entreco.dartsscorecard.play +import android.support.v4.app.FragmentManager import android.view.View import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.verify +import com.nhaarman.mockito_kotlin.whenever import nl.entreco.dartsscorecard.profile.view.ProfileActivity import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team @@ -20,6 +22,7 @@ class Play01NavigatorTest { @Mock private lateinit var mockView: View @Mock private lateinit var mockActivity: Play01Activity + @Mock private lateinit var mockFragmentManager: FragmentManager private lateinit var subject: Play01Navigator @Test(expected = NotAMockException::class) @@ -37,6 +40,7 @@ class Play01NavigatorTest { } private fun givenSubject() { + whenever(mockActivity.supportFragmentManager).thenReturn(mockFragmentManager) subject = Play01Navigator(mockActivity) } diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelMasterCallerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelMasterCallerTest.kt index 52d044d9..de04eb7f 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelMasterCallerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelMasterCallerTest.kt @@ -10,7 +10,7 @@ import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.DialogHelper import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team @@ -21,6 +21,7 @@ import nl.entreco.domain.play.revanche.RevancheUsecase import nl.entreco.domain.play.start.Play01Request import nl.entreco.domain.play.start.Play01Response import nl.entreco.domain.play.start.Play01Usecase +import nl.entreco.domain.rating.AskForRatingUsecase import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.settings.ScoreSettings import org.junit.Assert.assertEquals @@ -38,6 +39,7 @@ class Play01ViewModelMasterCallerTest { @Mock private lateinit var mockMenu: Menu @Mock private lateinit var mockMenuItem: MenuItem @Mock private lateinit var mockPlayGameUsecase: Play01Usecase + @Mock private lateinit var mockAskForRatingUsecase: AskForRatingUsecase @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase @Mock private lateinit var mockAudioPrefs: AudioPrefRepository @Mock private lateinit var mockAdProvider: AdViewModel @@ -97,7 +99,7 @@ class Play01ViewModelMasterCallerTest { } private fun givenGameAndRequest(vararg loaders: GameLoadedNotifier) { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(mockRequest, mockGameLoaded, *loaders) } @@ -106,7 +108,6 @@ class Play01ViewModelMasterCallerTest { val score = Score(501) whenever(mockGame.id).thenReturn(1) whenever(mockGame.previousScore()).thenReturn(score) - whenever(mockGame.isNewMatchLegOrSet()).thenReturn(false) whenever(mockGame.getTurnCount()).thenReturn(1) whenever(mockGame.wasBreakMade(any())).thenReturn(false) whenever(mockGame.next).thenReturn(Next(State.NORMAL, Team(arrayOf(player)), 0, player, score)) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelRevancheTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelRevancheTest.kt index 10cb9f7d..6094cecc 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelRevancheTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelRevancheTest.kt @@ -6,7 +6,7 @@ import com.nhaarman.mockito_kotlin.verify import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.DialogHelper import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.Game import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.mastercaller.MasterCaller @@ -16,6 +16,7 @@ import nl.entreco.domain.play.revanche.RevancheUsecase import nl.entreco.domain.play.start.Play01Request import nl.entreco.domain.play.start.Play01Response import nl.entreco.domain.play.start.Play01Usecase +import nl.entreco.domain.rating.AskForRatingUsecase import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.settings.ScoreSettings import org.junit.Test @@ -36,6 +37,7 @@ class Play01ViewModelRevancheTest { @Mock private lateinit var mockRevancheUsecase: RevancheUsecase @Mock private lateinit var mockGameListeners: Play01Listeners @Mock private lateinit var mockMasterCaller: MasterCaller + @Mock private lateinit var mockAskForRatingUsecase: AskForRatingUsecase @Mock private lateinit var mockLoadNotifier: GameLoadedNotifier @Mock private lateinit var mockDialogHelper: DialogHelper @Mock private lateinit var mockLogger: Logger @@ -59,7 +61,7 @@ class Play01ViewModelRevancheTest { } private fun givenFullyLoadedSubject() { - subject = Play01ViewModel(mockPlay01Usecamse, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlay01Usecamse, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(Play01Request(1, "1|2", 501, 1, 1, 1), mockLoadNotifier) verify(mockPlay01Usecamse).loadGameAndStart(any(), doneCaptor.capture(), any()) doneCaptor.lastValue.invoke(Play01Response(mockGame, mockScoreSettings, arrayOf(team1, team2), "1|2")) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelTest.kt index 6bd5cc98..8684fc88 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelTest.kt @@ -5,7 +5,7 @@ import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.DialogHelper import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier import nl.entreco.dartsscorecard.play.score.TeamScoreListener -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team @@ -21,6 +21,7 @@ import nl.entreco.domain.play.start.MarkGameAsFinishedRequest import nl.entreco.domain.play.start.Play01Request import nl.entreco.domain.play.start.Play01Response import nl.entreco.domain.play.start.Play01Usecase +import nl.entreco.domain.rating.AskForRatingUsecase import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.settings.ScoreSettings import nl.entreco.domain.setup.game.CreateGameRequest @@ -46,6 +47,7 @@ class Play01ViewModelTest { @Mock private lateinit var mockScore: Score @Mock private lateinit var mockRequest: Play01Request @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase + @Mock private lateinit var mockAskForRatingUsecase: AskForRatingUsecase @Mock private lateinit var mockAdProvider: AdViewModel @Mock private lateinit var mockAudioPrefs: AudioPrefRepository @Mock private lateinit var mockPlayGameUsecase: Play01Usecase @@ -83,7 +85,7 @@ class Play01ViewModelTest { @Test fun `it should stop mastercaller on stop`() { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.stop() verify(mockMasterCaller).stop() } @@ -220,12 +222,12 @@ class Play01ViewModelTest { game = Game(101, givenArbiter).start(0, givenTeams) req = Play01Request(gameId, teamIds, createGameRequest.startScore, createGameRequest.startIndex, createGameRequest.numLegs, createGameRequest.numSets) givenTeamScoreListeners = listOf(mockTeamScoreListener, mockTeamScoreListener) - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(req, mockCreatedNotifier, *loaders) } private fun givenFullyLoadedMockGame() { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(mockRequest, mockCreatedNotifier) verify(mockPlayGameUsecase).loadGameAndStart(any(), doneCaptor.capture(), any()) doneCaptor.firstValue.invoke(Play01Response(mockGame, mockScoreSettings, givenTeams, teamIds)) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelUndoTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelUndoTest.kt index 7345f121..cc92708a 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelUndoTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ViewModelUndoTest.kt @@ -4,7 +4,7 @@ import com.nhaarman.mockito_kotlin.* import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.DialogHelper import nl.entreco.dartsscorecard.play.score.GameLoadedNotifier -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.Game import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.mastercaller.MasterCaller @@ -15,6 +15,7 @@ import nl.entreco.domain.play.start.Play01Response import nl.entreco.domain.play.start.Play01Usecase import nl.entreco.domain.play.stats.UndoTurnRequest import nl.entreco.domain.play.stats.UndoTurnResponse +import nl.entreco.domain.rating.AskForRatingUsecase import nl.entreco.domain.repository.AudioPrefRepository import nl.entreco.domain.settings.ScoreSettings import org.junit.Assert.assertEquals @@ -36,6 +37,7 @@ class Play01ViewModelUndoTest { @Mock private lateinit var mockResponse: Play01Response @Mock private lateinit var mockAdProvider: AdViewModel @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase + @Mock private lateinit var mockAskForRatingUsecase: AskForRatingUsecase @Mock private lateinit var mockAudioPrefs: AudioPrefRepository @Mock private lateinit var mockLoad: GameLoadedNotifier @Mock private lateinit var mockLoaders: GameLoadedNotifier @@ -82,7 +84,7 @@ class Play01ViewModelUndoTest { whenever(mockResponse.teamIds).thenReturn("") whenever(mockResponse.settings).thenReturn(mockSettings) - subject = Play01ViewModel(mockPlay01Usecase, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) + subject = Play01ViewModel(mockPlay01Usecase, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAskForRatingUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(mockRequest, mockLoad, mockLoaders) verify(mockPlay01Usecase).loadGameAndStart(eq(mockRequest), load.capture(), any()) load.lastValue.invoke(mockResponse) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/input/InputViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/input/InputViewModelTest.kt index e3cf4086..f80f0d86 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/input/InputViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/input/InputViewModelTest.kt @@ -5,7 +5,7 @@ import com.nhaarman.mockito_kotlin.* import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.play.Play01Animator import nl.entreco.domain.Analytics -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.NoPlayer import nl.entreco.domain.model.players.Player diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt index 2c0c7057..5d3039e3 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt @@ -2,7 +2,7 @@ package nl.entreco.dartsscorecard.play.live import com.nhaarman.mockito_kotlin.* import nl.entreco.dartsscorecard.archive.ArchiveServiceLauncher -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.Game import nl.entreco.domain.model.LiveStat import nl.entreco.domain.model.Score diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/score/ScoreViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/score/ScoreViewModelTest.kt index 4833dd72..59fb7ec2 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/score/ScoreViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/score/ScoreViewModelTest.kt @@ -2,7 +2,6 @@ package nl.entreco.dartsscorecard.play.score import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.verifyZeroInteractions -import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team @@ -11,7 +10,6 @@ import nl.entreco.domain.settings.ScoreSettings import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -import org.junit.runner.Description import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.junit.MockitoJUnitRunner diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/Setup01ViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/Setup01ViewModelTest.kt index be0c25c3..e5bca00b 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/Setup01ViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/Setup01ViewModelTest.kt @@ -1,7 +1,7 @@ package nl.entreco.dartsscorecard.setup import com.nhaarman.mockito_kotlin.* -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.launch.ExtractTeamsRequest import nl.entreco.domain.launch.ExtractTeamsResponse import nl.entreco.domain.launch.ExtractTeamsUsecase diff --git a/android/DartsScorecard/build.gradle b/android/DartsScorecard/build.gradle index db8b5f29..bc3886ed 100644 --- a/android/DartsScorecard/build.gradle +++ b/android/DartsScorecard/build.gradle @@ -1,6 +1,5 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - apply from: 'scripts/dependencies.gradle' repositories { @@ -31,6 +30,7 @@ allprojects { google() jcenter() maven { url "https://jitpack.io" } + maven { url "https://dl.bintray.com/netguru/maven/" } } } diff --git a/android/DartsScorecard/data/build.gradle b/android/DartsScorecard/data/build.gradle index a8ab1150..03d70371 100644 --- a/android/DartsScorecard/data/build.gradle +++ b/android/DartsScorecard/data/build.gradle @@ -11,16 +11,21 @@ android { dependencies { implementation project(":domain") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" - implementation "com.google.firebase:firebase-core:$firebase" - implementation "com.google.firebase:firebase-firestore:$firebase" - implementation "com.google.firebase:firebase-config:$firebase" + implementation project(":shared") + + // Annotation Processing + kapt "android.arch.persistence.room:compiler:$room" + + // Implementation + implementation "com.google.firebase:firebase-core:$fbCore" + implementation "com.google.firebase:firebase-firestore:$fbStore" + implementation "com.google.firebase:firebase-config:$fbConfig" + implementation "com.google.firebase:firebase-database:$fbDatabase" + implementation "android.arch.persistence.room:runtime:$room" + implementation "com.android.support:appcompat-v7:$support" implementation "com.android.support:exifinterface:$support" implementation "android.arch.lifecycle:livedata:$architecture" - implementation "android.arch.persistence.room:runtime:$room" - kapt "android.arch.persistence.room:compiler:$room" - implementation "com.google.code.gson:gson:$gson" testImplementation "junit:junit:$junit" diff --git a/android/DartsScorecard/data/proguard-rules.pro b/android/DartsScorecard/data/proguard-rules.pro index f1b42451..c8de4dbe 100644 --- a/android/DartsScorecard/data/proguard-rules.pro +++ b/android/DartsScorecard/data/proguard-rules.pro @@ -19,3 +19,69 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile + +# Base Settings from Dev +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontskipnonpubliclibraryclassmembers +-dontpreverify +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +-keepattributes LineNumberTable,SourceFile,Signature,*Annotation*,Exceptions,InnerClasses + +# Crashlytics +-keepattributes *Annotation* +-keepattributes SourceFile,LineNumberTable +-keep public class * extends java.lang.Exception + +# Okio +-dontwarn okio.** +-dontnote okio.** + +# OkHttp +-dontwarn okhttp3.** + +# Billing +-keep class com.android.vending.billing.** + +# Glide +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + +# Databinding +-keepclasseswithmembernames interface android.databinding.DataBindingComponent +-dontwarn android.databinding.DataBindingComponent +-dontnote android.databinding.DataBindingComponent +-keep class android.databinding.DataBinderMapper +-dontwarn android.databinding.DataBinderMapper +-dontnote android.databinding.DataBinderMapper + +# WebRtc +-keep class org.webrtc.** { *; } +-dontnote org.apache.http.** +-dontwarn org.apache.http.** +-dontnote android.net.http.* +-dontwarn android.net.http.** +-dontnote org.apache.commons.codec.** +-dontwarn org.apache.commons.codec.** + +# Keep native methods +-keepclassmembers class * { + native ; +} + +#GMS +-keep class com.google.android.gms.common.api.internal.BasePendingResult$ReleasableResultGuardian +-keep class com.google.android.gms.** { *; } +-dontwarn com.google.android.gms.** + +-keepnames @pcom.google.android.gms.common.annotation.KeepName class * + +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/RemoteFeatureRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/RemoteFeatureRepository.kt index 9cef7b8b..676a80aa 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/RemoteFeatureRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/RemoteFeatureRepository.kt @@ -1,7 +1,7 @@ package nl.entreco.data.api.beta import com.google.firebase.firestore.* -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.beta.Feature import nl.entreco.domain.repository.FeatureRepository diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/PlayStoreBillingRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/PlayStoreBillingRepository.kt index adfd92cf..9461bf21 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/PlayStoreBillingRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/PlayStoreBillingRepository.kt @@ -63,7 +63,7 @@ class PlayStoreBillingRepository(private val context: Context, private val servi return if (bundle?.getInt(FETCH_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { - bundle.getStringArrayList(EXTRA_DETAILS_LIST).mapNotNull { response -> + bundle.getStringArrayList(EXTRA_DETAILS_LIST)!!.mapNotNull { response -> val donation = gson.fromJson(response, DonationApiData::class.java) val votes = donations.getVotes(donation.productId) @@ -81,7 +81,7 @@ class PlayStoreBillingRepository(private val context: Context, private val servi val bundle = service.getService()?.getBuyIntent(apiVersion, packageName, buy.sku(), buy.type(), payload) return if (bundle?.getInt(BUY_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { - val intent: PendingIntent = bundle.getParcelable(EXTRA_BUY_INTENT) + val intent: PendingIntent = bundle.getParcelable(EXTRA_BUY_INTENT)!! MakeDonationResponse(intent, payload) } else { @@ -100,7 +100,7 @@ class PlayStoreBillingRepository(private val context: Context, private val servi val bundle = service.getService()?.getPurchases(apiVersion, packageName, purchases.type(), purchases.token()) return if (bundle?.getInt(QUERY_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { - bundle.getStringArrayList(EXTRA_INAPP_PURCHASE_ITEM_LIST) + bundle.getStringArrayList(EXTRA_INAPP_PURCHASE_ITEM_LIST)!! } else { throw Throwable("Unable to getPurchases(), $bundle") } diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/game/LocalGameRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/game/LocalGameRepository.kt index 8a5ebdae..aec921c3 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/game/LocalGameRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/game/LocalGameRepository.kt @@ -69,6 +69,6 @@ class LocalGameRepository(db: DscDatabase, private val mapper: Mapper FileOutputStream(output).use { output -> - input.copyTo(output) + input?.copyTo(output) } } } @@ -53,7 +54,7 @@ class LocalImageRepository(private val context: Context, private val contentReso private fun getPhotoOrientation(uri: Uri): Float { contentResolver.openInputStream(uri).use { input -> - val exif = ExifInterface(input) + val exif = if (input != null) ExifInterface(input) else return 0F return when (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) { ExifInterface.ORIENTATION_ROTATE_270 -> 270F ExifInterface.ORIENTATION_ROTATE_180 -> 180F @@ -76,11 +77,13 @@ class LocalImageRepository(private val context: Context, private val contentReso val shortSide = min(width, height) / 2 val src = Rect(0, 0, width, height) - val dst = Rect(src.centerX() - shortSide, src.centerY() - shortSide, src.centerX() + shortSide, src.centerY() + shortSide) + val dst = Rect(src.centerX() - shortSide, src.centerY() - shortSide, + src.centerX() + shortSide, src.centerY() + shortSide) val matrix = Matrix() matrix.postRotate(degrees) - val tmp = Bitmap.createBitmap(bitmap, dst.left, dst.top, dst.width(), dst.height(), matrix, true) + val tmp = Bitmap.createBitmap(bitmap, dst.left, dst.top, dst.width(), dst.height(), matrix, + true) val resized = Bitmap.createScaledBitmap(tmp, size.toInt(), size.toInt(), true) @@ -90,7 +93,8 @@ class LocalImageRepository(private val context: Context, private val contentReso return resized } - private fun determineSampleSize(options: BitmapFactory.Options, startScale: Int, size: Float): Int { + private fun determineSampleSize(options: BitmapFactory.Options, startScale: Int, + size: Float): Int { var scale = startScale while (options.outWidth / scale / 2 >= size && options.outHeight / scale / 2 >= size) { scale *= 2 diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/prefs/SharedRatingPrefRepo.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/prefs/SharedRatingPrefRepo.kt new file mode 100644 index 00000000..8670fb67 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/prefs/SharedRatingPrefRepo.kt @@ -0,0 +1,22 @@ +package nl.entreco.data.prefs + +import android.content.SharedPreferences +import nl.entreco.data.prefs.SharedAudioPrefRepo.Companion.PREF_MASTER_CALLER +import nl.entreco.domain.repository.RatingPrefRepository + +class SharedRatingPrefRepo(private val prefs: SharedPreferences) : RatingPrefRepository { + + companion object { + const val PREF_SHOULD_ASK_RATING: String = "PREF_rating" + } + + override fun neverAskAgain() { + prefs.edit().apply{ + putBoolean(PREF_SHOULD_ASK_RATING, false) + }.apply() + } + + override fun shouldAskToRateApp(): Boolean { + return prefs.getBoolean(PREF_SHOULD_ASK_RATING, true) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/DisconnectFirebaseData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/DisconnectFirebaseData.kt new file mode 100644 index 00000000..385e764c --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/DisconnectFirebaseData.kt @@ -0,0 +1,9 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.gson.annotations.SerializedName + +@Keep +@IgnoreExtraProperties +internal data class DisconnectFirebaseData(@SerializedName("from") val from: String) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseAnswersRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseAnswersRepository.kt new file mode 100644 index 00000000..00509ebd --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseAnswersRepository.kt @@ -0,0 +1,55 @@ +package nl.entreco.data.stream + +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseError +import com.google.firebase.database.FirebaseDatabase +import com.google.firebase.database.ValueEventListener +import nl.entreco.domain.repository.AnswersRepository +import nl.entreco.domain.streaming.ice.DscSessionDescription +import nl.entreco.shared.log.Logger + +class FirebaseAnswersRepository( + private val db: FirebaseDatabase, + private val logger: Logger, + private val currentDeviceUuid: String +) : AnswersRepository { + + companion object { + private const val ANSWERS_PATH = "answers/" + } + + private fun deviceAnswersPath(uuid: String) = ANSWERS_PATH.plus(uuid) + + override fun create(recipientUuid: String, localSessionDescription: DscSessionDescription) { + val reference = db.getReference(deviceAnswersPath(recipientUuid)) + reference.onDisconnect().removeValue() + + val aha = SessionDescriptionFirebaseApiData() + aha.uuid = currentDeviceUuid + aha.type = localSessionDescription.type + aha.description = localSessionDescription.description + + logger.w("WEBRTC: create Answer $aha") + + reference.setValue(aha) + } + + override fun listenForNewAnswers(onChange: (DscSessionDescription) -> Unit) { + val reference = db.getReference(deviceAnswersPath(currentDeviceUuid)) + val valueListener = object : + ValueEventListener { + + override fun onCancelled(p0: DatabaseError) {} + + override fun onDataChange(p0: DataSnapshot) { + p0.getValue(SessionDescriptionFirebaseApiData::class.java)?.let { description -> + + logger.w("WEBRTC: listenForNewAnswers $description") + val session = DscSessionDescription(description.type, description.description ?: "") + onChange(session) + } + } + } + reference.addValueEventListener(valueListener) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseIceRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseIceRepository.kt new file mode 100644 index 00000000..5d9c8e36 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseIceRepository.kt @@ -0,0 +1,104 @@ +package nl.entreco.data.stream + +import com.google.firebase.database.* +import nl.entreco.domain.repository.IceRepository +import nl.entreco.domain.streaming.ice.DscIceCandidate +import nl.entreco.domain.streaming.ice.DscIceServer +import nl.entreco.shared.log.Logger + +class FirebaseIceRepository(private val db: FirebaseDatabase, + private val logger: Logger, + private val currentDeviceUuid: String) : IceRepository { + + companion object { + private const val ICE_SERVERS_PATH = "ice_servers" + private const val ICE_CANDIDATES_PATH = "ice_candidates/" + } + + private val mapper by lazy { IceCandidateMapper() } + private fun deviceIceCandidatesPath(uuid: String) = ICE_CANDIDATES_PATH.plus(uuid) + + override fun fetchIceServers(done: (List) -> Unit) { + db.getReference(ICE_SERVERS_PATH) + .addListenerForSingleValueEvent(object : ValueEventListener { + override fun onCancelled(p0: DatabaseError) { + done(emptyList()) + } + + override fun onDataChange(p0: DataSnapshot) { + val genericTypeIndicator = object : + GenericTypeIndicator>() {} + val servers = p0.getValue(genericTypeIndicator) + done(mapper.map(servers)) + } + }) + } + + override fun send(candidate: DscIceCandidate, done:(Boolean)->Unit) { + val reference = db.getReference(deviceIceCandidatesPath(currentDeviceUuid)) + with(reference) { + onDisconnect().removeValue() + push().setValue(mapper.map(candidate)){ dbError, _ -> + if(dbError != null){ + done(false) + } else { + done(true) + } + } + } + } + + override fun remove(iceCandidatesToRemove: Array, done: (Boolean) -> Unit) { + val iceCandidatesToRemoveList = mapper.map(iceCandidatesToRemove).toMutableList() + val reference = db.getReference(deviceIceCandidatesPath(currentDeviceUuid)) + + reference.runTransaction(object : Transaction.Handler { + override fun doTransaction(mutableData: MutableData): Transaction.Result { + val typeIndicator = object : GenericTypeIndicator>() {} + val currentIceCandidatesInFirebaseMap = mutableData.getValue(typeIndicator) ?: + return Transaction.success(mutableData) + + + for ((key, value) in currentIceCandidatesInFirebaseMap) { + if (iceCandidatesToRemoveList.remove(value)) { + currentIceCandidatesInFirebaseMap.remove(key) + } + } + mutableData.value = currentIceCandidatesInFirebaseMap + return Transaction.success(mutableData) + } + + override fun onComplete(databaseError: DatabaseError?, committed: Boolean, p2: DataSnapshot?) { + if (committed) { + done(true) + } else { + done(false) + } + } + }) + } + + override fun listenForIceCandidates(remoteUuid: String, add: (DscIceCandidate) -> Unit, + remove: (DscIceCandidate) -> Unit) { + db.getReference(deviceIceCandidatesPath(remoteUuid)) + .addChildEventListener(object : ChildEventListener { + override fun onCancelled(p0: DatabaseError) {} + + override fun onChildMoved(p0: DataSnapshot, p1: String?) {} + + override fun onChildChanged(p0: DataSnapshot, p1: String?) {} + + override fun onChildAdded(p0: DataSnapshot, p1: String?) { + p0.getValue(IceCandidateFirebaseApiData::class.java)?.let { + add(mapper.map(it)) + } + } + + override fun onChildRemoved(p0: DataSnapshot) { + p0.getValue(IceCandidateFirebaseApiData::class.java)?.let { + remove(mapper.map(it)) + } + } + }) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseOffersRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseOffersRepository.kt new file mode 100644 index 00000000..716d1aaf --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseOffersRepository.kt @@ -0,0 +1,53 @@ +package nl.entreco.data.stream + +import com.google.firebase.database.DataSnapshot +import com.google.firebase.database.DatabaseError +import com.google.firebase.database.FirebaseDatabase +import com.google.firebase.database.ValueEventListener +import nl.entreco.domain.repository.OffersRepository +import nl.entreco.domain.streaming.ice.DscSessionDescription +import nl.entreco.shared.log.Logger + +class FirebaseOffersRepository(private val db: FirebaseDatabase, + private val logger: Logger, + private val currentDeviceUuid: String) : OffersRepository { + + companion object { + private const val OFFERS_PATH = "offers/" + } + + private fun deviceOffersPath(uuid: String) = OFFERS_PATH.plus(uuid) + + override fun create(recipientUuid: String, localSessionDescription: DscSessionDescription) { + val reference = db.getReference(deviceOffersPath(recipientUuid)) + reference.onDisconnect().removeValue() + + val aha = SessionDescriptionFirebaseApiData() + aha.uuid = currentDeviceUuid + aha.type = localSessionDescription.type + aha.description = localSessionDescription.description + + logger.w("WEBRTC: create Offer $aha") + + reference.setValue(aha) + } + + override fun listenForNewOffersWithUuid(onChange: (String, DscSessionDescription) -> Unit) { + val reference = db.getReference(deviceOffersPath(currentDeviceUuid)) + val valueListener = object : ValueEventListener { + + override fun onCancelled(p0: DatabaseError) {} + + override fun onDataChange(p0: DataSnapshot) { + p0.getValue(SessionDescriptionFirebaseApiData::class.java)?.let { description -> + + logger.w("WEBRTC: listenForNewOffersWithUuid $description") + val session = DscSessionDescription(description.type, description.description ?: "") + onChange(description.uuid, session) + + } + } + } + reference.addValueEventListener(valueListener) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseSignallingRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseSignallingRepository.kt new file mode 100644 index 00000000..079fa9b3 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/FirebaseSignallingRepository.kt @@ -0,0 +1,150 @@ +package nl.entreco.data.stream + +import com.google.firebase.database.* +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.log.Logger + +class FirebaseSignallingRepository(private val db: FirebaseDatabase, + private val logger: Logger, + private val currentDeviceUuid: String) : SignallingRepository { + + companion object { + private const val RECEIVER_DEVICES_PATH = "receiving_devices/" + private const val STREAMER_DEVICES_PATH = "streaming_devices/" + private const val DISCONNECT_PATH = "should_disconnect/" + } + + private val onlineReceivers = RECEIVER_DEVICES_PATH.plus(currentDeviceUuid) + private val onlineStreamers = STREAMER_DEVICES_PATH.plus(currentDeviceUuid) + private fun deviceDisconnectPath(uuid: String) = DISCONNECT_PATH.plus(uuid) + + init { + logger.w("UUID: $currentDeviceUuid") + logger.w("UUID: onlineReceivers $onlineReceivers") + } + + + override fun connect() { + db.goOnline() + } + + override fun disconnect() { + db.goOffline() + } + + override fun listenForDisconnects(done: () -> Unit) { + disconnecter = Disconnecter(done) + disconnecter?.let { + db.getReference(deviceDisconnectPath(currentDeviceUuid)) + .addChildEventListener(it) + } + } + + override fun stopListenForDisconnects() { + disconnecter?.let { + db.getReference(deviceDisconnectPath(currentDeviceUuid)) + .removeEventListener(it) + } + disconnecter = null + } + + override fun sendDisconnectOrderToOtherParty(uuid: String, done: () -> Unit) { + val reference = db.getReference(deviceDisconnectPath(uuid)) + reference.setValue(DisconnectFirebaseData(currentDeviceUuid)) { databaseError, _ -> + if (databaseError != null) { + logger.e(databaseError.toString()) + } else { + logger.e("Disconnected Order ") + } + + done() + } + } + + override fun cleanDisconnectOrders(done: () -> Unit, fail: (Throwable) -> Unit) { + val reference = db.getReference(deviceDisconnectPath(currentDeviceUuid)) + reference.onDisconnect().removeValue() + reference.removeValue { dbError, _ -> + if (dbError != null) { + fail(dbError.toException()) + } else { + done() + } + } + } + + override fun setReceiverOnline(connectCode: String, done: (String) -> Unit, + fail: (Throwable) -> Unit) { + val firebaseOnlineReference = db.getReference(onlineReceivers) + with(firebaseOnlineReference) { + onDisconnect().removeValue() + setValue(ReceiverFirebaseApiData(connectCode, false)) { _, _ -> + done(connectCode) + } + } + } + + override fun setStreamerOnline(connectCode: String, done: (String?) -> Unit, + fail: (Throwable) -> Unit) { + val firebaseOnlineReference = db.getReference(onlineStreamers) + with(firebaseOnlineReference) { + onDisconnect().removeValue() + setValue(StreamerFirebaseData(connectCode, true)) { _, _ -> + findReceiverDevice(connectCode, done, fail) + } + } + } + + private fun findReceiverDevice(connectCode: String, done: (String?) -> Unit, + fail: (Throwable) -> Unit) { + var receiverUuid: String? = null + db.getReference(RECEIVER_DEVICES_PATH).runTransaction(object : Transaction.Handler { + override fun doTransaction(mutableData: MutableData): Transaction.Result { + val genericTypeIndicator = object : + GenericTypeIndicator>() {} + val availableDevices = mutableData.getValue(genericTypeIndicator) + ?: return Transaction.success(mutableData) + if (!availableDevices.isEmpty()) { + receiverUuid = deleteDeviceFromAvailable(connectCode, availableDevices) + mutableData.value = availableDevices + } + + return Transaction.success(mutableData) + } + + private fun deleteDeviceFromAvailable(connectCode: String, + availableDevices: MutableMap): String? { + val remoteDeviceUuid = availableDevices.entries.firstOrNull { it.value.code == connectCode } + ?.key + logger.d("Device number $remoteDeviceUuid was chosen because of code $connectCode.") + availableDevices.remove(remoteDeviceUuid) + return remoteDeviceUuid + } + + override fun onComplete(databaseError: DatabaseError?, completed: Boolean, + p2: DataSnapshot?) { + if (databaseError != null) { + fail(databaseError.toException()) + } else if (completed) { + done(receiverUuid) + } + } + }) + } + + private var disconnecter: ChildEventListener? = null + + private class Disconnecter(private val done: () -> Unit) : ChildEventListener { + override fun onCancelled(p0: DatabaseError) {} + + override fun onChildMoved(p0: DataSnapshot, p1: String?) {} + + override fun onChildChanged(p0: DataSnapshot, p1: String?) {} + + override fun onChildAdded(p0: DataSnapshot, p1: String?) { + done() + } + + override fun onChildRemoved(p0: DataSnapshot) {} + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateFirebaseApiData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateFirebaseApiData.kt new file mode 100644 index 00000000..80c6348a --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateFirebaseApiData.kt @@ -0,0 +1,19 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.gson.annotations.SerializedName + +@Keep +@IgnoreExtraProperties +internal data class IceCandidateFirebaseApiData( + + @SerializedName("sdpMid") + var sdpMid: String = "", + + @SerializedName("sdpMLineIndex") + var sdpMLineIndex: Int = -1, + + @SerializedName("sdp") + var sdp: String = "" +) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateMapper.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateMapper.kt new file mode 100644 index 00000000..de1caa7b --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceCandidateMapper.kt @@ -0,0 +1,34 @@ +package nl.entreco.data.stream + +import nl.entreco.domain.streaming.ice.DscIceCandidate +import nl.entreco.domain.streaming.ice.DscIceServer + +internal class IceCandidateMapper { + internal fun map(servers: ArrayList?): List { + return servers?.mapNotNull { map(it) } ?: emptyList() + } + + private fun map(apiData: IceServerFirebaseApiData): DscIceServer? { + return if (apiData.uri?.isNotBlank() == true) { + DscIceServer(apiData.uri) + } else { + null + } + } + + internal fun map(apiData: IceCandidateFirebaseApiData): DscIceCandidate { + return DscIceCandidate(apiData.sdpMid, apiData.sdpMLineIndex, apiData.sdp) + } + + internal fun map(data: DscIceCandidate) : IceCandidateFirebaseApiData { + val candidate = IceCandidateFirebaseApiData() + candidate.sdp = data.sdp + candidate.sdpMLineIndex = data.sdpMLineIndex + candidate.sdpMid = data.sdpMid + return candidate + } + + internal fun map(data: Array) : List { + return data.map { map(it) } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceServerFirebaseApiData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceServerFirebaseApiData.kt new file mode 100644 index 00000000..b992f66d --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/IceServerFirebaseApiData.kt @@ -0,0 +1,18 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.firebase.firestore.PropertyName + +@Keep +@IgnoreExtraProperties +internal data class IceServerFirebaseApiData( + @PropertyName("uri") + val uri: String? = null, + + @PropertyName("username") + val username: String? = null, + + @PropertyName("password") + val password: String? = null +) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/ReceiverFirebaseApiData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/ReceiverFirebaseApiData.kt new file mode 100644 index 00000000..65c5ba1c --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/ReceiverFirebaseApiData.kt @@ -0,0 +1,16 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.firebase.firestore.PropertyName + +@Keep +@IgnoreExtraProperties +internal data class ReceiverFirebaseApiData( + + @PropertyName("code") + val code: String = "", + + @PropertyName("inCall") + val inCall: Boolean = false +) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/SessionDescriptionFirebaseApiData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/SessionDescriptionFirebaseApiData.kt new file mode 100644 index 00000000..8686ecd5 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/SessionDescriptionFirebaseApiData.kt @@ -0,0 +1,19 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.firebase.firestore.PropertyName + +@Keep +@IgnoreExtraProperties +internal data class SessionDescriptionFirebaseApiData( + + @PropertyName("uuid") + var uuid: String = "", + + @PropertyName("type") + var type: Int = 0, + + @PropertyName("description") + var description: String? = null +) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/StreamerFirebaseData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/StreamerFirebaseData.kt new file mode 100644 index 00000000..a8b8d0e1 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/stream/StreamerFirebaseData.kt @@ -0,0 +1,14 @@ +package nl.entreco.data.stream + +import android.support.annotation.Keep +import com.google.firebase.firestore.IgnoreExtraProperties +import com.google.firebase.firestore.PropertyName + +@Keep +@IgnoreExtraProperties +internal data class StreamerFirebaseData( + @PropertyName("code") + val code: String, + @PropertyName("inCall") + val inCall: Boolean = false +) \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/wtf/RemoteWtfRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/wtf/RemoteWtfRepository.kt index 4d3d3204..11510dee 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/wtf/RemoteWtfRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/wtf/RemoteWtfRepository.kt @@ -1,7 +1,7 @@ package nl.entreco.data.wtf import com.google.firebase.firestore.* -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.repository.WtfRepository import nl.entreco.domain.wtf.WtfItem diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/api/beta/RemoteFeatureRepositoryTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/api/beta/RemoteFeatureRepositoryTest.kt index 4f0025de..21abe0f3 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/api/beta/RemoteFeatureRepositoryTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/api/beta/RemoteFeatureRepositoryTest.kt @@ -3,7 +3,7 @@ package nl.entreco.data.api.beta import com.google.firebase.firestore.CollectionReference import com.google.firebase.firestore.FirebaseFirestore import com.nhaarman.mockito_kotlin.whenever -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.beta.Feature import org.junit.Assert.* import org.junit.Ignore diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/play/local/LocalGameRepositoryTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/play/local/LocalGameRepositoryTest.kt index 0d860ebe..52efdb07 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/play/local/LocalGameRepositoryTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/play/local/LocalGameRepositoryTest.kt @@ -102,7 +102,7 @@ class LocalGameRepositoryTest { fun `it should return finished game count (10)`() { givenFinishedGames(4) whenCountingFinishedGames() - thenNumberOfFinishedGamesIs(0) + thenNumberOfFinishedGamesIs(4) } private fun givenExistingGames() { diff --git a/android/DartsScorecard/domain/build.gradle b/android/DartsScorecard/domain/build.gradle index 8d310468..fa8b8c6b 100644 --- a/android/DartsScorecard/domain/build.gradle +++ b/android/DartsScorecard/domain/build.gradle @@ -10,7 +10,8 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + implementation project(":shared") + implementation "com.android.support:support-annotations:$support" implementation "com.google.dagger:dagger:$daggerVersion" implementation "com.google.code.gson:gson:$gson" diff --git a/android/DartsScorecard/domain/proguard-rules.pro b/android/DartsScorecard/domain/proguard-rules.pro index f1b42451..c8de4dbe 100644 --- a/android/DartsScorecard/domain/proguard-rules.pro +++ b/android/DartsScorecard/domain/proguard-rules.pro @@ -19,3 +19,69 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile + +# Base Settings from Dev +-optimizationpasses 5 +-dontusemixedcaseclassnames +-dontskipnonpubliclibraryclasses +-dontskipnonpubliclibraryclassmembers +-dontpreverify +-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* +-keepattributes LineNumberTable,SourceFile,Signature,*Annotation*,Exceptions,InnerClasses + +# Crashlytics +-keepattributes *Annotation* +-keepattributes SourceFile,LineNumberTable +-keep public class * extends java.lang.Exception + +# Okio +-dontwarn okio.** +-dontnote okio.** + +# OkHttp +-dontwarn okhttp3.** + +# Billing +-keep class com.android.vending.billing.** + +# Glide +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep public class * extends com.bumptech.glide.module.AppGlideModule +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} + +# Databinding +-keepclasseswithmembernames interface android.databinding.DataBindingComponent +-dontwarn android.databinding.DataBindingComponent +-dontnote android.databinding.DataBindingComponent +-keep class android.databinding.DataBinderMapper +-dontwarn android.databinding.DataBinderMapper +-dontnote android.databinding.DataBinderMapper + +# WebRtc +-keep class org.webrtc.** { *; } +-dontnote org.apache.http.** +-dontwarn org.apache.http.** +-dontnote android.net.http.* +-dontwarn android.net.http.** +-dontnote org.apache.commons.codec.** +-dontwarn org.apache.commons.codec.** + +# Keep native methods +-keepclassmembers class * { + native ; +} + +#GMS +-keep class com.google.android.gms.common.api.internal.BasePendingResult$ReleasableResultGuardian +-keep class com.google.android.gms.** { *; } +-dontwarn com.google.android.gms.** + +-keepnames @pcom.google.android.gms.common.annotation.KeepName class * + +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/BaseUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/BaseUsecase.kt index 456eb817..0f063af7 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/BaseUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/BaseUsecase.kt @@ -1,7 +1,7 @@ package nl.entreco.domain -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground /** * Created by Entreco on 17/12/2017. diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecase.kt index 8ce2ebb6..c28e63aa 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.ad import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.BillingRepository import nl.entreco.domain.repository.GameRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecase.kt index fbace94b..8324668f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecase.kt @@ -3,8 +3,8 @@ package nl.entreco.domain.beta.donations import com.google.gson.GsonBuilder import com.google.gson.annotations.SerializedName import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.BillingRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsUsecase.kt index 8f1c6e0e..226a1968 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.beta.donations import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.BillingRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationUsecase.kt index b2ada61b..b06bc10b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.beta.donations import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.BillingRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteUsecase.kt index 15905941..482da236 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.beta.vote import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.FeatureRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsUsecase.kt index 83d79af1..73f98518 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.launch import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.model.players.Player import nl.entreco.domain.repository.PlayerRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/RetrieveLatestGameUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/RetrieveLatestGameUsecase.kt index d50ad568..c56eae57 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/RetrieveLatestGameUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/RetrieveLatestGameUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.launch import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/description/FetchMatchDescriptionUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/description/FetchMatchDescriptionUsecase.kt index 7f5ff853..d09e9fd0 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/description/FetchMatchDescriptionUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/description/FetchMatchDescriptionUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.description import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.MatchDescriptionRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishUsecase.kt index 1a96cb6e..efad6e20 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishUsecase.kt @@ -2,9 +2,8 @@ package nl.entreco.domain.play.finish import android.support.annotation.VisibleForTesting import android.support.annotation.WorkerThread -import nl.entreco.domain.common.executors.Background +import nl.entreco.shared.threading.Background import nl.entreco.domain.model.Dart -import java.nio.file.Files.find import java.util.concurrent.Future import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCaller.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCaller.kt index 66788e5a..905bbc36 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCaller.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCaller.kt @@ -1,9 +1,9 @@ package nl.entreco.domain.play.mastercaller import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.log.Logger -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.log.Logger +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.SoundRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/ToggleSoundUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/ToggleSoundUsecase.kt index ee29cf5f..c93f4e17 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/ToggleSoundUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/ToggleSoundUsecase.kt @@ -1,15 +1,15 @@ package nl.entreco.domain.play.mastercaller import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.AudioPrefRepository import javax.inject.Inject /** * Created by entreco on 14/03/2018. */ -class ToggleSoundUsecase @Inject constructor(private val audioPrefRepository: AudioPrefRepository,bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { +class ToggleSoundUsecase @Inject constructor(private val audioPrefRepository: AudioPrefRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { fun toggle(){ onBackground({ val toggled = !audioPrefRepository.isMasterCallerEnabled() diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheUsecase.kt index d529faca..54fccbfa 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.revanche import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import nl.entreco.domain.settings.ScoreSettings import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/MarkGameAsFinishedUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/MarkGameAsFinishedUsecase.kt index 1f1eb3ee..6ad10a1f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/MarkGameAsFinishedUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/MarkGameAsFinishedUsecase.kt @@ -2,8 +2,8 @@ package nl.entreco.domain.play.start import nl.entreco.domain.Analytics import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Usecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Usecase.kt index 9b9e1103..723a5138 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Usecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Usecase.kt @@ -1,6 +1,6 @@ package nl.entreco.domain.play.start -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.TurnMeta import nl.entreco.domain.play.stats.* import nl.entreco.domain.settings.ScoreSettings diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameUsecase.kt index 140bacaa..92599299 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.start import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsUsecase.kt index 2df530ab..158e20d2 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.start import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.model.players.DeletedPlayer import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTurnsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTurnsUsecase.kt index c7f8f6c4..6c6e6d27 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTurnsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTurnsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.start import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.TurnRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsUsecase.kt index 81eb27e5..f8e1942c 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.LiveStatRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt index 168ab5e1..26c11751 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.LiveStatRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreMetaUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreMetaUsecase.kt index a73f8cea..923798be 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreMetaUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreMetaUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.play.ScoreEstimator import nl.entreco.domain.repository.MetaRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreTurnUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreTurnUsecase.kt index 8cc83207..9e2dfe84 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreTurnUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/StoreTurnUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.model.Dart import nl.entreco.domain.model.State import nl.entreco.domain.model.Turn diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/UndoTurnUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/UndoTurnUsecase.kt index f7de4f87..b4157055 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/UndoTurnUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/UndoTurnUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import nl.entreco.domain.repository.MetaRepository import nl.entreco.domain.repository.TurnRepository diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecase.kt index 72ff0095..d2ab7638 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.profile.archive import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.ArchiveRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatsUsecase.kt index a074a913..9060d41b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.profile.fetch import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.ProfileStatRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileUsecase.kt index 5aa55b7d..c2dc97c1 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.profile.fetch import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.ProfileInfoRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileUsecase.kt index 11cdd838..aa148e20 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.profile.update import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.ImageRepository import nl.entreco.domain.repository.ProfileInfoRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt index d3fa4725..aa35950d 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt @@ -2,8 +2,8 @@ package nl.entreco.domain.purchases.connect import android.support.annotation.UiThread import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.BillingRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt index bae6e6a0..173af2a5 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt @@ -2,8 +2,8 @@ package nl.entreco.domain.purchases.connect import nl.entreco.domain.BaseUsecase import nl.entreco.domain.beta.Feature -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.FeatureRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingResponse.kt new file mode 100644 index 00000000..80064e06 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.rating + +data class AskForRatingResponse(val shouldAskForRating: Boolean) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingUsecase.kt new file mode 100644 index 00000000..19ee1054 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/rating/AskForRatingUsecase.kt @@ -0,0 +1,25 @@ +package nl.entreco.domain.rating + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.GameRepository +import nl.entreco.domain.repository.RatingPrefRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class AskForRatingUsecase @Inject constructor( + private val ratingPrefRepository: RatingPrefRepository, + private val gameRepository: GameRepository, bg: Background, fg: Foreground) : + BaseUsecase(bg, fg) { + + fun go(done: (AskForRatingResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + var shouldRateApp = false + if (ratingPrefRepository.shouldAskToRateApp()) { + val finishedGames = gameRepository.countFinishedGames() + shouldRateApp = finishedGames >= 5 + } + onUi { done(AskForRatingResponse(shouldRateApp)) } + }, fail) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/AnswersRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/AnswersRepository.kt new file mode 100644 index 00000000..c6e5f58b --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/AnswersRepository.kt @@ -0,0 +1,12 @@ +package nl.entreco.domain.repository + +import android.support.annotation.WorkerThread +import nl.entreco.domain.streaming.ice.DscSessionDescription + +interface AnswersRepository { + @WorkerThread + fun create(recipientUuid: String, localSessionDescription: DscSessionDescription) + + @WorkerThread + fun listenForNewAnswers(onChange:(DscSessionDescription)->Unit) +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/IceRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/IceRepository.kt new file mode 100644 index 00000000..31765afd --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/IceRepository.kt @@ -0,0 +1,19 @@ +package nl.entreco.domain.repository + +import android.support.annotation.WorkerThread +import nl.entreco.domain.streaming.ice.DscIceCandidate +import nl.entreco.domain.streaming.ice.DscIceServer + +interface IceRepository { + @WorkerThread + fun fetchIceServers(done: (List) -> Unit) + + @WorkerThread + fun listenForIceCandidates(remoteUuid: String, add:(DscIceCandidate)->Unit, remove: (DscIceCandidate)->Unit) + + @WorkerThread + fun send(candidate: DscIceCandidate, done:(Boolean)->Unit) + + @WorkerThread + fun remove(iceCandidatesToRemove: Array, done: (Boolean)->Unit) +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/OffersRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/OffersRepository.kt new file mode 100644 index 00000000..582cf238 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/OffersRepository.kt @@ -0,0 +1,14 @@ +package nl.entreco.domain.repository + +import android.support.annotation.WorkerThread +import nl.entreco.domain.streaming.ice.DscSessionDescription + +interface OffersRepository { + + @WorkerThread + fun create(recipientUuid: String, localSessionDescription: DscSessionDescription) + + @WorkerThread + fun listenForNewOffersWithUuid(onChange:(String, DscSessionDescription)->Unit) + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/RatingPrefRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/RatingPrefRepository.kt new file mode 100644 index 00000000..e47835a6 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/RatingPrefRepository.kt @@ -0,0 +1,6 @@ +package nl.entreco.domain.repository + +interface RatingPrefRepository { + fun neverAskAgain() + fun shouldAskToRateApp() : Boolean +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/SignallingRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/SignallingRepository.kt new file mode 100644 index 00000000..9d9166a0 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/SignallingRepository.kt @@ -0,0 +1,12 @@ +package nl.entreco.domain.repository + +interface SignallingRepository { + fun connect() + fun disconnect() + fun listenForDisconnects(done: () -> Unit) + fun stopListenForDisconnects() + fun cleanDisconnectOrders(done: () -> Unit, fail: (Throwable) -> Unit) + fun setStreamerOnline(connectCode: String, done: (String?) -> Unit, fail: (Throwable) -> Unit) + fun setReceiverOnline(connectCode: String, done: (String) -> Unit, fail: (Throwable) -> Unit) + fun sendDisconnectOrderToOtherParty(uuid: String, done: () -> Unit) +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/game/CreateGameUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/game/CreateGameUsecase.kt index 4d68e50c..a2393953 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/game/CreateGameUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/game/CreateGameUsecase.kt @@ -2,8 +2,8 @@ package nl.entreco.domain.setup.game import nl.entreco.domain.Analytics import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.GameRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerUsecase.kt index c276b7a1..6e88c31f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.setup.players import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.PlayerPrefs import nl.entreco.domain.repository.PlayerRepository diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerUsecase.kt index c8713f56..8508e735 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.setup.players import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.PlayerRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersUsecase.kt index b016e249..8a6e42e2 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.setup.players import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.PlayerRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ConnectionState.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ConnectionState.kt new file mode 100644 index 00000000..905c3d06 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ConnectionState.kt @@ -0,0 +1,12 @@ +package nl.entreco.domain.streaming + +sealed class ConnectionState + +object Unknown : ConnectionState() +object Initializing : ConnectionState() +object ReadyToConnect : ConnectionState() +object Connecting : ConnectionState() +object Connected : ConnectionState() +object Disconnecting : ConnectionState() +object Disconnected : ConnectionState() +object Killing : ConnectionState() diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingRequest.kt new file mode 100644 index 00000000..0b70b6f7 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming + +data class DisconnectFromSignallingRequest (val uuid: String?) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingUsecase.kt new file mode 100644 index 00000000..eed700c2 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectFromSignallingUsecase.kt @@ -0,0 +1,33 @@ +package nl.entreco.domain.streaming + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.log.Logger +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class DisconnectFromSignallingUsecase @Inject constructor( + private val logger: Logger, + private val signallingRepository: SignallingRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: DisconnectFromSignallingRequest, done: () -> Unit) { + onBackground({ + + if(request.uuid != null) { + signallingRepository.sendDisconnectOrderToOtherParty(request.uuid) { + done() + } + } else { + done() + } + }, onError()) + } + + private fun onError(): (Throwable) -> Unit { + return { + logger.w(it.localizedMessage) + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectUsecase.kt new file mode 100644 index 00000000..08acce11 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/DisconnectUsecase.kt @@ -0,0 +1,30 @@ +package nl.entreco.domain.streaming + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.log.Logger +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class DisconnectUsecase @Inject constructor( + private val logger: Logger, + private val signallingRepository: SignallingRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(done:()->Unit) { + onBackground({ + + signallingRepository.disconnect() + signallingRepository.stopListenForDisconnects() + onUi(done) + + }, onError()) + } + + private fun onError(): (Throwable) -> Unit { + return { + logger.w(it.localizedMessage) + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferRequest.kt new file mode 100644 index 00000000..478ac499 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class CreateOfferRequest(val recipientUuid: String, val description: DscSessionDescription) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferResponse.kt new file mode 100644 index 00000000..70181dc8 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class CreateOfferResponse(val todo: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferUsecase.kt new file mode 100644 index 00000000..7f9c157c --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/CreateOfferUsecase.kt @@ -0,0 +1,21 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.OffersRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class CreateOfferUsecase @Inject constructor( + private val respository: OffersRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: CreateOfferRequest, + fail: (Throwable) -> Unit) { + onBackground({ + respository.create(request.recipientUuid, request.description) + }, fail) + + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceCandidate.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceCandidate.kt new file mode 100644 index 00000000..882e65f5 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceCandidate.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class DscIceCandidate(val sdpMid: String, val sdpMLineIndex: Int, val sdp: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceServer.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceServer.kt new file mode 100644 index 00000000..193a06d2 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscIceServer.kt @@ -0,0 +1,5 @@ +package nl.entreco.domain.streaming.ice + +data class DscIceServer(val uri: String, + val username: String? = null, + val password: String? = null) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscSessionDescription.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscSessionDescription.kt new file mode 100644 index 00000000..a0d57db8 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/DscSessionDescription.kt @@ -0,0 +1,4 @@ +package nl.entreco.domain.streaming.ice + +data class DscSessionDescription(val type: Int, + val description: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerResponse.kt new file mode 100644 index 00000000..ccd7ffc8 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class FetchIceServerResponse(val iceServers: List) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerUsecase.kt new file mode 100644 index 00000000..cb81dfe4 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/FetchIceServerUsecase.kt @@ -0,0 +1,24 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.IceRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class FetchIceServerUsecase @Inject constructor( + private val iceRepository: IceRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go( + done: (FetchIceServerResponse) -> Unit, + fail: (Throwable) -> Unit) { + + onBackground({ + iceRepository.fetchIceServers { servers -> + onUi { done(FetchIceServerResponse(servers)) } + } + }, fail) + + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersResponse.kt new file mode 100644 index 00000000..9b8f5d9d --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class ListenForAnswersResponse(val sessionType: Int, val sessionDescription: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersUsecase.kt new file mode 100644 index 00000000..e8f5ddf8 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForAnswersUsecase.kt @@ -0,0 +1,26 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.AnswersRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class ListenForAnswersUsecase @Inject constructor( + private val repository: AnswersRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(done: (ListenForAnswersResponse) -> Unit, + fail: (Throwable) -> Unit) { + onBackground({ + + repository.listenForNewAnswers { change -> + val response = ListenForAnswersResponse(change.type, change.description) + onUi { done(response) } + } + + }, fail) + + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesRequest.kt new file mode 100644 index 00000000..b785e7e7 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class ListenForIceCandidatesRequest(val uuid: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesResponse.kt new file mode 100644 index 00000000..340406a4 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class ListenForIceCandidatesResponse(val candidate: DscIceCandidate, val shouldAdd: Boolean) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesUsecase.kt new file mode 100644 index 00000000..b241fbd9 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForIceCandidatesUsecase.kt @@ -0,0 +1,32 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.IceRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class ListenForIceCandidatesUsecase @Inject constructor( + private val repository: IceRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: ListenForIceCandidatesRequest, + done: (ListenForIceCandidatesResponse) -> Unit, + fail: (Throwable) -> Unit) { + + onBackground({ + + repository.listenForIceCandidates(request.uuid, + shouldAdd(done, true), + shouldAdd(done, false)) + + }, fail) + + } + + private fun shouldAdd( + done: (ListenForIceCandidatesResponse) -> Unit, + add: Boolean): (DscIceCandidate) -> Unit = + { done(ListenForIceCandidatesResponse(it, add)) } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferRequest.kt new file mode 100644 index 00000000..82c5cab7 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class ListenForOfferRequest(val todo: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferResponse.kt new file mode 100644 index 00000000..89be4618 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class ListenForOfferResponse(val senderUuid: String, val sessionType: Int, val sessionDescription: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferUsecase.kt new file mode 100644 index 00000000..ada6449b --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/ListenForOfferUsecase.kt @@ -0,0 +1,26 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.OffersRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class ListenForOfferUsecase @Inject constructor( + private val respository: OffersRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(done: (ListenForOfferResponse) -> Unit, + fail: (Throwable) -> Unit) { + onBackground({ + + respository.listenForNewOffersWithUuid { senderUuid, session -> + val response = ListenForOfferResponse(senderUuid, session.type, session.description) + onUi { done(response) } + } + + }, fail) + + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerRequest.kt new file mode 100644 index 00000000..b108b67b --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.ice + +data class SendAnswerRequest(val recipientUuid: String, val localSessionDescription: DscSessionDescription) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerUsecase.kt new file mode 100644 index 00000000..bae559c5 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/ice/SendAnswerUsecase.kt @@ -0,0 +1,19 @@ +package nl.entreco.domain.streaming.ice + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.AnswersRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class SendAnswerUsecase @Inject constructor( + private val respository: AnswersRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: SendAnswerRequest, fail: (Throwable) -> Unit) { + onBackground({ + respository.create(request.recipientUuid, request.localSessionDescription) + }, fail) + + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateRequest.kt new file mode 100644 index 00000000..a4867bcc --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateRequest.kt @@ -0,0 +1,5 @@ +package nl.entreco.domain.streaming.p2p + +import nl.entreco.domain.streaming.ice.DscIceCandidate + +data class RemoveIceCandidateRequest(val candidates: Array) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateResponse.kt new file mode 100644 index 00000000..9daaad42 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.p2p + +data class RemoveIceCandidateResponse(val todo: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateUsecase.kt new file mode 100644 index 00000000..a85c91bb --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/RemoveIceCandidateUsecase.kt @@ -0,0 +1,28 @@ +package nl.entreco.domain.streaming.p2p + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.IceRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class RemoveIceCandidateUsecase @Inject constructor( + private val iceRepository: IceRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: RemoveIceCandidateRequest, done: (RemoveIceCandidateResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + + iceRepository.remove(request.candidates) { success -> + if (success) { + onUi { done(RemoveIceCandidateResponse("done")) } + } else { + onUi { fail(IllegalStateException("Unable to add IceCandiate")) } + } + } + + }, fail) + + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateRequest.kt new file mode 100644 index 00000000..36986ab3 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateRequest.kt @@ -0,0 +1,5 @@ +package nl.entreco.domain.streaming.p2p + +import nl.entreco.domain.streaming.ice.DscIceCandidate + +data class SendIceCandidateRequest(val candidate: DscIceCandidate) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateResponse.kt new file mode 100644 index 00000000..aeede225 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.p2p + +data class SendIceCandidateResponse(val todo: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateUsecase.kt new file mode 100644 index 00000000..69a66895 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/p2p/SendIceCandidateUsecase.kt @@ -0,0 +1,28 @@ +package nl.entreco.domain.streaming.p2p + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.IceRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class SendIceCandidateUsecase @Inject constructor( + private val iceRepository: IceRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: SendIceCandidateRequest, done: (SendIceCandidateResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + + iceRepository.send(request.candidate) { success -> + if (success) { + onUi { done(SendIceCandidateResponse("done")) } + } else { + onUi { fail(IllegalStateException("Unable to add IceCandiate")) } + } + } + + }, fail) + + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/ListenForDisconnectsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/ListenForDisconnectsUsecase.kt new file mode 100644 index 00000000..bcfc55f3 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/ListenForDisconnectsUsecase.kt @@ -0,0 +1,29 @@ +package nl.entreco.domain.streaming.receive + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.log.Logger +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class ListenForDisconnectsUsecase @Inject constructor( + private val logger: Logger, + private val signallingRepository: SignallingRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(done: () -> Unit) { + onBackground({ + signallingRepository.cleanDisconnectOrders({}, {}) + signallingRepository.listenForDisconnects { + onUi(done) + } + }, onError()) + } + + private fun onError(): (Throwable) -> Unit { + return { + logger.w("Listen for Disconnects error :$it") + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverRequest.kt new file mode 100644 index 00000000..8607aa22 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.receive + +data class RegisterReceiverRequest(val extra: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverResponse.kt new file mode 100644 index 00000000..a83e3d81 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.receive + +data class RegisterReceiverResponse(val code: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverUsecase.kt new file mode 100644 index 00000000..f39eaff8 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/receive/RegisterReceiverUsecase.kt @@ -0,0 +1,47 @@ +package nl.entreco.domain.streaming.receive + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import java.util.* +import javax.inject.Inject + +class RegisterReceiverUsecase @Inject constructor( + private val signallingRepository: SignallingRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + private var connectCode = "" + + fun go(request: RegisterReceiverRequest, done: (RegisterReceiverResponse) -> Unit, + fail: (Throwable) -> Unit) { + + onBackground({ + + signallingRepository.connect() + signallingRepository.cleanDisconnectOrders(onDisconnectSuccess(done, fail), + onError("error disconnecting orders", fail)) + }, fail) + + } + + private fun onDisconnectSuccess( + done: (RegisterReceiverResponse) -> Unit, + fail: (Throwable) -> Unit): () -> Unit = { + connectCode = (0..4).map { Random().nextInt(9) }.joinToString("") { it.toString() } + signallingRepository.setReceiverOnline( + connectCode, + onFoundDevice(done), + onError("error find online device", fail)) + } + + private fun onFoundDevice(done: (RegisterReceiverResponse) -> Unit): (String) -> Unit { + return { code -> + onUi { done(RegisterReceiverResponse(code)) } + } + } + + private fun onError(msg: String, fail: (Throwable) -> Unit): (Throwable) -> Unit = { err -> + onUi { fail(IllegalArgumentException(msg)) } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerRequest.kt new file mode 100644 index 00000000..a946fb7f --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.send + +data class RegisterStreamerRequest(val deviceId: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerResponse.kt new file mode 100644 index 00000000..4c73e567 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerResponse.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.streaming.send + +data class RegisterStreamerResponse(val uuid: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerUsecase.kt new file mode 100644 index 00000000..02b435e1 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/streaming/send/RegisterStreamerUsecase.kt @@ -0,0 +1,51 @@ +package nl.entreco.domain.streaming.send + +import nl.entreco.domain.BaseUsecase +import nl.entreco.domain.repository.SignallingRepository +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground +import javax.inject.Inject + +class RegisterStreamerUsecase @Inject constructor( + private val signallingRepository: SignallingRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun go(request: RegisterStreamerRequest, done: (RegisterStreamerResponse) -> Unit, + fail: (Throwable) -> Unit) { + + onBackground({ + + signallingRepository.connect() + signallingRepository.cleanDisconnectOrders(onDisconnectSuccess(request, done, fail), onError("error disconnecting orders", fail)) + }, onError("Unknown error", fail)) + + } + + private fun onDisconnectSuccess(request: RegisterStreamerRequest, + done: (RegisterStreamerResponse) -> Unit, + fail: (Throwable) -> Unit): () -> Unit = { + // done + // Start UseCase that listens for Disconnects + // signallingRepository.listenForDisconnectOrders(request.onDisconnect) + signallingRepository.setStreamerOnline(request.deviceId, + onFoundDevice(done, fail), + onError("error find online device", fail)) + } + + private fun onFoundDevice(done: (RegisterStreamerResponse) -> Unit, + fail: (Throwable) -> Unit): (String?) -> Unit { + return { uuid -> + if (uuid != null) { + // Bingo -> connect to the mofo + onUi { done(RegisterStreamerResponse(uuid)) } + } else { + // Device Not Found + onUi { fail(IllegalArgumentException("No device found")) } + } + } + } + + private fun onError(msg: String, fail: (Throwable) -> Unit): (Throwable) -> Unit = { err -> + onUi { fail(IllegalArgumentException(msg)) } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubmitViewedItemUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubmitViewedItemUsecase.kt index a2c74e1d..5215b3a6 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubmitViewedItemUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubmitViewedItemUsecase.kt @@ -2,8 +2,8 @@ package nl.entreco.domain.wtf import nl.entreco.domain.Analytics import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.WtfRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubscribeToWtfsUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubscribeToWtfsUsecase.kt index 046804a6..a8e3f44b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubscribeToWtfsUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/wtf/SubscribeToWtfsUsecase.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.wtf import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.repository.WtfRepository import javax.inject.Inject diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/BgExecutorTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/BgExecutorTest.kt index 26e12864..a84efa94 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/BgExecutorTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/BgExecutorTest.kt @@ -1,6 +1,7 @@ package nl.entreco.domain.common.executors import com.nhaarman.mockito_kotlin.verify +import nl.entreco.shared.threading.BgExecutor import org.junit.Before import org.junit.Test import org.mockito.Mock diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/FgExecutorTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/FgExecutorTest.kt index 90408d7a..9aa1717b 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/FgExecutorTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/FgExecutorTest.kt @@ -2,6 +2,7 @@ package nl.entreco.domain.common.executors import android.os.Handler import com.nhaarman.mockito_kotlin.verify +import nl.entreco.shared.threading.FgExecutor import org.junit.Before import org.junit.Test import org.mockito.Mock diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestBackground.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestBackground.kt index 7e4f6832..c3e2039b 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestBackground.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestBackground.kt @@ -1,5 +1,6 @@ package nl.entreco.domain.common.executors +import nl.entreco.shared.threading.Background import java.util.concurrent.Future import java.util.concurrent.FutureTask diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestForeground.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestForeground.kt index 366ffe7f..2657b473 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestForeground.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/common/executors/TestForeground.kt @@ -1,5 +1,7 @@ package nl.entreco.domain.common.executors +import nl.entreco.shared.threading.Foreground + /** * Created by Entreco on 12/12/2017. */ diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/finish/GetFinishUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/finish/GetFinishUsecaseTest.kt index e06c5d32..c68d4b9d 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/finish/GetFinishUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/finish/GetFinishUsecaseTest.kt @@ -1,7 +1,7 @@ package nl.entreco.domain.play.finish import com.nhaarman.mockito_kotlin.verify -import nl.entreco.domain.common.executors.Background +import nl.entreco.shared.threading.Background import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.model.Dart import nl.entreco.domain.model.Score diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/mastercaller/MasterCallerTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/mastercaller/MasterCallerTest.kt index 982a59c6..f5d1366c 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/mastercaller/MasterCallerTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/mastercaller/MasterCallerTest.kt @@ -3,7 +3,7 @@ package nl.entreco.domain.play.mastercaller import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.whenever -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.common.executors.TestForeground import nl.entreco.domain.repository.SoundRepository diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01UsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01UsecaseTest.kt index 60bd125e..cd0923b9 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01UsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01UsecaseTest.kt @@ -1,7 +1,7 @@ package nl.entreco.domain.play.start import com.nhaarman.mockito_kotlin.* -import nl.entreco.domain.common.log.Logger +import nl.entreco.shared.log.Logger import nl.entreco.domain.model.* import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/StoreTurnUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/StoreTurnUsecaseTest.kt index f08d0793..0894eeb5 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/StoreTurnUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/StoreTurnUsecaseTest.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats import com.nhaarman.mockito_kotlin.* -import nl.entreco.domain.common.executors.Background -import nl.entreco.domain.common.executors.Foreground +import nl.entreco.shared.threading.Background +import nl.entreco.shared.threading.Foreground import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.common.executors.TestForeground import nl.entreco.domain.model.Dart diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/rating/AskForRatingUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/rating/AskForRatingUsecaseTest.kt new file mode 100644 index 00000000..855b335b --- /dev/null +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/rating/AskForRatingUsecaseTest.kt @@ -0,0 +1,76 @@ +package nl.entreco.domain.rating + +import com.nhaarman.mockito_kotlin.verify +import com.nhaarman.mockito_kotlin.whenever +import nl.entreco.domain.common.executors.TestBackground +import nl.entreco.domain.common.executors.TestForeground +import nl.entreco.domain.repository.GameRepository +import nl.entreco.domain.repository.RatingPrefRepository +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class AskForRatingUsecaseTest { + + private val bg = TestBackground() + private val fg = TestForeground() + @Mock private lateinit var mockFail: (Throwable) -> Unit + @Mock private lateinit var mockDone: (AskForRatingResponse) -> Unit + @Mock private lateinit var mockGameRepo: GameRepository + @Mock private lateinit var mockRatePrefsRepo: RatingPrefRepository + private lateinit var subject: AskForRatingUsecase + private var givenRatedBefore: Boolean = false + private var givenGamesFinished: Int = 0 + + + @Before + fun setUp() { + subject = AskForRatingUsecase(mockRatePrefsRepo, mockGameRepo, bg, fg) + } + + @Test + fun `it should ask for rating when not asked before and more than 3 games finished`() { + givenRatedBefore(false) + givenGamesFinished(5) + thenShouldAskForRating(true) + } + + @Test + fun `it should NOT ask for rating when asked before and more than 3 games finished`() { + givenRatedBefore(true) + givenGamesFinished(5) + thenShouldAskForRating(false) + } + + @Test + fun `it should NOT ask for rating when not asked before but no games finished`() { + givenRatedBefore(false) + givenGamesFinished(0) + thenShouldAskForRating(false) + } + + @Test + fun `it should NOT ask for rating when not asked before and more than 3 games finished`() { + givenRatedBefore(true) + givenGamesFinished(0) + thenShouldAskForRating(false) + } + + private fun givenRatedBefore(rated: Boolean) { + givenRatedBefore = rated + } + + private fun givenGamesFinished(finished: Int) { + givenGamesFinished = finished + } + + private fun thenShouldAskForRating(expected: Boolean) { + whenever(mockRatePrefsRepo.shouldAskToRateApp()).thenReturn(!givenRatedBefore) + whenever(mockGameRepo.countFinishedGames()).thenReturn(givenGamesFinished) + subject.go(mockDone, mockFail) + verify(mockDone).invoke(AskForRatingResponse(expected)) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/gradle.properties b/android/DartsScorecard/gradle.properties index bc57493f..83d3ebc1 100644 --- a/android/DartsScorecard/gradle.properties +++ b/android/DartsScorecard/gradle.properties @@ -9,7 +9,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx4096m +org.gradle.jvmargs=-Xmx3000m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit diff --git a/android/DartsScorecard/gradle/wrapper/gradle-wrapper.properties b/android/DartsScorecard/gradle/wrapper/gradle-wrapper.properties index c3bdbcdf..99467343 100644 --- a/android/DartsScorecard/gradle/wrapper/gradle-wrapper.properties +++ b/android/DartsScorecard/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Mar 28 20:41:11 CEST 2018 +#Fri Aug 17 21:46:33 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/android/DartsScorecard/scripts/android_common.gradle b/android/DartsScorecard/scripts/android_common.gradle index fbb54841..839a6e20 100644 --- a/android/DartsScorecard/scripts/android_common.gradle +++ b/android/DartsScorecard/scripts/android_common.gradle @@ -31,6 +31,13 @@ android { testOptions { unitTests.returnDefaultValues = true + unitTests.all { + jvmArgs '-noverify' + } + } + + dataBinding { + enabled = true } configurations.all { @@ -39,4 +46,8 @@ android { resolutionStrategy.force "com.android.support:support-media-compat:$support" resolutionStrategy.force "com.android.support:customtabs:$support" } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" } \ No newline at end of file diff --git a/android/DartsScorecard/scripts/dependencies.gradle b/android/DartsScorecard/scripts/dependencies.gradle index 8921cb8d..03946967 100644 --- a/android/DartsScorecard/scripts/dependencies.gradle +++ b/android/DartsScorecard/scripts/dependencies.gradle @@ -34,35 +34,43 @@ ext.versionName = { -> ext { - kotlinVersion = '1.2.51' - gradleVersion = '3.1.3' - gmsVersion = '3.2.0' + kotlinVersion = '1.2.61' + gradleVersion = '3.2.0-beta05' + gmsVersion = '4.0.1' dexCountVersion = '0.8.2' detektVersion = '1.0.0.RC7' jacocoCoverageVersion = '0.4.0' coverallsVersion = '2.8.2' - fabricVersion = '1.25.1' + fabricVersion = '1.25.4' - androidCompileSdkVersion = 27 - androidMinSdkVersion = 23 - androidTargetSdkVersion = 27 + androidCompileSdkVersion = 28 + androidMinSdkVersion = 24 + androidTargetSdkVersion = 28 versionCode = versionCode() versionName = versionName() dependencies = [ - support = '27.1.1', + support = '28.0.0-rc01', daggerVersion = '2.13', constraint = '1.1.2', architecture = '1.1.1', - room = '1.1.0', - firebase = '15.0.0', - glide = '4.7.1', + room = '1.1.1', + fbAds = '15.0.1', + fbCore = '16.0.3', + fbStore = '17.1.0', + fbConfig = '16.0.0', + fbDatabase = '16.0.1', + glide = '4.8.0', circleImageView = '2.2.0', jelly = 'v1.0', crash = '2.9.1@aar', gson = '2.8.2', - leakCanary = '1.5.4', +// webRtc = '1.0.20284', + webRtc = '1.0.22672', +// webRtc = '1.0.24180', +// webRtc = '1.0.24277', + leakCanary = '1.6.1', junit = '4.12', mockito = '2.12.0', mockitoKotlin = '1.5.0', diff --git a/android/DartsScorecard/scripts/tasks.gradle b/android/DartsScorecard/scripts/tasks.gradle index 3fe441af..5d0e703b 100644 --- a/android/DartsScorecard/scripts/tasks.gradle +++ b/android/DartsScorecard/scripts/tasks.gradle @@ -1,9 +1,9 @@ task checkDebug(type: GradleBuild) { group "Dsc" - tasks = ['app:testDebugUnitTest', 'data:testDebugUnitTest', 'domain:testDebugUnitTest', 'app:jacocoDebugReport', 'domain:jacocoDebugReport', 'data:jacocoDebugReport', 'lintDebug', 'detektCheck'] + tasks = ['app:testDebugUnitTest', 'data:testDebugUnitTest', 'domain:testDebugUnitTest', 'lintDebug', 'detektCheck'] } task checkRelease(type: GradleBuild) { group "Dsc" - tasks = ['app:testReleaseUnitTest', 'data:testReleaseUnitTest', 'domain:testReleaseUnitTest', 'app:jacocoDebugReport', 'domain:jacocoDebugReport', 'data:jacocoDebugReport', 'lintRelease', 'detektCheck'] + tasks = [] } \ No newline at end of file diff --git a/android/DartsScorecard/settings.gradle b/android/DartsScorecard/settings.gradle index 5f094eb8..dfb1ec23 100644 --- a/android/DartsScorecard/settings.gradle +++ b/android/DartsScorecard/settings.gradle @@ -1 +1 @@ -include ':app', ':domain', ':data' +include ':app', ':domain', ':data', ':shared' diff --git a/android/DartsScorecard/shared/.gitignore b/android/DartsScorecard/shared/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/android/DartsScorecard/shared/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android/DartsScorecard/shared/build.gradle b/android/DartsScorecard/shared/build.gradle new file mode 100644 index 00000000..7fd9bd70 --- /dev/null +++ b/android/DartsScorecard/shared/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' +apply plugin: 'kotlin-android-extensions' +apply from: '../scripts/coverage_library.gradle' +apply from: '../scripts/android_common.gradle' + +android { + defaultPublishConfig "debug" +} + +dependencies { + // Annotation Processing + kapt "com.github.bumptech.glide:compiler:$glide" + + // Implementation + implementation "com.android.support:appcompat-v7:$support" + implementation "com.google.code.gson:gson:$gson" + implementation "com.github.bumptech.glide:glide:$glide" + + testImplementation "junit:junit:$junit" + testImplementation "org.mockito:mockito-core:$mockito" + testImplementation "com.nhaarman:mockito-kotlin-kt1.1:$mockitoKotlin" +} diff --git a/android/DartsScorecard/shared/proguard-rules.pro b/android/DartsScorecard/shared/proguard-rules.pro new file mode 100644 index 00000000..5e5a8566 --- /dev/null +++ b/android/DartsScorecard/shared/proguard-rules.pro @@ -0,0 +1,42 @@ +# 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 + + +# Databinding +-keepclasseswithmembernames interface android.databinding.DataBindingComponent +-dontwarn android.databinding.DataBindingComponent +-dontnote android.databinding.DataBindingComponent +-keep class android.databinding.DataBinderMapper +-dontwarn android.databinding.DataBinderMapper +-dontnote android.databinding.DataBinderMapper + +#GMS +-keep class com.google.android.gms.common.api.internal.BasePendingResult$ReleasableResultGuardian +-keep class com.google.android.gms.** { *; } +-dontwarn com.google.android.gms.** + +-keepnames @pcom.google.android.gms.common.annotation.KeepName class * + +-keepclassmembernames class * { + @com.google.android.gms.common.annotation.KeepName *; +} + diff --git a/android/DartsScorecard/shared/src/main/AndroidManifest.xml b/android/DartsScorecard/shared/src/main/AndroidManifest.xml new file mode 100644 index 00000000..16130945 --- /dev/null +++ b/android/DartsScorecard/shared/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/glide/GlideModule.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/libs/GlideModule.kt similarity index 77% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/glide/GlideModule.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/libs/GlideModule.kt index 4a81f929..47c7620c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/glide/GlideModule.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/libs/GlideModule.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.di.glide +package nl.entreco.shared.libs import com.bumptech.glide.annotation.GlideModule import com.bumptech.glide.module.AppGlideModule diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/log/Logger.kt similarity index 93% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/log/Logger.kt index 915f5288..b7d0dac3 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/log/Logger.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.common.log +package nl.entreco.shared.log /** * Created by Entreco on 27/11/2017. diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Background.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Background.kt similarity index 77% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Background.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Background.kt index 0aa33473..212f8caf 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Background.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Background.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.common.executors +package nl.entreco.shared.threading import java.util.concurrent.Future diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/BgExecutor.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/BgExecutor.kt similarity index 79% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/BgExecutor.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/BgExecutor.kt index 4a66a13a..e08f88dd 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/BgExecutor.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/BgExecutor.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.common.executors +package nl.entreco.shared.threading import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @@ -7,7 +7,8 @@ import java.util.concurrent.Future /** * Created by Entreco on 12/12/2017. */ -class BgExecutor(private val bg: ExecutorService = Executors.newSingleThreadExecutor()) : Background { +class BgExecutor(private val bg: ExecutorService = Executors.newSingleThreadExecutor()) : + Background { override fun post(runnable: Runnable): Future<*>? { return bg.submit(runnable) } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/FgExecutor.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/FgExecutor.kt similarity index 77% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/FgExecutor.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/FgExecutor.kt index 7ea9c990..1c2d8ce3 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/FgExecutor.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/FgExecutor.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.common.executors +package nl.entreco.shared.threading import android.os.Handler import android.os.Looper @@ -6,7 +6,8 @@ import android.os.Looper /** * Created by Entreco on 12/12/2017. */ -class FgExecutor(private val fg: Handler = Handler(Looper.getMainLooper())) : Foreground { +class FgExecutor(private val fg: Handler = Handler(Looper.getMainLooper())) : + Foreground { override fun post(runnable: Runnable) { fg.post(runnable) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Foreground.kt b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Foreground.kt similarity index 70% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Foreground.kt rename to android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Foreground.kt index bb2be116..3af853ee 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/executors/Foreground.kt +++ b/android/DartsScorecard/shared/src/main/java/nl/entreco/shared/threading/Foreground.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.common.executors +package nl.entreco.shared.threading /** * Created by Entreco on 12/12/2017. diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_entreco_black_bg.xml b/android/DartsScorecard/shared/src/main/res/drawable/ic_entreco_black_bg.xml similarity index 100% rename from android/DartsScorecard/app/src/main/res/drawable/ic_entreco_black_bg.xml rename to android/DartsScorecard/shared/src/main/res/drawable/ic_entreco_black_bg.xml diff --git a/android/DartsScorecard/app/src/main/res/layout/include_launch_header.xml b/android/DartsScorecard/shared/src/main/res/layout/include_launch_header.xml similarity index 91% rename from android/DartsScorecard/app/src/main/res/layout/include_launch_header.xml rename to android/DartsScorecard/shared/src/main/res/layout/include_launch_header.xml index 83408e52..3c737668 100644 --- a/android/DartsScorecard/app/src/main/res/layout/include_launch_header.xml +++ b/android/DartsScorecard/shared/src/main/res/layout/include_launch_header.xml @@ -2,10 +2,9 @@ + android:gravity="center_horizontal"> + + + Group + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/design/live_stop.svg b/design/live_stop.svg new file mode 100644 index 00000000..501d507b --- /dev/null +++ b/design/live_stop.svg @@ -0,0 +1,18 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/design/playstore.sketch b/design/playstore.sketch index 32253c7c..945e48c3 100644 Binary files a/design/playstore.sketch and b/design/playstore.sketch differ diff --git a/design/tv_promo.png b/design/tv_promo.png new file mode 100644 index 00000000..4675a788 Binary files /dev/null and b/design/tv_promo.png differ diff --git a/design/tv_promo.sketch b/design/tv_promo.sketch new file mode 100644 index 00000000..29d550b8 Binary files /dev/null and b/design/tv_promo.sketch differ