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 8c7d977f..8944468e 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 @@ -658,6 +658,24 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat } + fun duplicate() : Session { + + val copy = Session.newInstance(this.realm, this.isTournament(), this.bankroll) + + copy.game = this.game + copy.limit = this.limit + copy.cgSmallBlind = this.cgSmallBlind + copy.cgBigBlind = this.cgBigBlind + copy.tournamentEntryFee = this.tournamentEntryFee + copy.tournamentFeatures = this.tournamentFeatures + copy.tournamentName = this.tournamentName + copy.tournamentType = this.tournamentType + copy.tableSize = this.tableSize + copy.numberOfTables = this.numberOfTables + + return copy + } + @Ignore override val viewType: Int = RowViewType.ROW_SESSION.ordinal diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt index e082fb49..602762c9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt @@ -14,32 +14,32 @@ class SessionActivity: PokerAnalyticsActivity() { enum class IntentKey(val keyName : String) { IS_TOURNAMENT("IS_TOURNAMENT"), + DUPLICATE("DUPLICATE"), SESSION_ID("SESSION_ID"); } companion object { - fun newInstance(context: Context, isTournament: Boolean? = false, sessionId: String? = "") { - val intent = Intent(context, SessionActivity::class.java) - isTournament?.let { - intent.putExtra(IntentKey.IS_TOURNAMENT.keyName, isTournament) - } - sessionId?.let { - intent.putExtra(IntentKey.SESSION_ID.keyName, sessionId) - } + fun newInstance(context: Context, isTournament: Boolean? = false, sessionId: String? = "", duplicate: Boolean = false) { + val intent = this.intent(context, isTournament, sessionId, duplicate) context.startActivity(intent) } - fun newInstanceforResult(fragment: Fragment, isTournament: Boolean? = false, sessionId: String? = "", requestCode: Int) { - val intent = Intent(fragment.requireContext(), SessionActivity::class.java) + fun newInstanceforResult(fragment: Fragment, isTournament: Boolean? = false, sessionId: String? = "", duplicate: Boolean = false, requestCode: Int) { + val intent = this.intent(fragment.requireContext(), isTournament, sessionId, duplicate) + fragment.startActivityForResult(intent, requestCode) + } + + private fun intent(context: Context, isTournament: Boolean? = false, sessionId: String? = "", duplicate: Boolean = false) : Intent { + val intent = Intent(context, SessionActivity::class.java) isTournament?.let { intent.putExtra(IntentKey.IS_TOURNAMENT.keyName, isTournament) } + intent.putExtra(IntentKey.DUPLICATE.keyName, duplicate) sessionId?.let { intent.putExtra(IntentKey.SESSION_ID.keyName, sessionId) } - - fragment.startActivityForResult(intent, requestCode) + return intent } } @@ -62,8 +62,9 @@ class SessionActivity: PokerAnalyticsActivity() { private fun initUI() { val sessionId = intent.getStringExtra(IntentKey.SESSION_ID.keyName) val isTournament = intent.getBooleanExtra(IntentKey.IS_TOURNAMENT.keyName, false) + val duplicate = intent.getBooleanExtra(IntentKey.DUPLICATE.keyName, false) val fragment = sessionFragment as SessionFragment - fragment.setData(isTournament, sessionId) + fragment.setData(isTournament, sessionId, duplicate) } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt index 405167e7..849487ec 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt @@ -8,7 +8,6 @@ import androidx.appcompat.widget.AppCompatTextView import androidx.recyclerview.widget.RecyclerView import io.realm.RealmResults 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 import net.pokeranalytics.android.ui.view.RowViewType @@ -43,6 +42,7 @@ class FeedSessionRowRepresentableAdapter( * Display a session view */ inner class RowSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder { + fun bind(position: Int, row: Session?, adapter: FeedSessionRowRepresentableAdapter) { itemView.sessionRow.setData(row as Session) @@ -50,6 +50,10 @@ class FeedSessionRowRepresentableAdapter( adapter.delegate?.onRowSelected(position, row) } itemView.sessionRow.setOnClickListener(listener) + + itemView.sessionRow.setOnLongClickListener { + itemView.showContextMenu() + } } } @@ -59,7 +63,7 @@ class FeedSessionRowRepresentableAdapter( inner class HeaderTitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder { fun bind(title: String) { // Title - itemView.findViewById(R.id.title)?.let { + itemView.findViewById(net.pokeranalytics.android.R.id.title)?.let { it.text = title } } @@ -67,10 +71,10 @@ class FeedSessionRowRepresentableAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == RowViewType.ROW_SESSION.ordinal) { - val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_feed_session, parent, false) + val layout = LayoutInflater.from(parent.context).inflate(net.pokeranalytics.android.R.layout.row_feed_session, parent, false) RowSessionViewHolder(layout) } else { - val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_header_title, parent, false) + val layout = LayoutInflater.from(parent.context).inflate(net.pokeranalytics.android.R.layout.row_header_title, parent, false) HeaderTitleViewHolder(layout) } @@ -104,7 +108,7 @@ class FeedSessionRowRepresentableAdapter( // If the header has no date, it's a pending session return if (sortedHeaders[position] == null) { - context.getString(R.string.pending) + context.getString(net.pokeranalytics.android.R.string.pending) } else { // Else, return the formatted date val realmHeaderPosition = if (pendingRealmResults.size > 0) sortedHeaders.keys.indexOf(position) - 1 else sortedHeaders.keys.indexOf(position) @@ -114,6 +118,11 @@ class FeedSessionRowRepresentableAdapter( return NULL_TEXT } + fun sessionIdForPosition(position: Int): String? { + val session = this.getSessionForPosition(position) + return session?.id + } + /** * Get real index */ diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt index 47825d1d..dc1608ad 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt @@ -3,9 +3,7 @@ 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.view.* import android.widget.Toast import androidx.core.app.ActivityOptionsCompat import androidx.core.view.isVisible @@ -17,6 +15,7 @@ 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.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.interfaces.Editable import net.pokeranalytics.android.model.realm.Filter @@ -30,13 +29,14 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.fragment.components.FilterableFragment import net.pokeranalytics.android.ui.interfaces.FilterActivityRequestCode import net.pokeranalytics.android.ui.interfaces.FilterableType +import net.pokeranalytics.android.ui.view.ContextMenuRecyclerView import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.util.Preferences +import timber.log.Timber import java.text.SimpleDateFormat import java.util.* - class FeedFragment : FilterableFragment(), RowRepresentableDelegate { private enum class Tab { @@ -91,6 +91,35 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { return inflater.inflate(R.layout.fragment_feed, container, false) } + override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { + super.onCreateContextMenu(menu, v, menuInfo) + + if (v?.id == R.id.recyclerView) { + activity?.menuInflater?.inflate(R.menu.menu_session, menu) + } + + } + + override fun onContextItemSelected(item: MenuItem?): Boolean { + + when (item?.itemId) { + R.id.duplicate -> { + val info = item.menuInfo as ContextMenuRecyclerView.RecyclerViewContextMenuInfo + Timber.d("info = $info") + + val sessionId = this.feedSessionAdapter.sessionIdForPosition(info.position) + if (sessionId != null) { + createNewSession(true, sessionId = sessionId, duplicate = true) + } else { + throw PAIllegalStateException("Session not found for duplicate at position: ${info.position}") + } + } + else -> { } + } + + return true + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initUI() @@ -160,6 +189,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { */ private fun initUI() { + registerForContextMenu(this.recyclerView) + disclaimerContainer.isVisible = Preferences.shouldShowDisclaimer(requireContext()) disclaimerDismiss.setOnClickListener { @@ -272,7 +303,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { /** * Create a new cash game */ - private fun createNewSession(isTournament: Boolean) { + private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) { // val sessionCount = this.feedSessionAdapter.realmResults.size // if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG @@ -287,7 +318,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { return } - SessionActivity.newInstanceforResult(this, isTournament, requestCode = RequestCode.NEW_SESSION.value) + SessionActivity.newInstanceforResult(this, isTournament, sessionId = sessionId, duplicate = duplicate, requestCode = RequestCode.NEW_SESSION.value) newSessionCreated = true } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index 335aa4f4..e62eabc5 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -61,14 +61,28 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { /** * Set fragment data */ - fun setData(isTournament: Boolean, sessionId: String) { + fun setData(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean) { val realm = getRealm() - val sessionRealm = realm.findById(sessionId) - if (sessionRealm != null) { - currentSession = sessionRealm - sessionHasBeenCustomized = true - } else { + if (sessionId != null) { + + val sessionRealm = realm.findById(sessionId) + if (sessionRealm != null) { + + if (duplicate) { // duplicate session + realm.executeTransaction { + val session = sessionRealm.duplicate() + currentSession = session + } + sessionHasBeenCustomized = false + } else { // show existing session + currentSession = sessionRealm + sessionHasBeenCustomized = true + } + } else { + throw PAIllegalStateException("Session cannot be null here, session id = $sessionId") + } + } else { // create new session realm.executeTransaction { executeRealm -> currentSession = Session.newInstance(executeRealm, isTournament) FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, null, requireContext()) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/ContextMenuRecyclerView.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/ContextMenuRecyclerView.kt new file mode 100644 index 00000000..07dbdb18 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/ContextMenuRecyclerView.kt @@ -0,0 +1,38 @@ +package net.pokeranalytics.android.ui.view + +import android.content.Context +import android.util.AttributeSet +import android.view.ContextMenu +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import timber.log.Timber + + +class ContextMenuRecyclerView : RecyclerView { + + constructor(context: Context, attributeSet: AttributeSet?, defStyle: Int) : super(context, attributeSet, defStyle) + constructor(context: Context, attributeSet: AttributeSet?) : super(context, attributeSet) + constructor(context: Context) : super(context) + + private var mContextMenuInfo: RecyclerViewContextMenuInfo? = null + + override fun getContextMenuInfo(): ContextMenu.ContextMenuInfo? { + return mContextMenuInfo + } + + override fun showContextMenuForChild(originalView: View): Boolean { + val longPressPosition = getChildAdapterPosition(originalView) + Timber.d("longPressPosition = $longPressPosition") + if (longPressPosition >= 0) { + val longPressId = adapter!!.getItemId(longPressPosition) + Timber.d("longPressId = $longPressId") + mContextMenuInfo = RecyclerViewContextMenuInfo(longPressPosition, longPressId) + return super.showContextMenuForChild(originalView) + } + return false + } + + class RecyclerViewContextMenuInfo(val position: Int, val id: Long) : ContextMenu.ContextMenuInfo + +} + diff --git a/app/src/main/res/layout/fragment_feed.xml b/app/src/main/res/layout/fragment_feed.xml index 9ee9dc14..b8000803 100644 --- a/app/src/main/res/layout/fragment_feed.xml +++ b/app/src/main/res/layout/fragment_feed.xml @@ -57,7 +57,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/appBar" /> - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 23e128e8..c0562ef6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -17,7 +17,7 @@ @style/PokerAnalyticsTheme.Toolbar @style/PokerAnalyticsTheme.BottomAppBar @style/PokerAnalyticsTheme.EditText - @style/PokerAnalyticsTheme.TextView + @style/PokerAnalyticsTheme.AlertDialog @style/PokerAnalyticsTheme.Chip @style/PokerAnalyticsTheme.TabLayout @@ -83,6 +83,11 @@ @font/roboto + +