diff --git a/Changelog.md b/Changelog.md
index a14d5fadd..dfb3c4d00 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,15 @@
# Most recent version
+## v3.1.1
+```
+This version contains a bunch of bug fixes! Here's just a few:
+- Creating or opening an event should no longer crash the app
+- Fixed sharing games through the game overview
+- Prevented scores from dropping below zero when there are too many fouls
+```
+
+# Legacy versions
+
## v3.1.0
```
Thank you for using the app while some of the kinks in the new version are worked out!
@@ -12,8 +22,6 @@ Bug fixes
- Fix some more rotation crashes and returning to the app from the background
```
-# Legacy versions
-
## v3.0.2
```
diff --git a/app/build.gradle b/app/build.gradle
index 7b8c65e9b..80568badd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -6,7 +6,7 @@ apply plugin: 'kotlin-android-extensions'
def versionMajor = 3
def versionMinor = 1
-def versionPatch = 0
+def versionPatch = 1
android {
compileSdkVersion 28
@@ -32,8 +32,7 @@ android {
["BANNER_AD_UNIT_ID", "ca-app-pub-3940256099942544/6300978111"],
["ADMOB_APP_ID", "ca-app-pub-3940256099942544~3347511713"],
["TRANSFER_API_KEY", "API_KEY_GOES_HERE"],
- ["MIXPANEL_TOKEN", "API_KEY_GOES_HERE"],
- ["BUGSNAG_TOKEN", "API_KEY_GOES_HERE"]
+ ["MIXPANEL_TOKEN", "API_KEY_GOES_HERE"]
]
apiKeys.each { key, value ->
@@ -48,9 +47,9 @@ android {
def apiKeys = [
["TRANSFER_SERVER_URL", "API_KEY_GOES_HERE"],
["BANNER_AD_UNIT_ID", "API_KEY_GOES_HERE"],
+ ["ADMOB_APP_ID", "ca-app-pub-3940256099942544~3347511713"],
["TRANSFER_API_KEY", "API_KEY_GOES_HERE"],
- ["MIXPANEL_TOKEN", "API_KEY_GOES_HERE"],
- ["BUGSNAG_TOKEN", "API_KEY_GOES_HERE"]
+ ["MIXPANEL_TOKEN", "API_KEY_GOES_HERE"]
]
apiKeys.each { key, value ->
@@ -76,16 +75,13 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.2'
implementation 'android.arch.lifecycle:extensions:1.1.1'
- implementation 'com.nex3z:flow-layout:1.2.2' // https://github.com/nex3z/FlowLayout
- implementation 'com.robertlevonyan.view:MaterialChipView:1.2.4' // https://github.com/robertlevonyan/materialChipView
implementation 'com.ncapdevi:frag-nav:2.4.0' // https://github.com/ncapdevi/FragNav
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3' // https://github.com/PhilJay/MPAndroidChart
- implementation 'com.mixpanel.android:mixpanel-android:5.4.2' // https://github.com/mixpanel/mixpanel-android
- implementation 'com.bugsnag:bugsnag-android:4.8.2' // https://github.com/bugsnag/bugsnag-android
+ implementation 'com.mixpanel.android:mixpanel-android:5.4.4' // https://github.com/mixpanel/mixpanel-android
implementation 'com.google.android.gms:play-services-gcm:16.0.0'
- implementation 'com.google.android.gms:play-services-ads:17.0.0'
+ implementation 'com.google.android.gms:play-services-ads:17.1.2'
testImplementation 'junit:junit:4.12'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ed517d92b..df4576a59 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,16 +19,14 @@
android:networkSecurityConfig="@xml/network_security_config"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
+
+
-
-
+
+
+
+
diff --git a/app/src/main/assets/changelog.txt b/app/src/main/assets/changelog.txt
index 85cd94f3c..9deb1efd0 100644
--- a/app/src/main/assets/changelog.txt
+++ b/app/src/main/assets/changelog.txt
@@ -1,3 +1,9 @@
+v3.1.1
+This version contains a bunch of bug fixes! Here's just a few:
+- Creating or opening an event should no longer crash the app
+- Fixed sharing games through the game overview
+- Prevented scores from dropping below zero when there are too many fouls
+
v3.1.0
Thank you for using the app while some of the kinks in the new version are worked out!
- See an overview of your games by tapping the list icon in the top right, or the overview menu item
diff --git a/app/src/main/assets/licenses.txt b/app/src/main/assets/licenses.txt
index 92e50def5..abdfaaf54 100644
--- a/app/src/main/assets/licenses.txt
+++ b/app/src/main/assets/licenses.txt
@@ -21,23 +21,6 @@ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-FlowLayout
-
-FlowLayout
-Copyright 2016 nex3z
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
FragNav
FragNav Android Fragment Navigation Library
@@ -55,24 +38,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-Material Chip View
-
-Material Chip View
-Copyright 2017 Robert Levonyan
-Url: https://github.com/robertlevonyan/materialChipView
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
Material design icons
Material design icons
Copyright 2018 Google
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/App.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/App.kt
index ea7fd13a1..175a31900 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/App.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/App.kt
@@ -8,7 +8,6 @@ import android.arch.lifecycle.OnLifecycleEvent
import android.content.Context
import android.support.v7.preference.PreferenceManager
import android.view.inputmethod.InputMethodManager
-import com.bugsnag.android.Bugsnag
import com.google.android.gms.ads.MobileAds
import java.util.concurrent.atomic.AtomicBoolean
@@ -47,10 +46,6 @@ class App : Application(), LifecycleObserver {
super.onCreate()
PreferenceManager.setDefaultValues(this, R.xml.pref_app, false)
MobileAds.initialize(this, BuildConfig.ADMOB_APP_ID)
-
- if (!BuildConfig.DEBUG) {
- Bugsnag.init(this)
- }
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/NavigationActivity.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/NavigationActivity.kt
index c9ad18c0d..8604967cb 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/NavigationActivity.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/NavigationActivity.kt
@@ -10,7 +10,6 @@ import android.support.v4.widget.DrawerLayout
import android.view.MenuItem
import android.view.View
import ca.josephroque.bowlingcompanion.bowlers.BowlerListFragment
-import ca.josephroque.bowlingcompanion.common.Android
import ca.josephroque.bowlingcompanion.common.FabController
import ca.josephroque.bowlingcompanion.common.NavigationDrawerController
import ca.josephroque.bowlingcompanion.common.interfaces.IFloatingActionButtonHandler
@@ -31,7 +30,6 @@ import ca.josephroque.bowlingcompanion.utils.StartupManager
import ca.josephroque.bowlingcompanion.utils.isVisible
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavTransactionOptions
-import kotlinx.coroutines.experimental.launch
import kotlinx.android.synthetic.main.activity_navigation.ad_view as adView
import kotlinx.android.synthetic.main.activity_navigation.bottom_navigation as bottomNavigation
import kotlinx.android.synthetic.main.activity_navigation.drawer_layout as drawerLayout
@@ -169,6 +167,11 @@ class NavigationActivity : BaseActivity(),
}
override fun onBackPressed() {
+ if (fragNavController?.isStateSaved == true) {
+ super.onBackPressed()
+ return
+ }
+
val fragNavController = fragNavController
if (fragNavController != null) {
if (currentFragment?.popChildFragment() == true) {
@@ -279,7 +282,7 @@ class NavigationActivity : BaseActivity(),
// MARK: TransactionListener
override fun onFragmentTransaction(fragment: Fragment?, transactionType: FragNavController.TransactionType?) {
- handleFragmentChange(fragment)
+ handleFragmentChange(fragment, transactionType)
}
override fun onTabTransaction(fragment: Fragment?, index: Int) {
@@ -311,7 +314,7 @@ class NavigationActivity : BaseActivity(),
// MARK: Private functions
- private fun handleFragmentChange(fragment: Fragment?) {
+ private fun handleFragmentChange(fragment: Fragment?, transactionType: FragNavController.TransactionType? = null) {
fragNavController?.let {
val showBackButton = it.isRootFragment.not() || BottomTab.fromInt(it.currentStackIndex) == BottomTab.Statistics
supportActionBar?.setDisplayHomeAsUpEnabled(showBackButton)
@@ -340,7 +343,7 @@ class NavigationActivity : BaseActivity(),
refreshCurrentFragment()
}
- if (fragment is StatisticsProviderListFragment) {
+ if (fragment is StatisticsProviderListFragment && transactionType != FragNavController.TransactionType.POP) {
val statisticsContext = fragNavController?.getStack(BottomTab.toInt(BottomTab.Record))?.peek() as? IStatisticsContext
fragment.arguments = StatisticsProviderListFragment.buildArguments(statisticsContext?.statisticsProviders ?: emptyList())
}
@@ -378,17 +381,9 @@ class NavigationActivity : BaseActivity(),
}
bottomNavigation.setOnNavigationItemSelectedListener {
- launch(Android) {
- fragNavController?.switchTab(BottomTab.fromId(it.itemId).ordinal)
- }
-
+ fragNavController?.switchTab(BottomTab.fromId(it.itemId).ordinal)
return@setOnNavigationItemSelectedListener true
}
-
- bottomNavigation.setOnNavigationItemReselectedListener {
- // FIXME: probably refresh the current fragment, not reset the stack
-// fragNavController?.clearStack()
- }
}
private fun setupNavigationDrawer() {
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/common/FragmentBreadcrumbLogger.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/common/FragmentBreadcrumbLogger.kt
deleted file mode 100644
index a538b75f2..000000000
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/common/FragmentBreadcrumbLogger.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package ca.josephroque.bowlingcompanion.common
-
-import android.os.Bundle
-import android.support.v4.app.Fragment
-import android.support.v4.app.FragmentManager
-import ca.josephroque.bowlingcompanion.BuildConfig
-import com.bugsnag.android.BreadcrumbType
-import com.bugsnag.android.Bugsnag
-
-/**
- * Copyright (C) 2018 Joseph Roque
- *
- * Add breadcrumb logging to fragments for Bugsnag.
- */
-class FragmentBreadcrumbLogger : FragmentManager.FragmentLifecycleCallbacks() {
- companion object {
- @Suppress("unused")
- private const val TAG = "FragmentBreadcrumbLogger"
-
- private const val FRAG_LIFECYCLE_CALLBACK = "FragmentLifecycleCallback"
- }
-
- // MARK: FragmentLifecycleCallbacks
-
- override fun onFragmentCreated(fm: FragmentManager, f: Fragment, savedInstanceState: Bundle?) {
- leaveLifecycleBreadcrumb(f, "onFragmentCreated()")
- }
-
- override fun onFragmentDestroyed(fm: FragmentManager, f: Fragment) {
- leaveLifecycleBreadcrumb(f, "onFragmentDestroyed()")
- }
-
- override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
- leaveLifecycleBreadcrumb(f, "onFragmentResumed()")
- }
-
- override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
- leaveLifecycleBreadcrumb(f, "onFragmentPaused()")
- }
-
- // MARK: Private functions
-
- private fun leaveLifecycleBreadcrumb(fragment: Fragment, lifecycleCallback: String) {
- if (BuildConfig.DEBUG) { return }
- val fragmentName = fragment.javaClass.simpleName
-
- val metadata = HashMap()
- metadata[FRAG_LIFECYCLE_CALLBACK] = lifecycleCallback
- Bugsnag.leaveBreadcrumb(fragmentName, BreadcrumbType.NAVIGATION, metadata)
- }
-}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/common/activities/BaseActivity.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/common/activities/BaseActivity.kt
index a02d437ae..2be0df78e 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/common/activities/BaseActivity.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/common/activities/BaseActivity.kt
@@ -6,7 +6,6 @@ import android.view.Menu
import android.view.MenuItem
import ca.josephroque.bowlingcompanion.BuildConfig
import ca.josephroque.bowlingcompanion.R
-import ca.josephroque.bowlingcompanion.common.FragmentBreadcrumbLogger
import ca.josephroque.bowlingcompanion.settings.SettingsActivity
import ca.josephroque.bowlingcompanion.utils.Analytics
import ca.josephroque.bowlingcompanion.utils.Email
@@ -23,20 +22,8 @@ abstract class BaseActivity : AppCompatActivity() {
private const val TAG = "BaseActivity"
}
- private val fragmentBreadcrumbLogger = FragmentBreadcrumbLogger()
-
// MARK: Lifecycle functions
- override fun onStart() {
- super.onStart()
- supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentBreadcrumbLogger, true)
- }
-
- override fun onStop() {
- super.onStop()
- supportFragmentManager.unregisterFragmentLifecycleCallbacks(fragmentBreadcrumbLogger)
- }
-
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.base_activity, menu)
return true
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/BaseRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/BaseRecyclerViewAdapter.kt
index a7fe3bfef..41a59129b 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/BaseRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/BaseRecyclerViewAdapter.kt
@@ -158,7 +158,7 @@ abstract class BaseRecyclerViewAdapter- (
// MARK:: ViewHolder
abstract inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- abstract fun bind(item: Item, position: Int)
+ abstract fun bind(item: Item)
}
// MARK: SwipeCallback
@@ -174,8 +174,7 @@ abstract class BaseRecyclerViewAdapter
- (
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
if (swipeable) {
- val position = viewHolder.adapterPosition
- delegate?.onItemSwipe(getItemAt(position))
+ delegate?.onItemSwipe(getItemAt(viewHolder.adapterPosition))
}
}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/NameAverageRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/NameAverageRecyclerViewAdapter.kt
index 2dd0adb21..9010b8ff9 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/NameAverageRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/common/adapters/NameAverageRecyclerViewAdapter.kt
@@ -74,7 +74,7 @@ class NameAverageRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: ViewHolderActive
@@ -85,7 +85,7 @@ class NameAverageRecyclerViewAdapter(
private val ivIcon: ImageView? = view.findViewById(R.id.iv_name_average)
private val checkBox: CheckBox? = view.findViewById(R.id.check_name_average)
- override fun bind(item: T, position: Int) {
+ override fun bind(item: T) {
val context = itemView.context
tvName?.text = item.name
@@ -100,7 +100,7 @@ class NameAverageRecyclerViewAdapter(
ivIcon?.visibility = View.VISIBLE
checkBox?.visibility = View.GONE
- val imageResource = buildImageResource?.invoke(item, position)
+ val imageResource = buildImageResource?.invoke(item, adapterPosition)
imageResource?.let {
ivIcon?.setImageResource(it.first)
ivIcon?.setColorFilter(it.second)
@@ -118,19 +118,19 @@ class NameAverageRecyclerViewAdapter(
private val tvDeleted: TextView? = view.findViewById(R.id.tv_deleted)
private val tvUndo: TextView? = view.findViewById(R.id.tv_undo)
- override fun bind(item: T, position: Int) {
+ override fun bind(item: T) {
val context = itemView.context
tvDeleted?.text = String.format(
context.resources.getString(R.string.query_delete_item),
- getItemAt(position).name
+ getItemAt(adapterPosition).name
)
val deletedItemListener = View.OnClickListener {
if (it.id == R.id.tv_undo) {
- delegate?.onItemSwipe(getItemAt(position))
+ delegate?.onItemSwipe(getItemAt(adapterPosition))
} else {
- delegate?.onItemDelete(getItemAt(position))
+ delegate?.onItemDelete(getItemAt(adapterPosition))
}
}
itemView.setOnClickListener(deletedItemListener)
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/games/Game.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/games/Game.kt
index cc7411d0f..90c72a0e3 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/games/Game.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/games/Game.kt
@@ -170,7 +170,7 @@ class Game(
// Calculate the final score of the game
if (!isManual) {
- score = totalScore - fouls * Game.FOUL_PENALTY
+ score = maxOf(totalScore - fouls * Game.FOUL_PENALTY, 0)
dirty = false
}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameFragment.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameFragment.kt
index e9166517a..59ae39573 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameFragment.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameFragment.kt
@@ -74,7 +74,6 @@ class GameFragment : BaseFragment(),
set(value) {
saveCurrentGame(false)
field = value
- gameHeader.currentGame = gameNumber
gameState.currentGameIdx = gameNumber
gameState.currentFrame.isAccessed = true
render(ballChanged = true, isGameFirstRender = true)
@@ -250,6 +249,8 @@ class GameFragment : BaseFragment(),
launch(Android) {
if (view == null) { return@launch }
+ // Update current game / frame / ball
+ gameHeader.currentGame = gameNumber
scoreSheet.apply(gameState.currentFrameIdx, gameState.currentBallIdx, gameState.currentGame)
// Update up/down pins
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameState.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameState.kt
index 0984075bd..2e1d2d867 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameState.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/games/GameState.kt
@@ -338,18 +338,21 @@ class GameState(
}
fun saveFrame(context: WeakReference, ignoreManualScore: Boolean) {
+ if (!gamesLoaded) { return }
if (!ignoreManualScore && currentGame.isManual) { return }
val copy = currentFrame.deepCopy()
Saviour.instance.saveFrame(context, currentGame.score, copy)
}
fun saveGame(context: WeakReference, ignoreManualScore: Boolean) {
+ if (!gamesLoaded) { return }
if (!ignoreManualScore && currentGame.isManual) { return }
val copy = currentGame.deepCopy()
Saviour.instance.saveGame(context, copy)
}
fun saveMatchPlay(context: WeakReference) {
+ if (!gamesLoaded) { return }
val copy = currentGame.matchPlay.deepCopy()
Saviour.instance.saveMatchPlay(context, copy)
}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewFragment.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewFragment.kt
index 5b8b5c74b..1fb152955 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewFragment.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewFragment.kt
@@ -20,7 +20,7 @@ import android.support.v7.app.AlertDialog
import ca.josephroque.bowlingcompanion.statistics.interfaces.IStatisticsContext
import ca.josephroque.bowlingcompanion.statistics.provider.StatisticsProvider
import ca.josephroque.bowlingcompanion.utils.Permission
-import ca.josephroque.bowlingcompanion.utils.ShareUtils
+import ca.josephroque.bowlingcompanion.utils.sharing.ShareUtils
/**
* Copyright (C) 2018 Joseph Roque
@@ -208,15 +208,16 @@ class GameOverviewFragment : ListFragment
.setPositiveButton(R.string.okay) { dialog, _ ->
if (dialog is AlertDialog) {
val selectedItem = ShareOption.fromInt(dialog.listView.checkedItemPosition)!!
+ externalPermissionsGrantedCallback = {
+ when (selectedItem) {
+ ShareOption.Share -> ShareUtils.shareGames(activity, sortedGames)
+ ShareOption.Save -> ShareUtils.saveGames(activity, sortedGames)
+ }
+ externalPermissionsGrantedCallback = null
+ }
when (selectedItem) {
ShareOption.Share -> ShareUtils.shareGames(activity, sortedGames)
- ShareOption.Save -> {
- externalPermissionsGrantedCallback = {
- ShareUtils.saveGames(activity, sortedGames)
- externalPermissionsGrantedCallback = null
- }
- ShareUtils.saveGames(activity, sortedGames)
- }
+ ShareOption.Save -> ShareUtils.saveGames(activity, sortedGames)
}
}
dialog.dismiss()
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewRecyclerViewAdapter.kt
index 1765a8ff5..2cc3499ea 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/games/overview/GameOverviewRecyclerViewAdapter.kt
@@ -38,7 +38,7 @@ class GameOverviewRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: ViewHolder
@@ -48,7 +48,7 @@ class GameOverviewRecyclerViewAdapter(
private val scoreSheet: ScoreSheet? = view.findViewById(R.id.score_sheet)
private val checkBox: CheckBox? = view.findViewById(R.id.checkbox_share)
- override fun bind(item: Game, position: Int) {
+ override fun bind(item: Game) {
val context = itemView.context
tvGameNumber?.text = context.resources.getString(R.string.game_number).format(item.ordinal)
@@ -65,12 +65,12 @@ class GameOverviewRecyclerViewAdapter(
it.apply(-1, -1, item)
// Remember scroll position
- val (x, y) = scrollOffsets[position] ?: Pair(0, 0)
+ val (x, y) = scrollOffsets[adapterPosition] ?: Pair(0, 0)
it.scrollTo(x, y)
it.delegate = object : ScoreSheet.SheetScrollListener {
override fun didScroll(x: Int, y: Int) {
- scrollOffsets[position] = Pair(x, y)
+ scrollOffsets[adapterPosition] = Pair(x, y)
}
}
}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/leagues/League.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/leagues/League.kt
index 2afc05504..26f151a42 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/leagues/League.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/leagues/League.kt
@@ -213,6 +213,8 @@ data class League(
private fun isLeagueNameValid(name: String): Boolean = REGEX_NAME.matches(name)
+ private fun nameMatchesPracticeLeague(name: String): Boolean = PRACTICE_LEAGUE_NAME.toLowerCase().equals(name.toLowerCase())
+
private fun isLeagueNameUnique(context: Context, name: String, id: Long = -1): Deferred {
return async(CommonPool) {
val database = DatabaseManager.getReadableDatabase(context).await()
@@ -256,10 +258,12 @@ data class League(
return async(CommonPool) {
val errorTitle = if (isEvent) R.string.issue_saving_event else R.string.issue_saving_league
val errorMessage: Int?
- if (!isLeagueNameValid(name)) {
+ if (nameMatchesPracticeLeague(name)) {
+ errorMessage = R.string.error_league_name_is_practice
+ } else if (!isLeagueNameValid(name)) {
errorMessage = if (isEvent) R.string.error_event_name_invalid else R.string.error_league_name_invalid
} else if (!isLeagueNameUnique(context, name, id).await()) {
- errorMessage = if (isEvent) R.string.error_event_name_in_use else R.string.error_league_name_in_use
+ errorMessage = R.string.error_league_name_in_use
} else if (name == PRACTICE_LEAGUE_NAME) {
errorMessage = R.string.error_cannot_edit_practice_league
} else if (
@@ -374,7 +378,7 @@ data class League(
* If the new entry is an event, its series is also created at this time
* since there is only a single series to an event
*/
- val (series, seriesError) = league.createNewSeries(context).await()
+ val (series, seriesError) = league.createNewSeries(context, database).await()
if (seriesError != null || (series?.id ?: -1L) == -1L) {
throw IllegalStateException("Series was not saved.")
}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/matchplay/MatchPlaySheet.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/matchplay/MatchPlaySheet.kt
index a5407538d..92726de25 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/matchplay/MatchPlaySheet.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/matchplay/MatchPlaySheet.kt
@@ -9,7 +9,6 @@ import android.support.v4.app.DialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.FrameLayout
import ca.josephroque.bowlingcompanion.R
import ca.josephroque.bowlingcompanion.common.fragments.BaseBottomSheetDialogFragment
import ca.josephroque.bowlingcompanion.games.Game
@@ -65,7 +64,7 @@ class MatchPlaySheet : BaseBottomSheetDialogFragment() {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.setOnShowListener {
if (it is BottomSheetDialog) {
- val bottomSheet = it.findViewById(R.id.design_bottom_sheet)
+ val bottomSheet = it.findViewById(android.support.design.R.id.design_bottom_sheet)
val bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesRecyclerViewAdapter.kt
index 7c38d1d9f..1f00b6cb8 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesRecyclerViewAdapter.kt
@@ -1,5 +1,7 @@
package ca.josephroque.bowlingcompanion.series
+import android.support.design.chip.Chip
+import android.support.design.chip.ChipGroup
import android.support.v4.content.ContextCompat
import android.support.v7.preference.PreferenceManager
import android.support.v7.widget.RecyclerView
@@ -12,7 +14,6 @@ import ca.josephroque.bowlingcompanion.common.adapters.BaseRecyclerViewAdapter
import ca.josephroque.bowlingcompanion.matchplay.MatchPlayResult
import ca.josephroque.bowlingcompanion.leagues.League
import ca.josephroque.bowlingcompanion.settings.Settings
-import com.nex3z.flowlayout.FlowLayout
/**
* Copyright (C) 2018 Joseph Roque
@@ -98,7 +99,7 @@ class SeriesRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: SeriesRecyclerViewAdapter
@@ -125,7 +126,7 @@ class SeriesRecyclerViewAdapter(
private val tvDate: TextView? = view.findViewById(R.id.tv_date)
private val tvTotal: TextView? = view.findViewById(R.id.tv_total)
- override fun bind(item: Series, position: Int) {
+ override fun bind(item: Series) {
val context = itemView.context
val seriesTotal = item.scores.sum()
@@ -149,9 +150,9 @@ class SeriesRecyclerViewAdapter(
private val tvDate: TextView? = view.findViewById(R.id.tv_date)
private val tvTotal: TextView? = view.findViewById(R.id.tv_total)
- private val flowScores: FlowLayout? = view.findViewById(R.id.flow_scores)
+ private val chipGroupScores: ChipGroup? = view.findViewById(R.id.cg_scores)
- override fun bind(item: Series, position: Int) {
+ override fun bind(item: Series) {
val context = itemView.context
val seriesTotal = item.scores.sum()
@@ -168,32 +169,47 @@ class SeriesRecyclerViewAdapter(
val shouldShowMatchPlayResult = Settings.BooleanSetting.ShowMatchResults.getValue(preferences)
val shouldHighlightMatchPlayResult = Settings.BooleanSetting.HighlightMatchResults.getValue(preferences)
- flowScores?.removeAllViews()
+ chipGroupScores?.removeAllViews()
if (shouldShowMatchPlayResult) {
for (i in 0 until item.scores.size) {
- val id = View.generateViewId()
- val scoreView = SeriesScoreView(context)
+ val viewId = View.generateViewId()
+ val score = item.scores[i]
val matchPlayResult = MatchPlayResult.fromInt(item.matchPlay[i].toInt())!!
- scoreView.id = id
- scoreView.isFocusable = false
- scoreView.isClickable = false
- scoreView.score = item.scores[i]
- scoreView.matchPlay = matchPlayResult
-
- scoreView.scoreTextColor = if (shouldHighlightGame(item.scores[i])) {
- ContextCompat.getColor(context, R.color.gameHighlight)
- } else {
- ContextCompat.getColor(context, R.color.primaryBlackText)
- }
- when {
- !shouldHighlightMatchPlayResult || matchPlayResult == MatchPlayResult.NONE -> scoreView.matchPlayTextColor = ContextCompat.getColor(context, R.color.primaryBlackText)
- matchPlayResult == MatchPlayResult.WON -> scoreView.matchPlayTextColor = ContextCompat.getColor(context, R.color.matchPlayWin)
- matchPlayResult == MatchPlayResult.LOST -> scoreView.matchPlayTextColor = ContextCompat.getColor(context, R.color.matchPlayLoss)
- matchPlayResult == MatchPlayResult.TIED -> scoreView.matchPlayTextColor = ContextCompat.getColor(context, R.color.matchPlayTie)
+ val chipIconResource: Int?
+ val chipIconTintResource: Int?
+ when (matchPlayResult) {
+ MatchPlayResult.WON -> {
+ chipIconResource = R.drawable.ic_match_play_won_chip
+ chipIconTintResource = if (shouldHighlightMatchPlayResult) R.color.matchPlayWin else R.color.primaryBlackText
+ }
+ MatchPlayResult.LOST -> {
+ chipIconResource = R.drawable.ic_match_play_lost_chip
+ chipIconTintResource = if (shouldHighlightMatchPlayResult) R.color.matchPlayLoss else R.color.primaryBlackText
+ }
+ MatchPlayResult.TIED -> {
+ chipIconResource = R.drawable.ic_match_play_tied_chip
+ chipIconTintResource = if (shouldHighlightMatchPlayResult) R.color.matchPlayTie else R.color.primaryBlackText
+ }
+ MatchPlayResult.NONE -> {
+ chipIconResource = null
+ chipIconTintResource = null
+ }
+ }
+ val chipTextColorResource = if (shouldHighlightGame(score)) R.color.gameHighlight else R.color.primaryBlackText
+
+ val chip = Chip(context).apply {
+ id = viewId
+ isFocusable = false
+ isClickable = false
+ text = score.toString()
+ setTextColor(ContextCompat.getColor(context, chipTextColorResource))
+ chipIconResource?.let { setChipIconResource(it) }
+ chipIconTintResource?.let { setChipIconTintResource(it) }
+ setChipBackgroundColorResource(R.color.colorListContrast)
}
- flowScores?.addView(scoreView)
+ chipGroupScores?.addView(chip)
}
}
@@ -208,19 +224,19 @@ class SeriesRecyclerViewAdapter(
private val tvDeleted: TextView? = view.findViewById(R.id.tv_deleted)
private val tvUndo: TextView? = view.findViewById(R.id.tv_undo)
- override fun bind(item: Series, position: Int) {
+ override fun bind(item: Series) {
val context = itemView.context
tvDeleted?.text = String.format(
context.resources.getString(R.string.query_delete_item),
- getItemAt(position).prettyDate
+ getItemAt(adapterPosition).prettyDate
)
val deletedItemListener = View.OnClickListener {
if (it.id == R.id.tv_undo) {
- delegate?.onItemSwipe(getItemAt(position))
+ delegate?.onItemSwipe(getItemAt(adapterPosition))
} else {
- delegate?.onItemDelete(getItemAt(position))
+ delegate?.onItemDelete(getItemAt(adapterPosition))
}
}
itemView.setOnClickListener(deletedItemListener)
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesScoreView.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesScoreView.kt
deleted file mode 100644
index c2a7c3746..000000000
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/series/SeriesScoreView.kt
+++ /dev/null
@@ -1,97 +0,0 @@
-package ca.josephroque.bowlingcompanion.series
-
-import android.content.Context
-import android.graphics.Color
-import android.os.Bundle
-import android.os.Parcelable
-import android.util.AttributeSet
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.LinearLayout
-import ca.josephroque.bowlingcompanion.R
-import ca.josephroque.bowlingcompanion.matchplay.MatchPlayResult
-import kotlinx.android.synthetic.main.view_series_score.view.tv_score as tvScore
-import kotlinx.android.synthetic.main.view_series_score.view.tv_match_play as tvMatchPlay
-
-/**
- * Copyright (C) 2018 Joseph Roque
- *
- * Display a score and its match play result in unison.
- */
-class SeriesScoreView : LinearLayout {
-
- companion object {
- @Suppress("unused")
- private const val TAG = "SeriesScoreView"
-
- private const val SUPER_STATE = "${TAG}_super_state"
- private const val SCORE = "${TAG}_score"
- private const val MATCH_PLAY = "${TAG}_match_play"
- private const val SCORE_TEXT_COLOR = "${TAG}_score_text_color"
- private const val MATCH_PLAY_TEXT_COLOR = "${TAG}_match_play_text_color"
- }
-
- // MARK: Constructors
-
- constructor(context: Context) : this(context, null)
- constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
- constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
- orientation = LinearLayout.VERTICAL
- LayoutInflater.from(context).inflate(R.layout.view_series_score, this, true)
- }
-
- // MARK: Lifecycle functions
-
- override fun onSaveInstanceState(): Parcelable {
- return Bundle().apply {
- putParcelable(SUPER_STATE, super.onSaveInstanceState())
- putInt(SCORE, score)
- putInt(SCORE_TEXT_COLOR, scoreTextColor)
- putInt(MATCH_PLAY, matchPlay.ordinal)
- putInt(MATCH_PLAY_TEXT_COLOR, matchPlayTextColor)
- }
- }
-
- override fun onRestoreInstanceState(state: Parcelable?) {
- var superState: Parcelable? = null
- if (state is Bundle) {
- score = state.getInt(SCORE)
- scoreTextColor = state.getInt(SCORE_TEXT_COLOR)
- matchPlay = MatchPlayResult.fromInt(state.getInt(MATCH_PLAY))!!
- matchPlayTextColor = state.getInt(MATCH_PLAY_TEXT_COLOR)
- superState = state.getParcelable(SUPER_STATE)
- }
-
- super.onRestoreInstanceState(superState)
- }
-
- var score: Int = 0
- set(value) {
- tvScore.text = value.toString()
- field = value
- }
-
- var matchPlay: MatchPlayResult = MatchPlayResult.NONE
- set(value) {
- when (value) {
- MatchPlayResult.NONE -> tvMatchPlay.text = null
- MatchPlayResult.WON -> tvMatchPlay.text = context.getString(R.string.match_play_won_short)
- MatchPlayResult.LOST -> tvMatchPlay.text = context.getString(R.string.match_play_lost_short)
- MatchPlayResult.TIED -> tvMatchPlay.text = context.getString(R.string.match_play_tied_short)
- }
- tvMatchPlay.visibility = if (value == MatchPlayResult.NONE) View.GONE else View.VISIBLE
- field = value
- }
-
- var scoreTextColor: Int = Color.BLACK
- set(value) {
- tvScore.setTextColor(value)
- field = value
- }
-
- var matchPlayTextColor: Int = Color.BLACK
- set(value) {
- tvMatchPlay.setTextColor(value)
- field = value
- }
-}
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/list/StatisticsRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/list/StatisticsRecyclerViewAdapter.kt
index 87991f37e..cae83c90c 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/list/StatisticsRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/list/StatisticsRecyclerViewAdapter.kt
@@ -59,7 +59,7 @@ class StatisticsRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: HeaderViewHolder
@@ -67,7 +67,7 @@ class StatisticsRecyclerViewAdapter(
inner class HeaderViewHolder(view: View) : BaseRecyclerViewAdapter.ViewHolder(view) {
private val tvTitle: TextView? = view.findViewById(R.id.tv_title)
- override fun bind(item: StatisticListItem, position: Int) {
+ override fun bind(item: StatisticListItem) {
val context = itemView.context
val header = item as StatisticsCategory
@@ -82,7 +82,7 @@ class StatisticsRecyclerViewAdapter(
private val tvValue: TextView? = view.findViewById(R.id.tv_value)
private val tvSubtitle: TextView? = view.findViewById(R.id.tv_subtitle)
- override fun bind(item: StatisticListItem, position: Int) {
+ override fun bind(item: StatisticListItem) {
val context = itemView.context
val statistic = item as Statistic
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/provider/StatisticsProviderRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/provider/StatisticsProviderRecyclerViewAdapter.kt
index 67eac8b9f..4b4857833 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/provider/StatisticsProviderRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/statistics/provider/StatisticsProviderRecyclerViewAdapter.kt
@@ -26,9 +26,7 @@ class StatisticsProviderRecyclerViewAdapter(
// MARK: BaseRecyclerViewAdapter
- override fun getItemViewType(position: Int): Int {
- return 0
- }
+ override fun getItemViewType(position: Int) = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseRecyclerViewAdapter.ViewHolder {
return ViewHolderName(
@@ -39,7 +37,7 @@ class StatisticsProviderRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: ViewHolderName
@@ -48,7 +46,7 @@ class StatisticsProviderRecyclerViewAdapter(
private val tvName: TextView? = view.findViewById(R.id.tv_name)
private val tvType: TextView? = view.findViewById(R.id.tv_type)
- override fun bind(item: StatisticsProvider, position: Int) {
+ override fun bind(item: StatisticsProvider) {
tvName?.text = item.name
tvType?.setText(item.typeName)
itemView.setOnClickListener(this@StatisticsProviderRecyclerViewAdapter)
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/teams/list/TeamRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/teams/list/TeamRecyclerViewAdapter.kt
index 6950b609b..792480a05 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/teams/list/TeamRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/teams/list/TeamRecyclerViewAdapter.kt
@@ -1,5 +1,7 @@
package ca.josephroque.bowlingcompanion.teams.list
+import android.support.design.chip.Chip
+import android.support.design.chip.ChipGroup
import android.support.v4.content.ContextCompat
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
@@ -9,8 +11,6 @@ import android.widget.TextView
import ca.josephroque.bowlingcompanion.R
import ca.josephroque.bowlingcompanion.common.adapters.BaseRecyclerViewAdapter
import ca.josephroque.bowlingcompanion.teams.Team
-import com.nex3z.flowlayout.FlowLayout
-import com.robertlevonyan.views.chip.Chip
/**
* Copyright (C) 2018 Joseph Roque
@@ -61,30 +61,30 @@ class TeamRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
// MARK: ViewHolderActive
inner class ViewHolderActive(view: View) : BaseRecyclerViewAdapter.ViewHolder(view) {
private val tvName: TextView? = view.findViewById(R.id.tv_name)
- private val flowMembers: FlowLayout? = view.findViewById(R.id.flow_members)
+ private val chipGroupMembers: ChipGroup? = view.findViewById(R.id.cg_members)
- override fun bind(item: Team, position: Int) {
+ override fun bind(item: Team) {
val context = itemView.context
tvName?.text = item.name
- flowMembers?.removeAllViews()
+ chipGroupMembers?.removeAllViews()
item.members.forEach {
val viewId = View.generateViewId()
Chip(context).apply {
id = viewId
isFocusable = false
isClickable = false
- chipText = it.bowlerName
- changeBackgroundColor(ContextCompat.getColor(context, R.color.colorPrimary))
- textColor = ContextCompat.getColor(context, R.color.primaryWhiteText)
- flowMembers?.addView(this)
+ text = it.bowlerName
+ setChipBackgroundColorResource(R.color.colorPrimary)
+ setTextColor(ContextCompat.getColor(context, R.color.primaryWhiteText))
+ chipGroupMembers?.addView(this)
}
}
@@ -99,19 +99,19 @@ class TeamRecyclerViewAdapter(
private val tvDeleted: TextView? = view.findViewById(R.id.tv_deleted)
private val tvUndo: TextView? = view.findViewById(R.id.tv_undo)
- override fun bind(item: Team, position: Int) {
+ override fun bind(item: Team) {
val context = itemView.context
tvDeleted?.text = String.format(
context.resources.getString(R.string.query_delete_item),
- getItemAt(position).name
+ getItemAt(adapterPosition).name
)
val deletedItemListener = View.OnClickListener {
if (it.id == R.id.tv_undo) {
- delegate?.onItemSwipe(getItemAt(position))
+ delegate?.onItemSwipe(getItemAt(adapterPosition))
} else {
- delegate?.onItemDelete(getItemAt(position))
+ delegate?.onItemDelete(getItemAt(adapterPosition))
}
}
itemView.setOnClickListener(deletedItemListener)
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/teams/teammember/TeamMembersRecyclerViewAdapter.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/teams/teammember/TeamMembersRecyclerViewAdapter.kt
index e9ef72b8b..6aaa9a0d4 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/teams/teammember/TeamMembersRecyclerViewAdapter.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/teams/teammember/TeamMembersRecyclerViewAdapter.kt
@@ -56,7 +56,7 @@ class TeamMembersRecyclerViewAdapter(
}
override fun onBindViewHolder(holder: BaseRecyclerViewAdapter.ViewHolder, position: Int) {
- holder.bind(getItemAt(position), position)
+ holder.bind(getItemAt(position))
}
override fun buildItemTouchHelper(): ItemTouchHelper.Callback {
@@ -71,7 +71,7 @@ class TeamMembersRecyclerViewAdapter(
private val tvSeriesName: TextView = view.findViewById(R.id.tv_team_member_series)
private val ivIcon: ImageView = view.findViewById(R.id.iv_team_member_icon)
- override fun bind(item: TeamMember, position: Int) {
+ override fun bind(item: TeamMember) {
val context = itemView.context
ivIcon.setImageResource(R.drawable.ic_menu)
ivIcon.setColorFilter(ContextCompat.getColor(context, R.color.primaryBlackIcon))
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/utils/StartupManager.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/StartupManager.kt
index f2f973e26..593e51008 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/utils/StartupManager.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/StartupManager.kt
@@ -19,7 +19,7 @@ object StartupManager {
fun start(context: Context) {
val appVersion = getAppVersion(context)
val isNewVersion = BuildConfig.VERSION_CODE != appVersion
- setIsFirstLaunch(context, appVersion != -1)
+ setIsFirstLaunch(context, appVersion == -1)
setAppVersion(context, BuildConfig.VERSION_CODE)
val isFirstLaunch = isFirstLaunch(context)
@@ -31,8 +31,7 @@ object StartupManager {
}
fun isFirstLaunch(context: Context): Boolean {
- val preferences = PreferenceManager.getDefaultSharedPreferences(context)
- return preferences.getBoolean(IS_FIRST_LAUNCH, false)
+ return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(IS_FIRST_LAUNCH, false)
}
fun getAppVersion(context: Context): Int {
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/GameOverviewBitmapFileProvider.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/GameOverviewBitmapFileProvider.kt
new file mode 100644
index 000000000..01bdaf447
--- /dev/null
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/GameOverviewBitmapFileProvider.kt
@@ -0,0 +1,10 @@
+package ca.josephroque.bowlingcompanion.utils.sharing
+
+import android.support.v4.content.FileProvider
+
+/**
+ * Copyright (C) 2019 Joseph Roque
+ *
+ * Provider for Game Overview bitmaps.
+ */
+class GameOverviewBitmapFileProvider : FileProvider()
diff --git a/app/src/main/java/ca/josephroque/bowlingcompanion/utils/ShareUtils.kt b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/ShareUtils.kt
similarity index 78%
rename from app/src/main/java/ca/josephroque/bowlingcompanion/utils/ShareUtils.kt
rename to app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/ShareUtils.kt
index ae1b1668a..2e1ef8dd6 100644
--- a/app/src/main/java/ca/josephroque/bowlingcompanion/utils/ShareUtils.kt
+++ b/app/src/main/java/ca/josephroque/bowlingcompanion/utils/sharing/ShareUtils.kt
@@ -1,4 +1,4 @@
-package ca.josephroque.bowlingcompanion.utils
+package ca.josephroque.bowlingcompanion.utils.sharing
import android.app.Activity
import android.graphics.Bitmap
@@ -15,13 +15,18 @@ import kotlinx.coroutines.experimental.launch
import android.content.Intent
import android.graphics.Canvas
import android.graphics.Paint
-import android.net.Uri
import android.util.Log
import android.view.View
import ca.josephroque.bowlingcompanion.common.Android
import ca.josephroque.bowlingcompanion.games.Game
import ca.josephroque.bowlingcompanion.games.views.GameNumberView
import ca.josephroque.bowlingcompanion.games.views.ScoreSheet
+import ca.josephroque.bowlingcompanion.utils.Analytics
+import ca.josephroque.bowlingcompanion.utils.BCError
+import ca.josephroque.bowlingcompanion.utils.Permission
+import ca.josephroque.bowlingcompanion.utils.toBitmap
+import android.support.v4.content.FileProvider
+import ca.josephroque.bowlingcompanion.BuildConfig
/**
* Copyright (C) 2018 Joseph Roque
@@ -37,21 +42,30 @@ object ShareUtils {
private const val interGameBorderWidth = 4
fun shareGames(activity: Activity, games: List) {
- launch(CommonPool) {
- val bitmap = buildBitmap(activity, games)
- val destination = saveBitmap(activity, games.size, bitmap)
- bitmap.recycle()
+ if (Permission.WriteExternalStorage.requestPermission(activity)) {
+ launch(CommonPool) {
+ val bitmap = buildBitmap(activity, games)
+ val destination = saveBitmap(activity, games.size, bitmap)
+ bitmap.recycle()
- if (destination == null) { return@launch }
+ if (destination == null) {
+ return@launch
+ }
- val shareIntent = Intent(Intent.ACTION_SEND)
- shareIntent.type = "image/$exportFileType"
- shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(destination))
+ val providedImage = FileProvider.getUriForFile(activity,
+ "${BuildConfig.APPLICATION_ID}.utils.sharing.GameOverviewBitmapFileProvider",
+ destination)
- launch(Android) {
- activity.startActivity(Intent.createChooser(shareIntent, activity.resources.getString(R.string.share_image)))
+ val shareIntent = Intent(Intent.ACTION_SEND)
+ shareIntent.type = "image/$exportFileType"
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ shareIntent.putExtra(Intent.EXTRA_STREAM, providedImage)
- Analytics.trackShareImage(games.size)
+ launch(Android) {
+ activity.startActivity(Intent.createChooser(shareIntent, activity.resources.getString(R.string.share_image)))
+
+ Analytics.trackShareImage(games.size)
+ }
}
}
}
diff --git a/app/src/main/res/drawable-hdpi/ic_match_play_lost_chip.png b/app/src/main/res/drawable-hdpi/ic_match_play_lost_chip.png
new file mode 100644
index 000000000..c98cae3b0
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_match_play_lost_chip.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_match_play_tied_chip.png b/app/src/main/res/drawable-hdpi/ic_match_play_tied_chip.png
new file mode 100644
index 000000000..efbd11596
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_match_play_tied_chip.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_match_play_won_chip.png b/app/src/main/res/drawable-hdpi/ic_match_play_won_chip.png
new file mode 100644
index 000000000..c482cea75
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_match_play_won_chip.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_match_play_lost_chip.png b/app/src/main/res/drawable-mdpi/ic_match_play_lost_chip.png
new file mode 100644
index 000000000..60ece0386
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_match_play_lost_chip.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_match_play_tied_chip.png b/app/src/main/res/drawable-mdpi/ic_match_play_tied_chip.png
new file mode 100644
index 000000000..7fce4c66e
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_match_play_tied_chip.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_match_play_won_chip.png b/app/src/main/res/drawable-mdpi/ic_match_play_won_chip.png
new file mode 100644
index 000000000..aba6ae33c
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_match_play_won_chip.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_match_play_lost_chip.png b/app/src/main/res/drawable-xhdpi/ic_match_play_lost_chip.png
new file mode 100644
index 000000000..b801b4415
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_match_play_lost_chip.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_match_play_tied_chip.png b/app/src/main/res/drawable-xhdpi/ic_match_play_tied_chip.png
new file mode 100644
index 000000000..70deca444
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_match_play_tied_chip.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_match_play_won_chip.png b/app/src/main/res/drawable-xhdpi/ic_match_play_won_chip.png
new file mode 100644
index 000000000..d54f5a410
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_match_play_won_chip.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_match_play_lost_chip.png b/app/src/main/res/drawable-xxhdpi/ic_match_play_lost_chip.png
new file mode 100644
index 000000000..0b1492e8a
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_match_play_lost_chip.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_match_play_tied_chip.png b/app/src/main/res/drawable-xxhdpi/ic_match_play_tied_chip.png
new file mode 100644
index 000000000..4edb2c8d1
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_match_play_tied_chip.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_match_play_won_chip.png b/app/src/main/res/drawable-xxhdpi/ic_match_play_won_chip.png
new file mode 100644
index 000000000..0f9068395
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_match_play_won_chip.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_match_play_lost_chip.png b/app/src/main/res/drawable-xxxhdpi/ic_match_play_lost_chip.png
new file mode 100644
index 000000000..07f6df332
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_match_play_lost_chip.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_match_play_tied_chip.png b/app/src/main/res/drawable-xxxhdpi/ic_match_play_tied_chip.png
new file mode 100644
index 000000000..e7d68c9b9
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_match_play_tied_chip.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_match_play_won_chip.png b/app/src/main/res/drawable-xxxhdpi/ic_match_play_won_chip.png
new file mode 100644
index 000000000..b0371133f
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_match_play_won_chip.png differ
diff --git a/app/src/main/res/layout/fragment_game.xml b/app/src/main/res/layout/fragment_game.xml
index 219f00a04..d291a5225 100644
--- a/app/src/main/res/layout/fragment_game.xml
+++ b/app/src/main/res/layout/fragment_game.xml
@@ -42,6 +42,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
+ android:textAlignment="center"
android:textColor="@color/primaryWhiteText"
app:layout_constraintTop_toBottomOf="@id/game_header"
app:layout_constraintBottom_toTopOf="@id/game_footer"
diff --git a/app/src/main/res/layout/list_item_series_expanded.xml b/app/src/main/res/layout/list_item_series_expanded.xml
index 7dcc72db5..8ba65c85d 100644
--- a/app/src/main/res/layout/list_item_series_expanded.xml
+++ b/app/src/main/res/layout/list_item_series_expanded.xml
@@ -1,6 +1,5 @@
-
-
+ app:chipSpacing="@dimen/list_item_margin_small" />
diff --git a/app/src/main/res/layout/list_item_team.xml b/app/src/main/res/layout/list_item_team.xml
index eb5abcf46..8f96f6330 100644
--- a/app/src/main/res/layout/list_item_team.xml
+++ b/app/src/main/res/layout/list_item_team.xml
@@ -17,12 +17,11 @@
-
+ app:chipSpacing="@dimen/list_item_margin" />
diff --git a/app/src/main/res/layout/view_series_score.xml b/app/src/main/res/layout/view_series_score.xml
deleted file mode 100644
index b6a4976d8..000000000
--- a/app/src/main/res/layout/view_series_score.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 6b0a1a0f3..78bb677a1 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -12,6 +12,7 @@
#F5F5F5
#EBEBEB
+ #E1E1E1
#33000000
#EE5253
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 8f7c85c31..4d4f9165b 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -30,6 +30,7 @@
16dp
+ 8dp
48dp
40dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index da5a35a35..ba891f72d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -164,11 +164,12 @@
Issue saving league!
Unable to delete league!
You can only use letters, spaces, and the following characters: \'!@#$%^&*()_+:"?/~-.
- That name has already been used. You must choose another.
+ That name has already been used for a league or event. You must choose another.
You can only use numbers in your additional games and pinfall!
Your additional pinfall and games cannot equal an average greater than 450.
Your game highlight must be between 0 and 450, and series highlight cannot be greater than the maximum total series.
Leagues and events can be between 1 and 20 games.
+ You can\'t use the name \'Practice\'. Choose another name or try using the practice league to record your games.
An error occurred and the league could not be saved.
@@ -176,7 +177,6 @@
Issue saving event!
You can only use letters, spaces, and the following characters: \'!@#$%^&*()_+:"?/~-.
- That name has already been used. You must choose another.
Series
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 8a6efdc99..bbade9916 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -3,7 +3,7 @@
-