parent
b061038186
commit
6f539a277f
@ -1,179 +1,185 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/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="com.android.vending.BILLING" /> |
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> |
||||
|
||||
<application |
||||
android:name=".PokerAnalyticsApplication" |
||||
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:roundIcon="@mipmap/ic_launcher_round" |
||||
android:supportsRtl="true" |
||||
android:theme="@style/PokerAnalyticsTheme"> |
||||
|
||||
<meta-data |
||||
android:name="firebase_crashlytics_collection_enabled" |
||||
android:value="false" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" |
||||
android:launchMode="singleTop" |
||||
android:label="@string/app_name" |
||||
android:screenOrientation="portrait"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<action android:name="android.intent.action.VIEW" /> |
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
|
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ImportActivity" |
||||
android:screenOrientation="portrait" |
||||
android:launchMode="singleTop"> |
||||
|
||||
<intent-filter tools:ignore="AppLinkUrlError"> |
||||
<action android:name="android.intent.action.VIEW" /> |
||||
<category android:name="android.intent.category.DEFAULT" /> |
||||
|
||||
<data android:scheme="file" /> |
||||
<data android:scheme="content" /> |
||||
<data android:mimeType="text/comma-separated-values" /> |
||||
<data android:mimeType="text/csv" /> |
||||
|
||||
</intent-filter> |
||||
|
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.SessionActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" |
||||
android:windowSoftInputMode="adjustNothing" /> |
||||
|
||||
<!-- No screenOrientation="portrait" to fix Oreo crash --> |
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.NewDataMenuActivity" |
||||
android:launchMode="singleTop" |
||||
android:theme="@style/PokerAnalyticsTheme.MenuDialog" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BankrollDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.Top10Activity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.GraphActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ProgressReportActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ComparisonReportActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.DataListActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FiltersListActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.EditableDataActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.CurrenciesActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FiltersActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FilterDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.GDPRActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BillingActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<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> |
||||
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="com.android.vending.BILLING" /> |
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
||||
|
||||
<application |
||||
android:name=".PokerAnalyticsApplication" |
||||
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
||||
android:roundIcon="@mipmap/ic_launcher_round" |
||||
android:supportsRtl="true" |
||||
android:theme="@style/PokerAnalyticsTheme"> |
||||
|
||||
<meta-data |
||||
android:name="firebase_crashlytics_collection_enabled" |
||||
android:value="false" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" |
||||
android:label="@string/app_name" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<action android:name="android.intent.action.VIEW" /> |
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
|
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ImportActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait"> |
||||
|
||||
<intent-filter tools:ignore="AppLinkUrlError"> |
||||
<action android:name="android.intent.action.VIEW" /> |
||||
<category android:name="android.intent.category.DEFAULT" /> |
||||
|
||||
<data android:scheme="file" /> |
||||
<data android:scheme="content" /> |
||||
<data android:mimeType="text/comma-separated-values" /> |
||||
<data android:mimeType="text/csv" /> |
||||
|
||||
</intent-filter> |
||||
|
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.SessionActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" |
||||
android:windowSoftInputMode="adjustNothing" /> |
||||
|
||||
<!-- No screenOrientation="portrait" to fix Oreo crash --> |
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.NewDataMenuActivity" |
||||
android:launchMode="singleTop" |
||||
android:theme="@style/PokerAnalyticsTheme.MenuDialog" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BankrollActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BankrollDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.Top10Activity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.GraphActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ProgressReportActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ComparisonReportActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.CalendarDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.DataListActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FiltersListActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.EditableDataActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.CurrenciesActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FiltersActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.FilterDetailsActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.GDPRActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.BillingActivity" |
||||
android:launchMode="singleTop" |
||||
android:screenOrientation="portrait" /> |
||||
|
||||
<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" /> |
||||
|
||||
<activity |
||||
android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity" |
||||
android:theme="@style/PokerAnalyticsTheme.AlertDialog" |
||||
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> |
||||
@ -0,0 +1,78 @@ |
||||
package net.pokeranalytics.android.model.realm |
||||
|
||||
import android.content.Context |
||||
import io.realm.Realm |
||||
import io.realm.RealmObject |
||||
import io.realm.annotations.Ignore |
||||
import io.realm.annotations.PrimaryKey |
||||
import net.pokeranalytics.android.R |
||||
import net.pokeranalytics.android.exceptions.ModelException |
||||
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus |
||||
import net.pokeranalytics.android.model.interfaces.Identifiable |
||||
import net.pokeranalytics.android.model.interfaces.Manageable |
||||
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.RowViewType |
||||
import net.pokeranalytics.android.util.NULL_TEXT |
||||
import java.util.* |
||||
|
||||
open class Comment : RealmObject(), Manageable, RowRepresentable { |
||||
|
||||
@PrimaryKey |
||||
override var id = UUID.randomUUID().toString() |
||||
var content: String = "" |
||||
var date: Date = Date() |
||||
|
||||
@Ignore |
||||
override val realmObjectClass: Class<out Identifiable> = Comment::class.java |
||||
|
||||
@Ignore |
||||
override val viewType: Int = RowViewType.CONTENT.ordinal |
||||
|
||||
@Ignore |
||||
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT_MULTI_LINES |
||||
|
||||
// @Ignore |
||||
// override val valueCanBeClearedWhenEditing: Boolean = false |
||||
|
||||
override fun localizedTitle(context: Context): String { |
||||
return context.getString(R.string.comment) |
||||
} |
||||
|
||||
override fun getDisplayName(context: Context): String { |
||||
return if (content.isNotEmpty()) content else NULL_TEXT |
||||
} |
||||
|
||||
// override fun startEditing(dataSource: Any?, parent: Fragment?) { |
||||
// if (parent == null) return |
||||
// if (parent !is RowRepresentableDelegate) return |
||||
// val data = RowEditableDataSource() |
||||
// data.append(this.content, R.string.value) |
||||
// InputFragment.buildAndShow(this, parent, data, isDeletable = true) |
||||
// } |
||||
|
||||
override fun updateValue(value: Any?, row: RowRepresentable) { |
||||
this.content = value as String? ?: "" |
||||
} |
||||
|
||||
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 isValidForDelete(realm: Realm): Boolean { |
||||
return true |
||||
} |
||||
|
||||
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { |
||||
return R.string.cf_entry_delete_popup_message |
||||
} |
||||
} |
||||
@ -1,15 +1,191 @@ |
||||
package net.pokeranalytics.android.model.realm |
||||
|
||||
import android.content.Context |
||||
import io.realm.Realm |
||||
import io.realm.RealmList |
||||
import io.realm.RealmObject |
||||
import io.realm.annotations.Ignore |
||||
import io.realm.annotations.PrimaryKey |
||||
import io.realm.kotlin.where |
||||
import net.pokeranalytics.android.R |
||||
import net.pokeranalytics.android.model.interfaces.* |
||||
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource |
||||
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.CustomizableRowRepresentable |
||||
import net.pokeranalytics.android.ui.view.rowrepresentable.PlayerRow |
||||
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow |
||||
import net.pokeranalytics.android.util.NULL_TEXT |
||||
import net.pokeranalytics.android.util.extensions.isSameDay |
||||
import net.pokeranalytics.android.util.extensions.mediumDate |
||||
import java.util.* |
||||
import kotlin.collections.ArrayList |
||||
|
||||
open class Player : RealmObject() { |
||||
open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresentableDataSource, RowRepresentable { |
||||
|
||||
@PrimaryKey |
||||
var id = UUID.randomUUID().toString() |
||||
override var id = UUID.randomUUID().toString() |
||||
|
||||
// The name of the player |
||||
var name: String = "" |
||||
override var name: String = "" |
||||
|
||||
} |
||||
// New fields |
||||
var summary: String = "" |
||||
var color: Int? = null |
||||
var picture: String? = null |
||||
var comments: RealmList<Comment> = RealmList() |
||||
|
||||
@Ignore |
||||
override val realmObjectClass: Class<out Identifiable> = Player::class.java |
||||
|
||||
@Ignore |
||||
override val viewType: Int = RowViewType.ROW_PLAYER.ordinal |
||||
|
||||
@Ignore |
||||
private var rowRepresentation: List<RowRepresentable> = mutableListOf() |
||||
|
||||
@Ignore |
||||
private var commentsToDelete: ArrayList<Comment> = ArrayList() |
||||
|
||||
|
||||
override fun isValidForDelete(realm: Realm): Boolean { |
||||
//TODO |
||||
return true |
||||
} |
||||
|
||||
override fun getFailedSaveMessage(status: SaveValidityStatus): Int { |
||||
return when(status) { |
||||
SaveValidityStatus.ALREADY_EXISTS -> R.string.duplicate_user_error |
||||
else -> super.getFailedSaveMessage(status) |
||||
} |
||||
} |
||||
|
||||
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int { |
||||
//TODO |
||||
return R.string.relationship_error |
||||
} |
||||
|
||||
override fun adapterRows(): List<RowRepresentable>? { |
||||
return rowRepresentation |
||||
} |
||||
|
||||
override fun getDisplayName(context: Context): String { |
||||
return this.name |
||||
} |
||||
|
||||
override fun stringForRow(row: RowRepresentable): String { |
||||
return when (row) { |
||||
PlayerRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT |
||||
else -> return super.stringForRow(row) |
||||
} |
||||
} |
||||
|
||||
override fun updateValue(value: Any?, row: RowRepresentable) { |
||||
when (row) { |
||||
PlayerRow.NAME -> this.name = value as String? ?: "" |
||||
PlayerRow.SUMMARY -> this.summary = value as String? ?: "" |
||||
PlayerRow.IMAGE -> this.picture = value as String? ?: "" |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Update the row representation |
||||
*/ |
||||
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> { |
||||
val rows = ArrayList<RowRepresentable>() |
||||
rows.add(PlayerRow.IMAGE) |
||||
rows.add(PlayerRow.NAME) |
||||
rows.add(PlayerRow.SUMMARY) |
||||
|
||||
if (comments.size > 0) { |
||||
// Adds Comments section |
||||
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, R.string.comments)) |
||||
|
||||
val currentCommentCalendar = Calendar.getInstance() |
||||
val currentDateCalendar = Calendar.getInstance() |
||||
|
||||
val commentsToDisplay = ArrayList<Comment>() |
||||
commentsToDisplay.addAll(comments) |
||||
commentsToDisplay.sortByDescending { it.date } |
||||
|
||||
commentsToDisplay.forEachIndexed { index, comment -> |
||||
currentCommentCalendar.time = comment.date |
||||
|
||||
if (!currentCommentCalendar.isSameDay(currentDateCalendar) || index == 0) { |
||||
currentDateCalendar.time = currentCommentCalendar.time |
||||
// Adds day sub section |
||||
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_SUBTITLE, title = currentDateCalendar.time.mediumDate())) |
||||
} |
||||
|
||||
// Adds comment |
||||
rows.add(comment) |
||||
} |
||||
|
||||
rows.add(SeparatorRow()) |
||||
} |
||||
|
||||
return rows |
||||
} |
||||
|
||||
/** |
||||
* Return if the player has a picture |
||||
*/ |
||||
fun hasPicture(): Boolean { |
||||
return picture != null && picture?.isNotEmpty() == true |
||||
} |
||||
|
||||
/** |
||||
* Update row representation |
||||
*/ |
||||
fun updateRowRepresentation() { |
||||
this.rowRepresentation = this.updatedRowRepresentationForCurrentState() |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Add an entry |
||||
*/ |
||||
fun addComment(): Comment { |
||||
val entry = Comment() |
||||
this.comments.add(entry) |
||||
updateRowRepresentation() |
||||
return entry |
||||
} |
||||
|
||||
/** |
||||
* Delete an entry |
||||
*/ |
||||
fun deleteComment(comment: Comment) { |
||||
commentsToDelete.add(comment) |
||||
this.comments.remove(comment) |
||||
updateRowRepresentation() |
||||
} |
||||
|
||||
/** |
||||
* Clean up deleted entries |
||||
*/ |
||||
fun cleanupComments() { // called when saving the custom field |
||||
val realm = Realm.getDefaultInstance() |
||||
realm.executeTransaction { |
||||
this.commentsToDelete.forEach { // entries are out of realm |
||||
realm.where<Comment>().equalTo("id", it.id).findFirst()?.deleteFromRealm() |
||||
} |
||||
} |
||||
realm.close() |
||||
this.commentsToDelete.clear() |
||||
} |
||||
|
||||
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? { |
||||
|
||||
when (row) { |
||||
PlayerRow.NAME -> return row.editingDescriptors(mapOf("defaultValue" to this.name)) |
||||
PlayerRow.SUMMARY -> return row.editingDescriptors(mapOf("defaultValue" to this.summary)) |
||||
} |
||||
|
||||
return null |
||||
} |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,77 @@ |
||||
package net.pokeranalytics.android.ui.activity |
||||
|
||||
import android.app.Activity |
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.os.Bundle |
||||
import android.view.View |
||||
import androidx.fragment.app.Fragment |
||||
import kotlinx.android.synthetic.main.activity_color_picker.* |
||||
import net.pokeranalytics.android.R |
||||
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity |
||||
|
||||
class ColorPickerActivity : PokerAnalyticsActivity() { |
||||
|
||||
companion object { |
||||
|
||||
const val INTENT_COLOR = "INTENT_COLOR" |
||||
|
||||
fun newInstance(context: Context) { |
||||
val intent = Intent(context, ColorPickerActivity::class.java) |
||||
context.startActivity(intent) |
||||
} |
||||
|
||||
/** |
||||
* Create a new instance for result |
||||
*/ |
||||
fun newInstanceForResult(fragment: Fragment, requestCode: Int) { |
||||
val intent = Intent(fragment.requireContext(), ColorPickerActivity::class.java) |
||||
fragment.startActivityForResult(intent, requestCode) |
||||
} |
||||
|
||||
} |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
setContentView(R.layout.activity_color_picker) |
||||
|
||||
initUI() |
||||
} |
||||
|
||||
/** |
||||
* Init UI |
||||
*/ |
||||
private fun initUI() { |
||||
color1.setOnClickListener { manageSelectedColor(it) } |
||||
color2.setOnClickListener { manageSelectedColor(it) } |
||||
color3.setOnClickListener { manageSelectedColor(it) } |
||||
color4.setOnClickListener { manageSelectedColor(it) } |
||||
color5.setOnClickListener { manageSelectedColor(it) } |
||||
color6.setOnClickListener { manageSelectedColor(it) } |
||||
color7.setOnClickListener { manageSelectedColor(it) } |
||||
color8.setOnClickListener { manageSelectedColor(it) } |
||||
color9.setOnClickListener { manageSelectedColor(it) } |
||||
} |
||||
|
||||
private fun manageSelectedColor(view: View) { |
||||
|
||||
val color = when(view) { |
||||
color1 -> getColor(R.color.player_color_1) |
||||
color2 -> getColor(R.color.player_color_2) |
||||
color3 -> getColor(R.color.player_color_3) |
||||
color4 -> getColor(R.color.player_color_4) |
||||
color5 -> getColor(R.color.player_color_5) |
||||
color6 -> getColor(R.color.player_color_6) |
||||
color7 -> getColor(R.color.player_color_7) |
||||
color8 -> getColor(R.color.player_color_8) |
||||
color9 -> getColor(R.color.player_color_9) |
||||
else -> getColor(R.color.player_color_1) |
||||
} |
||||
|
||||
val intent = Intent() |
||||
intent.putExtra(INTENT_COLOR, color) |
||||
setResult(Activity.RESULT_OK, intent) |
||||
finish() |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,268 @@ |
||||
package net.pokeranalytics.android.ui.activity.components |
||||
|
||||
import android.Manifest |
||||
import android.app.Activity |
||||
import android.content.Intent |
||||
import android.content.pm.PackageManager |
||||
import android.graphics.Bitmap |
||||
import android.provider.MediaStore |
||||
import androidx.core.app.ActivityCompat |
||||
import androidx.core.content.ContextCompat |
||||
import androidx.core.content.FileProvider |
||||
import kotlinx.coroutines.Dispatchers |
||||
import kotlinx.coroutines.GlobalScope |
||||
import kotlinx.coroutines.launch |
||||
import net.pokeranalytics.android.util.ImageUtils |
||||
import timber.log.Timber |
||||
import java.io.File |
||||
import java.io.IOException |
||||
import java.util.* |
||||
|
||||
|
||||
open class MediaActivity : PokerAnalyticsActivity() { |
||||
|
||||
companion object { |
||||
const val SELECTED_CHOICE_TAKE_PICTURE = 10 |
||||
const val SELECTED_CHOICE_SELECT_PICTURE = 11 |
||||
const val REQUEST_CODE_TAKE_PICTURE = 100 |
||||
const val REQUEST_CODE_SELECT_PICTURE = 101 |
||||
const val PERMISSION_REQUEST_EXTERNAL_STORAGE = 201 |
||||
const val PERMISSION_REQUEST_CAMERA = 202 |
||||
} |
||||
|
||||
|
||||
// Data |
||||
private var tempFile: File? = null |
||||
private var mCurrentPhotoPath: String? = null |
||||
private var selectedChoice = -1 |
||||
private var multiplePictures = false |
||||
|
||||
override fun onDestroy() { |
||||
super.onDestroy() |
||||
if (tempFile != null) { |
||||
tempFile!!.delete() |
||||
} |
||||
} |
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||
super.onActivityResult(requestCode, resultCode, data) |
||||
|
||||
if (resultCode == Activity.RESULT_OK) { |
||||
if (requestCode == REQUEST_CODE_SELECT_PICTURE || requestCode == REQUEST_CODE_TAKE_PICTURE) { |
||||
|
||||
val filesList = ArrayList<File>() |
||||
|
||||
GlobalScope.launch { |
||||
|
||||
if (tempFile != null) { |
||||
tempFile?.let { |
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
filesList.add(it) |
||||
getPictures(filesList) |
||||
} |
||||
} |
||||
} else if (data?.clipData != null) { |
||||
data?.clipData?.let { clipData -> |
||||
try { |
||||
|
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
isLoadingNewPictures() |
||||
} |
||||
|
||||
for (i in 0 until clipData.itemCount) { |
||||
val item = clipData.getItemAt(i) |
||||
val uri = item.uri |
||||
val inputStream = contentResolver.openInputStream(uri) |
||||
val photoFile = ImageUtils.createTempImageFile(this@MediaActivity) |
||||
ImageUtils.copyInputStreamToFile(inputStream!!, photoFile) |
||||
filesList.add(photoFile) |
||||
} |
||||
|
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
getPictures(filesList) |
||||
} |
||||
|
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} |
||||
} |
||||
} else if (data?.data != null) { |
||||
data?.data?.let { uri -> |
||||
try { |
||||
|
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
isLoadingNewPictures() |
||||
} |
||||
|
||||
val inputStream = contentResolver.openInputStream(uri) |
||||
val photoFile = ImageUtils.createTempImageFile(this@MediaActivity) |
||||
ImageUtils.copyInputStreamToFile(inputStream!!, photoFile) |
||||
filesList.add(photoFile) |
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
getPictures(filesList) |
||||
} |
||||
|
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { |
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
||||
|
||||
if (grantResults.isNotEmpty()) { |
||||
for (result in grantResults) { |
||||
if (result != PackageManager.PERMISSION_GRANTED) { |
||||
//Toast.makeText(this, getString(R.string.photo_library_add_usage_description), Toast.LENGTH_SHORT).show() |
||||
selectedChoice = -1 |
||||
return |
||||
} |
||||
} |
||||
|
||||
when (selectedChoice) { |
||||
SELECTED_CHOICE_TAKE_PICTURE -> { |
||||
openImageCaptureIntent(multiplePictures) |
||||
} |
||||
SELECTED_CHOICE_SELECT_PICTURE -> { |
||||
openImageGalleryIntent(multiplePictures) |
||||
} |
||||
} |
||||
} |
||||
selectedChoice = -1 |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Open the Camera Intent |
||||
*/ |
||||
fun openImageCaptureIntent(multiplePictures: Boolean) { |
||||
|
||||
tempFile = null |
||||
|
||||
this.mCurrentPhotoPath = null |
||||
this.multiplePictures = multiplePictures |
||||
|
||||
// Test if we have the permission |
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { |
||||
selectedChoice = SELECTED_CHOICE_TAKE_PICTURE |
||||
askForStoragePermission() |
||||
return |
||||
} |
||||
|
||||
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) |
||||
// Ensure that there's a camera activity to handle the intent |
||||
if (takePictureIntent.resolveActivity(packageManager) != null) { |
||||
// Create the File where the photo should go |
||||
try { |
||||
tempFile = ImageUtils.createImageFile(this) |
||||
mCurrentPhotoPath = "file:" + tempFile?.absolutePath |
||||
} catch (ex: IOException) { |
||||
// Error occurred while creating the File |
||||
} |
||||
|
||||
// Continue only if the File was successfully created |
||||
if (tempFile != null) { |
||||
Timber.d("tempFile: ${tempFile?.absolutePath}") |
||||
val photoURI = FileProvider.getUriForFile( |
||||
this, |
||||
applicationContext.packageName + ".fileprovider", tempFile!! |
||||
) |
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI) |
||||
startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE) |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Open the gallery intent |
||||
*/ |
||||
fun openImageGalleryIntent(multiplePictures: Boolean) { |
||||
|
||||
tempFile = null |
||||
|
||||
this.multiplePictures = multiplePictures |
||||
|
||||
// Test if we have the permission |
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { |
||||
selectedChoice = SELECTED_CHOICE_SELECT_PICTURE |
||||
askForStoragePermission() |
||||
return |
||||
} |
||||
|
||||
this.multiplePictures = multiplePictures |
||||
|
||||
val galleryIntent = Intent() |
||||
galleryIntent.type = "image/*" |
||||
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiplePictures) |
||||
galleryIntent.action = Intent.ACTION_GET_CONTENT |
||||
startActivityForResult(galleryIntent, REQUEST_CODE_SELECT_PICTURE) |
||||
} |
||||
|
||||
/** |
||||
* Ask for the external storage permission |
||||
*/ |
||||
private fun askForStoragePermission() { |
||||
// Here, thisActivity is the current activity |
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { |
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), |
||||
PERMISSION_REQUEST_EXTERNAL_STORAGE) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Ask for the acmera permission |
||||
*/ |
||||
private fun askForCameraPermission() { |
||||
// Here, thisActivity is the current activity |
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { |
||||
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), |
||||
PERMISSION_REQUEST_CAMERA) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Ask for camera and storage permission |
||||
*/ |
||||
private fun askForCameraAndStoragePermissions() { |
||||
|
||||
val permissions = ArrayList<String>() |
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { |
||||
permissions.add(Manifest.permission.CAMERA) |
||||
} |
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { |
||||
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE) |
||||
} |
||||
|
||||
if (permissions.size > 0) { |
||||
ActivityCompat.requestPermissions(this, permissions.toArray(arrayOfNulls<String>(permissions.size)), PERMISSION_REQUEST_CAMERA) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Called when a bitmap is return |
||||
* |
||||
* @param bitmap the bitmap returned |
||||
*/ |
||||
open fun getBitmapImage(file: File?, bitmap: Bitmap?) {} |
||||
|
||||
|
||||
/** |
||||
* Called when the user is adding new photos |
||||
*/ |
||||
open fun isLoadingNewPictures() {} |
||||
|
||||
/** |
||||
* Called when the user has selected photos |
||||
*/ |
||||
open fun getPictures(files: ArrayList<File>) {} |
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,218 @@ |
||||
package net.pokeranalytics.android.ui.fragment.data |
||||
|
||||
import android.app.Activity.RESULT_OK |
||||
import android.content.Intent |
||||
import android.graphics.Color |
||||
import android.os.Bundle |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.appcompat.app.AlertDialog |
||||
import kotlinx.android.synthetic.main.fragment_player.* |
||||
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.model.realm.Comment |
||||
import net.pokeranalytics.android.model.realm.Player |
||||
import net.pokeranalytics.android.ui.activity.ColorPickerActivity |
||||
import net.pokeranalytics.android.ui.activity.components.MediaActivity |
||||
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource |
||||
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource |
||||
import net.pokeranalytics.android.ui.extensions.showAlertDialog |
||||
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment |
||||
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.PlayerRow |
||||
import net.pokeranalytics.android.util.NULL_TEXT |
||||
import java.io.File |
||||
|
||||
/** |
||||
* Player data fragment |
||||
*/ |
||||
class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource { |
||||
|
||||
companion object { |
||||
const val REQUEST_CODE_PICK_COLOR = 1000 |
||||
} |
||||
|
||||
private val player: Player |
||||
get() { |
||||
return this.item as Player |
||||
} |
||||
|
||||
private var mediaActivity: MediaActivity? = null |
||||
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |
||||
super.onCreateView(inflater, container, savedInstanceState) |
||||
shouldOpenKeyboard = false |
||||
return inflater.inflate(R.layout.fragment_player, container, false) |
||||
} |
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||
super.onActivityResult(requestCode, resultCode, data) |
||||
|
||||
if (requestCode == REQUEST_CODE_PICK_COLOR && resultCode == RESULT_OK && data?.hasExtra(ColorPickerActivity.INTENT_COLOR) == true) { |
||||
val color = data.getIntExtra(ColorPickerActivity.INTENT_COLOR, Color.TRANSPARENT) |
||||
player.color = if (color != Color.TRANSPARENT) color else null |
||||
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE) |
||||
} |
||||
} |
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
super.onViewCreated(view, savedInstanceState) |
||||
initUI() |
||||
} |
||||
|
||||
/** |
||||
* Init UI |
||||
*/ |
||||
private fun initUI() { |
||||
mediaActivity = parentActivity as MediaActivity? |
||||
|
||||
player.updateRowRepresentation() |
||||
|
||||
if (!deleteButtonShouldAppear) { |
||||
onRowSelected(0, PlayerRow.NAME) |
||||
} |
||||
|
||||
addComment.setOnClickListener { |
||||
val comment = player.addComment() |
||||
rowRepresentableAdapter.notifyDataSetChanged() |
||||
onRowSelected(-1, comment) |
||||
} |
||||
} |
||||
|
||||
override fun getPhotos(files: ArrayList<File>) { |
||||
super.getPhotos(files) |
||||
files.firstOrNull()?.let { picture -> |
||||
player.updateValue(picture.absolutePath, PlayerRow.IMAGE) |
||||
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE) |
||||
} |
||||
} |
||||
|
||||
override fun getDataSource(): RowRepresentableDataSource { |
||||
return this |
||||
} |
||||
|
||||
override fun adapterRows(): List<RowRepresentable>? { |
||||
return player.adapterRows() |
||||
} |
||||
|
||||
override fun viewTypeForPosition(position: Int): Int { |
||||
return when (position) { |
||||
0 -> RowViewType.ROW_PLAYER_IMAGE.ordinal |
||||
else -> super.viewTypeForPosition(position) |
||||
} |
||||
} |
||||
|
||||
override fun rowRepresentableForPosition(position: Int): RowRepresentable? { |
||||
return when (position) { |
||||
0 -> player |
||||
else -> super.rowRepresentableForPosition(position) |
||||
} |
||||
} |
||||
|
||||
override fun stringForRow(row: RowRepresentable): String { |
||||
return when (row) { |
||||
PlayerRow.NAME -> if (player.name.isNotEmpty()) player.name else NULL_TEXT |
||||
PlayerRow.SUMMARY -> if (player.summary.isNotEmpty()) player.summary else NULL_TEXT |
||||
else -> super.stringForRow(row) |
||||
} |
||||
} |
||||
|
||||
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { |
||||
when (row) { |
||||
PlayerRow.IMAGE -> openPictureDialog() |
||||
is Comment -> { |
||||
val data = arrayListOf(RowRepresentableEditDescriptor(row.content)) |
||||
BottomSheetFragment.create(fragmentManager, row, this, data, isClearable = false, isDeletable = true) |
||||
} |
||||
else -> super.onRowSelected(position, row, fromAction) |
||||
} |
||||
} |
||||
|
||||
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { |
||||
when (row) { |
||||
is Comment -> { |
||||
row.updateValue(value, row) |
||||
player.updateRowRepresentation() |
||||
rowRepresentableAdapter.notifyDataSetChanged() |
||||
} |
||||
else -> { |
||||
super.onRowValueChanged(value, row) |
||||
if (row == PlayerRow.NAME) { |
||||
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE) |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun onRowDeleted(row: RowRepresentable) { |
||||
super.onRowDeleted(row) |
||||
when (row) { |
||||
is Comment -> { |
||||
if (row.isValidForDelete(getRealm())) { |
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
delay(300) |
||||
showAlertDialog(requireContext(), message = R.string.are_you_sure_you_want_to_delete, showCancelButton = true, positiveAction = { |
||||
player.deleteComment(row) |
||||
rowRepresentableAdapter.notifyDataSetChanged() |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open picture dialog |
||||
*/ |
||||
private fun openPictureDialog() { |
||||
|
||||
val builder = AlertDialog.Builder(requireContext()) |
||||
|
||||
val placesArray = ArrayList<CharSequence>() |
||||
placesArray.add(getString(R.string.take_a_picture)) |
||||
placesArray.add(getString(R.string.library)) |
||||
placesArray.add(getString(R.string.select_a_color)) |
||||
|
||||
if (player.hasPicture()) { |
||||
placesArray.add(getString(R.string.remove_picture)) |
||||
} |
||||
|
||||
builder.setItems(placesArray.toTypedArray()) { _, which -> |
||||
when (placesArray[which]) { |
||||
getString(R.string.take_a_picture) -> mediaActivity?.openImageCaptureIntent(false) |
||||
getString(R.string.library) -> mediaActivity?.openImageGalleryIntent(false) |
||||
getString(R.string.select_a_color) -> { |
||||
ColorPickerActivity.newInstanceForResult(this, REQUEST_CODE_PICK_COLOR) |
||||
} |
||||
getString(R.string.remove_picture) -> { |
||||
player.updateValue(null, PlayerRow.IMAGE) |
||||
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE) |
||||
} |
||||
} |
||||
} |
||||
builder.show() |
||||
} |
||||
|
||||
|
||||
override fun onDataSaved() { |
||||
super.onDataSaved() |
||||
player.cleanupComments() |
||||
} |
||||
|
||||
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? { |
||||
when (row) { |
||||
PlayerRow.NAME -> return arrayListOf(RowRepresentableEditDescriptor(this.player.name, R.string.name)) |
||||
PlayerRow.SUMMARY -> return arrayListOf(RowRepresentableEditDescriptor(this.player.summary, R.string.summary)) |
||||
} |
||||
return null |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,69 @@ |
||||
package net.pokeranalytics.android.ui.view.rowrepresentable |
||||
|
||||
import net.pokeranalytics.android.R |
||||
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 |
||||
|
||||
/** |
||||
* An enum managing the player rows |
||||
*/ |
||||
enum class PlayerRow : RowRepresentable { |
||||
IMAGE, |
||||
NAME, |
||||
SUMMARY; |
||||
|
||||
override val resId: Int? |
||||
get() { |
||||
return when (this) { |
||||
IMAGE -> null |
||||
NAME -> R.string.name |
||||
SUMMARY -> R.string.summary |
||||
} |
||||
} |
||||
|
||||
override val viewType: Int |
||||
get() { |
||||
return when (this) { |
||||
IMAGE -> RowViewType.ROW_PLAYER_IMAGE.ordinal |
||||
NAME -> RowViewType.TITLE_SUBTITLE.ordinal |
||||
SUMMARY -> RowViewType.TITLE_SUBTITLE.ordinal |
||||
} |
||||
} |
||||
|
||||
override val bottomSheetType: BottomSheetType |
||||
get() { |
||||
return when (this) { |
||||
IMAGE -> BottomSheetType.NONE |
||||
NAME -> BottomSheetType.EDIT_TEXT |
||||
SUMMARY -> BottomSheetType.EDIT_TEXT_MULTI_LINES |
||||
} |
||||
} |
||||
|
||||
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { |
||||
return null |
||||
} |
||||
|
||||
|
||||
// override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { |
||||
// |
||||
// |
||||
// } |
||||
|
||||
// override fun startEditing(dataSource: Any?, parent: Fragment?) { |
||||
// if (dataSource == null) return |
||||
// if (dataSource !is Player) return |
||||
// if (parent == null) return |
||||
// if (parent !is RowRepresentableDelegate) return |
||||
// val data = RowEditableDataSource() |
||||
// when (this) { |
||||
// NAME -> data.append(dataSource.name) |
||||
// SUMMARY -> data.append(dataSource.summary) |
||||
// else -> PokerAnalyticsException.InputFragmentException |
||||
// } |
||||
// |
||||
// InputFragment.buildAndShow(this, parent, data) |
||||
// } |
||||
|
||||
} |
||||
@ -0,0 +1,377 @@ |
||||
package net.pokeranalytics.android.util |
||||
|
||||
|
||||
import android.app.Activity |
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import android.graphics.* |
||||
import android.graphics.Paint.FILTER_BITMAP_FLAG |
||||
import android.media.ExifInterface |
||||
import android.net.Uri |
||||
import android.os.Environment |
||||
import androidx.core.content.ContextCompat |
||||
import kotlinx.coroutines.Dispatchers |
||||
import kotlinx.coroutines.GlobalScope |
||||
import kotlinx.coroutines.launch |
||||
import net.pokeranalytics.android.R |
||||
import timber.log.Timber |
||||
import java.io.File |
||||
import java.io.FileOutputStream |
||||
import java.io.IOException |
||||
import java.io.InputStream |
||||
import java.text.SimpleDateFormat |
||||
import java.util.* |
||||
|
||||
|
||||
object ImageUtils { |
||||
|
||||
/** |
||||
* Rotate a bitmap if it's necessary (depending of the EXIF data) |
||||
* Some devices don't rotate the picture but instead add the orientation |
||||
* value in the EXIF data. |
||||
* That's why we need sometimes to rotate by ourselves the bitmap |
||||
* |
||||
* @param src The file to check (for getting the Exif data) |
||||
* @param bitmap The bitmap to modify (if necessary) |
||||
* @return The bitmap in the correct orientation |
||||
*/ |
||||
fun rotateBitmap(src: String, bitmap: Bitmap, updateFile: Boolean): Bitmap { |
||||
try { |
||||
val orientation = getExifOrientation(src) |
||||
|
||||
if (orientation == ExifInterface.ORIENTATION_NORMAL) { |
||||
return bitmap |
||||
} |
||||
|
||||
val matrix = Matrix() |
||||
when (orientation) { |
||||
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1f, 1f) |
||||
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180f) |
||||
ExifInterface.ORIENTATION_FLIP_VERTICAL -> { |
||||
matrix.setRotate(180f) |
||||
matrix.postScale(-1f, 1f) |
||||
} |
||||
ExifInterface.ORIENTATION_TRANSPOSE -> { |
||||
matrix.setRotate(90f) |
||||
matrix.postScale(-1f, 1f) |
||||
} |
||||
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90f) |
||||
ExifInterface.ORIENTATION_TRANSVERSE -> { |
||||
matrix.setRotate(-90f) |
||||
matrix.postScale(-1f, 1f) |
||||
} |
||||
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90f) |
||||
else -> return bitmap |
||||
} |
||||
|
||||
try { |
||||
val oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) |
||||
bitmap.recycle() |
||||
if (updateFile) { |
||||
updateFile(src, oriented) |
||||
} |
||||
return oriented |
||||
} catch (e: OutOfMemoryError) { |
||||
e.printStackTrace() |
||||
return bitmap |
||||
} |
||||
|
||||
} catch (e: IOException) { |
||||
e.printStackTrace() |
||||
} |
||||
|
||||
return bitmap |
||||
} |
||||
|
||||
/** |
||||
* Get the Exif orientation value |
||||
* |
||||
* @param filePath The path of the file |
||||
* @return the orientation value |
||||
* @throws IOException |
||||
*/ |
||||
@Throws(IOException::class) |
||||
private fun getExifOrientation(filePath: String): Int { |
||||
val exifInterface = ExifInterface(filePath) |
||||
return exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) |
||||
} |
||||
|
||||
/** |
||||
* Save a bitmap into a file (& apply 90% compression) |
||||
* |
||||
* @param filePath Path of the file |
||||
* @param bitmap Bitmap to save |
||||
*/ |
||||
fun updateFile(filePath: String, bitmap: Bitmap) { |
||||
var out: FileOutputStream? = null |
||||
try { |
||||
out = FileOutputStream(filePath) |
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out) |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} finally { |
||||
try { |
||||
out?.close() |
||||
} catch (e: IOException) { |
||||
e.printStackTrace() |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Resize a file with the given maximum width or height (and keep the ratio!) |
||||
* @param filePath String: File path |
||||
* @param bitmap Bitmap: Image |
||||
* @param maxWidth int: Max width |
||||
* @param maxHeight int: Max height |
||||
*/ |
||||
fun resizeFile(filePath: String, bitmap: Bitmap, maxWidth: Int, maxHeight: Int) { |
||||
var bitmap = bitmap |
||||
|
||||
val options = BitmapFactory.Options() |
||||
options.inJustDecodeBounds = true |
||||
BitmapFactory.decodeFile(filePath, options) |
||||
val imageWidth = options.outWidth |
||||
val imageHeight = options.outHeight |
||||
|
||||
var newWidth: Int |
||||
var newHeight: Int |
||||
|
||||
if (imageWidth > imageHeight) { |
||||
newWidth = maxWidth |
||||
newHeight = imageHeight * maxWidth / imageWidth |
||||
if (newHeight > maxHeight) { |
||||
newHeight = maxHeight |
||||
newWidth = imageWidth * maxHeight / imageHeight |
||||
} |
||||
} else { |
||||
newHeight = maxHeight |
||||
newWidth = imageWidth * maxHeight / imageHeight |
||||
if (newWidth > maxWidth) { |
||||
newWidth = maxWidth |
||||
newHeight = imageHeight * maxWidth / imageWidth |
||||
} |
||||
} |
||||
|
||||
bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true) |
||||
updateFile(filePath, bitmap) |
||||
} |
||||
|
||||
/** |
||||
* Create a unique temp image file name |
||||
* |
||||
* @return |
||||
* @throws IOException |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun createTempImageFile(context: Context): File { |
||||
// Create an image file name |
||||
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) |
||||
val imageFileName = "JPEG_" + timeStamp + "_" |
||||
val storageDir = context.cacheDir |
||||
return File.createTempFile(imageFileName, ".jpg", storageDir) |
||||
} |
||||
|
||||
/** |
||||
* Create a unique image file name |
||||
* |
||||
* @return |
||||
* @throws IOException |
||||
*/ |
||||
@Throws(IOException::class) |
||||
fun createImageFile(context: Context): File { |
||||
// Create an image file name |
||||
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) |
||||
val imageFileName = "JPEG_" + timeStamp + "_" |
||||
|
||||
val storage = ContextCompat.getExternalFilesDirs(context, Environment.DIRECTORY_PICTURES) |
||||
val storageDir = if (storage.isNotEmpty()) storage.first() else Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) |
||||
|
||||
val appStorageDir = File(storageDir.path + "/" + context.getString(R.string.app_name)) |
||||
if (!appStorageDir.exists()) { |
||||
appStorageDir.mkdirs() |
||||
} |
||||
|
||||
return File.createTempFile(imageFileName, ".jpg", appStorageDir) |
||||
} |
||||
|
||||
/** |
||||
* Decode sample Bitmap |
||||
* |
||||
* @param filePath The bitmap file path |
||||
* @param reqWidth Max width required |
||||
* @param reqHeight Max height required |
||||
* @return The sampled bitmap |
||||
*/ |
||||
fun decodeSampledBitmapFromFile(filePath: String, reqWidth: Int, reqHeight: Int): Bitmap { |
||||
|
||||
// First decode with inJustDecodeBounds=true to check dimensions |
||||
val options = BitmapFactory.Options() |
||||
options.inJustDecodeBounds = true |
||||
BitmapFactory.decodeFile(filePath, options) |
||||
|
||||
// Calculate inSampleSize |
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight) |
||||
|
||||
// Decode bitmap with inSampleSize set |
||||
options.inJustDecodeBounds = false |
||||
return BitmapFactory.decodeFile(filePath, options) |
||||
} |
||||
|
||||
/** |
||||
* Calculate the sample size |
||||
*/ |
||||
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, |
||||
reqHeight: Int): Int { |
||||
// Raw height and width of image |
||||
val height = options.outHeight |
||||
val width = options.outWidth |
||||
var inSampleSize = 1 |
||||
|
||||
if (height > reqHeight || width > reqWidth) { |
||||
|
||||
val halfHeight = height / 2 |
||||
val halfWidth = width / 2 |
||||
|
||||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both |
||||
// height and width larger than the requested height and width. |
||||
while (halfHeight / inSampleSize > reqHeight && halfWidth / inSampleSize > reqWidth) { |
||||
inSampleSize *= 2 |
||||
} |
||||
} |
||||
|
||||
return inSampleSize |
||||
} |
||||
|
||||
/** |
||||
* Copy an input stream inside a file |
||||
* |
||||
* @param in Input Stream |
||||
* @param file Destination file |
||||
*/ |
||||
fun copyInputStreamToFile(inputStream: InputStream, file: File) { |
||||
try { |
||||
val out = FileOutputStream(file) |
||||
val buf = ByteArray(4096) |
||||
var len = 0 |
||||
while ({ len = inputStream.read(buf); len }() > 0) { |
||||
out.write(buf, 0, len) |
||||
} |
||||
|
||||
out.close() |
||||
inputStream.close() |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Update the gallery with the current file |
||||
* |
||||
* @param context Context |
||||
* @param filePath The file to add |
||||
*/ |
||||
fun updateGallery(context: Context, filePath: String) { |
||||
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) |
||||
val f = File(filePath) |
||||
val contentUri = Uri.fromFile(f) |
||||
mediaScanIntent.data = contentUri |
||||
context.sendBroadcast(mediaScanIntent) |
||||
} |
||||
|
||||
/** |
||||
* Save the bitmap in a file |
||||
*/ |
||||
fun saveBitmapInFile(context: Context, bitmap: Bitmap, filename: String, action: (filePath: String) -> Unit) { |
||||
|
||||
GlobalScope.launch { |
||||
|
||||
val outputFile = File(context.filesDir, filename) |
||||
|
||||
var out: FileOutputStream? = null |
||||
try { |
||||
out = FileOutputStream(outputFile.absolutePath) |
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out) // bmp is your Bitmap instance |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} finally { |
||||
try { |
||||
if (out != null) { |
||||
out.close() |
||||
} |
||||
} catch (e: IOException) { |
||||
e.printStackTrace() |
||||
} |
||||
} |
||||
|
||||
GlobalScope.launch(Dispatchers.Main) { |
||||
Timber.d("Save file here: ${outputFile.absolutePath}") |
||||
action(outputFile.absolutePath) |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Bitmap resizer |
||||
*/ |
||||
fun bitmapResizer(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap { |
||||
val scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888) |
||||
|
||||
val ratioX = newWidth / bitmap.width.toFloat() |
||||
val ratioY = newHeight / bitmap.height.toFloat() |
||||
val middleX = newWidth / 2.0f |
||||
val middleY = newHeight / 2.0f |
||||
|
||||
val scaleMatrix = Matrix() |
||||
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY) |
||||
|
||||
val canvas = Canvas(scaledBitmap) |
||||
canvas.matrix = scaleMatrix |
||||
canvas.drawBitmap(bitmap, middleX - bitmap.width / 2, middleY - bitmap.height / 2, Paint(FILTER_BITMAP_FLAG)) |
||||
|
||||
return scaledBitmap |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Export a bitmap |
||||
*/ |
||||
private fun exportFile(context: Activity, bitmap: Bitmap) { |
||||
/* |
||||
val outputFile = File.createTempFile("test_export", ".jpg", context.cacheDir) |
||||
|
||||
var out: FileOutputStream? = null |
||||
try { |
||||
out = FileOutputStream(outputFile.absolutePath) |
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out) |
||||
} catch (e: Exception) { |
||||
e.printStackTrace() |
||||
} finally { |
||||
try { |
||||
if (out != null) { |
||||
out.close() |
||||
} |
||||
} catch (e: IOException) { |
||||
e.printStackTrace() |
||||
} |
||||
} |
||||
|
||||
val uri = FileProvider.getUriForFile(context, |
||||
context.packageName + ".provider", outputFile) |
||||
|
||||
val shareIntent = ShareCompat.IntentBuilder.from(context) |
||||
.setType("image/jpg") |
||||
.setSubject(context.getString(R.string.share_file_name)) |
||||
.setStream(uri) |
||||
.setChooserTitle(context.getString(R.string.share_title)) |
||||
.createChooserIntent() |
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) |
||||
|
||||
context.startActivity(shareIntent) |
||||
*/ |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,15 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_1" /> |
||||
|
||||
<stroke |
||||
android:color="@color/gray" |
||||
android:width="1dp" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_2" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_3" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_4" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_5" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_6" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_7" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_8" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<solid android:color="@color/player_color_9" /> |
||||
|
||||
<size |
||||
android:width="48dp" |
||||
android:height="48dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,12 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="oval"> |
||||
|
||||
<stroke android:color="@color/kaki" |
||||
android:width="1dp"/> |
||||
|
||||
<size |
||||
android:width="96dp" |
||||
android:height="96dp" /> |
||||
|
||||
</shape> |
||||
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24" |
||||
android:viewportHeight="24"> |
||||
<path |
||||
android:fillColor="#FFFFFFFF" |
||||
android:pathData="M9,13.75c-2.34,0 -7,1.17 -7,3.5L2,19h14v-1.75c0,-2.33 -4.66,-3.5 -7,-3.5zM4.34,17c0.84,-0.58 2.87,-1.25 4.66,-1.25s3.82,0.67 4.66,1.25L4.34,17zM9,12c1.93,0 3.5,-1.57 3.5,-3.5S10.93,5 9,5 5.5,6.57 5.5,8.5 7.07,12 9,12zM9,7c0.83,0 1.5,0.67 1.5,1.5S9.83,10 9,10s-1.5,-0.67 -1.5,-1.5S8.17,7 9,7zM16.04,13.81c1.16,0.84 1.96,1.96 1.96,3.44L18,19h4v-1.75c0,-2.02 -3.5,-3.17 -5.96,-3.44zM15,12c1.93,0 3.5,-1.57 3.5,-3.5S16.93,5 15,5c-0.54,0 -1.04,0.13 -1.5,0.35 0.63,0.89 1,1.98 1,3.15s-0.37,2.26 -1,3.15c0.46,0.22 0.96,0.35 1.5,0.35z"/> |
||||
</vector> |
||||
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24" |
||||
android:viewportHeight="24"> |
||||
<path |
||||
android:fillColor="#FFFFFFFF" |
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/> |
||||
</vector> |
||||
@ -0,0 +1,136 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
||||
|
||||
<androidx.cardview.widget.CardView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="center" |
||||
app:cardCornerRadius="8dp" |
||||
app:cardBackgroundColor="@color/white"> |
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="8dp"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color1" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_1" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color2" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_2" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintStart_toEndOf="@+id/color1" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color3" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:layout_marginEnd="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_3" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toEndOf="@+id/color2" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color4" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_4" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/color1" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color5" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_5" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintStart_toEndOf="@+id/color4" |
||||
app:layout_constraintTop_toBottomOf="@+id/color2" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color6" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:layout_marginEnd="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_6" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toEndOf="@+id/color5" |
||||
app:layout_constraintTop_toBottomOf="@+id/color2" /> |
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color7" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:layout_marginBottom="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_7" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/color4" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color8" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:layout_marginBottom="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_8" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintStart_toEndOf="@+id/color4" |
||||
app:layout_constraintTop_toBottomOf="@+id/color5" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/color9" |
||||
android:layout_width="@dimen/color_picker_circle_size" |
||||
android:layout_height="@dimen/color_picker_circle_size" |
||||
android:layout_marginStart="@dimen/color_picker_circle_margin" |
||||
android:layout_marginTop="@dimen/color_picker_circle_margin" |
||||
android:layout_marginEnd="@dimen/color_picker_circle_margin" |
||||
android:layout_marginBottom="@dimen/color_picker_circle_margin" |
||||
android:background="@drawable/circle_player_color_9" |
||||
android:foreground="?selectableItemBackgroundBorderless" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toEndOf="@+id/color8" |
||||
app:layout_constraintTop_toBottomOf="@+id/color6" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
|
||||
</androidx.cardview.widget.CardView> |
||||
|
||||
</FrameLayout> |
||||
@ -0,0 +1,80 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:animateLayoutChanges="true"> |
||||
|
||||
<com.google.android.material.appbar.AppBarLayout |
||||
android:id="@+id/appBar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:theme="@style/PokerAnalyticsTheme.Toolbar.Session" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent"> |
||||
|
||||
<androidx.appcompat.widget.Toolbar |
||||
android:id="@+id/toolbar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="?attr/actionBarSize" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" |
||||
app:title="@string/player" /> |
||||
|
||||
</com.google.android.material.appbar.AppBarLayout> |
||||
|
||||
<androidx.core.widget.NestedScrollView |
||||
android:id="@+id/nestedScrollView" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:fillViewport="true" |
||||
android:paddingBottom="56dp" |
||||
android:clipToPadding="false" |
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"> |
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<androidx.recyclerview.widget.RecyclerView |
||||
android:id="@+id/recyclerView" |
||||
android:layout_width="0dp" |
||||
android:layout_height="0dp" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
|
||||
</androidx.core.widget.NestedScrollView> |
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar |
||||
android:id="@+id/bottomBar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="bottom" |
||||
app:layout_constraintBottom_toBottomOf="@+id/recyclerView" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent"> |
||||
|
||||
<FrameLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatButton |
||||
android:id="@+id/addComment" |
||||
style="@style/PokerAnalyticsTheme.Button.Borderless" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_gravity="end" |
||||
android:text="@string/add_comment" /> |
||||
|
||||
</FrameLayout> |
||||
|
||||
</com.google.android.material.bottomappbar.BottomAppBar> |
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
||||
@ -0,0 +1,47 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<include layout="@layout/layout_swipe_to_delete" /> |
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout |
||||
android:id="@+id/foreground" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:background="@color/gray_dark" |
||||
android:foreground="?selectableItemBackground"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/title" |
||||
style="@style/PokerAnalyticsTheme.TextView.RowContent" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="4dp" |
||||
android:layout_marginBottom="4dp" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="@+id/guidelineEnd" |
||||
app:layout_constraintStart_toStartOf="@+id/guidelineStart" |
||||
app:layout_constraintTop_toTopOf="parent" |
||||
tools:text="Data Type Title\nThis is a multilines textView" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineStart" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_begin="16dp" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineEnd" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_end="16dp" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
|
||||
</FrameLayout> |
||||
@ -0,0 +1,18 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/title" |
||||
style="@style/PokerAnalyticsTheme.TextView.Header.Subtitle" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginStart="16dp" |
||||
android:layout_marginTop="8dp" |
||||
android:layout_marginBottom="4dp" |
||||
tools:text="Header" /> |
||||
|
||||
</LinearLayout> |
||||
@ -0,0 +1,91 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<include layout="@layout/layout_swipe_to_delete" /> |
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout |
||||
android:id="@+id/foreground" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="@color/gray_dark" |
||||
android:foreground="?selectableItemBackground"> |
||||
|
||||
<net.pokeranalytics.android.ui.view.PlayerImageView |
||||
android:id="@+id/playerImage" |
||||
android:layout_width="48dp" |
||||
android:layout_height="48dp" |
||||
android:layout_marginTop="8dp" |
||||
android:background="@android:color/transparent" |
||||
app:layout_constraintStart_toStartOf="@id/guidelineStart" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginStart="16dp" |
||||
android:layout_marginTop="8dp" |
||||
android:layout_marginEnd="8dp" |
||||
android:layout_marginBottom="8dp" |
||||
android:gravity="center_vertical" |
||||
android:minHeight="48dp" |
||||
android:orientation="vertical" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toStartOf="@+id/nextArrow" |
||||
app:layout_constraintStart_toEndOf="@+id/playerImage" |
||||
app:layout_constraintTop_toTopOf="parent"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/playerName" |
||||
style="@style/PokerAnalyticsTheme.TextView.RowTitle" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:ellipsize="end" |
||||
android:lines="1" |
||||
tools:text="John Smith" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/playerSummary" |
||||
style="@style/PokerAnalyticsTheme.TextView" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="2dp" |
||||
android:ellipsize="end" |
||||
android:maxLines="3" |
||||
android:textColor="@color/kaki_lighter" |
||||
android:visibility="visible" |
||||
tools:text="Summary" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/nextArrow" |
||||
android:layout_width="24dp" |
||||
android:layout_height="24dp" |
||||
android:src="@drawable/ic_arrow_right" |
||||
android:tint="@color/gray_light" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="@+id/guidelineEnd" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineStart" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_begin="16dp" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineEnd" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_end="8dp" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
|
||||
</FrameLayout> |
||||
@ -0,0 +1,20 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="@color/gray_dark" |
||||
android:foreground="?selectableItemBackground"> |
||||
|
||||
<net.pokeranalytics.android.ui.view.PlayerImageView |
||||
android:id="@+id/playerImageView" |
||||
android:layout_width="128dp" |
||||
android:layout_height="128dp" |
||||
android:layout_margin="16dp" |
||||
android:background="@android:color/transparent" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
@ -0,0 +1,47 @@ |
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="?selectableItemBackground"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/title" |
||||
style="@style/PokerAnalyticsTheme.TextView.RowTitle" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="8dp" |
||||
android:layout_marginEnd="8dp" |
||||
app:layout_constraintEnd_toStartOf="@+id/guidelineEnd" |
||||
app:layout_constraintStart_toStartOf="@+id/guidelineStart" |
||||
app:layout_constraintTop_toTopOf="parent" |
||||
tools:text="Title" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/value" |
||||
style="@style/PokerAnalyticsTheme.TextView.RowValueMultilines" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginBottom="8dp" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="@+id/guidelineEnd" |
||||
app:layout_constraintStart_toStartOf="@+id/guidelineStart" |
||||
app:layout_constraintTop_toBottomOf="@+id/title" |
||||
tools:text="Value" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineStart" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_begin="16dp" /> |
||||
|
||||
<androidx.constraintlayout.widget.Guideline |
||||
android:id="@+id/guidelineEnd" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
app:layout_constraintGuide_end="16dp" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
@ -0,0 +1,55 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="@android:color/transparent"> |
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView |
||||
android:id="@+id/playerInitial" |
||||
style="@style/PokerAnalyticsTheme.TextView.Player" |
||||
android:layout_width="0dp" |
||||
android:layout_height="0dp" |
||||
app:layout_constraintDimensionRatio="1:1" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" |
||||
tools:text="AH" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/playerImage" |
||||
android:layout_width="0dp" |
||||
android:layout_height="0dp" |
||||
app:layout_constraintDimensionRatio="1:1" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView |
||||
android:id="@+id/playerStroke" |
||||
android:layout_width="0dp" |
||||
android:layout_height="0dp" |
||||
app:layout_constraintDimensionRatio="1:1" |
||||
android:background="@drawable/circle_stroke_kaki" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<View |
||||
android:id="@+id/playerImageSelection" |
||||
android:layout_width="0dp" |
||||
android:layout_height="0dp" |
||||
app:layout_constraintWidth_percent="0.7" |
||||
app:layout_constraintHeight_percent="0.7" |
||||
android:background="?selectableItemBackgroundBorderless" |
||||
android:elevation="16dp" |
||||
app:layout_constraintBottom_toBottomOf="parent" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
||||
@ -0,0 +1,13 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto"> |
||||
|
||||
<item |
||||
android:id="@+id/action_search" |
||||
android:icon="@drawable/ic_outline_search" |
||||
app:showAsAction="always|collapseActionView" |
||||
app:actionViewClass="androidx.appcompat.widget.SearchView" |
||||
android:title="@android:string/search_go" |
||||
android:visible="false"/> |
||||
|
||||
</menu> |
||||
@ -1,6 +1,11 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<files-path |
||||
name="files" |
||||
path="." /> |
||||
<files-path |
||||
name="files" |
||||
path="." /> |
||||
|
||||
<external-path |
||||
name="external_files" |
||||
path="." /> |
||||
|
||||
</paths> |
||||
Loading…
Reference in new issue