diff --git a/.gitignore b/.gitignore index c8f4f452..934aa586 100644 --- a/.gitignore +++ b/.gitignore @@ -55,13 +55,11 @@ freeline/ freeline_project_description.json android/DartsScorecard/\.idea/ - android/DartsScorecard/scripts/dsc_keystore -android/DartsScorecard/app/lint-report\.html - release/ *.exec -android/DartsScorecard/dig/web/ +**/dig/web/ +**/lint-report\.html diff --git a/.travis.yml b/.travis.yml index 904c1833..fe5d6cde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ cache: - $HOME/.gradle/native #Cache library downloaded from the gradle dependency env: global: - - ANDROID_API=26 + - ANDROID_API=27 - EMULATOR_API=26 - - ANDROID_BUILD_TOOLS=26.0.2 + - ANDROID_BUILD_TOOLS=27.0.3 - ADB_INSTALL_TIMEOUT=5 - secure: UH6Td9+MFk1nsYYMKN9t6/XcMmSZtB+L4sWMUmYBMaK1Q6YnGCnyHmU5RWkP+9a3AiZQ+n9XK+9TV+azMxJzyOoPMEzvBYtienvI1ZwTg+gqVOsMGG8TKubdgBfYQKm+mtdc3ctgucqjRg0yb4aUDp4CeNwwCuX1zuzIaAYp8IgRElkJzhJMeTcrCUWTBNk2F9ix0eRyOKOCIwgiAa6wNn1zMRvpbPh3esJ7CcnC0xesBtWriFtJDKFhPPWowPrWhGerLe3y5oNySqPpjxfBDIU9HPThNLNwBgp25Ww2c4Ib4Im0p59dPyKBU8mv3eoHvWtrSYW0bZQfKuJD6JsI0wg7Afx2hOxhPWw2evwjmhYWEfspSTUDUZIV/BhLhR2WbeZgAgd1gBh1ulxe79kne1FLsojVr+wZXA5Cn1TF2R4pnTj8EYLctbz/J1/sbcKwut6+I4z7FgbLDOEvaHTJZiscotR0ofML6OoYkKba8LznCES8RqYc3oyCKJvRD5oiVyHhMScAptMeignnPCGmhzm2evpclZfjoZ6vGyI/MgZML4as7WWz1FuiaNV+vJx6PyuNzBjYyNpKJ7O/G4yUT6EITrw3UPVCaSJr6eM3o8eAjy8XTkFsuRJ4iEhMAGiDRlvIlAMrUQyp8PxxvKB9YS6skFfAXXAUp59m/PLbRc0= - secure: b9RwM5JGKpo0axCpeqDx9WZfZppiJWKF6d1zxTpO6cIiUmsgpL2GQy1fK/jHzKA1mlFIgq87pu11M696PqPJq7RadkeqlhKAq0zw8lBphg5Tn50wZUglusvIbMPC4VnsFLNeBd3elZIepglbh994sQxxpCpc8IF29x8cj//xrR6Z+EvyWYjnLgtbQjjdql6K0JRhGyTn+FXe5qLxmgu2lc4QL/RBcpnF+gpLrFfzBf/M/ruSyLjjpLZLCtzz90dAD/Ewb+sLvlfM0SUbXvFg+P2YoSo7rbDum+l45S6meIs6ygqcpb/3ByL9pSK3XEzrqLFQFggST8Puy8pHkwL8IVLuOtTPiO2HUtyzbTJLbEmupwEr6nXF2xtQE4vqgCNCLd63JxldRf3D2nrLG9OXJMlQRzkAfYtXj15tqyDfiLlCzIocfASsj/MF8XKzeR45+6GC9KLULpR0s1MdxYYhhb+Ss4sV8VElC3C4mlQiCA6G5AOJtPcnUshGNXbw3oWotJgY76IEJG2gSnb2SSI94VuXCI/39DLxXoTF1knixdaFJOO2QvBU2b8eZKrU4w1+rUrSfIMnBdn27hdqs+uKYNuJIwtMMCcrFtZmZnKjXcBwjgQdm51gWuMiJN5S8xM8turo23jL2Cak7rXn8RUmLHbhu3Jpl8iQzQOPFm1zmkg= @@ -35,6 +35,7 @@ android: - android-sdk-license-.+ - google-gdk-license-.+ before_install: +- yes | sdkmanager "platforms;android-27" - openssl aes-256-cbc -K $encrypted_c5c67234e863_key -iv $encrypted_c5c67234e863_iv -in android/DartsScorecard/scripts/dsc_keystore.enc -out android/DartsScorecard/scripts/dsc_keystore -d diff --git a/android/DartsScorecard/app/build.gradle b/android/DartsScorecard/app/build.gradle index 6d91e5c9..591dcb24 100644 --- a/android/DartsScorecard/app/build.gradle +++ b/android/DartsScorecard/app/build.gradle @@ -5,49 +5,25 @@ apply plugin: 'kotlin-android-extensions' apply plugin: 'com.getkeepsafe.dexcount' apply from: '../scripts/versioning.gradle' apply from: '../scripts/coverage.gradle' +apply from: '../scripts/android_common.gradle' android { - def config = rootProject.extensions.getByName("ext") - compileSdkVersion config.androidCompileSdkVersion - buildToolsVersion config.androidBuildToolsVersion + def config = rootProject.extensions.getByName("ext") defaultConfig { applicationId "nl.entreco.dartsscorecard" - minSdkVersion config.androidMinSdkVersion - targetSdkVersion config.androidTargetSdkVersion - versionCode config.versionCode - versionName config.versionName - - resConfigs "en", "nl" - resValue "string", "version", "${config.versionName}" - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + buildTypes { - debug { - testCoverageEnabled true - } release { shrinkResources true - minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - lintOptions { - htmlReport true - htmlOutput file("lint-report.html") - abortOnError false - } - dataBinding { enabled = true } - - testOptions { - unitTests.returnDefaultValues = true - } } dependencies { @@ -82,6 +58,4 @@ dependencies { androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoCore" } -apply plugin: 'com.google.gms.google-services' - - +apply plugin: 'com.google.gms.google-services' \ 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 03b1b0a8..86f68e47 100644 --- a/android/DartsScorecard/app/src/main/AndroidManifest.xml +++ b/android/DartsScorecard/app/src/main/AndroidManifest.xml @@ -20,9 +20,16 @@ - - - + + + 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 efbfd70b..7809c74a 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,13 +34,6 @@ abstract class TestableAdapter : RecyclerView.Adap } } - protected fun tryNotifyItemRangeInserted(position: Int, count: Int) { - try { - notifyItemRangeInserted(position, count) - } catch (ignore: NullPointerException) { - } - } - protected fun tryNotifyItemRangeChanged(position: Int, count: Int) { try { notifyItemRangeChanged(position, count) 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 e5d0e1e7..0bc1466d 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 @@ -6,8 +6,11 @@ import android.arch.lifecycle.ViewModelProvider import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.preference.PreferenceManager +import android.support.annotation.StringRes import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.Toolbar import nl.entreco.dartsscorecard.App +import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.di.viewmodel.ViewModelComponent import nl.entreco.dartsscorecard.di.viewmodel.ViewModelModule @@ -52,4 +55,10 @@ abstract class ViewModelActivity : AppCompatActivity() { protected fun swapStyle() { styler.switch() } + + protected fun initToolbar(toolbar: Toolbar, @StringRes title: Int = R.string.app_name, 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/di/setup/Setup01Module.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Module.kt index afb63265..45ac58a5 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Module.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/di/setup/Setup01Module.kt @@ -1,18 +1,38 @@ package nl.entreco.dartsscorecard.di.setup +import android.content.Context import dagger.Module import dagger.Provides import nl.entreco.dartsscorecard.setup.Setup01Activity import nl.entreco.dartsscorecard.setup.Setup01Navigator +import nl.entreco.dartsscorecard.setup.players.PlayerEditor +import nl.entreco.data.setup.repository.SharedPreferenceRepo +import nl.entreco.domain.repository.PreferenceRepository /** * Created by Entreco on 20/12/2017. */ @Module -class Setup01Module(private val activity: Setup01Activity) { +class Setup01Module(activity: Setup01Activity) { + + private val navigator = Setup01Navigator(activity) + private val prefs = activity.getSharedPreferences("setup", Context.MODE_PRIVATE) + @Provides @Setup01Scope fun provideNavigator(): Setup01Navigator { - return Setup01Navigator(activity) + return navigator + } + + @Provides + @Setup01Scope + fun providePlayerEditor(): PlayerEditor { + return navigator + } + + @Provides + @Setup01Scope + fun providePreferenceRepo(): PreferenceRepository { + return SharedPreferenceRepo(prefs) } } \ No newline at end of file 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 05c78d88..57104c5e 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 @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.databinding.DataBindingUtil import android.os.Bundle +import android.support.v7.widget.Toolbar import android.view.Menu import android.view.MenuItem import nl.entreco.dartsscorecard.R @@ -39,11 +40,16 @@ class Play01Activity : ViewModelActivity() { initGame() } + initToolbar(toolbar(binding)) resumeGame() } private fun initGame() { - viewModel.load(retrieveSetup(), scoreViewModel) + viewModel.load(retrieveSetup(intent), scoreViewModel) + } + + private fun toolbar(binding: ActivityPlay01Binding): Toolbar { + return binding.includeToolbar?.toolbar!! } private fun resumeGame() { @@ -65,13 +71,14 @@ class Play01Activity : ViewModelActivity() { return super.onOptionsItemSelected(item) } - private fun retrieveSetup(): RetrieveGameRequest { - return RetrieveGameRequest(intent.getLongExtra("gameId", -1), - TeamIdsString(intent.getStringExtra("teamIds")), - intent.getParcelableExtra("exec")) - } - companion object { + @JvmStatic + fun retrieveSetup(intent: Intent): RetrieveGameRequest { + return RetrieveGameRequest(intent.getLongExtra("gameId", -1), + TeamIdsString(intent.getStringExtra("teamIds")), + intent.getParcelableExtra("exec")) + } + @JvmStatic fun startGame(context: Context, retrieve: RetrieveGameRequest) { val intent = Intent(context, Play01Activity::class.java) diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt index 8800c253..03543060 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/play/score/TeamScoreBindings.kt @@ -9,7 +9,8 @@ import android.support.v4.graphics.ColorUtils import android.util.Log import android.util.TypedValue import android.view.animation.AccelerateDecelerateInterpolator -import android.view.animation.OvershootInterpolator +import android.view.animation.AccelerateInterpolator +import android.view.animation.DecelerateInterpolator import android.widget.ImageView import android.widget.TextView import nl.entreco.dartsscorecard.R @@ -35,33 +36,44 @@ abstract class TeamScoreBindings { val diff = oldScore - score when (diff) { 180 -> handle180(view) - 0 -> {} - else -> { clear(view, 0)} + 0 -> { } + else -> { + clear(view) + } } } - private fun clear(view: TextView, delay: Long) { - view.animate().cancel() - view.animate().translationX(200F).setStartDelay(delay).withEndAction({ - view.setText( R.string.empty ) - }).setDuration(DEFAULT_ANIMATION_TIME).start() + private fun clear(view: TextView, delay: Long = 0) { + view.animate().scaleY(0F).setStartDelay(delay) + .setInterpolator(DecelerateInterpolator()) + .withStartAction { + view.pivotY = view.height.toFloat() + } + .withEndAction({ + view.scaleY = 0F + view.translationY = 0F + view.setText(R.string.empty) + }).setDuration(if (delay == 0L) 0 else DEFAULT_ANIMATION_TIME).start() } private fun handle180(view: TextView) { - view.animate().cancel() - view.setText( R.string.score_180 ) - view.animate().translationX(0F).setInterpolator(OvershootInterpolator()).setDuration(DEFAULT_ANIMATION_TIME) + view.setText(R.string.score_180) + view.animate().scaleY(1F).setDuration(DEFAULT_ANIMATION_TIME) + .setInterpolator(AccelerateInterpolator()) + .withStartAction { + view.scaleY = 0F + view.pivotY = 0F + } .withEndAction({ - val howLong = 1200L - animateColor(view, R.attr.colorOneEighty, R.attr.scoreText, howLong) - clear(view, howLong) + animateColor(view, R.attr.colorOneEighty, R.attr.scoreText, 1200L) + clear(view, 1200L) }).start() } private fun animateColor(view: TextView, attr: Int, attr2: Int, duration: Long) { view.animate().setDuration(duration / 3) .setStartDelay(duration / 3) - .withStartAction{ view.setTextColor(fromAttr(view.context, attr)) } + .withStartAction { view.setTextColor(fromAttr(view.context, attr)) } .withEndAction { view.setTextColor(fromAttr(view.context, attr2)) } .start() } 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 8d4a07dd..eaa8b059 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,17 +1,16 @@ 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.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.edit.EditPlayerActivity import nl.entreco.dartsscorecard.setup.players.PlayersViewModel import nl.entreco.dartsscorecard.setup.settings.SettingsViewModel @@ -25,6 +24,7 @@ class Setup01Activity : ViewModelActivity() { 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 navigator: Setup01Navigator by lazy { Setup01Navigator(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -33,17 +33,19 @@ class Setup01Activity : ViewModelActivity() { binding.playersViewModel = playersViewModel binding.adsViewModel = adsViewModel binding.settingsViewModel = settingsViewModel - binding.navigator = Setup01Navigator(this).apply { onAddNewPlayer(playersViewModel.adapter) } + binding.navigator = navigator + + navigator.onAddNewPlayer(0) + initToolbar(toolbar(binding), R.string.title_setup) + } + + private fun toolbar(binding: ActivitySetup01Binding): Toolbar { + return binding.includeToolbar?.toolbar!! } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (resultCode == Activity.RESULT_OK && requestCode == EditPlayerActivity.REQUEST_CODE) { - val oldName = data?.getStringExtra("oldName")!! - val playerName = data.getStringExtra("playerName")!! - val teamIndex = data.getIntExtra("teamIndex", -1) - playersViewModel.handlePlayerUpdated(oldName, playerName, teamIndex) - } + navigator.handleResult(requestCode, resultCode, data, playersViewModel.adapter) } companion object { diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Navigator.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Navigator.kt index 3bfbde32..48bb7dbc 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Navigator.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/Setup01Navigator.kt @@ -1,26 +1,92 @@ package nl.entreco.dartsscorecard.setup +import android.app.Activity +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.support.v4.view.PagerAdapter.POSITION_NONE import nl.entreco.dartsscorecard.play.Play01Activity import nl.entreco.dartsscorecard.setup.edit.EditPlayerActivity -import nl.entreco.dartsscorecard.setup.players.PlayerAdapter +import nl.entreco.dartsscorecard.setup.players.PlayerEditor import nl.entreco.dartsscorecard.setup.players.PlayerViewModel +import nl.entreco.domain.model.players.Player import nl.entreco.domain.repository.RetrieveGameRequest /** * Created by Entreco on 02/01/2018. */ -class Setup01Navigator(private val activity: Setup01Activity) { +class Setup01Navigator(private val activity: Setup01Activity) : PlayerEditor { - fun onEditPlayerName(player: PlayerViewModel) { - EditPlayerActivity.start(activity, player.name.get(), player.teamIndex.get()) + fun launch(req: RetrieveGameRequest) { + Play01Activity.startGame(activity, req) + activity.finish() } - fun onAddNewPlayer(adapter: PlayerAdapter) { - EditPlayerActivity.start(activity, adapter.onAddPlayer(), adapter.itemCount) + override fun onEditPlayer(position: Int, player: PlayerViewModel) { + editPlayerRequest(activity, player.name.get(), player.teamIndex.get(), position) } - fun launch(req: RetrieveGameRequest) { - Play01Activity.startGame(activity, req) - activity.finish() + override fun onAddNewPlayer(index: Int) { + val vm = PlayerViewModel(index + 1) + editPlayerRequest(activity, vm.name.get(), vm.teamIndex.get(), POSITION_NONE) + } + + private fun editPlayerRequest(activity: Activity, suggestion: CharSequence, teamIndex: Int, positionInList: Int) { + val request = Intent(activity, EditPlayerActivity::class.java) + request.putExtra(EXTRA_SUGGESTION, suggestion) + request.putExtra(EXTRA_TEAM_INDEX, teamIndex) + request.putExtra(EXTRA_POSITION_IN_LIST, positionInList) + activity.startActivityForResult(request, REQUEST_CODE) + } + + override fun handleResult(requestCode: Int, resultCode: Int, data: Intent?, callback: PlayerEditor.Callback) { + if (resultCode == RESULT_OK && requestCode == REQUEST_CODE && data != null) { + val suggestion = data.getStringExtra(EXTRA_SUGGESTION) + val playerName = data.getStringExtra(EXTRA_PLAYER_NAME) + val teamIndex = data.getIntExtra(EXTRA_TEAM_INDEX, POSITION_NONE) + val index = data.getIntExtra(EXTRA_POSITION_IN_LIST, POSITION_NONE) + + if (isNewPlayer(index)) { + + if(suggestion.isEmpty()){ + callback.onPlayerAdded(playerName) + } else if(suggestion == "Player 1"){ + callback.onPlayerAdded(suggestion) + } + + } else { + callback.onPlayerEdited(index, teamIndex, playerName) + } + } + } + + private fun isNewPlayer(index: Int) = index == POSITION_NONE + + companion object { + + internal const val REQUEST_CODE = 1002 + internal const val EXTRA_SUGGESTION = "suggestion" + internal const val EXTRA_TEAM_INDEX = "teamIndex" + internal const val EXTRA_POSITION_IN_LIST = "positionInList" + internal const val EXTRA_PLAYER_NAME = "playerName" + + @JvmStatic + fun editPlayerResponse(player: Player, request: Intent): Intent { + val response = Intent() + response.putExtra(EXTRA_SUGGESTION, "") + response.putExtra(EXTRA_PLAYER_NAME, player.name) + response.putExtra(EXTRA_TEAM_INDEX, request.getIntExtra(EXTRA_TEAM_INDEX, POSITION_NONE)) + response.putExtra(EXTRA_POSITION_IN_LIST, request.getIntExtra(EXTRA_POSITION_IN_LIST, POSITION_NONE)) + return response + } + + @JvmStatic + fun cancelPlayerResponse(request: Intent): Intent { + val response = Intent() + response.putExtra(EXTRA_SUGGESTION, request.getStringExtra(EXTRA_SUGGESTION)) + response.putExtra(EXTRA_PLAYER_NAME, "") + response.putExtra(EXTRA_TEAM_INDEX, request.getIntExtra(EXTRA_TEAM_INDEX, POSITION_NONE)) + response.putExtra(EXTRA_POSITION_IN_LIST, request.getIntExtra(EXTRA_POSITION_IN_LIST, POSITION_NONE)) + return response + } } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerActivity.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerActivity.kt index 230efa7a..ea5f75c3 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerActivity.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerActivity.kt @@ -1,9 +1,8 @@ package nl.entreco.dartsscorecard.setup.edit -import android.app.Activity -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.base.ViewModelActivity import nl.entreco.dartsscorecard.databinding.ActivityEditPlayerBinding @@ -17,34 +16,25 @@ class EditPlayerActivity : ViewModelActivity() { private val component: EditPlayerComponent by componentProvider { it.plus(EditPlayerModule(getSuggestedName())) } private val viewModel: EditPlayerViewModel by viewModelProvider { component.viewModel() } + private val navigator: EditPlayerNavigator by lazy { EditPlayerNavigator(this) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = DataBindingUtil.setContentView(this, R.layout.activity_edit_player) binding.viewModel = viewModel - binding.navigator = EditPlayerNavigator(this) - initToolbar() - } - - private fun initToolbar() { - setTitle(R.string.title_select_player) - supportActionBar?.setDisplayShowHomeEnabled(true) + binding.navigator = navigator + initToolbar(toolbar(binding), R.string.title_select_player) } private fun getSuggestedName(): String { return intent.getStringExtra("suggestion") } - companion object { - - const val REQUEST_CODE = 1002 + private fun toolbar(binding: ActivityEditPlayerBinding): Toolbar { + return binding.includeToolbar?.toolbar!! + } - @JvmStatic - fun start(activity: Activity, suggestion: CharSequence, teamIndex: Int) { - val intent = Intent(activity, EditPlayerActivity::class.java) - intent.putExtra("suggestion", suggestion) - intent.putExtra("teamIndex", teamIndex) - activity.startActivityForResult(intent, REQUEST_CODE) - } + override fun onBackPressed() { + navigator.onBackPressed() } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerBindings.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerBindings.kt index 7beb599f..5b84f2da 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerBindings.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerBindings.kt @@ -20,7 +20,8 @@ class EditPlayerBindings { fun selectAll(view: TextView, suggestedName: String) { view.text = suggestedName view.setSelectAllOnFocus(true) - view.requestFocus() + view.clearFocus() + view.requestFocusFromTouch() } @JvmStatic 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 1cd081e3..958d8f38 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,21 +1,20 @@ package nl.entreco.dartsscorecard.setup.edit import android.app.Activity.RESULT_OK -import android.content.Intent -import android.view.View +import nl.entreco.dartsscorecard.setup.Setup01Navigator import nl.entreco.domain.model.players.Player /** * Created by Entreco on 02/01/2018. */ class EditPlayerNavigator(private val activity: EditPlayerActivity) : ExistingPlayerSelectedClicker { - override fun onSelected(view: View, player: Player) { - val intent = Intent() - intent.putExtra("oldName", activity.intent.getStringExtra("suggestion")) - intent.putExtra("playerName", player.name) - intent.putExtra("playerId", player.id) - intent.putExtra("teamIndex", activity.intent.getIntExtra("teamIndex", -1)) - activity.setResult(RESULT_OK, intent) + override fun onSelected(player: Player) { + activity.setResult(RESULT_OK, Setup01Navigator.editPlayerResponse(player, activity.intent)) + activity.finish() + } + + override fun onBackPressed() { + activity.setResult(RESULT_OK, 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/edit/EditPlayerViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerViewModel.kt index 78d7d098..1ad3b6c3 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/EditPlayerViewModel.kt @@ -2,8 +2,11 @@ package nl.entreco.dartsscorecard.setup.edit import android.databinding.ObservableArrayList import android.databinding.ObservableField +import android.support.design.widget.Snackbar +import android.view.View import android.view.inputmethod.EditorInfo import android.widget.TextView +import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.domain.model.players.Player import nl.entreco.domain.setup.usecase.CreatePlayerRequest @@ -42,23 +45,67 @@ class EditPlayerViewModel @Inject constructor(private val createPlayerUsecase: C } fun filter(text: CharSequence) { - val filter = allPlayers.filter { it.name.toLowerCase().startsWith(text.toString().toLowerCase()) } - filteredPlayers.clear() - filteredPlayers.addAll(filter) + val keep = addPlayersWhosNameStartsWith(text) + val typos = addPlayersWhosNameContains(text) + removeOthers(keep, typos) + } + + private fun addPlayersWhosNameStartsWith(text: CharSequence): List { + val keep = allPlayers.filter { it.name.toLowerCase().startsWith(text.toString().toLowerCase()) } + keep.forEach { + if (!filteredPlayers.contains(it)) { + filteredPlayers.add(0, it) + } else { + filteredPlayers.remove(it) + filteredPlayers.add(0, it) + } + } + return keep + } + + private fun addPlayersWhosNameContains(text: CharSequence): List { + val typos = allPlayers.filter { it.name.toLowerCase().contains(text.toString().toLowerCase()) } + typos.forEach { + if (!filteredPlayers.contains(it)) { + filteredPlayers.add(it) + } + } + return typos + } + + private fun removeOthers(keep: List, typos: List) { + val remove = allPlayers.filter { !keep.contains(it) && !typos.contains(it) } + remove.forEach { + if (filteredPlayers.contains(it)) { + filteredPlayers.remove(it) + } + } } fun onActionDone(view: TextView, action: Int, navigator: EditPlayerNavigator): Boolean { - if (action == EditorInfo.IME_ACTION_DONE) { - createPlayerUsecase.exec(CreatePlayerRequest(view.text.toString(), 16), - onCreateSuccess(navigator, view), - onCreateFailed()) + if (donePressed(action)) { + val desiredName = view.text.toString().toLowerCase() + val existing = allPlayers.findLast { + it.name.toLowerCase() == desiredName + } + if (existing == null) { + createPlayerUsecase.exec(CreatePlayerRequest(desiredName, 16), + onCreateSuccess(navigator), + onCreateFailed(view.rootView)) + } else { + navigator.onSelected(existing) + } return true } return false } - private fun onCreateSuccess(navigator: EditPlayerNavigator, view: TextView): (Player) -> Unit = - { player -> navigator.onSelected(view, player) } + private fun donePressed(action: Int) = action == EditorInfo.IME_ACTION_DONE + + private fun onCreateSuccess(navigator: EditPlayerNavigator): (Player) -> Unit = + { player -> navigator.onSelected(player) } - private fun onCreateFailed(): (Throwable) -> Unit = { } + private fun onCreateFailed(view : View): (Throwable) -> Unit = { + Snackbar.make(view, R.string.err_unable_to_create_player, Snackbar.LENGTH_SHORT).show() + } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/ExistingPlayerSelectedClicker.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/ExistingPlayerSelectedClicker.kt index edd03c57..73e99d21 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/ExistingPlayerSelectedClicker.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/edit/ExistingPlayerSelectedClicker.kt @@ -1,11 +1,11 @@ package nl.entreco.dartsscorecard.setup.edit -import android.view.View import nl.entreco.domain.model.players.Player /** * Created by Entreco on 02/01/2018. */ interface ExistingPlayerSelectedClicker { - fun onSelected(view: View, player: Player) + fun onSelected(player: Player) + fun onBackPressed() } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/AddPlayerClicker.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/AddPlayerClicker.kt deleted file mode 100644 index 549eb947..00000000 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/AddPlayerClicker.kt +++ /dev/null @@ -1,8 +0,0 @@ -package nl.entreco.dartsscorecard.setup.players - -/** - * Created by Entreco on 30/12/2017. - */ -interface AddPlayerClicker { - fun onAddPlayer() : String -} \ 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 4de3ad71..ad68ce0e 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 @@ -5,63 +5,53 @@ import android.view.ViewGroup import nl.entreco.dartsscorecard.R import nl.entreco.dartsscorecard.base.TestableAdapter import nl.entreco.dartsscorecard.databinding.SelectPlayerViewBinding -import nl.entreco.dartsscorecard.setup.Setup01Navigator import javax.inject.Inject /** * Created by Entreco on 30/12/2017. */ -class PlayerAdapter @Inject constructor(private val navigator: Setup01Navigator) : TestableAdapter(), AddPlayerClicker { +class PlayerAdapter @Inject constructor(private val editor: PlayerEditor) : TestableAdapter(), PlayerEditor.Callback { private val items = mutableListOf() private val teams = mutableListOf() override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): SelectPlayerView { - return createPlayer(parent) - } - - private fun createPlayer(parent: ViewGroup?): SelectPlayerView { val inflater = LazyInflater(parent?.context!!).inflater val binding = DataBindingUtil.inflate(inflater, R.layout.select_player_view, parent, false) return SelectPlayerView(binding) } + @Synchronized override fun onBindViewHolder(holder: SelectPlayerView?, position: Int) { - holder?.bind(items[position], navigator, teams) + holder?.bind(items[position], editor, teams, position) } override fun getItemCount(): Int { return items.size } - override fun onAddPlayer(): String { - return addPlayerNumber(itemCount + 1) + override fun onPlayerEdited(position: Int, teamIndex: Int, playerName: String) { + val viewModel = items[position] + viewModel.name.set(playerName) + viewModel.teamIndex.set(teamIndex) + tryNotifyItemChanged(position) } - private fun addPlayerNumber(index: Int): String { - val pvm = PlayerViewModel(index) - items.add(pvm) + override fun onPlayerAdded(playerName: String) { + val viewModel = PlayerViewModel(items.size + 1, playerName) + items.add(viewModel) + updateTeamCount() tryNotifyItemInserted(itemCount) - return pvm.name.get() - } - - private fun updateTeamCount() { - teams.clear() - teams += 1..itemCount - tryNotifyItemRangeChanged(0, itemCount) } fun playersMap(): Array { return items.toTypedArray() } - fun replacePlayer(oldPlayerName: String, newPlayerName: String, teamIndex: Int) { - val pvm = items.first { it.name.get() == oldPlayerName } - val index = items.indexOf(pvm) - pvm.name.set(newPlayerName) - pvm.teamIndex.set(teamIndex) - - updateTeamCount() - tryNotifyItemChanged(index) + @Synchronized + private fun updateTeamCount() { + teams.clear() + teams += 1..itemCount + tryNotifyItemRangeChanged(0, itemCount) } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerEditor.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerEditor.kt new file mode 100644 index 00000000..fb35a674 --- /dev/null +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerEditor.kt @@ -0,0 +1,17 @@ +package nl.entreco.dartsscorecard.setup.players + +import android.content.Intent + +/** + * Created by Entreco on 03/01/2018. + */ +interface PlayerEditor { + fun onEditPlayer(position: Int, player: PlayerViewModel) + fun onAddNewPlayer(index: Int) + fun handleResult(requestCode: Int, resultCode: Int, data: Intent?, callback: PlayerEditor.Callback) + + interface Callback { + fun onPlayerEdited(position: Int, teamIndex: Int, playerName: String) + fun onPlayerAdded(playerName: String) + } +} \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerViewModel.kt index 43ac9008..f5c81915 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayerViewModel.kt @@ -9,13 +9,10 @@ import android.widget.AdapterView */ class PlayerViewModel(teamIndex: Int, name: String = "Player $teamIndex") { val name = ObservableField(name) - val teamIndex = ObservableInt(teamIndex) + val teamIndex = ObservableInt(teamIndex - 1) fun onTeamSelected(adapter: AdapterView<*>, index: Int) { - try { - teamIndex.set(adapter.getItemAtPosition(index).toString().toInt()) - } catch (oops: IndexOutOfBoundsException) { - teamIndex.set(teamIndex.get()) - } + val resolved = adapter.getItemAtPosition(index).toString().toInt() + teamIndex.set(resolved) } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayersViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayersViewModel.kt index 61b678bd..6f71ae0a 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayersViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/PlayersViewModel.kt @@ -1,7 +1,6 @@ package nl.entreco.dartsscorecard.setup.players import nl.entreco.dartsscorecard.base.BaseViewModel -import nl.entreco.domain.Logger import nl.entreco.domain.launch.TeamNamesString import nl.entreco.domain.model.players.PlayerSeperator import nl.entreco.domain.model.players.TeamSeperator @@ -10,7 +9,7 @@ import javax.inject.Inject /** * Created by Entreco on 29/12/2017. */ -class PlayersViewModel @Inject constructor(val adapter: PlayerAdapter, private val logger: Logger) : BaseViewModel() { +class PlayersViewModel @Inject constructor(val adapter: PlayerAdapter) : BaseViewModel() { fun setupTeams(): TeamNamesString { val teamString = StringBuilder() @@ -36,8 +35,4 @@ class PlayersViewModel @Inject constructor(val adapter: PlayerAdapter, private v } } } - - fun handlePlayerUpdated(oldName: String, playerName: String, teamIndex: Int) { - adapter.replacePlayer(oldName, playerName, teamIndex) - } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/SelectPlayerView.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/SelectPlayerView.kt index 6cd3aad9..c47b1deb 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/SelectPlayerView.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/players/SelectPlayerView.kt @@ -2,16 +2,16 @@ package nl.entreco.dartsscorecard.setup.players import android.support.v7.widget.RecyclerView import nl.entreco.dartsscorecard.databinding.SelectPlayerViewBinding -import nl.entreco.dartsscorecard.setup.Setup01Navigator /** * Created by Entreco on 30/12/2017. */ class SelectPlayerView(private val binding: SelectPlayerViewBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(viewModel: PlayerViewModel, navigator: Setup01Navigator, entries: MutableList) { + fun bind(viewModel: PlayerViewModel, editor: PlayerEditor, entries: MutableList, positionInList: Int) { binding.player = viewModel - binding.navigator = navigator + binding.editor = editor binding.entries = entries + binding.positionInList = positionInList binding.executePendingBindings() } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/settings/SettingsViewModel.kt b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/settings/SettingsViewModel.kt index b408d2ee..d10a090e 100644 --- a/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/settings/SettingsViewModel.kt +++ b/android/DartsScorecard/app/src/main/java/nl/entreco/dartsscorecard/setup/settings/SettingsViewModel.kt @@ -1,28 +1,39 @@ package nl.entreco.dartsscorecard.setup.settings +import android.databinding.ObservableField import android.databinding.ObservableInt import android.widget.AdapterView import android.widget.SeekBar import nl.entreco.dartsscorecard.base.BaseViewModel import nl.entreco.domain.repository.CreateGameRequest +import nl.entreco.domain.setup.usecase.FetchPreferredSettingsUsecase +import nl.entreco.domain.setup.usecase.FetchSettingsResponse +import nl.entreco.domain.setup.usecase.StorePreferredSettingsUsecase +import nl.entreco.domain.setup.usecase.StoreSettingsRequest import javax.inject.Inject /** * Created by Entreco on 29/12/2017. */ -class SettingsViewModel @Inject constructor() : BaseViewModel() { +class SettingsViewModel @Inject constructor(fetchPrefs: FetchPreferredSettingsUsecase, private val storePrefs: StorePreferredSettingsUsecase) : BaseViewModel() { - internal val startSets = 1 - internal val startLegs = 1 - val min = 0 - val max = 20 - val startScore = ObservableInt(501) - val numSets = ObservableInt(startSets) - val numLegs = ObservableInt(startLegs) + private val preferred = ObservableField(FetchSettingsResponse()) + + init { + fetchPrefs.exec { preferred.set(it) } + } + + val startScoreIndex = ObservableInt(preferred.get().score) + val min = preferred.get().min + val max = preferred.get().max + val startScore = ObservableInt() + val numSets = ObservableInt(preferred.get().sets) + val numLegs = ObservableInt(preferred.get().legs) fun onStartScoreSelected(adapter: AdapterView<*>, index: Int) { - val selectedString = adapter.adapter.getItem(index) as? String - startScore.set(selectedString?.toInt()!!) + val resolved = adapter.getItemAtPosition(index).toString().toInt() + startScoreIndex.set(index) + startScore.set(resolved) } fun onSetsChanged(seekBar: SeekBar, delta: Int) { @@ -35,17 +46,18 @@ class SettingsViewModel @Inject constructor() : BaseViewModel() { fun onSetsProgressChanged(sets: Int) { if (sets in min..max) { - numSets.set(sets + 1) + numSets.set(sets) } } fun onLegsProgressChanged(legs: Int) { if (legs in min..max) { - numLegs.set(legs + 1) + numLegs.set(legs) } } fun setupRequest(): CreateGameRequest { - return CreateGameRequest(startScore.get(), 0, numLegs.get(), numSets.get()) + storePrefs.exec(StoreSettingsRequest(numSets.get(), numLegs.get(), min, max, startScoreIndex.get())) + return CreateGameRequest(startScore.get(), 0, numLegs.get() + 1, numSets.get() + 1) } } \ No newline at end of file diff --git a/android/DartsScorecard/app/src/main/res/layout/activity_edit_player.xml b/android/DartsScorecard/app/src/main/res/layout/activity_edit_player.xml index 71197e71..4a52ce5b 100644 --- a/android/DartsScorecard/app/src/main/res/layout/activity_edit_player.xml +++ b/android/DartsScorecard/app/src/main/res/layout/activity_edit_player.xml @@ -17,53 +17,61 @@ type="nl.entreco.dartsscorecard.setup.edit.EditPlayerNavigator" /> - + android:layout_height="match_parent"> - + - + android:layout_height="match_parent" + android:orientation="vertical" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + - + + - - - - + android:text="@string/choose_existing_player" + android:visibility="@{viewModel.filteredPlayers.isEmpty() ? View.GONE: View.VISIBLE}" /> + + + + + + + - + + \ 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 ee32ceee..238ec416 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 @@ -30,9 +30,14 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + android:layout_height="wrap_content" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + android:layout_height="match_parent"> - + + + android:layout_height="match_parent" + android:paddingBottom="@dimen/def" + android:paddingTop="@dimen/def" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + + - + - + - + -