Laurent 7 years ago
commit 0b60373f24
  1. 244
      app/src/main/AndroidManifest.xml
  2. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  3. 12
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  4. 25
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  5. 12
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  6. 48
      app/src/main/java/net/pokeranalytics/android/ui/activity/BankrollDetailsActivity.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/activity/EditableDataActivity.kt
  8. 1
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  9. 127
      app/src/main/java/net/pokeranalytics/android/ui/activity/NewDataMenuActivity.kt
  10. 4
      app/src/main/java/net/pokeranalytics/android/ui/adapter/ComparisonChartPagerAdapter.kt
  11. 18
      app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt
  12. 166
      app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedTransactionRowRepresentableAdapter.kt
  13. 6
      app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt
  14. 166
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt
  15. 11
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollEditDataFragment.kt
  16. 105
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt
  17. 27
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarDetailsFragment.kt
  18. 192
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt
  19. 152
      app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt
  20. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  21. 65
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetType.kt
  22. 6
      app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt
  23. 9
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  24. 69
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  25. 3
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GraphRow.kt
  26. 1
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt
  27. 7
      app/src/main/res/layout/activity_bankroll_details.xml
  28. 132
      app/src/main/res/layout/activity_new_data.xml
  29. 56
      app/src/main/res/layout/fragment_bankroll_details.xml
  30. 96
      app/src/main/res/layout/fragment_feed.xml
  31. 0
      app/src/main/res/layout/row_feed_session.xml
  32. 11
      app/src/main/res/menu/toolbar_bankroll_details.xml
  33. 13
      app/src/main/res/values/styles.xml

@ -1,120 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.pokeranalytics.android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:name=".PokerAnalyticsApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/PokerAnalyticsTheme">
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
<activity
android:name="net.pokeranalytics.android.ui.activity.HomeActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="net.pokeranalytics.android.ui.activity.SessionActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing" />
<activity
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.StatisticDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ReportDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.DataListActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.EditableDataActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.CurrenciesActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.FiltersActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.FilterDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.GDPRActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.BillingActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
package="net.pokeranalytics.android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:name=".PokerAnalyticsApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/PokerAnalyticsTheme">
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />
<activity
android:name="net.pokeranalytics.android.ui.activity.HomeActivity"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="net.pokeranalytics.android.ui.activity.SessionActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing" />
<activity
android:name="net.pokeranalytics.android.ui.activity.NewDataMenuActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/PokerAnalyticsTheme.MenuDialog" />
<activity
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.BankrollDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.StatisticDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ReportDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.DataListActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.EditableDataActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.CurrenciesActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.FiltersActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.FilterDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.GDPRActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.BillingActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application>
</manifest>

@ -33,7 +33,7 @@ class PokerAnalyticsApplication : Application() {
Realm.init(this)
val realmConfiguration = RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(5)
.schemaVersion(6)
.migration(PokerAnalyticsMigration())
.initialData(Seed(this))
.build()

@ -94,6 +94,18 @@ class PokerAnalyticsMigration : RealmMigration {
currentVersion++
}
// Migrate to version 6
if (currentVersion == 5) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Transaction")?.let {
it.addField("dayOfWeek", Integer::class.java)
it.addField("month", Integer::class.java)
it.addField("year", Integer::class.java)
it.addField("dayOfMonth", Integer::class.java)
}
currentVersion++
}
}
override fun equals(other: Any?): Boolean {

@ -4,12 +4,14 @@ import io.realm.Realm
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.DatedValue
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.model.interfaces.TimeFilterable
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
@ -18,9 +20,10 @@ import java.util.*
import kotlin.collections.ArrayList
open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Filterable, DatedValue {
open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, TimeFilterable, Filterable, DatedValue {
companion object {
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(TransactionRow.values())
@ -54,6 +57,12 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
// A user comment
var comment: String = ""
// Timed interface
override var dayOfWeek: Int? = null
override var month: Int? = null
override var year: Int? = null
override var dayOfMonth: Int? = null
@Ignore
override val viewType: Int = RowViewType.ROW_TRANSACTION.ordinal
@ -75,10 +84,6 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
return bankroll != null && type != null && amount != 0.0
}
override fun alreadyExists(realm: Realm): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
return if (bankroll == null) {
R.string.no_br_popup_message
@ -89,6 +94,10 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
}
}
override fun alreadyExists(realm: Realm): Boolean {
return realm.where<Transaction>().equalTo("id", id).findFirst()!= null
}
override fun isValidForDelete(realm: Realm): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@ -97,4 +106,10 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun getSaveValidityStatus(realm: Realm): SaveValidityStatus {
if (bankroll == null || type == null || amount == 0.0) {
return SaveValidityStatus.DATA_INVALID
}
return SaveValidityStatus.VALID
}
}

@ -3,6 +3,7 @@ package net.pokeranalytics.android.model.utils
import android.content.Context
import io.realm.Realm
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.util.UserDefaults
@ -19,7 +20,7 @@ class Seed(var context:Context) : Realm.Transaction {
}
private fun createDefaultTournamentFeatures(realm: Realm) {
context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_tournament_features).forEach {
context.resources.getStringArray(R.array.seed_tournament_features).forEach {
val tournamentFeature = TournamentFeature()
tournamentFeature.id = UUID.randomUUID().toString()
tournamentFeature.name = it
@ -44,8 +45,8 @@ class Seed(var context:Context) : Realm.Transaction {
}
private fun createDefaultGames(realm: Realm) {
val gamesName = context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_games)
val gamesShortName = context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_games_short_name)
val gamesName = context.resources.getStringArray(R.array.seed_games)
val gamesShortName = context.resources.getStringArray(R.array.seed_games_short_name)
for ((index, name) in gamesName.withIndex()) {
val game = Game()
game.id = UUID.randomUUID().toString()
@ -58,6 +59,11 @@ class Seed(var context:Context) : Realm.Transaction {
private fun createDefaultTransactionTypes(realm: Realm) {
TransactionType.Value.values().forEachIndexed { index, value ->
val type = TransactionType()
type.name = when(value) {
TransactionType.Value.WITHDRAWAL -> context.getString(R.string.withdrawal)
TransactionType.Value.DEPOSIT -> context.getString(R.string.deposit)
TransactionType.Value.BONUS -> context.getString(R.string.bonus)
}
type.additive = value.additive
type.kind = index
type.lock = true

@ -0,0 +1,48 @@
package net.pokeranalytics.android.ui.activity
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.bankroll.BankrollReport
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.BankrollDetailsFragment
class BankrollDetailsActivity : PokerAnalyticsActivity() {
companion object {
private var bankrollReport: BankrollReport? = null
/**
* Default constructor
*/
fun newInstanceForResult(fragment: Fragment, bankrollReport: BankrollReport, requestCode: Int) {
this.bankrollReport = bankrollReport
val intent = Intent(fragment.requireContext(), BankrollDetailsActivity::class.java)
fragment.startActivityForResult(intent, requestCode)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bankroll_details)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
bankrollReport?.let {
val fragmentTransaction = supportFragmentManager.beginTransaction()
val reportDetailsFragment = BankrollDetailsFragment.newInstance(it)
fragmentTransaction.add(R.id.container, reportDetailsFragment)
fragmentTransaction.commit()
bankrollReport = null
}
}
}

@ -7,7 +7,7 @@ import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.BankrollDataFragment
import net.pokeranalytics.android.ui.fragment.BankrollEditDataFragment
import net.pokeranalytics.android.ui.fragment.EditableDataFragment
import net.pokeranalytics.android.ui.fragment.LocationDataFragment
import net.pokeranalytics.android.ui.fragment.TransactionDataFragment
@ -62,7 +62,7 @@ class EditableDataActivity : PokerAnalyticsActivity() {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
val fragment: EditableDataFragment = when (dataType) {
LiveData.BANKROLL.ordinal -> BankrollDataFragment()
LiveData.BANKROLL.ordinal -> BankrollEditDataFragment()
LiveData.LOCATION.ordinal -> LocationDataFragment()
LiveData.TRANSACTION.ordinal -> TransactionDataFragment()
else -> EditableDataFragment()

@ -14,7 +14,6 @@ import kotlinx.android.synthetic.main.activity_home.*
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.HomePagerAdapter
import timber.log.Timber

@ -0,0 +1,127 @@
package net.pokeranalytics.android.ui.activity
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewAnimationUtils
import kotlinx.android.synthetic.main.activity_new_data.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.extensions.px
class NewDataMenuActivity : PokerAnalyticsActivity() {
enum class IntentKey(val keyName: String) {
CHOICE("CHOICE"),
}
companion object {
fun newInstance(context: Context) {
val intent = Intent(context, NewDataMenuActivity::class.java)
context.startActivity(intent)
}
}
private val fabSize = 48.px
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(net.pokeranalytics.android.R.layout.activity_new_data)
initUI()
}
override fun onBackPressed() {
hideMenu()
}
override fun onPause() {
super.onPause()
overridePendingTransition(0, 0)
}
/**
* Init UI
*/
private fun initUI() {
overridePendingTransition(0, 0)
container.viewTreeObserver.addOnGlobalLayoutListener {
showMenu()
}
newCashGame.setOnClickListener {
finishWithResult(0)
}
newTournament.setOnClickListener {
finishWithResult(1)
}
newTransaction.setOnClickListener {
finishWithResult(2)
}
container.setOnClickListener {
hideMenu()
}
}
/**
* Set the result and hide menu
*/
private fun finishWithResult(choice: Int) {
val intent = Intent()
intent.putExtra(IntentKey.CHOICE.keyName, choice)
setResult(RESULT_OK, intent)
GlobalScope.launch(Dispatchers.Main) {
delay(200)
hideMenu(true)
}
}
/**
* Show menu
*/
private fun showMenu() {
val cx = menuContainer.measuredWidth - fabSize / 2
val cy = menuContainer.measuredHeight - fabSize / 2
val finalRadius = Math.max(menuContainer.width, menuContainer.height)
val anim = ViewAnimationUtils.createCircularReveal(menuContainer, cx, cy, 0f, finalRadius.toFloat())
anim.duration = 300
menuContainer.visibility = View.VISIBLE
anim.start()
}
/**
* Hide menu
*/
private fun hideMenu(hideQuickly: Boolean = false) {
val cx = menuContainer.measuredWidth - fabSize / 2
val cy = menuContainer.measuredHeight - fabSize / 2
val initialRadius = menuContainer.width
val anim = ViewAnimationUtils.createCircularReveal(menuContainer, cx, cy, initialRadius.toFloat(), 0f)
anim.duration = if (hideQuickly) 150 else 300
anim.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
menuContainer.visibility = View.INVISIBLE
finish()
}
})
anim.start()
}
}

@ -8,7 +8,7 @@ import androidx.fragment.app.FragmentStatePagerAdapter
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.CalendarFragment
import net.pokeranalytics.android.ui.fragment.GraphFragment
import net.pokeranalytics.android.ui.fragment.HistoryFragment
import net.pokeranalytics.android.ui.fragment.FeedFragment
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import java.lang.ref.WeakReference
@ -24,7 +24,7 @@ class ComparisonChartPagerAdapter(val context: Context, fragmentManager: Fragmen
0 -> GraphFragment()
1 -> GraphFragment()
2 -> CalendarFragment.newInstance()
else -> HistoryFragment.newInstance()
else -> FeedFragment.newInstance()
}
}

@ -7,7 +7,7 @@ import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.realm.RealmResults
import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_feed_session.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.BindableHolder
@ -24,7 +24,7 @@ import kotlin.collections.HashMap
* @param dataSource the datasource providing rows
* @param delegate the delegate, notified of UI actions
*/
class HistorySessionRowRepresentableAdapter(
class FeedSessionRowRepresentableAdapter(
var delegate: RowRepresentableDelegate? = null,
var realmResults: RealmResults<Session>,
var pendingRealmResults: RealmResults<Session>,
@ -43,7 +43,7 @@ class HistorySessionRowRepresentableAdapter(
* Display a session view
*/
inner class RowSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
fun bind(position: Int, row: Session?, adapter: HistorySessionRowRepresentableAdapter) {
fun bind(position: Int, row: Session?, adapter: FeedSessionRowRepresentableAdapter) {
itemView.sessionRow.setData(row as Session)
val listener = View.OnClickListener {
@ -57,7 +57,7 @@ class HistorySessionRowRepresentableAdapter(
* Display a session view
*/
inner class HeaderTitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
fun bind(position: Int, title: String, adapter: HistorySessionRowRepresentableAdapter) {
fun bind(title: String) {
// Title
itemView.findViewById<AppCompatTextView>(R.id.title)?.let {
it.text = title
@ -66,12 +66,12 @@ class HistorySessionRowRepresentableAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == RowViewType.ROW_SESSION.ordinal) {
val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_history_session, parent, false)
return RowSessionViewHolder(layout)
return if (viewType == RowViewType.ROW_SESSION.ordinal) {
val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_feed_session, parent, false)
RowSessionViewHolder(layout)
} else {
val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_header_title, parent, false)
return HeaderTitleViewHolder(layout)
HeaderTitleViewHolder(layout)
}
}
@ -93,7 +93,7 @@ class HistorySessionRowRepresentableAdapter(
if (holder is RowSessionViewHolder) {
holder.bind(position, getSessionForPosition(position), this)
} else if (holder is HeaderTitleViewHolder) {
holder.bind(position, getHeaderForPosition(holder.itemView.context, position), this)
holder.bind(getHeaderForPosition(holder.itemView.context, position))
}
}

@ -0,0 +1,166 @@
package net.pokeranalytics.android.ui.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.realm.RealmResults
import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.getMonthAndYear
import timber.log.Timber
import java.util.*
import kotlin.collections.HashMap
/**
* An adapter capable of displaying a list of RowRepresentables
* @param dataSource the datasource providing rows
* @param delegate the delegate, notified of UI actions
*/
class FeedTransactionRowRepresentableAdapter(
var delegate: RowRepresentableDelegate? = null,
var realmTransactions: RealmResults<Transaction>,
var distinctTransactionsHeaders: RealmResults<Transaction>
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var headersPositions = HashMap<Int, Date?>()
private lateinit var sortedHeaders: SortedMap<Int, Date?>
init {
refreshData()
}
/**
* Display a transaction view
*/
inner class RowTransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
fun bind(position: Int, row: Transaction?, adapter: FeedTransactionRowRepresentableAdapter) {
itemView.transactionRow.setData(row as Transaction)
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
itemView.transactionRow.setOnClickListener(listener)
}
}
/**
* Display a header
*/
inner class HeaderTitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
fun bind(title: String) {
// Title
itemView.findViewById<AppCompatTextView>(R.id.title)?.let {
it.text = title
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == RowViewType.ROW_TRANSACTION.ordinal) {
val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_transaction, parent, false)
RowTransactionViewHolder(layout)
} else {
val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_header_title, parent, false)
HeaderTitleViewHolder(layout)
}
}
override fun getItemViewType(position: Int): Int {
if (sortedHeaders.containsKey(position)) {
return RowViewType.HEADER_TITLE.ordinal
} else {
return RowViewType.ROW_TRANSACTION.ordinal
}
}
override fun getItemCount(): Int {
return realmTransactions.size + distinctTransactionsHeaders.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is RowTransactionViewHolder) {
holder.bind(position, getTransactionForPosition(position), this)
} else if (holder is HeaderTitleViewHolder) {
holder.bind(getHeaderForPosition(position))
}
}
/**
* Return the header
*/
private fun getHeaderForPosition(position: Int): String {
if (sortedHeaders.containsKey(position)) {
val realmHeaderPosition = sortedHeaders.keys.indexOf(position)
return distinctTransactionsHeaders[realmHeaderPosition]?.date?.getMonthAndYear() ?: ""
}
return NULL_TEXT
}
/**
* Get real index
*/
private fun getTransactionForPosition(position: Int): Transaction? {
// Row position
var headersBefore = 0
for (key in sortedHeaders.keys) {
if (position > key) {
headersBefore++
} else {
break
}
}
return realmTransactions[position - headersBefore]
}
/**
* Refresh headers positions
*/
fun refreshData() {
headersPositions.clear()
val start = System.currentTimeMillis()
var previousYear = Int.MAX_VALUE
var previousMonth = Int.MAX_VALUE
val calendar = Calendar.getInstance()
// Add headers if the date doesn't exist yet
for ((index, transaction) in realmTransactions.withIndex()) {
calendar.time = transaction.date
if (checkHeaderCondition(calendar, previousYear, previousMonth)) {
headersPositions[index + headersPositions.size] = transaction.date
previousYear = calendar.get(Calendar.YEAR)
previousMonth = calendar.get(Calendar.MONTH)
}
}
sortedHeaders = headersPositions.toSortedMap()
Timber.d("Create viewTypesPositions in: ${System.currentTimeMillis() - start}ms")
}
/**
* Check if we need to add a header
* Can be change to manage different condition
*/
private fun checkHeaderCondition(currentCalendar: Calendar, previousYear: Int, previousMonth: Int): Boolean {
return currentCalendar.get(Calendar.YEAR) == previousYear && currentCalendar.get(Calendar.MONTH) < previousMonth || (currentCalendar.get(Calendar.YEAR) < previousYear)
}
}

@ -17,12 +17,12 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
override fun getItem(position: Int): PokerAnalyticsFragment {
return when (position) {
0 -> HistoryFragment.newInstance()
0 -> FeedFragment.newInstance()
1 -> StatisticsFragment.newInstance()
2 -> CalendarFragment.newInstance()
3 -> ReportsFragment.newInstance()
4 -> MoreFragment.newInstance()
else -> HistoryFragment.newInstance()
else -> FeedFragment.newInstance()
}
}
@ -43,7 +43,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
override fun getItemPosition(obj: Any): Int {
return when (obj) {
HistoryFragment::class.java -> 0
FeedFragment::class.java -> 0
StatisticsFragment::class.java -> 1
CalendarFragment::class.java -> 2
ReportsFragment::class.java -> 3

@ -0,0 +1,166 @@
package net.pokeranalytics.android.ui.fragment
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_bankroll.*
import kotlinx.android.synthetic.main.fragment_stats.recyclerView
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedStat
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.bankroll.BankrollReport
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
companion object {
const val REQUEST_CODE_EDIT = 1000
/**
* Create new instance
*/
fun newInstance(bankrollReport: BankrollReport): BankrollDetailsFragment {
val fragment = BankrollDetailsFragment()
fragment.bankrollReport = bankrollReport
return fragment
}
}
private lateinit var parentActivity: PokerAnalyticsActivity
private lateinit var bankrollAdapter: RowRepresentableAdapter
private lateinit var bankrollReport: BankrollReport
private var bankrollDetailsMenu: Menu? = null
private var rows: ArrayList<RowRepresentable> = ArrayList()
// Life Cycle
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_bankroll_details, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_EDIT && resultCode == RESULT_OK) {
if (data != null && data.getBooleanExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, false)) {
activity?.setResult(RESULT_OK, data)
activity?.finish()
} else {
updateMenuUI()
}
}
}
override fun adapterRows(): List<RowRepresentable>? {
return rows
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_comparison_chart, menu)
this.bankrollDetailsMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.settings -> editBankroll()
}
return true
}
// Business
/**
* Init data
*/
private fun initData() {
rows.clear()
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.global))
val totalComputedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total)
val netComputedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.netResult)
val netBankedComputedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.netBanked)
rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.bankroll, computedStat = totalComputedStat))
rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.net_result, computedStat = netComputedStat))
rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.net_banked, computedStat = netBankedComputedStat))
}
/**
* Init UI
*/
private fun initUI() {
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
updateMenuUI()
bankrollAdapter = RowRepresentableAdapter(this, this)
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = bankrollAdapter
}
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
if (bankrollReport.setup.virtualBankroll) {
toolbar.title = getString(R.string.total)
collapsingToolbar.title = getString(R.string.total)
bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = false
} else {
toolbar.title = bankrollReport.setup.bankroll?.name
collapsingToolbar.title = bankrollReport.setup.bankroll?.name
bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = true
}
}
/**
* Open Bankroll edit activity
*/
private fun editBankroll() {
EditableDataActivity.newInstanceForResult(this, LiveData.BANKROLL.ordinal, bankrollReport.setup.bankroll?.id, REQUEST_CODE_EDIT)
}
}

@ -3,6 +3,8 @@ package net.pokeranalytics.android.ui.fragment
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.View
import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.CurrencyConverterApi
@ -30,7 +32,7 @@ import java.util.*
/**
* Custom EditableDataFragment to manage the Bankroll data
*/
class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource {
class BankrollEditDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource {
companion object {
const val REQUEST_CODE_CURRENCY: Int = 100
@ -54,6 +56,11 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} ?: false
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
super.onCreateOptionsMenu(menu, inflater)
menu?.findItem(R.id.delete)?.isVisible = false
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -130,7 +137,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, REQUEST_CODE_CURRENCY)
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollEditDataFragment, REQUEST_CODE_CURRENCY)
BankrollRow.REFRESH_RATE -> refreshRate()
else -> super.onRowSelected(position, row, fromAction)
}

@ -6,7 +6,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import io.realm.Realm
@ -22,16 +21,14 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedStat
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.bankroll.BankrollCalculator
import net.pokeranalytics.android.calculus.bankroll.BankrollReport
import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup
import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.ui.activity.BankrollDetailsActivity
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.StatisticDetailsActivity
@ -39,8 +36,6 @@ import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.toast
import net.pokeranalytics.android.ui.fragment.DataListFragment.Companion.REQUEST_CODE_DETAILS
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
@ -54,6 +49,8 @@ class BankrollFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSou
companion object {
const val REQUEST_CODE_DETAILS = 1000
/**
* Create new instance
*/
@ -98,6 +95,9 @@ class BankrollFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSou
}
}
}
initData()
//TODO: Refresh bankroll
}
override fun adapterRows(): List<RowRepresentable>? {
@ -105,17 +105,22 @@ class BankrollFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSou
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
Timber.d("onRowSelected: $row")
when(row) {
when (row) {
is GraphRow -> {
row.report.results.firstOrNull()?.group?.let { computableGroup ->
StatisticDetailsActivity.newInstance(requireContext(), row.stat, computableGroup, row.report, false, row.title)
row.report?.let { report ->
row.stat?.let { stat ->
report.results.firstOrNull()?.group?.let { computableGroup ->
StatisticDetailsActivity.newInstance(requireContext(), stat, computableGroup, report, false, row.title)
}
}
}
}
else -> {
if (bankrollReportForRow.containsKey(row)) {
val bankrollReport = bankrollReportForRow[row]
toast("${bankrollReport?.total}")
bankrollReportForRow[row]?.let { bankrollReport ->
lastItemClickedPosition = position
BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS)
}
}
}
}
@ -137,41 +142,32 @@ class BankrollFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSou
val realm = Realm.getDefaultInstance()
// Graph
val requiredStats: List<Stat> = listOf(Stat.NET_RESULT)
val options = Calculator.Options(
evolutionValues = Calculator.Options.EvolutionValues.STANDARD,
stats = requiredStats,
criterias = listOf(Criteria.Bankrolls)
)
val report = Calculator.computeStats(realm, options = options)
rows.add(0, GraphRow(report, Stat.NET_RESULT))
val globalBankrollReportSetup = BankrollReportSetup()
val globalBankrollReport = BankrollCalculator.computeReport(globalBankrollReportSetup)
rows.add(0, GraphRow(dataSet = globalBankrollReport.lineDataSet(requireContext())))
rows.add(globalBankrollReport)
bankrollReportForRow[globalBankrollReport] = globalBankrollReport
// Bankrolls
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.bankrolls))
val bankrolls = LiveData.BANKROLL.items(realm) as RealmResults<Bankroll>
bankrolls.forEach {
val bankrollReportSetup = BankrollReportSetup(it)
val bankrollReport = BankrollCalculator.computeReport(bankrollReportSetup)
val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total)
val row = CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = it.name, computedStat = computedStat, isSelectable = true)
rows.add(row)
bankrollReportForRow[row] = bankrollReport
}
realm.close()
Timber.d("initData: ${System.currentTimeMillis() - startDate.time}ms")
launch(Dispatchers.Main) {
val bankrolls = LiveData.BANKROLL.items(getRealm()) as RealmResults<Bankroll>
bankrolls.forEach {
val bankrollReportSetup = BankrollReportSetup(it)
val bankrollReport = BankrollCalculator.computeReport(bankrollReportSetup)
val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total)
val row = CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = it.name, computedStat = computedStat, isSelectable = true)
rows.add(row)
bankrollReportForRow[row] = bankrollReport
}
if (!isDetached) {
bankrollAdapter.notifyDataSetChanged()
}
@ -218,32 +214,41 @@ class BankrollFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSou
*/
private fun deleteItem(position: Int) {
//TODO: Get bankroll from bankrollReport and delete it
/*
if (isDetached || activity == null) {
return
}
// Save the delete position & create a copy of the object
val mRecentlyDeletedItem = rowRepresentableForPosition(position)
var mRecentlyDeletedItem = rowRepresentableForPosition(position)
lastDeletedItemPosition = position
if (mRecentlyDeletedItem is RealmObject) {
// Check if the object is valid for the deletion
if ((mRecentlyDeletedItem as Deletable).isValidForDelete(this.getRealm())) {
deletedItem = getRealm().copyFromRealm(mRecentlyDeletedItem)
getRealm().executeTransaction {
mRecentlyDeletedItem.deleteFromRealm()
if (mRecentlyDeletedItem is BankrollReport) {
if (mRecentlyDeletedItem is RealmObject) {
// Check if the object is valid for the deletion
if ((mRecentlyDeletedItem as Deletable).isValidForDelete(this.getRealm())) {
deletedItem = getRealm().copyFromRealm(mRecentlyDeletedItem)
getRealm().executeTransaction {
mRecentlyDeletedItem.deleteFromRealm()
}
bankrollAdapter.notifyItemRemoved(position)
showUndoSnackBar()
} else {
bankrollAdapter.notifyItemChanged(position)
val builder = AlertDialog.Builder(requireContext())
.setMessage((mRecentlyDeletedItem as Deletable).getFailedDeleteMessage())
.setNegativeButton(R.string.ok, null)
builder.show()
}
bankrollAdapter.notifyItemRemoved(position)
showUndoSnackBar()
} else {
bankrollAdapter.notifyItemChanged(position)
val builder = AlertDialog.Builder(requireContext())
.setMessage((mRecentlyDeletedItem as Deletable).getFailedDeleteMessage())
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
*/
}
/**

@ -150,8 +150,12 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
is GraphRow -> {
row.report.results.firstOrNull()?.group?.let { computableGroup ->
StatisticDetailsActivity.newInstance(requireContext(), row.stat, computableGroup, row.report, false, row.title)
row.report?.let { report ->
row.stat?.let { stat ->
report.results.firstOrNull()?.group?.let { computableGroup ->
StatisticDetailsActivity.newInstance(requireContext(), stat, computableGroup, report, false, row.title)
}
}
}
}
}
@ -199,7 +203,8 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
val options = Calculator.Options(
evolutionValues = Calculator.Options.EvolutionValues.STANDARD,
stats = requiredStats,
query = query)
query = query
)
val report = Calculator.computeStats(realm, options)
Timber.d("Report take: ${System.currentTimeMillis() - startDate.time}ms")
@ -207,17 +212,27 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
report.results.firstOrNull()?.let {
// Create rows
val dataSet1 = report.results.firstOrNull()?.defaultStatEntries(Stat.NET_RESULT, requireContext())
val dataSet2 = report.results.firstOrNull()?.defaultStatEntries(Stat.STANDARD_DEVIATION, requireContext())
val dataSet3 = report.results.firstOrNull()?.defaultStatEntries(Stat.HOURLY_DURATION, requireContext())
rowRepresentables.clear()
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.net_result))
rowRepresentables.add(GraphRow(report, Stat.NET_RESULT))
rowRepresentables.add(GraphRow(dataSet1, report = report, stat = Stat.NET_RESULT))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.NET_RESULT), it.computedStat(Stat.HOURLY_RATE)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.LOCATIONS_PLAYED), it.computedStat(Stat.LONGEST_STREAKS)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.distribution))
rowRepresentables.add(GraphRow(report, Stat.STANDARD_DEVIATION, requireContext().getString(R.string.distribution)))
rowRepresentables.add(
GraphRow(
dataSet2,
requireContext().getString(R.string.distribution),
report = report,
stat = Stat.STANDARD_DEVIATION
)
)
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.WIN_RATIO), it.computedStat(Stat.MAXIMUM_NETRESULT)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.volume))
rowRepresentables.add(GraphRow(report, Stat.HOURLY_DURATION))
rowRepresentables.add(GraphRow(dataSet3, report = report, stat = Stat.HOURLY_DURATION))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.HOURLY_DURATION), it.computedStat(Stat.AVERAGE_HOURLY_DURATION)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DAYS_PLAYED), it.computedStat(Stat.MAXIMUM_DURATION)))
}

@ -0,0 +1,192 @@
package net.pokeranalytics.android.ui.fragment
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_feed.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.NewDataMenuActivity
import net.pokeranalytics.android.ui.activity.SessionActivity
import net.pokeranalytics.android.ui.adapter.FeedSessionRowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.FeedTransactionRowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences
import java.text.SimpleDateFormat
import java.util.*
class FeedFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
companion object {
const val REQUEST_CODE_MENU = 100
fun newInstance(): FeedFragment {
val fragment = FeedFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
}
private lateinit var feedSessionAdapter: FeedSessionRowRepresentableAdapter
private lateinit var feedTransactionAdapter: FeedTransactionRowRepresentableAdapter
private lateinit var realmSessions: RealmResults<Session>
private lateinit var realmTransactions: RealmResults<Transaction>
private lateinit var betaLimitDate: Date
private var newSessionCreated: Boolean = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_feed, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_MENU && resultCode == RESULT_OK && data != null) {
when(data.getIntExtra(NewDataMenuActivity.IntentKey.CHOICE.keyName, -1)) {
0 -> createNewSession(false)
1 -> createNewSession(true)
2 -> createNewTransaction()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
realmSessions.removeAllChangeListeners()
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when(row) {
is Session -> SessionActivity.newInstance(requireContext(), sessionId = (row as Editable).id)
is Transaction -> EditableDataActivity.newInstance(requireContext(), LiveData.TRANSACTION.ordinal, row.id)
}
}
/**
* Init UI
*/
private fun initUI() {
disclaimerContainer.isVisible = Preferences.shouldShowDisclaimer(requireContext())
disclaimerDismiss.setOnClickListener {
Preferences.setStopShowingDisclaimer(requireContext())
disclaimerContainer.animate().translationY(disclaimerContainer.height.toFloat())
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction { disclaimerContainer?.isVisible = false }
.start()
}
addButton.setOnClickListener {
activity?.let {
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(it)
val intent = Intent(requireContext(), NewDataMenuActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_MENU, options.toBundle())
}
}
filterSessions.setOnClickListener {
recyclerView.adapter = this.feedSessionAdapter
}
filterTransactions.setOnClickListener {
recyclerView.adapter = this.feedTransactionAdapter
}
}
/**
* Init data
*/
private fun initData() {
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm", Locale.getDefault())
betaLimitDate = sdf.parse("17/7/2019 10:00")
this.realmSessions = getRealm().where<Session>().findAll().sort("startDate", Sort.DESCENDING)
this.realmSessions.addChangeListener { _, _ ->
this.feedSessionAdapter.refreshData()
this.feedSessionAdapter.notifyDataSetChanged()
}
val pendingSessions = getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING)
val distinctDateSessions = getRealm().where<Session>().distinct("year", "month").findAll().sort("startDate", Sort.DESCENDING)
this.feedSessionAdapter = FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions)
this.realmTransactions = getRealm().where<Transaction>().findAll().sort("date", Sort.DESCENDING)
val distinctDateTransactions = getRealm().where<Transaction>().distinct("year", "month").findAll().sort("date", Sort.DESCENDING)
this.feedTransactionAdapter = FeedTransactionRowRepresentableAdapter(this, realmTransactions, distinctDateTransactions)
val viewManager = SmoothScrollLinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = feedSessionAdapter
}
}
/**
* Create a new cash game
*/
private fun createNewSession(isTournament: Boolean) {
if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage()
return
}
SessionActivity.newInstance(requireContext(), isTournament)
newSessionCreated = true
}
/**
* Create a new transaction
*/
private fun createNewTransaction() {
if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage()
return
}
EditableDataActivity.newInstance(requireContext(), LiveData.TRANSACTION.ordinal)
}
/**
* Show end of beta message
*/
private fun showEndOfBetaMessage() {
Toast.makeText(context, "Beta has ended. Please update with the Google Play version", Toast.LENGTH_LONG).show()
}
}

@ -1,152 +0,0 @@
package net.pokeranalytics.android.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_history.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.SessionActivity
import net.pokeranalytics.android.ui.adapter.HistorySessionRowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences
import java.text.SimpleDateFormat
import java.util.*
class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource, RowRepresentableDelegate {
companion object {
fun newInstance(): HistoryFragment {
val fragment = HistoryFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
}
private lateinit var historyAdapter: HistorySessionRowRepresentableAdapter
private lateinit var realmSessions: RealmResults<Session>
private val rows: ArrayList<RowRepresentable> = ArrayList()
private var newSessionCreated: Boolean = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_history, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onDestroyView() {
super.onDestroyView()
realmSessions.removeAllChangeListeners()
}
/**
* Init UI
*/
private fun initUI() {
disclaimerContainer.isVisible = Preferences.shouldShowDisclaimer(requireContext())
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val betaLimitDate = sdf.parse("17/7/2019 10:00")
newCashGame.setOnClickListener {
if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage()
return@setOnClickListener
}
SessionActivity.newInstance(requireContext(), false)
newSessionCreated = true
}
newTournament.setOnClickListener {
if (Date().after(betaLimitDate)) {
this.showEndOfBetaMessage()
return@setOnClickListener
}
SessionActivity.newInstance(requireContext(), true)
newSessionCreated = true
}
disclaimerDismiss.setOnClickListener {
Preferences.setStopShowingDisclaimer(requireContext())
disclaimerContainer.animate().translationY(disclaimerContainer.height.toFloat())
.setInterpolator(FastOutSlowInInterpolator())
.withEndAction { disclaimerContainer?.isVisible = false }
.start()
}
}
private fun showEndOfBetaMessage() {
Toast.makeText(context, "Beta has ended. Please update with the Google Play version", Toast.LENGTH_LONG).show()
}
/**
* Init data
*/
private fun initData() {
this.realmSessions = getRealm().where<Session>().findAll().sort("startDate", Sort.DESCENDING)
this.realmSessions.addChangeListener { _, _ ->
this.historyAdapter.refreshData()
this.historyAdapter.notifyDataSetChanged()
}
val startedSessions = getRealm().where<Session>().isNotNull("year").isNotNull("month").findAll().sort("startDate", Sort.DESCENDING)
val pendingSessions = getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING)
val distinctDateSessions = getRealm().where<Session>().distinct("year", "month").findAll().sort("startDate", Sort.DESCENDING)
this.historyAdapter = HistorySessionRowRepresentableAdapter(this, startedSessions, pendingSessions, distinctDateSessions)
val viewManager = SmoothScrollLinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = historyAdapter
}
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable? {
return this.rows[position]
}
override fun numberOfRows(): Int {
return this.rows.size
}
override fun viewTypeForPosition(position: Int): Int {
return rows[position].viewType
}
override fun indexForRow(row: RowRepresentable): Int {
return this.rows.indexOf(row)
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
SessionActivity.newInstance(requireContext(), sessionId = (row as Editable).id)
}
}

@ -314,13 +314,13 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
realm.commitTransaction()
// Find the nearest location around the user
parentActivity.findNearestLocation { location ->
location?.let {
parentActivity.findNearestLocation {
it?.let { location ->
realm.beginTransaction()
val location = realm.where<Location>().equalTo("id", it.id).findFirst()
FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, location, requireContext())
val realmLocation = realm.where<Location>().equalTo("id", location.id).findFirst()
FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, realmLocation, requireContext())
currentSession.location = location
currentSession.location = realmLocation
realm.commitTransaction()
updateSessionUI(true)
}

@ -1,33 +1,48 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
enum class BottomSheetType {
NONE { override fun newInstance() = BottomSheetFragment()},
LIST { override fun newInstance() = BottomSheetListFragment()},
LIST_STATIC { override fun newInstance() = BottomSheetStaticListFragment()},
LIST_GAME { override fun newInstance() = BottomSheetListGameFragment()},
DOUBLE_LIST { override fun newInstance() = BottomSheetListGameFragment()},
MULTI_SELECTION { override fun newInstance() = BottomSheetMultiSelectionFragment()},
GRID { override fun newInstance() = BottomSheetTableSizeGridFragment()},
EDIT_TEXT { override fun newInstance() = BottomSheetEditTextFragment()},
EDIT_TEXT_MULTI_LINES { override fun newInstance() = BottomSheetEditTextMultiLinesFragment()},
DOUBLE_EDIT_TEXT { override fun newInstance() = BottomSheetDoubleEditTextFragment()},
NUMERIC_TEXT { override fun newInstance() = BottomSheetNumericTextFragment()},
SUM { override fun newInstance() = BottomSheetSumFragment()};
NONE,
LIST,
LIST_STATIC,
LIST_GAME,
DOUBLE_LIST,
MULTI_SELECTION,
GRID,
EDIT_TEXT,
EDIT_TEXT_MULTI_LINES,
DOUBLE_EDIT_TEXT,
NUMERIC_TEXT,
SUM;
abstract fun newInstance(): BottomSheetFragment
fun newInstance(): BottomSheetFragment {
return when (this) {
NONE -> BottomSheetFragment()
LIST -> BottomSheetListFragment()
LIST_STATIC -> BottomSheetStaticListFragment()
LIST_GAME -> BottomSheetListGameFragment()
DOUBLE_LIST -> BottomSheetListGameFragment()
MULTI_SELECTION -> BottomSheetMultiSelectionFragment()
GRID -> BottomSheetTableSizeGridFragment()
EDIT_TEXT -> BottomSheetEditTextFragment()
EDIT_TEXT_MULTI_LINES -> BottomSheetEditTextMultiLinesFragment()
DOUBLE_EDIT_TEXT -> BottomSheetDoubleEditTextFragment()
NUMERIC_TEXT -> BottomSheetNumericTextFragment()
SUM -> BottomSheetSumFragment()
}
}
val validationRequired : Boolean
get() = when (this) {
LIST, LIST_GAME, LIST_STATIC, GRID, DOUBLE_LIST -> false
else -> true
}
val validationRequired: Boolean
get() = when (this) {
LIST, LIST_GAME, LIST_STATIC, GRID, DOUBLE_LIST -> false
else -> true
}
val clearRequired : Boolean
get() = true
val clearRequired: Boolean
get() = true
val addRequired : Boolean
get() = when (this) {
EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM -> false
else -> true
}
val addRequired: Boolean
get() = when (this) {
EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM -> false
else -> true
}
}

@ -35,11 +35,7 @@ class HistorySessionDiffCallback(var newRows: List<RowRepresentable>, var oldRow
// Force to update all the rows that were already there
if (oldRows[oldItemPosition] is Session && newRows[newItemPosition] is Session) {
val session1 = oldRows[oldItemPosition] as Session
val session2 = newRows[newItemPosition] as Session
return false //session1.id == session2.id
return false
} else if (oldRows[oldItemPosition] is CustomizableRowRepresentable && newRows[newItemPosition] is CustomizableRowRepresentable) {
val header1 = oldRows[oldItemPosition] as CustomizableRowRepresentable
val header2 = newRows[newItemPosition] as CustomizableRowRepresentable

@ -17,7 +17,7 @@ import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_feed_session.view.*
import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedStat
@ -71,7 +71,7 @@ enum class RowViewType(private var layoutRes: Int) {
LOADER(R.layout.row_loader),
// Custom row
ROW_SESSION(R.layout.row_history_session),
ROW_SESSION(R.layout.row_feed_session),
ROW_TRANSACTION(R.layout.row_transaction),
ROW_BUTTON(R.layout.row_button),
ROW_FOLLOW_US(R.layout.row_follow_us),
@ -93,7 +93,7 @@ enum class RowViewType(private var layoutRes: Int) {
return when (this) {
// Row View Holder
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE,
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE,
INFO, TITLE, TITLE_ARROW, TITLE_ICON_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID,
TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK,
DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout)
@ -126,6 +126,7 @@ enum class RowViewType(private var layoutRes: Int) {
/**
* Display a generic row (title, value, container)
*/
@SuppressWarnings("ResourceType")
inner class RowViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
@ -319,7 +320,7 @@ enum class RowViewType(private var layoutRes: Int) {
if (row is GraphRow) {
row.report.results.firstOrNull()?.defaultStatEntries(row.stat, itemView.context)?.let { dataSet ->
row.dataSet?.let { dataSet ->
val context = itemView.context

@ -26,7 +26,7 @@ import net.pokeranalytics.android.util.extensions.toCurrency
*/
class SessionRowView : FrameLayout {
private lateinit var rowHistorySession: ConstraintLayout
private lateinit var rowSession: ConstraintLayout
/**
* Constructors
@ -48,9 +48,9 @@ class SessionRowView : FrameLayout {
*/
private fun init() {
val layoutInflater = LayoutInflater.from(context)
rowHistorySession = layoutInflater.inflate(R.layout.row_session_view, this, false) as ConstraintLayout
rowSession = layoutInflater.inflate(R.layout.row_session_view, this, false) as ConstraintLayout
val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
addView(rowHistorySession, layoutParams)
addView(rowSession, layoutParams)
}
/**
@ -61,8 +61,8 @@ class SessionRowView : FrameLayout {
val date = session.startDate ?: session.creationDate
// Date
rowHistorySession.dateDay.text = date.getShortDayName()
rowHistorySession.dateNumber.text = date.getDayNumber()
rowSession.dateDay.text = date.getShortDayName()
rowSession.dateNumber.text = date.getDayNumber()
// Title / Game type
@ -99,60 +99,55 @@ class SessionRowView : FrameLayout {
}
val title = parameters.joinToString(separator = " ")
rowHistorySession.sessionTitle.text = title
rowSession.sessionTitle.text = title
// Duration
// rowHistorySession.sessionInfoDurationIcon.isVisible = session.timeFrame != null
// rowHistorySession.sessionInfoDurationValue.isVisible = session.timeFrame != null
// session.timeFrame?.let {
// rowHistorySession.sessionInfoDurationValue.text = session.getFormattedDuration()
// }
rowHistorySession.sessionInfoDurationValue.text = session.getFormattedDuration()
rowSession.sessionInfoDurationValue.text = session.getFormattedDuration()
// Location
rowHistorySession.sessionInfoLocationIcon.isVisible = session.location != null
rowHistorySession.sessionInfoLocationValue.isVisible = session.location != null
rowSession.sessionInfoLocationIcon.isVisible = session.location != null
rowSession.sessionInfoLocationValue.isVisible = session.location != null
session.location?.let {
rowHistorySession.sessionInfoLocationValue.text = it.name
rowSession.sessionInfoLocationValue.text = it.name
}
// Table size
rowHistorySession.sessionInfoTableIcon.isVisible = session.tableSize != null
rowHistorySession.sessionInfoTableValue.isVisible = session.tableSize != null
rowSession.sessionInfoTableIcon.isVisible = session.tableSize != null
rowSession.sessionInfoTableValue.isVisible = session.tableSize != null
session.tableSize?.let {
rowHistorySession.sessionInfoTableValue.text = TableSize(it).localizedTitle(context)
rowSession.sessionInfoTableValue.text = TableSize(it).localizedTitle(context)
}
val state = session.getState()
rowHistorySession.sessionInfoDurationIcon.isVisible = state.hasStarted
rowHistorySession.sessionInfoDurationValue.isVisible = state.hasStarted
rowSession.sessionInfoDurationIcon.isVisible = state.hasStarted
rowSession.sessionInfoDurationValue.isVisible = state.hasStarted
// State
if (state == SessionState.STARTED) {
rowHistorySession.gameResult.isVisible = false
rowHistorySession.infoIcon.isVisible = true
rowHistorySession.infoIcon.setImageResource(R.drawable.chip)
rowHistorySession.infoTitle.isVisible = true
rowHistorySession.infoTitle.text = context.getString(R.string.running_session_state)
rowSession.gameResult.isVisible = false
rowSession.infoIcon.isVisible = true
rowSession.infoIcon.setImageResource(R.drawable.chip)
rowSession.infoTitle.isVisible = true
rowSession.infoTitle.text = context.getString(R.string.running_session_state)
} else if (state == SessionState.PLANNED) {
rowHistorySession.gameResult.isVisible = false
rowHistorySession.infoIcon.isVisible = true
rowHistorySession.infoIcon.setImageResource(R.drawable.ic_planned)
rowHistorySession.infoTitle.isVisible = true
rowHistorySession.infoTitle.text = session.startDate!!.shortTime()
rowSession.gameResult.isVisible = false
rowSession.infoIcon.isVisible = true
rowSession.infoIcon.setImageResource(R.drawable.ic_planned)
rowSession.infoTitle.isVisible = true
rowSession.infoTitle.text = session.startDate!!.shortTime()
} else if (state == SessionState.PENDING) {
rowHistorySession.gameResult.isVisible = false
rowHistorySession.infoIcon.isVisible = false
rowHistorySession.infoTitle.isVisible = false
rowSession.gameResult.isVisible = false
rowSession.infoIcon.isVisible = false
rowSession.infoTitle.isVisible = false
} else {
rowHistorySession.gameResult.isVisible = true
rowHistorySession.infoIcon.isVisible = false
rowHistorySession.infoTitle.isVisible = false
rowSession.gameResult.isVisible = true
rowSession.infoIcon.isVisible = false
rowSession.infoTitle.isVisible = false
val result = session.result?.net ?: 0.0
val formattedStat = ComputedStat(Stat.NET_RESULT, result, currency = session.currency).format()
rowHistorySession.gameResult.setTextFormat(formattedStat, context)
rowSession.gameResult.setTextFormat(formattedStat, context)
}
}

@ -1,12 +1,13 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import com.github.mikephil.charting.data.DataSet
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
class GraphRow(var report: Report, var stat: Stat, var title: String? = null) : RowRepresentable {
class GraphRow(var dataSet: DataSet<*>?, var title: String? = null, var report: Report? = null, var stat: Stat? = null) : RowRepresentable {
override val viewType: Int
get() = RowViewType.GRAPH.ordinal

@ -95,7 +95,6 @@ fun Date.getMonthAndYear(): String {
// Return the netDuration between two dates
fun Date.getFormattedDuration(toDate: Date) : String {
val difference = (toDate.time - this.time).toInt()
val numOfDays = (difference / (1000 * 60 * 60 * 24))
val hours = (difference / (1000 * 60 * 60))
val minutes = (difference / (1000 * 60)) % 60

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/menuContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginBottom="72dp"
android:background="@android:color/transparent"
android:elevation="4dp"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:transitionName="newButtonTransition"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@color/gray_darker"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/newCashGame"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="8dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="@color/green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/add_cash_game" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@string/new_cash_game"
app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout>
<LinearLayout
android:id="@+id/newTournament"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newCashGame">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="@color/green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/add_tournament" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@string/new_tournament"
app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout>
<LinearLayout
android:id="@+id/newTransaction"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingEnd="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newTournament">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="@color/green"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/add_transaction" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@string/new_operation"
app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</FrameLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/PokerAnalyticsTheme.Toolbar.Session">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="@string/bankroll"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -7,49 +7,66 @@
android:layout_height="match_parent"
tools:context=".ui.activity.HomeActivity">
<com.google.android.material.button.MaterialButton
android:id="@+id/newCashGame"
style="@style/PokerAnalyticsTheme.Button"
android:layout_width="wrap_content"
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/new_cash_game"
app:icon="@drawable/add_cash_game"
app:iconSize="28dp"
app:layout_constraintEnd_toStartOf="@+id/newTournament"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
android:theme="@style/PokerAnalyticsTheme.Toolbar.Session"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/newTournament"
style="@style/PokerAnalyticsTheme.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:text="@string/new_tournament"
app:icon="@drawable/add_tournament"
app:iconSize="28dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/newCashGame"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="8dp">
<com.google.android.material.chip.ChipGroup
android:id="@+id/filtersTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacing="8dp"
app:singleSelection="true">
<!--
<com.google.android.material.chip.Chip
android:id="@+id/filterAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/all" />
-->
<com.google.android.material.chip.Chip
android:id="@+id/filterSessions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/sessions" />
<com.google.android.material.chip.Chip
android:id="@+id/filterTransactions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/operations" />
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newCashGame"
tools:listitem="@layout/row_history_session" />
app:layout_constraintTop_toBottomOf="@+id/appBar"
tools:listitem="@layout/row_feed_session" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/noSessionFound"
@ -70,6 +87,20 @@
app:layout_constraintVertical_bias="0.5"
tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/addButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_add"
android:tint="@color/black"
android:transitionName="floating_action_button"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/disclaimerContainer"
android:layout_width="0dp"
@ -77,6 +108,7 @@
android:background="@color/green_darker"
android:orientation="vertical"
android:padding="24dp"
android:elevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/settings"
android:title="@string/services"
android:icon="@drawable/ic_outline_settings"
app:showAsAction="always" />
</menu>

@ -11,6 +11,7 @@
<item name="android:navigationBarColor">@color/colorPrimary</item>
<item name="android:actionMenuTextColor">@color/white</item>
<item name="colorControlNormal">@color/white</item>
<item name="android:windowActivityTransitions">true</item>
<item name="bottomNavigationStyle">@style/PokerAnalyticsTheme.BottomNavigationView</item>
<item name="toolbarStyle">@style/PokerAnalyticsTheme.Toolbar</item>
@ -23,6 +24,7 @@
</style>
<!-- Defaults -->
@ -241,6 +243,17 @@
<!-- Alert Dialog -->
<style name="PokerAnalyticsTheme.MenuDialog" parent="PokerAnalyticsTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>
<style name="PokerAnalyticsTheme.AlertDialog" parent="Theme.MaterialComponents.Dialog">
<item name="colorAccent">@color/green</item>
<item name="android:textColorPrimary">@color/white</item>

Loading…
Cancel
Save