diff --git a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt index f54b5fd8..f4cc0770 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt @@ -4,14 +4,25 @@ import io.realm.Realm import io.realm.RealmObject import io.realm.RealmResults import io.realm.Sort +import net.pokeranalytics.android.R import net.pokeranalytics.android.model.realm.* -import java.util.* +import net.pokeranalytics.android.ui.view.Localizable -enum class LiveData { +/** + * An interface to easily handle the validity of any object we want to save + */ +interface ObjectSavable { + fun isValidForSave(): Boolean { return true } +} + +/** + * An enum managing the business objects related to a realm results + */ +enum class LiveData : Localizable { BANKROLL, GAME, LOCATION, - TOURNAMENT_TYPE, + TOURNAMENT_FEATURE, TRANSACTION_TYPE; fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> { @@ -28,11 +39,21 @@ enum class LiveData { BANKROLL -> Bankroll::class.java GAME -> Game::class.java LOCATION -> Location::class.java - TOURNAMENT_TYPE -> TournamentFeature::class.java + TOURNAMENT_FEATURE -> TournamentFeature::class.java TRANSACTION_TYPE -> TransactionType::class.java } } + fun newEntity(): RealmObject { + return when (this) { + BANKROLL -> Bankroll() + GAME -> Game() + LOCATION -> Location() + TOURNAMENT_FEATURE -> TournamentFeature() + TRANSACTION_TYPE -> TransactionType() + } + } + fun getData(realm:Realm, primaryKey:String?): RealmObject? { var proxyItem: RealmObject? = null primaryKey?.let { @@ -49,13 +70,24 @@ enum class LiveData { proxyItem?.let { return realm.copyFromRealm(it) } ?: run { - realm.beginTransaction() + return this.newEntity() +/* realm.beginTransaction() val t = realm.createObject(this.relatedEntity, UUID.randomUUID().toString()) realm.commitTransaction() - return realm.copyFromRealm(t) + return realm.copyFromRealm(t)*/ } } -} + + override val resId: Int? + get() { + return when (this) { + BANKROLL -> R.string.bankroll + GAME -> R.string.game + LOCATION -> R.string.location + TOURNAMENT_FEATURE -> R.string.tournament_type + TRANSACTION_TYPE -> R.string.operation_types + } + }} /* interface ListableDataSource { diff --git a/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt new file mode 100644 index 00000000..278ece74 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt @@ -0,0 +1,40 @@ +package net.pokeranalytics.android.model.extensions + +import net.pokeranalytics.android.model.realm.Session +import java.util.* + +enum class SessionState { + PENDING, + STARTED, + PAUSED, + FINISHED, + INVALID; +} + +/** + * Return the current state of a session + * For example: STARTED, PAUSED, FINISHED + */ +fun Session.getState(): SessionState { + + if (timeFrame == null) { + return SessionState.PENDING + } + + val endDate = timeFrame?.endDate + timeFrame?.let {sessionTimeFrame -> + timeFrame?.startDate?.let {startDate -> + if (startDate > Date()) { + return SessionState.PENDING + } else if (endDate != null) { + return SessionState.FINISHED + } else if (sessionTimeFrame.paused) { + return SessionState.PAUSED + } else { + return SessionState.STARTED + } + } + } + + return SessionState.INVALID +} diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt index bf23ca9c..d33a9174 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt @@ -4,6 +4,7 @@ import android.text.InputType import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import net.pokeranalytics.android.model.ObjectSavable import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData @@ -15,7 +16,7 @@ import java.util.* import kotlin.collections.ArrayList open class Bankroll(name: String = "") : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, - RowEditable { + RowEditable, ObjectSavable { companion object { fun newInstance() : Bankroll { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt index c0a419a1..e83f7c77 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt @@ -3,6 +3,7 @@ package net.pokeranalytics.android.model.realm import android.text.InputType import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import net.pokeranalytics.android.model.ObjectSavable import net.pokeranalytics.android.ui.adapter.components.* import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData import net.pokeranalytics.android.ui.view.RowEditable @@ -11,7 +12,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SimpleRow import java.util.* -open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable { +open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable { @PrimaryKey var id = UUID.randomUUID().toString() @@ -35,6 +36,7 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, override fun stringForRow(row: RowRepresentable): String { return when (row) { SimpleRow.NAME -> this.name + GameRow.SHORT_NAME -> this.shortName?:"" else -> return super.stringForRow(row) } } @@ -43,6 +45,7 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, val data = java.util.ArrayList() when (row) { SimpleRow.NAME -> data.add(BottomSheetData(this.name, SimpleRow.NAME.resId, InputType.TYPE_CLASS_TEXT)) + GameRow.SHORT_NAME -> data.add(BottomSheetData(this.shortName, GameRow.SHORT_NAME.resId, InputType.TYPE_CLASS_TEXT)) } return data } @@ -50,6 +53,11 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, override fun updateValue(value: Any?, row: RowRepresentable) { when (row) { SimpleRow.NAME -> this.name = value as String? ?: "" + GameRow.SHORT_NAME -> this.shortName = value as String } } + + override fun isValidForSave(): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 05bd5dd1..6901c6e1 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -7,6 +7,8 @@ import io.realm.annotations.PrimaryKey import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.SessionInterface import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.extensions.SessionState +import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData @@ -88,15 +90,70 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource // The features of the tournament, like Knockout, Shootout, Turbo... var tournamentFeatures: RealmList = RealmList() - companion object { + /** + * Start a session + */ + fun startSession() { + realm.executeTransaction { + when (getState()) { + SessionState.PENDING -> { + val sessionTimeFrame = this.timeFrame ?: realm.createObject(TimeFrame::class.java) + sessionTimeFrame.setDate(Date(), null) + this.timeFrame = sessionTimeFrame + } + SessionState.PAUSED -> { + this.timeFrame?.paused = false + } + else -> { + } + } + } + } + + /** + * Pause a session + */ + fun pauseSession() { + realm.executeTransaction { + when (getState()) { + SessionState.STARTED -> { + this.timeFrame?.paused = true + } + } + } + } + + /** + * Stop a session + */ + fun stopSession() { + realm.executeTransaction { + when (getState()) { + SessionState.STARTED, SessionState.PAUSED -> { + this.timeFrame?.paused = false + this.timeFrame?.setDate(null, Date()) + } + } + } + } + /** + * Delete the object from realm + * TODO: Cascade delete? + */ + fun delete() { + realm.executeTransaction { + deleteFromRealm() + } + } + + companion object { fun newInstance(): Session { var session: Session = Session() session.result = Result() session.timeFrame = TimeFrame() return session } - } @Ignore // SessionInterface value @@ -161,7 +218,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource override fun adapterRows(): ArrayList { val rows = ArrayList() - rows.addAll(SessionRow.values()) + rows.addAll(SessionRow.getRowsForState(getState())) return rows } @@ -185,7 +242,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource override fun actionIconForRow(row: RowRepresentable): Int? { return when (row) { SessionRow.START_DATE, SessionRow.END_DATE -> { - R.drawable.ic_close_white_24dp + R.drawable.ic_close } else -> null } @@ -204,10 +261,22 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource data.add(BottomSheetData(game, inputType = InputType.TYPE_NULL, data = LiveData.GAME.items(realm))) } SessionRow.LOCATION -> { - data.add(BottomSheetData(location, inputType = InputType.TYPE_NULL, data = LiveData.LOCATION.items(realm))) + data.add( + BottomSheetData( + location, + inputType = InputType.TYPE_NULL, + data = LiveData.LOCATION.items(realm) + ) + ) } SessionRow.BANKROLL -> { - data.add(BottomSheetData(bankroll, inputType = InputType.TYPE_NULL, data = LiveData.BANKROLL.items(realm))) + data.add( + BottomSheetData( + bankroll, + inputType = InputType.TYPE_NULL, + data = LiveData.BANKROLL.items(realm) + ) + ) } SessionRow.BLINDS -> { data.add(BottomSheetData(cgSmallBlind, R.string.smallblind, InputType.TYPE_CLASS_NUMBER)) @@ -223,14 +292,22 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource override fun updateValue(value: Any?, row: RowRepresentable) { realm.beginTransaction() - when(row) { + when (row) { SessionRow.GAME -> game = value as Game? SessionRow.BANKROLL -> bankroll = value as Bankroll? SessionRow.LOCATION -> location = value as Location? SessionRow.COMMENT -> comment = value as String? ?: "" SessionRow.BLINDS -> if (value is ArrayList<*>) { - cgSmallBlind = try {(value[0] as String? ?: "0").toDouble()} catch (e:Exception) {null} - cgBigBlind = try {(value[1] as String? ?: "0").toDouble()} catch (e:Exception) {null} + cgSmallBlind = try { + (value[0] as String? ?: "0").toDouble() + } catch (e: Exception) { + null + } + cgBigBlind = try { + (value[1] as String? ?: "0").toDouble() + } catch (e: Exception) { + null + } } //TODO: Update SessionRow.START_DATE -> if (value is Date) { @@ -251,6 +328,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource } realm.commitTransaction() } + } enum class TournamentKind { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt index 49481045..40dae22f 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt @@ -51,7 +51,7 @@ open class TimeFrame : RealmObject() { @Ignore var session: Session? = null - get() = this.sessions?.first() + //get() = this.sessions?.first() ?: null // Group @LinkingObjects("timeFrame") @@ -61,8 +61,12 @@ open class TimeFrame : RealmObject() { var set: SessionSet? = null get() = this.sets?.first() - fun setDate(startDate: Date, endDate: Date?) { - this.startDate = startDate + fun setDate(startDate: Date?, endDate: Date?) { + + startDate?.let { + this.startDate = startDate + } + this.endDate = endDate this.computeDuration() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt index e7d7810c..0017d653 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt @@ -10,16 +10,21 @@ import net.pokeranalytics.android.ui.fragment.SessionFragment class SessionActivity: PokerAnalyticsActivity() { + enum class IntentKey(val keyName : String) { + IS_TOURNAMENT("IS_TOURNAMENT"), + SESSION_ID("SESSION_ID"); + } + companion object { fun newInstance(context: Context, isTournament: Boolean? = false, sessionId: String? = "") { val intent = Intent(context, SessionActivity::class.java) isTournament?.let { - intent.putExtra("is_tournament", isTournament) + intent.putExtra(IntentKey.IS_TOURNAMENT.keyName, isTournament) } sessionId?.let { - intent.putExtra("session_id", sessionId) + intent.putExtra(IntentKey.SESSION_ID.keyName, sessionId) } context.startActivity(intent) @@ -38,8 +43,8 @@ class SessionActivity: PokerAnalyticsActivity() { * Init UI */ private fun initUI() { - val sessionId = intent.getStringExtra("session_id") - val isTournament = intent.getBooleanExtra("is_tournament", false) + val sessionId = intent.getStringExtra(IntentKey.SESSION_ID.keyName) + val isTournament = intent.getBooleanExtra(IntentKey.IS_TOURNAMENT.keyName, false) val fragment = newSessionFragment as SessionFragment fragment.setData(isTournament, sessionId) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt index 3def2642..343dfcd9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt @@ -111,4 +111,12 @@ class RowRepresentableAdapter(var rowRepresentableDataSource: RowRepresentableDa } } + /** + * Refresh all adapter rows + */ + fun refreshAllRows() { + this.rows = rowRepresentableDataSource.adapterRows() + notifyDataSetChanged() + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt index 7a1041b0..97bc80e7 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt @@ -1,17 +1,19 @@ package net.pokeranalytics.android.ui.fragment +import android.content.DialogInterface import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager -import io.realm.Realm import io.realm.RealmObject import kotlinx.android.synthetic.main.fragment_editable_data.* import kotlinx.android.synthetic.main.fragment_editable_data.view.* import net.pokeranalytics.android.R import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.ObjectSavable import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.adapter.components.* import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment @@ -78,26 +80,56 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, setHasFixedSize(true) layoutManager = viewManager } + + this.saveButton.text = this.saveButton.context.getString(R.string.save) + this.saveButton.setOnClickListener { + + if ((this.item as ObjectSavable).isValidForSave()) { + this.getRealm().executeTransaction { + it.copyToRealmOrUpdate(this.item) + } + this.activity?.let { + it.finish() + } + } else { + val builder = AlertDialog.Builder(it.context) + builder.setTitle(R.string.warning) + .setNegativeButton(R.string.ok, null) + builder.show() + } + } + + this.deleteButton.text = this.deleteButton.context.getString(R.string.delete) + this.deleteButton.setOnClickListener { + val builder = AlertDialog.Builder(it.context) + builder.setTitle(R.string.warning) + .setMessage(R.string.are_you_sure_you_want_to_do_that_) + .setNeutralButton(R.string.no, null) + .setNegativeButton(R.string.yes, DialogInterface.OnClickListener { dialog, id -> + this.getRealm().executeTransaction { + this.item.deleteFromRealm() + } + this.activity?.let { + it.finish() + } + }) + builder.show() + } } /** * Set fragment data */ fun setData(dataType: Int, primaryKey: String?) { - this.liveDataType = LiveData.values()[dataType] - val realm = Realm.getDefaultInstance() - var proxyItem : RealmObject? = this.liveDataType.getData(realm, primaryKey) + var proxyItem : RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey) proxyItem?.let { this.appBar.toolbar.title = "Update ${this.liveDataType.name.toLowerCase().capitalize()}" } ?: run { this.appBar.toolbar.title = "New ${this.liveDataType.name.toLowerCase().capitalize()}" } - - this.item = this.liveDataType.updateOrCreate(realm, primaryKey) - + this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) this.rowRepresentableAdapter = RowRepresentableAdapter((this.item as RowRepresentableDataSource), this) this.recyclerView.adapter = rowRepresentableAdapter - } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index c89e6e56..a71988a4 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -1,15 +1,16 @@ package net.pokeranalytics.android.ui.fragment import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup +import android.view.* import android.widget.Toast +import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.recyclerview.widget.LinearLayoutManager import io.realm.kotlin.where -import kotlinx.android.synthetic.main.fragment_new_session.* +import kotlinx.android.synthetic.main.fragment_session.* import net.pokeranalytics.android.R import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.extensions.SessionState +import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity @@ -21,15 +22,17 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SessionRow +import net.pokeranalytics.android.util.toast +import timber.log.Timber import java.util.* class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, BottomSheetDelegate { private lateinit var currentSession: Session - private lateinit var sessionAdapter : RowRepresentableAdapter + private lateinit var sessionAdapter: RowRepresentableAdapter override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_new_session, container, false) + return inflater.inflate(R.layout.fragment_session, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -37,6 +40,23 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott initUI() } + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + inflater?.inflate(R.menu.session_toolbar, menu) + super.onCreateOptionsMenu(menu, inflater) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.restart -> toast("Restard is clicked!") + R.id.delete -> { + currentSession.delete() + activity?.finish() + } + } + return true + } + + override fun onRowSelected(row: RowRepresentable) { val data = currentSession.getBottomSheetData(row) when (row) { @@ -84,8 +104,13 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott private fun initUI() { val activity = activity as PokerAnalyticsActivity + + // Avoid a bug during setting the title + toolbar.title = "" + activity.setSupportActionBar(toolbar) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) val viewManager = LinearLayoutManager(requireContext()) @@ -94,13 +119,83 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott layoutManager = viewManager } + bottomAppBar.inflateMenu(R.menu.session_bottom_app_bar) + bottomAppBar.menu.findItem(R.id.stop).isVisible = false + + bottomAppBar.setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.stop -> { + currentSession.stopSession() + updateSessionUI() + } + } + false + } + + floatingActionButton.setExpanded(false) + floatingActionButton.setOnClickListener { + manageSessionState() + } + + } + + /** + * Update the UI with the session data + * Should be called after the initialization of the session + */ + private fun updateSessionUI() { + + when (currentSession.getState()) { + SessionState.PENDING -> { + floatingActionButton.setImageResource(R.drawable.ic_outline_play) + bottomAppBar.menu.findItem(R.id.stop).isVisible = false + } + SessionState.STARTED -> { + floatingActionButton.setImageResource(R.drawable.ic_outline_pause) + bottomAppBar.menu.findItem(R.id.stop).isVisible = true + } + SessionState.PAUSED -> { + floatingActionButton.setImageResource(R.drawable.ic_outline_play) + bottomAppBar.menu.findItem(R.id.stop).isVisible = true + } + SessionState.FINISHED -> { + bottomAppBar.menu.findItem(R.id.stop).isVisible = false + floatingActionButton.animate() + .scaleX(0f) + .scaleY(0f) + .alpha(0f) + .setInterpolator(FastOutSlowInInterpolator()) + .start() + } + } + + sessionAdapter.refreshAllRows() + } + + /** + * Update the state of the session (start / pause) + */ + private fun manageSessionState() { + when (currentSession.getState()) { + SessionState.PENDING -> { + currentSession.startSession() + } + SessionState.STARTED -> { + currentSession.pauseSession() + } + SessionState.PAUSED -> { + currentSession.startSession() + } + } + + updateSessionUI() } /** * Set fragment data */ fun setData(isTournament: Boolean, sessionId: String) { - toolbar.title = if (isTournament) "Tournament" else "Cash game" + toolbar.title = if (isTournament) getString(R.string.tournament) else getString(R.string.cash_game) val realm = getRealm() val sessionRealm = realm.where().equalTo("id", sessionId).findFirst() @@ -115,6 +210,8 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott sessionAdapter = RowRepresentableAdapter(currentSession, this) recyclerView.adapter = sessionAdapter + updateSessionUI() + Timber.d("Session state: ${currentSession.getState()}") } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt index 58157e5d..65830541 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt @@ -3,14 +3,13 @@ package net.pokeranalytics.android.ui.view import android.content.Context import net.pokeranalytics.android.R import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType /** - * An interface used so that enums values can be represented visually - * as rows in RecyclerViews + * An interface to easily localize any object */ -interface RowRepresentable { - +interface Localizable { /** * The resource identifier of the localized title */ @@ -28,12 +27,18 @@ interface RowRepresentable { } return "LOCALISATION NOT FOUND" } +} +/** + * An interface used so that enums values can be represented visually + * as rows in RecyclerViews + */ +interface RowRepresentable : Localizable { /** * The type of view associated with the row */ val viewType: Int - get() { + get() { return 0 } @@ -52,32 +57,89 @@ interface RowRepresentable { } enum class SessionRow : RowRepresentable { + + DURATION, + NET_HOURLY_RATE, + BANKROLL_VARIATION, + + CASHED_OUT, + BUY_IN, + TIPS, + GAME, BLINDS, LOCATION, BANKROLL, + TABLE_SIZE, START_DATE, END_DATE, + + BREAK_TIME, COMMENT; + companion object { + /** + * Return the rows to display for the current session state + */ + fun getRowsForState(sessionState: SessionState): ArrayList { + return when (sessionState) { + SessionState.PENDING -> { + arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE) + } + SessionState.STARTED -> { + arrayListOf( + CASHED_OUT, BUY_IN, TIPS, + GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT + ) + } + SessionState.PAUSED -> { + arrayListOf( + CASHED_OUT, BUY_IN, TIPS, + GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT + ) + } + SessionState.FINISHED -> { + arrayListOf( + DURATION, NET_HOURLY_RATE, BANKROLL_VARIATION, + CASHED_OUT, BUY_IN, TIPS, + GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT + ) + } + else -> arrayListOf() + } + } + } + override val resId: Int? get() { return when (this) { - BLINDS -> R.string.blinds + + DURATION -> R.string.duration + NET_HOURLY_RATE -> R.string.hour_rate_without_pauses + BANKROLL_VARIATION -> R.string.bankroll_variation + + CASHED_OUT -> R.string.cashed_out + BUY_IN -> R.string.buyin + TIPS -> R.string.tips + GAME -> R.string.game + BLINDS -> R.string.blinds LOCATION -> R.string.location BANKROLL -> R.string.bankroll - COMMENT -> R.string.comment + TABLE_SIZE -> R.string.table_size START_DATE -> R.string.start_date END_DATE -> R.string.end_date + BREAK_TIME -> R.string.break_time + COMMENT -> R.string.comment } } override val viewType: Int get() { return when (this) { - BLINDS, GAME, BANKROLL, LOCATION, COMMENT -> RowViewType.TITLE_VALUE.ordinal - START_DATE, END_DATE -> RowViewType.TITLE_VALUE_ACTION.ordinal + DURATION, NET_HOURLY_RATE, BANKROLL_VARIATION, + CASHED_OUT, BUY_IN, TIPS, + GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal } } @@ -96,6 +158,7 @@ enum class SessionRow : RowRepresentable { enum class SimpleRow : RowRepresentable { NAME; + override val resId: Int? = R.string.name override val viewType: Int = RowViewType.TITLE_VALUE.ordinal override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT @@ -130,9 +193,53 @@ enum class BankrollRow : RowRepresentable { } enum class GameRow : RowRepresentable { + SHORT_NAME; + + override val resId: Int? + get() { + return when (this) { + SHORT_NAME -> R.string.short_name + } + } + + override val viewType: Int + get() { + return when (this) { + SHORT_NAME -> RowViewType.TITLE_VALUE.ordinal + } + } + + override val bottomSheetType: BottomSheetType + get() { + return when (this) { + SHORT_NAME -> BottomSheetType.EDIT_TEXT + } + } } enum class LocationRow : RowRepresentable { + LOCATION_STATUS; + + override val resId: Int? + get() { + return when (this) { + LOCATION_STATUS -> R.string.short_name + } + } + + override val viewType: Int + get() { + return when (this) { + LOCATION_STATUS -> RowViewType.TITLE.ordinal + } + } + + override val bottomSheetType: BottomSheetType + get() { + return when (this) { + LOCATION_STATUS -> BottomSheetType.NONE + } + } } enum class TransactionTypeRow : RowRepresentable { @@ -141,33 +248,31 @@ enum class TransactionTypeRow : RowRepresentable { enum class TournamentFeatureRow : RowRepresentable { } -enum class SettingRow: RowRepresentable { +enum class SettingRow : RowRepresentable { BANKROLL, GAME, LOCATION, - TOURNAMENT_TYPE, + TOURNAMENT_FEATURE, TRANSACTION_TYPE; override val resId: Int? get() { - return when (this) { - BANKROLL -> R.string.bankroll - GAME -> R.string.game - LOCATION -> R.string.location - TOURNAMENT_TYPE -> R.string.tournament_type - TRANSACTION_TYPE -> R.string.operation_types + this.relatedResultsRepresentable?. let { + return it.resId + } ?: run { + return super.resId } } override val viewType: Int = RowViewType.TITLE.ordinal - override val relatedResultsRepresentable : LiveData? + override val relatedResultsRepresentable: LiveData? get() { return when (this) { BANKROLL -> LiveData.BANKROLL GAME -> LiveData.GAME LOCATION -> LiveData.LOCATION - TOURNAMENT_TYPE -> LiveData.TOURNAMENT_TYPE + TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE } } diff --git a/app/src/main/java/net/pokeranalytics/android/util/Extensions.kt b/app/src/main/java/net/pokeranalytics/android/util/Extensions.kt index 07b21294..b931034e 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Extensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Extensions.kt @@ -1,5 +1,8 @@ package net.pokeranalytics.android.util +import android.widget.Toast +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import java.text.DateFormat import java.util.* @@ -18,4 +21,15 @@ fun Date.medium(): String { fun Date.full(): String { return DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(this) +} + + +// Toast + +fun PokerAnalyticsActivity.toast(message: String) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show() +} + +fun PokerAnalyticsFragment.toast(message: String) { + Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show() } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_white_24dp.xml b/app/src/main/res/drawable/ic_add.xml similarity index 100% rename from app/src/main/res/drawable/ic_add_white_24dp.xml rename to app/src/main/res/drawable/ic_add.xml diff --git a/app/src/main/res/drawable/ic_check_white_24dp.xml b/app/src/main/res/drawable/ic_check.xml similarity index 100% rename from app/src/main/res/drawable/ic_check_white_24dp.xml rename to app/src/main/res/drawable/ic_check.xml diff --git a/app/src/main/res/drawable/ic_close_white_24dp.xml b/app/src/main/res/drawable/ic_close.xml similarity index 100% rename from app/src/main/res/drawable/ic_close_white_24dp.xml rename to app/src/main/res/drawable/ic_close.xml diff --git a/app/src/main/res/drawable/ic_close_24dp.xml b/app/src/main/res/drawable/ic_close_black.xml similarity index 100% rename from app/src/main/res/drawable/ic_close_24dp.xml rename to app/src/main/res/drawable/ic_close_black.xml diff --git a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/app/src/main/res/drawable/ic_dashboard_black_24dp.xml deleted file mode 100644 index 85b70f19..00000000 --- a/app/src/main/res/drawable/ic_dashboard_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_delete_white_24dp.xml b/app/src/main/res/drawable/ic_delete_white_24dp.xml deleted file mode 100644 index 8bed121a..00000000 --- a/app/src/main/res/drawable/ic_delete_white_24dp.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_home_black_24dp.xml b/app/src/main/res/drawable/ic_home_black_24dp.xml deleted file mode 100644 index de832bb2..00000000 --- a/app/src/main/res/drawable/ic_home_black_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/app/src/main/res/drawable/ic_notifications.xml similarity index 91% rename from app/src/main/res/drawable/ic_notifications_black_24dp.xml rename to app/src/main/res/drawable/ic_notifications.xml index fa1d5fe0..cebca454 100644 --- a/app/src/main/res/drawable/ic_notifications_black_24dp.xml +++ b/app/src/main/res/drawable/ic_notifications.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/app/src/main/res/drawable/ic_outline_chart_bar.xml b/app/src/main/res/drawable/ic_outline_chart_bar.xml index bfc0c1e8..b1c1d2f4 100644 --- a/app/src/main/res/drawable/ic_outline_chart_bar.xml +++ b/app/src/main/res/drawable/ic_outline_chart_bar.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_chart_show.xml b/app/src/main/res/drawable/ic_outline_chart_show.xml index 9a7f2079..0d4f8c3f 100644 --- a/app/src/main/res/drawable/ic_outline_chart_show.xml +++ b/app/src/main/res/drawable/ic_outline_chart_show.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_delete.xml b/app/src/main/res/drawable/ic_outline_delete.xml new file mode 100644 index 00000000..2ca348f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_delete.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_outline_filter_list.xml b/app/src/main/res/drawable/ic_outline_filter_list.xml index 5959f25e..c349e010 100644 --- a/app/src/main/res/drawable/ic_outline_filter_list.xml +++ b/app/src/main/res/drawable/ic_outline_filter_list.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_history.xml b/app/src/main/res/drawable/ic_outline_history.xml index c1caa0b0..2de7cb47 100644 --- a/app/src/main/res/drawable/ic_outline_history.xml +++ b/app/src/main/res/drawable/ic_outline_history.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_pause.xml b/app/src/main/res/drawable/ic_outline_pause.xml index ed500a75..d62dc651 100644 --- a/app/src/main/res/drawable/ic_outline_pause.xml +++ b/app/src/main/res/drawable/ic_outline_pause.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_play.xml b/app/src/main/res/drawable/ic_outline_play.xml index a5a83b07..e60f917c 100644 --- a/app/src/main/res/drawable/ic_outline_play.xml +++ b/app/src/main/res/drawable/ic_outline_play.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_restart.xml b/app/src/main/res/drawable/ic_outline_restart.xml new file mode 100644 index 00000000..1fb063df --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_restart.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_outline_settings.xml b/app/src/main/res/drawable/ic_outline_settings.xml index e1fb6a23..364c03b7 100644 --- a/app/src/main/res/drawable/ic_outline_settings.xml +++ b/app/src/main/res/drawable/ic_outline_settings.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_sort.xml b/app/src/main/res/drawable/ic_outline_sort.xml index 26453725..ac6dbe47 100644 --- a/app/src/main/res/drawable/ic_outline_sort.xml +++ b/app/src/main/res/drawable/ic_outline_sort.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_outline_stop.xml b/app/src/main/res/drawable/ic_outline_stop.xml index 5074c18d..28ec1ce3 100644 --- a/app/src/main/res/drawable/ic_outline_stop.xml +++ b/app/src/main/res/drawable/ic_outline_stop.xml @@ -4,6 +4,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/layout/fragment_data_list.xml b/app/src/main/res/layout/fragment_data_list.xml index 49a6b1a3..c2fd9428 100644 --- a/app/src/main/res/layout/fragment_data_list.xml +++ b/app/src/main/res/layout/fragment_data_list.xml @@ -33,7 +33,7 @@ android:layout_height="wrap_content" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" - android:src="@drawable/ic_add_white_24dp" + android:src="@drawable/ic_add" app:fabSize="normal" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> diff --git a/app/src/main/res/layout/fragment_editable_data.xml b/app/src/main/res/layout/fragment_editable_data.xml index d072701e..ed7b8bf4 100644 --- a/app/src/main/res/layout/fragment_editable_data.xml +++ b/app/src/main/res/layout/fragment_editable_data.xml @@ -9,7 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" - app:layout_behavior="@string/appbar_scrolling_view_behavior"> + app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/nestedScrollView"> + app:layout_constraintTop_toTopOf="parent"/> @@ -51,10 +51,24 @@ android:layout_height="?attr/actionBarSize" app:title="Poker Analytics" app:titleTextColor="@color/white" - app:layout_collapseMode="pin" /> + app:layout_collapseMode="pin"/> +