From 90593e6284f80197808f38503cb56014efcba6b7 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:13:37 +0100 Subject: [PATCH 1/7] Add new drawables --- .../main/res/drawable/ic_add_white_24dp.xml | 5 +++ .../main/res/drawable/ic_check_white_24dp.xml | 5 +++ .../main/res/drawable/ic_close_white_24dp.xml | 5 +++ .../res/drawable/ic_delete_white_24dp.xml | 5 +++ .../main/res/layout/fragment_bottom_sheet.xml | 25 +++++++++++ .../fragment_bottom_sheet_container.xml | 45 ------------------- 6 files changed, 45 insertions(+), 45 deletions(-) create mode 100644 app/src/main/res/drawable/ic_add_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_check_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_close_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_delete_white_24dp.xml create mode 100644 app/src/main/res/layout/fragment_bottom_sheet.xml delete mode 100644 app/src/main/res/layout/fragment_bottom_sheet_container.xml diff --git a/app/src/main/res/drawable/ic_add_white_24dp.xml b/app/src/main/res/drawable/ic_add_white_24dp.xml new file mode 100644 index 00000000..e3979cd7 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_check_white_24dp.xml b/app/src/main/res/drawable/ic_check_white_24dp.xml new file mode 100644 index 00000000..17aca2af --- /dev/null +++ b/app/src/main/res/drawable/ic_check_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_close_white_24dp.xml b/app/src/main/res/drawable/ic_close_white_24dp.xml new file mode 100644 index 00000000..0c8775c4 --- /dev/null +++ b/app/src/main/res/drawable/ic_close_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_delete_white_24dp.xml b/app/src/main/res/drawable/ic_delete_white_24dp.xml new file mode 100644 index 00000000..8bed121a --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_white_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/fragment_bottom_sheet.xml b/app/src/main/res/layout/fragment_bottom_sheet.xml new file mode 100644 index 00000000..11c21412 --- /dev/null +++ b/app/src/main/res/layout/fragment_bottom_sheet.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bottom_sheet_container.xml b/app/src/main/res/layout/fragment_bottom_sheet_container.xml deleted file mode 100644 index 41ecaf8f..00000000 --- a/app/src/main/res/layout/fragment_bottom_sheet_container.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - \ No newline at end of file From 28518f1574b2c12914be39e4c1e4752f65b94718 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:13:58 +0100 Subject: [PATCH 2/7] Add new bottom sheet layouts --- .../main/res/layout/bottom_sheet_blinds.xml | 59 +++++++++++++++++++ app/src/main/res/layout/bottom_sheet_game.xml | 11 ++++ .../main/res/layout/fragment_bottom_sheet.xml | 9 ++- app/src/main/res/menu/bottom_sheet_menu.xml | 23 ++++++++ 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 app/src/main/res/layout/bottom_sheet_blinds.xml create mode 100644 app/src/main/res/layout/bottom_sheet_game.xml create mode 100644 app/src/main/res/menu/bottom_sheet_menu.xml diff --git a/app/src/main/res/layout/bottom_sheet_blinds.xml b/app/src/main/res/layout/bottom_sheet_blinds.xml new file mode 100644 index 00000000..c0d86a55 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_blinds.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_game.xml b/app/src/main/res/layout/bottom_sheet_game.xml new file mode 100644 index 00000000..7372733e --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_game.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_bottom_sheet.xml b/app/src/main/res/layout/fragment_bottom_sheet.xml index 11c21412..76eabc63 100644 --- a/app/src/main/res/layout/fragment_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_bottom_sheet.xml @@ -1,17 +1,20 @@ + app:layout_constraintTop_toTopOf="parent" + tools:title="Test" /> + app:layout_constraintTop_toBottomOf="@+id/bottomSheetToolbar" /> \ No newline at end of file diff --git a/app/src/main/res/menu/bottom_sheet_menu.xml b/app/src/main/res/menu/bottom_sheet_menu.xml new file mode 100644 index 00000000..f1301ad6 --- /dev/null +++ b/app/src/main/res/menu/bottom_sheet_menu.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file From 20f166146d00864fafc083aea4dbaa0a2786d4a3 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:14:05 +0100 Subject: [PATCH 3/7] Update style --- app/src/main/res/values/styles.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1c56072b..9d7c9fb5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -8,4 +8,10 @@ @color/colorAccent + + + From a92c2acd880993f822111ba6496a310f45787f5b Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:52:44 +0100 Subject: [PATCH 4/7] Add layouts --- .../main/res/layout/bottom_sheet_bankroll.xml | 13 ++++++++ app/src/main/res/layout/bottom_sheet_date.xml | 32 +++++++++++++++++++ app/src/main/res/layout/bottom_sheet_game.xml | 16 +++++++--- .../main/res/layout/bottom_sheet_location.xml | 13 ++++++++ .../res/layout/bottom_sheet_table_size.xml | 13 ++++++++ 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/layout/bottom_sheet_bankroll.xml create mode 100644 app/src/main/res/layout/bottom_sheet_date.xml create mode 100644 app/src/main/res/layout/bottom_sheet_location.xml create mode 100644 app/src/main/res/layout/bottom_sheet_table_size.xml diff --git a/app/src/main/res/layout/bottom_sheet_bankroll.xml b/app/src/main/res/layout/bottom_sheet_bankroll.xml new file mode 100644 index 00000000..56b38a58 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_bankroll.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_date.xml b/app/src/main/res/layout/bottom_sheet_date.xml new file mode 100644 index 00000000..d04e9d17 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_date.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_game.xml b/app/src/main/res/layout/bottom_sheet_game.xml index 7372733e..5a052178 100644 --- a/app/src/main/res/layout/bottom_sheet_game.xml +++ b/app/src/main/res/layout/bottom_sheet_game.xml @@ -1,11 +1,19 @@ - + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_location.xml b/app/src/main/res/layout/bottom_sheet_location.xml new file mode 100644 index 00000000..7546616e --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_location.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bottom_sheet_table_size.xml b/app/src/main/res/layout/bottom_sheet_table_size.xml new file mode 100644 index 00000000..7546616e --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_table_size.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file From 1d8fd2aff5210714302d56b90b0d1d0748afbd75 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:52:56 +0100 Subject: [PATCH 5/7] Add date & time helper classes --- .../android/util/DatePickerFragment.kt | 26 +++++++++++++++++++ .../android/util/TimePickerFragment.kt | 26 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 app/src/main/java/net/pokeranalytics/android/util/DatePickerFragment.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/util/TimePickerFragment.kt diff --git a/app/src/main/java/net/pokeranalytics/android/util/DatePickerFragment.kt b/app/src/main/java/net/pokeranalytics/android/util/DatePickerFragment.kt new file mode 100644 index 00000000..dd81a825 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/util/DatePickerFragment.kt @@ -0,0 +1,26 @@ +package net.pokeranalytics.android.util + +import android.app.DatePickerDialog +import android.app.Dialog +import android.os.Bundle +import android.widget.DatePicker +import androidx.fragment.app.DialogFragment +import java.util.* + +class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + // Use the current date as the default date in the picker + val c = Calendar.getInstance() + val year = c.get(Calendar.YEAR) + val month = c.get(Calendar.MONTH) + val day = c.get(Calendar.DAY_OF_MONTH) + + // Create a new instance of DatePickerDialog and return it + return DatePickerDialog(activity, this, year, month, day) + } + + override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) { + // Do something with the date chosen by the user + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/TimePickerFragment.kt b/app/src/main/java/net/pokeranalytics/android/util/TimePickerFragment.kt new file mode 100644 index 00000000..aeae4652 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/util/TimePickerFragment.kt @@ -0,0 +1,26 @@ +package net.pokeranalytics.android.util + +import android.app.Dialog +import android.app.TimePickerDialog +import android.os.Bundle +import android.text.format.DateFormat +import android.widget.TimePicker +import androidx.fragment.app.DialogFragment +import java.util.* + +class TimePickerFragment : DialogFragment(), TimePickerDialog.OnTimeSetListener { + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + // Use the current time as the default values for the picker + val c = Calendar.getInstance() + val hour = c.get(Calendar.HOUR_OF_DAY) + val minute = c.get(Calendar.MINUTE) + + // Create a new instance of TimePickerDialog and return it + return TimePickerDialog(activity, this, hour, minute, DateFormat.is24HourFormat(activity)) + } + + override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) { + // Do something with the time chosen by the user + } +} \ No newline at end of file From e7d1b1a231e7aadf8e4495ba0b9924493e912b7d Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 14 Feb 2019 15:53:31 +0100 Subject: [PATCH 6/7] Start bottom sheet customization --- .../adapter/components/DynamicListAdapter.kt | 2 +- .../adapter/components/DynamicRowInterface.kt | 104 +++++++------ .../ui/fragment/BottomSheetFragment.kt | 137 +++++++++++++++--- .../android/ui/fragment/NewSessionFragment.kt | 11 +- .../android/ui/fragment/SettingsFragment.kt | 2 +- .../ui/fragment/components/BottomSheetType.kt | 13 ++ .../android/util/PokerAnalyticsFragment.kt | 3 +- 7 files changed, 193 insertions(+), 79 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BottomSheetType.kt diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicListAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicListAdapter.kt index 9cd13d2a..4b047693 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicListAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicListAdapter.kt @@ -6,7 +6,7 @@ import android.widget.Toast import androidx.recyclerview.widget.RecyclerView import io.realm.Realm.init -interface EditableDataDelegate : DynamicRowDelegate { +interface EditableDataDelegate { fun setValue(value: Any, row: DynamicRowInterface) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicRowInterface.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicRowInterface.kt index 1ef17b2d..138681c6 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicRowInterface.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicRowInterface.kt @@ -2,69 +2,77 @@ package net.pokeranalytics.android.ui.adapter.components import android.content.Context import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.fragment.components.BottomSheetType -class SectionRow(stringRes: Int) : DynamicRowInterface { - - var stringRes: Int = stringRes - - override fun localizedTitle(context: Context): String { - return context.getString(this.stringRes) - } - - override var viewType: Int = 0 - +interface DynamicRowInterface { + fun localizedTitle(context: Context): String + var viewType: Int + var bottomSheetType: BottomSheetType } -interface DynamicRowInterface { +class SectionRow(stringRes: Int) : DynamicRowInterface { - fun localizedTitle(context: Context): String - var viewType: Int + var stringRes: Int = stringRes + override fun localizedTitle(context: Context): String { + return context.getString(this.stringRes) + } + + override var viewType: Int = 0 + override var bottomSheetType: BottomSheetType = BottomSheetType.NONE } enum class SessionRow(val resId: Int) : DynamicRowInterface { - BLINDS(R.string.app_name), - GAME(R.string.title_history), - DATE(R.string.title_settings); - - override fun localizedTitle(context: Context): String { - return context.getString(this.resId) - } - - override var viewType: Int = RowViewType.HEADER.ordinal - get() { - return when (this) { - BLINDS, GAME, DATE -> RowViewType.TITLE_VALUE.ordinal - } - } - + BLINDS(R.string.app_name), + GAME(R.string.title_history), + DATE(R.string.title_settings); + + override fun localizedTitle(context: Context): String { + return context.getString(this.resId) + } + + override var viewType: Int = RowViewType.HEADER.ordinal + get() { + return when (this) { + BLINDS, GAME, DATE -> RowViewType.TITLE_VALUE.ordinal + } + } + + override var bottomSheetType: BottomSheetType = BottomSheetType.NONE + get() { + return when (this) { + BLINDS -> BottomSheetType.BLINDS + GAME -> BottomSheetType.GAME + DATE -> BottomSheetType.DATE + } + } } enum class BankrollRow(val resId: Int) : DynamicRowInterface { - NAME(R.string.app_name), - LIVE(R.string.app_name), - CURRENCY(R.string.app_name); + NAME(R.string.app_name), + LIVE(R.string.app_name), + CURRENCY(R.string.app_name); - override fun localizedTitle(context: Context): String { - return context.getString(this.resId) - } - - override var viewType: Int = 1 + override fun localizedTitle(context: Context): String { + return context.getString(this.resId) + } + override var viewType: Int = 1 + override var bottomSheetType: BottomSheetType = BottomSheetType.NONE } enum class BusinessObjectRowType(val resId: Int) : DynamicRowInterface { - BANKROLL(R.string.bankroll), - GAME(R.string.game), - LOCATION(R.string.location), - TOURNAMENT_TYPE(R.string.tournament_type), - TRANSACTION_TYPE(R.string.transaction_type); - - override fun localizedTitle(context: Context): String { - return context.getString(this.resId) - } - - override var viewType: Int = RowViewType.TITLE.ordinal - + BANKROLL(R.string.bankroll), + GAME(R.string.game), + LOCATION(R.string.location), + TOURNAMENT_TYPE(R.string.tournament_type), + TRANSACTION_TYPE(R.string.transaction_type); + + override fun localizedTitle(context: Context): String { + return context.getString(this.resId) + } + + override var viewType: Int = RowViewType.TITLE.ordinal + override var bottomSheetType: BottomSheetType = BottomSheetType.NONE } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BottomSheetFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BottomSheetFragment.kt index c1970ca4..b306cdfd 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BottomSheetFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BottomSheetFragment.kt @@ -1,21 +1,76 @@ package net.pokeranalytics.android.ui.fragment +import android.app.DatePickerDialog import android.os.Bundle import com.google.android.material.bottomsheet.BottomSheetDialogFragment -import kotlinx.android.synthetic.main.fragment_bottom_sheet_container.* -import android.content.Context import android.content.DialogInterface import android.view.* -import android.view.inputmethod.InputMethodManager - +import androidx.constraintlayout.widget.ConstraintLayout +import kotlinx.android.synthetic.main.bottom_sheet_blinds.* +import kotlinx.android.synthetic.main.bottom_sheet_date.* +import kotlinx.android.synthetic.main.fragment_bottom_sheet.* +import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.* +import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface +import net.pokeranalytics.android.ui.adapter.components.EditableDataDelegate +import net.pokeranalytics.android.ui.fragment.components.BottomSheetType +import timber.log.Timber +import android.widget.DatePicker +import net.pokeranalytics.android.util.DatePickerFragment +import net.pokeranalytics.android.util.TimePickerFragment +import java.util.* class BottomSheetFragment : BottomSheetDialogFragment() { + private var row: DynamicRowInterface? = null + private var valueDelegate: EditableDataDelegate? = null + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate( + net.pokeranalytics.android.R.layout.fragment_bottom_sheet, + container, + false + ) as ConstraintLayout + + row?.let { + when (it.bottomSheetType) { + BottomSheetType.BANKROLL -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_bankroll, + view.bottomSheetContainer, + true + ) + BottomSheetType.BLINDS -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_blinds, + view.bottomSheetContainer, + true + ) + BottomSheetType.DATE -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_date, + view.bottomSheetContainer, + true + ) + BottomSheetType.GAME -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_game, + view.bottomSheetContainer, + true + ) + BottomSheetType.LOCATION -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_location, + view.bottomSheetContainer, + true + ) + BottomSheetType.TABLE_SIZE -> inflater.inflate( + net.pokeranalytics.android.R.layout.bottom_sheet_table_size, + view.bottomSheetContainer, + true + ) + else -> { + } + } + } - return inflater.inflate(net.pokeranalytics.android.R.layout.fragment_bottom_sheet_container, container, false) + return view } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -23,46 +78,80 @@ class BottomSheetFragment : BottomSheetDialogFragment() { initUI() } + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + // To display correctly the keyboard + dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) + } + override fun onStart() { super.onStart() // Open the keyboard - /* - val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) - editText.requestFocus() - */ + row?.let { + when (it.bottomSheetType) { + BottomSheetType.BLINDS -> { + smallBlind.requestFocus() + } + else -> { + } + } + } } - /** - * Actions: - * - Add / Add ? - * - Clear / Garbage ? - * - Done / Check ? - * - - */ - override fun onDismiss(dialog: DialogInterface?) { super.onDismiss(dialog) - val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0) + + // Return the value + row?.let { + valueDelegate?.setValue("Test", it) + } } /** * Init UI */ private fun initUI() { - close.setOnClickListener { - dismiss() + + row?.let { + //bottomSheetToolbar.title = row?.localizedTitle(requireContext()) + bottomSheetToolbar.inflateMenu(net.pokeranalytics.android.R.menu.bottom_sheet_menu) + bottomSheetToolbar.setOnMenuItemClickListener { + false + } + } + + row?.let { + when (it.bottomSheetType) { + BottomSheetType.DATE -> initDateUI() + else -> {} + } } } /** - * + * Init date UI */ - fun displayDataForRow() { + private fun initDateUI() { + + startDate.setOnClickListener { + val dateFragment = DatePickerFragment() + dateFragment.show(fragmentManager, "datePicker") + } + + endDate.setOnClickListener { + val timeFragment = TimePickerFragment() + timeFragment.show(fragmentManager, "timePicker") + } } + /** + * Init + */ + fun init(row: DynamicRowInterface, valueDelegate: EditableDataDelegate) { + this.row = row + this.valueDelegate = valueDelegate + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/NewSessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/NewSessionFragment.kt index 1b0d7def..2daa7e57 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/NewSessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/NewSessionFragment.kt @@ -18,9 +18,10 @@ import net.pokeranalytics.android.ui.adapter.NewSessionAdapter import net.pokeranalytics.android.ui.adapter.components.DynamicListAdapter import net.pokeranalytics.android.ui.adapter.components.DynamicRowCallback import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface +import net.pokeranalytics.android.ui.adapter.components.EditableDataDelegate import net.pokeranalytics.android.util.PokerAnalyticsFragment -class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback { +class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback, EditableDataDelegate { private lateinit var newSession: Session @@ -30,13 +31,17 @@ class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initData() initUI() } override fun onRowSelected(row: DynamicRowInterface) { - val bottomSheetFragment = openBottomSheet(row) + val bottomSheetFragment = openBottomSheet() + bottomSheetFragment.init(row, this) + } + + override fun setValue(value: Any, row: DynamicRowInterface) { + Toast.makeText(requireContext(), "Callback for ${row.localizedTitle(requireContext())} ($value)", Toast.LENGTH_SHORT).show() } private fun initData() { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt index 499a5ad6..e6ee295c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt @@ -45,7 +45,7 @@ class SettingsFragment : PokerAnalyticsFragment(), DynamicRowDelegate, DynamicRo } override fun onRowSelected(row: DynamicRowInterface) { - val bottomSheetFragment = openBottomSheet(row) + //val bottomSheetFragment = openBottomSheet(row) } /** diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BottomSheetType.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BottomSheetType.kt new file mode 100644 index 00000000..61127db5 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BottomSheetType.kt @@ -0,0 +1,13 @@ +package net.pokeranalytics.android.ui.fragment.components + +enum class BottomSheetType { + + NONE, + GAME, + BLINDS, + LOCATION, + BANKROLL, + TABLE_SIZE, + DATE + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/PokerAnalyticsFragment.kt b/app/src/main/java/net/pokeranalytics/android/util/PokerAnalyticsFragment.kt index 6687471e..754429c3 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/PokerAnalyticsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/PokerAnalyticsFragment.kt @@ -27,8 +27,7 @@ open class PokerAnalyticsFragment: Fragment() { /** * Open the bottom sheet */ - fun openBottomSheet(row: DynamicRowInterface): BottomSheetFragment { - //TODO: Give the data to display in the bottom sheet here + fun openBottomSheet(): BottomSheetFragment { val bottomSheetFragment = BottomSheetFragment() bottomSheetFragment.show(fragmentManager, "bottomSheet") return bottomSheetFragment From 1ccd36edc24fd8eb81fb6dc7c979906d34522632 Mon Sep 17 00:00:00 2001 From: Laurent Date: Thu, 14 Feb 2019 16:01:33 +0100 Subject: [PATCH 7/7] Added stats + calculation --- .../android/calculus/Calculator.kt | 118 +++++++++++++++--- .../android/calculus/Computable.kt | 4 + .../pokeranalytics/android/calculus/Stat.kt | 35 +++++- .../android/model/realm/Result.kt | 2 +- .../android/model/realm/Session.kt | 73 ++++++++--- .../android/model/realm/TimeFrame.kt | 61 ++++++++- .../android/model/realm/TimeFrameGroup.kt | 15 ++- .../pokeranalytics/android/ExampleUnitTest.kt | 43 ++++++- 8 files changed, 296 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index 3cb8d1ff..4dbdd4b0 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.calculus +import net.pokeranalytics.android.calculus.Stat.* import net.pokeranalytics.android.model.realm.TimeFrameGroup @@ -25,6 +26,15 @@ class Calculator { var evolutionValues: EvolutionValues = EvolutionValues.NONE var displayedStats: List = listOf() + fun shouldComputeStandardDeviation() : Boolean { + this.displayedStats.forEach { stat -> + when (stat) { + STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> return true + } + } + return false + } + // var aggregation: Aggregation? = null } @@ -62,43 +72,113 @@ class Calculator { fun compute(group: SessionGroup, options: Options) : ComputedResults { val sessions: List = group.sessionGroup - val series: Set = setOf() // @todo get unique list of serie + val sessionGroups: Set = setOf() // @todo get unique list of serie var results: ComputedResults = ComputedResults() var sum: Double = 0.0 - var duration: Double = 0.0 + var totalHands: Double = 0.0 + var bbSum: Double = 0.0 + var bbSessionCount: Int = 0 + var winningSessionCount: Int = 0 + var totalBuyin: Double = 0.0 + // @todo add all stats // Compute for each session - sessions.forEach { item -> - sum += item.value - - when (options.evolutionValues) { - Options.EvolutionValues.STANDARD -> { - results.addEvolutionValue(sum, Stat.NETRESULT) - } - Options.EvolutionValues.DATED -> { - results.addEvolutionValue(sum, duration, Stat.NETRESULT) - } + var index: Int = 0 + sessions.forEach { s -> + index++; + + bbSessionCount += s.bigBlindSessionCount + if (s.value >= 0) { + winningSessionCount++ + } + totalBuyin += s.buyin + + if (options.evolutionValues != Options.EvolutionValues.NONE) { + + sum += s.value + totalHands += s.estimatedHands + bbSum += s.bbNetResult + + results.addEvolutionValue(sum / index, AVERAGE) + results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES) + results.addEvolutionValue(bbSum / bbSessionCount, AVERAGE_NET_BB) + results.addEvolutionValue((winningSessionCount / index).toDouble(), WIN_RATIO) + results.addEvolutionValue(totalBuyin / index, AVERAGE_BUYIN) + results.addEvolutionValue(Stat.returnOnInvestment(sum, totalBuyin), ROI) } } // Compute for each serie - series.forEach { serie -> - duration += serie.duration + var duration: Double = 0.0 + var hourlyRate: Double = 0.0; var hourlyRateBB: Double = 0.0 + + index = 0; sum = 0.0; totalHands = 0.0; bbSum = 0.0; + sessionGroups.forEach { group -> + index++ + duration += group.duration + sum += group.netResult + totalHands += group.estimatedHands + bbSum += group.bbNetResult + + hourlyRate = sum / duration * 3600.0 + hourlyRateBB = bbSum / duration * 3600.0 if (options.evolutionValues != Options.EvolutionValues.NONE) { - results.addEvolutionValue(duration, Stat.DURATION) + results.addEvolutionValue(sum, duration, NETRESULT) + results.addEvolutionValue(sum / duration * 3600.0, duration, HOURLY_RATE) + results.addEvolutionValue(Stat.netBBPer100Hands(bbSum, totalHands), duration, NET_BB_PER_100_HANDS) + results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE) + results.addEvolutionValue(index.toDouble(), duration, NUMBER_OF_GROUPS) + results.addEvolutionValue(group.duration, duration, DURATION) + results.addEvolutionValue(duration / index, duration, AVERAGE_DURATION) + results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB) } } + val average: Double = sum / sessions.size + // Create stats results.addStats(setOf( - ComputedStat(Stat.NETRESULT, sum), - ComputedStat(Stat.AVERAGE,sum / sessions.size), - ComputedStat(Stat.DURATION, duration) - )) + ComputedStat(NETRESULT, sum), + ComputedStat(HOURLY_RATE, hourlyRate), + ComputedStat(AVERAGE, average), + ComputedStat(DURATION, duration), + ComputedStat(NUMBER_OF_GROUPS, sessionGroups.size.toDouble()), + ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()), + ComputedStat(AVERAGE_DURATION, (duration / 3600.0) / sessions.size), + ComputedStat(NET_BB_PER_100_HANDS, Stat.netBBPer100Hands(bbSum, totalHands)), + ComputedStat(HOURLY_RATE_BB, bbSum / duration * 3600.0), + ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount), + ComputedStat(WIN_RATIO, (winningSessionCount / sessions.size).toDouble()), + ComputedStat(AVERAGE_BUYIN, totalBuyin / sessions.size), + ComputedStat(ROI, Stat.returnOnInvestment(sum, totalBuyin)) + + )) + + + // Standard Deviation + if (options.shouldComputeStandardDeviation()) { + + var stdSum: Double = 0.0 + sessions.forEach { s -> + stdSum += Math.pow(s.value - average, 2.0) + } + val standardDeviation: Double = Math.sqrt(stdSum / sessions.size) + + var hourlyStdSum: Double = 0.0 + sessionGroups.forEach { sg -> + hourlyStdSum += Math.pow(sg.hourlyRate - hourlyRate, 2.0) + } + val hourlyStandardDeviation: Double = Math.sqrt(hourlyStdSum / sessionGroups.size) + + results.addStats(setOf( + ComputedStat(STANDARD_DEVIATION, standardDeviation), + ComputedStat(Stat.STANDARD_DEVIATION_HOURLY, hourlyStandardDeviation) + )) + } return results } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt index fda109f8..2d341fa9 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt @@ -10,6 +10,10 @@ interface Summable { // An interface describing some class that can be computed interface SessionInterface : Summable { var serie: TimeFrameGroup + var estimatedHands: Double + var bbNetResult: Double + var bigBlindSessionCount: Int // 0 or 1 + var buyin: Double } /** diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index d3a9afda..a77de252 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -7,25 +7,48 @@ interface AnyStat { enum class Stat : AnyStat { NETRESULT, - HOURLYRATE, - DURATION, + HOURLY_RATE, AVERAGE, - STANDARDDEVIATION, - HOURLYSTANDARDDEVIATION; + NUMBER_OF_GROUPS, + NUMBER_OF_GAMES, + DURATION, + AVERAGE_DURATION, + NET_BB_PER_100_HANDS, + HOURLY_RATE_BB, + AVERAGE_NET_BB, + WIN_RATIO, + AVERAGE_BUYIN, + ROI, + STANDARD_DEVIATION, + STANDARD_DEVIATION_HOURLY, + STANDARD_DEVIATION_BB_PER_100_HANDS; fun label() : String = when (this) { NETRESULT -> "" - HOURLYRATE -> "" + HOURLY_RATE -> "" else -> throw IllegalArgumentException("Label not defined") } fun hasDistributionSorting() : Boolean { when (this) { - STANDARDDEVIATION, HOURLYSTANDARDDEVIATION -> return true + STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> return true else -> return false } } + companion object { + + fun returnOnInvestment(netResult: Double, buyin: Double) : Double { + return netResult / buyin + } + + fun netBBPer100Hands(netBB: Double, numberOfHands: Double) : Double { + return netBB / numberOfHands * 100 + } + + } + + } enum class CashSessionStat : AnyStat { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt index f0fa0f89..548f27b0 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt @@ -36,7 +36,7 @@ open class Result : RealmObject() { } // The net (readonly) - var net: Double? = null + var net: Double = 0.0 // The transactions associated with the Result, impacting the result var transactions: RealmList = RealmList() 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 04e17243..01a66795 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 @@ -1,18 +1,13 @@ package net.pokeranalytics.android.model.realm -import io.realm.RealmList -import io.realm.Realm -import io.realm.RealmObject -import io.realm.RealmResults -import io.realm.Sort +import io.realm.* +import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey -import net.pokeranalytics.android.* import net.pokeranalytics.android.ui.adapter.components.DynamicRowDelegate import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface import net.pokeranalytics.android.ui.adapter.components.SessionRow import net.pokeranalytics.android.util.data.sessionDao import java.util.* -import java.util.UUID.randomUUID import kotlin.collections.ArrayList @@ -21,6 +16,9 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate { @PrimaryKey var id = UUID.randomUUID().toString() + // The result of the main user + var result: Result? = null + // The time frame of the Session, i.e. the start & end date var timeFrame: TimeFrame? = null @@ -30,30 +28,27 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate { // the date of creation of the app var creationDate: Date = Date() + // The bankroll hosting the results + var bankroll: Bankroll? = null + // The limit type: NL, PL... var limit: Int? = null - // The number of tables played at the same time - var numberOfTables: Int = 1 + // The game played during the Session + var game: Game? = null // The number of players at the table var tableSize: Int? = null - // The game played during the Session - var game: Game? = null + // the location where the session is played + var location: Location? = null - // The bankroll hosting the results - var bankroll: Bankroll? = null + // The number of tables played at the same time + var numberOfTables: Int = 1 // The hands list associated with the Session var hands: RealmList = RealmList() - // the location where the session is played - var location: Location? = null - - // The result of the main user - var result: Result? = null - // The list of opponents who participated to the session var opponents: RealmList = RealmList() @@ -85,6 +80,46 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate { // The features of the tournament, like Knockout, Shootout, Turbo... var tournamentFeatures: RealmList = RealmList() + companion object { + + fun newInstance() : Session { + var session: Session = Session() + session.result = Result() + session.timeFrame = TimeFrame() + return session + } + + } + + @Ignore + var estimatedHands: Double = 0.0 + + @Ignore + var bbNetResult: Double = 0.0 + get() { + this.cgBigBlind?.let { bb -> + this.result?.let { result -> + return result.net / bb + } + } + return 0.0 + } + + @Ignore + var bigBlindSessionCount: Int = if (this.cgBigBlind != null) 1 else 0 +// get() = if (this.cgBigBlind != null) 1 else 0 + + @Ignore + var buyin: Double = 0.0 + get() { + this.result?.let { + it.buyin?.let { + return it + } + } + return 0.0 + } + override fun adapterRows(): ArrayList { val rows = ArrayList() 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 886028a7..32042c33 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 @@ -1,24 +1,79 @@ package net.pokeranalytics.android.model.realm import io.realm.RealmObject -import io.realm.annotations.PrimaryKey +import io.realm.RealmResults +import io.realm.annotations.LinkingObjects import java.util.* + + open class TimeFrame : RealmObject() { // A start date var startDate: Date = Date() + set(value) { + field = value + this.computeDuration() + if (this.session != null) { + this.notifyDateChange() + } + } // An end date var endDate: Date? = null + set(value) { + field = value + this.computeDuration() + if (this.session != null) { + this.notifyDateChange() + } + } // The break duration - var breakDuration: Double = 0.0 + var breakDuration: Long = 0L + set(value) { + field = value + this.computeDuration() + } // the total duration - var duration: Double = 0.0 + var duration: Long = 0L + private set // indicates a state of pause var paused: Boolean = false + @LinkingObjects("timeFrame") + private val session: RealmResults? = null + + @LinkingObjects("timeFrame") + private val group: RealmResults? = null + + private fun computeDuration() { + + var endDate: Date + if (this.endDate != null) { + endDate = this.endDate!! + } else { + endDate = Date() + } + this.duration = endDate.time - startDate.time - this.breakDuration + } + + private fun notifyDateChange() { +// val realm = Realm.getDefaultInstance() +// +// var query: RealmQuery = realm.where(TimeFrame::class.java) +// query.greaterThan("startDate", this.startDate.time) +// +// this.endDate?.let { endDate -> +// query.or() +// .greaterThan("startDate", endDate.time) +// .lessThan("endDate", endDate.time) +// } +// +// +// realm.close() + } + } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrameGroup.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrameGroup.kt index 4cd6726e..02777b1e 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrameGroup.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrameGroup.kt @@ -3,8 +3,6 @@ package net.pokeranalytics.android.model.realm import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.Ignore -import io.realm.annotations.PrimaryKey -import java.util.* open class TimeFrameGroup() : RealmObject() { @@ -13,10 +11,21 @@ open class TimeFrameGroup() : RealmObject() { var timeFrame: TimeFrame? = null // The list of Session played within the group, i.e. played within the same time frame - var timeFrames: RealmList = RealmList() + var sessions: RealmList = RealmList() @Ignore // a duration shortcut var duration: Double = 0.0 + @Ignore // a netResult shortcut + var netResult: Double = 0.0 + + @Ignore // a duration shortcut + var hourlyRate: Double = 0.0 + + @Ignore + var estimatedHands: Double = 0.0 + + @Ignore + var bbNetResult: Double = 0.0 } diff --git a/app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt b/app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt index 4dc74ef7..b6fbf93a 100644 --- a/app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt +++ b/app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt @@ -1,17 +1,52 @@ package net.pokeranalytics.android +import net.pokeranalytics.android.calculus.* +import net.pokeranalytics.android.model.realm.TimeFrameGroup +import org.junit.Assert.fail import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * * See [testing documentation](http://d.android.com/tools/testing). */ + class ExampleUnitTest { + + class Grade(someValue: Double) : SessionInterface { +// override var serie: Serie = Serie(TimeFrame()) + override var value: Double = someValue + + override var serie: TimeFrameGroup = TimeFrameGroup() + override var estimatedHands: Double = 0.0 + override var bbNetResult: Double = 0.0 + override var bigBlindSessionCount: Int = 0 // 0 or 1 + override var buyin: Double = 0.0 + + } + @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) + fun testStats() { + + val grades: List = listOf(Grade(someValue = 10.0), Grade(someValue = 20.0)) + val group = SessionGroup(name = "test", sessions = grades) + + val results: ComputedResults = Calculator.compute(group, Calculator.Options()) + + val sum = results.computedStat(Stat.NETRESULT) + if (sum != null) { + assert(sum.value == 30.0) + } else { + fail("No Net result stat") + } + + val average = results.computedStat(Stat.AVERAGE) + if (average != null) { + assert(average.value == 15.0) + } else { + fail("No AVERAGE stat") + } + } + }