commit
3984357077
@ -0,0 +1,85 @@ |
|||||||
|
package net.pokeranalytics.android.unitTests.filter |
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||||
|
import net.pokeranalytics.android.components.BaseFilterInstrumentedUnitTest |
||||||
|
import net.pokeranalytics.android.model.filter.Query |
||||||
|
import net.pokeranalytics.android.model.filter.QueryCondition |
||||||
|
import net.pokeranalytics.android.model.realm.CustomField |
||||||
|
import net.pokeranalytics.android.model.realm.CustomFieldEntry |
||||||
|
import net.pokeranalytics.android.model.realm.Filter |
||||||
|
import net.pokeranalytics.android.model.realm.Session |
||||||
|
import org.junit.Assert |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class CustomFieldFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { |
||||||
|
|
||||||
|
@Test |
||||||
|
fun testCustomFieldListFilter() { |
||||||
|
|
||||||
|
val realm = this.mockRealm |
||||||
|
realm.beginTransaction() |
||||||
|
|
||||||
|
val cf1 = CustomField() |
||||||
|
cf1.id = "1" |
||||||
|
cf1.type = CustomField.Type.LIST.ordinal |
||||||
|
|
||||||
|
val cfe1 = CustomFieldEntry() |
||||||
|
val cfe2 = CustomFieldEntry() |
||||||
|
cfe1.value = "super" |
||||||
|
cfe2.value = "nul" |
||||||
|
|
||||||
|
cf1.entries.add(cfe1) |
||||||
|
cf1.entries.add(cfe2) |
||||||
|
|
||||||
|
val s1 = Session.testInstance(100.0, false, Date(), 1) |
||||||
|
s1.customFieldEntries.add(cfe1) |
||||||
|
val s2 = Session.testInstance(100.0, true, Date(), 1) |
||||||
|
s2.customFieldEntries.add(cfe2) |
||||||
|
realm.commitTransaction() |
||||||
|
|
||||||
|
val sessions = Filter.queryOn<Session>(realm, Query(QueryCondition.CustomFieldListQuery(cfe2))) |
||||||
|
|
||||||
|
Assert.assertEquals(1, sessions.size) |
||||||
|
sessions[0]?.run { |
||||||
|
Assert.assertEquals(s2.id, (this).id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
fun testCustomFieldAmountFilter() { |
||||||
|
|
||||||
|
val realm = this.mockRealm |
||||||
|
realm.beginTransaction() |
||||||
|
|
||||||
|
val cf1 = CustomField() |
||||||
|
cf1.id = "1234" |
||||||
|
cf1.type = CustomField.Type.AMOUNT.ordinal |
||||||
|
|
||||||
|
|
||||||
|
val cfe1 = CustomFieldEntry() |
||||||
|
cfe1.id = "999" |
||||||
|
cf1.entries.add(cfe1) |
||||||
|
cfe1.numericValue = 30.0 |
||||||
|
|
||||||
|
val cfe2 = CustomFieldEntry() |
||||||
|
cfe2.id = "888" |
||||||
|
cf1.entries.add(cfe2) |
||||||
|
cfe2.numericValue = 100.0 |
||||||
|
|
||||||
|
val s1 = Session.testInstance(100.0, false, Date(), 1) |
||||||
|
s1.customFieldEntries.add(cfe1) |
||||||
|
val s2 = Session.testInstance(100.0, true, Date(), 1) |
||||||
|
s2.customFieldEntries.add(cfe2) |
||||||
|
realm.commitTransaction() |
||||||
|
|
||||||
|
val sessions = Filter.queryOn<Session>(realm, Query(QueryCondition.CustomFieldNumberQuery(cf1.id, 100.0))) |
||||||
|
|
||||||
|
Assert.assertEquals(1, sessions.size) |
||||||
|
sessions[0]?.run { |
||||||
|
Assert.assertEquals(s2.id, (this).id) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,57 @@ |
|||||||
|
package net.pokeranalytics.android.unitTests.filter |
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||||
|
import androidx.test.platform.app.InstrumentationRegistry |
||||||
|
import io.realm.RealmList |
||||||
|
import io.realm.RealmResults |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.components.BaseFilterInstrumentedUnitTest |
||||||
|
import net.pokeranalytics.android.model.filter.Query |
||||||
|
import net.pokeranalytics.android.model.filter.QueryCondition |
||||||
|
import net.pokeranalytics.android.model.realm.* |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow |
||||||
|
import org.junit.Assert |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class TransactionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { |
||||||
|
|
||||||
|
@Test |
||||||
|
fun testTransactionTypeFilter() { |
||||||
|
val context = InstrumentationRegistry.getInstrumentation().context |
||||||
|
|
||||||
|
val realm = this.mockRealm |
||||||
|
realm.beginTransaction() |
||||||
|
TransactionType.Value.values().forEachIndexed { index, value -> |
||||||
|
val type = TransactionType() |
||||||
|
val name = "test" |
||||||
|
type.name = name |
||||||
|
type.additive = value.additive |
||||||
|
type.kind = index |
||||||
|
type.lock = true |
||||||
|
realm.insertOrUpdate(type) |
||||||
|
} |
||||||
|
|
||||||
|
val t1: Transaction = realm.createObject(Transaction::class.java, "1") |
||||||
|
t1.type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm) |
||||||
|
val t2: Transaction = realm.createObject(Transaction::class.java, "2") |
||||||
|
t2.type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm) |
||||||
|
|
||||||
|
val b1 = realm.createObject(Bankroll::class.java, "1") |
||||||
|
t1.bankroll = b1 |
||||||
|
|
||||||
|
val b2 = realm.createObject(Bankroll::class.java, "2") |
||||||
|
t2.bankroll = b2 |
||||||
|
|
||||||
|
realm.commitTransaction() |
||||||
|
|
||||||
|
val transactions = Filter.queryOn<Transaction>(realm, Query(QueryCondition.AnyTransactionType(t1.type!!))) |
||||||
|
|
||||||
|
Assert.assertEquals(1, transactions.size) |
||||||
|
transactions[0]?.run { |
||||||
|
Assert.assertEquals(t1.type!!.id, (this).type!!.id) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,115 +1,168 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
package="net.pokeranalytics.android"> |
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
package="net.pokeranalytics.android"> |
||||||
<uses-permission android:name="android.permission.INTERNET" /> |
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
<uses-permission android:name="android.permission.INTERNET" /> |
||||||
<uses-permission android:name="com.android.vending.BILLING" /> |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> |
||||||
|
<uses-permission android:name="com.android.vending.BILLING" /> |
||||||
<application |
|
||||||
android:name=".PokerAnalyticsApplication" |
<application |
||||||
android:allowBackup="true" |
android:name=".PokerAnalyticsApplication" |
||||||
android:icon="@mipmap/ic_launcher" |
android:allowBackup="true" |
||||||
android:label="@string/app_name" |
android:icon="@mipmap/ic_launcher" |
||||||
android:roundIcon="@mipmap/ic_launcher_round" |
android:label="@string/app_name" |
||||||
android:supportsRtl="true" |
android:roundIcon="@mipmap/ic_launcher_round" |
||||||
android:theme="@style/PokerAnalyticsTheme"> |
android:supportsRtl="true" |
||||||
|
android:theme="@style/PokerAnalyticsTheme"> |
||||||
<meta-data |
|
||||||
android:name="firebase_crashlytics_collection_enabled" |
<meta-data |
||||||
android:value="false" /> |
android:name="firebase_crashlytics_collection_enabled" |
||||||
|
android:value="false" /> |
||||||
<activity |
|
||||||
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" |
<activity |
||||||
android:label="@string/app_name" |
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" |
||||||
android:screenOrientation="portrait"> |
android:launchMode="singleTop" |
||||||
<intent-filter> |
android:label="@string/app_name" |
||||||
<action android:name="android.intent.action.MAIN" /> |
android:screenOrientation="portrait"> |
||||||
<action android:name="android.intent.action.VIEW" /> |
<intent-filter> |
||||||
<category android:name="android.intent.category.LAUNCHER" /> |
<action android:name="android.intent.action.MAIN" /> |
||||||
</intent-filter> |
<action android:name="android.intent.action.VIEW" /> |
||||||
</activity> |
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
<activity |
</intent-filter> |
||||||
android:name="net.pokeranalytics.android.ui.activity.SessionActivity" |
|
||||||
android:launchMode="singleTop" |
<intent-filter tools:ignore="AppLinkUrlError"> |
||||||
android:screenOrientation="portrait" |
<action android:name="android.intent.action.VIEW" /> |
||||||
android:windowSoftInputMode="adjustNothing" /> |
<category android:name="android.intent.category.DEFAULT" /> |
||||||
|
|
||||||
<activity |
<data android:scheme="file" /> |
||||||
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity" |
<data android:scheme="content" /> |
||||||
android:launchMode="singleTop" |
<data android:mimeType="text/comma-separated-values" /> |
||||||
android:screenOrientation="portrait" /> |
<data android:mimeType="text/csv" /> |
||||||
|
|
||||||
<activity |
</intent-filter> |
||||||
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity" |
|
||||||
android:launchMode="singleTop" |
</activity> |
||||||
android:screenOrientation="portrait" /> |
|
||||||
|
<activity |
||||||
<activity |
android:name="net.pokeranalytics.android.ui.activity.ImportActivity" |
||||||
android:name="net.pokeranalytics.android.ui.activity.StatisticDetailsActivity" |
android:screenOrientation="portrait" |
||||||
android:launchMode="singleTop" |
android:launchMode="singleTop"> |
||||||
android:screenOrientation="portrait" /> |
|
||||||
|
</activity> |
||||||
<activity |
|
||||||
android:name="net.pokeranalytics.android.ui.activity.ReportDetailsActivity" |
<activity |
||||||
android:launchMode="singleTop" |
android:name="net.pokeranalytics.android.ui.activity.SessionActivity" |
||||||
android:screenOrientation="portrait" /> |
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="portrait" |
||||||
<activity |
android:windowSoftInputMode="adjustNothing" /> |
||||||
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity" |
|
||||||
android:launchMode="singleTop" |
<activity |
||||||
android:screenOrientation="portrait" /> |
android:name="net.pokeranalytics.android.ui.activity.NewDataMenuActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
<activity |
android:screenOrientation="portrait" |
||||||
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity" |
android:theme="@style/PokerAnalyticsTheme.MenuDialog" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.DataListActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.BankrollDetailsActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.EditableDataActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.CurrenciesActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.GraphActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.FiltersActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.ProgressReportActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.FilterDetailsActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.ComparisonReportActivity" |
||||||
<activity |
android:launchMode="singleTop" |
||||||
android:name="net.pokeranalytics.android.ui.activity.GDPRActivity" |
android:screenOrientation="portrait" /> |
||||||
android:launchMode="singleTop" |
|
||||||
android:screenOrientation="portrait" /> |
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity" |
||||||
<meta-data |
android:launchMode="singleTop" |
||||||
android:name="preloaded_fonts" |
android:screenOrientation="portrait" /> |
||||||
android:resource="@array/preloaded_fonts" /> |
|
||||||
|
<activity |
||||||
<provider |
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity" |
||||||
android:name="androidx.core.content.FileProvider" |
android:launchMode="singleTop" |
||||||
android:authorities="${applicationId}.fileprovider" |
android:screenOrientation="portrait" /> |
||||||
android:exported="false" |
|
||||||
android:grantUriPermissions="true"> |
<activity |
||||||
<meta-data |
android:name="net.pokeranalytics.android.ui.activity.DataListActivity" |
||||||
android:name="android.support.FILE_PROVIDER_PATHS" |
android:launchMode="singleTop" |
||||||
android:resource="@xml/provider_paths" /> |
android:screenOrientation="portrait" /> |
||||||
</provider> |
|
||||||
|
<activity |
||||||
</application> |
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" /> |
||||||
|
|
||||||
|
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.ReportCreationActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="portrait" /> |
||||||
|
|
||||||
|
<activity |
||||||
|
android:name="net.pokeranalytics.android.ui.activity.TableReportActivity" |
||||||
|
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> |
</manifest> |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
package net.pokeranalytics.android.calculus |
||||||
|
|
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.model.Criteria |
||||||
|
import net.pokeranalytics.android.ui.graph.AxisFormatting |
||||||
|
|
||||||
|
enum class AggregationType { |
||||||
|
SESSION, |
||||||
|
MONTH, |
||||||
|
YEAR, |
||||||
|
DURATION; |
||||||
|
|
||||||
|
val resId: Int |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
SESSION -> R.string.session |
||||||
|
MONTH -> R.string.month |
||||||
|
YEAR -> R.string.year |
||||||
|
DURATION -> R.string.duration |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val axisFormatting: AxisFormatting |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
DURATION -> AxisFormatting.X_DURATION |
||||||
|
else -> AxisFormatting.DEFAULT |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val criterias: List<Criteria> |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
MONTH -> listOf(Criteria.AllMonthsUpToNow) |
||||||
|
YEAR -> listOf(Criteria.Years) |
||||||
|
else -> listOf() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,12 +0,0 @@ |
|||||||
package net.pokeranalytics.android.calculus |
|
||||||
|
|
||||||
class AggregationParameter<T> { |
|
||||||
var values: List<T>? = null |
|
||||||
} |
|
||||||
|
|
||||||
class Aggregator { |
|
||||||
|
|
||||||
var parameters: List<AggregationParameter<*>> = listOf() |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,313 @@ |
|||||||
package net.pokeranalytics.android.model.realm |
package net.pokeranalytics.android.model.realm |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.text.InputType |
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmList |
||||||
import io.realm.RealmObject |
import io.realm.RealmObject |
||||||
|
import io.realm.annotations.Ignore |
||||||
import io.realm.annotations.PrimaryKey |
import io.realm.annotations.PrimaryKey |
||||||
|
import io.realm.kotlin.where |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.model.Criteria |
||||||
|
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus |
||||||
|
import net.pokeranalytics.android.model.interfaces.NameManageable |
||||||
|
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus |
||||||
|
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource |
||||||
|
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor |
||||||
|
import net.pokeranalytics.android.ui.view.RowViewType |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow |
||||||
|
import net.pokeranalytics.android.util.enumerations.IntIdentifiable |
||||||
import java.util.* |
import java.util.* |
||||||
|
import kotlin.collections.ArrayList |
||||||
|
|
||||||
|
|
||||||
open class CustomField : RealmObject() { |
open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable { |
||||||
|
|
||||||
@PrimaryKey |
/** |
||||||
var id = UUID.randomUUID().toString() |
* The custom field type: a list of items, a number or an amont |
||||||
|
*/ |
||||||
|
enum class Type(override var uniqueIdentifier: Int, var resId: Int, var isEnabled: Boolean = true) : |
||||||
|
IntIdentifiable { |
||||||
|
LIST(0, R.string.enum_custom_field_type), |
||||||
|
NUMBER(1, R.string.number), |
||||||
|
AMOUNT(2, R.string.amount) |
||||||
|
} |
||||||
|
|
||||||
// The name of the currency field |
/** |
||||||
var name: String = "" |
* The sorting used for the list, either custom, or alphabetically asc/desc |
||||||
|
*/ |
||||||
|
enum class Sort(override var uniqueIdentifier: Int) : IntIdentifiable { |
||||||
|
DEFAULT(0), |
||||||
|
ASCENDING(1), |
||||||
|
DESCENDING(2) |
||||||
|
} |
||||||
|
|
||||||
// @todo |
@PrimaryKey |
||||||
|
override var id = UUID.randomUUID().toString() |
||||||
|
|
||||||
|
/** |
||||||
|
* The name of the custom field |
||||||
|
*/ |
||||||
|
override var name: String = "" |
||||||
|
|
||||||
|
// The type of the custom fields, mapped with the CustomField.Type enum |
||||||
|
var type: Int = Type.LIST.uniqueIdentifier |
||||||
|
set(value) { |
||||||
|
if (field == Type.LIST.uniqueIdentifier && value != Type.LIST.uniqueIdentifier) { |
||||||
|
this.removeListEntries() |
||||||
|
} |
||||||
|
field = value |
||||||
|
|
||||||
|
this.updateRowRepresentation() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Indicates whether the custom field value should be copied when a session is duplicated |
||||||
|
*/ |
||||||
|
var duplicateValue: Boolean = false |
||||||
|
|
||||||
|
/** |
||||||
|
* The list of entries for the LIST type |
||||||
|
*/ |
||||||
|
var entries: RealmList<CustomFieldEntry> = RealmList() |
||||||
|
|
||||||
|
/** |
||||||
|
* The sorting of the entries, mapped with the CustomField.Sort enum |
||||||
|
*/ |
||||||
|
var sortCondition: Int = Sort.DEFAULT.uniqueIdentifier |
||||||
|
set(value) { |
||||||
|
field = value |
||||||
|
sortEntries() |
||||||
|
updateRowRepresentation() |
||||||
|
} |
||||||
|
|
||||||
|
@Ignore |
||||||
|
private var entriesToDelete: ArrayList<CustomFieldEntry> = ArrayList() |
||||||
|
|
||||||
|
@Ignore |
||||||
|
override var viewType: Int = RowViewType.TITLE_VALUE_ARROW.ordinal |
||||||
|
|
||||||
|
@Ignore |
||||||
|
private var rowRepresentation: List<RowRepresentable> = mutableListOf() |
||||||
|
|
||||||
|
|
||||||
|
//helper |
||||||
|
|
||||||
|
val isListType: Boolean |
||||||
|
get() { |
||||||
|
return this.type == Type.LIST.uniqueIdentifier |
||||||
|
} |
||||||
|
|
||||||
|
val isAmountType: Boolean |
||||||
|
get() { |
||||||
|
return this.type == Type.AMOUNT.uniqueIdentifier |
||||||
|
} |
||||||
|
|
||||||
|
override fun localizedTitle(context: Context): String { |
||||||
|
return this.name |
||||||
|
} |
||||||
|
|
||||||
|
override fun getDisplayName(context: Context): String { |
||||||
|
return this.name |
||||||
|
} |
||||||
|
|
||||||
|
override fun adapterRows(): List<RowRepresentable>? { |
||||||
|
return rowRepresentation |
||||||
|
} |
||||||
|
|
||||||
|
override fun updateValue(value: Any?, row: RowRepresentable) { |
||||||
|
when (row) { |
||||||
|
SimpleRow.NAME -> this.name = value as String? ?: "" |
||||||
|
CustomFieldRow.TYPE -> this.type = (value as Type?)?.uniqueIdentifier ?: Type.LIST.uniqueIdentifier |
||||||
|
CustomFieldRow.COPY_ON_DUPLICATE -> this.duplicateValue = value as Boolean? ?: false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun isValidForSave(): Boolean { |
||||||
|
return super.isValidForSave() |
||||||
|
} |
||||||
|
|
||||||
|
override fun getFailedSaveMessage(status: SaveValidityStatus): Int { |
||||||
|
return when (status) { |
||||||
|
SaveValidityStatus.DATA_INVALID -> R.string.cf_empty_field_error |
||||||
|
SaveValidityStatus.ALREADY_EXISTS -> R.string.duplicate_cf_error |
||||||
|
else -> super.getFailedSaveMessage(status) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun alreadyExists(realm: Realm): Boolean { |
||||||
|
return realm.where(this::class.java).equalTo("name", this.name).and().notEqualTo("id", this.id).findAll() |
||||||
|
.isNotEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
override fun isValidForDelete(realm: Realm): Boolean { |
||||||
|
val sessions = realm.where<Session>().contains("customFieldEntries.customField.id", id).findAll() |
||||||
|
return sessions.isEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { |
||||||
|
//TODO: |
||||||
|
return R.string.cf_entry_delete_popup_message |
||||||
|
} |
||||||
|
|
||||||
|
override val bottomSheetType: BottomSheetType |
||||||
|
get() { |
||||||
|
return when (type) { |
||||||
|
Type.LIST.uniqueIdentifier -> BottomSheetType.LIST_STATIC |
||||||
|
else -> BottomSheetType.NUMERIC_TEXT |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun deleteDependencies() { |
||||||
|
if (isValid) { |
||||||
|
val entries = realm.where<CustomFieldEntry>().equalTo("customField.id", id).findAll() |
||||||
|
entries.deleteAllFromRealm() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? { |
||||||
|
return when (row) { |
||||||
|
is CustomFieldEntry -> row.editingDescriptors( |
||||||
|
mapOf( |
||||||
|
"defaultValue" to row.value |
||||||
|
) |
||||||
|
) |
||||||
|
else -> null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { |
||||||
|
return when (type) { |
||||||
|
Type.LIST.uniqueIdentifier -> { |
||||||
|
val defaultValue: Any? by map |
||||||
|
val data: RealmList<CustomFieldEntry>? by map |
||||||
|
arrayListOf( |
||||||
|
RowRepresentableEditDescriptor(defaultValue, staticData = data) |
||||||
|
) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
val defaultValue: Double? by map |
||||||
|
arrayListOf( |
||||||
|
RowRepresentableEditDescriptor( |
||||||
|
defaultValue, inputType = InputType.TYPE_CLASS_NUMBER |
||||||
|
or InputType.TYPE_NUMBER_FLAG_DECIMAL |
||||||
|
or InputType.TYPE_NUMBER_FLAG_SIGNED |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Update the row representation |
||||||
|
*/ |
||||||
|
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> { |
||||||
|
val rows = ArrayList<RowRepresentable>() |
||||||
|
rows.add(SimpleRow.NAME) |
||||||
|
rows.add(CustomFieldRow.TYPE) |
||||||
|
|
||||||
|
if (type == Type.LIST.uniqueIdentifier && entries.size >= 0) { |
||||||
|
if (entries.isNotEmpty()) { |
||||||
|
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, R.string.items_list)) |
||||||
|
sortEntries() |
||||||
|
entries.forEach { customFieldEntry -> |
||||||
|
customFieldEntry.isMovable = sortCondition == Sort.DEFAULT.uniqueIdentifier |
||||||
|
} |
||||||
|
rows.addAll(entries) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return rows |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sort the entries element |
||||||
|
*/ |
||||||
|
private fun sortEntries() { |
||||||
|
when (sortCondition) { |
||||||
|
Sort.ASCENDING.uniqueIdentifier -> entries.sortBy { it.value } |
||||||
|
Sort.DESCENDING.uniqueIdentifier -> entries.sortByDescending { it.value } |
||||||
|
} |
||||||
|
entries.forEachIndexed { index, customFieldEntry -> |
||||||
|
customFieldEntry.order = index |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun updateRowRepresentation() { |
||||||
|
this.rowRepresentation = this.updatedRowRepresentationForCurrentState() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add an entry |
||||||
|
*/ |
||||||
|
fun addEntry(): CustomFieldEntry { |
||||||
|
val entry = CustomFieldEntry() |
||||||
|
this.entries.add(entry) |
||||||
|
sortEntries() |
||||||
|
updateRowRepresentation() |
||||||
|
return entry |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Delete an entry |
||||||
|
*/ |
||||||
|
fun deleteEntry(entry: CustomFieldEntry) { |
||||||
|
entries.remove(entry) |
||||||
|
entriesToDelete.add(entry) |
||||||
|
sortEntries() |
||||||
|
updateRowRepresentation() |
||||||
|
} |
||||||
|
|
||||||
|
private fun removeListEntries() { |
||||||
|
|
||||||
|
this.entriesToDelete.addAll(entries) |
||||||
|
this.entries.clear() |
||||||
|
|
||||||
|
if (realm != null) { |
||||||
|
realm.executeTransaction { |
||||||
|
this.entriesToDelete.forEach { |
||||||
|
if (it.isManaged) { |
||||||
|
it.deleteFromRealm() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Clean the entries if the type is not a list & remove the deleted entries from realm |
||||||
|
*/ |
||||||
|
// fun cleanEntries(realm: Realm) { |
||||||
|
// realm.executeTransaction { |
||||||
|
// |
||||||
|
// if (!isListType) { |
||||||
|
// entriesToDelete.addAll(entries) |
||||||
|
// entries.clear() |
||||||
|
// } |
||||||
|
// |
||||||
|
// // @TODO |
||||||
|
// entriesToDelete.forEach { |
||||||
|
// Timber.d("Delete entry: V=${it.value} N=${it.numericValue} / ID=${it.id}") |
||||||
|
// realm.where<CustomFieldEntry>().equalTo("id", it.id).findFirst()?.deleteFromRealm() |
||||||
|
// } |
||||||
|
// entriesToDelete.clear() |
||||||
|
// } |
||||||
|
// } |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a comparison criteria based on this custom field |
||||||
|
*/ |
||||||
|
val criteria: Criteria |
||||||
|
get() { |
||||||
|
return when (this.type) { |
||||||
|
CustomField.Type.LIST.uniqueIdentifier -> Criteria.ListCustomFields(this.id) |
||||||
|
else -> Criteria.ValueCustomFields(this.id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
@ -0,0 +1,148 @@ |
|||||||
|
package net.pokeranalytics.android.model.realm |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.text.InputType |
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmObject |
||||||
|
import io.realm.RealmResults |
||||||
|
import io.realm.annotations.Ignore |
||||||
|
import io.realm.annotations.LinkingObjects |
||||||
|
import io.realm.annotations.PrimaryKey |
||||||
|
import io.realm.kotlin.where |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.exceptions.ModelException |
||||||
|
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus |
||||||
|
import net.pokeranalytics.android.model.interfaces.NameManageable |
||||||
|
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus |
||||||
|
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor |
||||||
|
import net.pokeranalytics.android.ui.view.RowViewType |
||||||
|
import net.pokeranalytics.android.util.NULL_TEXT |
||||||
|
import net.pokeranalytics.android.util.extensions.toCurrency |
||||||
|
import java.text.NumberFormat |
||||||
|
import java.util.* |
||||||
|
import java.util.Currency |
||||||
|
|
||||||
|
|
||||||
|
open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable { |
||||||
|
|
||||||
|
@PrimaryKey |
||||||
|
override var id = UUID.randomUUID().toString() |
||||||
|
|
||||||
|
/** |
||||||
|
* The order in the list |
||||||
|
*/ |
||||||
|
var order: Int = 0 |
||||||
|
|
||||||
|
/** |
||||||
|
* The inverse relationship with CustomField |
||||||
|
*/ |
||||||
|
@LinkingObjects("entries") |
||||||
|
val customFields: RealmResults<CustomField>? = null |
||||||
|
|
||||||
|
val customField: CustomField? |
||||||
|
get() { |
||||||
|
return this.customFields?.first() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The string value of the entry |
||||||
|
*/ |
||||||
|
var value: String = "" |
||||||
|
|
||||||
|
/** |
||||||
|
* The numeric value of the entry |
||||||
|
*/ |
||||||
|
var numericValue: Double? = null |
||||||
|
|
||||||
|
@Ignore |
||||||
|
override var name: String = value |
||||||
|
get() { return value } |
||||||
|
|
||||||
|
@Ignore |
||||||
|
var isMovable: Boolean = false |
||||||
|
|
||||||
|
@Ignore |
||||||
|
override val viewType: Int = RowViewType.TITLE_VALUE_ACTION.ordinal |
||||||
|
|
||||||
|
override val imageRes: Int? |
||||||
|
get() { |
||||||
|
return if (isMovable) R.drawable.ic_reorder else null |
||||||
|
} |
||||||
|
|
||||||
|
override val imageTint: Int? |
||||||
|
get() { |
||||||
|
return R.color.kaki |
||||||
|
} |
||||||
|
|
||||||
|
@Ignore |
||||||
|
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT |
||||||
|
|
||||||
|
override fun localizedTitle(context: Context): String { |
||||||
|
return context.getString(R.string.value) |
||||||
|
} |
||||||
|
|
||||||
|
override fun getDisplayName(context: Context): String { |
||||||
|
return if (value.isNotEmpty()) value else NULL_TEXT |
||||||
|
} |
||||||
|
|
||||||
|
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { |
||||||
|
val defaultValue: Any? by map |
||||||
|
return arrayListOf( |
||||||
|
RowRepresentableEditDescriptor(defaultValue, R.string.value, InputType.TYPE_CLASS_TEXT) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
override fun isValidForSave(): Boolean { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
override fun alreadyExists(realm: Realm): Boolean { |
||||||
|
return realm.where(this::class.java).notEqualTo("id", this.id).findAll().isNotEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
override fun getFailedSaveMessage(status: SaveValidityStatus): Int { |
||||||
|
throw ModelException("${this::class.java} getFailedSaveMessage for $status not handled") |
||||||
|
} |
||||||
|
|
||||||
|
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { |
||||||
|
return R.string.cf_entry_delete_popup_message |
||||||
|
} |
||||||
|
|
||||||
|
override fun deleteDependencies() { |
||||||
|
if (isValid) { |
||||||
|
val entries = realm.where<CustomFieldEntry>().equalTo("customField.id", id).findAll() |
||||||
|
entries.deleteAllFromRealm() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun updateValue(value: Any?, row: RowRepresentable) { |
||||||
|
this.value = value as String? ?: "" |
||||||
|
} |
||||||
|
|
||||||
|
override fun isValidForDelete(realm: Realm): Boolean { |
||||||
|
if (realm.where<Session>().contains("customFieldEntries.id", id).findAll().isNotEmpty()) { |
||||||
|
return false |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the amount |
||||||
|
*/ |
||||||
|
fun getFormattedValue(currency: Currency? = null): String { |
||||||
|
return when (customField?.type) { |
||||||
|
CustomField.Type.AMOUNT.uniqueIdentifier -> { |
||||||
|
numericValue?.toCurrency(currency) ?: run { NULL_TEXT } |
||||||
|
} |
||||||
|
CustomField.Type.NUMBER.uniqueIdentifier -> { |
||||||
|
NumberFormat.getInstance().format(this.numericValue) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
value |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,33 +1,98 @@ |
|||||||
package net.pokeranalytics.android.model.realm |
package net.pokeranalytics.android.model.realm |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import io.realm.Realm |
||||||
import io.realm.RealmList |
import io.realm.RealmList |
||||||
import io.realm.RealmObject |
import io.realm.RealmObject |
||||||
|
import io.realm.annotations.Ignore |
||||||
import io.realm.annotations.PrimaryKey |
import io.realm.annotations.PrimaryKey |
||||||
|
import net.pokeranalytics.android.calculus.Calculator |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.model.Criteria |
||||||
|
import net.pokeranalytics.android.model.interfaces.Deletable |
||||||
|
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.RowViewType |
||||||
|
import net.pokeranalytics.android.util.extensions.findById |
||||||
import java.util.* |
import java.util.* |
||||||
|
|
||||||
enum class ReportDisplay { |
|
||||||
TABLE, |
|
||||||
GRAPH, |
|
||||||
MAP |
|
||||||
} |
|
||||||
|
|
||||||
open class ReportSetup : RealmObject() { |
open class ReportSetup : RealmObject(), RowRepresentable, Deletable { |
||||||
|
|
||||||
@PrimaryKey |
@PrimaryKey |
||||||
var id = UUID.randomUUID().toString() |
override var id = UUID.randomUUID().toString() |
||||||
|
|
||||||
// The name of the report |
// The name of the report |
||||||
var name: String = "" |
var name: String = "" |
||||||
|
|
||||||
// The type of display of the report |
// The type of display of the report |
||||||
var display: Int = ReportDisplay.TABLE.ordinal |
var display: Int = Calculator.Options.Display.TABLE.ordinal |
||||||
|
|
||||||
|
/** |
||||||
|
* A list of statIds to compute |
||||||
|
* Must contain at least 1 |
||||||
|
*/ |
||||||
|
var statIds: RealmList<Int> = RealmList() |
||||||
|
|
||||||
|
/** |
||||||
|
* An optional list of criteriaIds to compare statIds |
||||||
|
*/ |
||||||
|
var criteriaIds: RealmList<Int> = RealmList() |
||||||
|
|
||||||
|
/** |
||||||
|
* An optional list of custom fields ids to be compared |
||||||
|
*/ |
||||||
|
var criteriaCustomFieldIds: RealmList<String> = RealmList() |
||||||
|
|
||||||
|
/** |
||||||
|
* An optional filter to narrow the results |
||||||
|
*/ |
||||||
|
var filter: Filter? = null |
||||||
|
|
||||||
|
// RowRepresentable |
||||||
|
override fun getDisplayName(context: Context): String { |
||||||
|
return this.name |
||||||
|
} |
||||||
|
|
||||||
|
@Ignore |
||||||
|
override val viewType: Int = RowViewType.TITLE_ARROW.ordinal |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the Options based on the ReportSetup parameters |
||||||
|
*/ |
||||||
|
val options: Calculator.Options |
||||||
|
get() { |
||||||
|
|
||||||
|
val realm = Realm.getDefaultInstance() |
||||||
|
val stats = this.statIds.map { Stat.valueByIdentifier(it) } |
||||||
|
|
||||||
|
// Comparison criteria |
||||||
|
val criteria = this.criteriaIds.map { Criteria.valueByIdentifier(it) } |
||||||
|
val customFields = this.criteriaCustomFieldIds.mapNotNull { realm.findById<CustomField>(it) } |
||||||
|
val cfCriteria = customFields.map { it.criteria } |
||||||
|
|
||||||
|
val allCriteria = mutableListOf<Criteria>() |
||||||
|
allCriteria.addAll(criteria) |
||||||
|
allCriteria.addAll(cfCriteria) |
||||||
|
|
||||||
|
return Calculator.Options( |
||||||
|
display = Calculator.Options.Display.values()[this.display], |
||||||
|
stats = stats, |
||||||
|
criterias = allCriteria, |
||||||
|
filter = this.filter, |
||||||
|
userGenerated = true, |
||||||
|
reportSetupId = this.id |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
// @todo define the configuration options |
// Deletable |
||||||
|
|
||||||
// var criteria: List<Int> = listOf() |
override fun isValidForDelete(realm: Realm): Boolean { |
||||||
// var stats: List<Int> = listOf() |
return true |
||||||
|
} |
||||||
|
|
||||||
// The filters associated with the report |
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { |
||||||
var filters: RealmList<Filter> = RealmList() |
TODO("not implemented") //To change body of created functions use File | Settings | File Templates. |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,21 @@ |
|||||||
|
package net.pokeranalytics.android.model.utils |
||||||
|
|
||||||
|
import io.realm.Realm |
||||||
|
import net.pokeranalytics.android.model.realm.Session |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
class SessionUtils { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true if the provided parameters doesn't correspond to an existing session |
||||||
|
*/ |
||||||
|
fun unicityCheck(realm: Realm, startDate: Date, endDate: Date, net: Double) : Boolean { |
||||||
|
val sessions = realm.where(Session::class.java).equalTo("startDate", startDate).equalTo("endDate", endDate).equalTo("result.net", net).findAll() |
||||||
|
return sessions.isEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,31 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
||||||
|
import net.pokeranalytics.android.util.billing.AppGuard |
||||||
|
|
||||||
|
class BillingActivity : PokerAnalyticsActivity() { |
||||||
|
|
||||||
|
companion object { |
||||||
|
fun newInstance(context: Context) { |
||||||
|
val intent = Intent(context, BillingActivity::class.java) |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_billing) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onResume() { |
||||||
|
super.onResume() |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,36 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.ReportActivity |
||||||
|
import net.pokeranalytics.android.ui.fragment.report.ComparisonReportFragment |
||||||
|
|
||||||
|
|
||||||
|
class ComparisonReportActivity : ReportActivity() { |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_report_details) |
||||||
|
initUI() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init UI |
||||||
|
*/ |
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
parameters?.let { |
||||||
|
|
||||||
|
val report = it.report |
||||||
|
val title = it.title |
||||||
|
|
||||||
|
val fragmentTransaction = supportFragmentManager.beginTransaction() |
||||||
|
val reportDetailsFragment = ComparisonReportFragment.newInstance(report, title) |
||||||
|
fragmentTransaction.add(R.id.reportDetailsContainer, reportDetailsFragment) |
||||||
|
fragmentTransaction.commit() |
||||||
|
} |
||||||
|
parameters = null |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import com.github.mikephil.charting.data.BarDataSet |
||||||
|
import com.github.mikephil.charting.data.LineDataSet |
||||||
|
import kotlinx.android.synthetic.main.activity_graph.* |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
||||||
|
import net.pokeranalytics.android.ui.fragment.GraphFragment |
||||||
|
|
||||||
|
|
||||||
|
class GraphActivity : PokerAnalyticsActivity() { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
private var lineDataSets: List<LineDataSet>? = null |
||||||
|
private var barDataSets: List<BarDataSet>? = null |
||||||
|
private var style: GraphFragment.Style? = GraphFragment.Style.LINE |
||||||
|
private var activityTitle: String? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* Default constructor |
||||||
|
*/ |
||||||
|
fun newInstance( |
||||||
|
context: Context, lineDataSets: List<LineDataSet>? = null, barDataSets: List<BarDataSet>? = null, |
||||||
|
style: GraphFragment.Style = GraphFragment.Style.LINE, title: String? = null |
||||||
|
) { |
||||||
|
this.lineDataSets = lineDataSets |
||||||
|
this.barDataSets = barDataSets |
||||||
|
this.style = style |
||||||
|
this.activityTitle = title |
||||||
|
val intent = Intent(context, GraphActivity::class.java) |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_graph) |
||||||
|
initUI() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init UI |
||||||
|
*/ |
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
activityTitle?.let { |
||||||
|
setSupportActionBar(toolbar) |
||||||
|
supportActionBar?.setDisplayHomeAsUpEnabled(true) |
||||||
|
title = activityTitle |
||||||
|
activityTitle = null |
||||||
|
} |
||||||
|
|
||||||
|
style?.let { |
||||||
|
val fragmentTransaction = supportFragmentManager.beginTransaction() |
||||||
|
val graphFragment = GraphFragment.newInstance(lineDataSets, barDataSets, it) |
||||||
|
fragmentTransaction.add(R.id.container, graphFragment) |
||||||
|
fragmentTransaction.commit() |
||||||
|
} |
||||||
|
|
||||||
|
lineDataSets = null |
||||||
|
barDataSets = null |
||||||
|
style = null |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.net.Uri |
||||||
|
import android.os.Bundle |
||||||
|
import androidx.fragment.app.FragmentActivity |
||||||
|
import io.realm.Realm |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
||||||
|
import net.pokeranalytics.android.ui.activity.components.RequestCode |
||||||
|
import net.pokeranalytics.android.ui.fragment.ImportFragment |
||||||
|
import timber.log.Timber |
||||||
|
|
||||||
|
class ImportActivity : PokerAnalyticsActivity() { |
||||||
|
|
||||||
|
private lateinit var fileURI: Uri |
||||||
|
|
||||||
|
enum class IntentKey(val keyName: String) { |
||||||
|
URI("uri") |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new instance for result |
||||||
|
*/ |
||||||
|
fun newInstanceForResult(context: FragmentActivity, uri: Uri) { |
||||||
|
context.startActivityForResult(getIntent(context, uri), RequestCode.IMPORT.value) |
||||||
|
} |
||||||
|
|
||||||
|
private fun getIntent(context: Context, uri: Uri): Intent { |
||||||
|
val intent = Intent(context, ImportActivity::class.java) |
||||||
|
intent.putExtra(ImportActivity.IntentKey.URI.keyName, uri) |
||||||
|
return intent |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
|
||||||
|
this.fileURI = intent.getParcelableExtra(ImportActivity.IntentKey.URI.keyName) |
||||||
|
|
||||||
|
setContentView(R.layout.activity_import) |
||||||
|
initUI() |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onStop() { |
||||||
|
super.onStop() |
||||||
|
|
||||||
|
// Updates the main thread instance with newly inserted data |
||||||
|
val realm = Realm.getDefaultInstance() |
||||||
|
realm.refresh() |
||||||
|
realm.close() |
||||||
|
} |
||||||
|
|
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
val fragmentTransaction = supportFragmentManager.beginTransaction() |
||||||
|
val fragment = ImportFragment() |
||||||
|
|
||||||
|
val fis = contentResolver.openInputStream(fileURI) |
||||||
|
Timber.d("Load fragment data with: $fis") |
||||||
|
fis?.let { |
||||||
|
fragment.setData(it) |
||||||
|
} |
||||||
|
|
||||||
|
fragmentTransaction.add(R.id.container, fragment) |
||||||
|
fragmentTransaction.commit() |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// private fun requestPermission() { |
||||||
|
// if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { |
||||||
|
// ActivityCompat.requestPermissions( |
||||||
|
// this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_REQUEST_ACCESS_FINE_LOCATION |
||||||
|
// ) |
||||||
|
// } |
||||||
|
// } |
||||||
|
// |
||||||
|
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { |
||||||
|
// super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
||||||
|
// } |
||||||
|
|
||||||
|
} |
||||||
@ -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 = 150 |
||||||
|
|
||||||
|
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 = 150 |
||||||
|
|
||||||
|
anim.addListener(object : AnimatorListenerAdapter() { |
||||||
|
override fun onAnimationEnd(animation: Animator?) { |
||||||
|
super.onAnimationEnd(animation) |
||||||
|
menuContainer.visibility = View.INVISIBLE |
||||||
|
finish() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
anim.start() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.calculus.Report |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.ui.activity.components.ReportActivity |
||||||
|
import net.pokeranalytics.android.ui.activity.components.ReportParameters |
||||||
|
import net.pokeranalytics.android.ui.activity.components.RequestCode |
||||||
|
import net.pokeranalytics.android.ui.fragment.report.ProgressReportFragment |
||||||
|
|
||||||
|
class ProgressReportActivity : ReportActivity() { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects |
||||||
|
|
||||||
|
/** |
||||||
|
* Default constructor |
||||||
|
*/ |
||||||
|
fun newInstance(context: Context, report: Report, title: String, stat: Stat? = null, displayAggregationChoices: Boolean = true) { |
||||||
|
parameters = ReportParameters(report, title, stat, showAggregationChoices = displayAggregationChoices) |
||||||
|
val intent = Intent(context, ProgressReportActivity::class.java) |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
fun newInstanceForResult(fragment: Fragment, report: Report, title: String, stat: Stat? = null, displayAggregationChoices: Boolean = true) { |
||||||
|
parameters = ReportParameters(report, title, stat, showAggregationChoices = displayAggregationChoices) |
||||||
|
val intent = Intent(fragment.context, ProgressReportActivity::class.java) |
||||||
|
fragment.startActivityForResult(intent, RequestCode.DEFAULT.value) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_progress_report) |
||||||
|
initUI() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init UI |
||||||
|
*/ |
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
val fragmentTransaction = supportFragmentManager.beginTransaction() |
||||||
|
val statisticDetailsFragment = ProgressReportFragment() |
||||||
|
fragmentTransaction.add(R.id.statisticDetailsContainer, statisticDetailsFragment) |
||||||
|
fragmentTransaction.commit() |
||||||
|
|
||||||
|
parameters?.let { |
||||||
|
val report = it.report |
||||||
|
val stat = it.stat ?: report.options.stats.first() |
||||||
|
statisticDetailsFragment.setData(report, stat, it.showAggregationChoices, it.title) |
||||||
|
parameters = null |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.calculus.Calculator |
||||||
|
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
||||||
|
import net.pokeranalytics.android.ui.activity.components.RequestCode |
||||||
|
|
||||||
|
class ReportCreationActivity : PokerAnalyticsActivity() { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
var options: Calculator.Options? = null |
||||||
|
|
||||||
|
fun newInstanceForResult(fragment: Fragment, context: Context) { |
||||||
|
val intent = Intent(context, ReportCreationActivity::class.java) |
||||||
|
fragment.startActivityForResult(intent, RequestCode.NEW_REPORT.value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_report_creation) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,55 +0,0 @@ |
|||||||
package net.pokeranalytics.android.ui.activity |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.content.Intent |
|
||||||
import android.os.Bundle |
|
||||||
import net.pokeranalytics.android.R |
|
||||||
import net.pokeranalytics.android.calculus.Report |
|
||||||
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
|
||||||
import net.pokeranalytics.android.ui.fragment.ReportDetailsFragment |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ReportDetailsActivity : PokerAnalyticsActivity() { |
|
||||||
|
|
||||||
companion object { |
|
||||||
|
|
||||||
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects |
|
||||||
private var report: Report? = null |
|
||||||
private var reportTitle: String = "" |
|
||||||
|
|
||||||
/** |
|
||||||
* Default constructor |
|
||||||
*/ |
|
||||||
fun newInstance(context: Context, report: Report, reportTitle: String) { |
|
||||||
//parameters = GraphParameters(stat, group, report) |
|
||||||
this.report = report |
|
||||||
this.reportTitle = reportTitle |
|
||||||
val intent = Intent(context, ReportDetailsActivity::class.java) |
|
||||||
context.startActivity(intent) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) { |
|
||||||
super.onCreate(savedInstanceState) |
|
||||||
setContentView(R.layout.activity_report_details) |
|
||||||
initUI() |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Init UI |
|
||||||
*/ |
|
||||||
private fun initUI() { |
|
||||||
|
|
||||||
report?.let { |
|
||||||
val fragmentTransaction = supportFragmentManager.beginTransaction() |
|
||||||
val reportDetailsFragment = ReportDetailsFragment.newInstance(it, reportTitle) |
|
||||||
fragmentTransaction.add(R.id.reportDetailsContainer, reportDetailsFragment) |
|
||||||
fragmentTransaction.commit() |
|
||||||
|
|
||||||
report = null |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,59 +0,0 @@ |
|||||||
package net.pokeranalytics.android.ui.activity |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.content.Intent |
|
||||||
import android.os.Bundle |
|
||||||
import net.pokeranalytics.android.R |
|
||||||
import net.pokeranalytics.android.calculus.ComputableGroup |
|
||||||
import net.pokeranalytics.android.calculus.Report |
|
||||||
import net.pokeranalytics.android.calculus.Stat |
|
||||||
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
|
||||||
import net.pokeranalytics.android.ui.fragment.StatisticDetailsFragment |
|
||||||
|
|
||||||
|
|
||||||
class StatisticsDetailsParameters(var stat: Stat, var computableGroup: ComputableGroup, var report: Report, var title: String? = null) |
|
||||||
|
|
||||||
class StatisticDetailsActivity : PokerAnalyticsActivity() { |
|
||||||
|
|
||||||
companion object { |
|
||||||
|
|
||||||
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects |
|
||||||
private var parameters: StatisticsDetailsParameters? = null |
|
||||||
private var displayAggregationChoices: Boolean = true |
|
||||||
|
|
||||||
/** |
|
||||||
* Default constructor |
|
||||||
*/ |
|
||||||
fun newInstance(context: Context, stat: Stat, group: ComputableGroup, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) { |
|
||||||
parameters = StatisticsDetailsParameters(stat, group, report, title) |
|
||||||
this.displayAggregationChoices = displayAggregationChoices |
|
||||||
val intent = Intent(context, StatisticDetailsActivity::class.java) |
|
||||||
context.startActivity(intent) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) { |
|
||||||
super.onCreate(savedInstanceState) |
|
||||||
setContentView(R.layout.activity_statistic_details) |
|
||||||
initUI() |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Init UI |
|
||||||
*/ |
|
||||||
private fun initUI() { |
|
||||||
|
|
||||||
val fragmentTransaction = supportFragmentManager.beginTransaction() |
|
||||||
val statisticDetailsFragment = StatisticDetailsFragment() |
|
||||||
fragmentTransaction.add(R.id.statisticDetailsContainer, statisticDetailsFragment) |
|
||||||
fragmentTransaction.commit() |
|
||||||
|
|
||||||
parameters?.let { |
|
||||||
statisticDetailsFragment.setData(it.stat, it.computableGroup, it.report, displayAggregationChoices, it.title) |
|
||||||
parameters = null |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,35 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.ReportActivity |
||||||
|
import net.pokeranalytics.android.ui.fragment.report.TableReportFragment |
||||||
|
|
||||||
|
class TableReportActivity : ReportActivity() { |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
setContentView(R.layout.activity_table_report) |
||||||
|
initUI() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init UI |
||||||
|
*/ |
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
parameters?.let { |
||||||
|
|
||||||
|
val report = it.report |
||||||
|
val title = it.title |
||||||
|
|
||||||
|
val fragmentTransaction = supportFragmentManager.beginTransaction() |
||||||
|
val fragment = TableReportFragment.newInstance(report, title) |
||||||
|
fragmentTransaction.add(R.id.reportDetailsContainer, fragment) |
||||||
|
fragmentTransaction.commit() |
||||||
|
} |
||||||
|
parameters = null |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity.components |
||||||
|
|
||||||
|
enum class RequestCode(var value: Int) { |
||||||
|
DEFAULT(1), |
||||||
|
NEW_SESSION(800), |
||||||
|
NEW_TRANSACTION(801), |
||||||
|
NEW_REPORT(802), |
||||||
|
IMPORT(900) |
||||||
|
} |
||||||
|
|
||||||
|
enum class ResultCode(var value: Int) { |
||||||
|
IMPORT_UNRECOGNIZED_FORMAT(901) |
||||||
|
} |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
package net.pokeranalytics.android.ui.activity.components |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import net.pokeranalytics.android.calculus.Report |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
|
||||||
|
class ReportParameters(var report: Report, var title: String, var stat: Stat? = null, var showAggregationChoices: Boolean = true) |
||||||
|
|
||||||
|
abstract class ReportActivity : PokerAnalyticsActivity() { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects |
||||||
|
var parameters: ReportParameters? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* Default constructor |
||||||
|
*/ |
||||||
|
fun newInstance(context: Context, report: Report, reportTitle: String, stat: Stat? = null) { |
||||||
|
val options = report.options |
||||||
|
this.parameters = ReportParameters(report, reportTitle, stat) |
||||||
|
val intent = Intent(context, options.display.activityClass) |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
fun newInstanceForResult(fragment: Fragment, report: Report, reportTitle: String, stat: Stat? = null) { |
||||||
|
val options = report.options |
||||||
|
this.parameters = ReportParameters(report, reportTitle, stat) |
||||||
|
val intent = Intent(fragment.requireContext(), options.display.activityClass) |
||||||
|
fragment.startActivityForResult(intent, RequestCode.DEFAULT.value) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,163 @@ |
|||||||
|
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 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() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,167 @@ |
|||||||
|
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 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.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 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?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) != null) { |
||||||
|
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)) |
||||||
|
|
||||||
|
if (bankrollReport.transactionBuckets.isNotEmpty()) { |
||||||
|
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.operations)) |
||||||
|
bankrollReport.transactionBuckets.keys.forEach { key -> |
||||||
|
bankrollReport.transactionBuckets[key]?.let { transactionBucket -> |
||||||
|
val typeName = transactionBucket.transactions.firstOrNull()?.type?.getDisplayName(requireContext()) |
||||||
|
val computedStat = ComputedStat(Stat.NET_RESULT, transactionBucket.total) |
||||||
|
rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, title = typeName, computedStat = computedStat)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init UI |
||||||
|
*/ |
||||||
|
private fun initUI() { |
||||||
|
|
||||||
|
setDisplayHomeAsUpEnabled(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) { |
||||||
|
setToolbarTitle(getString(R.string.total)) |
||||||
|
bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = false |
||||||
|
} else { |
||||||
|
setToolbarTitle(bankrollReport.setup.bankroll?.name) |
||||||
|
bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = true |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Open Bankroll edit activity |
||||||
|
*/ |
||||||
|
private fun editBankroll() { |
||||||
|
EditableDataActivity.newInstanceForResult(this, LiveData.BANKROLL, bankrollReport.setup.bankroll?.id, REQUEST_CODE_EDIT) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,72 +1,228 @@ |
|||||||
package net.pokeranalytics.android.ui.fragment |
package net.pokeranalytics.android.ui.fragment |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.content.Intent |
||||||
import android.os.Bundle |
import android.os.Bundle |
||||||
import android.view.LayoutInflater |
import android.view.LayoutInflater |
||||||
import android.view.View |
import android.view.View |
||||||
import android.view.ViewGroup |
import android.view.ViewGroup |
||||||
import androidx.recyclerview.widget.LinearLayoutManager |
import androidx.recyclerview.widget.LinearLayoutManager |
||||||
|
import com.github.mikephil.charting.data.LineDataSet |
||||||
|
import io.realm.RealmObject |
||||||
|
import io.realm.RealmResults |
||||||
import kotlinx.android.synthetic.main.fragment_bankroll.* |
import kotlinx.android.synthetic.main.fragment_bankroll.* |
||||||
import kotlinx.android.synthetic.main.fragment_stats.recyclerView |
import kotlinx.coroutines.Dispatchers |
||||||
|
import kotlinx.coroutines.GlobalScope |
||||||
|
import kotlinx.coroutines.delay |
||||||
|
import kotlinx.coroutines.launch |
||||||
import net.pokeranalytics.android.R |
import net.pokeranalytics.android.R |
||||||
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
import net.pokeranalytics.android.calculus.ComputedStat |
||||||
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment |
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.calculus.bankroll.BankrollCalculator |
||||||
class BankrollFragment : PokerAnalyticsFragment() { |
import net.pokeranalytics.android.calculus.bankroll.BankrollReport |
||||||
|
import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup |
||||||
|
import net.pokeranalytics.android.model.LiveData |
||||||
|
import net.pokeranalytics.android.model.interfaces.Deletable |
||||||
|
import net.pokeranalytics.android.model.interfaces.Identifiable |
||||||
|
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.GraphActivity |
||||||
|
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.DeletableItemFragment |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.RowViewType |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow |
||||||
|
import net.pokeranalytics.android.util.extensions.sorted |
||||||
|
import timber.log.Timber |
||||||
|
import java.util.* |
||||||
|
import kotlin.collections.ArrayList |
||||||
|
|
||||||
|
class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
const val REQUEST_CODE_DETAILS = 100 |
||||||
|
const val REQUEST_CODE_CREATE = 101 |
||||||
|
|
||||||
|
/** |
||||||
|
* Create new instance |
||||||
|
*/ |
||||||
|
fun newInstance(): BankrollFragment { |
||||||
|
val fragment = BankrollFragment() |
||||||
|
val bundle = Bundle() |
||||||
|
fragment.arguments = bundle |
||||||
|
return fragment |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
companion object { |
private var rows: ArrayList<RowRepresentable> = ArrayList() |
||||||
|
private var bankrollReportForRow: HashMap<RowRepresentable, BankrollReport> = HashMap() |
||||||
|
private var lastItemClickedPosition: Int = 0 |
||||||
|
private var lastItemClickedId: String = "" |
||||||
|
private var deletedRow: RowRepresentable? = null |
||||||
|
|
||||||
/** |
private lateinit var bankrolls: RealmResults<Bankroll> |
||||||
* Create new instance |
|
||||||
*/ |
|
||||||
fun newInstance(): BankrollFragment { |
|
||||||
val fragment = BankrollFragment() |
|
||||||
val bundle = Bundle() |
|
||||||
fragment.arguments = bundle |
|
||||||
return fragment |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private lateinit var parentActivity: PokerAnalyticsActivity |
override fun deletableItems() : List<Deletable> { |
||||||
|
return this.bankrolls |
||||||
|
} |
||||||
|
|
||||||
// Life Cycle |
// Life Cycle |
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
||||||
return inflater.inflate(R.layout.fragment_bankroll, container, false) |
super.onCreateView(inflater, container, savedInstanceState) |
||||||
} |
return inflater.inflate(R.layout.fragment_bankroll, 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_DETAILS && resultCode == Activity.RESULT_OK) { |
||||||
|
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) |
||||||
|
itemToDeleteId?.let { id -> |
||||||
|
GlobalScope.launch(Dispatchers.Main) { |
||||||
|
delay(300) |
||||||
|
deleteItem(dataListAdapter, bankrolls, id) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) { |
||||||
|
//TODO: Refresh bankrolls |
||||||
|
initData() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun adapterRows(): List<RowRepresentable>? { |
||||||
|
return rows |
||||||
|
} |
||||||
|
|
||||||
|
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { |
||||||
|
when (row) { |
||||||
|
is GraphRow -> { |
||||||
|
val lineDataSet = row.dataSet as LineDataSet |
||||||
|
GraphActivity.newInstance(requireContext(), listOf(lineDataSet), title = getString(R.string.bankroll)) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
if (bankrollReportForRow.containsKey(row)) { |
||||||
|
bankrollReportForRow[row]?.let { bankrollReport -> |
||||||
|
lastItemClickedPosition = position |
||||||
|
lastItemClickedId = (row as? Identifiable)?.id ?: "" |
||||||
|
BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Business |
||||||
|
|
||||||
|
/** |
||||||
|
* Init data |
||||||
|
*/ |
||||||
|
private fun initData() { |
||||||
|
|
||||||
|
val realm = getRealm() |
||||||
|
this.bankrolls = realm.sorted() |
||||||
|
|
||||||
|
rows.clear() |
||||||
|
bankrollReportForRow.clear() |
||||||
|
|
||||||
|
GlobalScope.launch { |
||||||
|
|
||||||
|
launch(Dispatchers.Main) { |
||||||
|
|
||||||
|
// TODO: Improve that |
||||||
|
// We are in the main thread... |
||||||
|
|
||||||
|
val startDate = Date() |
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
// Graph |
||||||
super.onViewCreated(view, savedInstanceState) |
val globalBankrollReportSetup = BankrollReportSetup() |
||||||
initData() |
val globalBankrollReport = BankrollCalculator.computeReport(getRealm(), globalBankrollReportSetup) |
||||||
initUI() |
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)) |
||||||
|
|
||||||
// Business |
Timber.d("initData: ${System.currentTimeMillis() - startDate.time}ms") |
||||||
|
|
||||||
/** |
// val bankrolls = LiveData.Bankroll.items(getRealm()) as RealmResults<Bankroll> |
||||||
* Init data |
|
||||||
*/ |
|
||||||
private fun initData() { |
|
||||||
|
|
||||||
} |
bankrolls.forEach { bankroll -> |
||||||
|
val bankrollReportSetup = BankrollReportSetup(bankroll) |
||||||
|
val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) |
||||||
|
val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total) |
||||||
|
val row = |
||||||
|
CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = bankroll.name, computedStat = computedStat, isSelectable = true) |
||||||
|
row.id = bankroll.id |
||||||
|
|
||||||
|
rows.add(row) |
||||||
|
bankrollReportForRow[row] = bankrollReport |
||||||
|
} |
||||||
|
|
||||||
|
if (!isDetached) { |
||||||
|
dataListAdapter.notifyDataSetChanged() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
/** |
/** |
||||||
* Init UI |
* Init UI |
||||||
*/ |
*/ |
||||||
private fun initUI() { |
private fun initUI() { |
||||||
|
|
||||||
parentActivity = activity as PokerAnalyticsActivity |
setDisplayHomeAsUpEnabled(true) |
||||||
|
|
||||||
parentActivity.setSupportActionBar(toolbar) |
dataListAdapter = RowRepresentableAdapter(this, this) |
||||||
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) |
|
||||||
setHasOptionsMenu(true) |
|
||||||
|
|
||||||
val viewManager = LinearLayoutManager(requireContext()) |
val viewManager = LinearLayoutManager(requireContext()) |
||||||
|
|
||||||
recyclerView.apply { |
recyclerView.apply { |
||||||
setHasFixedSize(true) |
setHasFixedSize(true) |
||||||
layoutManager = viewManager |
layoutManager = viewManager |
||||||
//adapter = statsAdapter |
adapter = dataListAdapter |
||||||
|
} |
||||||
|
|
||||||
|
addButton.setOnClickListener { |
||||||
|
EditableDataActivity.newInstanceForResult(this@BankrollFragment, dataType = LiveData.BANKROLL, primaryKey = null, requestCode = REQUEST_CODE_CREATE) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun updateUIAfterDeletion(itemPosition: Int) { |
||||||
|
lastItemClickedPosition = rows.indexOfFirst { if (it is Identifiable) it.id == lastItemClickedId else false } |
||||||
|
deletedRow = rows.find { if (it is Identifiable) it.id == lastItemClickedId else false } |
||||||
|
rows.removeAt(lastItemClickedPosition) |
||||||
|
dataListAdapter.notifyItemRemoved(lastItemClickedPosition) |
||||||
|
} |
||||||
|
|
||||||
|
override fun updateUIAfterUndoDeletion(newItem: RealmObject) { |
||||||
|
|
||||||
|
// TODO: Improve that |
||||||
|
// We are recreating a Bankroll report because the last one is invalid => the bankroll of the setup has been deleted |
||||||
|
|
||||||
|
deletedRow?.let { row -> |
||||||
|
val bankrollReportSetup = BankrollReportSetup(newItem as Bankroll) |
||||||
|
val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) |
||||||
|
bankrollReportForRow[row] = bankrollReport |
||||||
|
|
||||||
|
rows.add(lastItemClickedPosition, row) |
||||||
|
dataListAdapter.notifyItemInserted(lastItemClickedPosition) |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
|
|||||||
@ -1,222 +0,0 @@ |
|||||||
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.appcompat.app.AlertDialog |
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager |
|
||||||
import io.realm.RealmObject |
|
||||||
import kotlinx.android.synthetic.main.fragment_editable_data.* |
|
||||||
import kotlinx.android.synthetic.main.fragment_editable_data.view.* |
|
||||||
import net.pokeranalytics.android.R |
|
||||||
import net.pokeranalytics.android.exceptions.ConfigurationException |
|
||||||
import net.pokeranalytics.android.model.LiveData |
|
||||||
import net.pokeranalytics.android.model.interfaces.Deletable |
|
||||||
import net.pokeranalytics.android.model.interfaces.Editable |
|
||||||
import net.pokeranalytics.android.model.interfaces.Savable |
|
||||||
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus |
|
||||||
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.RowRepresentableDataSource |
|
||||||
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate |
|
||||||
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment |
|
||||||
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment |
|
||||||
import net.pokeranalytics.android.ui.view.RowRepresentable |
|
||||||
|
|
||||||
|
|
||||||
open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate { |
|
||||||
|
|
||||||
lateinit var parentActivity: PokerAnalyticsActivity |
|
||||||
lateinit var item: RealmObject |
|
||||||
lateinit var liveDataType: LiveData |
|
||||||
lateinit var rowRepresentableAdapter: RowRepresentableAdapter |
|
||||||
|
|
||||||
private var editableMenu: Menu? = null |
|
||||||
private var dataType: Int? = null |
|
||||||
private var primaryKey: String? = null |
|
||||||
|
|
||||||
var isUpdating = false |
|
||||||
var shouldOpenKeyboard = true |
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
|
||||||
return inflater.inflate(R.layout.fragment_editable_data, container, false) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
|
||||||
super.onViewCreated(view, savedInstanceState) |
|
||||||
initUI() |
|
||||||
initData() |
|
||||||
} |
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { |
|
||||||
menu?.clear() |
|
||||||
inflater?.inflate(R.menu.toolbar_editable_data, menu) |
|
||||||
this.editableMenu = menu |
|
||||||
updateMenuUI() |
|
||||||
super.onCreateOptionsMenu(menu, inflater) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean { |
|
||||||
when (item!!.itemId) { |
|
||||||
R.id.save -> saveData() |
|
||||||
R.id.delete -> deleteData() |
|
||||||
} |
|
||||||
return true |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { |
|
||||||
BottomSheetFragment.create(fragmentManager, row, this, getDataSource().editDescriptors(row)) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { |
|
||||||
this.getRealm().executeTransaction { |
|
||||||
(this.item as Editable).updateValue(value, row) |
|
||||||
} |
|
||||||
rowRepresentableAdapter.refreshRow(row) |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Init UI |
|
||||||
*/ |
|
||||||
private fun initUI() { |
|
||||||
parentActivity = activity as PokerAnalyticsActivity |
|
||||||
parentActivity.setSupportActionBar(toolbar) |
|
||||||
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) |
|
||||||
setHasOptionsMenu(true) |
|
||||||
|
|
||||||
val viewManager = LinearLayoutManager(requireContext()) |
|
||||||
|
|
||||||
recyclerView.apply { |
|
||||||
setHasFixedSize(true) |
|
||||||
layoutManager = viewManager |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Return the data source |
|
||||||
*/ |
|
||||||
open fun getDataSource(): RowRepresentableDataSource { |
|
||||||
return this.item as RowRepresentableDataSource |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Init data |
|
||||||
*/ |
|
||||||
private fun initData() { |
|
||||||
if (this.dataType != null) { |
|
||||||
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey) |
|
||||||
proxyItem?.let { |
|
||||||
//TODO: Localize |
|
||||||
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" |
|
||||||
isUpdating = true |
|
||||||
} ?: run { |
|
||||||
//TODO: Localize |
|
||||||
this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext()) |
|
||||||
} |
|
||||||
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) |
|
||||||
|
|
||||||
val dataSource = getDataSource() |
|
||||||
this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this) |
|
||||||
this.recyclerView.adapter = rowRepresentableAdapter |
|
||||||
|
|
||||||
// When creating an object, open automatically the keyboard for the first row |
|
||||||
if (!isUpdating && shouldOpenKeyboard) { |
|
||||||
val row = dataSource.adapterRows()?.firstOrNull() |
|
||||||
row?.let { |
|
||||||
onRowSelected(0, it) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Update menu UI |
|
||||||
*/ |
|
||||||
private fun updateMenuUI() { |
|
||||||
editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating |
|
||||||
editableMenu?.findItem(R.id.save)?.isVisible = true |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Save data |
|
||||||
*/ |
|
||||||
fun saveData() { |
|
||||||
|
|
||||||
val savable = this.item |
|
||||||
when (savable) { |
|
||||||
is Savable -> { |
|
||||||
val status = savable.getSaveValidityStatus(realm = this.getRealm()) |
|
||||||
when (status) { |
|
||||||
SaveValidityStatus.VALID -> { |
|
||||||
this.getRealm().executeTransaction { |
|
||||||
val managedItem = it.copyToRealmOrUpdate(this.item) |
|
||||||
if (managedItem is Savable) { |
|
||||||
val uniqueIdentifier = (managedItem as Savable).id |
|
||||||
finishActivityWithResult(uniqueIdentifier) |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
else -> { |
|
||||||
val message = savable.getFailedSaveMessage(status) |
|
||||||
val builder = AlertDialog.Builder(requireContext()) |
|
||||||
.setMessage(message) |
|
||||||
.setNegativeButton(R.string.ok, null) |
|
||||||
builder.show() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} else -> { |
|
||||||
throw ConfigurationException("Save action called on un-Savable object") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Delete data |
|
||||||
*/ |
|
||||||
private fun deleteData() { |
|
||||||
|
|
||||||
val deletable = this.item as Deletable |
|
||||||
val realm = this.getRealm() |
|
||||||
|
|
||||||
if (deletable.isValidForDelete(realm)) { |
|
||||||
val intent = Intent() |
|
||||||
intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, true) |
|
||||||
activity?.setResult(RESULT_OK, intent) |
|
||||||
activity?.finish() |
|
||||||
} else { |
|
||||||
val message = deletable.getFailedDeleteMessage() |
|
||||||
val builder = AlertDialog.Builder(requireContext()) |
|
||||||
.setMessage(message) |
|
||||||
.setNegativeButton(R.string.ok, null) |
|
||||||
builder.show() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Finish the activity with a result |
|
||||||
*/ |
|
||||||
private fun finishActivityWithResult(uniqueIdentifier: String) { |
|
||||||
val intent = Intent() |
|
||||||
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType) |
|
||||||
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier) |
|
||||||
activity?.setResult(RESULT_OK, intent) |
|
||||||
activity?.finish() |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Set fragment data |
|
||||||
*/ |
|
||||||
fun setData(dataType: Int, primaryKey: String?) { |
|
||||||
this.dataType = dataType |
|
||||||
this.liveDataType = LiveData.values()[dataType] |
|
||||||
this.primaryKey = primaryKey |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,377 @@ |
|||||||
|
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 com.google.android.material.tabs.TabLayout |
||||||
|
import io.realm.RealmModel |
||||||
|
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.Filter |
||||||
|
import net.pokeranalytics.android.model.realm.Session |
||||||
|
import net.pokeranalytics.android.model.realm.Transaction |
||||||
|
import net.pokeranalytics.android.ui.activity.* |
||||||
|
import net.pokeranalytics.android.ui.activity.components.RequestCode |
||||||
|
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.FilterableFragment |
||||||
|
import net.pokeranalytics.android.ui.interfaces.FilterActivityRequestCode |
||||||
|
import net.pokeranalytics.android.ui.interfaces.FilterableType |
||||||
|
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 : FilterableFragment(), RowRepresentableDelegate { |
||||||
|
|
||||||
|
private enum class Tab { |
||||||
|
SESSIONS, |
||||||
|
TRANSACTIONS |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
const val REQUEST_CODE_MENU = 100 |
||||||
|
const val REQUEST_CODE_TRANSACTION_DETAILS = 101 |
||||||
|
|
||||||
|
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 |
||||||
|
private var adapterHasBeenSet: Boolean = false |
||||||
|
private var selectedTransaction: Transaction? = null |
||||||
|
private var selectedTransactionPosition: Int = -1 |
||||||
|
|
||||||
|
override val observedEntities: List<Class<out RealmModel>> = listOf(Session::class.java, Transaction::class.java) |
||||||
|
|
||||||
|
override fun entitiesChanged(clazz: Class<out RealmModel>) { |
||||||
|
super.entitiesChanged(clazz) |
||||||
|
|
||||||
|
when (clazz.kotlin) { |
||||||
|
Session::class -> { |
||||||
|
this.feedSessionAdapter.refreshData() |
||||||
|
this.feedSessionAdapter.notifyDataSetChanged() |
||||||
|
} |
||||||
|
Transaction::class -> { |
||||||
|
this.feedTransactionAdapter.refreshData() |
||||||
|
this.feedTransactionAdapter.notifyDataSetChanged() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
||||||
|
super.onCreateView(inflater, container, savedInstanceState) |
||||||
|
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() |
||||||
|
} |
||||||
|
} else if (requestCode == REQUEST_CODE_TRANSACTION_DETAILS && resultCode == RESULT_OK && data != null) { |
||||||
|
if (data.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) != null) { |
||||||
|
deleteSelectedTransaction() |
||||||
|
} |
||||||
|
} else if (requestCode == FilterActivityRequestCode.CREATE_FILTER.ordinal && resultCode == RESULT_OK) { |
||||||
|
data?.let { |
||||||
|
this.saveFilter(this.requireContext(), it.getStringExtra(FiltersActivity.IntentKey.FILTER_ID.keyName)) |
||||||
|
} |
||||||
|
} else if (requestCode == RequestCode.NEW_TRANSACTION.value && resultCode == RESULT_OK) { |
||||||
|
this.selectTab(Tab.TRANSACTIONS) |
||||||
|
} else if (requestCode == RequestCode.NEW_SESSION.value && resultCode == RESULT_OK) { |
||||||
|
this.selectTab(Tab.SESSIONS) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroyView() { |
||||||
|
super.onDestroyView() |
||||||
|
realmSessions.removeAllChangeListeners() |
||||||
|
realmTransactions.removeAllChangeListeners() |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
override fun setUserVisibleHint(isVisibleToUser: Boolean) { |
||||||
|
super.setUserVisibleHint(isVisibleToUser) |
||||||
|
if (isVisibleToUser && view != null) { |
||||||
|
if (FilterHandler.filterWasUpdated) { |
||||||
|
applyFilter() |
||||||
|
FilterHandler.filterWasUpdated = false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { |
||||||
|
when (row) { |
||||||
|
is Session -> SessionActivity.newInstance(requireContext(), sessionId = (row as Editable).id) |
||||||
|
is Transaction -> { |
||||||
|
selectedTransaction = row |
||||||
|
selectedTransactionPosition = position |
||||||
|
EditableDataActivity.newInstanceForResult( |
||||||
|
this, |
||||||
|
LiveData.TRANSACTION, |
||||||
|
row.id, |
||||||
|
REQUEST_CODE_TRANSACTION_DETAILS |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { |
||||||
|
override fun onTabSelected(tab: TabLayout.Tab) { |
||||||
|
when (tab.position) { |
||||||
|
0 -> { |
||||||
|
currentFilterable = FilterableType.SESSION |
||||||
|
recyclerView.adapter = feedSessionAdapter |
||||||
|
} |
||||||
|
1 -> { |
||||||
|
currentFilterable = FilterableType.TRANSACTION |
||||||
|
recyclerView.adapter = feedTransactionAdapter |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onTabUnselected(tab: TabLayout.Tab) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onTabReselected(tab: TabLayout.Tab) { |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Init data |
||||||
|
*/ |
||||||
|
private fun initData() { |
||||||
|
|
||||||
|
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm", Locale.getDefault()) |
||||||
|
betaLimitDate = sdf.parse("17/7/2019 10:00") |
||||||
|
this.currentFilterable = FilterableType.SESSION |
||||||
|
|
||||||
|
val viewManager = SmoothScrollLinearLayoutManager(requireContext()) |
||||||
|
recyclerView.apply { |
||||||
|
setHasFixedSize(true) |
||||||
|
layoutManager = viewManager |
||||||
|
} |
||||||
|
|
||||||
|
applyFilter() |
||||||
|
} |
||||||
|
|
||||||
|
private fun loadSessions(filter: Filter? = null) { |
||||||
|
val sessionFilter: Filter? = filter?.let { |
||||||
|
if (it.filterableType == FilterableType.SESSION) { |
||||||
|
it |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Sessions |
||||||
|
this.realmSessions = |
||||||
|
sessionFilter?.results() ?: run { getRealm().where<Session>().isNotNull("startDate").findAll() } |
||||||
|
this.realmSessions = this.realmSessions.sort("startDate", Sort.DESCENDING) |
||||||
|
|
||||||
|
val pendingSessions = sessionFilter?.let { |
||||||
|
getRealm().where<Session>().alwaysFalse().findAll() |
||||||
|
} ?: run { |
||||||
|
getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING) |
||||||
|
} |
||||||
|
var distinctDateSessions = sessionFilter?.results("year", "month") ?: run { |
||||||
|
getRealm().where<Session>().distinct("year", "month").findAll() |
||||||
|
} |
||||||
|
distinctDateSessions = distinctDateSessions.sort("startDate", Sort.DESCENDING) |
||||||
|
this.feedSessionAdapter = |
||||||
|
FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions) |
||||||
|
} |
||||||
|
|
||||||
|
private fun loadTransactions(filter: Filter? = null) { |
||||||
|
val transactionFilter: Filter? = filter?.let { |
||||||
|
if (it.filterableType == FilterableType.TRANSACTION) { |
||||||
|
it |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Transactions |
||||||
|
this.realmTransactions = transactionFilter?.results() ?: run { getRealm().where<Transaction>().findAll() } |
||||||
|
this.realmTransactions = this.realmTransactions.sort("date", Sort.DESCENDING) |
||||||
|
|
||||||
|
var distinctDateTransactions = transactionFilter?.results("year", "month") ?: run { |
||||||
|
getRealm().where<Transaction>().distinct("year", "month").findAll() |
||||||
|
} |
||||||
|
distinctDateTransactions = distinctDateTransactions.sort("date", Sort.DESCENDING) |
||||||
|
this.feedTransactionAdapter = |
||||||
|
FeedTransactionRowRepresentableAdapter(this, realmTransactions, distinctDateTransactions) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new cash game |
||||||
|
*/ |
||||||
|
private fun createNewSession(isTournament: Boolean) { |
||||||
|
|
||||||
|
// val sessionCount = this.feedSessionAdapter.realmResults.size |
||||||
|
// if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG |
||||||
|
// Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show() |
||||||
|
// BillingActivity.newInstanceForResult(requireContext()) |
||||||
|
// return |
||||||
|
// } |
||||||
|
|
||||||
|
if (Date().after(betaLimitDate)) { |
||||||
|
this.showEndOfBetaMessage() |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
SessionActivity.newInstanceforResult(this, isTournament, requestCode = RequestCode.NEW_SESSION.value) |
||||||
|
newSessionCreated = true |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new transaction |
||||||
|
*/ |
||||||
|
private fun createNewTransaction() { |
||||||
|
|
||||||
|
if (Date().after(betaLimitDate)) { |
||||||
|
this.showEndOfBetaMessage() |
||||||
|
return |
||||||
|
} |
||||||
|
EditableDataActivity.newInstanceForResult(this, LiveData.TRANSACTION, null, RequestCode.NEW_TRANSACTION.value) |
||||||
|
|
||||||
|
// EditableDataActivity.newInstance(requireContext(), LiveData.TRANSACTION.ordinal) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Delete selected transaction |
||||||
|
*/ |
||||||
|
private fun deleteSelectedTransaction() { |
||||||
|
val realm = getRealm() |
||||||
|
realm.beginTransaction() |
||||||
|
selectedTransaction?.deleteFromRealm() |
||||||
|
realm.commitTransaction() |
||||||
|
selectedTransactionPosition = -1 |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Show end of beta message |
||||||
|
*/ |
||||||
|
private fun showEndOfBetaMessage() { |
||||||
|
Toast.makeText( |
||||||
|
context, |
||||||
|
"Beta has ended. Thanks a lot for your participation! Please update with the Google Play version to continue using the app", |
||||||
|
Toast.LENGTH_LONG |
||||||
|
).show() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Filter Handler |
||||||
|
|
||||||
|
override fun applyFilter() { |
||||||
|
super.applyFilter() |
||||||
|
|
||||||
|
val filter: Filter? = this.currentFilter(this.requireContext(), getRealm()) |
||||||
|
this.loadSessions(filter) |
||||||
|
this.loadTransactions(filter) |
||||||
|
|
||||||
|
filter?.let { |
||||||
|
when (it.filterableType) { |
||||||
|
FilterableType.SESSION -> { |
||||||
|
recyclerView.adapter = feedSessionAdapter |
||||||
|
this.selectTab(Tab.SESSIONS) |
||||||
|
} |
||||||
|
FilterableType.TRANSACTION -> { |
||||||
|
recyclerView.adapter = feedTransactionAdapter |
||||||
|
this.selectTab(Tab.TRANSACTIONS) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
} |
||||||
|
} |
||||||
|
adapterHasBeenSet = true |
||||||
|
} |
||||||
|
|
||||||
|
if (!adapterHasBeenSet) { |
||||||
|
adapterHasBeenSet = true |
||||||
|
recyclerView.adapter = feedSessionAdapter |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun removeFilter() { |
||||||
|
super.removeFilter() |
||||||
|
|
||||||
|
this.loadSessions() |
||||||
|
this.loadTransactions() |
||||||
|
if (currentFilterable == FilterableType.SESSION) { |
||||||
|
recyclerView.adapter = feedSessionAdapter |
||||||
|
} else { |
||||||
|
recyclerView.adapter = feedTransactionAdapter |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun selectTab(tab: Tab) { |
||||||
|
this.tabs.getTabAt(tab.ordinal)?.select() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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) |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,84 @@ |
|||||||
|
package net.pokeranalytics.android.ui.fragment |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import android.view.LayoutInflater |
||||||
|
import android.view.View |
||||||
|
import android.view.ViewGroup |
||||||
|
import kotlinx.coroutines.Dispatchers |
||||||
|
import kotlinx.coroutines.GlobalScope |
||||||
|
import kotlinx.coroutines.async |
||||||
|
import kotlinx.coroutines.launch |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.ui.activity.components.ResultCode |
||||||
|
import net.pokeranalytics.android.ui.fragment.components.RealmFragment |
||||||
|
import net.pokeranalytics.android.util.csv.CSVImporter |
||||||
|
import net.pokeranalytics.android.util.csv.ImportException |
||||||
|
import timber.log.Timber |
||||||
|
import java.io.InputStream |
||||||
|
import java.util.* |
||||||
|
import kotlin.coroutines.CoroutineContext |
||||||
|
|
||||||
|
class ImportFragment : RealmFragment() { |
||||||
|
|
||||||
|
val coroutineContext: CoroutineContext |
||||||
|
get() = Dispatchers.Main |
||||||
|
|
||||||
|
private lateinit var filePath: String |
||||||
|
private lateinit var inputStream: InputStream |
||||||
|
|
||||||
|
fun setData(path: String) { |
||||||
|
this.filePath = path |
||||||
|
} |
||||||
|
|
||||||
|
fun setData(inputStream: InputStream) { |
||||||
|
this.inputStream = inputStream |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
||||||
|
super.onCreateView(inflater, container, savedInstanceState) |
||||||
|
return inflater.inflate(R.layout.fragment_import, container, false) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||||
|
super.onViewCreated(view, savedInstanceState) |
||||||
|
|
||||||
|
this.startImport() |
||||||
|
} |
||||||
|
|
||||||
|
fun startImport() { |
||||||
|
|
||||||
|
var shouldDismissActivity = false |
||||||
|
|
||||||
|
GlobalScope.launch(coroutineContext) { |
||||||
|
|
||||||
|
val test = GlobalScope.async { |
||||||
|
val s = Date() |
||||||
|
Timber.d(">>> Start Import...") |
||||||
|
|
||||||
|
try { |
||||||
|
val csv = CSVImporter(inputStream) |
||||||
|
csv.start() |
||||||
|
} catch (e: ImportException) { |
||||||
|
shouldDismissActivity = true |
||||||
|
} |
||||||
|
val e = Date() |
||||||
|
val duration = (e.time - s.time) / 1000.0 |
||||||
|
Timber.d(">>> Import ended in $duration seconds") |
||||||
|
|
||||||
|
} |
||||||
|
test.await() |
||||||
|
|
||||||
|
if (shouldDismissActivity) { |
||||||
|
|
||||||
|
activity?.let { |
||||||
|
it.setResult(ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) |
||||||
|
it.finish() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue