diff --git a/android/DartsScorecard/app/build.gradle b/android/DartsScorecard/app/build.gradle index a2cc09d0..071cc967 100644 --- a/android/DartsScorecard/app/build.gradle +++ b/android/DartsScorecard/app/build.gradle @@ -36,7 +36,7 @@ dependencies { kapt "android.arch.persistence.room:compiler:$room" // Implementation - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion" + 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" @@ -51,11 +51,14 @@ dependencies { transitive = true } + // Leaks + debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanary" + releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakCanary" + // Test testImplementation "junit:junit:$junit" testImplementation "org.mockito:mockito-core:$mockito" testImplementation "com.nhaarman:mockito-kotlin-kt1.1:$mockitoKotlin" - testImplementation "com.github.dpreussler:android-tdd-utils:$tddUtils" // AndroidTest androidTestImplementation "com.android.support.test:runner:$espressoRunner" diff --git a/android/DartsScorecard/app/proguard-rules.pro b/android/DartsScorecard/app/proguard-rules.pro index 4dd7d104..c0ebf43b 100644 --- a/android/DartsScorecard/app/proguard-rules.pro +++ b/android/DartsScorecard/app/proguard-rules.pro @@ -36,5 +36,8 @@ -dontwarn okio.** -dontnote okio.** +# OkHttp +-dontwarn okhttp3.** + # Billing -keep class com.android.vending.billing.** diff --git a/android/DartsScorecard/app/src/debug/res/values/keys.xml b/android/DartsScorecard/app/src/debug/res/values/keys.xml index d8efecf1..750c7d56 100644 --- a/android/DartsScorecard/app/src/debug/res/values/keys.xml +++ b/android/DartsScorecard/app/src/debug/res/values/keys.xml @@ -1,5 +1,7 @@ + ca-app-pub-3793327349392749~1846337901 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 18c6b59e..73df1f62 100644 --- a/android/DartsScorecard/app/src/main/AndroidManifest.xml +++ b/android/DartsScorecard/app/src/main/AndroidManifest.xml @@ -44,6 +44,11 @@ android:name=".profile.edit.EditPlayerNameActivity" android:parentActivityName=".profile.view.ProfileActivity" /> + + diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/App.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/App.kt index e0eeacee..574a94b6 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/App.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/App.kt @@ -1,11 +1,14 @@ package nl.entreco.dartsscorecard import android.app.Application +import android.os.StrictMode import com.google.android.gms.ads.MobileAds +import com.squareup.leakcanary.LeakCanary import nl.entreco.dartsscorecard.di.application.AppComponent import nl.entreco.dartsscorecard.di.application.AppModule import nl.entreco.dartsscorecard.di.application.DaggerAppComponent + /** * Created by Entreco on 14/11/2017. */ @@ -15,11 +18,38 @@ class App : Application() { override fun onCreate() { super.onCreate() - appComponent.inject(this) + initDagger() + initStrictMode() + initLeakCanary() initAdMob() } + private fun initDagger() { + appComponent.inject(this) + } + + private fun initStrictMode() { + if (BuildConfig.DEBUG) { + StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder() + .detectAll() + .penaltyLog() + .penaltyFlashScreen() + .build()) + StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder() + .detectAll() + .penaltyLog() + .build()) + } + } + + private fun initLeakCanary() { + if (LeakCanary.isInAnalyzerProcess(this)) return + LeakCanary.install(this) + } + private fun initAdMob() { - MobileAds.initialize(this, "ca-app-pub-3793327349392749~1846337901") + Thread { + MobileAds.initialize(this, resources.getString(R.string.app_id)) + }.start() } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt index 9db42309..60509514 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/DscLogger.kt @@ -1,7 +1,7 @@ package nl.entreco.dartsscorecard import android.util.Log -import nl.entreco.domain.Logger +import nl.entreco.domain.common.log.Logger /** * Created by Entreco on 27/11/2017. diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdBindings.kt new file mode 100644 index 00000000..f8862430 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdBindings.kt @@ -0,0 +1,24 @@ +package nl.entreco.dartsscorecard.ad + +import android.databinding.BindingAdapter +import android.view.View +import com.google.android.gms.ads.AdView + +/** + * Created by Entreco on 29/12/2017. + */ +abstract class AdBindings { + companion object { + @JvmStatic + @BindingAdapter("viewModel") + fun loadAd(view: AdView, viewModel: AdViewModel?) { + viewModel?.provideAdd(view) + } + + @JvmStatic + @BindingAdapter("showAd") + fun showAd(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/ad/AdLoader.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdLoader.kt new file mode 100644 index 00000000..f6cab5c6 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdLoader.kt @@ -0,0 +1,38 @@ +package nl.entreco.dartsscorecard.ad + +import com.google.android.gms.ads.AdListener +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.AdSize +import com.google.android.gms.ads.AdView +import javax.inject.Inject +import javax.inject.Named + +/** + * Created by Entreco on 29/12/2017. + */ +class AdLoader @Inject constructor() : AdListener() { + + interface AdListener { + fun onAdLoaded() + fun onAdFailed() + } + + private val adRequest by lazy { AdRequest.Builder().build() } + private var listener: AdListener? = null + + override fun onAdLoaded() { + super.onAdLoaded() + listener?.onAdLoaded() + } + + override fun onAdFailedToLoad(p0: Int) { + super.onAdFailedToLoad(p0) + listener?.onAdFailed() + } + + fun loadAd(view: AdView, adListener: AdListener) { + listener = adListener + view.adListener = this + view.loadAd(adRequest) + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..58767a37 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/AdViewModel.kt @@ -0,0 +1,90 @@ +package nl.entreco.dartsscorecard.ad + +import android.arch.lifecycle.Lifecycle +import android.arch.lifecycle.LifecycleObserver +import android.arch.lifecycle.OnLifecycleEvent +import android.databinding.ObservableBoolean +import com.google.android.gms.ads.AdView +import nl.entreco.dartsscorecard.BuildConfig +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.domain.purchases.connect.ConnectToBillingUsecase +import java.util.concurrent.atomic.AtomicBoolean +import javax.inject.Inject +import javax.inject.Named + +@ActivityScope +class AdViewModel @Inject constructor( + @ActivityScope private val lifeCycle: Lifecycle, + @ActivityScope private val connectToBillingUsecase: ConnectToBillingUsecase, + private val fetchPurchasedItemsUsecase: FetchPurchasedItemsUsecase, + private val adLoader: AdLoader, + private val interstitialLoader: InterstitialLoader, + private val logger: Logger, + @Named("debugMode") private val debug: Boolean = BuildConfig.DEBUG) : BaseViewModel(), LifecycleObserver { + + val showAd = ObservableBoolean(false) + private var serveAds = AtomicBoolean(false) // Let's give the user no Ads by default + + init { + lifeCycle.addObserver(this) + } + + fun provideAdd(view: AdView) { + if(!debug) { + adLoader.loadAd(view, object : AdLoader.AdListener { + override fun onAdLoaded() { + showAd.set(serveAds.get()) + } + + override fun onAdFailed() { + showAd.set(false) + } + }) + } + } + + fun provideInterstitial() { + if (!debug && serveAds.get()) { + interstitialLoader.showInterstitial() + } + } + + private fun checkIfUserHasPurchasedItems() { + connectToBillingUsecase.bind { connected -> + if (connected) { + fetchPurchasedItemsUsecase.exec(onPurchasesRetrieved(), onPurchasesError()) + } + } + } + + private fun onPurchasesRetrieved(): (FetchPurchasedItemsResponse) -> Unit { + return { response -> + serveAds.set(response.serveAds) + } + } + + private fun onPurchasesError(): (Throwable) -> Unit { + return { err -> + logger.w("Unable to fetchPurchasedItems, $err") + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + fun bind() { + checkIfUserHasPurchasedItems() + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + fun unbind() { + connectToBillingUsecase.unbind() + } + + @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) + fun destroy() { + lifeCycle.removeObserver(this) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/InterstitialLoader.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/InterstitialLoader.kt new file mode 100644 index 00000000..8b9f3154 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/ad/InterstitialLoader.kt @@ -0,0 +1,32 @@ +package nl.entreco.dartsscorecard.ad + +import com.google.android.gms.ads.AdListener +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.InterstitialAd +import javax.inject.Inject +import javax.inject.Named + + +class InterstitialLoader @Inject constructor( + @Named("interstitialId") private val interstitialId: String, + private val interstitial: InterstitialAd) : AdListener() { + + private val adRequest: AdRequest by lazy { AdRequest.Builder().build() } + + init { + interstitial.adUnitId = interstitialId + interstitial.adListener = this + interstitial.loadAd(adRequest) + } + + fun showInterstitial() { + if (interstitial.isLoaded) { + interstitial.show() + } + } + + override fun onAdClosed() { + super.onAdClosed() + interstitial.loadAd(adRequest) + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..f15d0208 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveJobService.kt @@ -0,0 +1,104 @@ +package nl.entreco.dartsscorecard.archive + +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.job.JobParameters +import android.app.job.JobService +import android.content.Context +import android.graphics.Color +import android.os.Build +import android.support.v4.app.NotificationCompat +import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.archive.ArchiveServiceLauncher.Companion.EXTRA_GAME_ID +import nl.entreco.dartsscorecard.di.archive.ArchiveModule +import nl.entreco.dartsscorecard.di.service.ServiceModule +import nl.entreco.domain.profile.archive.ArchiveStatsRequest +import nl.entreco.domain.profile.archive.ArchiveStatsResponse +import java.util.concurrent.atomic.AtomicBoolean + +class ArchiveJobService : JobService() { + + companion object { + private const val CHANNEL_ID = "dsc_archive_channel" + private const val NOTIF_ID = 180 + private const val NOTIF_COLOR = "#A4B5CE" + } + + private val app by lazy { application as App } + private val component by lazy { app.appComponent.plus(ServiceModule()) } + private val archiveStatsUsecase by lazy { component.plus(ArchiveModule()).archive() } + + private val isWorking = AtomicBoolean(false) + private val isCancelled = AtomicBoolean(false) + + 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.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) + .setProgress(0, 0, true) + } + + override fun onCreate() { + registerChannel() + super.onCreate() + } + + 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 importance = NotificationManager.IMPORTANCE_LOW + val channel = NotificationChannel(CHANNEL_ID, name, importance) + channel.description = desc + // Register channel with the system + notificationManager.createNotificationChannel(channel) + } + } + + override fun onStartJob(params: JobParameters): Boolean { + isCancelled.set(false) + isWorking.set(true) + notificationManager.notify(NOTIF_ID, notif.build()) + archiveStatsUsecase.exec(ArchiveStatsRequest(params.extras.getLong(EXTRA_GAME_ID)), onArchiveDone(params), onArchiveFailed(params)) + return isWorking.get() + } + + private fun onArchiveDone(params: JobParameters): (ArchiveStatsResponse) -> Unit { + return { + isWorking.set(false) + finish(params) + } + } + + private fun onArchiveFailed(params: JobParameters): (Throwable) -> Unit { + return { + isWorking.set(false) + finish(params) + } + } + + override fun onStopJob(params: JobParameters): Boolean { + notificationManager.cancel(NOTIF_ID) + isCancelled.set(true) + return finish(params) + } + + private fun finish(params: JobParameters): Boolean { + notificationManager.cancel(NOTIF_ID) + val reschedule = isWorking.get() + jobFinished(params, reschedule) + return reschedule + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveServiceLauncher.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveServiceLauncher.kt new file mode 100644 index 00000000..e2dca117 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/archive/ArchiveServiceLauncher.kt @@ -0,0 +1,34 @@ +package nl.entreco.dartsscorecard.archive + +import android.app.job.JobInfo +import android.app.job.JobScheduler +import android.content.ComponentName +import android.content.Context +import android.os.PersistableBundle +import javax.inject.Inject + + +class ArchiveServiceLauncher @Inject constructor(private val context: Context, private val componentName: ComponentName) { + + companion object { + internal const val EXTRA_GAME_ID = "gameId" + } + + fun launch(gameId: Long): Int { + val bundle = PersistableBundle(1) + bundle.putLong(EXTRA_GAME_ID, gameId) + return startService(bundle) + } + + private fun startService(bundle: PersistableBundle): Int { + val job = JobInfo.Builder(180, componentName) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE) + .setBackoffCriteria(10000, JobInfo.BACKOFF_POLICY_EXPONENTIAL) + .setRequiresCharging(false) + .setOverrideDeadline(0) + .setExtras(bundle) + .build() + val scheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler + return scheduler.schedule(job) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/TestableAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/TestableAdapter.kt index 1fe7e58c..4a3bc7ed 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/TestableAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/base/TestableAdapter.kt @@ -34,12 +34,13 @@ abstract class TestableAdapter : RecyclerView.Adap } } - protected fun tryNotifyItemRangeChanged(position: Int, count: Int) { + protected fun tryNotifyItemRangeInserted(position: Int, count: Int) { try { notifyItemRangeChanged(position, count) } catch (ignore: NullPointerException) { } } + protected fun tryNotifyItemRemoved(position: Int) { try { notifyItemRemoved(position) 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 0bc1466d..03a9c8bf 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 @@ -61,4 +61,10 @@ abstract class ViewModelActivity : AppCompatActivity() { setTitle(title) supportActionBar?.setDisplayHomeAsUpEnabled(showHomeEnabled) } + + protected fun initToolbar(toolbar: Toolbar, title: String, showHomeEnabled: Boolean = true) { + setSupportActionBar(toolbar) + setTitle(title) + supportActionBar?.setDisplayHomeAsUpEnabled(showHomeEnabled) + } } \ No newline at end of file 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 2290dae5..2d049e1f 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 @@ -7,10 +7,12 @@ import android.content.Intent import android.content.IntentSender import android.databinding.DataBindingUtil import android.os.Bundle +import android.support.design.widget.CollapsingToolbarLayout +import android.support.design.widget.Snackbar import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.Toolbar -import android.widget.Toast +import android.view.MenuItem import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.ViewModelActivity import nl.entreco.dartsscorecard.beta.donate.DonateCallback @@ -25,8 +27,9 @@ import nl.entreco.domain.beta.donations.MakeDonationResponse /** * Created by entreco on 30/01/2018. */ -class BetaActivity : ViewModelActivity(), DonateCallback { +class BetaActivity : ViewModelActivity(), DonateCallback, BetaAnimator.Swapper { + private lateinit var binding: ActivityBetaBinding private val component: BetaComponent by componentProvider { it.plus(BetaModule(this)) } private val viewModel: BetaViewModel by viewModelProvider { component.viewModel() } private val votesViewModel: VoteViewModel by viewModelProvider { component.votes() } @@ -37,7 +40,7 @@ class BetaActivity : ViewModelActivity(), DonateCallback { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val binding = DataBindingUtil.setContentView(this, R.layout.activity_beta) + binding = DataBindingUtil.setContentView(this, R.layout.activity_beta) animator = BetaAnimator(binding) binding.viewModel = viewModel binding.voteViewModel = votesViewModel @@ -45,6 +48,7 @@ class BetaActivity : ViewModelActivity(), DonateCallback { binding.animator = animator animator.toggler = votesViewModel + animator.swapper = this adapter.betaAnimator = animator initToolbar(toolbar(binding), R.string.title_beta) @@ -65,24 +69,52 @@ class BetaActivity : ViewModelActivity(), DonateCallback { return lifecycle } + override fun onSwapToolbar(showDetails: Boolean, title: String) { + if(showDetails){ + supportActionBar?.title = title + binding.includeToolbar.collapsingToolbar.title = title + } else { + supportActionBar?.setTitle(R.string.title_beta) + binding.includeToolbar.collapsingToolbar.title = getString(R.string.title_beta) + } + } + override fun makeDonation(response: MakeDonationResponse) { donate(this, response.intent.intentSender) } override fun onDonationMade(donation: Donation) { votesViewModel.submitDonation(donation) - Toast.makeText(this, R.string.donation_thanks, Toast.LENGTH_SHORT).show() + showTankYouToast() + } + + private fun showTankYouToast() { + val snack = Snackbar.make(binding.root, R.string.donation_thanks, Snackbar.LENGTH_INDEFINITE) + snack.setAction(R.string.donation_ok, { snack.dismiss() }) + snack.setActionTextColor(getColor(R.color.colorAccent)) + snack.show() } private fun initRecyclerView(binding: ActivityBetaBinding) { val recyclerView = binding.betaRecyclerView recyclerView.setHasFixedSize(true) + recyclerView.setItemViewCacheSize(20) recyclerView.layoutManager = GridLayoutManager(binding.root.context, 2) recyclerView.itemAnimator = DefaultItemAnimator() recyclerView.isDrawingCacheEnabled = true recyclerView.adapter = adapter } + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when(item?.itemId){ + android.R.id.home -> { + onBackPressed() + return true + } + } + return super.onOptionsItemSelected(item) + } + private fun toolbar(binding: ActivityBetaBinding): Toolbar { return binding.includeToolbar.toolbar } 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 ecb2d68a..5e56eeed 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,14 +9,18 @@ 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 java.util.* import javax.inject.Inject /** * Created by entreco on 30/01/2018. */ -class BetaAdapter @Inject constructor() : TestableAdapter(), Observer> { +class BetaAdapter @Inject constructor(private val bg: Background, private val fg: Foreground) : TestableAdapter(), Observer> { private val items: MutableList = mutableListOf() + private val queue: Queue> = ArrayDeque() var betaAnimator: BetaAnimator? = null override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BetaView { @@ -35,10 +39,29 @@ class BetaAdapter @Inject constructor() : TestableAdapter(), Observer< override fun onChanged(features: List?) { if (features != null) { - val diff = DiffUtil.calculateDiff(BetaDiffCalculator(items, features)) - items.clear() - items.addAll(features) - diff.dispatchUpdatesTo(this) + queue.add(features) + if (queue.size <= 1) { + calculateDiff(features) + } } } + + private fun calculateDiff(features: List) { + bg.post(Runnable { + val diff = DiffUtil.calculateDiff(BetaDiffCalculator(items, features), true) + fg.post(Runnable { + queue.remove() + updateItems(features, diff) + if (queue.size > 0) { + calculateDiff(queue.peek()) + } + }) + }) + } + + private fun updateItems(features: List, diff: DiffUtil.DiffResult) { + items.clear() + items.addAll(features) + diff.dispatchUpdatesTo(this) + } } 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 594e1694..0e871fc0 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 @@ -17,11 +17,16 @@ class BetaAnimator(binding: ActivityBetaBinding) { private val appBar = binding.includeToolbar.betaAppbar private val animator = BetaAnimatorHandler(appBar, binding.includeToolbar.toolbar, binding.sheet, binding.sheet.voteFab) internal var toggler: Toggler? = null + internal var swapper: Swapper? = null interface Toggler { fun onFeatureSelected(feature: BetaModel) } + interface Swapper { + fun onSwapToolbar(showDetails: Boolean, title: String = "") + } + init { appBar.addOnOffsetChangedListener { appBarLayout, verticalOffset -> animator.onOffsetChanged(appBarLayout, verticalOffset) } behaviour.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { @@ -31,6 +36,9 @@ class BetaAnimator(binding: ActivityBetaBinding) { override fun onStateChanged(bottomSheet: View, newState: Int) { animator.onStateChanged(newState) + if(newState == BottomSheetBehavior.STATE_COLLAPSED){ + swapper?.onSwapToolbar(false) + } } }) @@ -42,6 +50,7 @@ class BetaAnimator(binding: ActivityBetaBinding) { appBar.setExpanded(false, true) appBar.isEnabled = false behaviour.state = BottomSheetBehavior.STATE_EXPANDED + swapper?.onSwapToolbar(true, model.title.get()!!) toggler?.onFeatureSelected(model) } } 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 671a5e41..b0bbbb15 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 @@ -19,9 +19,7 @@ class BetaBindings { @BindingAdapter("imageUrl") fun loadImage(view: ImageView, url: String?) { url?.let { - Picasso.with(view.context) - .load(Uri.parse(it)) - .into(view) + Picasso.get().load(Uri.parse(it)).fit().centerCrop().into(view) } } @@ -37,7 +35,7 @@ class BetaBindings { @JvmStatic @BindingAdapter("textWithTags") fun setTextWithTags(view: TextView, message: String?) { - if(message != null) { + if (message != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { view.text = Html.fromHtml(message, Html.FROM_HTML_MODE_COMPACT) } else { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculator.kt index eda01ffc..9d378be1 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculator.kt @@ -17,12 +17,6 @@ class BetaDiffCalculator(private val old: List, private val new: List(feature.image) val remarks = ObservableField(formatHtml(feature.remarks)) + val video = ObservableField(feature.video) private fun format(value: Int): String { return when { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaViewModel.kt index fd7e5566..6415ce7a 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/BetaViewModel.kt @@ -5,7 +5,7 @@ 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.beta.connect.SubscribeToFeaturesUsecase +import nl.entreco.domain.purchases.connect.SubscribeToFeaturesUsecase import javax.inject.Inject /** diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateBindings.kt index 4edddbb7..f7cec2c6 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/donate/DonateBindings.kt @@ -2,6 +2,7 @@ package nl.entreco.dartsscorecard.beta.donate import android.databinding.BindingAdapter import android.databinding.DataBindingUtil +import android.util.Log import android.view.LayoutInflater import android.view.ViewGroup import android.widget.TextView @@ -35,9 +36,7 @@ class DonateBindings { } internal fun clearPreviousViewsIfEmpty(viewGroup: ViewGroup) { - val count = (0 until viewGroup.childCount).count { viewGroup.getChildAt(it) is TextView } - if (count == 0) (0 until viewGroup.childCount).forEach { viewGroup.removeViewAt(it) } - else (1 until viewGroup.childCount).forEach { viewGroup.removeViewAt(it) } + viewGroup.removeAllViews() } } } \ No newline at end of file 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 b86acc8b..6208004b 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 @@ -9,8 +9,9 @@ import android.databinding.ObservableBoolean import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.domain.Analytics import nl.entreco.domain.beta.Donation -import nl.entreco.domain.beta.connect.ConnectToBillingUsecase import nl.entreco.domain.beta.donations.* +import nl.entreco.domain.purchases.connect.ConnectToBillingUsecase +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject /** @@ -29,6 +30,7 @@ class DonateViewModel @Inject constructor( } internal var productId: String = "" + internal var requiresConsumption = AtomicBoolean(true) val donations = ObservableArrayList() val loading = ObservableBoolean(false) @@ -49,7 +51,7 @@ class DonateViewModel @Inject constructor( if (purchaseData == null || dataSignature == null) onConsumeDonationFailed().invoke(Throwable()) else { analytics.trackAchievement("Donation $data") - consumeDonation.exec(ConsumeDonationRequest(purchaseData, dataSignature), + consumeDonation.exec(ConsumeDonationRequest(purchaseData, dataSignature, requiresConsumption.get()), onConsumeDonationSuccess(), onConsumeDonationFailed()) } @@ -59,16 +61,19 @@ class DonateViewModel @Inject constructor( analytics.trackPurchaseFailed(productId, "GetBuyIntent failed") loading.set(false) productId = "" + requiresConsumption.set(false) } private fun onConsumeDonationSuccess(): (ConsumeDonationResponse) -> Unit = { response -> when (response.resultCode) { - 0 -> donationDone(response) + ConsumeDonationResponse.CONSUME_OK -> donationDone(response) else -> analytics.trackPurchaseFailed(response.productId, "Consume failed ${response.resultCode}") } loading.set(false) productId = "" + requiresConsumption.set(false) + fetchDonationsUsecase.exec(onFetchDonationsSuccess(), onFetchDonationsFailed()) } private fun donationDone(response: ConsumeDonationResponse) { @@ -82,24 +87,26 @@ class DonateViewModel @Inject constructor( analytics.trackPurchaseFailed(productId, "ConsumeDonation failed") loading.set(false) productId = "" + requiresConsumption.set(false) } - - private fun donationWithId(response: ConsumeDonationResponse): Donation? = - donations.firstOrNull { it.sku == response.productId } + private fun donationWithId(response: ConsumeDonationResponse) = donations.firstOrNull { it.sku == response.productId } fun onMakeDonationFailed() { analytics.trackPurchaseFailed(productId, "ActivityResult failed") loading.set(false) productId = "" + requiresConsumption.set(false) } private fun onFetchDonationsSuccess(): (FetchDonationsResponse) -> Unit = { result -> + requiresConsumption.set(result.needToBeConsumed) donations.clear() donations.addAll(result.donations) } private fun onFetchDonationsFailed(): (Throwable) -> Unit = { + requiresConsumption.set(false) analytics.trackPurchaseFailed(productId, "FetchDonations failed") } @@ -121,5 +128,4 @@ class DonateViewModel @Inject constructor( fun destroy() { donateCallback.lifeCycle().removeObserver(this) } - } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModel.kt index a5efe678..f125709b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModel.kt @@ -1,7 +1,12 @@ package nl.entreco.dartsscorecard.beta.votes +import android.content.ActivityNotFoundException +import android.content.Intent import android.databinding.ObservableBoolean import android.databinding.ObservableField +import android.databinding.ObservableInt +import android.net.Uri +import android.view.View import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.dartsscorecard.beta.BetaAnimator import nl.entreco.dartsscorecard.beta.BetaModel @@ -12,6 +17,7 @@ import nl.entreco.domain.beta.vote.SubmitVoteRequest import nl.entreco.domain.beta.vote.SubmitVoteResponse import nl.entreco.domain.beta.vote.SubmitVoteUsecase import javax.inject.Inject +import kotlin.math.min /** * Created by entreco on 07/02/2018. @@ -21,9 +27,11 @@ class VoteViewModel @Inject constructor(private val submitVoteUsecase: SubmitVot val feature = ObservableField() val didAlreadyVote = ObservableBoolean(false) val votes = mutableListOf() + val showVideo = ObservableInt(View.GONE) override fun onFeatureSelected(feature: BetaModel) { this.feature.set(feature) + this.showVideo.set(if(feature.video.get()!!.isNotBlank()) View.VISIBLE else View.GONE) this.didAlreadyVote.set(votes.contains(feature.feature.ref)) this.analytics.trackAchievement("viewed Feature ${feature.title.get()}") } @@ -32,11 +40,26 @@ class VoteViewModel @Inject constructor(private val submitVoteUsecase: SubmitVot submitVote(donation.votes) } + fun launchVideo(view: View){ + if(showVideo.get() == View.VISIBLE){ + val uri = Uri.parse(feature.get()?.video?.get()) + val id = uri.getQueryParameter( "v" ) + val app = Intent(Intent.ACTION_VIEW, Uri.parse("vnd.youtube:$id")) + val web = Intent(Intent.ACTION_VIEW, uri) + + try { + view.context.startActivity(app) + } catch(youtubeNotInstalled: ActivityNotFoundException){ + view.context.startActivity(web) + } + } + } + fun submitVote(amount: Int) { val betaModel = feature.get()!! val currentFeature = betaModel.feature if (allowedToVote(betaModel, currentFeature)) { - feature.set(BetaModel(currentFeature.copy(votes = currentFeature.votes + amount))) + feature.set(BetaModel(currentFeature.copy(votes = min(currentFeature.required ,currentFeature.votes + amount)))) votes.add(currentFeature.ref) analytics.trackViewFeature(currentFeature) submitVoteUsecase.exec(SubmitVoteRequest(betaModel.feature.ref, amount), onVoteSuccess(currentFeature), onVoteFailed(currentFeature)) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppComponent.kt index 1ee39dc9..e070c92d 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppComponent.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/application/AppComponent.kt @@ -2,6 +2,8 @@ package nl.entreco.dartsscorecard.di.application import dagger.Component import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.di.service.ServiceComponent +import nl.entreco.dartsscorecard.di.service.ServiceModule import nl.entreco.dartsscorecard.di.viewmodel.ViewModelComponent import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule @@ -13,4 +15,5 @@ import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule interface AppComponent { fun inject(app: App) fun plus(sub: ViewModelModule): ViewModelComponent + fun plus(sub: ServiceModule): ServiceComponent } \ No newline at end of file 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 0837bee3..a334ffcb 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 @@ -5,11 +5,13 @@ import com.google.firebase.firestore.FirebaseFirestore import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.BuildConfig import nl.entreco.dartsscorecard.DscLogger import nl.entreco.data.analytics.FirebaseAnalytics import nl.entreco.data.db.DscDatabase import nl.entreco.domain.Analytics -import nl.entreco.domain.Logger +import nl.entreco.domain.common.log.Logger +import javax.inject.Named /** * Created by Entreco on 14/11/2017. @@ -36,7 +38,8 @@ class AppModule(val app: App) { @Provides @ApplicationScope fun provideDb(app: App): DscDatabase { - return Room.databaseBuilder(app, DscDatabase::class.java, DscDatabase.name).build() + return Room.databaseBuilder(app, DscDatabase::class.java, DscDatabase.name) + .build() } @Provides @@ -44,4 +47,11 @@ class AppModule(val app: App) { fun provideFireStore(): FirebaseFirestore { return FirebaseFirestore.getInstance() } + + @Provides + @Named("debugMode") + @ApplicationScope + fun provideDebugMode(): Boolean { + return BuildConfig.DEBUG + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveComponent.kt new file mode 100644 index 00000000..5836a4d2 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveComponent.kt @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard.di.archive + +import dagger.Subcomponent +import nl.entreco.domain.profile.archive.ArchiveStatsUsecase + +@ArchiveScope +@Subcomponent(modules = [(ArchiveModule::class)]) +interface ArchiveComponent { + fun archive(): ArchiveStatsUsecase +} \ No newline at end of file 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 new file mode 100644 index 00000000..a2517fe2 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveModule.kt @@ -0,0 +1,26 @@ +package nl.entreco.dartsscorecard.di.archive + +import dagger.Module +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 + + +@Module +class ArchiveModule { + + @Provides + @ArchiveScope + fun provideArchiveStatMapper(): ArchiveStatMapper { + return ArchiveStatMapper() + } + + @Provides + @ArchiveScope + fun provideArchiveRepository(db: DscDatabase, mapper: ArchiveStatMapper, logger: Logger): ArchiveRepository { + return ArchiveServiceRepository(db, mapper, logger) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveScope.kt new file mode 100644 index 00000000..c8ba2b62 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/archive/ArchiveScope.kt @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard.di.archive + +import javax.inject.Scope + +/** + * Created by Entreco on 15/11/2017. + */ +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ArchiveScope \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/beta/BetaModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/beta/BetaModule.kt index b771fa6f..05fa40d9 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/beta/BetaModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/beta/BetaModule.kt @@ -1,13 +1,8 @@ package nl.entreco.dartsscorecard.di.beta -import android.content.Context import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.beta.donate.DonateCallback -import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope -import nl.entreco.data.billing.BillingServiceConnection -import nl.entreco.data.billing.PlayStoreBillingRepository -import nl.entreco.domain.repository.BillingRepository /** * Created by entreco on 30/01/2018. @@ -20,16 +15,4 @@ class BetaModule(private val donateCallback: DonateCallback) { fun provideDonateCallback(): DonateCallback { return donateCallback } - - @Provides - @BetaScope - fun provideServiceConnection(): BillingServiceConnection { - return BillingServiceConnection() - } - - @Provides - @BetaScope - fun provideBillingRepository(@ActivityScope context: Context, serviceConnection: BillingServiceConnection): BillingRepository { - return PlayStoreBillingRepository(context, serviceConnection) - } } \ No newline at end of file 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 29b33fd6..491fd0a5 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 @@ -5,7 +5,7 @@ import nl.entreco.dartsscorecard.play.Play01Navigator 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.stats.MatchStatViewModel +import nl.entreco.dartsscorecard.play.live.LiveStatViewModel import nl.entreco.domain.play.finish.GetFinishUsecase /** @@ -18,6 +18,6 @@ interface Play01Component { fun navigator(): Play01Navigator fun scoreViewModel(): ScoreViewModel fun inputViewModel(): InputViewModel - fun statViewModel(): MatchStatViewModel + fun statViewModel(): LiveStatViewModel fun finishUsecase(): GetFinishUsecase } \ No newline at end of file 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 e1f2d044..df8555eb 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 @@ -1,10 +1,13 @@ 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 dagger.Module import dagger.Provides +import nl.entreco.dartsscorecard.archive.ArchiveJobService +import nl.entreco.dartsscorecard.archive.ArchiveServiceLauncher import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.dartsscorecard.play.Play01Activity import nl.entreco.data.prefs.SharedAudioPrefRepo @@ -23,7 +26,7 @@ class Play01Module(private val activity: Play01Activity) { @Provides @Play01Scope - fun provide01Activity() : Play01Activity { + fun provide01Activity(): Play01Activity { return activity } @@ -35,13 +38,13 @@ class Play01Module(private val activity: Play01Activity) { @Provides @Play01Scope - fun provideSoundMapper() : SoundMapper { + fun provideSoundMapper(): SoundMapper { return SoundMapper() } @Provides @Play01Scope - fun provideAudioPreferences() : AudioPrefRepository { + fun provideAudioPreferences(): AudioPrefRepository { return SharedAudioPrefRepo(prefs) } @@ -56,4 +59,10 @@ class Play01Module(private val activity: Play01Activity) { fun provideSoundRepository(@ActivityScope context: Context, @Play01Scope soundPool: SoundPool, @Play01Scope mapper: SoundMapper, @Play01Scope prefs: AudioPrefRepository): SoundRepository { return LocalSoundRepository(context, soundPool, prefs, mapper) } + + @Provides + @Play01Scope + fun provideArchiveServiceLauncher(@ActivityScope context: Context): ArchiveServiceLauncher { + return ArchiveServiceLauncher(context, ComponentName(context, ArchiveJobService::class.java)) + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/profile/ProfileModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/profile/ProfileModule.kt index 15ce9db9..cbf117cd 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/profile/ProfileModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/profile/ProfileModule.kt @@ -6,11 +6,14 @@ import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.data.db.DscDatabase -import nl.entreco.data.db.profile.LocalProfileRepository +import nl.entreco.data.db.profile.LocalProfileInfoInfoRepository +import nl.entreco.data.db.profile.LocalProfileStatRepository import nl.entreco.data.db.profile.ProfileMapper +import nl.entreco.data.db.profile.ProfileStatMapper import nl.entreco.data.image.LocalImageRepository import nl.entreco.domain.repository.ImageRepository -import nl.entreco.domain.repository.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository +import nl.entreco.domain.repository.ProfileStatRepository /** * Created by entreco on 21/02/2018. @@ -26,14 +29,26 @@ class ProfileModule { @Provides @ProfileScope - fun provideMapper(): ProfileMapper { + fun provideProfileMapper(): ProfileMapper { return ProfileMapper() } @Provides @ProfileScope - fun provideProfileRepository(db: DscDatabase, mapper: ProfileMapper): ProfileRepository { - return LocalProfileRepository(db, mapper) + fun provideProfileStatMapper(): ProfileStatMapper { + return ProfileStatMapper() + } + + @Provides + @ProfileScope + fun provideProfileStatRepository(db: DscDatabase, mapper: ProfileStatMapper): ProfileStatRepository { + return LocalProfileStatRepository(db, mapper) + } + + @Provides + @ProfileScope + fun provideProfileRepository(db: DscDatabase, mapper: ProfileMapper): ProfileInfoRepository { + return LocalProfileInfoInfoRepository(db, mapper) } @Provides 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 new file mode 100644 index 00000000..b3e90b38 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceComponent.kt @@ -0,0 +1,14 @@ +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.viewmodel.api.FeatureApiModule +import nl.entreco.dartsscorecard.di.viewmodel.db.* +import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule + +@ServiceScope +@Subcomponent(modules = [(ServiceModule::class), (ThreadingModule::class)]) +interface ServiceComponent { + fun plus(module: ArchiveModule): ArchiveComponent +} \ 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 new file mode 100644 index 00000000..c2792561 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceModule.kt @@ -0,0 +1,6 @@ +package nl.entreco.dartsscorecard.di.service + +import dagger.Module + +@Module +class ServiceModule \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceScope.kt new file mode 100644 index 00000000..8f9f0fbc --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/service/ServiceScope.kt @@ -0,0 +1,11 @@ +package nl.entreco.dartsscorecard.di.service + +import javax.inject.Scope + + +/** + * Created by Entreco on 15/11/2017. + */ +@Scope +@Retention(AnnotationRetention.RUNTIME) +annotation class ServiceScope \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Component.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Component.kt index 52c3fe33..bda36d96 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Component.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Component.kt @@ -1,8 +1,8 @@ package nl.entreco.dartsscorecard.di.setup import dagger.Subcomponent +import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.setup.Setup01ViewModel -import nl.entreco.dartsscorecard.setup.ad.AdViewModel import nl.entreco.dartsscorecard.setup.players.PlayersViewModel import nl.entreco.dartsscorecard.setup.settings.SettingsViewModel @@ -14,6 +14,6 @@ import nl.entreco.dartsscorecard.setup.settings.SettingsViewModel interface Setup01Component { fun viewModel(): Setup01ViewModel fun players(): PlayersViewModel - fun ads(): AdViewModel fun settings(): SettingsViewModel + fun ads(): AdViewModel } \ 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 b9cfd77b..5f2de695 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 @@ -12,6 +12,7 @@ import nl.entreco.dartsscorecard.di.setup.EditPlayerComponent import nl.entreco.dartsscorecard.di.setup.EditPlayerModule import nl.entreco.dartsscorecard.di.setup.Setup01Component import nl.entreco.dartsscorecard.di.setup.Setup01Module +import nl.entreco.dartsscorecard.di.viewmodel.ad.AdModule import nl.entreco.dartsscorecard.di.viewmodel.api.FeatureApiModule import nl.entreco.dartsscorecard.di.viewmodel.db.* import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule @@ -20,13 +21,14 @@ import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule * Created by Entreco on 14/11/2017. */ @ActivityScope -@Subcomponent(modules = [(ViewModelModule::class), (ThreadingModule::class), +@Subcomponent(modules = [(ViewModelModule::class), (ThreadingModule::class), (AdModule::class), (GameDbModule::class), (PlayerDbModule::class), (TurnDbModule::class), (MetaDbModule::class), (StatDbModule::class), (FeatureApiModule::class)]) interface ViewModelComponent { // Where can this be used fun plus(module: LaunchModule): LaunchComponent + fun plus(module: BetaModule): BetaComponent fun plus(module: Setup01Module): Setup01Component fun plus(module: EditPlayerModule): EditPlayerComponent 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 8c883132..e80963ee 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 @@ -1,16 +1,43 @@ package nl.entreco.dartsscorecard.di.viewmodel -import android.app.Activity +import android.arch.lifecycle.Lifecycle import android.content.Context +import android.content.res.Resources +import android.support.v4.app.FragmentActivity import dagger.Module import dagger.Provides +import nl.entreco.data.billing.BillingServiceConnection +import nl.entreco.data.billing.PlayStoreBillingRepository +import nl.entreco.domain.repository.BillingRepository /** * Created by Entreco on 14/11/2017. */ @Module -class ViewModelModule(private val activity: Activity) { +class ViewModelModule(private val activity: FragmentActivity) { @Provides @ActivityScope fun context(): Context = activity + + @Provides + @ActivityScope + fun resources(): Resources = activity.resources + + @Provides + @ActivityScope + fun lifeCycle(): Lifecycle { + return activity.lifecycle + } + + @Provides + @ActivityScope + fun provideServiceConnection(): BillingServiceConnection { + return BillingServiceConnection() + } + + @Provides + @ActivityScope + fun provideBillingRepository(@ActivityScope context: Context, @ActivityScope serviceConnection: BillingServiceConnection): BillingRepository { + return PlayStoreBillingRepository(context, serviceConnection) + } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModule.kt new file mode 100644 index 00000000..334f665c --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModule.kt @@ -0,0 +1,29 @@ +package nl.entreco.dartsscorecard.di.viewmodel.ad + +import android.content.Context +import android.content.res.Resources +import com.google.android.gms.ads.InterstitialAd +import dagger.Module +import dagger.Provides +import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.di.beta.BetaScope +import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope +import nl.entreco.data.billing.BillingServiceConnection +import nl.entreco.data.billing.PlayStoreBillingRepository +import nl.entreco.domain.repository.BillingRepository +import javax.inject.Named + +@Module +class AdModule { + + @Provides + fun provideInterstialAd(@ActivityScope context: Context): InterstitialAd { + return InterstitialAd(context) + } + + @Provides + @Named("interstitialId") + fun provideInterstitialUnitId(@ActivityScope resources: Resources): String { + return resources.getString(R.string.setup_interstitial_unit_id) + } +} \ No newline at end of file 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 a74a4544..4c779770 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.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.repository.FeatureRepository /** diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModule.kt index ca9d32e7..ff37448b 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModule.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModule.kt @@ -4,9 +4,9 @@ import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.data.db.DscDatabase -import nl.entreco.data.db.stats.LocalStatRepository -import nl.entreco.data.db.stats.StatMapper -import nl.entreco.domain.repository.StatRepository +import nl.entreco.data.db.stats.LocalLiveStatRepository +import nl.entreco.data.db.stats.LiveStatMapper +import nl.entreco.domain.repository.LiveStatRepository /** * Created by entreco on 16/01/2018. @@ -16,13 +16,13 @@ class StatDbModule { @Provides @ActivityScope - fun provideStatMapper(): StatMapper { - return StatMapper() + fun provideStatMapper(): LiveStatMapper { + return LiveStatMapper() } @Provides @ActivityScope - fun provideStatRepository(db: DscDatabase, mapper: StatMapper): StatRepository { - return LocalStatRepository(db, mapper) + fun provideStatRepository(db: DscDatabase, mapperLive: LiveStatMapper): LiveStatRepository { + return LocalLiveStatRepository(db, mapperLive) } } \ 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 bac82e91..01950632 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,7 +4,6 @@ import android.os.Handler import android.os.Looper import dagger.Module import dagger.Provides -import nl.entreco.dartsscorecard.di.viewmodel.ActivityScope import nl.entreco.domain.common.executors.Background import nl.entreco.domain.common.executors.BgExecutor import nl.entreco.domain.common.executors.FgExecutor @@ -16,19 +15,16 @@ import nl.entreco.domain.common.executors.Foreground @Module class ThreadingModule { @Provides - @ActivityScope fun provideBackground(): Background { return BgExecutor() } @Provides - @ActivityScope fun provideForeground(handler: Handler): Foreground { return FgExecutor(handler) } @Provides - @ActivityScope fun provideHandler(): Handler { return Handler(Looper.myLooper()) } 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 e535bcfb..eecfa493 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,7 +14,7 @@ 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.stats.MatchStatViewModel +import nl.entreco.dartsscorecard.play.live.LiveStatViewModel import nl.entreco.domain.play.finish.GetFinishUsecase import nl.entreco.domain.play.start.Play01Request import nl.entreco.domain.setup.game.CreateGameResponse @@ -25,7 +25,7 @@ class Play01Activity : ViewModelActivity() { private val viewModel: Play01ViewModel by viewModelProvider { component.viewModel() } private val scoreViewModel: ScoreViewModel by viewModelProvider { component.scoreViewModel() } private val inputViewModel: InputViewModel by viewModelProvider { component.inputViewModel() } - private val statViewModel: MatchStatViewModel by viewModelProvider { component.statViewModel() } + private val statViewModel: LiveStatViewModel by viewModelProvider { component.statViewModel() } private val finishUsecase: GetFinishUsecase by componentProvider { component.finishUsecase() } private val navigator: Play01Navigator by lazy { component.navigator() } 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 a6ba2e22..bc07f75f 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 @@ -9,7 +9,7 @@ import kotlinx.android.synthetic.main.activity_play_01.view.* import kotlinx.android.synthetic.main.play_01_score.view.* import nl.entreco.dartsscorecard.base.widget.MaxHeightRecyclerView import nl.entreco.dartsscorecard.databinding.ActivityPlay01Binding -import nl.entreco.dartsscorecard.play.stats.MatchStatSlideAnimator +import nl.entreco.dartsscorecard.play.live.LiveStatSlideAnimator import kotlin.math.max import kotlin.math.sqrt @@ -56,7 +56,7 @@ class Play01Animator(binding: ActivityPlay01Binding) { private val scoreHeader: View, private val scoreFooter: View, private val toolbar: View) { private var animatorPosition: Int = 0 - internal var animator: MatchStatSlideAnimator? = null + internal var animator: LiveStatSlideAnimator? = null private val lock = Object() fun onSlide(slideOffset: Float) { @@ -111,10 +111,10 @@ class Play01Animator(binding: ActivityPlay01Binding) { anim.translationY(-index * 50 * slideOffset * index).scaleX(max(0f, (1 - slideOffset * index))).alpha(1 - slideOffset).setDuration(0).start() } - private fun getAnimatorForPosition(position: Int): MatchStatSlideAnimator? { + private fun getAnimatorForPosition(position: Int): LiveStatSlideAnimator? { synchronized(lock) { if (animator == null) { - animator = MatchStatSlideAnimator(pager.findViewWithTag(position), pager.findViewWithTag(position - 1), pager.findViewWithTag(position + 1)) + animator = LiveStatSlideAnimator(pager.findViewWithTag(position), pager.findViewWithTag(position - 1), pager.findViewWithTag(position + 1)) } return animator } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Listeners.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Listeners.kt index b0baf1fd..2560a85c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Listeners.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/Play01Listeners.kt @@ -54,6 +54,10 @@ class Play01Listeners @Inject constructor() { notifyNextPlayer(next) } + fun onGameFinished(gameId: Long) { + notifyGameFinished(gameId) + } + private fun addScoreListener(scoreListener: ScoreListener) { synchronized(scoreListeners) { if (!scoreListeners.contains(scoreListener)) { @@ -103,4 +107,10 @@ class Play01Listeners @Inject constructor() { playerListeners.forEach { it.onNext(next) } } } + + private fun notifyGameFinished(gameId: Long) { + synchronized(statListeners) { + statListeners.forEach { it.onGameFinished(gameId) } + } + } } \ No newline at end of file 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 8c6d3459..5f4e1648 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 @@ -5,12 +5,13 @@ import android.databinding.ObservableInt import android.view.Menu import android.view.MenuItem 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.play.score.GameLoadedNotifier import nl.entreco.dartsscorecard.play.score.TeamScoreListener import nl.entreco.dartsscorecard.play.score.UiCallback -import nl.entreco.domain.Logger +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 @@ -41,6 +42,7 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use private val dialogHelper: DialogHelper, private val toggleSoundUsecase: ToggleSoundUsecase, private val audioPrefRepository: AudioPrefRepository, + private val adViewModel: AdViewModel, private val logger: Logger) : BaseViewModel(), UiCallback, InputListener { val loading = ObservableBoolean(true) @@ -139,6 +141,7 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use handleGameFinished(next, game.id) notifyListeners(next, turn, by, scores) notifyMasterCaller(next, turn) + showInterstitial(next) storeTurn(turn, by, next) } @@ -159,6 +162,7 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use finished.set(gameFinished) if (gameFinished) { playGameUsecase.markGameAsFinished(MarkGameAsFinishedRequest(gameId)) + gameListeners.onGameFinished(gameId) } } @@ -166,8 +170,8 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use gameListeners.onTurnSubmitted(next, turn, by, scores) } - private fun notifyMasterCaller(next: Next, turn: Turn){ - when(next.state){ + private fun notifyMasterCaller(next: Next, turn: Turn) { + when (next.state) { State.START -> masterCaller.play(MasterCallerRequest(start = true)) State.LEG -> masterCaller.play(MasterCallerRequest(leg = true)) State.SET -> masterCaller.play(MasterCallerRequest(set = true)) @@ -177,11 +181,21 @@ class Play01ViewModel @Inject constructor(private val playGameUsecase: Play01Use } } + private fun showInterstitial(next: Next) { + when (next.state) { + State.START -> adViewModel.provideInterstitial() + State.LEG -> adViewModel.provideInterstitial() + State.SET -> adViewModel.provideInterstitial() + State.MATCH -> adViewModel.provideInterstitial() + else -> { } + } + } + fun stop() { masterCaller.stop() } - fun initToggleMenuItem(menu: Menu?){ + fun initToggleMenuItem(menu: Menu?) { menu?.findItem(R.id.menu_sound_settings)?.isChecked = audioPrefRepository.isMasterCallerEnabled() } 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 7b2402ef..f652986a 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.Logger +import nl.entreco.domain.common.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/stats/MatchStatAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapter.kt similarity index 78% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatAdapter.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapter.kt index 8f10a617..95d7eb58 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapter.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.databinding.DataBindingUtil import android.support.v4.view.PagerAdapter @@ -14,14 +14,14 @@ import kotlin.math.max /** * Created by entreco on 24/03/2018. */ -class MatchStatAdapter @Inject constructor(private val navigator: Play01Navigator) : PagerAdapter() { +class LiveStatAdapter @Inject constructor(private val navigator: Play01Navigator) : PagerAdapter() { - private val items: MutableList = mutableListOf() + private val items: MutableList = mutableListOf() override fun instantiateItem(container: ViewGroup, position: Int): Any { val binding = DataBindingUtil.inflate(LayoutInflater.from(container.context), R.layout.widget_list_stats, container, false) binding.team0 = items[position] - binding.team1 = items[(position + 1) % items.size] + binding.team1 = if(items.size >= 2) items[(position + 1) % items.size] else null binding.navigator = navigator binding.root.tag = position binding.executePendingBindings() @@ -42,7 +42,7 @@ class MatchStatAdapter @Inject constructor(private val navigator: Play01Navigato return if(items.size == 1) 1 else return max(0, items.size - 1) } - fun populate(stats: Map) { + fun populate(stats: Map) { items.clear() items.addAll(stats.map { it.value }) notifyDataSetChanged() diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatBinding.kt new file mode 100644 index 00000000..8dfb3b41 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatBinding.kt @@ -0,0 +1,49 @@ +package nl.entreco.dartsscorecard.play.live + +import android.databinding.BindingAdapter +import android.support.v4.view.ViewPager +import android.view.Gravity +import android.view.View +import android.widget.RelativeLayout +import android.widget.TextView +import nl.entreco.dartsscorecard.R + +/** + * Created by entreco on 24/03/2018. + */ +class LiveStatBinding { + + companion object { + @JvmStatic + @BindingAdapter("liveStats", "adapter") + fun setupViewPager(view: ViewPager, stats: Map, adapter: LiveStatAdapter) { + adapter.populate(stats) + view.setPageTransformer(false, LiveStatTransformer(view.context.resources.getDimension(R.dimen.match_stat_width))) + view.adapter = adapter + view.setCurrentItem(0, true) + val margin = if (stats.size < 2) view.context.resources.getDimensionPixelOffset(R.dimen.xxlarge) else 0 + val lp = (view.layoutParams as RelativeLayout.LayoutParams) + lp.setMargins(margin, 0, margin, 0) + view.layoutParams = lp + } + + @JvmStatic + @BindingAdapter("hideIfOneTeam") + fun hideIfOnlyOneTeam(view: View, hide: Boolean) { + view.visibility = if (hide) View.GONE else View.VISIBLE + } + + @JvmStatic + @BindingAdapter("centerIfOneTeam") + fun centerIfOnlyOneTeam(view: TextView, oneTeam: Boolean) { + view.gravity = if(oneTeam) Gravity.CENTER else Gravity.END + } + + @JvmStatic + @BindingAdapter("currentTeam") + fun scrollToCurrentTeam(pager: ViewPager, currentTeamIndex: Int) { + pager.setCurrentItem(currentTeamIndex, true) + } + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimator.kt similarity index 83% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimator.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimator.kt index 722c0737..2ba7b789 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimator.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.view.View import nl.entreco.dartsscorecard.databinding.WidgetListStatsBinding @@ -6,14 +6,15 @@ import nl.entreco.dartsscorecard.databinding.WidgetListStatsBinding /** * Created by entreco on 27/03/2018. */ -class MatchStatPageAnimator(private val size: Float) { +class LiveStatPageAnimator(private val size: Float) { fun transform(binding: WidgetListStatsBinding, page: View, position: Float) { page.alpha = 1F val statFactor = page.width - size val animator = MatchStatPageAnimatorHandler(binding.player1, binding.player2, binding.name1, binding.name2, binding.score, - binding.stat1, binding.stat2, binding.stat3, binding.stat4, binding.stat5, binding.stat6, binding.stat7, statFactor) + binding.stat1, binding.stat2, binding.stat3, binding.stat4, binding.stat5, binding.stat6, binding.stat7, + binding.stat8, binding.stat9, binding.stat10, statFactor) animator.transform(page, position) } @@ -21,7 +22,8 @@ class MatchStatPageAnimator(private val size: Float) { private val name1: View, private val name2: View, private val score: View, private val stat1: View, private val stat2: View, private val stat3: View, private val stat4: View, private val stat5: View, private val stat6: View, - private val stat7: View, private val statFactor: Float) { + private val stat7: View, private val stat8: View, private val stat9: View, + private val stat10: View, private val statFactor: Float) { // [-1. 1] range of position fun transform(page: View, position: Float) { @@ -47,6 +49,9 @@ class MatchStatPageAnimator(private val size: Float) { animateStat(stat5, position, statFactor) animateStat(stat6, position, statFactor) animateStat(stat7, position, statFactor) + animateStat(stat8, position, statFactor) + animateStat(stat9, position, statFactor) + animateStat(stat10, position, statFactor) } private fun stayPut(view: View) { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimator.kt similarity index 81% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimator.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimator.kt index c5e88603..46a15180 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimator.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.databinding.DataBindingUtil import android.view.View @@ -9,12 +9,13 @@ import kotlin.math.max /** * Created by entreco on 24/03/2018. */ -class MatchStatSlideAnimator(private val view: View, private val left: View?, private val right: View?) { +class LiveStatSlideAnimator(private val view: View, private val left: View?, private val right: View?) { private val binding by lazy { DataBindingUtil.getBinding(view)!! } private val animator by lazy { MatchStatSlideAnimatorHandler(binding.player1, binding.player2, binding.name1, binding.name2, binding.score, - binding.stat1, binding.stat2, binding.stat3, binding.stat4, binding.stat5, binding.stat6, binding.stat7) + binding.stat1, binding.stat2, binding.stat3, binding.stat4, binding.stat5, binding.stat6, binding.stat7, + binding.stat8, binding.stat9, binding.stat10) } fun onSlide(slideOffset: Float) { @@ -28,7 +29,8 @@ class MatchStatSlideAnimator(private val view: View, private val left: View?, pr private val name1: View, private val name2: View, private val score: View, private val stat1: View, private val stat2: View, private val stat3: View, private val stat4: View, private val stat5: View, private val stat6: View, - private val stat7: View) { + private val stat7: View, private val stat8: View, private val stat9: View, + private val stat10: View) { fun slide(slideOffset: Float) { // Fly In Players player1.animate().translationX(slideOffset * -player1.width / 3).setDuration(0).start() @@ -45,6 +47,9 @@ class MatchStatSlideAnimator(private val view: View, private val left: View?, pr animateState(stat5.animate(), 5, slideOffset) animateState(stat6.animate(), 6, slideOffset) animateState(stat7.animate(), 7, slideOffset) + animateState(stat8.animate(), 8, slideOffset) + animateState(stat9.animate(), 9, slideOffset) + animateState(stat10.animate(), 10, slideOffset) } private fun animateState(anim: ViewPropertyAnimator, index: Int, slideOffset: Float) { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatTransformer.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatTransformer.kt similarity index 79% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatTransformer.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatTransformer.kt index 9da48674..3ccee292 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatTransformer.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatTransformer.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.databinding.DataBindingUtil import android.support.v4.view.ViewPager @@ -8,9 +8,9 @@ import nl.entreco.dartsscorecard.databinding.WidgetListStatsBinding /** * Created by entreco on 24/03/2018. */ -class MatchStatTransformer(size: Float) : ViewPager.PageTransformer { +class LiveStatTransformer(size: Float) : ViewPager.PageTransformer { - private val animator = MatchStatPageAnimator(size) + private val animator = LiveStatPageAnimator(size) override fun transformPage(page: View, position: Float) { when { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt similarity index 60% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModel.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt index b012d2a4..fe081f41 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModel.kt @@ -1,10 +1,12 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.databinding.ObservableArrayMap +import android.databinding.ObservableInt +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.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.Score import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.listeners.StatListener @@ -15,11 +17,16 @@ import javax.inject.Inject /** * Created by entreco on 11/01/2018. */ -class MatchStatViewModel @Inject constructor( - val adapter: MatchStatAdapter, private val fetchGameStatsUsecase: FetchGameStatsUsecase, - private val fetchGameStatUsecase: FetchGameStatUsecase, private val logger: Logger) : BaseViewModel(), GameLoadedNotifier, StatListener { +class LiveStatViewModel @Inject constructor( + val adapter: LiveStatAdapter, + private val fetchGameStatsUsecase: FetchGameStatsUsecase, + private val fetchLiveStatUsecase: FetchLiveStatUsecase, + private val archiveServiceLauncher: ArchiveServiceLauncher, + private val logger: Logger) + : BaseViewModel(), GameLoadedNotifier, StatListener { - val teamStats = ObservableArrayMap() + val teamStats = ObservableArrayMap() + val currentTeam = ObservableInt() private lateinit var teams: Array @@ -35,8 +42,9 @@ class MatchStatViewModel @Inject constructor( this.teams = teams teams.forEachIndexed { index, team -> - teamStats[index] = TeamStatModel(team) + teamStats[index] = TeamLiveStatModel(team) } + currentTeam.set(0) } private fun onStatsFetched(teams: Array): (FetchGameStatsResponse) -> Unit { @@ -53,15 +61,20 @@ class MatchStatViewModel @Inject constructor( private fun onStatsFailed(): (Throwable) -> Unit = { err -> logger.e(err.localizedMessage) } override fun onStatsChange(turnId: Long, metaId: Long) { - fetchGameStatUsecase.exec(FetchGameStatRequest(turnId, metaId), onStatUpdated(), onStatsFailed()) + fetchLiveStatUsecase.exec(FetchLiveStatRequest(turnId, metaId), onStatUpdated(), onStatsFailed()) } - private fun onStatUpdated(): (FetchGameStatResponse) -> Unit { + private fun onStatUpdated(): (FetchLiveStatResponse) -> Unit { return { response -> - val teamIndex = teams.indexOfFirst { it.contains(response.stat.playerId) } + val teamIndex = teams.indexOfFirst { it.contains(response.liveStat.playerId) } if (teamIndex >= 0) { - teamStats[teamIndex]?.append(listOf(response.stat)) + teamStats[teamIndex]?.append(listOf(response.liveStat)) + currentTeam.set(teamIndex) } } } + + override fun onGameFinished(gameId: Long) { + archiveServiceLauncher.launch(gameId) + } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/TeamStatModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModel.kt similarity index 54% rename from android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/TeamStatModel.kt rename to android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModel.kt index 168bc6cd..ac1906d2 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/TeamStatModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModel.kt @@ -1,13 +1,13 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.databinding.ObservableField -import nl.entreco.domain.model.Stat +import nl.entreco.domain.model.LiveStat import nl.entreco.domain.model.players.Team /** * Created by entreco on 11/01/2018. */ -class TeamStatModel(val team: Team, private val stats: MutableList = mutableListOf()) { +class TeamLiveStatModel(val team: Team, private val liveStats: MutableList = mutableListOf()) { companion object { const val empty = "--" @@ -18,20 +18,23 @@ class TeamStatModel(val team: Team, private val stats: MutableList = mutab val n180 = ObservableField(empty) val n140 = ObservableField(empty) val n100 = ObservableField(empty) + val n60 = ObservableField(empty) + val n20 = ObservableField(empty) + val hScore = ObservableField(empty) val hCo = ObservableField(empty) val co = ObservableField(empty) val breaks = ObservableField(empty) val image = ObservableField(team.imageUrl()) init { - if (stats.isNotEmpty()) { + if (liveStats.isNotEmpty()) { update() } } - fun append(updates: List) { - updates.forEach { stats.add(it) } - if (stats.isNotEmpty()) { + fun append(updates: List) { + updates.forEach { liveStats.add(it) } + if (liveStats.isNotEmpty()) { update() } } @@ -41,19 +44,22 @@ class TeamStatModel(val team: Team, private val stats: MutableList = mutab update180s() update140s() update100s() + update60s() + update20s() + updateHighestScore() updateHighestCheckout() updateDoublePercentage() updateBreaksMade() } private fun updateBreaksMade() { - val value = stats.sumBy { it.nBreaks } + val value = liveStats.sumBy { it.nBreaks } breaks.set("$value") } private fun updateDoublePercentage() { - val aggregator = stats.sumBy { it.nCheckouts } - val denominator = stats.sumBy { it.nAtCheckout } + val aggregator = liveStats.sumBy { it.nCheckouts } + val denominator = liveStats.sumBy { it.nAtCheckout } when (denominator) { 0 -> co.set(empty) @@ -61,8 +67,18 @@ class TeamStatModel(val team: Team, private val stats: MutableList = mutab } } + private fun updateHighestScore() { + val value = liveStats + .filter { it.highest.isNotEmpty() } + .maxBy { it.highest[0] } + ?.highest?.firstOrNull() + when (value) { + null -> hScore.set(empty) + else -> hScore.set("$value") + } + } private fun updateHighestCheckout() { - val value = stats + val value = liveStats .filter { it.highestCo.isNotEmpty() } .maxBy { it.highestCo[0] } ?.highestCo?.firstOrNull() @@ -72,24 +88,33 @@ class TeamStatModel(val team: Team, private val stats: MutableList = mutab } } + private fun update20s() { + val value = liveStats.sumBy { it.n20 } + n20.set("$value") + } + private fun update60s() { + val value = liveStats.sumBy { it.n60 } + n60.set("$value") + } + private fun update100s() { - val value = stats.sumBy { it.n100 } + val value = liveStats.sumBy { it.n100 } n100.set("$value") } private fun update140s() { - val value = stats.sumBy { it.n140 } + val value = liveStats.sumBy { it.n140 } n140.set("$value") } private fun update180s() { - val value = stats.sumBy { it.n180 } + val value = liveStats.sumBy { it.n180 } n180.set("$value") } private fun updateAverage() { - val aggregator = stats.sumBy { it.totalScore } - val denominator = stats.sumBy { it.nDarts } + val aggregator = liveStats.sumBy { it.totalScore } + val denominator = liveStats.sumBy { it.nDarts } when (denominator) { 0 -> avg.set(empty) 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 8063bf54..0c6c0983 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 @@ -3,7 +3,6 @@ package nl.entreco.dartsscorecard.play.score import android.databinding.BindingAdapter import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView -import android.util.Log import nl.entreco.domain.model.Score import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.finish.GetFinishUsecase @@ -24,13 +23,13 @@ abstract class ScoreBindings { throw IllegalStateException("state mismatch, scores.size != teams.size! -> was this game already started?") } + recyclerView.setHasFixedSize(true) recyclerView.layoutManager = LinearLayoutManager(recyclerView.context) recyclerView.itemAnimator = null + recyclerView.isDrawingCacheEnabled = true recyclerView.adapter = adapter adapter.clear() - Log.w("TAG", "teams: $teams scores: $scores tsi:${scoreSettings.teamStartIndex}") - val listeners = mutableListOf() teams.forEachIndexed { index, team -> val vm = TeamScoreViewModel(team, scores[index], finishUsecase, starter = scoreSettings.teamStartIndex == index) 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 af2f73c6..78a6c20a 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,7 @@ import android.databinding.ObservableArrayList import android.databinding.ObservableField import android.databinding.ObservableInt import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.Logger +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 @@ -38,18 +38,15 @@ class ScoreViewModel @Inject constructor(val adapter: ScoreAdapter, private val } override fun onScoreChange(scores: Array, by: Player) { - logger.d("NoNICE", "1:$scores by:$by") scores.forEachIndexed { index, score -> adapter.teamAtIndexScored(index, score, by) } } override fun onDartThrown(turn: Turn, by: Player) { - logger.d("NoNICE", "onDartThrown: ${turn.last()} from:$by") val index = teams.indexOfFirst { it.contains(by) } adapter.teamAtIndexThrew(index, turn, by) } override fun onNext(next: Next) { - logger.d("NoNICE", "onNext: ${next.player}") currentTeam.set(teams.indexOf(next.team)) teams.forEachIndexed({ index, _ -> adapter.teamAtIndexTurnUpdate(index, next) }) } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatBinding.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatBinding.kt deleted file mode 100644 index 5ffb7ec1..00000000 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/stats/MatchStatBinding.kt +++ /dev/null @@ -1,22 +0,0 @@ -package nl.entreco.dartsscorecard.play.stats - -import android.databinding.BindingAdapter -import android.support.v4.view.ViewPager -import nl.entreco.dartsscorecard.R - -/** - * Created by entreco on 24/03/2018. - */ -class MatchStatBinding { - - companion object { - @JvmStatic - @BindingAdapter("stats", "adapter") - fun setupViewPager(view: ViewPager, stats: Map, adapter: MatchStatAdapter) { - adapter.populate(stats) - view.setPageTransformer(false, MatchStatTransformer(view.context.resources.getDimension(R.dimen.match_stat_width))) - view.adapter = adapter - view.setCurrentItem(0, true) - } - } -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModel.kt index a7e2d841..c640abc1 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModel.kt @@ -29,8 +29,8 @@ class EditPlayerNameViewModel @Inject constructor(private val handler: Handler, fetchExistingPlayersUsecase: FetchExistingPlayersUsecase) : BaseViewModel() { val isTyping = ObservableBoolean(false) - val name = ObservableField() - val favDouble = ObservableField() + val name = ObservableField("") + val favDouble = ObservableField("") val favDoubleIndex = ObservableInt() val errorMsg = ObservableInt() internal lateinit var initialProfileName: String 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 822da37a..033ab336 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 @@ -50,6 +50,8 @@ class SelectProfileActivity : ViewModelActivity() { val recyclerView = binding.profileRecyclerView recyclerView.layoutManager = LinearLayoutManager(binding.root.context!!) recyclerView.itemAnimator = DefaultItemAnimator() + recyclerView.setHasFixedSize(true) + recyclerView.setItemViewCacheSize(20) recyclerView.isDrawingCacheEnabled = true val swipeToDeleteHelper = ItemTouchHelper(object : SwipeToDeleteCallback(binding.root.context!!) { override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { 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 bbfb8152..74d36a40 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 @@ -1,6 +1,10 @@ package nl.entreco.dartsscorecard.profile.select import android.databinding.DataBindingUtil +import android.support.annotation.NonNull +import android.support.v7.recyclerview.extensions.AsyncDifferConfig +import android.support.v7.recyclerview.extensions.ListAdapter +import android.support.v7.util.DiffUtil import android.view.LayoutInflater import android.view.ViewGroup import nl.entreco.dartsscorecard.R @@ -11,9 +15,7 @@ import nl.entreco.domain.profile.Profile /** * Created by entreco on 04/03/2018. */ -class SelectProfileAdapter(private val navigator: SelectProfileNavigator) : TestableAdapter() { - - private val items: MutableList = mutableListOf() +class SelectProfileAdapter(private val navigator: SelectProfileNavigator) : ListAdapter(diff) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProfileView { val inflater = LayoutInflater.from(parent.context) @@ -22,25 +24,24 @@ class SelectProfileAdapter(private val navigator: SelectProfileNavigator) : Test } override fun onBindViewHolder(holder: ProfileView, position: Int) { - holder.bind(items[position], navigator) + holder.bind(getItem(position), navigator) } - override fun getItemCount(): Int { - return items.size + fun playerIdAt(position: Int): Long { + return getItem(position).id } - fun playerIdAt(position: Int): Long{ - return items[position].id + fun setItems(profiles: List) { + submitList(profiles) } +} - fun setItems(profiles: List) { - items.clear() - items.addAll(profiles) - tryNotifyItemRangeChanged(0, profiles.size) +val diff : DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Profile?, newItem: Profile?): Boolean { + return oldItem?.id == newItem?.id } - fun removeAt(position: Int) { - items.removeAt(position) - tryNotifyItemRemoved(position) + 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/SelectProfileViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileViewModel.kt index 9f0d451f..d3c1772c 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileViewModel.kt @@ -37,7 +37,6 @@ class SelectProfileViewModel @Inject constructor( fun deletePlayerProfile(position: Int, adapter: SelectProfileAdapter) { val player = adapter.playerIdAt(position) - adapter.removeAt(position) deletePlayerUsecase.delete(DeletePlayerRequest(player), {}, onFailed()) reload(adapter) } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/PlayerStats.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/PlayerStats.kt new file mode 100644 index 00000000..68faf735 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/PlayerStats.kt @@ -0,0 +1,18 @@ +package nl.entreco.dartsscorecard.profile.view + +import android.databinding.ObservableBoolean +import android.databinding.ObservableField +import android.databinding.ObservableInt +import nl.entreco.domain.profile.ProfileStat + + +class PlayerStats(stat: ProfileStat) { + val isEmpty = ObservableBoolean(stat.numberOfGames <= 0) + val gamesPlayed = ObservableField("${stat.numberOfGames}") + val average = ObservableField("%.2f".format(avgOf(stat.numberOfPoints, stat.numberOfDarts) * 3F)) + + private fun avgOf(sum: Int, total: Int) : Float = when(total){ + 0 -> 0F + else -> sum / total.toFloat() + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileActivity.kt index d73542d0..abd3d614 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileActivity.kt @@ -5,7 +5,9 @@ import android.content.Intent import android.databinding.DataBindingUtil import android.os.Bundle import android.support.v4.app.ActivityOptionsCompat +import android.support.v7.widget.Toolbar import android.transition.TransitionInflater +import android.view.MenuItem import android.view.View import android.widget.TextView import nl.entreco.dartsscorecard.R @@ -34,6 +36,12 @@ class ProfileActivity : ViewModelActivity() { binding.navigator = ProfileNavigator(this) viewModel.fetchProfile(idsFromIntent(intent)) + + initToolbar(toolbar(binding), R.string.empty) + } + + private fun toolbar(binding: ActivityProfileBinding): Toolbar { + return binding.includeAppbar.toolbar } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -47,6 +55,16 @@ class ProfileActivity : ViewModelActivity() { super.onActivityResult(requestCode, resultCode, data) } + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + return when (item?.itemId) { + android.R.id.home -> { + onBackPressed() + true + } + else -> super.onOptionsItemSelected(item) + } + } + override fun onBackPressed() { if (madeChanges) { setResult(Activity.RESULT_OK) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModel.kt index 27334725..b0f853b8 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModel.kt @@ -5,9 +5,7 @@ import android.databinding.ObservableField import android.databinding.ObservableInt import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.profile.fetch.FetchProfileRequest -import nl.entreco.domain.profile.fetch.FetchProfileResponse -import nl.entreco.domain.profile.fetch.FetchProfileUsecase +import nl.entreco.domain.profile.fetch.* import nl.entreco.domain.profile.update.UpdateProfileRequest import nl.entreco.domain.profile.update.UpdateProfileResponse import nl.entreco.domain.profile.update.UpdateProfileUsecase @@ -17,14 +15,17 @@ import javax.inject.Inject * Created by entreco on 21/02/2018. */ class ProfileViewModel @Inject constructor(private val fetchProfileUsecase: FetchProfileUsecase, - private val updateProfileUsecase: UpdateProfileUsecase) : BaseViewModel() { + private val updateProfileUsecase: UpdateProfileUsecase, + private val fetchProfileStatsUsecase: FetchProfileStatsUsecase) : BaseViewModel() { val profile = ObservableField() + val stats = ObservableField() val errorMsg = ObservableInt() fun fetchProfile(playerIds: LongArray) { if (profile.get() == null && playerIds.isNotEmpty()) { fetchProfileUsecase.exec(FetchProfileRequest(playerIds), onProfileSuccess(), onProfileFailed()) + fetchProfileStatsUsecase.exec(FetchProfileStatRequest(playerIds[0]), onStatsSuccess(), onStatsFailed()) } } @@ -56,6 +57,14 @@ class ProfileViewModel @Inject constructor(private val fetchProfileUsecase: Fetc } private fun onProfileFailed(): (Throwable) -> Unit = { - errorMsg.set(R.string.err_unable_to_fetch_players) + this.errorMsg.set(R.string.err_unable_to_fetch_players) + } + + private fun onStatsSuccess(): (FetchProfileStatResponse) -> Unit = { stats -> + this.stats.set(PlayerStats(stats.stat)) + } + + private fun onStatsFailed():(Throwable)->Unit = { + this.errorMsg.set(R.string.err_unable_to_fetch_stats) } } diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Activity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Activity.kt index 503b34e6..68fef086 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Activity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Activity.kt @@ -1,16 +1,17 @@ package nl.entreco.dartsscorecard.setup +import android.app.Activity import android.content.Context import android.content.Intent import android.databinding.DataBindingUtil import android.os.Bundle import android.support.v7.widget.Toolbar import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.ad.AdViewModel import nl.entreco.dartsscorecard.base.ViewModelActivity import nl.entreco.dartsscorecard.databinding.ActivitySetup01Binding import nl.entreco.dartsscorecard.di.setup.Setup01Component import nl.entreco.dartsscorecard.di.setup.Setup01Module -import nl.entreco.dartsscorecard.setup.ad.AdViewModel import nl.entreco.dartsscorecard.setup.players.PlayersViewModel import nl.entreco.dartsscorecard.setup.settings.SettingsViewModel @@ -22,22 +23,24 @@ class Setup01Activity : ViewModelActivity() { private val component: Setup01Component by componentProvider { it.plus(Setup01Module(this)) } private val viewModel: Setup01ViewModel by viewModelProvider { component.viewModel() } private val playersViewModel: PlayersViewModel by viewModelProvider { component.players() } - private val adsViewModel: AdViewModel by viewModelProvider { component.ads() } private val settingsViewModel: SettingsViewModel by viewModelProvider { component.settings() } + private val adViewModel: AdViewModel by viewModelProvider { component.ads() } private val navigator: Setup01Navigator by lazy { Setup01Navigator(this) } + private var initialLaunch = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView(this, R.layout.activity_setup_01) binding.viewModel = viewModel binding.playersViewModel = playersViewModel - binding.adsViewModel = adsViewModel + binding.adViewModel = adViewModel binding.settingsViewModel = settingsViewModel binding.navigator = navigator initToolbar(toolbar(binding), R.string.title_setup) if (savedInstanceState == null) { + initialLaunch = true navigator.onAddNewPlayer(0, emptyList()) } } @@ -48,6 +51,11 @@ class Setup01Activity : ViewModelActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) + if(resultCode == Activity.RESULT_CANCELED && initialLaunch){ + finish() + return + } + initialLaunch = false navigator.handleResult(requestCode, resultCode, data, playersViewModel.adapter) } 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 852c3d77..8c6ccac9 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.Logger +import nl.entreco.domain.common.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/setup/ad/AdBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdBindings.kt deleted file mode 100644 index 09a62329..00000000 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdBindings.kt +++ /dev/null @@ -1,30 +0,0 @@ -package nl.entreco.dartsscorecard.setup.ad - -import android.databinding.BindingAdapter -import android.view.View -import com.google.android.gms.ads.AdListener -import com.google.android.gms.ads.AdRequest -import com.google.android.gms.ads.AdView - -/** - * Created by Entreco on 29/12/2017. - */ -abstract class AdBindings { - companion object { - @JvmStatic - @BindingAdapter("loadAdd", "adListener") - fun loadAd(view: AdView, load: Boolean, adListener: AdListener) { - if (load) { - val adRequest = AdRequest.Builder().build() - view.adListener = adListener - view.loadAd(adRequest) - } - } - - @JvmStatic - @BindingAdapter("showAd") - fun showAd(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/setup/ad/AdLoader.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdLoader.kt deleted file mode 100644 index 2a38e38b..00000000 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdLoader.kt +++ /dev/null @@ -1,30 +0,0 @@ -package nl.entreco.dartsscorecard.setup.ad - -import com.google.android.gms.ads.AdListener -import javax.inject.Inject - -/** - * Created by Entreco on 29/12/2017. - */ -class AdLoader @Inject constructor(private val listener: Listener) : AdListener() { - interface Listener { - fun onAdClicked() - fun onAdLoaded() - fun onAdFailed(err: Int) - } - - override fun onAdClicked() { - super.onAdClicked() - listener.onAdClicked() - } - - override fun onAdLoaded() { - super.onAdLoaded() - listener.onAdLoaded() - } - - override fun onAdFailedToLoad(err: Int) { - super.onAdFailedToLoad(err) - listener.onAdFailed(err) - } -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdViewModel.kt deleted file mode 100644 index a1986fcb..00000000 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/ad/AdViewModel.kt +++ /dev/null @@ -1,28 +0,0 @@ -package nl.entreco.dartsscorecard.setup.ad - -import android.databinding.ObservableBoolean -import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.Analytics -import javax.inject.Inject - -/** - * Created by Entreco on 29/12/2017. - */ -class AdViewModel @Inject constructor(private val analytics: Analytics) : BaseViewModel(), AdLoader.Listener { - - val loadAd by lazy { ObservableBoolean(true) } - val showAd by lazy { ObservableBoolean(false) } - val adLoader by lazy { AdLoader(this) } - - override fun onAdClicked() { - analytics.trackAchievement("onAdClicked") - } - - override fun onAdLoaded() { - showAd.set(true) - } - - override fun onAdFailed(err: Int) { - showAd.set(false) - } -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigator.kt index 958d8f38..c6c71164 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigator.kt @@ -1,5 +1,6 @@ package nl.entreco.dartsscorecard.setup.edit +import android.app.Activity.RESULT_CANCELED import android.app.Activity.RESULT_OK import nl.entreco.dartsscorecard.setup.Setup01Navigator import nl.entreco.domain.model.players.Player @@ -14,7 +15,7 @@ class EditPlayerNavigator(private val activity: EditPlayerActivity) : ExistingPl } override fun onBackPressed() { - activity.setResult(RESULT_OK, Setup01Navigator.cancelPlayerResponse(activity.intent)) + activity.setResult(RESULT_CANCELED, Setup01Navigator.cancelPlayerResponse(activity.intent)) activity.finish() } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerAdapter.kt index 4b3e0cc0..18f38f7f 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerAdapter.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerAdapter.kt @@ -57,6 +57,6 @@ class PlayerAdapter @Inject constructor(private val editor: PlayerEditor) : Test private fun updateTeamCount() { teams.clear() teams += 1..itemCount - tryNotifyItemRangeChanged(0, itemCount) + tryNotifyItemRangeInserted(0, itemCount) } } diff --git a/android/DartsScorecard/app/src/main/res/drawable-hdpi/ic_stat_name.png b/android/DartsScorecard/app/src/main/res/drawable-hdpi/ic_stat_name.png new file mode 100644 index 00000000..f40e2f7e Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-hdpi/ic_stat_name.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable-mdpi/ic_stat_name.png b/android/DartsScorecard/app/src/main/res/drawable-mdpi/ic_stat_name.png new file mode 100644 index 00000000..79c3bfd0 Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-mdpi/ic_stat_name.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable-nodpi/play01_bg_image.jpg b/android/DartsScorecard/app/src/main/res/drawable-nodpi/play01_bg_image.jpg index aa90252e..e2a55da1 100644 Binary files a/android/DartsScorecard/app/src/main/res/drawable-nodpi/play01_bg_image.jpg and b/android/DartsScorecard/app/src/main/res/drawable-nodpi/play01_bg_image.jpg differ diff --git a/android/DartsScorecard/app/src/main/res/drawable-xhdpi/ic_stat_name.png b/android/DartsScorecard/app/src/main/res/drawable-xhdpi/ic_stat_name.png new file mode 100644 index 00000000..ca23098a Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-xhdpi/ic_stat_name.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable-xxhdpi/ic_stat_name.png b/android/DartsScorecard/app/src/main/res/drawable-xxhdpi/ic_stat_name.png new file mode 100644 index 00000000..e903fb0b Binary files /dev/null and b/android/DartsScorecard/app/src/main/res/drawable-xxhdpi/ic_stat_name.png differ diff --git a/android/DartsScorecard/app/src/main/res/drawable/beta_gradient_bottom.xml b/android/DartsScorecard/app/src/main/res/drawable/beta_gradient_bottom.xml new file mode 100644 index 00000000..1fad0f5a --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/beta_gradient_bottom.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_start.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_start.xml index 3ec66f15..0f70f989 100644 --- a/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_start.xml +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_start.xml @@ -3,7 +3,6 @@ android:height="@dimen/icon_size_default" android:viewportWidth="136.0" android:viewportHeight="136.0"> - + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_play_video.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_play_video.xml new file mode 100644 index 00000000..3621fbac --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_play_video.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_stat_side.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_stat_side.xml new file mode 100644 index 00000000..6e993ead --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/ic_stat_side.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/android/DartsScorecard/app/src/main/res/drawable/profile_stat_bg.xml b/android/DartsScorecard/app/src/main/res/drawable/profile_stat_bg.xml new file mode 100644 index 00000000..c0592b13 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/drawable/profile_stat_bg.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + \ No newline at end of file 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 17cb5bf4..948369bf 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 @@ -14,7 +14,7 @@ + type="nl.entreco.dartsscorecard.play.live.LiveStatViewModel" /> + + @@ -20,7 +24,8 @@ + android:layout_height="match_parent" + android:background="@drawable/stats_bg"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + name="adViewModel" + type="nl.entreco.dartsscorecard.ad.AdViewModel" /> + app:viewModel="@{adViewModel}" /> @@ -109,10 +111,10 @@ android:layout_width="match_parent" android:layout_height="110dp" android:background="@null" + android:contentDescription="@null" android:elevation="6dp" android:scaleType="fitEnd" android:src="@drawable/ic_started" - android:contentDescription="@null" android:visibility="@{feature.votable ? View.GONE : View.VISIBLE}" /> diff --git a/android/DartsScorecard/app/src/main/res/layout/include_beta_detail.xml b/android/DartsScorecard/app/src/main/res/layout/include_beta_detail.xml index 4a47c6c6..9f4351fd 100644 --- a/android/DartsScorecard/app/src/main/res/layout/include_beta_detail.xml +++ b/android/DartsScorecard/app/src/main/res/layout/include_beta_detail.xml @@ -22,14 +22,13 @@ + android:layout_height="match_parent"> + android:fillViewport="true" + android:layout_marginTop="?android:attr/actionBarSize"> - - + android:background="@drawable/beta_gradient_bottom" /> + + @@ -114,7 +121,7 @@ layout="@layout/include_beta_implementation" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_below="@id/description" + android:layout_below="@id/video" android:visibility="@{viewModel.feature.votable ? View.GONE : View.VISIBLE}" app:feature="@{viewModel.feature}" /> diff --git a/android/DartsScorecard/app/src/main/res/layout/include_beta_donate.xml b/android/DartsScorecard/app/src/main/res/layout/include_beta_donate.xml index 63f97276..92ec601d 100644 --- a/android/DartsScorecard/app/src/main/res/layout/include_beta_donate.xml +++ b/android/DartsScorecard/app/src/main/res/layout/include_beta_donate.xml @@ -15,6 +15,17 @@ type="nl.entreco.dartsscorecard.beta.donate.DonateViewModel" /> + + + - - + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/include_profile_empty.xml b/android/DartsScorecard/app/src/main/res/layout/include_profile_empty.xml new file mode 100644 index 00000000..20d002c9 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout/include_profile_empty.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/include_profile_stats.xml b/android/DartsScorecard/app/src/main/res/layout/include_profile_stats.xml new file mode 100644 index 00000000..d7f38810 --- /dev/null +++ b/android/DartsScorecard/app/src/main/res/layout/include_profile_stats.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/include_setup_ad.xml b/android/DartsScorecard/app/src/main/res/layout/include_setup_ad.xml index 8b08bddd..1d6ea385 100644 --- a/android/DartsScorecard/app/src/main/res/layout/include_setup_ad.xml +++ b/android/DartsScorecard/app/src/main/res/layout/include_setup_ad.xml @@ -1,7 +1,7 @@ @@ -9,7 +9,7 @@ + type="nl.entreco.dartsscorecard.ad.AdViewModel" /> + app:viewModel="@{viewModel}" /> diff --git a/android/DartsScorecard/app/src/main/res/layout/play_01_loading.xml b/android/DartsScorecard/app/src/main/res/layout/play_01_loading.xml index 966f9353..d0809df9 100644 --- a/android/DartsScorecard/app/src/main/res/layout/play_01_loading.xml +++ b/android/DartsScorecard/app/src/main/res/layout/play_01_loading.xml @@ -1,19 +1,21 @@ - + - + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + \ 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 bb85c484..f415af64 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 @@ -7,7 +7,7 @@ + type="nl.entreco.dartsscorecard.play.live.LiveStatViewModel" /> + app:liveStats="@{viewModel.teamStats}" /> + + type="nl.entreco.dartsscorecard.play.live.TeamLiveStatModel" /> + + type="nl.entreco.dartsscorecard.play.live.TeamLiveStatModel" /> + @@ -44,8 +47,8 @@ android:background="@drawable/profile_bg" android:contentDescription="@null" android:onClick="@{(view) -> navigator.gotoTeamProfile(view, team0.team)}" - app:profileImage="@{team0.image}" - android:transitionName="profile" /> + android:transitionName="profile" + app:profileImage="@{team0.image}" /> + android:transitionName="profile" + app:hideIfOneTeam="@{team1 == null}" + app:profileImage="@{team1.image}" /> + android:layout_weight="1" + app:hideIfOneTeam="@{team1 == null}" /> @@ -85,7 +90,7 @@ style="@style/Main.Player" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center|end" + app:centerIfOneTeam="@{team1 == null}" android:text="@{team0.name}" /> + android:layout_weight="1" + app:hideIfOneTeam="@{team1 == null}"> + android:text="@{team1.avg.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> + + + + + + + + + + + + + + + + + + + android:text="@{team1.n100.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> @@ -198,11 +261,12 @@ style="@style/Main.Value" android:layout_width="68dp" android:layout_height="wrap_content" - android:text="@{team1.n140.toString()}" /> + android:text="@{team1.n140.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> @@ -225,11 +289,39 @@ style="@style/Main.Value" android:layout_width="68dp" android:layout_height="wrap_content" - android:text="@{team1.n180.toString()}" /> + android:text="@{team1.n180.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> + + + + + + + + + @@ -251,11 +343,12 @@ style="@style/Main.Value" android:layout_width="68dp" android:layout_height="wrap_content" - android:text="@{team1.hCo.toString()}" /> + android:text="@{team1.hCo.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> @@ -277,11 +370,12 @@ style="@style/Main.Value" android:layout_width="68dp" android:layout_height="wrap_content" - android:text="@{team1.co.toString()}" /> + android:text="@{team1.co.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> @@ -303,7 +397,8 @@ style="@style/Main.Value" android:layout_width="68dp" android:layout_height="wrap_content" - android:text="@{team1.breaks.toString()}" /> + android:text="@{team1.breaks.toString()}" + app:hideIfOneTeam="@{team1 == null}" /> diff --git a/android/DartsScorecard/app/src/main/res/values/dimens.xml b/android/DartsScorecard/app/src/main/res/values/dimens.xml index ea7c63da..d0f71401 100644 --- a/android/DartsScorecard/app/src/main/res/values/dimens.xml +++ b/android/DartsScorecard/app/src/main/res/values/dimens.xml @@ -5,6 +5,7 @@ 8dp 16dp 32dp + 64dp 6dp 24dp diff --git a/android/DartsScorecard/app/src/main/res/values/keys.xml b/android/DartsScorecard/app/src/main/res/values/keys.xml index 8e48ed6e..ece27ad3 100644 --- a/android/DartsScorecard/app/src/main/res/values/keys.xml +++ b/android/DartsScorecard/app/src/main/res/values/keys.xml @@ -1,5 +1,7 @@ + ca-app-pub-3793327349392749~1846337901 ca-app-pub-3793327349392749/2238054293 + 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 876e1091..3db5dd91 100644 --- a/android/DartsScorecard/app/src/main/res/values/strings.xml +++ b/android/DartsScorecard/app/src/main/res/values/strings.xml @@ -31,8 +31,10 @@ VOTE %1$s VOTES %1$s %2$s - Thanks! You are AWESOME! - <p>Once this feature has <b>%1$s</b> votes, development will start.</p> + You are AWESOME & will no longer see those annoying ads ;) + THANKS + <p>Once this feature has <b>%1$s</b> votes, development will start.</p><p>All Donations <b>include removing all ads</b> from the app</p> + <b>Watch the video</b> Select Players @@ -69,12 +71,25 @@ Match Statistics Breaks Made Double Success + Highest Score Highest Out 180\'s 140+ 100+ + 60+ + 20+ average + + No stats available yet + Complete a game and come back here to see how you\'re doing + + + Archive Stats Service + Archive stats + Calculating stats & averages + Calculating new stats, averages & hiscores + BDO World Cup - semi finals PDC World Cup - semi finals @@ -86,6 +101,7 @@ Unable to create player. Unable to donate for features at the moment. Unable to fetch players. + Unable to fetch statistics for player Player name already exists. Please choose a different name Invalid player name Please type desired player name diff --git a/android/DartsScorecard/app/src/main/res/values/styles.xml b/android/DartsScorecard/app/src/main/res/values/styles.xml index 891f6182..22670dff 100644 --- a/android/DartsScorecard/app/src/main/res/values/styles.xml +++ b/android/DartsScorecard/app/src/main/res/values/styles.xml @@ -17,7 +17,6 @@ false - + + + + + + + + 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 new file mode 100644 index 00000000..b49e867b --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestBackground.kt @@ -0,0 +1,13 @@ +package nl.entreco.dartsscorecard + +import nl.entreco.domain.common.executors.Background +import java.util.concurrent.Future +import java.util.concurrent.FutureTask + + +class TestBackground : Background { + override fun post(runnable: Runnable): Future<*> { + runnable.run() + return FutureTask(runnable, 0) + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..07f10be8 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/TestForeground.kt @@ -0,0 +1,10 @@ +package nl.entreco.dartsscorecard + +import nl.entreco.domain.common.executors.Foreground + + +class TestForeground : Foreground { + override fun post(runnable: Runnable) { + runnable.run() + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..b79bc164 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/AdViewModelTest.kt @@ -0,0 +1,182 @@ +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.domain.ad.FetchPurchasedItemsResponse +import nl.entreco.domain.ad.FetchPurchasedItemsUsecase +import nl.entreco.domain.purchases.connect.ConnectToBillingUsecase +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class AdViewModelTest { + + @Mock private lateinit var mockAdView: AdView + @Mock private lateinit var mockBillingUsecas: ConnectToBillingUsecase + @Mock private lateinit var mockFetchItemsUsecase: FetchPurchasedItemsUsecase + @Mock private lateinit var mockAdLoader: AdLoader + @Mock private lateinit var mockInterstitialLoader: InterstitialLoader + @Mock private lateinit var mockLogger: Logger + @Mock private lateinit var mockLifecycle: Lifecycle + private lateinit var subject : AdViewModel + + @Test + fun `it should register on init`() { + givenSubject() + thenObserverIsAdded() + } + + @Test + fun `it should deregister on destroy`() { + givenSubject() + whenDestroying() + thenObserverIsRemoved() + } + + @Test + fun `it should not serve adds initially`() { + givenSubject() + whenLoadingAdSucceeds() + thenShowAdIs(false) + } + + @Test + fun `it should NOT serve adds when purchasedItems exist`() { + givenSubject() + givenPurchasedItems(true) + whenLoadingAdSucceeds() + thenShowAdIs(false) + } + + @Test + fun `it should serve adds when no purchasedItems exist`() { + givenSubject() + givenPurchasedItems(false) + whenLoadingAdSucceeds() + thenShowAdIs(true) + } + + @Test + fun `it should not serve adds when loading fails`() { + givenSubject() + whenLoadingAdFails() + thenShowAdIs(false) + } + + @Test + fun `it should NOT serve interstitial initially`() { + givenSubject() + whenProvidingInterstitials() + thenNoInterstialIsLoaded() + } + + @Test + fun `it should NOT serve interstitial when unable to bind`() { + givenSubject() + givenBindingToBillingFails() + whenProvidingInterstitials() + thenNoInterstialIsLoaded() + } + + @Test + fun `it should serve interstitial when no items purchased`() { + givenSubject() + givenPurchasedItems(false) + whenProvidingInterstitials() + thenInterstialIsLoaded() + } + + @Test + fun `it should NOT serve interstitial when items purchased`() { + givenSubject() + givenPurchasedItems(true) + whenProvidingInterstitials() + thenNoInterstialIsLoaded() + } + + @Test + fun `it should NOT serve interstitial when items cannot be retrieved`() { + givenSubject() + givenPurchasedItemsFails() + whenProvidingInterstitials() + thenNoInterstialIsLoaded() + } + + private fun givenSubject() { + subject = AdViewModel(mockLifecycle, mockBillingUsecas, mockFetchItemsUsecase, mockAdLoader, mockInterstitialLoader, mockLogger, false) + } + + private fun givenPurchasedItems(purchasedItems: Boolean){ + val bindCaptor = argumentCaptor<(Boolean)->Unit>() + val doneCaptor = argumentCaptor<(FetchPurchasedItemsResponse)->Unit>() + subject.bind() + verify(mockBillingUsecas).bind(bindCaptor.capture()) + bindCaptor.lastValue.invoke(true) + verify(mockFetchItemsUsecase).exec(doneCaptor.capture(), any()) + doneCaptor.lastValue.invoke(FetchPurchasedItemsResponse(!purchasedItems)) + } + + private fun givenPurchasedItemsFails(){ + val bindCaptor = argumentCaptor<(Boolean)->Unit>() + val failCaptor = argumentCaptor<(Throwable)->Unit>() + subject.bind() + verify(mockBillingUsecas).bind(bindCaptor.capture()) + bindCaptor.lastValue.invoke(true) + verify(mockFetchItemsUsecase).exec(any(), failCaptor.capture()) + failCaptor.lastValue.invoke(RuntimeException("Unable to query purchased items")) + } + + private fun givenBindingToBillingFails(){ + val bindCaptor = argumentCaptor<(Boolean)->Unit>() + subject.bind() + verify(mockBillingUsecas).bind(bindCaptor.capture()) + bindCaptor.lastValue.invoke(false) + } + + private fun whenLoadingAdSucceeds() { + val listenerCaptor = argumentCaptor() + subject.provideAdd(mockAdView) + verify(mockAdLoader).loadAd(eq(mockAdView), listenerCaptor.capture()) + listenerCaptor.lastValue.onAdLoaded() + } + + private fun whenLoadingAdFails() { + val listenerCaptor = argumentCaptor() + subject.provideAdd(mockAdView) + verify(mockAdLoader).loadAd(eq(mockAdView), listenerCaptor.capture()) + listenerCaptor.lastValue.onAdFailed() + } + + private fun whenProvidingInterstitials() { + subject.provideInterstitial() + } + + private fun whenDestroying() { + subject.destroy() + } + + private fun thenObserverIsAdded() { + verify(mockLifecycle).addObserver(subject) + } + + private fun thenObserverIsRemoved() { + verify(mockLifecycle).removeObserver(subject) + } + + private fun thenNoInterstialIsLoaded() { + verifyZeroInteractions(mockInterstitialLoader) + } + + private fun thenInterstialIsLoaded() { + verify(mockInterstitialLoader).showInterstitial() + } + + private fun thenShowAdIs(expected: Boolean){ + assertEquals(expected, subject.showAd.get()) + } +} diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/InterstitialLoaderTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/InterstitialLoaderTest.kt new file mode 100644 index 00000000..a73f7219 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/ad/InterstitialLoaderTest.kt @@ -0,0 +1,67 @@ +package nl.entreco.dartsscorecard.ad + +import com.google.android.gms.ads.InterstitialAd +import com.nhaarman.mockito_kotlin.any +import com.nhaarman.mockito_kotlin.never +import com.nhaarman.mockito_kotlin.verify +import com.nhaarman.mockito_kotlin.whenever +import org.junit.Test + +import org.junit.Assert.* +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.times +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class InterstitialLoaderTest { + + @Mock private lateinit var mockInterstitial: InterstitialAd + private lateinit var subject : InterstitialLoader + + @Test + fun `it should show Interstitial when loaded ok`() { + givenSubject(true) + whenShowingInterstitial() + thenInterstialIsShown() + } + + @Test + fun `it should NOT show interstitial when not loaded ok`() { + givenSubject(false) + whenShowingInterstitial() + thenInterstialIsNotShown() + } + + @Test + fun `it should load new interstitial onAdClosed`() { + givenSubject(true) + whenAdClosed() + thenNewInterstitialIsLoaded() + } + + private fun givenSubject(loaded: Boolean) { + whenever(mockInterstitial.isLoaded).thenReturn(loaded) + subject = InterstitialLoader("interstialAdUnitId", mockInterstitial) + } + + private fun whenShowingInterstitial() { + subject.showInterstitial() + } + + private fun whenAdClosed() { + subject.onAdClosed() + } + + private fun thenInterstialIsShown() { + verify(mockInterstitial).show() + } + + private fun thenInterstialIsNotShown() { + verify(mockInterstitial, never()).show() + } + + private fun thenNewInterstitialIsLoaded() { + verify(mockInterstitial, times(2)).loadAd(any()) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaAdapterTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaAdapterTest.kt index 43bd4463..362683d3 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaAdapterTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaAdapterTest.kt @@ -3,6 +3,8 @@ package nl.entreco.dartsscorecard.beta import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.isNull import com.nhaarman.mockito_kotlin.verify +import nl.entreco.dartsscorecard.TestBackground +import nl.entreco.dartsscorecard.TestForeground import nl.entreco.domain.beta.Feature import org.junit.Assert.assertEquals import org.junit.Before @@ -23,7 +25,7 @@ class BetaAdapterTest { @Before fun setUp() { - subject = BetaAdapter() + subject = BetaAdapter(TestBackground(), TestForeground()) } @Test diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaBindingsTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaBindingsTest.kt index 49cf791e..914f6cc5 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaBindingsTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaBindingsTest.kt @@ -27,7 +27,7 @@ class BetaBindingsTest { @Mock private lateinit var mockImageView: ImageView @Mock private lateinit var mockAnimator: ViewPropertyAnimator - @Test(expected = NullPointerException::class) + @Test(expected = IllegalStateException::class) fun loadImage() { setupContextMocking() BetaBindings.loadImage(mockImageView, "some url") @@ -69,9 +69,7 @@ class BetaBindingsTest { verify(mockTextView, never()).text = any() } - private fun setupContextMocking() { - whenever(mockImageView.context).thenReturn(mockContext) - } + private fun setupContextMocking() {} private fun setupMocking() { whenever(mockView.animate()).thenReturn(mockAnimator) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculatorTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculatorTest.kt index ce6ec4f5..0600aaee 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculatorTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaDiffCalculatorTest.kt @@ -9,10 +9,10 @@ import org.junit.Test */ class BetaDiffCalculatorTest { - private val feature1 = Feature("ref1", "title1", "desc1", "img1", "update", 1, 1) - private val feature2 = Feature("ref2", "title2", "desc2", "img2", "update", 2, 2) - private val feature3 = Feature("ref3", "title3", "desc3", "img3", "update", 3, 3) - private val feature4 = Feature("ref4", "title4", "desc4", "img4", "update", 4, 4) + private val feature1 = Feature("ref1", "title1", "desc1", "img1", "update", 1, 1, "") + private val feature2 = Feature("ref2", "title2", "desc2", "img2", "update", 2, 2, "") + private val feature3 = Feature("ref3", "title3", "desc3", "img3", "update", 3, 3, "") + private val feature4 = Feature("ref4", "title4", "desc4", "img4", "update", 4, 4, "") @Test fun `areItemsTheSame 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 8712be08..4ee31bd6 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,7 @@ 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 feature = Feature("reference", "title", "description", "http://url.com", "remarks", 10000, 500, "") private val subject = BetaModel(feature) @Test diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaViewModelTest.kt index 53e4cafb..0fd60bc5 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/BetaViewModelTest.kt @@ -8,7 +8,7 @@ import com.nhaarman.mockito_kotlin.argumentCaptor import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.whenever import nl.entreco.domain.beta.Feature -import nl.entreco.domain.beta.connect.SubscribeToFeaturesUsecase +import nl.entreco.domain.purchases.connect.SubscribeToFeaturesUsecase import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith @@ -72,7 +72,7 @@ class BetaViewModelTest { } private fun whenFetchingFeaturesSucceeds() { - expectedFeatureList = listOf(Feature("ref", "title", "desc", "img", "", 3, 1)) + expectedFeatureList = listOf(Feature("ref", "title", "desc", "img", "", 3, 1, "")) subject.refresh() verify(mockSubscribeToFeaturesUsecase).subscribe(doneCaptor.capture(), any()) try { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateBindingsTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateBindingsTest.kt index 86190dd0..8aba8e47 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateBindingsTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/donate/DonateBindingsTest.kt @@ -18,26 +18,8 @@ class DonateBindingsTest { @Mock private lateinit var mockViewGroup: ViewGroup @Test - fun `it should clear previous views when list is NOT empty`() { - whenever(mockViewGroup.childCount).thenReturn(5) + fun `it should clear previous views`() { DonateBindings.clearPreviousViewsIfEmpty(mockViewGroup) - verify(mockViewGroup).removeViewAt(1) - verify(mockViewGroup).removeViewAt(2) - verify(mockViewGroup).removeViewAt(3) - verify(mockViewGroup).removeViewAt(4) - } - - @Test - fun `it should remove empty View when list is empty`() { - whenever(mockViewGroup.childCount).thenReturn(0) - DonateBindings.clearPreviousViewsIfEmpty(mockViewGroup) - verify(mockViewGroup, never()).removeViewAt(0) - } - - @Test - fun `it should remove empty View when list has 1 item`() { - whenever(mockViewGroup.childCount).thenReturn(2) - DonateBindings.clearPreviousViewsIfEmpty(mockViewGroup) - verify(mockViewGroup).removeViewAt(1) + verify(mockViewGroup).removeAllViews() } } \ No newline at end of file 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 ba3f4165..d405ff36 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 @@ -5,7 +5,7 @@ import android.content.Intent import com.nhaarman.mockito_kotlin.* import nl.entreco.domain.Analytics import nl.entreco.domain.beta.Donation -import nl.entreco.domain.beta.connect.ConnectToBillingUsecase +import nl.entreco.domain.purchases.connect.ConnectToBillingUsecase import nl.entreco.domain.beta.donations.* import org.junit.Assert.assertEquals import org.junit.Test @@ -289,7 +289,7 @@ class DonateViewModelTest { private fun whenFetchingDonationsSucceeds(list: List) { whenBindingSucceeds() verify(mockFetchDonationsUsecase).exec(fetchDoneCaptor.capture(), any()) - fetchDoneCaptor.lastValue.invoke(FetchDonationsResponse(list)) + fetchDoneCaptor.lastValue.invoke(FetchDonationsResponse(list, true)) } private fun whenFetchingDonationsFails() { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModelTest.kt index 399440a3..46b99381 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/beta/votes/VoteViewModelTest.kt @@ -1,7 +1,9 @@ package nl.entreco.dartsscorecard.beta.votes +import android.content.Context import android.databinding.ObservableBoolean import android.databinding.ObservableField +import android.view.View import com.nhaarman.mockito_kotlin.* import nl.entreco.dartsscorecard.beta.BetaModel import nl.entreco.domain.Analytics @@ -25,7 +27,9 @@ class VoteViewModelTest { @Mock private lateinit var mockObservableField: ObservableField @Mock private lateinit var mockVoteUsecase: SubmitVoteUsecase @Mock private lateinit var mockAnalytics: Analytics + @Mock private lateinit var mockContext: Context @Mock private lateinit var mockModel: BetaModel + @Mock private lateinit var mockView: View private lateinit var subject: VoteViewModel private lateinit var givenDonation: Donation @@ -100,22 +104,35 @@ class VoteViewModelTest { thenDidAlreadyVoteIs(false) } + @Test(expected = NullPointerException::class) // Meaning Uri.parse() called + fun `it should launch video for valid url`() { + givenSubject() + whenLaunchingVideo("http://www.url.com") + thenVideoIsLaunched() + } + private fun givenDonation(amount: Int) { givenDonation = Donation("title", "desc", "sku", "price", amount, "e", "12222") } - private fun givenSubject() { subject = VoteViewModel(mockVoteUsecase, mockAnalytics) } private fun whenFeatureSelected(feature: BetaModel) { whenever(mockObservableField.get()).thenReturn("Feature Title") - whenever(mockModel.feature).thenReturn(Feature("reference", "feature title", "feature description", "some image", "updates", 10, 2)) + whenever(mockModel.feature).thenReturn(Feature("reference", "feature title", "feature description", "some image", "updates", 10, 2, "")) + whenever(mockModel.video).thenReturn(mockObservableField) whenever(mockModel.title).thenReturn(mockObservableField) subject.onFeatureSelected(feature) } + private fun whenLaunchingVideo(url: String) { + val feature = Feature("reference", "feature title", "feature description", "some image", "updates", 10, 2, url) + subject.onFeatureSelected(BetaModel(feature)) + subject.launchVideo(mockView) + } + private fun whenSubmittingDonation() { whenever(mockModel.votable).thenReturn(ObservableBoolean(true)) subject.submitDonation(givenDonation) @@ -162,4 +179,8 @@ class VoteViewModelTest { private fun thenViewFeatureIsTracked() { verify(mockAnalytics).trackViewFeature(any()) } + + private fun thenVideoIsLaunched() { + verify(mockView).context + } } 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 14f713d9..d17d6946 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 @@ -3,10 +3,10 @@ package nl.entreco.dartsscorecard.di.application 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.data.analytics.FirebaseAnalytics -import org.junit.Assert.assertNotNull -import org.junit.Assert.assertTrue +import org.junit.Assert.* import org.junit.Before import org.junit.Test import org.mockito.Mock @@ -52,4 +52,13 @@ class AppModuleTest { fun provideFireStore() { assertNotNull(subject.provideFireStore()) } + + @Test + fun provideDebugMode() { + if(BuildConfig.DEBUG) { + assertTrue(subject.provideDebugMode()) + } else { + assertFalse(subject.provideDebugMode()) + } + } } \ No newline at end of file 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 new file mode 100644 index 00000000..e8f795e2 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/archive/ArchiveModuleTest.kt @@ -0,0 +1,29 @@ +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 +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class ArchiveModuleTest { + + @Mock private lateinit var mockMapper: ArchiveStatMapper + @Mock private lateinit var mockDb: DscDatabase + @Mock private lateinit var mockLogger: Logger + + @Test + fun `it should provide ProfileStatMapper`() { + assertNotNull(ArchiveModule().provideArchiveStatMapper()) + } + + + @Test + fun provideArchiveRepository() { + assertNotNull(ArchiveModule().provideArchiveRepository(mockDb, mockMapper, mockLogger)) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/beta/BetaModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/beta/BetaModuleTest.kt index eb180f02..352df3a6 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/beta/BetaModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/beta/BetaModuleTest.kt @@ -1,8 +1,6 @@ package nl.entreco.dartsscorecard.di.beta -import android.content.Context import nl.entreco.dartsscorecard.beta.donate.DonateCallback -import nl.entreco.data.billing.BillingServiceConnection import org.junit.Assert import org.junit.Assert.assertNotNull import org.junit.Test @@ -16,8 +14,6 @@ import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) class BetaModuleTest { - @Mock private lateinit var mockContext: Context - @Mock private lateinit var mockBillingConnection: BillingServiceConnection @Mock private lateinit var mockDonateCallback: DonateCallback @Test @@ -29,14 +25,4 @@ class BetaModuleTest { fun `it should provide callback`() { assertNotNull(BetaModule(mockDonateCallback).provideDonateCallback()) } - - @Test - fun `it should provide service Connection`() { - assertNotNull(BetaModule(mockDonateCallback).provideServiceConnection()) - } - - @Test - fun `it should provide BillingRepository`() { - assertNotNull(BetaModule(mockDonateCallback).provideBillingRepository(mockContext, mockBillingConnection)) - } } 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 660d7231..c29601e8 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 @@ -57,6 +57,11 @@ class Play01ModuleTest { assertNotNull(subject().provideAudioPreferences()) } + @Test + fun `it should provide ArchiveServiceLauncher`() { + assertNotNull(subject().provideArchiveServiceLauncher(mockContext)) + } + @Test(expected = NullPointerException::class) // SoundPool.Builder() cannot be mocked fun `it should provide soundPool`() { assertNotNull(subject().provideSoundPool()) diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/profile/ProfileModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/profile/ProfileModuleTest.kt index 782c78ce..03a25af0 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/profile/ProfileModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/profile/ProfileModuleTest.kt @@ -5,6 +5,7 @@ import android.content.Context import com.nhaarman.mockito_kotlin.whenever import nl.entreco.data.db.DscDatabase import nl.entreco.data.db.profile.ProfileMapper +import nl.entreco.data.db.profile.ProfileStatMapper import org.junit.Assert.assertNotNull import org.junit.Test import org.junit.runner.RunWith @@ -18,7 +19,8 @@ import org.mockito.junit.MockitoJUnitRunner class ProfileModuleTest { @Mock private lateinit var mockDatabase: DscDatabase - @Mock private lateinit var mockMapper: ProfileMapper + @Mock private lateinit var mockProfileMapper: ProfileMapper + @Mock private lateinit var mockProfileStatMapper: ProfileStatMapper @Mock private lateinit var mockContext: Context @Mock private lateinit var mockContentResolver: ContentResolver @@ -27,9 +29,18 @@ class ProfileModuleTest { assertNotNull(ProfileModule()) } + @Test + fun `it should provide profile mapper`() { + assertNotNull(ProfileModule().provideProfileMapper()) + } + + @Test + fun `it should provide profile stat mapper`() { + assertNotNull(ProfileModule().provideProfileStatMapper()) + } @Test fun `it should provide mapper`() { - assertNotNull(ProfileModule().provideMapper()) + assertNotNull(ProfileModule().provideProfileStatRepository(mockDatabase, mockProfileStatMapper)) } @Test @@ -45,6 +56,6 @@ class ProfileModuleTest { @Test fun `it should provide profileRepository`() { - assertNotNull(ProfileModule().provideProfileRepository(mockDatabase, mockMapper)) + assertNotNull(ProfileModule().provideProfileRepository(mockDatabase, mockProfileMapper)) } } 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 new file mode 100644 index 00000000..1f0f49f4 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/service/ServiceModuleTest.kt @@ -0,0 +1,12 @@ +package nl.entreco.dartsscorecard.di.service + +import org.junit.Assert.* +import org.junit.Test + +class ServiceModuleTest{ + + @Test + fun `can be created`() { + assertNotNull(ServiceModule()) + } +} \ 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 f789a5d0..d43ccb86 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 @@ -1,28 +1,32 @@ package nl.entreco.dartsscorecard.di.viewmodel -import android.app.Activity +import android.arch.lifecycle.Lifecycle +import android.content.Context +import android.support.v4.app.FragmentActivity import com.nhaarman.mockito_kotlin.whenever -import nl.entreco.dartsscorecard.App +import nl.entreco.data.billing.BillingServiceConnection import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.MockitoAnnotations +import org.mockito.junit.MockitoJUnitRunner /** * Created by Entreco on 17/12/2017. */ +@RunWith(MockitoJUnitRunner::class) class ViewModelModuleTest { - @Mock private lateinit var mockApp: App - @Mock private lateinit var mockActivity: Activity + @Mock private lateinit var mockLifeCycle: Lifecycle + @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockBillingConnection: BillingServiceConnection + @Mock private lateinit var mockActivity: FragmentActivity private lateinit var subject: ViewModelModule @Before fun setUp() { - MockitoAnnotations.initMocks(this) - whenever(mockApp.applicationContext).thenReturn(mockApp) subject = ViewModelModule(mockActivity) } @@ -32,4 +36,20 @@ class ViewModelModuleTest { assertEquals(mockActivity, subject.context()) } + @Test + fun `it should provide lifecycle`() { + whenever(mockActivity.lifecycle).thenReturn(mockLifeCycle) + assertNotNull(subject.lifeCycle()) + } + + @Test + fun `it should provide service Connection`() { + assertNotNull(subject.provideServiceConnection()) + } + + @Test + fun `it should provide BillingRepository`() { + assertNotNull(subject.provideBillingRepository(mockContext, mockBillingConnection)) + } + } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModuleTest.kt new file mode 100644 index 00000000..c861f7a9 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/ad/AdModuleTest.kt @@ -0,0 +1,30 @@ +package nl.entreco.dartsscorecard.di.viewmodel.ad + +import android.content.Context +import android.content.res.Resources +import com.nhaarman.mockito_kotlin.whenever +import nl.entreco.dartsscorecard.R +import org.junit.Test + +import org.junit.Assert.* +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class AdModuleTest { + + @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockResources: Resources + + @Test + fun provideInterstialAd() { + assertNotNull(AdModule().provideInterstialAd(mockContext)) + } + + @Test + fun provideInterstitialUnitId() { + whenever(mockResources.getString(R.string.setup_interstitial_unit_id)).thenReturn("interstitial id") + assertNotNull(AdModule().provideInterstitialUnitId(mockResources)) + } +} \ No newline at end of file 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 8b65be53..1c36d26e 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.Logger +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/viewmodel/db/StatDbModuleTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/db/LiveStatDbModuleTest.kt similarity index 79% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModuleTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/db/LiveStatDbModuleTest.kt index 0c571360..82ddd201 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/db/StatDbModuleTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/di/viewmodel/db/LiveStatDbModuleTest.kt @@ -1,7 +1,7 @@ package nl.entreco.dartsscorecard.di.viewmodel.db import nl.entreco.data.db.DscDatabase -import nl.entreco.data.db.stats.StatMapper +import nl.entreco.data.db.stats.LiveStatMapper import org.junit.Assert.assertNotNull import org.junit.Test import org.junit.runner.RunWith @@ -12,10 +12,10 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 26/02/2018. */ @RunWith(MockitoJUnitRunner::class) -class StatDbModuleTest { +class LiveStatDbModuleTest { @Mock private lateinit var mockDb: DscDatabase - @Mock private lateinit var mockMapper: StatMapper + @Mock private lateinit var mockMapperLive: LiveStatMapper @Test fun provideStatMapper() { @@ -24,7 +24,7 @@ class StatDbModuleTest { @Test fun provideStatRepository() { - assertNotNull(StatDbModule().provideStatRepository(mockDb, mockMapper)) + assertNotNull(StatDbModule().provideStatRepository(mockDb, mockMapperLive)) } } diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ListenersTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ListenersTest.kt index cea3bea3..d3841fd2 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ListenersTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/Play01ListenersTest.kt @@ -130,6 +130,14 @@ class Play01ListenersTest { thenPlayerListenersAreNotified() } + @Test + fun `it should notify stat listeners when game finished`() { + givenSubject() + whenRegisteringListeners() + whenGameFinished(42) + thenStatListenersAreNotifiedOfGameFinished(42) + } + private fun givenSubject() { subject = Play01Listeners() } @@ -159,6 +167,10 @@ class Play01ListenersTest { subject.onTurnSubmitted(mockNext, mockTurn, mockPlayer, givenScores) } + private fun whenGameFinished(gameId: Long) { + subject.onGameFinished(gameId) + } + private fun thenScoreListenerIsAdded() { assertEquals(1, subject.scoreListeners.size) assertEquals(mockScoreListener, subject.scoreListeners[0]) @@ -200,6 +212,10 @@ class Play01ListenersTest { private fun thenStatListenersAreNotifiedOfDartThrown() { verify(mockStatListener).onStatsChange(any(), any()) } + + private fun thenStatListenersAreNotifiedOfGameFinished(gameId: Long) { + verify(mockStatListener).onGameFinished(gameId) + } private fun thenSpecialEventListenersAreNotified() { verify(mockSpecialEventListener).onSpecialEvent(mockNext, mockTurn, mockPlayer, givenScores) 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 ea2f1611..52d044d9 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 @@ -7,9 +7,10 @@ import com.nhaarman.mockito_kotlin.argumentCaptor import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.whenever 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.Logger +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 @@ -32,19 +33,22 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 14/03/2018. */ @RunWith(MockitoJUnitRunner::class) -class Play01ViewModelMasterCallerTest{ +class Play01ViewModelMasterCallerTest { + @Mock private lateinit var mockMenu: Menu + @Mock private lateinit var mockMenuItem: MenuItem @Mock private lateinit var mockPlayGameUsecase: Play01Usecase @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase @Mock private lateinit var mockAudioPrefs: AudioPrefRepository + @Mock private lateinit var mockAdProvider: AdViewModel @Mock private lateinit var mockRevancheUsecase: RevancheUsecase @Mock private lateinit var mock01Listeners: Play01Listeners @Mock private lateinit var mockMasterCaller: MasterCaller @Mock private lateinit var mockDialogHelper: DialogHelper @Mock private lateinit var mockLogger: Logger - @Mock private lateinit var mockGame : Game - @Mock private lateinit var mockRequest : Play01Request + @Mock private lateinit var mockGame: Game + @Mock private lateinit var mockRequest: Play01Request @Mock private lateinit var mockGameLoaded: GameLoadedNotifier private val doneCaptor = argumentCaptor<(Play01Response) -> Unit>() @@ -87,16 +91,13 @@ class Play01ViewModelMasterCallerTest{ thenToggleUsecaseIsCalled() } - @Mock private lateinit var mockMenu: Menu - - @Mock private lateinit var mockMenuItem: MenuItem private fun givenSubject() { givenGameAndRequest() whenLoadingOk() } private fun givenGameAndRequest(vararg loaders: GameLoadedNotifier) { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(mockRequest, mockGameLoaded, *loaders) } @@ -110,7 +111,7 @@ class Play01ViewModelMasterCallerTest{ whenever(mockGame.wasBreakMade(any())).thenReturn(false) whenever(mockGame.next).thenReturn(Next(State.NORMAL, Team(arrayOf(player)), 0, player, score)) verify(mockPlayGameUsecase).loadGameAndStart(any(), doneCaptor.capture(), any()) - doneCaptor.firstValue.invoke(Play01Response(mockGame, ScoreSettings(501, 1,1, 0), emptyArray(), "1")) + doneCaptor.firstValue.invoke(Play01Response(mockGame, ScoreSettings(501, 1, 1, 0), emptyArray(), "1")) } private fun whenSubmittingTurn(turn: Turn) { @@ -124,7 +125,7 @@ class Play01ViewModelMasterCallerTest{ } private fun whenTogglingMasterCaller(enabled: Boolean) { - whenever(mockMenuItem.isChecked).thenReturn( enabled ) + whenever(mockMenuItem.isChecked).thenReturn(enabled) subject.toggleMasterCaller(mockMenuItem) } @@ -133,11 +134,11 @@ class Play01ViewModelMasterCallerTest{ assertEquals(expected, callerCaptor.lastValue.scored) } - private fun thenMenuIs(expected: Boolean){ + private fun thenMenuIs(expected: Boolean) { verify(mockMenuItem).isChecked = expected } - private fun thenToggleUsecaseIsCalled(){ + private fun thenToggleUsecaseIsCalled() { verify(mockToggleSoundUsecase).toggle() } } \ No newline at end of file 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 f52bfcbf..10cb9f7d 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 @@ -3,9 +3,10 @@ package nl.entreco.dartsscorecard.play import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.argumentCaptor 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.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.Game import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.mastercaller.MasterCaller @@ -31,6 +32,7 @@ class Play01ViewModelRevancheTest { @Mock private lateinit var mockPlay01Usecamse: Play01Usecase @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase @Mock private lateinit var mockAudioPrefs: AudioPrefRepository + @Mock private lateinit var mockAdProvider: AdViewModel @Mock private lateinit var mockRevancheUsecase: RevancheUsecase @Mock private lateinit var mockGameListeners: Play01Listeners @Mock private lateinit var mockMasterCaller: MasterCaller @@ -42,7 +44,6 @@ class Play01ViewModelRevancheTest { @Mock private lateinit var team1: Team @Mock private lateinit var team2: Team - private val revancheCaptor = argumentCaptor<(RevancheResponse) -> Unit>() private lateinit var subject: Play01ViewModel @@ -58,7 +59,7 @@ class Play01ViewModelRevancheTest { } private fun givenFullyLoadedSubject() { - subject = Play01ViewModel(mockPlay01Usecamse, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockLogger) + subject = Play01ViewModel(mockPlay01Usecamse, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, 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 39c0a972..a2af638f 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 @@ -1,10 +1,11 @@ package nl.entreco.dartsscorecard.play 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.dartsscorecard.play.score.TeamScoreListener -import nl.entreco.domain.Logger +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 @@ -45,6 +46,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 mockAdProvider: AdViewModel @Mock private lateinit var mockAudioPrefs: AudioPrefRepository @Mock private lateinit var mockPlayGameUsecase: Play01Usecase @Mock private lateinit var mockRevancheUsecase: RevancheUsecase @@ -67,7 +69,6 @@ class Play01ViewModelTest { private val gameId: Long = 1002 private val teamIds = "1|2" - @Before fun setUp() { MockitoAnnotations.initMocks(this) @@ -82,7 +83,7 @@ class Play01ViewModelTest { @Test fun `it should stop mastercaller on stop`() { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.stop() verify(mockMasterCaller).stop() } @@ -179,6 +180,13 @@ class Play01ViewModelTest { thenGameIsMarkedAsFinished() } + @Test + fun `it should archive stats when game finished`() { + givenFullyLoadedMockGame() + whenNextStateIs(State.MATCH) + thenStatListenersAreNotifiedOfGameFinished() + } + @Test fun `it should NOT mark game finished when state != MATCH`() { givenGameLoadedOk() @@ -212,12 +220,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, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(req, mockCreatedNotifier, *loaders) } private fun givenFullyLoadedMockGame() { - subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockLogger) + subject = Play01ViewModel(mockPlayGameUsecase, mockRevancheUsecase, mock01Listeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockAdProvider, mockLogger) subject.load(mockRequest, mockCreatedNotifier) verify(mockPlayGameUsecase).loadGameAndStart(any(), doneCaptor.capture(), any()) doneCaptor.firstValue.invoke(Play01Response(mockGame, mockScoreSettings, givenTeams, teamIds)) @@ -339,4 +347,8 @@ class Play01ViewModelTest { private fun thenStatListenersAreNotified() { verify(mock01Listeners).onStatsUpdated(1, 2) } + + private fun thenStatListenersAreNotifiedOfGameFinished() { + verify(mock01Listeners).onGameFinished(gameId) + } } 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 164649cd..35090570 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 @@ -1,9 +1,10 @@ package nl.entreco.dartsscorecard.play 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.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.Game import nl.entreco.domain.play.mastercaller.MasterCaller import nl.entreco.domain.play.mastercaller.ToggleSoundUsecase @@ -30,6 +31,7 @@ class Play01ViewModelUndoTest { @Mock private lateinit var mockGame: Game @Mock private lateinit var mockRequest: Play01Request @Mock private lateinit var mockResponse: Play01Response + @Mock private lateinit var mockAdProvider: AdViewModel @Mock private lateinit var mockToggleSoundUsecase: ToggleSoundUsecase @Mock private lateinit var mockAudioPrefs: AudioPrefRepository @Mock private lateinit var mockLoad: GameLoadedNotifier @@ -74,7 +76,7 @@ class Play01ViewModelUndoTest { whenever(mockGame.id).thenReturn(5) whenever(mockResponse.game).thenReturn(mockGame) - subject = Play01ViewModel(mockPlay01Usecase, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, mockAudioPrefs, mockLogger) + subject = Play01ViewModel(mockPlay01Usecase, mockRevancheUsecase, mockGameListeners, mockMasterCaller, mockDialogHelper, mockToggleSoundUsecase, 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 e682b8af..e3cf4086 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.Logger +import nl.entreco.domain.common.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/stats/MatchStatAdapterTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapterTest.kt similarity index 86% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatAdapterTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapterTest.kt index 08a3a79d..b4ec3b0e 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatAdapterTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatAdapterTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.view.View import android.view.ViewGroup @@ -16,12 +16,12 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 24/03/2018. */ @RunWith(MockitoJUnitRunner::class) -class MatchStatAdapterTest { +class LiveStatAdapterTest { @Mock private lateinit var mockView: View @Mock private lateinit var mockContainer: ViewGroup @Mock private lateinit var mockNavigator: Play01Navigator - private lateinit var subject: MatchStatAdapter + private lateinit var subject: LiveStatAdapter @Before fun setUp() { @@ -61,11 +61,11 @@ class MatchStatAdapterTest { } private fun givenSubject() { - subject = MatchStatAdapter(mockNavigator) + subject = LiveStatAdapter(mockNavigator) } private fun givenItems(vararg items: Int) { - subject.populate(items.map { Pair(it, TeamStatModel(mock())) }.toMap()) + subject.populate(items.map { Pair(it, TeamLiveStatModel(mock())) }.toMap()) } private fun whenInstantiating(position: Int) { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatBindingTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatBindingTest.kt new file mode 100644 index 00000000..b0b9d440 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatBindingTest.kt @@ -0,0 +1,70 @@ +package nl.entreco.dartsscorecard.play.live + +import android.content.Context +import android.content.res.Resources +import android.support.v4.view.ViewPager +import android.view.Gravity +import android.view.View +import android.widget.RelativeLayout +import android.widget.TextView +import com.nhaarman.mockito_kotlin.any +import com.nhaarman.mockito_kotlin.verify +import com.nhaarman.mockito_kotlin.whenever +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +/** + * Created by entreco on 24/03/2018. + */ +@RunWith(MockitoJUnitRunner::class) +class LiveStatBindingTest { + + @Mock private lateinit var mockTextView: TextView + @Mock private lateinit var mockLayoutParams: RelativeLayout.LayoutParams + @Mock private lateinit var mockView: View + @Mock private lateinit var mockResources: Resources + @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockPager: ViewPager + @Mock private lateinit var mockAdapter: LiveStatAdapter + + @Test + fun setupViewPager() { + whenever(mockContext.resources).thenReturn(mockResources) + whenever(mockPager.layoutParams).thenReturn(mockLayoutParams) + whenever(mockPager.context).thenReturn(mockContext) + LiveStatBinding.setupViewPager(mockPager, emptyMap(), mockAdapter) + verify(mockPager).setPageTransformer(any(), any()) + } + + @Test + fun `it should set Visibility to GONE if hide(true)`() { + LiveStatBinding.hideIfOnlyOneTeam(mockView, true) + verify(mockView).visibility = View.GONE + } + + @Test + fun `it should set Visibility to VISIBLE if hide(false)`() { + LiveStatBinding.hideIfOnlyOneTeam(mockView, false) + verify(mockView).visibility = View.VISIBLE + } + + @Test + fun `it should center text if oneTeam(true)`() { + LiveStatBinding.centerIfOnlyOneTeam(mockTextView, true) + verify(mockTextView).gravity = Gravity.CENTER + } + + @Test + fun `it should center | end if oneTeam(false)`() { + LiveStatBinding.centerIfOnlyOneTeam(mockTextView, false) + verify(mockTextView).gravity = Gravity.END + } + + @Test + fun `it should scroll to currentTeam`() { + LiveStatBinding.scrollToCurrentTeam(mockPager, 0) + verify(mockPager).setCurrentItem( 0, true) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimatorHandlerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimatorHandlerTest.kt similarity index 72% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimatorHandlerTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimatorHandlerTest.kt index b8228f67..6da1a99f 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatPageAnimatorHandlerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatPageAnimatorHandlerTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.view.View import android.view.ViewPropertyAnimator @@ -15,12 +15,12 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 27/03/2018. */ @RunWith(MockitoJUnitRunner::class) -class MatchStatPageAnimatorHandlerTest { +class LiveStatPageAnimatorHandlerTest { @Mock private lateinit var mockView: View @Mock private lateinit var mockAnimator: ViewPropertyAnimator - private lateinit var subject: MatchStatPageAnimator.MatchStatPageAnimatorHandler + private lateinit var subject: LiveStatPageAnimator.MatchStatPageAnimatorHandler @Test fun transform() { @@ -30,7 +30,7 @@ class MatchStatPageAnimatorHandlerTest { } private fun givenSubject() { - subject = MatchStatPageAnimator.MatchStatPageAnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, 100F) + subject = LiveStatPageAnimator.MatchStatPageAnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView,100F) } private fun whenTransforming() { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimatorTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimatorTest.kt similarity index 77% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimatorTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimatorTest.kt index c5ccea06..6d161276 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatSlideAnimatorTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatSlideAnimatorTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import android.view.View import android.view.ViewPropertyAnimator @@ -15,12 +15,12 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 25/03/2018. */ @RunWith(MockitoJUnitRunner::class) -class MatchStatSlideAnimatorTest { +class LiveStatSlideAnimatorTest { @Mock private lateinit var mockView: View @Mock private lateinit var mockAnimator: ViewPropertyAnimator - private lateinit var subject: MatchStatSlideAnimator.MatchStatSlideAnimatorHandler + private lateinit var subject: LiveStatSlideAnimator.MatchStatSlideAnimatorHandler @Test fun onSlide() { @@ -30,7 +30,7 @@ class MatchStatSlideAnimatorTest { } private fun givenSubject() { - subject = MatchStatSlideAnimator.MatchStatSlideAnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView) + subject = LiveStatSlideAnimator.MatchStatSlideAnimatorHandler(mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView, mockView) } private fun whenSliding() { diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt similarity index 77% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModelTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt index 3e8ded67..2c0c7057 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/LiveStatViewModelTest.kt @@ -1,10 +1,11 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import com.nhaarman.mockito_kotlin.* -import nl.entreco.domain.Logger +import nl.entreco.dartsscorecard.archive.ArchiveServiceLauncher +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.model.Game +import nl.entreco.domain.model.LiveStat import nl.entreco.domain.model.Score -import nl.entreco.domain.model.Stat import nl.entreco.domain.model.players.Player import nl.entreco.domain.model.players.Team import nl.entreco.domain.play.start.Play01Response @@ -20,24 +21,25 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 14/01/2018. */ @RunWith(MockitoJUnitRunner::class) -class MatchStatViewModelTest { +class LiveStatViewModelTest { - @Mock private lateinit var mockAdapter: MatchStatAdapter + @Mock private lateinit var mockAdapter: LiveStatAdapter @Mock private lateinit var mockFetchGameStatsUsecase: FetchGameStatsUsecase - @Mock private lateinit var mockFetchGameStatUsecase: FetchGameStatUsecase + @Mock private lateinit var mockFetchLiveStatUsecase: FetchLiveStatUsecase + @Mock private lateinit var mockArchiveServiceLauncher: ArchiveServiceLauncher @Mock private lateinit var mockLogger: Logger @Mock private lateinit var mockGame: Game @Mock private lateinit var mockResponse: Play01Response - private lateinit var subject: MatchStatViewModel + private lateinit var subject: LiveStatViewModel private var givenGameId: Long = 1003 private var givenTeamIds: String = "1|2" private var givenTeams: Array = emptyArray() private var givenScores: Array = emptyArray() - private var givenExistingStats: Map = emptyMap() + private var givenExistingStats: Map = emptyMap() - private var givenUpdatedStat: Stat = Stat(1, 2, 3, 4, 5, 6, 7, 8, 9, emptyList(), emptyList()) + private var givenUpdatedLiveStat: LiveStat = LiveStat(1, 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, emptyList(), emptyList()) private val statsDoneCaptor = argumentCaptor<(FetchGameStatsResponse) -> Unit>() - private val statDoneCaptor = argumentCaptor<(FetchGameStatResponse) -> Unit>() + private val statDoneCaptor = argumentCaptor<(FetchLiveStatResponse) -> Unit>() private val failCaptor = argumentCaptor<(Throwable) -> Unit>() @@ -117,11 +119,19 @@ class MatchStatViewModelTest { thenErrorIsLogged() } + @Test + fun `it should archive stats on game finished`() { + givenTeams("barney", "army") + givenSubjectLoaded() + whenGameFinished() + thenStatsAreArchived() + } + private fun givenSubjectLoaded() { whenever(mockGame.id).thenReturn(givenGameId) whenever(mockResponse.game).thenReturn(mockGame) whenever(mockResponse.teamIds).thenReturn(givenTeamIds) - subject = MatchStatViewModel(mockAdapter, mockFetchGameStatsUsecase, mockFetchGameStatUsecase, mockLogger) + subject = LiveStatViewModel(mockAdapter, mockFetchGameStatsUsecase, mockFetchLiveStatUsecase, mockArchiveServiceLauncher, mockLogger) subject.onLoaded(givenTeams, givenScores, mockResponse, null) } @@ -133,9 +143,9 @@ class MatchStatViewModelTest { givenTeams = teams.toTypedArray() } - private fun givenExistingStats(vararg stats: Stat) { - val existing = HashMap() - stats.forEachIndexed { index, stat -> + private fun givenExistingStats(vararg liveStats: LiveStat) { + val existing = HashMap() + liveStats.forEachIndexed { index, stat -> val player = givenTeams[index % givenTeams.size].players[0] existing[player.id] = stat } @@ -143,7 +153,7 @@ class MatchStatViewModelTest { } private fun givenUpdatedStat(playerId: Long, value: Int) { - givenUpdatedStat = givenUpdatedStat.copy(playerId = playerId, n180 = value) + givenUpdatedLiveStat = givenUpdatedLiveStat.copy(playerId = playerId, n180 = value) } private fun whenStatsFetchSucceeds() { @@ -165,21 +175,25 @@ class MatchStatViewModelTest { private fun whenStatsChangeSucceeds() { val turnId: Long = 1 val metaId: Long = 20000 - val req = FetchGameStatRequest(turnId, metaId) - val response = FetchGameStatResponse(givenUpdatedStat) + val req = FetchLiveStatRequest(turnId, metaId) + val response = FetchLiveStatResponse(givenUpdatedLiveStat) subject.onStatsChange(turnId, metaId) - verify(mockFetchGameStatUsecase).exec(eq(req), statDoneCaptor.capture(), failCaptor.capture()) + verify(mockFetchLiveStatUsecase).exec(eq(req), statDoneCaptor.capture(), failCaptor.capture()) statDoneCaptor.lastValue.invoke(response) } private fun whenStatsChangeFails(err: Throwable) { subject.onStatsChange(8, 9) - verify(mockFetchGameStatUsecase).exec(any(), any(), failCaptor.capture()) + verify(mockFetchLiveStatUsecase).exec(any(), any(), failCaptor.capture()) failCaptor.lastValue.invoke(err) } + private fun whenGameFinished() { + subject.onGameFinished(12) + } + private fun thenStatIsFetched() { - verify(mockFetchGameStatUsecase).exec(any(), any(), any()) + verify(mockFetchLiveStatUsecase).exec(any(), any(), any()) } private fun thenStatsAreFetched() { @@ -216,4 +230,8 @@ class MatchStatViewModelTest { private fun thenTeamStat180IsEmpty(index: Int) { assertEquals("--", subject.teamStats[index]?.n180?.get()) } + + private fun thenStatsAreArchived() { + verify(mockArchiveServiceLauncher).launch(any()) + } } diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModelTest.kt new file mode 100644 index 00000000..d4f7eab8 --- /dev/null +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamLiveStatModelTest.kt @@ -0,0 +1,106 @@ +package nl.entreco.dartsscorecard.play.live + +import com.nhaarman.mockito_kotlin.whenever +import nl.entreco.domain.model.LiveStat +import nl.entreco.domain.model.players.Team +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +/** + * Created by entreco on 13/01/2018. + */ +@RunWith(MockitoJUnitRunner::class) +class TeamLiveStatModelTest { + + @Mock + private lateinit var mockTeam: Team + private lateinit var subject: TeamLiveStatModel + + @Test + fun `empty should be double dashes`() { + assertEquals("--", TeamLiveStatModel.empty) + } + + @Test + fun `it should update stats at the start`() { + subject = TeamLiveStatModel(mockTeam, mutableListOf(LiveStat(1, 2, 3, 4, 5, 6, 2, 3, 15, 5, 9, listOf(10), listOf(11)))) + thenStatsAre("2.00", "4", "5", "6", "2", "3", "11", "33.33%", "9") + } + + @Test + fun `it should have name as specified`() { + givenSubject("Pjotr") + thenNameIs("Pjotr") + } + + @Test + fun `it should have empty stats initially`() { + givenSubject("Pjotr") + thenStatsAreEmpty() + } + + @Test + fun `it should update stats (normal case)`() { + givenSubject("Team name") + whenUpdating(LiveStat(1, 2, 3, 4, 5, 6, 2, 3, 15, 5, 9, listOf(10), listOf(11))) + thenStatsAre("2.00", "4", "5", "6", "2", "3", "11", "33.33%", "9") + } + + @Test + fun `it should update stats (no average)`() { + givenSubject("Team name") + whenUpdating(LiveStat(1, 0, 0, 4, 5, 6, 2, 3, 15, 5, 9, listOf(10), listOf(11))) + thenStatsAre("--", "4", "5", "6", "2", "3", "11", "33.33%", "9") + } + + @Test + fun `it should update stats (no percentage)`() { + givenSubject("Team name") + whenUpdating(LiveStat(1, 2, 3, 4, 5, 6, 2, 3, 0, 0, 9, listOf(10), listOf(11))) + thenStatsAre("2.00", "4", "5", "6", "2", "3", "11", "--", "9") + } + + @Test + fun `it should update stats (no high checkout)`() { + givenSubject("Team name") + whenUpdating(LiveStat(1, 2, 3, 4, 5, 6, 2, 3, 0, 0, 9, emptyList(), emptyList())) + thenStatsAre("2.00", "4", "5", "6", "2", "3", "--", "--", "9") + } + + private fun givenSubject(name: String) { + whenever(mockTeam.toString()).thenReturn(name) + subject = TeamLiveStatModel(mockTeam) + } + + private fun whenUpdating(liveStat: LiveStat) { + subject.append(listOf(liveStat)) + } + + private fun thenStatsAreEmpty() { + assertEquals(TeamLiveStatModel.empty, subject.avg.get().toString()) + assertEquals(TeamLiveStatModel.empty, subject.n180.get().toString()) + assertEquals(TeamLiveStatModel.empty, subject.n140.get().toString()) + assertEquals(TeamLiveStatModel.empty, subject.n100.get().toString()) + assertEquals(TeamLiveStatModel.empty, subject.n60.get().toString()) + assertEquals(TeamLiveStatModel.empty, subject.n20.get().toString()) + } + + private fun thenNameIs(expectedName: String) { + assertEquals(expectedName, subject.name.get()) + } + + private fun thenStatsAre(avg: String, n180: String, n140: String, n100: String, n60: String, n20: String, highestCheckout: String, checkoutPercentage: String, numberOfBreaks: String) { + assertEquals(avg, subject.avg.get()) + assertEquals(n180, subject.n180.get()) + assertEquals(n140, subject.n140.get()) + assertEquals(n100, subject.n100.get()) + assertEquals(n60, subject.n60.get()) + assertEquals(n20, subject.n20.get()) + assertEquals(highestCheckout, subject.hCo.get()) + assertEquals(checkoutPercentage, subject.co.get()) + assertEquals(numberOfBreaks, subject.breaks.get()) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamScoreListenerTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamScoreListenerTest.kt similarity index 96% rename from android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamScoreListenerTest.kt rename to android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamScoreListenerTest.kt index 864d8912..fe230eaf 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamScoreListenerTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/live/TeamScoreListenerTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.dartsscorecard.play.stats +package nl.entreco.dartsscorecard.play.live import nl.entreco.dartsscorecard.play.score.TeamScoreListener import nl.entreco.domain.model.players.Player 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 6088c53e..3aa1a7a7 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,7 @@ package nl.entreco.dartsscorecard.play.score import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.verifyZeroInteractions -import nl.entreco.domain.Logger +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 diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatBindingTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatBindingTest.kt deleted file mode 100644 index a8cb62cd..00000000 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/MatchStatBindingTest.kt +++ /dev/null @@ -1,33 +0,0 @@ -package nl.entreco.dartsscorecard.play.stats - -import android.content.Context -import android.content.res.Resources -import android.support.v4.view.ViewPager -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.verify -import com.nhaarman.mockito_kotlin.whenever -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner - -/** - * Created by entreco on 24/03/2018. - */ -@RunWith(MockitoJUnitRunner::class) -class MatchStatBindingTest { - - @Mock private lateinit var mockResources: Resources - @Mock private lateinit var mockContext: Context - @Mock private lateinit var mockPager: ViewPager - @Mock private lateinit var mockAdapter: MatchStatAdapter - - @Test - fun setupViewPager() { - whenever(mockContext.resources).thenReturn(mockResources) - whenever(mockPager.context).thenReturn(mockContext) - MatchStatBinding.setupViewPager(mockPager, emptyMap(), mockAdapter) - verify(mockPager).setPageTransformer(any(), any()) - } - -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamStatModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamStatModelTest.kt deleted file mode 100644 index dc87a4fd..00000000 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/play/stats/TeamStatModelTest.kt +++ /dev/null @@ -1,104 +0,0 @@ -package nl.entreco.dartsscorecard.play.stats - -import com.nhaarman.mockito_kotlin.whenever -import nl.entreco.domain.model.Stat -import nl.entreco.domain.model.players.Team -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner - -/** - * Created by entreco on 13/01/2018. - */ -@RunWith(MockitoJUnitRunner::class) -class TeamStatModelTest { - - @Mock - private lateinit var mockTeam: Team - private lateinit var subject: TeamStatModel - - @Test - fun `empty should be double dashes`() { - assertEquals("--", TeamStatModel.empty) - } - - @Test - fun `it should update stats at the start`() { - subject = TeamStatModel(mockTeam, mutableListOf(Stat(1, 2, 3, 4, 5, 6, 15, 5, 9, listOf(10), listOf(11)))) - thenStatsAre("2.00", "4", "5", "6", "11", "33.33%", "9") - } - - @Test - fun `it should have name as specified`() { - givenSubject("Pjotr") - thenNameIs("Pjotr") - } - - @Test - fun `it should have empty stats initially`() { - givenSubject("Pjotr") - thenStatsAreEmpty() - } - - @Test - fun `it should update stats (normal case)`() { - givenSubject("Team name") - whenUpdating(Stat(1, 2, 3, 4, 5, 6, 15, 5, 9, listOf(10), listOf(11))) - thenStatsAre("2.00", "4", "5", "6", "11", "33.33%", "9") - } - - @Test - fun `it should update stats (no average)`() { - givenSubject("Team name") - whenUpdating(Stat(1, 0, 0, 4, 5, 6, 15, 5, 9, listOf(10), listOf(11))) - thenStatsAre("--", "4", "5", "6", "11", "33.33%", "9") - } - - @Test - fun `it should update stats (no percentage)`() { - givenSubject("Team name") - whenUpdating(Stat(1, 2, 3, 4, 5, 6, 0, 0, 9, listOf(10), listOf(11))) - thenStatsAre("2.00", "4", "5", "6", "11", "--", "9") - } - - @Test - fun `it should update stats (no high checkout)`() { - givenSubject("Team name") - whenUpdating(Stat(1, 2, 3, 4, 5, 6, 0, 0, 9, emptyList(), emptyList())) - thenStatsAre("2.00", "4", "5", "6", "--", "--", "9") - } - - private fun givenSubject(name: String) { - whenever(mockTeam.toString()).thenReturn(name) - subject = TeamStatModel(mockTeam) - } - - private fun whenUpdating(stat: Stat) { - subject.append(listOf(stat)) - } - - private fun thenStatsAreEmpty() { - assertEquals(TeamStatModel.empty, subject.avg.get().toString()) - assertEquals(TeamStatModel.empty, subject.n180.get().toString()) - assertEquals(TeamStatModel.empty, subject.n140.get().toString()) - assertEquals(TeamStatModel.empty, subject.n100.get().toString()) - } - - private fun thenNameIs(expectedName: String) { - assertEquals(expectedName, subject.name.get()) - } - - private fun thenStatsAre(avg: String, n180: String, n140: String, n100: String, highestCheckout: String, checkoutPercentage: String, numberOfBreaks: String) { - assertEquals(avg, subject.avg.get()) - assertEquals(n180, subject.n180.get()) - assertEquals(n140, subject.n140.get()) - assertEquals(n100, subject.n100.get()) - assertEquals(highestCheckout, subject.hCo.get()) - assertEquals(checkoutPercentage, subject.co.get()) - assertEquals(numberOfBreaks, subject.breaks.get()) - - - } -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModelTest.kt index e84fa1e3..82d0f831 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/edit/EditPlayerNameViewModelTest.kt @@ -2,9 +2,14 @@ package nl.entreco.dartsscorecard.profile.edit import android.content.Context import android.os.Handler -import com.nhaarman.mockito_kotlin.argumentCaptor -import com.nhaarman.mockito_kotlin.verify +import android.text.Editable +import android.text.SpannableStringBuilder +import android.view.inputmethod.EditorInfo +import android.widget.AdapterView +import android.widget.TextView +import com.nhaarman.mockito_kotlin.* import nl.entreco.dartsscorecard.R +import nl.entreco.dartsscorecard.setup.edit.EditPlayerNavigator import nl.entreco.domain.Analytics import nl.entreco.domain.model.players.Player import nl.entreco.domain.setup.players.FetchExistingPlayersResponse @@ -21,6 +26,10 @@ import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) class EditPlayerNameViewModelTest { + @Mock private lateinit var mockView: TextView + @Mock private lateinit var mockNavigator: EditPlayerNameNavigator + @Mock private lateinit var mockAdapter: AdapterView<*> + @Mock private lateinit var mockEditable: Editable @Mock private lateinit var mockContext: Context @Mock private lateinit var mockHandler: Handler @Mock private lateinit var mockAnalytics: Analytics @@ -38,6 +47,18 @@ class EditPlayerNameViewModelTest { thenExistingPlayersAreFetched() } + @Test + fun `it should have empty name initially`() { + givenSubject() + thenNameIs("") + } + + @Test + fun `it should have empty favdouble initially`() { + givenSubject() + thenFavouriteDoubleIs("") + } + @Test fun `it should add all players when fetching existing players succeeds (empty)`() { givenExistingPlayers() @@ -77,6 +98,94 @@ class EditPlayerNameViewModelTest { thenInitialNameIs("remco") } + @Test + fun `it should set to Lowercase onNameChanged`() { + givenSubject() + whenNameChanged("ReMcO") + thenNameIs("remco") + } + + @Test + fun `it should set favouriteDouble onFavouriteDoubleSelected`() { + givenSubject() + whenFavouriteDoubleSelected(12) + thenFavouriteDoubleIndexIs(12) + } + + @Test + fun `it should trackAnalytics onFavouriteDoubleSelected`() { + givenSubject() + whenFavouriteDoubleSelected(12) + thenAnalyticsIsNotified(12) + } + + @Test + fun `it should set name onActionDone (IME_ACTION_DONE)`() { + givenSubject() + whenOnActionDone("REMCO", EditorInfo.IME_ACTION_DONE) + thenNameIs("remco") + } + + @Test + fun `it should NOT set name onActionDone (IME_ACTION_DONE)`() { + givenSubject() + whenOnActionDone("Pietje", 0) + thenNameIs("") + } + + @Test + fun `it should set typing(false) onDone when valid name entered`() { + givenSubject() + givenExistingPlayers("p1", "p2") + whenNameChanged("NEW PLAYER") + whenDone() + thenIsTypingIs(false) + } + + @Test + fun `it should notifyNavigator onDone when valid name entered`() { + givenSubject() + givenExistingPlayers("p1", "p2") + whenNameChanged("NEW PLAYER") + whenDone() + thenNavigatorIsNotified("new player") + } + + @Test + fun `it should set typing(true) onDone when name is empty`() { + givenSubject() + whenDone() + thenIsTypingIs(true) + } + + @Test + fun `it should set errorMessage onDone when name is empty`() { + givenSubject() + whenDone() + thenErrorMessageIs(R.string.err_player_name_is_empty) + } + @Test + fun `it should set typing(true) onDone when name is already taken`() { + givenExistingPlayers("p1") + givenSubject() + whenSettingPlayerName("player 1") + whenFetchingExistingPlayersSucceeds() + whenNameChanged("p1") + whenDone() + thenIsTypingIs(true) + } + + @Test + fun `it should set errorMessage onDone when name is already taken`() { + givenExistingPlayers("p1") + givenSubject() + whenSettingPlayerName("player 1") + whenFetchingExistingPlayersSucceeds() + whenNameChanged("p1") + whenDone() + thenErrorMessageIs(R.string.err_player_already_exists) + } + private fun givenExistingPlayers(vararg players: String) { givenExistingPlayers = players.map { Player(it) } } @@ -95,9 +204,30 @@ class EditPlayerNameViewModelTest { } private fun whenSettingPlayerName(initialName: String) { + val runnableCaptor = argumentCaptor() subject.playerName(initialName, "", mockContext) + verify(mockHandler).postDelayed(runnableCaptor.capture(), eq(500)) + runnableCaptor.lastValue.run() + } + + private fun whenNameChanged(name: String) { + whenever(mockEditable.toString()).thenReturn(name) + subject.onNameChanged(mockEditable) } + private fun whenFavouriteDoubleSelected(index: Int) { + whenever(mockAdapter.getItemAtPosition(any())).thenReturn("$index") + subject.onFavouriteDoubleSelected(mockAdapter, index) + } + + private fun whenOnActionDone(name: String, action: Int) { + whenever(mockView.text).thenReturn(name) + subject.onActionDone(mockView, action, mockNavigator) + } + + private fun whenDone(){ + subject.onDone(mockNavigator) + } private fun thenExistingPlayersAreFetched() {} @@ -112,4 +242,29 @@ class EditPlayerNameViewModelTest { private fun thenInitialNameIs(expected: String) { assertEquals(expected, subject.initialProfileName) } + + private fun thenNameIs(expected: String) { + assertEquals(expected, subject.name.get()) + } + + private fun thenFavouriteDoubleIs(expected: String) { + assertEquals(expected, subject.favDouble.get()) + } + + private fun thenFavouriteDoubleIndexIs(expected: Int) { + assertEquals(expected, subject.favDoubleIndex.get()) + assertEquals("$expected", subject.favDouble.get()) + } + + private fun thenAnalyticsIsNotified(expected: Int){ + verify(mockAnalytics).setFavDoubleProperty("$expected") + } + + private fun thenIsTypingIs(expected: Boolean) { + assertEquals(expected, subject.isTyping.get()) + } + + private fun thenNavigatorIsNotified(expected: String){ + verify(mockNavigator).onDoneEditing(eq(expected), any()) + } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivityTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivityTest.kt index f3e0b08b..f9c896ad 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivityTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivityTest.kt @@ -1,7 +1,5 @@ package nl.entreco.dartsscorecard.profile.select -import android.app.Activity.RESULT_OK -import android.app.onActivityResult import android.content.Context import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.spy @@ -25,9 +23,4 @@ class SelectProfileActivityTest { SelectProfileActivity.launch(mockContext) verify(mockContext).startActivity(any()) } - - @Test - fun `should handle activity result`() { - subject.onActivityResult(0, RESULT_OK, null) - } } diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapterTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapterTest.kt deleted file mode 100644 index 305bfecd..00000000 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/select/SelectProfileAdapterTest.kt +++ /dev/null @@ -1,64 +0,0 @@ -package nl.entreco.dartsscorecard.profile.select - -import nl.entreco.domain.profile.Profile -import org.junit.Assert.assertTrue -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner - -/** - * Created by entreco on 12/03/2018. - */ -@RunWith(MockitoJUnitRunner::class) -class SelectProfileAdapterTest { - - @Mock private lateinit var mockNavigator: SelectProfileNavigator - private lateinit var subject: SelectProfileAdapter - - @Test - fun `it should set items (0)`() { - givenSubject() - whenSettingItems() - thenItemCountIs(0) - } - - @Test - fun `it should set items (1)`() { - givenSubject() - whenSettingItems("one") - thenItemCountIs(1) - } - - @Test - fun `it should set items (2)`() { - givenSubject() - whenSettingItems("one", "two") - thenItemCountIs(2) - } - - @Test - fun `it should remote item`() { - givenSubject() - whenSettingItems("one", "two") - whenRemovingItem(0) - thenItemCountIs(1) - } - - private fun givenSubject() { - subject = SelectProfileAdapter(mockNavigator) - } - - private fun whenSettingItems(vararg items: String) { - subject.setItems(items.map { Profile(it, image = "image") }) - } - - private fun whenRemovingItem(position: Int) { - subject.removeAt(position) - } - - private fun thenItemCountIs(expected: Int) { - assertTrue(subject.itemCount == expected) - } - -} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModelTest.kt index e72ff152..85a62ee8 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModelTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/profile/view/ProfileViewModelTest.kt @@ -1,9 +1,19 @@ package nl.entreco.dartsscorecard.profile.view +import android.content.Intent +import android.net.Uri +import com.nhaarman.mockito_kotlin.* +import nl.entreco.dartsscorecard.R +import nl.entreco.data.db.DscDatabase.Companion.name +import nl.entreco.domain.model.players.PlayerPrefs +import nl.entreco.domain.profile.Profile +import nl.entreco.domain.profile.fetch.FetchProfileRequest +import nl.entreco.domain.profile.fetch.FetchProfileResponse +import nl.entreco.domain.profile.fetch.FetchProfileStatsUsecase import nl.entreco.domain.profile.fetch.FetchProfileUsecase +import nl.entreco.domain.profile.update.UpdateProfileResponse import nl.entreco.domain.profile.update.UpdateProfileUsecase -import org.junit.Assert.assertEquals -import org.junit.Assert.assertNull +import org.junit.Assert.* import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -16,8 +26,11 @@ import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) class ProfileViewModelTest{ + @Mock private lateinit var mockUri: Uri + @Mock private lateinit var mockIntent: Intent @Mock private lateinit var mockFetchProfile: FetchProfileUsecase @Mock private lateinit var mockUpdateProfile: UpdateProfileUsecase + @Mock private lateinit var mockFetchProfileStat: FetchProfileStatsUsecase private lateinit var subject: ProfileViewModel @Before @@ -31,7 +44,227 @@ class ProfileViewModelTest{ assertEquals(0, subject.errorMsg.get()) } + @Test + fun `it should fetch profiles when ids provided`() { + givenSubject() + whenFetchingProfiles(1,2) + thenProfilesAreFetched() + } + + @Test + fun `it should fetch profile stats when ids provided`() { + givenSubject() + whenFetchingProfiles(1,2) + thenProfilesStatsAreFetched() + } + + @Test + fun `it should NOT fetch profiles when NO ids provided`() { + givenSubject() + whenFetchingProfiles() + thenProfilesAreNotFetched() + } + + @Test + fun `it should store Profile(0) when profiles are fetched`() { + givenSubject() + whenFetchingProfilesSucceeds(1,2) + thenProfileIdIs(1) + } + + @Test + fun `it should fetch Profiles once when profiles already loaded`() { + givenSubject() + whenFetchingProfilesSucceeds(1,2) + whenFetchingProfiles(4,5) + thenProfilesAreNotFetched() + } + + @Test + fun `it should NOT set error msg when profiles are fetched`() { + givenSubject() + whenFetchingProfilesSucceeds(1,2) + thenErrorMessageIs(0) + } + + @Test + fun `it should set error msg when profiles cannot be fetched`() { + givenSubject() + whenFetchingProfilesFails() + thenErrorMessageIs(R.string.err_unable_to_fetch_players) + } + + @Test + fun `it should update name when name updated`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingName("Remco") + thenProfileNameIs("Remco") + } + + @Test + fun `it should update double when double updated`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingDouble(20) + thenProfileDoubleIs(20) + } + + @Test + fun `it should update image when image updated`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingImage("some image") + thenProfileImageIs("some image") + } + + @Test + fun `it should update profile when name or double updating profile succeeds`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingProfileSucceeds("Remco", 25) + thenProfileNameIs("Remco") + thenProfileDoubleIs(25) + } + + @Test + fun `it should update profile when name or double even when updating profile fails`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingProfileFails("Remco", 25) + thenProfileNameIs("Remco") + thenProfileDoubleIs(25) + } + + @Test + fun `it should show errorMessage when updating profile fails`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingProfileFails("Remco", 25) + thenErrorMessageIs(R.string.err_unable_to_fetch_players) + } + + @Test + fun `it should update image when updating Image succeeds`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingImageSucceeds("some image") + thenProfileImageIs("some image") + } + + @Test + fun `it should update image even when updating Image fails`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingImageFails("some image") + thenProfileImageIs("some image") + } + + @Test + fun `it should show errorMessage when updating Image fails`() { + givenSubject() + whenFetchingProfilesSucceeds(1) + whenUpdatingImageFails("some image") + thenErrorMessageIs(R.string.err_unable_to_fetch_players) + } + private fun givenSubject() { - subject = ProfileViewModel(mockFetchProfile, mockUpdateProfile) + subject = ProfileViewModel(mockFetchProfile, mockUpdateProfile, mockFetchProfileStat) + } + + private fun whenFetchingProfiles(vararg ids: Long) { + subject.fetchProfile(ids.map { it }.toLongArray()) + } + + private fun whenUpdatingName(name: String) { + subject.showNameForProfile(name, 0) + } + + private fun whenUpdatingDouble(double: Int) { + subject.showNameForProfile("some name", double) + } + private fun whenUpdatingImage(image: String) { + whenever(mockUri.toString()).thenReturn(image) + whenever(mockIntent.data).thenReturn(mockUri) + subject.showImageForProfile(mockIntent, 200F) + } + + private fun whenFetchingProfilesSucceeds(vararg ids: Long) { + val doneCaptor = argumentCaptor<(FetchProfileResponse)->Unit>() + subject.fetchProfile(ids) + verify(mockFetchProfile).exec(any(), doneCaptor.capture(), any()) + doneCaptor.lastValue.invoke(FetchProfileResponse(ids.map { Profile("$it", it, "image$it", PlayerPrefs(0)) })) + } + + private fun whenFetchingProfilesFails() { + val ids = listOf(1,2,3).toLongArray() + val failCaptor = argumentCaptor<(Throwable)->Unit>() + subject.fetchProfile(ids) + verify(mockFetchProfile).exec(any(), any(), failCaptor.capture()) + failCaptor.lastValue.invoke(RuntimeException("Unable to fetch player profiles")) + } + + private fun whenUpdatingProfileSucceeds(name: String, double: Int) { + val doneCaptor = argumentCaptor<(UpdateProfileResponse)->Unit>() + subject.showNameForProfile(name, double) + verify(mockUpdateProfile).exec(any(), doneCaptor.capture(), any()) + doneCaptor.lastValue.invoke(UpdateProfileResponse(Profile(name, 2, "", PlayerPrefs(double)))) + } + + private fun whenUpdatingProfileFails(name: String, double: Int) { + val failCaptor = argumentCaptor<(Throwable)->Unit>() + subject.showNameForProfile(name, double) + verify(mockUpdateProfile).exec(any(), any(), failCaptor.capture()) + failCaptor.lastValue.invoke(RuntimeException("unable to update")) + } + + private fun whenUpdatingImageSucceeds(image: String) { + val doneCaptor = argumentCaptor<(UpdateProfileResponse)->Unit>() + whenever(mockUri.toString()).thenReturn(image) + whenever(mockIntent.data).thenReturn(mockUri) + subject.showImageForProfile(mockIntent, 200F) + verify(mockUpdateProfile).exec(any(), doneCaptor.capture(), any()) + doneCaptor.lastValue.invoke(UpdateProfileResponse(Profile("name", 2, image, PlayerPrefs(0)))) + } + + private fun whenUpdatingImageFails(image: String) { + val failCaptor = argumentCaptor<(Throwable)->Unit>() + whenever(mockUri.toString()).thenReturn(image) + whenever(mockIntent.data).thenReturn(mockUri) + subject.showImageForProfile(mockIntent, 200F) + verify(mockUpdateProfile).exec(any(), any(), failCaptor.capture()) + failCaptor.lastValue.invoke(RuntimeException("unable to update")) + } + + private fun thenProfilesAreFetched() { + verify(mockFetchProfile).exec(any(), any(), any()) + } + + private fun thenProfilesStatsAreFetched() { + verify(mockFetchProfileStat).exec(any(), any(), any()) + } + + private fun thenProfilesAreNotFetched() { + verifyZeroInteractions(mockFetchProfile) + } + + private fun thenErrorMessageIs(expected: Int) { + assertEquals(expected, subject.errorMsg.get()) + } + + private fun thenProfileIdIs(expected: Long) { + assertEquals(expected, subject.profile.get()?.id) + } + + private fun thenProfileNameIs(expected: String) { + assertEquals(expected, subject.profile.get()?.name?.get()) + } + + private fun thenProfileDoubleIs(expected: Int) { + assertEquals(expected, subject.profile.get()?.fav?.get()) + } + + private fun thenProfileImageIs(expected: String) { + assertEquals(expected, subject.profile.get()?.image?.get()) } } \ No newline at end of file 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 629170cf..be0c25c3 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.Logger +import nl.entreco.domain.common.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/test/java/nl/entreco/dartsscorecard/setup/ad/AdBindingsTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdBindingsTest.kt index 64714a24..407d720d 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdBindingsTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdBindingsTest.kt @@ -3,6 +3,7 @@ package nl.entreco.dartsscorecard.setup.ad import android.view.View import com.google.android.gms.ads.AdListener import com.nhaarman.mockito_kotlin.verify +import nl.entreco.dartsscorecard.ad.AdBindings import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdLoaderTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdLoaderTest.kt index 5f98c935..c781ada0 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdLoaderTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdLoaderTest.kt @@ -1,6 +1,10 @@ package nl.entreco.dartsscorecard.setup.ad +import com.google.android.gms.ads.AdView import com.nhaarman.mockito_kotlin.verify +import nl.entreco.dartsscorecard.ad.AdBindings.Companion.loadAd +import nl.entreco.dartsscorecard.ad.AdLoader +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.InjectMocks @@ -13,25 +17,31 @@ import org.mockito.junit.MockitoJUnitRunner @RunWith(MockitoJUnitRunner::class) class AdLoaderTest { - @Mock private lateinit var mockListener: AdLoader.Listener - @InjectMocks private lateinit var subject: AdLoader + @Mock private lateinit var mockView: AdView + @Mock private lateinit var mockListener: AdLoader.AdListener + private lateinit var subject: AdLoader - @Test - fun onAdClicked() { - subject.onAdClicked() - verify(mockListener).onAdClicked() + @Before + fun setUp() { + subject = AdLoader() } @Test fun onAdLoaded() { + loadAd() subject.onAdLoaded() verify(mockListener).onAdLoaded() } @Test fun onAdFailedToLoad() { + loadAd() subject.onAdFailedToLoad(12) - verify(mockListener).onAdFailed(12) + verify(mockListener).onAdFailed() + } + + private fun loadAd(){ + subject.loadAd(mockView, mockListener) } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdViewModelTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdViewModelTest.kt deleted file mode 100644 index 13edfc45..00000000 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/ad/AdViewModelTest.kt +++ /dev/null @@ -1,74 +0,0 @@ -package nl.entreco.dartsscorecard.setup.ad - -import com.nhaarman.mockito_kotlin.any -import com.nhaarman.mockito_kotlin.verify -import nl.entreco.domain.Analytics -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.junit.MockitoJUnitRunner - -/** - * Created by Entreco on 29/12/2017. - */ -@RunWith(MockitoJUnitRunner::class) -class AdViewModelTest { - - @Mock private lateinit var mockAnalytics: Analytics - private lateinit var subject: AdViewModel - - @Before - fun setUp() { - givenViewModel() - } - - @Test - fun `it should track achievement, when ad is clicked`() { - whenOnAdClicked() - thenAchieventIsTracked() - } - - @Test - fun onAdLoaded() { - whenOnAdLoaded() - thenAdIsShown() - } - - @Test - fun onAdFailed() { - whenOnAdFailed(400) - thenAdIsHidden() - } - - private fun givenViewModel() { - subject = AdViewModel(mockAnalytics) - } - - private fun whenOnAdClicked() { - subject.onAdClicked() - } - - private fun whenOnAdLoaded() { - subject.onAdLoaded() - } - - private fun whenOnAdFailed(err: Int) { - subject.onAdFailed(err) - } - - private fun thenAchieventIsTracked() { - verify(mockAnalytics).trackAchievement(any()) - } - - private fun thenAdIsShown() { - assertTrue(subject.showAd.get()) - } - - private fun thenAdIsHidden() { - assertFalse(subject.showAd.get()) - } - -} diff --git a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigatorTest.kt b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigatorTest.kt index f46546d2..2b6542dd 100644 --- a/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigatorTest.kt +++ b/android/DartsScorecard/app/src/test/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerNavigatorTest.kt @@ -47,7 +47,7 @@ class EditPlayerNavigatorTest { @Test fun `it should set RESULT_CANCELLED onBackPressed`() { subject.onBackPressed() - verify(mockActivity).setResult(eq(Activity.RESULT_OK), any()) + verify(mockActivity).setResult(eq(Activity.RESULT_CANCELED), any()) } @Test diff --git a/android/DartsScorecard/build.gradle b/android/DartsScorecard/build.gradle index a367a44d..db8b5f29 100644 --- a/android/DartsScorecard/build.gradle +++ b/android/DartsScorecard/build.gradle @@ -36,7 +36,20 @@ allprojects { configurations.all { resolutionStrategy { - force "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + force "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" + force "com.android.support:appcompat-v7:$support" + force "com.android.support:design:$support" + force "com.android.support:appcompat-v7:$support" + force "com.android.support:support-annotations:$support" + force "com.android.support:animated-vector-drawable:$support" + force "com.android.support:exifinterface:$support" + force "com.android.support:customtabs:$support" + } +} + +gradle.projectsEvaluated { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xmaxerrs" << "1500" } } diff --git a/android/DartsScorecard/data/build.gradle b/android/DartsScorecard/data/build.gradle index 4bd38082..c6d4d07b 100644 --- a/android/DartsScorecard/data/build.gradle +++ b/android/DartsScorecard/data/build.gradle @@ -11,7 +11,7 @@ android { dependencies { implementation project(":domain") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" implementation "com.google.firebase:firebase-core:$firebase" implementation "com.google.firebase:firebase-firestore:$firebase" implementation "com.android.support:appcompat-v7:$support" diff --git a/android/DartsScorecard/data/src/androidTest/java/nl/entreco/data/analytics/FirebaseAnalyticsInstrumentationTest.kt b/android/DartsScorecard/data/src/androidTest/java/nl/entreco/data/analytics/FirebaseAnalyticsInstrumentationTest.kt index 3e6efb8c..f85b21bd 100644 --- a/android/DartsScorecard/data/src/androidTest/java/nl/entreco/data/analytics/FirebaseAnalyticsInstrumentationTest.kt +++ b/android/DartsScorecard/data/src/androidTest/java/nl/entreco/data/analytics/FirebaseAnalyticsInstrumentationTest.kt @@ -32,7 +32,7 @@ class FirebaseAnalyticsInstrumentationTest { @Test fun itShouldTrackViewFeature() { - subject.trackViewFeature(Feature("ref", "ti", "d", "i", "u", 12, 2)) + subject.trackViewFeature(Feature("ref", "ti", "d", "i", "u", 12, 2, "video")) } private fun givenSubject() { diff --git a/android/DartsScorecard/data/src/main/AndroidManifest.xml b/android/DartsScorecard/data/src/main/AndroidManifest.xml index a052c5cb..79f52e5c 100644 --- a/android/DartsScorecard/data/src/main/AndroidManifest.xml +++ b/android/DartsScorecard/data/src/main/AndroidManifest.xml @@ -1,7 +1,9 @@ - + + + diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/FeatureApiData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/FeatureApiData.kt index 423f5940..41cdeaa6 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/FeatureApiData.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/api/beta/FeatureApiData.kt @@ -28,4 +28,7 @@ internal class FeatureApiData { @PropertyName("count") val count: Int = 0 + + @PropertyName("video") + val video: String = "" } 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 dca09617..9cef7b8b 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.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.beta.Feature import nl.entreco.domain.repository.FeatureRepository @@ -29,8 +29,8 @@ class RemoteFeatureRepository(private val db: FirebaseFirestore, private val log private fun convertToFeature(doc: DocumentSnapshot) { try { - val feature = doc.toObject(FeatureApiData::class.java) - features[doc.id] = Feature(doc.id, feature.title, feature.description, feature.image, feature.remarks ?: "", feature.goal, feature.count) + val feature = doc.toObject(FeatureApiData::class.java)!! + features[doc.id] = Feature(doc.id, feature.title, feature.description, feature.image, feature.remarks ?: "", feature.goal, feature.count, feature.video) } catch (oops: Exception) { logger.e("Unable to convert snapshot to feature( $doc ) $oops") } @@ -44,8 +44,8 @@ class RemoteFeatureRepository(private val db: FirebaseFirestore, private val log override fun submitVote(featureId: String, amount: Int) { val feature = featureRef.document(featureId) db.runTransaction { transaction -> - val max = transaction.get(feature).getLong("goal") - val count = transaction.get(feature).getLong("count") + amount + val max = transaction.get(feature).getLong("goal")!! + val count = amount + transaction.get(feature).getLong("count")!! if (count <= max) { transaction.update(feature, "count", count) } else { diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/BillingData.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/BillingData.kt index 7fcce215..49550e0d 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/BillingData.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/billing/BillingData.kt @@ -13,19 +13,29 @@ const val type = "inapp" internal val chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/:".toCharArray() class Donate10Votes : BillingData("10_feature_votes", 10) +class Donate20Votes : BillingData("20_feature_votes", 20) class Donate50Votes : BillingData("50_feature_votes", 50) class Donate100Votes : BillingData("100_feature_votes", 100) +class Donate200Votes : BillingData("200_feature_votes", 200) class Donate500Votes : BillingData("500_feature_votes", 500) +class Donate1000Votes : BillingData("1000_feature_votes", 1000) + +class DonateAds10Votes : BillingData("10_remove_ads_votes", 10) +class DonateAds20Votes : BillingData("20_remove_ads_votes", 20) +class DonateAds50Votes : BillingData("50_remove_ads_votes", 50) +class DonateAds100Votes : BillingData("100_remove_ads_votes", 100) +class DonateAds200Votes : BillingData("200_remove_ads_votes", 200) +class DonateAds500Votes : BillingData("500_remove_ads_votes", 500) +class DonateAds1000Votes : BillingData("1000_remove_ads_votes", 1000) + class DonateTestPurchased : BillingData("android.test.purchased", 10) class DonateTestCancelled : BillingData("android.test.canceled", 10) class DonateTestRefunded : BillingData("android.test.refunded", 10) class DonateTestUnavailable : BillingData("android.test.item_unavailable", 10) -class FetchDonationsData { - +sealed class InAppProducts(private val billingData: List) { private fun listOfDonations(): List { - return listOf(Donate10Votes(), Donate50Votes(), Donate100Votes(), Donate500Votes()) -// return listOf(DonateTestPurchased(), DonateTestCancelled(), DonateTestRefunded(), DonateTestUnavailable()) + return billingData } private fun listOfProducts(): List { @@ -51,6 +61,11 @@ class FetchDonationsData { } } +class FetchDonationsInclAdsData : InAppProducts(listOf(DonateAds10Votes(), DonateAds20Votes(), DonateAds50Votes(), DonateAds100Votes(), DonateAds200Votes(), DonateAds500Votes(), DonateAds1000Votes())) +class FetchDonationsData : InAppProducts(listOf(Donate10Votes(), Donate20Votes(), Donate50Votes(), Donate100Votes(), Donate200Votes(), Donate500Votes(), Donate1000Votes())) +class FetchDonationsTestData : InAppProducts(listOf(DonateTestPurchased(), DonateTestCancelled(), DonateTestRefunded(), DonateTestUnavailable())) +class FetchDonationsInclAdsTestData : InAppProducts(listOf(DonateTestPurchased(), DonateTestCancelled(), DonateTestRefunded(), DonateTestUnavailable())) + class MakeDonationData(private val donation: Donation) { fun sku(): String { @@ -66,3 +81,13 @@ class MakeDonationData(private val donation: Donation) { } } +class FetchPurchasesData { + fun type(): String { + return type + } + + fun token(): String { + return "unused token" + } +} + 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 3650aa39..8abd5a35 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 @@ -15,7 +15,17 @@ import nl.entreco.domain.repository.BillingRepository */ class PlayStoreBillingRepository(private val context: Context, private val service: BillingServiceConnection) : BillingRepository { - private val BILLINGRESPONSERESULTOK = 0 + companion object { + private const val BILLING_RESPONSE_RESULT_OK = 0 + private const val BILLING_INTENT = "com.android.vending.billing.InAppBillingService.BIND" + private const val BILLING_PACKAGE = "com.android.vending" + private const val FETCH_RESPONSE_CODE = "RESPONSE_CODE" + private const val EXTRA_DETAILS_LIST = "DETAILS_LIST" + private const val BUY_RESPONSE_CODE = "RESPONSE_CODE" + private const val EXTRA_BUY_INTENT = "BUY_INTENT" + private const val QUERY_RESPONSE_CODE = "RESPONSE_CODE" + private const val EXTRA_INAPP_PURCHASE_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST" + } private val gson by lazy { GsonBuilder().create() } private val apiVersion = 5 @@ -24,8 +34,8 @@ class PlayStoreBillingRepository(private val context: Context, private val servi @UiThread override fun bind(done: (Boolean) -> Unit) { service.setCallback(done) - val intent = Intent("com.android.vending.billing.InAppBillingService.BIND") - intent.`package` = "com.android.vending" + val intent = Intent(BILLING_INTENT) + intent.`package` = BILLING_PACKAGE context.bindService(intent, service, Context.BIND_AUTO_CREATE) } @@ -36,14 +46,24 @@ class PlayStoreBillingRepository(private val context: Context, private val servi } @WorkerThread - override fun fetchDonations(): List { - + override fun fetchDonationsExclAds(): List { val donations = FetchDonationsData() + return fetchProducts(donations) + } + + @WorkerThread + override fun fetchDonationsInclAds(): List { + val donations = FetchDonationsInclAdsData() + return fetchProducts(donations) + } + + @WorkerThread + private fun fetchProducts(donations: InAppProducts): List { val bundle = service.getService()?.getSkuDetails(apiVersion, packageName, donations.type(), donations.skuBundle()) - return if (bundle?.getInt("RESPONSE_CODE") == BILLINGRESPONSERESULTOK) { + return if (bundle?.getInt(FETCH_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { - bundle.getStringArrayList("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) @@ -54,25 +74,35 @@ class PlayStoreBillingRepository(private val context: Context, private val servi } } + @WorkerThread override fun donate(donation: Donation): MakeDonationResponse { val buy = MakeDonationData(donation) val payload = buy.payload() - val bundle = service.getService()?.run { - getBuyIntent(apiVersion, packageName, buy.sku(), buy.type(), payload) - } + val bundle = service.getService()?.getBuyIntent(apiVersion, packageName, buy.sku(), buy.type(), payload) - return if (bundle?.getInt("RESPONSE_CODE") == BILLINGRESPONSERESULTOK) { - val intent: PendingIntent = bundle.getParcelable("BUY_INTENT") + return if (bundle?.getInt(BUY_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { + val intent: PendingIntent = bundle.getParcelable(EXTRA_BUY_INTENT) MakeDonationResponse(intent, payload) } else { - throw Throwable("oops, $bundle") + throw Throwable("Unable to getBuyIntent() $bundle") } } + @WorkerThread override fun consume(token: String): Int { - return service.getService()?.run { - consumePurchase(apiVersion, packageName, token) - }!! + return service.getService()?.consumePurchase(apiVersion, packageName, token)!! + } + + @WorkerThread + override fun fetchPurchasedItems(): List { + val purchases = FetchPurchasesData() + val bundle = service.getService()?.getPurchases(apiVersion, packageName, purchases.type(), purchases.token()) + + return if (bundle?.getInt(QUERY_RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { + return 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/DscDatabase.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/DscDatabase.kt index 05f4dfe4..ff97bf54 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/DscDatabase.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/DscDatabase.kt @@ -8,18 +8,21 @@ import nl.entreco.data.db.meta.MetaDao import nl.entreco.data.db.meta.MetaTable import nl.entreco.data.db.player.PlayerDao import nl.entreco.data.db.player.PlayerTable +import nl.entreco.data.db.profile.ProfileDao +import nl.entreco.data.db.profile.ProfileTable import nl.entreco.data.db.turn.TurnDao import nl.entreco.data.db.turn.TurnTable /** * Created by Entreco on 12/12/2017. */ -@Database(entities = [(GameTable::class), (PlayerTable::class), (TurnTable::class), (MetaTable::class)], version = 1, exportSchema = false) +@Database(entities = [(GameTable::class), (PlayerTable::class), (TurnTable::class), (MetaTable::class), (ProfileTable::class)], version = 1, exportSchema = false) abstract class DscDatabase : RoomDatabase() { abstract fun gameDao(): GameDao abstract fun playerDao(): PlayerDao abstract fun turnDao(): TurnDao abstract fun metaDao(): MetaDao + abstract fun profileDao(): ProfileDao companion object { const val name: String = "dsc_database" 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 ddc127e7..9be2a5d8 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 @@ -45,8 +45,7 @@ class LocalGameRepository(db: DscDatabase, private val mapper: Mapper + val profileTable = mapper.to(gameId, player.toLong(), turnTable, metaTable) + profileDao.create(profileTable) + } + + return 1 + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ArchiveStatMapper.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ArchiveStatMapper.kt new file mode 100644 index 00000000..c0b9d5d5 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ArchiveStatMapper.kt @@ -0,0 +1,26 @@ +package nl.entreco.data.db.profile + +import nl.entreco.data.db.meta.MetaTable +import nl.entreco.data.db.turn.TurnTable + + +class ArchiveStatMapper { + fun to(gameId: Long, playerId: Long, turns: List, metas: List): ProfileTable { + val table = ProfileTable() + table.gameId = gameId + table.playerId = playerId + table.numDarts = turns.filter { it.player == playerId }.sumBy { it.numDarts } + table.totalScore = turns.filter { it.player == playerId }.sumBy { score(it) } + return table + } + + private fun score(it: TurnTable): Int { + return when (it.numDarts) { + 0 -> 0 + 1 -> it.d1 * it.m1 + 2 -> it.d1 * it.m1 + it.d2 * it.m2 + 3 -> it.d1 * it.m1 + it.d2 * it.m2 + it.d3 * it.m3 + else -> 0 + } + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileInfoInfoRepository.kt similarity index 73% rename from android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileRepository.kt rename to android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileInfoInfoRepository.kt index 705ae72e..0e6bf301 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/LocalProfileInfoInfoRepository.kt @@ -6,12 +6,12 @@ import nl.entreco.data.db.Mapper import nl.entreco.data.db.player.PlayerDao import nl.entreco.data.db.player.PlayerTable import nl.entreco.domain.profile.Profile -import nl.entreco.domain.repository.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository /** * Created by entreco on 23/02/2018. */ -class LocalProfileRepository(db: DscDatabase, private val mapper: Mapper) : ProfileRepository { +class LocalProfileInfoInfoRepository(db: DscDatabase, private val mapper: Mapper) : ProfileInfoRepository { private val playerDao: PlayerDao = db.playerDao() @WorkerThread @@ -22,8 +22,7 @@ class LocalProfileRepository(db: DscDatabase, private val mapper: Mapper + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun create(profile: ProfileTable): Long +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileStatMapper.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileStatMapper.kt new file mode 100644 index 00000000..8f7eb709 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileStatMapper.kt @@ -0,0 +1,11 @@ +package nl.entreco.data.db.profile + +import nl.entreco.domain.profile.ProfileStat + + +class ProfileStatMapper { + + fun to(playerId: Long, stats: List): ProfileStat { + return ProfileStat(playerId, stats.size, stats.sumBy { it.numDarts }, stats.sumBy { it.totalScore }) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileTable.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileTable.kt new file mode 100644 index 00000000..27da6eb3 --- /dev/null +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/profile/ProfileTable.kt @@ -0,0 +1,29 @@ +package nl.entreco.data.db.profile + +import android.arch.persistence.room.ColumnInfo +import android.arch.persistence.room.Entity +import android.arch.persistence.room.PrimaryKey + +@Entity(tableName = "Profile") +class ProfileTable { + @PrimaryKey(autoGenerate = true) + var id: Long = 0 + + @ColumnInfo(name = "player") + var playerId: Long = -1 + + @ColumnInfo(name = "game") + var gameId: Long = -1 + + @ColumnInfo(name = "numDarts") + var numDarts: Int = 0 + + @ColumnInfo(name = "numDarts9") + var numDarts9: Int = 0 + + @ColumnInfo(name = "totalScore") + var totalScore: Int = 0 + + @ColumnInfo(name = "totalScore9") + var totalScore9: Int = 0 +} \ No newline at end of file diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/StatMapper.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LiveStatMapper.kt similarity index 60% rename from android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/StatMapper.kt rename to android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LiveStatMapper.kt index 49668707..05999651 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/StatMapper.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LiveStatMapper.kt @@ -3,35 +3,37 @@ package nl.entreco.data.db.stats import nl.entreco.data.db.meta.MetaTable import nl.entreco.data.db.turn.TurnMapper import nl.entreco.data.db.turn.TurnTable -import nl.entreco.domain.model.Stat +import nl.entreco.domain.model.LiveStat import nl.entreco.domain.model.Turn /** * Created by entreco on 16/01/2018. */ -class StatMapper { +class LiveStatMapper { - fun to(turns: List, metas: List): Map { - val list = HashMap() + fun to(turns: List, metas: List): Map { + val list = HashMap() turns.forEachIndexed { index, turn -> - var stat: Stat? = null + var liveStat: LiveStat? = null if (list.containsKey(turn.player)) { - stat = list[turn.player] + liveStat = list[turn.player] } - list[turn.player] = to(turn, metas[index]) + stat + list[turn.player] = to(turn, metas[index]) + liveStat } return list } - fun to(turn: TurnTable, meta: MetaTable): Stat { + fun to(turn: TurnTable, meta: MetaTable): LiveStat { val t = TurnMapper().to(turn) val n180 = if (t.total() == 180) 1 else 0 val n140 = if (t.total() in 140..179) 1 else 0 val n100 = if (t.total() in 100..139) 1 else 0 + val n60 = if (t.total() in 60..99) 1 else 0 + val n20 = if (t.total() in 20..59) 1 else 0 val checkout = if (didFinish(t, meta)) 1 else 0 val highCo = if (didFinish(t, meta)) listOf(t.total()) else emptyList() val breaks = if (meta.breakMade) 1 else 0 - return Stat(turn.player, t.total(), t.dartsUsed(), n180, n140, n100, meta.atCheckout, checkout, breaks, listOf(t.total()), highCo) + return LiveStat(turn.player, t.total(), t.dartsUsed(), n180, n140, n100, n60, n20, meta.atCheckout, checkout, breaks, listOf(t.total()), highCo) } private fun didFinish(t: Turn, meta: MetaTable) = t.total() == meta.score diff --git a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalStatRepository.kt b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalLiveStatRepository.kt similarity index 52% rename from android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalStatRepository.kt rename to android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalLiveStatRepository.kt index bce86704..8192c8f2 100644 --- a/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalStatRepository.kt +++ b/android/DartsScorecard/data/src/main/java/nl/entreco/data/db/stats/LocalLiveStatRepository.kt @@ -2,28 +2,28 @@ package nl.entreco.data.db.stats import android.support.annotation.WorkerThread import nl.entreco.data.db.DscDatabase -import nl.entreco.domain.model.Stat -import nl.entreco.domain.repository.StatRepository +import nl.entreco.domain.model.LiveStat +import nl.entreco.domain.repository.LiveStatRepository /** * Created by entreco on 16/01/2018. */ -class LocalStatRepository(db: DscDatabase, private val mapper: StatMapper) : StatRepository { +class LocalLiveStatRepository(db: DscDatabase, private val mapperLive: LiveStatMapper) : LiveStatRepository { private val turnDao = db.turnDao() private val metaDao = db.metaDao() @WorkerThread - override fun fetchAllForGame(gameId: Long): Map { + override fun fetchAllForGame(gameId: Long): Map { val turnTable = turnDao.fetchAll(gameId) val metaTable = metaDao.fetchAll(gameId) - return mapper.to(turnTable, metaTable) + return mapperLive.to(turnTable, metaTable) } @WorkerThread - override fun fetchStat(turnId: Long, metaId: Long): Stat { + override fun fetchStat(turnId: Long, metaId: Long): LiveStat { val turnTable = turnDao.fetchById(turnId) val metaTable = metaDao.fetchById(metaId) - return mapper.to(turnTable, metaTable) + return mapperLive.to(turnTable, metaTable) } } \ No newline at end of file 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 5fd435a0..a6ee9acb 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.Logger +import nl.entreco.domain.common.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/billing/BillingDataTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/BillingDataTest.kt index cc7f4b5f..1e77b557 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/BillingDataTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/BillingDataTest.kt @@ -7,20 +7,50 @@ import org.junit.Test * Created by entreco on 09/02/2018. */ class BillingDataTest { + @Test fun getProductIds() { assertEquals("10_feature_votes", Donate10Votes().productId) + assertEquals("20_feature_votes", Donate20Votes().productId) assertEquals("50_feature_votes", Donate50Votes().productId) assertEquals("100_feature_votes", Donate100Votes().productId) + assertEquals("200_feature_votes", Donate200Votes().productId) assertEquals("500_feature_votes", Donate500Votes().productId) + assertEquals("1000_feature_votes", Donate1000Votes().productId) } @Test fun getVotes() { assertEquals(10, Donate10Votes().votes) + assertEquals(20, Donate20Votes().votes) assertEquals(50, Donate50Votes().votes) assertEquals(100, Donate100Votes().votes) + assertEquals(200, Donate200Votes().votes) assertEquals(500, Donate500Votes().votes) + assertEquals(1000, Donate1000Votes().votes) + } + + + @Test + fun getProductIdsIncl() { + assertEquals("10_remove_ads_votes", DonateAds10Votes().productId) + assertEquals("20_remove_ads_votes", DonateAds20Votes().productId) + assertEquals("50_remove_ads_votes", DonateAds50Votes().productId) + assertEquals("100_remove_ads_votes", DonateAds100Votes().productId) + assertEquals("200_remove_ads_votes", DonateAds200Votes().productId) + assertEquals("500_remove_ads_votes", DonateAds500Votes().productId) + assertEquals("1000_remove_ads_votes", DonateAds1000Votes().productId) + } + + @Test + fun getVotesIncl() { + assertEquals(10, DonateAds10Votes().votes) + assertEquals(20, DonateAds20Votes().votes) + assertEquals(50, DonateAds50Votes().votes) + assertEquals(100, DonateAds100Votes().votes) + assertEquals(200, DonateAds200Votes().votes) + assertEquals(500, DonateAds500Votes().votes) + assertEquals(1000, DonateAds1000Votes().votes) } } \ No newline at end of file diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/FetchDonationsDataTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/FetchDonationsDataTest.kt index cf3bf983..1373eb24 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/FetchDonationsDataTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/FetchDonationsDataTest.kt @@ -17,6 +17,9 @@ class FetchDonationsDataTest { assertTrue(FetchDonationsData().contains("10_feature_votes")) assertTrue(FetchDonationsData().contains("50_feature_votes")) assertTrue(FetchDonationsData().contains("100_feature_votes")) + assertTrue(FetchDonationsData().contains("200_feature_votes")) + assertTrue(FetchDonationsData().contains("500_feature_votes")) + assertTrue(FetchDonationsData().contains("1000_feature_votes")) } @Test @@ -27,15 +30,28 @@ class FetchDonationsDataTest { } @Test - fun type() { + fun `should have correct fetch type`() { assertEquals("inapp", FetchDonationsData().type()) } + @Test + fun `should have correct purchase type`() { + assertEquals("inapp", FetchPurchasesData().type()) + } + + @Test + fun `should have correct purchase token`() { + assertEquals("unused token", FetchPurchasesData().token()) + } + @Test fun `should get correct votes`() { assertEquals(10, FetchDonationsData().getVotes("10_feature_votes")) assertEquals(50, FetchDonationsData().getVotes("50_feature_votes")) assertEquals(100, FetchDonationsData().getVotes("100_feature_votes")) + assertEquals(200, FetchDonationsData().getVotes("200_feature_votes")) + assertEquals(500, FetchDonationsData().getVotes("500_feature_votes")) + assertEquals(1000, FetchDonationsData().getVotes("1000_feature_votes")) } @Test(expected = NoSuchElementException::class) diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/PlayStoreBillingRepositoryTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/PlayStoreBillingRepositoryTest.kt index 2e3f1f92..4a2ae261 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/PlayStoreBillingRepositoryTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/billing/PlayStoreBillingRepositoryTest.kt @@ -11,8 +11,7 @@ import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.whenever import nl.entreco.domain.beta.Donation import nl.entreco.domain.beta.donations.MakeDonationResponse -import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotNull +import org.junit.Assert.* import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -35,6 +34,7 @@ class PlayStoreBillingRepositoryTest { private lateinit var expectedResponse: MakeDonationResponse private var expectedConsumtionResponse: Int = 0 private var expectedDonation = emptyList() + private var expectedPurchasedItems = emptyList() private val gson = GsonBuilder().create() @@ -106,6 +106,19 @@ class PlayStoreBillingRepositoryTest { whenConsumingFails() } + @Test + fun `it should report result when query purchase items succeeds`() { + givenSubject() + whenFetchingPurchasesSucceeds("item§1", "item 2") + assertNotNull(expectedPurchasedItems) + } + + @Test(expected = Throwable::class) + fun `it should throw exception when query purchase items fails`() { + givenSubject() + whenFetchingPurchasesFails() + } + private fun givenSubject() { subject = PlayStoreBillingRepository(mockContext, mockServiceConnection) } @@ -125,12 +138,12 @@ class PlayStoreBillingRepositoryTest { whenever(mockInappBillingService.getSkuDetails(any(), eq(null), any(), any())).thenReturn(mockBundle) whenever(mockServiceConnection.getService()).thenReturn(mockInappBillingService) - expectedDonation = subject.fetchDonations() + expectedDonation = subject.fetchDonationsExclAds() } private fun whenFetchingDonationsFails() { whenever(mockServiceConnection.getService()).thenReturn(mockInappBillingService) - subject.fetchDonations() + subject.fetchDonationsExclAds() } private fun whenDonationsSucceeds() { @@ -156,6 +169,18 @@ class PlayStoreBillingRepositoryTest { subject.consume("token") } + private fun whenFetchingPurchasesSucceeds(vararg purchases: String) { + whenever(mockBundle.getStringArrayList("INAPP_PURCHASE_ITEM_LIST")).thenReturn(ArrayList(purchases.map { it })) + whenever(mockInappBillingService.getPurchases(any(), eq(null), eq("inapp"), eq("unused token"))).thenReturn(mockBundle) + whenever(mockServiceConnection.getService()).thenReturn(mockInappBillingService) + expectedPurchasedItems = subject.fetchPurchasedItems() + } + + private fun whenFetchingPurchasesFails() { + whenever(mockServiceConnection.getService()).thenReturn(mockInappBillingService) + subject.fetchPurchasedItems() + } + private fun thenCallbackIsSetOnService() { verify(mockServiceConnection).setCallback(mockDoneCallback) } diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileRepositoryTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileInfoRepositoryTest.kt similarity index 58% rename from android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileRepositoryTest.kt rename to android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileInfoRepositoryTest.kt index c546df75..3f69d73f 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileRepositoryTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/profile/LocalProfileInfoRepositoryTest.kt @@ -3,6 +3,7 @@ package nl.entreco.data.db.profile import com.nhaarman.mockito_kotlin.whenever import nl.entreco.data.db.DscDatabase import nl.entreco.data.db.player.PlayerDao +import nl.entreco.data.db.player.PlayerTable import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test @@ -14,18 +15,18 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 26/02/2018. */ @RunWith(MockitoJUnitRunner::class) -class LocalProfileRepositoryTest { +class LocalProfileInfoRepositoryTest { @Mock private lateinit var mockDb: DscDatabase @Mock private lateinit var mockPlayerDao: PlayerDao - private lateinit var subject: LocalProfileRepository + private lateinit var subject: LocalProfileInfoInfoRepository private lateinit var mapper: ProfileMapper @Before fun setUp() { whenever(mockDb.playerDao()).thenReturn(mockPlayerDao) mapper = ProfileMapper() - subject = LocalProfileRepository(mockDb, mapper) + subject = LocalProfileInfoInfoRepository(mockDb, mapper) } @Test @@ -33,4 +34,14 @@ class LocalProfileRepositoryTest { assertNotNull(subject.fetchAll(LongArray(0))) } + @Test + fun update() { + whenever(mockPlayerDao.fetchById(0)).thenReturn(PlayerTable()) + assertNotNull(subject.update(0, "name", "image", "20")) + } + + @Test(expected = IllegalStateException::class) + fun `update can also throw for non-existing players`() { + assertNotNull(subject.update(0, "name", "image", "double")) + } } diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/StatMapperTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LiveLiveStatMapperTest.kt similarity index 97% rename from android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/StatMapperTest.kt rename to android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LiveLiveStatMapperTest.kt index 5ef768ee..b5159fcb 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/StatMapperTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LiveLiveStatMapperTest.kt @@ -12,9 +12,9 @@ import org.junit.Test /** * Created by entreco on 20/01/2018. */ -class StatMapperTest { +class LiveLiveStatMapperTest { - private lateinit var subject: StatMapper + private lateinit var subject: LiveStatMapper private lateinit var givenScores: Map private lateinit var givenTurns: List private lateinit var givenPlayerIds: List @@ -22,7 +22,7 @@ class StatMapperTest { private val gameId: Long = 3 private val turnMapper = TurnMapper() private val metaMapper = MetaMapper() - private lateinit var expectedStats: Map + private lateinit var expectedStats: Map private val scoreEstimator = ScoreEstimator() @Test @@ -120,7 +120,7 @@ class StatMapperTest { } private fun givenSubject() { - subject = StatMapper() + subject = LiveStatMapper() } private fun givenPlayers(vararg ids: Long) { diff --git a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalStatRepositoryTest.kt b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalLiveLiveStatRepositoryTest.kt similarity index 80% rename from android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalStatRepositoryTest.kt rename to android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalLiveLiveStatRepositoryTest.kt index f44567b3..51f86d6c 100644 --- a/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalStatRepositoryTest.kt +++ b/android/DartsScorecard/data/src/test/java/nl/entreco/data/db/stats/LocalLiveLiveStatRepositoryTest.kt @@ -16,13 +16,13 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 24/01/2018. */ @RunWith(MockitoJUnitRunner::class) -class LocalStatRepositoryTest { +class LocalLiveLiveStatRepositoryTest { @Mock private lateinit var mockDb: DscDatabase - @Mock private lateinit var mockMapper: StatMapper + @Mock private lateinit var mockMapperLive: LiveStatMapper @Mock private lateinit var mockTurnDao: TurnDao @Mock private lateinit var mockMetaDao: MetaDao - private lateinit var subject: LocalStatRepository + private lateinit var subject: LocalLiveStatRepository @Before fun setUp() { @@ -32,7 +32,7 @@ class LocalStatRepositoryTest { private fun givenSubject() { whenever(mockDb.turnDao()).thenReturn(mockTurnDao) whenever(mockDb.metaDao()).thenReturn(mockMetaDao) - subject = LocalStatRepository(mockDb, mockMapper) + subject = LocalLiveStatRepository(mockDb, mockMapperLive) } @Test @@ -40,7 +40,7 @@ class LocalStatRepositoryTest { subject.fetchAllForGame(2) verify(mockTurnDao).fetchAll(2) verify(mockMetaDao).fetchAll(2) - verify(mockMapper).to(anyList(), anyList()) + verify(mockMapperLive).to(anyList(), anyList()) } @Test diff --git a/android/DartsScorecard/domain/build.gradle b/android/DartsScorecard/domain/build.gradle index b5dc3242..8d310468 100644 --- a/android/DartsScorecard/domain/build.gradle +++ b/android/DartsScorecard/domain/build.gradle @@ -10,7 +10,7 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" 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/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsResponse.kt new file mode 100644 index 00000000..0fe2a18d --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsResponse.kt @@ -0,0 +1,4 @@ +package nl.entreco.domain.ad + + +data class FetchPurchasedItemsResponse(val serveAds: Boolean) \ No newline at end of file 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 new file mode 100644 index 00000000..1058213a --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecase.kt @@ -0,0 +1,20 @@ +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.domain.repository.BillingRepository +import javax.inject.Inject + + +class FetchPurchasedItemsUsecase @Inject constructor(private val billingRepository: BillingRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun exec(done: (FetchPurchasedItemsResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + val items = billingRepository.fetchPurchasedItems() + onUi { + done(FetchPurchasedItemsResponse(items.isEmpty())) + } + }, fail) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Donation.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Donation.kt index 8975e358..d5c57b3c 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Donation.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Donation.kt @@ -3,5 +3,5 @@ package nl.entreco.domain.beta /** * Created by entreco on 08/02/2018. */ -data class Donation(val title: String, val description: String, val sku: String, val price: String, +class Donation(val title: String, val description: String, val sku: String, val price: String, val votes: Int, val priceCurrencyCode: String, val priceMicros: String) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Feature.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Feature.kt index e3ef181b..f3eb5335 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Feature.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/Feature.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.beta /** * Created by entreco on 03/02/2018. */ -data class Feature(val ref: String, val title: String, val description: String, val image: String, val remarks: String, val required: Int, val votes: Int) +data class Feature(val ref: String, val title: String, val description: String, val image: String, val remarks: String, val required: Int, val votes: Int, val video: String) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationRequest.kt index 967c366e..1d4be32d 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.beta.donations /** * Created by entreco on 09/02/2018. */ -data class ConsumeDonationRequest(val purchaseData: String, val signature: String) \ No newline at end of file +class ConsumeDonationRequest(val purchaseData: String, val signature: String, val requiresConsumption: Boolean) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationResponse.kt index 0d228416..b42359ec 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/ConsumeDonationResponse.kt @@ -3,4 +3,8 @@ package nl.entreco.domain.beta.donations /** * Created by entreco on 09/02/2018. */ -data class ConsumeDonationResponse(val resultCode: Int, val productId: String, val orderId: String) +class ConsumeDonationResponse(val resultCode: Int, val productId: String, val orderId: String){ + companion object { + const val CONSUME_OK = 0 + } +} 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 f0ffe861..8dadca9b 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,6 +3,7 @@ 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.beta.donations.ConsumeDonationResponse.Companion.CONSUME_OK import nl.entreco.domain.common.executors.Background import nl.entreco.domain.common.executors.Foreground import nl.entreco.domain.repository.BillingRepository @@ -24,7 +25,8 @@ class ConsumeDonationUsecase @Inject constructor(private val billingRepository: val token = json.purchaseToken!! val productId = json.productId!! val orderId = json.orderId!! - val result = billingRepository.consume(token) + + val result = if(req.requiresConsumption) billingRepository.consume(token) else ConsumeDonationResponse.CONSUME_OK onUi { done(ConsumeDonationResponse(result, productId, orderId)) } }, fail) } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsResponse.kt index bfbca6c6..bc3d737f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/FetchDonationsResponse.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.beta.Donation /** * Created by entreco on 09/02/2018. */ -data class FetchDonationsResponse(val donations: List) \ No newline at end of file +class FetchDonationsResponse(val donations: List, val needToBeConsumed: Boolean) \ No newline at end of file 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 281c5854..8f1c6e0e 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 @@ -11,11 +11,17 @@ import javax.inject.Inject */ class FetchDonationsUsecase @Inject constructor(private val billingRepository: BillingRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { - fun exec(done: (FetchDonationsResponse)->Unit, fail: (Throwable) -> Unit){ + fun exec(done: (FetchDonationsResponse) -> Unit, fail: (Throwable) -> Unit) { onBackground({ - val donations = billingRepository.fetchDonations().sortedBy { it.priceMicros } - val sorted = donations.sortedBy { it.price } - onUi { done(FetchDonationsResponse(sorted)) } + + val hasPreviouslyBoughtItems = billingRepository.fetchPurchasedItems().isNotEmpty() + if (hasPreviouslyBoughtItems) { + val donations = billingRepository.fetchDonationsExclAds().sortedBy { it.priceMicros.toLong() } + onUi { done(FetchDonationsResponse(donations, true)) } + } else { + val donations = billingRepository.fetchDonationsInclAds().sortedBy { it.priceMicros.toLong() } + onUi { done(FetchDonationsResponse(donations, false)) } + } }, fail) } } \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationRequest.kt index af3356b5..9580fe18 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationRequest.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.beta.Donation /** * Created by entreco on 09/02/2018. */ -data class MakeDonationRequest(val donation: Donation) \ No newline at end of file +class MakeDonationRequest(val donation: Donation) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationResponse.kt index 3a52261c..65d66216 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/donations/MakeDonationResponse.kt @@ -5,4 +5,4 @@ import android.app.PendingIntent /** * Created by entreco on 09/02/2018. */ -data class MakeDonationResponse(val intent: PendingIntent, val payload: String) \ No newline at end of file +class MakeDonationResponse(val intent: PendingIntent, val payload: String) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteRequest.kt index 5630e380..31faf8e0 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.beta.vote /** * Created by entreco on 07/02/2018. */ -data class SubmitVoteRequest (val featureId: String, val amount: Int) \ No newline at end of file +class SubmitVoteRequest (val featureId: String, val amount: Int) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteResponse.kt index c4a1d0f4..84c60c33 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/vote/SubmitVoteResponse.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.beta.vote /** * Created by entreco on 07/02/2018. */ -data class SubmitVoteResponse (val ok: Boolean) \ No newline at end of file +class SubmitVoteResponse (val ok: Boolean) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/Logger.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt similarity index 93% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/Logger.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt index 4ad7cbda..915f5288 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/Logger.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/common/log/Logger.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain +package nl.entreco.domain.common.log /** * Created by Entreco on 27/11/2017. diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsRequest.kt index c8830b46..91a97f66 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/launch/ExtractTeamsRequest.kt @@ -6,7 +6,7 @@ import nl.entreco.domain.model.players.TeamSeperator /** * Created by entreco on 06/01/2018. */ -data class ExtractTeamsRequest(private val teamString: String){ +data class ExtractTeamsRequest(private val teamString: String) { private val illegalState = IllegalStateException("invalid team string, should be 'player1,player2|player3|player4,player5'") private val playerSplit: MutableList> = emptyList>().toMutableList() private lateinit var teamSplit: List diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Game.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Game.kt index cf9f807b..7036aa05 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Game.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Game.kt @@ -17,7 +17,7 @@ data class Game(val id: Long = 0, val arbiter: Arbiter) { fun start(startIndex: Int, teams: Array): Game { next = arbiter.start(startIndex, teams) starters.clear() - starters.add( 0, next.team) + starters.add(0, next.team) previousState = next.state newMatchSetOrLeg = true return this @@ -32,9 +32,10 @@ data class Game(val id: Long = 0, val arbiter: Arbiter) { } private fun updateStartTeam(next: Next) { + if (previousState == State.START) return newMatchSetOrLeg = when (next.state) { State.MATCH, State.LEG, State.SET -> { - starters.add( 0, next.team) + starters.add(0, next.team) true } else -> { @@ -56,7 +57,7 @@ data class Game(val id: Long = 0, val arbiter: Arbiter) { } fun wasBreakMade(by: Player): Boolean { - if(starters.size < 2) return false + if (starters.size < 2) return false return newMatchSetOrLeg && !starters[1].contains(by) } } \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/LiveStat.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/LiveStat.kt new file mode 100644 index 00000000..21a779a9 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/LiveStat.kt @@ -0,0 +1,42 @@ +package nl.entreco.domain.model + +/** + * Created by entreco on 16/01/2018. + */ +data class LiveStat(val playerId: Long, val totalScore: Int, val nDarts: Int, val n180: Int, val n140: Int, val n100: Int, val n60: Int, val n20: Int, + val nAtCheckout: Int, val nCheckouts : Int, val nBreaks : Int, val highest: List, val highestCo: List) { + + operator fun plus(liveStat: LiveStat?): LiveStat { + liveStat?.let { + val high = scoreList(liveStat) + val highCo = checkoutList(liveStat) + return copy(totalScore = totalScore + liveStat.totalScore, + nDarts = nDarts + liveStat.nDarts, + n180 = n180 + liveStat.n180, + n140 = n140 + liveStat.n140, + n100 = n100 + liveStat.n100, + n60 = n60 + liveStat.n60, + n20 = n20 + liveStat.n20, + nAtCheckout = nAtCheckout + liveStat.nAtCheckout, + nCheckouts = nCheckouts + liveStat.nCheckouts, + nBreaks = nBreaks + liveStat.nBreaks, + highest = high, + highestCo = highCo) + } + return this + } + + private fun scoreList(liveStat: LiveStat): List { + val high = ArrayList() + high.addAll(highest) + high.addAll(liveStat.highest) + return high.sorted().reversed() + } + + private fun checkoutList(liveStat: LiveStat): List { + val high = ArrayList() + high.addAll(highestCo) + high.addAll(liveStat.highestCo) + return high.sorted().reversed() + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Stat.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Stat.kt deleted file mode 100644 index d5ae7e09..00000000 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/Stat.kt +++ /dev/null @@ -1,39 +0,0 @@ -package nl.entreco.domain.model - -/** - * Created by entreco on 16/01/2018. - */ -data class Stat(val playerId: Long, val totalScore: Int, val nDarts: Int, val n180: Int, val n140: Int, val n100: Int, val nAtCheckout: Int, val nCheckouts : Int, val nBreaks : Int, val highest: List, val highestCo: List) { - - operator fun plus(stat: Stat?): Stat { - stat?.let { - val high = scoreList(stat) - val highCo = checkoutList(stat) - return copy(totalScore = totalScore + stat.totalScore, - nDarts = nDarts + stat.nDarts, - n180 = n180 + stat.n180, - n140 = n140 + stat.n140, - n100 = n100 + stat.n100, - nAtCheckout = nAtCheckout + stat.nAtCheckout, - nCheckouts = nCheckouts + stat.nCheckouts, - nBreaks = nBreaks + stat.nBreaks, - highest = high, - highestCo = highCo) - } - return this - } - - private fun scoreList(stat: Stat): List { - val high = ArrayList() - high.addAll(highest) - high.addAll(stat.highest) - return high.sorted().reversed() - } - - private fun checkoutList(stat: Stat): List { - val high = ArrayList() - high.addAll(highestCo) - high.addAll(stat.highestCo) - return high.sorted().reversed() - } -} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/players/Team.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/players/Team.kt index 3832eed6..62e4f954 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/players/Team.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/model/players/Team.kt @@ -8,7 +8,7 @@ const val PlayerSeperator = "," */ class Team(val players: Array = emptyArray()) { - private var STARTTURN = -1 + private val STARTTURN = -1 private var turns = STARTTURN private var offset = 0 private var lastLeg = 0 diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishRequest.kt index cc706402..e90e81e7 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/finish/GetFinishRequest.kt @@ -6,7 +6,7 @@ import nl.entreco.domain.model.Turn /** * Created by entreco on 06/01/2018. */ -data class GetFinishRequest(val score: Score, val turn: Turn, private val favDouble: Int) { +class GetFinishRequest(val score: Score, val turn: Turn, private val favDouble: Int) { fun score(): Int { return score.score } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/listeners/StatListener.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/listeners/StatListener.kt index 5f1adea1..80ba1f4c 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/listeners/StatListener.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/listeners/StatListener.kt @@ -5,4 +5,5 @@ package nl.entreco.domain.play.listeners */ interface StatListener { fun onStatsChange(turnId: Long, metaId: Long) + fun onGameFinished(gameId: Long) } \ No newline at end of file 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 e4a78f67..66788e5a 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,7 +1,7 @@ package nl.entreco.domain.play.mastercaller import nl.entreco.domain.BaseUsecase -import nl.entreco.domain.Logger +import nl.entreco.domain.common.log.Logger import nl.entreco.domain.common.executors.Background import nl.entreco.domain.common.executors.Foreground import nl.entreco.domain.repository.SoundRepository diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCallerRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCallerRequest.kt index 7051ca50..c4770890 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCallerRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/mastercaller/MasterCallerRequest.kt @@ -3,7 +3,7 @@ package nl.entreco.domain.play.mastercaller /** * Created by entreco on 14/03/2018. */ -data class MasterCallerRequest(val scored: Int = -1, val start: Boolean = false, val leg: Boolean = false, val set: Boolean = false, val match:Boolean = false) { +class MasterCallerRequest(val scored: Int = -1, val start: Boolean = false, val leg: Boolean = false, val set: Boolean = false, val match:Boolean = false) { fun toSound(): Sound { return when { diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheRequest.kt index 414f389a..9fd513d1 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheRequest.kt @@ -6,4 +6,4 @@ import nl.entreco.domain.play.start.Play01Request /** * Created by entreco on 19/02/2018. */ -data class RevancheRequest(val originalRequest: Play01Request, val teams: Array, val newStartIndex: Int) +class RevancheRequest(val originalRequest: Play01Request, val teams: Array, val newStartIndex: Int) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheResponse.kt index 6b907784..d17844d2 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/revanche/RevancheResponse.kt @@ -7,4 +7,4 @@ import nl.entreco.domain.settings.ScoreSettings /** * Created by entreco on 19/02/2018. */ -data class RevancheResponse(val game: Game, val settings: ScoreSettings, val teams: Array, val teamIds: String) +class RevancheResponse(val game: Game, val settings: ScoreSettings, val teams: Array, val teamIds: String) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Response.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Response.kt index fd8f7a56..407e2561 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Response.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/Play01Response.kt @@ -18,6 +18,7 @@ data class Play01Response(val game: Game, val settings: ScoreSettings, val teams if (game != other.game) return false if (settings != other.settings) return false if (!Arrays.equals(teams, other.teams)) return false + if (teamIds != other.teamIds) return false return true } @@ -26,7 +27,7 @@ data class Play01Response(val game: Game, val settings: ScoreSettings, val teams var result = game.hashCode() result = 31 * result + settings.hashCode() result = 31 * result + Arrays.hashCode(teams) + result = 31 * result + teamIds.hashCode() return result } - } \ No newline at end of file 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 d6633d72..9b9e1103 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.Logger +import nl.entreco.domain.common.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/RetrieveGameResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameResponse.kt index d35f0442..b23ed11b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveGameResponse.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.model.Game /** * Created by entreco on 06/01/2018. */ -data class RetrieveGameResponse(val game: Game) \ No newline at end of file + data class RetrieveGameResponse(val game: Game) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsResponse.kt index 5d6072be..e5d9d16b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/start/RetrieveTeamsResponse.kt @@ -6,7 +6,7 @@ import java.util.* /** * Created by entreco on 06/01/2018. */ -data class RetrieveTeamsResponse(val teams: Array) { + class RetrieveTeamsResponse(val teams: Array) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatResponse.kt deleted file mode 100644 index cf149c9e..00000000 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package nl.entreco.domain.play.stats - -import nl.entreco.domain.model.Stat - -/** - * Created by entreco on 22/01/2018. - */ -data class FetchGameStatResponse(val stat: Stat) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsResponse.kt index d119ae41..917ae1c3 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatsResponse.kt @@ -1,8 +1,8 @@ package nl.entreco.domain.play.stats -import nl.entreco.domain.model.Stat +import nl.entreco.domain.model.LiveStat /** * Created by entreco on 16/01/2018. */ -data class FetchGameStatsResponse(val gameId: Long, val stats: Map) \ No newline at end of file +data class FetchGameStatsResponse(val gameId: Long, val stats: Map) \ No newline at end of file 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 1c3a4259..81eb27e5 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 @@ -3,20 +3,20 @@ 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.domain.repository.StatRepository +import nl.entreco.domain.repository.LiveStatRepository import javax.inject.Inject /** * Created by entreco on 16/01/2018. */ class FetchGameStatsUsecase @Inject constructor( - private val statRepository: StatRepository, + private val liveStatRepository: LiveStatRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { fun exec(req: FetchGameStatsRequest, done: (FetchGameStatsResponse) -> Unit, fail: (Throwable) -> Unit) { onBackground({ - val stats = statRepository.fetchAllForGame(req.gameId) + val stats = liveStatRepository.fetchAllForGame(req.gameId) onUi { done(FetchGameStatsResponse(req.gameId, stats)) } }, fail) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatRequest.kt similarity index 57% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatRequest.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatRequest.kt index d5cad924..a3b8d8df 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.play.stats /** * Created by entreco on 22/01/2018. */ -data class FetchGameStatRequest(val turnId: Long, val metaId: Long) \ No newline at end of file +data class FetchLiveStatRequest(val turnId: Long, val metaId: Long) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatResponse.kt new file mode 100644 index 00000000..d68cae50 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatResponse.kt @@ -0,0 +1,8 @@ +package nl.entreco.domain.play.stats + +import nl.entreco.domain.model.LiveStat + +/** + * Created by entreco on 22/01/2018. + */ +data class FetchLiveStatResponse(val liveStat: LiveStat) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt similarity index 53% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatUsecase.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt index c1298801..168ab5e1 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchGameStatUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/play/stats/FetchLiveStatUsecase.kt @@ -3,21 +3,21 @@ 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.domain.repository.StatRepository +import nl.entreco.domain.repository.LiveStatRepository import javax.inject.Inject /** * Created by entreco on 22/01/2018. */ -class FetchGameStatUsecase @Inject constructor( - private val statRepository: StatRepository, +class FetchLiveStatUsecase @Inject constructor( + private val liveStatRepository: LiveStatRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { - fun exec(req: FetchGameStatRequest, done: (FetchGameStatResponse) -> Unit, fail: (Throwable) -> Unit) { + fun exec(req: FetchLiveStatRequest, done: (FetchLiveStatResponse) -> Unit, fail: (Throwable) -> Unit) { onBackground({ - val stat = statRepository.fetchStat(req.turnId, req.metaId) - onUi { done(FetchGameStatResponse(stat)) } + val stat = liveStatRepository.fetchStat(req.turnId, req.metaId) + onUi { done(FetchLiveStatResponse(stat)) } }, fail) } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/Profile.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/Profile.kt index ba4d8be7..e43b5d64 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/Profile.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/Profile.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.model.players.PlayerPrefs /** * Created by entreco on 23/02/2018. */ -class Profile(val name: String, val id: Long = 0, val image: String, val prefs: PlayerPrefs = PlayerPrefs(16)) +data class Profile(val name: String, val id: Long = 0, val image: String, val prefs: PlayerPrefs = PlayerPrefs(16)) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/ProfileStat.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/ProfileStat.kt new file mode 100644 index 00000000..9270b727 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/ProfileStat.kt @@ -0,0 +1,4 @@ +package nl.entreco.domain.profile + + +data class ProfileStat(val playerId: Long, val numberOfGames: Int, val numberOfDarts: Int, val numberOfPoints: Int) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsRequest.kt new file mode 100644 index 00000000..24602e6d --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsRequest.kt @@ -0,0 +1,3 @@ +package nl.entreco.domain.profile.archive + +class ArchiveStatsRequest(val gameId: Long) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsResponse.kt new file mode 100644 index 00000000..bc70a288 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsResponse.kt @@ -0,0 +1,4 @@ +package nl.entreco.domain.profile.archive + + +data class ArchiveStatsResponse(val scheduled: Int) \ No newline at end of file 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 new file mode 100644 index 00000000..72ff0095 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecase.kt @@ -0,0 +1,22 @@ +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.domain.repository.ArchiveRepository +import javax.inject.Inject + + +class ArchiveStatsUsecase @Inject constructor( + private val archiveRepository: ArchiveRepository, + bg: Background, fg: Foreground) + : BaseUsecase(bg, fg) { + + fun exec(request: ArchiveStatsRequest, done: (ArchiveStatsResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + + val scheduled = archiveRepository.archive(request.gameId) + onUi { done(ArchiveStatsResponse(scheduled)) } + }, fail) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileRequest.kt index 1585b69d..5c9218f2 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.profile.fetch /** * Created by entreco on 23/02/2018. */ -data class FetchProfileRequest(val players: LongArray) +class FetchProfileRequest(val players: LongArray) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileResponse.kt index 282f046c..c8b0d5fa 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileResponse.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.profile.Profile /** * Created by entreco on 23/02/2018. */ -data class FetchProfileResponse (val profiles: List) +class FetchProfileResponse (val profiles: List) diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatRequest.kt new file mode 100644 index 00000000..e8f2e08f --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatRequest.kt @@ -0,0 +1,4 @@ +package nl.entreco.domain.profile.fetch + + +data class FetchProfileStatRequest(val playerId: Long) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatResponse.kt new file mode 100644 index 00000000..f1f52a1e --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatResponse.kt @@ -0,0 +1,5 @@ +package nl.entreco.domain.profile.fetch + +import nl.entreco.domain.profile.ProfileStat + +data class FetchProfileStatResponse(val stat: ProfileStat) \ No newline at end of file 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 new file mode 100644 index 00000000..6a1dd3e0 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/fetch/FetchProfileStatsUsecase.kt @@ -0,0 +1,20 @@ +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.domain.repository.ProfileStatRepository +import javax.inject.Inject + + +class FetchProfileStatsUsecase @Inject constructor( + private val profileStatRepository: ProfileStatRepository, + bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { + + fun exec(req: FetchProfileStatRequest, done: (FetchProfileStatResponse) -> Unit, fail: (Throwable) -> Unit) { + onBackground({ + val stat = profileStatRepository.fetchForPlayer(req.playerId) + onUi { done(FetchProfileStatResponse(stat)) } + }, fail) + } +} \ No newline at end of file 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 37b7ab8d..5aa55b7d 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 @@ -3,19 +3,19 @@ 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.domain.repository.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository import javax.inject.Inject /** * Created by entreco on 23/02/2018. */ class FetchProfileUsecase @Inject constructor( - private val profileRepository: ProfileRepository, + private val profileInfoRepository: ProfileInfoRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { fun exec(request: FetchProfileRequest, done: (FetchProfileResponse) -> Unit, fail: (Throwable) -> Unit) { onBackground({ - val profiles = profileRepository.fetchAll(request.players) + val profiles = profileInfoRepository.fetchAll(request.players) onUi { done(FetchProfileResponse(profiles)) } }, fail) } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileRequest.kt index 73d344ce..e333f05b 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/profile/update/UpdateProfileRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.profile.update /** * Created by entreco on 28/02/2018. */ -data class UpdateProfileRequest(val id: Long, val name: String?, val double: String?, val image: String?, val size: Float) +class UpdateProfileRequest(val id: Long, val name: String?, val double: String?, val image: String?, val size: Float) 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 0ac2e529..11cdd838 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 @@ -4,7 +4,7 @@ import nl.entreco.domain.BaseUsecase import nl.entreco.domain.common.executors.Background import nl.entreco.domain.common.executors.Foreground import nl.entreco.domain.repository.ImageRepository -import nl.entreco.domain.repository.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository import javax.inject.Inject /** @@ -12,7 +12,7 @@ import javax.inject.Inject */ class UpdateProfileUsecase @Inject constructor( private val imageRepository: ImageRepository, - private val profileRepository: ProfileRepository, + private val profileInfoRepository: ProfileInfoRepository, bg: Background, fg: Foreground) : BaseUsecase(bg, fg) { fun exec(req: UpdateProfileRequest, done: (UpdateProfileResponse) -> Unit, fail: (Throwable) -> Unit) { @@ -20,7 +20,7 @@ class UpdateProfileUsecase @Inject constructor( // Copy image to local file && resize val localImage = imageRepository.copyImageToPrivateAppData(req.image, req.size) - val profile = profileRepository.update(req.id, req.name, localImage, req.double) + val profile = profileInfoRepository.update(req.id, req.name, localImage, req.double) onUi { done(UpdateProfileResponse(profile)) } }, fail) } diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt similarity index 94% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecase.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt index fa3a36b5..d3fa4725 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecase.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.beta.connect +package nl.entreco.domain.purchases.connect import android.support.annotation.UiThread import nl.entreco.domain.BaseUsecase diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecase.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt similarity index 95% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecase.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt index 5d7a5e19..bae6e6a0 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecase.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecase.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.beta.connect +package nl.entreco.domain.purchases.connect import nl.entreco.domain.BaseUsecase import nl.entreco.domain.beta.Feature diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ArchiveRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ArchiveRepository.kt new file mode 100644 index 00000000..4bd35636 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ArchiveRepository.kt @@ -0,0 +1,6 @@ +package nl.entreco.domain.repository + + +interface ArchiveRepository { + fun archive(gameId: Long) : Int +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/BillingRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/BillingRepository.kt index d3358827..c9b01a2f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/BillingRepository.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/BillingRepository.kt @@ -16,11 +16,17 @@ interface BillingRepository { fun unbind() @WorkerThread - fun fetchDonations(): List + fun fetchDonationsExclAds(): List + + @WorkerThread + fun fetchDonationsInclAds(): List @WorkerThread fun donate(donation: Donation) : MakeDonationResponse @WorkerThread fun consume(token: String): Int + + @WorkerThread + fun fetchPurchasedItems(): List } \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/LiveStatRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/LiveStatRepository.kt new file mode 100644 index 00000000..20aae028 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/LiveStatRepository.kt @@ -0,0 +1,16 @@ +package nl.entreco.domain.repository + +import android.support.annotation.WorkerThread +import nl.entreco.domain.model.LiveStat + +/** + * Created by entreco on 16/01/2018. + */ +interface LiveStatRepository { + + @WorkerThread + fun fetchAllForGame(gameId: Long): Map + + @WorkerThread + fun fetchStat(turnId: Long, metaId: Long): LiveStat +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileInfoRepository.kt similarity index 91% rename from android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileRepository.kt rename to android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileInfoRepository.kt index afd73a52..578b927d 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileRepository.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileInfoRepository.kt @@ -6,7 +6,7 @@ import nl.entreco.domain.profile.Profile /** * Created by entreco on 23/02/2018. */ -interface ProfileRepository { +interface ProfileInfoRepository { @WorkerThread fun fetchAll(players: LongArray): List diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileStatRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileStatRepository.kt new file mode 100644 index 00000000..0feae7e4 --- /dev/null +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/ProfileStatRepository.kt @@ -0,0 +1,10 @@ +package nl.entreco.domain.repository + +import android.support.annotation.WorkerThread +import nl.entreco.domain.profile.ProfileStat + + +interface ProfileStatRepository { + @WorkerThread + fun fetchForPlayer(playerId: Long): ProfileStat +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/StatRepository.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/StatRepository.kt deleted file mode 100644 index 9340b455..00000000 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/repository/StatRepository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package nl.entreco.domain.repository - -import android.support.annotation.WorkerThread -import nl.entreco.domain.model.Stat - -/** - * Created by entreco on 16/01/2018. - */ -interface StatRepository { - - @WorkerThread - fun fetchAllForGame(gameId: Long): Map - - @WorkerThread - fun fetchStat(turnId: Long, metaId: Long): Stat -} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerRequest.kt index 6c08f3a3..38496fe4 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.setup.players /** * Created by Entreco on 02/01/2018. */ -data class CreatePlayerRequest(val name: String, val double: Int) \ No newline at end of file +class CreatePlayerRequest(val name: String, val double: Int) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerResponse.kt index 257d0579..8cf95c5f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/CreatePlayerResponse.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.model.players.Player /** * Created by entreco on 06/01/2018. */ -data class CreatePlayerResponse(val player: Player) \ No newline at end of file +class CreatePlayerResponse(val player: Player) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerRequest.kt index 89125a85..5c67258f 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.setup.players /** * Created by entreco on 17/03/2018. */ -data class DeletePlayerRequest(val id: Long) \ No newline at end of file +class DeletePlayerRequest(val id: Long) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerResponse.kt index 66b7c917..50b72143 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/DeletePlayerResponse.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.setup.players /** * Created by entreco on 17/03/2018. */ -data class DeletePlayerResponse(val id: Long) \ No newline at end of file +class DeletePlayerResponse(val id: Long) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersResponse.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersResponse.kt index 113a69e6..4a59a469 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersResponse.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/players/FetchExistingPlayersResponse.kt @@ -5,4 +5,4 @@ import nl.entreco.domain.model.players.Player /** * Created by entreco on 06/01/2018. */ -data class FetchExistingPlayersResponse(val players: List) \ No newline at end of file +class FetchExistingPlayersResponse(val players: List) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/settings/StoreSettingsRequest.kt b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/settings/StoreSettingsRequest.kt index 435a240b..1ed957e9 100644 --- a/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/settings/StoreSettingsRequest.kt +++ b/android/DartsScorecard/domain/src/main/java/nl/entreco/domain/setup/settings/StoreSettingsRequest.kt @@ -3,4 +3,4 @@ package nl.entreco.domain.setup.settings /** * Created by entreco on 04/01/2018. */ -data class StoreSettingsRequest(val sets: Int, val legs: Int, val min: Int, val max: Int, val score: Int) \ No newline at end of file +class StoreSettingsRequest(val sets: Int, val legs: Int, val min: Int, val max: Int, val score: Int) \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecaseTest.kt new file mode 100644 index 00000000..830f1d18 --- /dev/null +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/ad/FetchPurchasedItemsUsecaseTest.kt @@ -0,0 +1,75 @@ +package nl.entreco.domain.ad + +import com.nhaarman.mockito_kotlin.any +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.BillingRepository +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class FetchPurchasedItemsUsecaseTest { + + private var bg = TestBackground() + private var fg = TestForeground() + @Mock private lateinit var mockDone: (FetchPurchasedItemsResponse) -> Unit + @Mock private lateinit var mockFail: (Throwable) -> Unit + @Mock private lateinit var mockBillingRepo: BillingRepository + private lateinit var subject: FetchPurchasedItemsUsecase + + private var givenPurchases = emptyList() + + @Test + fun `it should report ok(false) if purchases is not empty`() { + givenPurchases("sku1", "sku2") + givenSubject() + whenFetchingSucceeds() + thenOkIsReported(false) + } + + @Test + fun `it should report ok(true) if purchases is empty`() { + givenPurchases() + givenSubject() + whenFetchingSucceeds() + thenOkIsReported(true) + } + + @Test + fun `it should report failure if purchases cannot be retrieved`() { + givenPurchases() + givenSubject() + whenFetchingFails() + thenFailureIsReported() + } + + private fun givenSubject() { + subject = FetchPurchasedItemsUsecase(mockBillingRepo, bg, fg) + } + + private fun givenPurchases(vararg skus: String) { + givenPurchases = skus.map { it } + } + + private fun whenFetchingSucceeds() { + whenever(mockBillingRepo.fetchPurchasedItems()).thenReturn(givenPurchases) + subject.exec(mockDone, mockFail) + } + + private fun whenFetchingFails() { + whenever(mockBillingRepo.fetchPurchasedItems()).thenThrow(RuntimeException("do'h")) + subject.exec(mockDone, mockFail) + } + + private fun thenOkIsReported(expected: Boolean) { + verify(mockDone).invoke(FetchPurchasedItemsResponse(expected)) + } + + private fun thenFailureIsReported() { + verify(mockFail).invoke(any()) + } +} diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecaseTest.kt index c7ac8340..01d35f1e 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/ConsumeDonationUsecaseTest.kt @@ -2,6 +2,7 @@ package nl.entreco.domain.beta.donations import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.verify +import com.nhaarman.mockito_kotlin.verifyZeroInteractions import com.nhaarman.mockito_kotlin.whenever import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.common.executors.TestForeground @@ -40,21 +41,33 @@ class ConsumeDonationUsecaseTest { @Test fun `it should notify callback of success`() { whenever(mockBillingRepository.consume(any())).thenReturn(1) - subject.exec(ConsumeDonationRequest(purchaseData, "sig"), done, fail) + subject.exec(ConsumeDonationRequest(purchaseData, "sig", true), done, fail) verify(done).invoke(any()) } @Test fun `it should notify callback of failure`() { whenever(mockBillingRepository.consume(any())).thenThrow(RuntimeException("Oh no you didn't")) - subject.exec(ConsumeDonationRequest(purchaseData, "sig"), done, fail) + subject.exec(ConsumeDonationRequest(purchaseData, "sig", true), done, fail) verify(fail).invoke(any()) } @Test fun `it should notify callback of failure when invalid json object`() { - subject.exec(ConsumeDonationRequest("thiz iz no json dude", "sig"), done, fail) + subject.exec(ConsumeDonationRequest("thiz iz no json dude", "sig", true), done, fail) verify(fail).invoke(any()) } + @Test + fun `it should not consume item when 'requiresConsumption is false'`() { + subject.exec(ConsumeDonationRequest(purchaseData, "sig", false), done, fail) + verifyZeroInteractions(mockBillingRepository) + } + + @Test + fun `it should notify success when 'requiresConsumption is false'`() { + subject.exec(ConsumeDonationRequest(purchaseData, "sig", false), done, fail) + verify(done).invoke(any()) + } + } diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/FetchDonationsUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/FetchDonationsUsecaseTest.kt index 70054753..b874c7f6 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/FetchDonationsUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/donations/FetchDonationsUsecaseTest.kt @@ -1,12 +1,14 @@ package nl.entreco.domain.beta.donations import com.nhaarman.mockito_kotlin.any +import com.nhaarman.mockito_kotlin.argumentCaptor import com.nhaarman.mockito_kotlin.verify import com.nhaarman.mockito_kotlin.whenever import nl.entreco.domain.beta.Donation import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.common.executors.TestForeground import nl.entreco.domain.repository.BillingRepository +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -27,34 +29,62 @@ class FetchDonationsUsecaseTest{ private lateinit var subject : FetchDonationsUsecase @Test - fun `it should report success if fetch donations succeeds`() { - givenSubject() - whenFetchinDonationsSucceeds() - thenSuccessIsReported() + fun `it should report success if fetch donations incl succeeds`() { + givenSubject(false) + whenFetchingDonationsInclSucceeds() + thenSuccessIsReported(false) } + + @Test + fun `it should report error if fetch donations incl fails`() { + givenSubject(false) + whenFetchingDonationsInclThrows(RuntimeException("play services not installed")) + thenErrorIsReported() + } + + @Test + fun `it should report success if fetch donations excl succeeds`() { + givenSubject(true) + whenFetchingDonationsExclSucceeds() + thenSuccessIsReported(true) + } + @Test - fun `it should report error if fetch donations fails`() { - givenSubject() - whenFetchinDonationsThrows(RuntimeException("play services not installed")) + fun `it should report error if fetch donations excl fails`() { + givenSubject(true) + whenFetchingDonationsExclThrows(RuntimeException("play services not installed")) thenErrorIsReported() } - private fun givenSubject() { + private fun givenSubject(purchasedBefore: Boolean) { + whenever(mockBillingRepo.fetchPurchasedItems()).thenReturn(if(purchasedBefore) listOf("1", "2") else emptyList()) subject = FetchDonationsUsecase(mockBillingRepo, bg, fg) } - private fun whenFetchinDonationsSucceeds(vararg donations: Donation) { - whenever(mockBillingRepo.fetchDonations()).thenReturn(listOf(*donations)) + private fun whenFetchingDonationsInclSucceeds(vararg donations: Donation) { + whenever(mockBillingRepo.fetchDonationsInclAds()).thenReturn(listOf(*donations)) + subject.exec(mockDone, mockFail) + } + + private fun whenFetchingDonationsExclSucceeds(vararg donations: Donation) { + whenever(mockBillingRepo.fetchDonationsExclAds()).thenReturn(listOf(*donations)) + subject.exec(mockDone, mockFail) + } + + private fun whenFetchingDonationsInclThrows(err: Throwable) { + whenever(mockBillingRepo.fetchDonationsInclAds()).thenThrow(err) subject.exec(mockDone, mockFail) } - private fun whenFetchinDonationsThrows(err: Throwable) { - whenever(mockBillingRepo.fetchDonations()).thenThrow(err) + private fun whenFetchingDonationsExclThrows(err: Throwable) { + whenever(mockBillingRepo.fetchDonationsExclAds()).thenThrow(err) subject.exec(mockDone, mockFail) } - private fun thenSuccessIsReported() { - verify(mockDone).invoke(any()) + private fun thenSuccessIsReported(expected: Boolean) { + val captor = argumentCaptor() + verify(mockDone).invoke(captor.capture()) + assertEquals(expected, captor.lastValue.needToBeConsumed) } private fun thenErrorIsReported() { diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/launch/RetrieveLatestGameUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/launch/RetrieveLatestGameUsecaseTest.kt index c889f596..88267478 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/launch/RetrieveLatestGameUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/launch/RetrieveLatestGameUsecaseTest.kt @@ -29,7 +29,7 @@ class RetrieveLatestGameUsecaseTest { private val createRequest = CreateGameRequest(501, 1, 2, 3) private lateinit var subject: RetrieveLatestGameUsecase - private lateinit var gavenLatestGame: FetchLatestGameResponse + private lateinit var givenLatestGame: FetchLatestGameResponse @Before fun setUp() { @@ -53,12 +53,12 @@ class RetrieveLatestGameUsecaseTest { } private fun givenLatestGameExists() { - gavenLatestGame = FetchLatestGameResponse(gameId, teamids, createRequest.startScore, createRequest.startIndex, createRequest.numLegs, createRequest.numSets) - whenever(mockGameRepository.fetchLatest()).thenReturn(gavenLatestGame) + givenLatestGame = FetchLatestGameResponse(gameId, teamids, createRequest.startScore, createRequest.startIndex, createRequest.numLegs, createRequest.numSets) + whenever(mockGameRepository.fetchLatest()).thenReturn(givenLatestGame) } private fun givenLatestGameDoesNotExists() { - gavenLatestGame = FetchLatestGameResponse(gameId, teamids, createRequest.startScore, createRequest.startIndex, createRequest.numLegs, createRequest.numSets) + givenLatestGame = FetchLatestGameResponse(gameId, teamids, createRequest.startScore, createRequest.startIndex, createRequest.numLegs, createRequest.numSets) whenever(mockGameRepository.fetchLatest()).thenThrow(IllegalStateException("no game available")) } @@ -67,7 +67,7 @@ class RetrieveLatestGameUsecaseTest { } private fun thenDoneIsCalled() { - verify(mockDone).invoke(gavenLatestGame) + verify(mockDone).invoke(givenLatestGame) } private fun thenErrorIsReported() { diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/StatTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/LiveStatTest.kt similarity index 61% rename from android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/StatTest.kt rename to android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/LiveStatTest.kt index 24266fe9..37133d08 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/StatTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/model/LiveStatTest.kt @@ -7,7 +7,7 @@ import org.junit.Test /** * Created by entreco on 23/01/2018. */ -class StatTest { +class LiveStatTest { @Test fun `it should handle adding nulls`() { @@ -47,39 +47,61 @@ class StatTest { assertEquals(3, n100s(1, 1, 1).n100) } - private fun totalScore(score: Int, vararg scores: Int): Stat { + @Test + fun `it should add 60-stats together`() { + assertEquals(6, n60s(1, 1, 0, 4).n60) + } + + @Test + fun `it should add 20-stats together`() { + assertEquals(14, n20s(8, 5, 1).n20) + } + + private fun totalScore(score: Int, vararg scores: Int): LiveStat { var stat = statWith(totalScore = score) scores.map { statWith(totalScore = it) }.forEach { stat += it } return stat } - private fun numDarts(dart: Int, vararg darts: Int): Stat { + private fun numDarts(dart: Int, vararg darts: Int): LiveStat { var stat = statWith(nDarts = dart) darts.map { statWith(nDarts = it) }.forEach { stat += it } return stat } - private fun n180s(dart: Int, vararg darts: Int): Stat { + private fun n180s(dart: Int, vararg darts: Int): LiveStat { var stat = statWith(n180 = dart) darts.map { statWith(n180 = it) }.forEach { stat += it } return stat } - private fun n140s(dart: Int, vararg darts: Int): Stat { + private fun n140s(dart: Int, vararg darts: Int): LiveStat { var stat = statWith(n140 = dart) darts.map { statWith(n140 = it) }.forEach { stat += it } return stat } - private fun n100s(dart: Int, vararg darts: Int): Stat { + private fun n100s(dart: Int, vararg darts: Int): LiveStat { var stat = statWith(n100 = dart) darts.map { statWith(n100 = it) }.forEach { stat += it } return stat } + private fun n60s(dart: Int, vararg darts: Int): LiveStat { + var stat = statWith(n60 = dart) + darts.map { statWith(n60 = it) }.forEach { stat += it } + return stat + } + + private fun n20s(dart: Int, vararg darts: Int): LiveStat { + var stat = statWith(n20 = dart) + darts.map { statWith(n20 = it) }.forEach { stat += it } + return stat + } + private fun statWith(playerId: Long = 0, totalScore: Int = 0, nDarts: Int = 0, - n180: Int = 0, n140: Int = 0, n100: Int = 0, nAtCheckout: Int = 0, nCheckouts: Int = 0, - nBreaks: Int = 0, highest: List = emptyList(), highestCo: List = emptyList()): Stat { - return Stat(playerId, totalScore, nDarts, n180, n140, n100, nAtCheckout, nCheckouts, nBreaks, highest, highestCo) + n180: Int = 0, n140: Int = 0, n100: Int = 0, n60: Int = 0, n20: Int = 0, nAtCheckout: Int = 0, nCheckouts: Int = 0, + nBreaks: Int = 0, highest: List = emptyList(), highestCo: List = emptyList()): LiveStat { + return LiveStat(playerId, totalScore, nDarts, n180, n140, n100, n60, n20, nAtCheckout, nCheckouts, nBreaks, highest, highestCo) } } \ No newline at end of file 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 f73a06d8..982a59c6 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.Logger +import nl.entreco.domain.common.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/Play01ResponseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01ResponseTest.kt index df113a33..59eb3b4f 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01ResponseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/Play01ResponseTest.kt @@ -29,7 +29,7 @@ class Play01ResponseTest { @Test fun `it should report equals on new instance`() { val response1 = Play01Response(mockGame, mockSettings, arrayOf(mockTeam1, mockTeam2), "") - val response2 = Play01Response(mockGame, mockSettings, arrayOf(mockTeam1, mockTeam2),"") + val response2 = Play01Response(mockGame, mockSettings, arrayOf(mockTeam1, mockTeam2), "") assertEquals(response1, response2) } 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 74c47e91..c6d52a98 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.Logger +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 @@ -115,7 +115,7 @@ class Play01UsecaseTest { thenUndoUsecaseIsExecuted() } - private fun whenStoringTurn(turn: Turn, state : State = State.NORMAL) { + private fun whenStoringTurn(turn: Turn, state: State = State.NORMAL) { expectedTurnRequest = StoreTurnRequest(0, gameId, turn, state) expectedTurnMeta = TurnMeta(1, 2, Score()) subject.storeTurnAndMeta(expectedTurnRequest, expectedTurnMeta, mockDone) @@ -169,6 +169,7 @@ class Play01UsecaseTest { givenMarkFinishRequest = MarkGameAsFinishedRequest(gameId) subject.markGameAsFinished(givenMarkFinishRequest) } + private fun whenUndoLastTurn() { expectedUndoRequest = UndoTurnRequest(1) subject.undoLastTurn(expectedUndoRequest, {}, {}) @@ -197,5 +198,4 @@ class Play01UsecaseTest { private fun thenUndoUsecaseIsExecuted() { verify(mockUndo).exec(eq(expectedUndoRequest), any(), any()) } - } diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/RetrieveTurnsUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/RetrieveTurnsUsecaseTest.kt index 50a34581..f841e369 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/RetrieveTurnsUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/start/RetrieveTurnsUsecaseTest.kt @@ -31,7 +31,7 @@ class RetrieveTurnsUsecaseTest { @Test fun `it should retrieve turns from database`() { givenUsecase(66) - givenStoredTurns(listOf(Pair(1L,Turn()), Pair(2L,Turn()))) + givenStoredTurns(listOf(Pair(1L, Turn()), Pair(2L, Turn()))) whenRetrievingTurnsSucceeds() thenOkIsExecuted() } @@ -39,7 +39,7 @@ class RetrieveTurnsUsecaseTest { @Test fun `it should report error when failing to retrieve turns from database`() { givenUsecase(66) - givenStoredTurns(listOf(Pair(1L,Turn()), Pair(2L,Turn()))) + givenStoredTurns(listOf(Pair(1L, Turn()), Pair(2L, Turn()))) whenRetrievingTurnsFails(RuntimeException("Something wrong with db")) thenFailIsExecuted() } diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatsUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatsUsecaseTest.kt index cc993c25..ad41fbe3 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatsUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatsUsecaseTest.kt @@ -5,7 +5,7 @@ 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.StatRepository +import nl.entreco.domain.repository.LiveStatRepository import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -16,7 +16,7 @@ import org.mockito.junit.MockitoJUnitRunner */ @RunWith(MockitoJUnitRunner::class) class FetchGameStatsUsecaseTest{ - @Mock private lateinit var mockStatRepository: StatRepository + @Mock private lateinit var mockLiveStatRepository: LiveStatRepository @Mock private lateinit var done: (FetchGameStatsResponse)->Unit @Mock private lateinit var fail: (Throwable)->Unit private val bg = TestBackground() @@ -45,7 +45,7 @@ class FetchGameStatsUsecaseTest{ } private fun givenSubject() { - subject = FetchGameStatsUsecase(mockStatRepository, bg, fg) + subject = FetchGameStatsUsecase(mockLiveStatRepository, bg, fg) } private fun whenFetchingStats() { @@ -54,19 +54,19 @@ class FetchGameStatsUsecaseTest{ } private fun whenFetchingStatsSucceeds() { - whenever(mockStatRepository.fetchAllForGame(givenGameId)).thenReturn(emptyMap()) + whenever(mockLiveStatRepository.fetchAllForGame(givenGameId)).thenReturn(emptyMap()) val req = FetchGameStatsRequest(givenGameId, "") subject.exec(req, done, fail) } private fun whenFetchingStatsFails(err: Throwable) { - whenever(mockStatRepository.fetchAllForGame(givenGameId)).thenThrow(err) + whenever(mockLiveStatRepository.fetchAllForGame(givenGameId)).thenThrow(err) val req = FetchGameStatsRequest(givenGameId, "") subject.exec(req, done, fail) } private fun thenStatsAreFetched(){ - verify(mockStatRepository).fetchAllForGame(givenGameId) + verify(mockLiveStatRepository).fetchAllForGame(givenGameId) } private fun thenDoneIsInvoked(){ diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchLiveStatUsecaseTest.kt similarity index 65% rename from android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatUsecaseTest.kt rename to android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchLiveStatUsecaseTest.kt index bda52bad..c052d6ea 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchGameStatUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/play/stats/FetchLiveStatUsecaseTest.kt @@ -5,8 +5,8 @@ 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.model.Stat -import nl.entreco.domain.repository.StatRepository +import nl.entreco.domain.model.LiveStat +import nl.entreco.domain.repository.LiveStatRepository import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -16,15 +16,15 @@ import org.mockito.junit.MockitoJUnitRunner * Created by entreco on 24/01/2018. */ @RunWith(MockitoJUnitRunner::class) -class FetchGameStatUsecaseTest { +class FetchLiveStatUsecaseTest { - @Mock private lateinit var mockStatRepository: StatRepository - @Mock private lateinit var done: (FetchGameStatResponse) -> Unit + @Mock private lateinit var mockLiveStatRepository: LiveStatRepository + @Mock private lateinit var done: (FetchLiveStatResponse) -> Unit @Mock private lateinit var fail: (Throwable) -> Unit - @Mock private lateinit var mockStat: Stat + @Mock private lateinit var mockLiveStat: LiveStat private val bg = TestBackground() private val fg = TestForeground() - private lateinit var subject: FetchGameStatUsecase + private lateinit var subject: FetchLiveStatUsecase private val givenTurnId: Long = 8888 private val givenMetaId: Long = 9999 @@ -51,28 +51,28 @@ class FetchGameStatUsecaseTest { } private fun givenSubject() { - subject = FetchGameStatUsecase(mockStatRepository, bg, fg) + subject = FetchLiveStatUsecase(mockLiveStatRepository, bg, fg) } private fun whenFetchingStats() { - val req = FetchGameStatRequest(givenTurnId, givenMetaId) + val req = FetchLiveStatRequest(givenTurnId, givenMetaId) subject.exec(req, done, fail) } private fun whenFetchingStatsSucceeds() { - whenever(mockStatRepository.fetchStat(givenTurnId, givenMetaId)).thenReturn(mockStat) - val req = FetchGameStatRequest(givenTurnId, givenMetaId) + whenever(mockLiveStatRepository.fetchStat(givenTurnId, givenMetaId)).thenReturn(mockLiveStat) + val req = FetchLiveStatRequest(givenTurnId, givenMetaId) subject.exec(req, done, fail) } private fun whenFetchingStatsFails(err: Throwable) { - whenever(mockStatRepository.fetchStat(givenTurnId, givenMetaId)).thenThrow(err) - val req = FetchGameStatRequest(givenTurnId, givenMetaId) + whenever(mockLiveStatRepository.fetchStat(givenTurnId, givenMetaId)).thenThrow(err) + val req = FetchLiveStatRequest(givenTurnId, givenMetaId) subject.exec(req, done, fail) } private fun thenStatsAreFetched() { - verify(mockStatRepository).fetchStat(givenTurnId, givenMetaId) + verify(mockLiveStatRepository).fetchStat(givenTurnId, givenMetaId) } private fun thenDoneIsInvoked() { diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/ProfileStatTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/ProfileStatTest.kt new file mode 100644 index 00000000..97c3856d --- /dev/null +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/ProfileStatTest.kt @@ -0,0 +1,26 @@ +package nl.entreco.domain.profile + +import org.junit.Assert.assertEquals +import org.junit.Test + +class ProfileStatTest { + + private lateinit var subject: ProfileStat + + @Test + fun getId() { + givenSubject(id = 180) + assertEquals(180, subject.playerId) + } + + @Test + fun getNumberOfGamesPlayed() { + givenSubject(numberOfGames = 8) + assertEquals(8, subject.numberOfGames) + } + + private fun givenSubject(id: Long = -2, numberOfGames: Int = -2) { + subject = ProfileStat(id, numberOfGames, 4, 8) + } + +} \ No newline at end of file diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecaseTest.kt new file mode 100644 index 00000000..2f9def85 --- /dev/null +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/archive/ArchiveStatsUsecaseTest.kt @@ -0,0 +1,69 @@ +package nl.entreco.domain.profile.archive + +import com.nhaarman.mockito_kotlin.* +import nl.entreco.domain.common.executors.TestBackground +import nl.entreco.domain.common.executors.TestForeground +import nl.entreco.domain.repository.ArchiveRepository +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class ArchiveStatsUsecaseTest { + + @Mock private lateinit var mockDone: (ArchiveStatsResponse) -> Unit + @Mock private lateinit var mockFail: (Throwable) -> Unit + @Mock private lateinit var mockArchiveRepository: ArchiveRepository + private lateinit var subject: ArchiveStatsUsecase + private val responseCaptor = argumentCaptor() + + @Test + fun `it should archive stats`() { + givenSubject() + whenArchivingStats(2) + thenArchiveIsCalled(2) + } + @Test + fun `it should report success when archiving succeeds`() { + givenSubject() + whenArchivingStatsSucceeds(1) + thenSuccessIsReported(1) + } + @Test + fun `it should report fail when archiving fails`() { + givenSubject() + whenArchivingStatsFails() + thenFailureIsReported() + } + + private fun givenSubject() { + subject = ArchiveStatsUsecase(mockArchiveRepository, TestBackground(), TestForeground()) + } + + private fun whenArchivingStats(gameId: Long) { + subject.exec(ArchiveStatsRequest(gameId), mockDone, mockFail) + } + + private fun whenArchivingStatsSucceeds(result: Int) { + whenever(mockArchiveRepository.archive(1)).thenReturn(result) + subject.exec(ArchiveStatsRequest(1), mockDone, mockFail) + } + + private fun whenArchivingStatsFails() { + whenever(mockArchiveRepository.archive(1)).thenThrow(RuntimeException("wtf")) + subject.exec(ArchiveStatsRequest(1), mockDone, mockFail) + } + + private fun thenArchiveIsCalled(expected: Long) { + verify(mockArchiveRepository).archive(expected) + } + + private fun thenSuccessIsReported(expected: Int) { + verify(mockDone).invoke(eq(ArchiveStatsResponse(expected))) + } + private fun thenFailureIsReported() { + verify(mockFail).invoke(any()) + } + +} diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/fetch/FetchProfileUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/fetch/FetchProfileUsecaseTest.kt index db03a030..53afa079 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/fetch/FetchProfileUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/fetch/FetchProfileUsecaseTest.kt @@ -5,7 +5,7 @@ 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.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -19,7 +19,7 @@ class FetchProfileUsecaseTest { private val bg = TestBackground() private val fg = TestForeground() - @Mock private lateinit var mockProfileRepo: ProfileRepository + @Mock private lateinit var mockProfileInfoRepo: ProfileInfoRepository @Mock private lateinit var mockDone: (FetchProfileResponse) -> Unit @Mock private lateinit var mockFail: (Throwable) -> Unit @@ -40,17 +40,17 @@ class FetchProfileUsecaseTest { } private fun givenSubject() { - subject = FetchProfileUsecase(mockProfileRepo, bg, fg) + subject = FetchProfileUsecase(mockProfileInfoRepo, bg, fg) } private fun whenFetchingProfileSucceeds() { val players = LongArray(4) - whenever(mockProfileRepo.fetchAll(players)).thenReturn(emptyList()) + whenever(mockProfileInfoRepo.fetchAll(players)).thenReturn(emptyList()) subject.exec(FetchProfileRequest(players), mockDone, mockFail) } private fun whenFetchingProfileFails() { - whenever(mockProfileRepo.fetchAll(any())).thenThrow(RuntimeException("Unable to fetch profile")) + whenever(mockProfileInfoRepo.fetchAll(any())).thenThrow(RuntimeException("Unable to fetch profile")) subject.exec(FetchProfileRequest(LongArray(4)), mockDone, mockFail) } diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/update/UpdateProfileUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/update/UpdateProfileUsecaseTest.kt index 61729acb..6b8c71c5 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/update/UpdateProfileUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/profile/update/UpdateProfileUsecaseTest.kt @@ -7,7 +7,7 @@ import nl.entreco.domain.common.executors.TestBackground import nl.entreco.domain.common.executors.TestForeground import nl.entreco.domain.profile.Profile import nl.entreco.domain.repository.ImageRepository -import nl.entreco.domain.repository.ProfileRepository +import nl.entreco.domain.repository.ProfileInfoRepository import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock @@ -25,7 +25,7 @@ class UpdateProfileUsecaseTest { @Mock private lateinit var mockDone: (UpdateProfileResponse) -> Unit @Mock private lateinit var mockFail: (Throwable) -> Unit @Mock private lateinit var mockImageRepository: ImageRepository - @Mock private lateinit var mockProfileService: ProfileRepository + @Mock private lateinit var mockProfileInfoService: ProfileInfoRepository private lateinit var subject: UpdateProfileUsecase @Test @@ -50,14 +50,14 @@ class UpdateProfileUsecaseTest { } private fun givenSubject() { - subject = UpdateProfileUsecase(mockImageRepository, mockProfileService, bg, fg) + subject = UpdateProfileUsecase(mockImageRepository, mockProfileInfoService, bg, fg) } private fun whenUpdatingProfileSucceeds(name: String = "name", image: String = "image") { whenever(mockImageRepository.copyImageToPrivateAppData(any(), any())).thenReturn(image) - whenever(mockProfileService.update(12, name, image, "12")).thenReturn(mockProfile) + whenever(mockProfileInfoService.update(12, name, image, "12")).thenReturn(mockProfile) subject.exec(UpdateProfileRequest(12, name, "12", image, 200F), mockDone, mockFail) - verify(mockProfileService).update(12, name, image, "12") + verify(mockProfileInfoService).update(12, name, image, "12") } private fun thenProfileIsReported() { diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecaseTest.kt similarity index 96% rename from android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecaseTest.kt rename to android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecaseTest.kt index 74346ee1..cf3ef0e2 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/ConnectToBillingUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/ConnectToBillingUsecaseTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.beta.connect +package nl.entreco.domain.purchases.connect import com.nhaarman.mockito_kotlin.verify import nl.entreco.domain.common.executors.TestBackground diff --git a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecaseTest.kt b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecaseTest.kt similarity index 98% rename from android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecaseTest.kt rename to android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecaseTest.kt index caaa2803..12ff98c4 100644 --- a/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/beta/connect/SubscribeToFeaturesUsecaseTest.kt +++ b/android/DartsScorecard/domain/src/test/java/nl/entreco/domain/purchases/connect/SubscribeToFeaturesUsecaseTest.kt @@ -1,4 +1,4 @@ -package nl.entreco.domain.beta.connect +package nl.entreco.domain.purchases.connect import com.nhaarman.mockito_kotlin.any import com.nhaarman.mockito_kotlin.argumentCaptor @@ -118,6 +118,6 @@ class SubscribeToFeaturesUsecaseTest { } private fun f(title: String, required: Int, votes: Int): Feature { - return Feature("reference", title, "desc", "image", "",required, votes) + return Feature("reference", title, "desc", "image", "",required, votes, "") } } diff --git a/android/DartsScorecard/scripts/dependencies.gradle b/android/DartsScorecard/scripts/dependencies.gradle index 5df4c3b4..1b83e812 100644 --- a/android/DartsScorecard/scripts/dependencies.gradle +++ b/android/DartsScorecard/scripts/dependencies.gradle @@ -34,8 +34,8 @@ ext.versionName = { -> ext { - kotlinVersion = '1.2.31' - gradleVersion = '3.1.0' + kotlinVersion = '1.2.41' + gradleVersion = '3.1.2' gmsVersion = '3.2.0' dexCountVersion = '0.8.2' detektVersion = '1.0.0.RC6-3' @@ -52,20 +52,20 @@ ext { versionName = versionName() dependencies = [ - support = '27.1.0', + support = '27.1.1', daggerVersion = '2.13', - constraint = '1.0.2', + constraint = '1.1.0', architecture = '1.1.1', - room = '1.0.0', - firebase = '12.0.1', - picasso = '2.5.1', + room = '1.1.0', + firebase = '15.0.0', + picasso = '2.71828', circleImageView = '2.2.0', crash = '2.9.1@aar', gson = '2.8.2', + leakCanary = '1.5.4', junit = '4.12', mockito = '2.12.0', mockitoKotlin = '1.5.0', - tddUtils = 'v0.1', espressoCore = '3.0.1', espressoRunner = '1.0.1' ] diff --git a/design/PDC-World-Darts-Championship-Alexandra-Palace-2017.jpg b/design/PDC-World-Darts-Championship-Alexandra-Palace-2017.jpg new file mode 100644 index 00000000..2bc9f750 Binary files /dev/null and b/design/PDC-World-Darts-Championship-Alexandra-Palace-2017.jpg differ diff --git a/design/launcher_v2.sketch b/design/launcher_v2.sketch index 9366ec2c..918e8012 100644 Binary files a/design/launcher_v2.sketch and b/design/launcher_v2.sketch differ diff --git a/design/notif.png b/design/notif.png new file mode 100644 index 00000000..2c109468 Binary files /dev/null and b/design/notif.png differ diff --git a/design/notif_inverse.png b/design/notif_inverse.png new file mode 100644 index 00000000..7bf00e71 Binary files /dev/null and b/design/notif_inverse.png differ diff --git a/design/scoreboard_sketch.sketch b/design/scoreboard_sketch.sketch index 1a6e5736..cdaff93c 100644 Binary files a/design/scoreboard_sketch.sketch and b/design/scoreboard_sketch.sketch differ diff --git a/site-profile/README.txt b/site-profile/README.txt new file mode 100644 index 00000000..bd7666c1 --- /dev/null +++ b/site-profile/README.txt @@ -0,0 +1,5 @@ +A Pen created at CodePen.io. You can find this one at https://codepen.io/anon/pen/aYQqOL. + + When designing a pricing table for a product or service, your job as a web designer/developer is to make sure that the table is easy to understand, intuitive and clear. This way, you will help users to choose the best plan for theirs needs. + +So, in this article you’ll learn how to build an awesome CSS3 pricing table, with no images and minimal HTML markup. \ No newline at end of file diff --git a/site-profile/css/style.css b/site-profile/css/style.css new file mode 100644 index 00000000..af9815d3 --- /dev/null +++ b/site-profile/css/style.css @@ -0,0 +1,179 @@ +body{ + background: #303030; +} + +#pricing-table { + margin: 100px auto; + text-align: center; + width: 222px; /* total computed width = 222 x 3 + 226 */ +} + +#pricing-table .plan { + font: 12px 'Lucida Sans', 'trebuchet MS', Arial, Helvetica; + text-shadow: 0 1px rgba(255,255,255,.8); + background: #fff; + border: 1px solid #ddd; + color: #333; + padding: 20px; + width: 180px; /* plan width = 180 + 20 + 20 + 1 + 1 = 222px */ + float: left; + position: relative; +} + +#pricing-table #most-popular { + z-index: 2; + top: -13px; + border-width: 3px; + padding: 30px 20px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border-radius: 5px; + -moz-box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15); + -webkit-box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15); + box-shadow: 20px 0 10px -10px rgba(0, 0, 0, .15), -20px 0 10px -10px rgba(0, 0, 0, .15); +} + +#pricing-table .plan:nth-child(1) { + -moz-border-radius: 5px 0 0 5px; + -webkit-border-radius: 5px 0 0 5px; + border-radius: 5px 0 0 5px; +} + +#pricing-table .plan:nth-child(4) { + -moz-border-radius: 0 5px 5px 0; + -webkit-border-radius: 0 5px 5px 0; + border-radius: 0 5px 5px 0; +} + +/* --------------- */ + +#pricing-table h3 { + font-size: 20px; + font-weight: normal; + padding: 20px; + margin: -20px -20px 50px -20px; + background-color: #eee; + background-image: -moz-linear-gradient(#fff,#eee); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#eee)); + background-image: -webkit-linear-gradient(#fff, #eee); + background-image: -o-linear-gradient(#fff, #eee); + background-image: -ms-linear-gradient(#fff, #eee); + background-image: linear-gradient(#fff, #eee); +} + +#pricing-table #most-popular h3 { + background-color: #ddd; + background-image: -moz-linear-gradient(#eee,#ddd); + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#ddd)); + background-image: -webkit-linear-gradient(#eee, #ddd); + background-image: -o-linear-gradient(#eee, #ddd); + background-image: -ms-linear-gradient(#eee, #ddd); + background-image: linear-gradient(#eee, #ddd); + margin-top: -30px; + padding-top: 30px; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +#pricing-table .plan:nth-child(1) h3 { + -moz-border-radius: 5px 0 0 0; + -webkit-border-radius: 5px 0 0 0; + border-radius: 5px 0 0 0; +} + +#pricing-table .plan:nth-child(4) h3 { + -moz-border-radius: 0 5px 0 0; + -webkit-border-radius: 0 5px 0 0; + border-radius: 0 5px 0 0; +} + +#pricing-table h3 span { + display: block; + font: bold 25px/100px Georgia, Serif; + color: #777; + background: #fff; + border: 5px solid #fff; + height: 100px; + width: 100px; + margin: 10px auto -65px; + -moz-border-radius: 100px; + -webkit-border-radius: 100px; + border-radius: 100px; + -moz-box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset; + -webkit-box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset; + box-shadow: 0 5px 20px #ddd inset, 0 3px 0 #999 inset; +} + +/* --------------- */ + +#pricing-table ul { + margin: 20px 0 0 0; + padding: 0; + list-style: none; +} + +#pricing-table li { + border-top: 1px solid #ddd; + padding: 10px 0; +} + +/* --------------- */ + +#pricing-table .signup { + position: relative; + padding: 8px 20px; + margin: 20px 0 0 0; + color: #fff; + font: bold 14px Arial, Helvetica; + text-transform: uppercase; + text-decoration: none; + display: inline-block; + background-color: #72ce3f; + background-image: -moz-linear-gradient(#72ce3f, #62bc30); + background-image: -webkit-gradient(linear, left top, left bottom, from(#72ce3f), to(#62bc30)); + background-image: -webkit-linear-gradient(#72ce3f, #62bc30); + background-image: -o-linear-gradient(#72ce3f, #62bc30); + background-image: -ms-linear-gradient(#72ce3f, #62bc30); + background-image: linear-gradient(#72ce3f, #62bc30); + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + text-shadow: 0 1px 0 rgba(0,0,0,.3); + -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7); + -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7); + box-shadow: 0 1px 0 rgba(255, 255, 255, .5), 0 2px 0 rgba(0, 0, 0, .7); +} + +#pricing-table .signup:hover { + background-color: #62bc30; + background-image: -moz-linear-gradient(#62bc30, #72ce3f); + background-image: -webkit-gradient(linear, left top, left bottom, from(#62bc30), to(#72ce3f)); + background-image: -webkit-linear-gradient(#62bc30, #72ce3f); + background-image: -o-linear-gradient(#62bc30, #72ce3f); + background-image: -ms-linear-gradient(#62bc30, #72ce3f); + background-image: linear-gradient(#62bc30, #72ce3f); +} + +#pricing-table .signup:active, #pricing-table .signup:focus { + background: #62bc30; + top: 2px; + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset; + box-shadow: 0 0 3px rgba(0, 0, 0, .7) inset; +} + +/* --------------- */ + +.clear:before, .clear:after { + content:""; + display:table +} + +.clear:after { + clear:both +} + +.clear { + zoom:1 +} \ No newline at end of file diff --git a/site-profile/index.html b/site-profile/index.html new file mode 100644 index 00000000..cd0d3b31 --- /dev/null +++ b/site-profile/index.html @@ -0,0 +1,42 @@ + + + + + + Darts Scorecard + + + + + + + +
+ + + +
+ + + + + + + diff --git a/site-profile/index.php b/site-profile/index.php new file mode 100644 index 00000000..4ca71b6f --- /dev/null +++ b/site-profile/index.php @@ -0,0 +1,39 @@ + + + + + + Darts Scorecard + + + + + + +
+ + + + +
+ + + + + + + diff --git a/site-profile/js/index.js b/site-profile/js/index.js new file mode 100644 index 00000000..deeee63e --- /dev/null +++ b/site-profile/js/index.js @@ -0,0 +1 @@ +/* original post: http://www.red-team-design.com/css3-pricing-table */ \ No newline at end of file diff --git a/site-profile/license.txt b/site-profile/license.txt new file mode 100644 index 00000000..f7e45325 --- /dev/null +++ b/site-profile/license.txt @@ -0,0 +1,16 @@ + + + diff --git a/site-profile/profile.php b/site-profile/profile.php new file mode 100644 index 00000000..699067ed --- /dev/null +++ b/site-profile/profile.php @@ -0,0 +1,11 @@ + \ No newline at end of file