diff --git a/android/DartsScorecard/app/build.gradle b/android/DartsScorecard/app/build.gradle
index 6c2b7b96..00300d56 100644
--- a/android/DartsScorecard/app/build.gradle
+++ b/android/DartsScorecard/app/build.gradle
@@ -46,6 +46,7 @@ dependencies {
implementation "com.google.firebase:firebase-firestore:$firebase"
implementation "android.arch.lifecycle:extensions:$architecture"
implementation "android.arch.persistence.room:runtime:$room"
+ implementation "com.github.yalantis:jellytoolbar:$jelly"
implementation "com.github.bumptech.glide:glide:$glide"
implementation "de.hdodenhof:circleimageview:$circleImageView"
implementation("com.crashlytics.sdk.android:crashlytics:$crash") {
diff --git a/android/DartsScorecard/app/src/main/AndroidManifest.xml b/android/DartsScorecard/app/src/main/AndroidManifest.xml
index f6d031e4..cb4fe281 100644
--- a/android/DartsScorecard/app/src/main/AndroidManifest.xml
+++ b/android/DartsScorecard/app/src/main/AndroidManifest.xml
@@ -47,6 +47,10 @@
+
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 03a9c8bf..44413956 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
@@ -9,10 +9,12 @@ import android.preference.PreferenceManager
import android.support.annotation.StringRes
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
+import android.view.MenuItem
import nl.entreco.dartsscorecard.App
import nl.entreco.dartsscorecard.R
import nl.entreco.dartsscorecard.di.viewmodel.ViewModelComponent
import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule
+import nl.entreco.dartsscorecard.wtf.WtfActivity
/**
* Created by Entreco on 14/11/2017.
@@ -56,6 +58,16 @@ abstract class ViewModelActivity : AppCompatActivity() {
styler.switch()
}
+ override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+ return when (item?.itemId) {
+ R.id.menu_faq -> {
+ WtfActivity.launch(this)
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
protected fun initToolbar(toolbar: Toolbar, @StringRes title: Int = R.string.app_name, showHomeEnabled: Boolean = true) {
setSupportActionBar(toolbar)
setTitle(title)
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 71b36793..945e6ff8 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
@@ -11,6 +11,7 @@ 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.view.Menu
import android.view.MenuItem
import nl.entreco.dartsscorecard.R
import nl.entreco.dartsscorecard.base.ViewModelActivity
@@ -64,6 +65,11 @@ class BetaActivity : ViewModelActivity(), DonateCallback, BetaAnimator.Swapper {
viewModel.unsubscribe(this)
}
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.beta, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
override fun lifeCycle(): Lifecycle {
return lifecycle
}
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 6415ce7a..9d550a1d 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
@@ -15,7 +15,6 @@ class BetaViewModel @Inject constructor(private val subscribeToFeaturesUsecase:
private val features: MutableLiveData> = MutableLiveData()
-
fun refresh() {
subscribeToFeaturesUsecase.subscribe({
features.value = it
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 6208004b..f075aa86 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
@@ -18,7 +18,7 @@ import javax.inject.Inject
* Created by entreco on 08/02/2018.
*/
class DonateViewModel @Inject constructor(
- private val donateCallback: DonateCallback,
+ private var donateCallback: DonateCallback?,
private val connectToBillingUsecase: ConnectToBillingUsecase,
private val fetchDonationsUsecase: FetchDonationsUsecase,
private val makeDonation: MakeDonationUsecase,
@@ -26,7 +26,7 @@ class DonateViewModel @Inject constructor(
private val analytics: Analytics) : BaseViewModel(), LifecycleObserver {
init {
- donateCallback.lifeCycle().addObserver(this)
+ donateCallback?.lifeCycle()?.addObserver(this)
}
internal var productId: String = ""
@@ -42,7 +42,7 @@ class DonateViewModel @Inject constructor(
}
private fun onStartMakeDonation(): (MakeDonationResponse) -> Unit = { response ->
- donateCallback.makeDonation(response)
+ donateCallback?.makeDonation(response)
}
fun onMakeDonationSuccess(data: Intent?) {
@@ -79,7 +79,7 @@ class DonateViewModel @Inject constructor(
private fun donationDone(response: ConsumeDonationResponse) {
donationWithId(response)?.let { donation ->
analytics.trackPurchase(donation, response.orderId)
- donateCallback.onDonationMade(donation)
+ donateCallback?.onDonationMade(donation)
}
}
@@ -126,6 +126,11 @@ class DonateViewModel @Inject constructor(
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun destroy() {
- donateCallback.lifeCycle().removeObserver(this)
+ donateCallback?.lifeCycle()?.removeObserver(this)
+ }
+
+ override fun onCleared() {
+ donateCallback = null
+ super.onCleared()
}
}
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 5f2de695..433c0374 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
@@ -13,9 +13,12 @@ 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.FaqApiModule
import nl.entreco.dartsscorecard.di.viewmodel.api.FeatureApiModule
import nl.entreco.dartsscorecard.di.viewmodel.db.*
import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule
+import nl.entreco.dartsscorecard.di.wtf.WtfComponent
+import nl.entreco.dartsscorecard.di.wtf.WtfModule
/**
* Created by Entreco on 14/11/2017.
@@ -23,13 +26,14 @@ import nl.entreco.dartsscorecard.di.viewmodel.threading.ThreadingModule
@ActivityScope
@Subcomponent(modules = [(ViewModelModule::class), (ThreadingModule::class), (AdModule::class),
(GameDbModule::class), (PlayerDbModule::class), (TurnDbModule::class),
- (MetaDbModule::class), (StatDbModule::class), (FeatureApiModule::class)])
+ (MetaDbModule::class), (StatDbModule::class), (FeatureApiModule::class), (FaqApiModule::class)])
interface ViewModelComponent {
// Where can this be used
fun plus(module: LaunchModule): LaunchComponent
fun plus(module: BetaModule): BetaComponent
+ fun plus(module: WtfModule): WtfComponent
fun plus(module: Setup01Module): Setup01Component
fun plus(module: EditPlayerModule): EditPlayerComponent
fun plus(module: Play01Module): Play01Component
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt
new file mode 100644
index 00000000..98147d80
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/viewmodel/api/FaqApiModule.kt
@@ -0,0 +1,17 @@
+package nl.entreco.dartsscorecard.di.viewmodel.api
+
+import com.google.firebase.firestore.FirebaseFirestore
+import dagger.Module
+import dagger.Provides
+import nl.entreco.data.wtf.RemoteWtfRepository
+import nl.entreco.domain.common.log.Logger
+import nl.entreco.domain.repository.WtfRepository
+
+@Module
+class FaqApiModule {
+
+ @Provides
+ fun provideRemoteFaqRepository(db: FirebaseFirestore, logger: Logger): WtfRepository {
+ return RemoteWtfRepository(db, logger)
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt
new file mode 100644
index 00000000..b3a7698c
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfComponent.kt
@@ -0,0 +1,12 @@
+package nl.entreco.dartsscorecard.di.wtf
+
+import dagger.Subcomponent
+import nl.entreco.dartsscorecard.wtf.WtfAdapter
+import nl.entreco.dartsscorecard.wtf.WtfViewModel
+
+@WtfScope
+@Subcomponent(modules = [(WtfModule::class)])
+interface WtfComponent {
+ fun viewModel(): WtfViewModel
+ fun adapter(): WtfAdapter
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt
new file mode 100644
index 00000000..60db3918
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfModule.kt
@@ -0,0 +1,6 @@
+package nl.entreco.dartsscorecard.di.wtf
+
+import dagger.Module
+
+@Module
+class WtfModule
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt
new file mode 100644
index 00000000..60b9eb56
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/wtf/WtfScope.kt
@@ -0,0 +1,7 @@
+package nl.entreco.dartsscorecard.di.wtf
+
+import javax.inject.Scope
+
+@Scope
+@Retention(AnnotationRetention.RUNTIME)
+annotation class WtfScope
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt
index 683b94d3..9b6fb7df 100644
--- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/launch/LaunchViewModel.kt
@@ -7,6 +7,7 @@ import nl.entreco.dartsscorecard.beta.BetaActivity
import nl.entreco.dartsscorecard.play.Play01Activity
import nl.entreco.dartsscorecard.profile.select.SelectProfileActivity
import nl.entreco.dartsscorecard.setup.Setup01Activity
+import nl.entreco.dartsscorecard.wtf.WtfActivity
import nl.entreco.domain.launch.FetchLatestGameResponse
import nl.entreco.domain.launch.RetrieveLatestGameUsecase
import nl.entreco.domain.setup.game.CreateGameResponse
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/profile/select/SelectProfileActivity.kt
index 4177fdcd..fbfbf138 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
@@ -9,6 +9,7 @@ import android.support.v7.widget.DefaultItemAnimator
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
+import android.view.Menu
import nl.entreco.dartsscorecard.R
import nl.entreco.dartsscorecard.base.ViewModelActivity
import nl.entreco.dartsscorecard.databinding.ActivitySelectProfileBinding
@@ -63,6 +64,11 @@ class SelectProfileActivity : ViewModelActivity() {
swipeToDeleteHelper.attachToRecyclerView(recyclerView)
}
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.select, menu)
+ return super.onCreateOptionsMenu(menu)
+ }
+
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_VIEW && resultCode == Activity.RESULT_OK) {
viewModel.reload(adapter)
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt
new file mode 100644
index 00000000..45b473e3
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfActivity.kt
@@ -0,0 +1,107 @@
+package nl.entreco.dartsscorecard.wtf
+
+import android.content.Context
+import android.content.Intent
+import android.databinding.DataBindingUtil
+import android.os.Bundle
+import android.support.v7.widget.DefaultItemAnimator
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.Toolbar
+import android.view.LayoutInflater
+import android.view.MenuItem
+import com.yalantis.jellytoolbar.listener.JellyListener
+import nl.entreco.dartsscorecard.R
+import nl.entreco.dartsscorecard.base.ViewModelActivity
+import nl.entreco.dartsscorecard.databinding.ActivityWtfBinding
+import nl.entreco.dartsscorecard.databinding.SearchbarBinding
+import nl.entreco.dartsscorecard.di.wtf.WtfComponent
+import nl.entreco.dartsscorecard.di.wtf.WtfModule
+import android.support.v4.content.ContextCompat
+import android.view.WindowManager
+import android.view.inputmethod.InputMethodManager
+
+
+class WtfActivity : ViewModelActivity() {
+
+ private lateinit var binding: ActivityWtfBinding
+ private lateinit var searchBinding: SearchbarBinding
+ private val component: WtfComponent by componentProvider { it.plus(WtfModule()) }
+ private val viewModel: WtfViewModel by viewModelProvider { component.viewModel() }
+ private val adapter: WtfAdapter by lazy { component.adapter() }
+
+ private val jellyListener by lazy {
+ object : JellyListener() {
+ override fun onCancelIconClicked() {
+ val searchField = searchBinding.searchField
+ if (searchField.text.isEmpty()) {
+ binding.includeToolbar.toolbar.collapse()
+ val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+ imm.hideSoftInputFromWindow(searchField.windowToken, 0)
+ } else {
+ searchField.text.clear()
+ }
+ }
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_wtf)
+ binding.viewModel = viewModel
+
+ initJellyBar()
+ initToolbar(toolbar(binding), R.string.title_wtf)
+ initRecyclerView(binding)
+ }
+
+ private fun initJellyBar() {
+ binding.includeToolbar.toolbar.jellyListener = jellyListener
+ searchBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.searchbar, null, false)
+ searchBinding.listener = adapter
+ binding.includeToolbar.toolbar.contentView = searchBinding.root
+ }
+
+ private fun initRecyclerView(binding: ActivityWtfBinding) {
+ val recyclerView = binding.wtfRecyclerView
+ recyclerView.setHasFixedSize(true)
+ recyclerView.setItemViewCacheSize(20)
+ recyclerView.layoutManager = GridLayoutManager(binding.root.context, 1)
+ recyclerView.itemAnimator = DefaultItemAnimator()
+ recyclerView.isDrawingCacheEnabled = true
+ recyclerView.adapter = adapter
+ }
+
+ private fun toolbar(binding: ActivityWtfBinding): Toolbar {
+ return binding.includeToolbar.toolbar.toolbar!!
+ }
+
+ override fun onResume() {
+ super.onResume()
+ viewModel.subscribe(this, adapter)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ viewModel.unsubscribe(this)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+ return when (item?.itemId) {
+ android.R.id.home -> {
+ onBackPressed()
+ true
+ }
+ else -> super.onOptionsItemSelected(item)
+ }
+ }
+
+ companion object {
+
+ @JvmStatic
+ fun launch(context: Context) {
+ val intent = Intent(context, WtfActivity::class.java)
+ context.startActivity(intent)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt
new file mode 100644
index 00000000..14d93c65
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfAdapter.kt
@@ -0,0 +1,111 @@
+package nl.entreco.dartsscorecard.wtf
+
+import android.arch.lifecycle.Observer
+import android.databinding.DataBindingUtil
+import android.support.v7.util.DiffUtil
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import nl.entreco.dartsscorecard.R
+import nl.entreco.dartsscorecard.base.TestableAdapter
+import nl.entreco.dartsscorecard.databinding.WtfViewBinding
+import nl.entreco.domain.common.executors.Background
+import nl.entreco.domain.common.executors.Foreground
+import nl.entreco.domain.wtf.SubmitViewedItemRequest
+import nl.entreco.domain.wtf.SubmitViewedItemUsecase
+import nl.entreco.domain.wtf.WtfItem
+import java.util.*
+import java.util.Locale.filter
+import javax.inject.Inject
+
+class WtfAdapter @Inject constructor(private val bg: Background, private val fg: Foreground,
+ private val submitViewedItemUsecase: SubmitViewedItemUsecase) : TestableAdapter(), Observer>, WtfToggler, WtfSearchable {
+
+ private var searchText : String = ""
+ private var allItems: MutableSet = mutableSetOf()
+ private val visibleItems: MutableList = mutableListOf()
+ private val queue: Queue> = ArrayDeque()
+ private var expandedItem: String? = null
+ private val lock: Any = Any()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WtfView {
+ val inflater = LayoutInflater.from(parent.context)
+ val binding = DataBindingUtil.inflate(inflater, R.layout.wtf_view, parent, false)
+ return WtfView(binding)
+ }
+
+ override fun onBindViewHolder(holder: WtfView, position: Int) {
+
+ synchronized(lock) {
+ val currentItem = visibleItems[position]
+ holder.bind(currentItem, currentItem.docId != expandedItem, this)
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return visibleItems.size
+ }
+
+ override fun search(text: CharSequence) {
+
+ if (text.isNotEmpty() && text.length >= 3) {
+ searchText = text.toString().toLowerCase()
+ onChanged(allItems.toList())
+ } else {
+ clearSearch()
+ }
+ }
+
+ private fun clearSearch() {
+ searchText = ""
+ onChanged(allItems.toList())
+ }
+
+ override fun toggle(item: WtfItem) {
+ synchronized(lock) {
+ expandedItem = if (item.docId == expandedItem) null
+ else item.docId
+ notifyItemRangeChanged(0, visibleItems.size)
+ submitViewedItemUsecase.exec(SubmitViewedItemRequest(item.docId))
+ }
+ }
+
+ override fun onChanged(features: List?) {
+ if (features != null) {
+ queue.add(features)
+ if (queue.size <= 1) {
+ calculateDiff(features)
+ }
+ }
+ }
+
+ private fun calculateDiff(features: List) {
+ bg.post(Runnable {
+ allItems.addAll(features)
+ val filtSort = features.filter { doFilter(it, searchText) }.sortedByDescending { score(it, searchText) }
+ val diff = DiffUtil.calculateDiff(WtfDiffCalculator(visibleItems, filtSort), true)
+ fg.post(Runnable {
+ queue.remove()
+ updateItems(filtSort, diff)
+ if (queue.size > 0) {
+ calculateDiff(queue.peek())
+ }
+ })
+ })
+ }
+
+ private fun doFilter(item: WtfItem, searchText: String): Boolean {
+ if(searchText.isBlank()) return true
+ return item.title.toLowerCase().contains(searchText) || item.description.toLowerCase().contains(searchText)
+ }
+ private fun score(item: WtfItem, searchText: String): Int {
+ if(searchText.isBlank()) return 0
+ return if(item.title.toLowerCase().contains(searchText)) 10 else 0 +
+ if(item.description.toLowerCase().contains(searchText)) 5 else 0
+ }
+
+ private fun updateItems(features: List, diff: DiffUtil.DiffResult) {
+ visibleItems.clear()
+ visibleItems.addAll(features)
+ diff.dispatchUpdatesTo(this)
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt
new file mode 100644
index 00000000..4dfab971
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfDiffCalculator.kt
@@ -0,0 +1,22 @@
+package nl.entreco.dartsscorecard.wtf
+
+import android.support.v7.util.DiffUtil
+import nl.entreco.domain.wtf.WtfItem
+
+class WtfDiffCalculator(private val old: List, private val new: List) : DiffUtil.Callback() {
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ return old[oldItemPosition].docId == new[newItemPosition].docId
+ }
+
+ override fun getOldListSize(): Int {
+ return old.size
+ }
+
+ override fun getNewListSize(): Int {
+ return new.size
+ }
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+ return old[oldItemPosition] == new[newItemPosition]
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt
new file mode 100644
index 00000000..1ee12716
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfModel.kt
@@ -0,0 +1,38 @@
+package nl.entreco.dartsscorecard.wtf
+
+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.domain.wtf.WtfItem
+
+class WtfModel(private val item: WtfItem, private val toggler: WtfToggler, collapse: Boolean = true) {
+ val title = ObservableField(item.title)
+ val description = ObservableField(item.description)
+ val image = ObservableField(item.image)
+ val showImage = ObservableInt(if(!collapse && item.image?.isNotBlank() == true) View.VISIBLE else View.GONE)
+ val showVideo = ObservableInt(if(!collapse && item.video?.isNotBlank() == true) View.VISIBLE else View.GONE)
+ val collapsed = ObservableBoolean(collapse)
+
+ fun launchVideo(view: View){
+ if(showVideo.get() == View.VISIBLE){
+ val uri = Uri.parse(item.video)
+ 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 toggle(){
+ toggler.toggle(item)
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt
new file mode 100644
index 00000000..6d7682b1
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfSearchable.kt
@@ -0,0 +1,5 @@
+package nl.entreco.dartsscorecard.wtf
+
+interface WtfSearchable {
+ fun search(text: CharSequence)
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt
new file mode 100644
index 00000000..a3c1205e
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfToggler.kt
@@ -0,0 +1,7 @@
+package nl.entreco.dartsscorecard.wtf
+
+import nl.entreco.domain.wtf.WtfItem
+
+interface WtfToggler {
+ fun toggle(item: WtfItem)
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt
new file mode 100644
index 00000000..f95da599
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfView.kt
@@ -0,0 +1,12 @@
+package nl.entreco.dartsscorecard.wtf
+
+import android.support.v7.widget.RecyclerView
+import nl.entreco.dartsscorecard.databinding.WtfViewBinding
+import nl.entreco.domain.wtf.WtfItem
+
+class WtfView(private val binding: WtfViewBinding) : RecyclerView.ViewHolder(binding.root) {
+ fun bind(item: WtfItem, collapsed: Boolean, toggler: WtfToggler) {
+ binding.wtf = WtfModel(item, toggler, collapsed)
+ binding.executePendingBindings()
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt
new file mode 100644
index 00000000..53556ed1
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/wtf/WtfViewModel.kt
@@ -0,0 +1,33 @@
+package nl.entreco.dartsscorecard.wtf
+
+import android.arch.lifecycle.LifecycleOwner
+import android.arch.lifecycle.MutableLiveData
+import android.arch.lifecycle.Observer
+import nl.entreco.dartsscorecard.base.BaseViewModel
+import nl.entreco.domain.beta.Feature
+import nl.entreco.domain.purchases.connect.SubscribeToFeaturesUsecase
+import nl.entreco.domain.wtf.SubscribeToWtfsUsecase
+import nl.entreco.domain.wtf.WtfItem
+import javax.inject.Inject
+
+class WtfViewModel @Inject constructor(private val subscribeToWtfUsecase: SubscribeToWtfsUsecase) : BaseViewModel() {
+
+ private val items: MutableLiveData> = MutableLiveData()
+
+ fun refresh() {
+ subscribeToWtfUsecase.subscribe({
+ items.value = it
+ }, {})
+ }
+
+ fun subscribe(owner: LifecycleOwner, observer: Observer>) {
+ items.observe(owner, observer)
+ refresh()
+ }
+
+ fun unsubscribe(owner: LifecycleOwner) {
+ items.removeObservers(owner)
+ items.value = emptyList()
+ subscribeToWtfUsecase.unsubscribe()
+ }
+}
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/anim/layout_animation_from_bottom.xml b/android/DartsScorecard/app/src/main/res/anim/layout_animation_from_bottom.xml
index 441de770..7e4802a5 100644
--- a/android/DartsScorecard/app/src/main/res/anim/layout_animation_from_bottom.xml
+++ b/android/DartsScorecard/app/src/main/res/anim/layout_animation_from_bottom.xml
@@ -2,4 +2,4 @@
+ android:delay="8%" />
diff --git a/android/DartsScorecard/app/src/main/res/drawable/faq_image_bg.xml b/android/DartsScorecard/app/src/main/res/drawable/faq_image_bg.xml
new file mode 100644
index 00000000..1182829a
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/drawable/faq_image_bg.xml
@@ -0,0 +1,21 @@
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_drop_down.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_drop_down.xml
new file mode 100644
index 00000000..67f670ab
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/drawable/ic_arrow_drop_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_clear.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_clear.xml
new file mode 100644
index 00000000..2a8b72a6
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/drawable/ic_clear.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_search.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_search.xml
new file mode 100644
index 00000000..3661d395
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/drawable/ic_search.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/drawable/ic_wtf.xml b/android/DartsScorecard/app/src/main/res/drawable/ic_wtf.xml
new file mode 100644
index 00000000..35ac03da
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/drawable/ic_wtf.xml
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/layout/activity_wtf.xml b/android/DartsScorecard/app/src/main/res/layout/activity_wtf.xml
new file mode 100644
index 00000000..6c979fdf
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/layout/activity_wtf.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/layout/jelly_toolbar.xml b/android/DartsScorecard/app/src/main/res/layout/jelly_toolbar.xml
new file mode 100644
index 00000000..7b16b85c
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/layout/jelly_toolbar.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/layout/searchbar.xml b/android/DartsScorecard/app/src/main/res/layout/searchbar.xml
new file mode 100644
index 00000000..8b5c32b0
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/layout/searchbar.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/layout/toolbar_beta.xml b/android/DartsScorecard/app/src/main/res/layout/toolbar_beta.xml
index fdb57f2e..570bd24d 100644
--- a/android/DartsScorecard/app/src/main/res/layout/toolbar_beta.xml
+++ b/android/DartsScorecard/app/src/main/res/layout/toolbar_beta.xml
@@ -14,7 +14,6 @@
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fitsSystemWindows="true"
app:collapsedTitleGravity="start"
app:contentScrim="?android:attr/colorPrimary"
app:expandedTitleGravity="start"
diff --git a/android/DartsScorecard/app/src/main/res/layout/toolbar_wtf.xml b/android/DartsScorecard/app/src/main/res/layout/toolbar_wtf.xml
new file mode 100644
index 00000000..e65c88c3
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/layout/toolbar_wtf.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/layout/wtf_view.xml b/android/DartsScorecard/app/src/main/res/layout/wtf_view.xml
new file mode 100644
index 00000000..882248fd
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/layout/wtf_view.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/DartsScorecard/app/src/main/res/menu/beta.xml b/android/DartsScorecard/app/src/main/res/menu/beta.xml
new file mode 100644
index 00000000..ddc9b093
--- /dev/null
+++ b/android/DartsScorecard/app/src/main/res/menu/beta.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/android/DartsScorecard/app/src/main/res/menu/play.xml b/android/DartsScorecard/app/src/main/res/menu/play.xml
index 5f25c8a7..a99e3dd8 100644
--- a/android/DartsScorecard/app/src/main/res/menu/play.xml
+++ b/android/DartsScorecard/app/src/main/res/menu/play.xml
@@ -1,5 +1,12 @@
-