diff --git a/app/build.gradle b/app/build.gradle index 9384d02..4dbb44d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,13 +11,14 @@ android { 'LICENSE.txt', 'NOTICE.txt', 'README.txt', '.readme'] defaultConfig { applicationId "com.ediposouza.teslesgendstracker" - minSdkVersion prepareRelease ? 16 : 21 + minSdkVersion prepareToRelease ? 16 : 21 targetSdkVersion 25 versionCode appVersionCode versionName appVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" buildConfigField("boolean", "ENABLE_LOGS_IN_RELEASE", "false") + buildConfigField("boolean", "PREPARE_TO_RELEASE", "$prepareToRelease") buildConfigField("String", "MIXPANEL_TOKEN", '"eb99af1dad563cbaaf02f008b28e321f"') buildConfigField("String", "GCM_SENDER", '"597127048287"') vectorDrawables.useSupportLibrary true @@ -58,7 +59,7 @@ ext { icePickVersion = "3.2.+" okIOVersion = "1.10.+" okHttpVersion = "3.4.+" - playServicesVersion = prepareRelease ? "10.0.1" : "9.8.0" + playServicesVersion = prepareToRelease ? "10.0.1" : "9.8.0" supportLibraryVersion = "25.1.0" threetenabpVersion = "1.0.+" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 10e00e6..356cc85 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -17,7 +17,7 @@ #} ## TES Legends Tracker --keepclassmembers class com.ediposouza.teslesgendstracker.interactor.*Parser { *; } +-keepclassmembers class com.ediposouza.teslesgendstracker.interactor.FirebaseParsers$* { *; } ## Kotlin -dontwarn kotlin.** diff --git a/app/src/debug/java/com/ediposouza/teslesgendstracker/manager/LoggerManager.kt b/app/src/debug/java/com/ediposouza/teslesgendstracker/util/LoggerManager.kt similarity index 88% rename from app/src/debug/java/com/ediposouza/teslesgendstracker/manager/LoggerManager.kt rename to app/src/debug/java/com/ediposouza/teslesgendstracker/util/LoggerManager.kt index 485987a..a9b4804 100644 --- a/app/src/debug/java/com/ediposouza/teslesgendstracker/manager/LoggerManager.kt +++ b/app/src/debug/java/com/ediposouza/teslesgendstracker/util/LoggerManager.kt @@ -1,4 +1,4 @@ -package com.ediposouza.teslesgendstracker.manager +package com.ediposouza.teslesgendstracker.util import timber.log.Timber diff --git a/app/src/debug/java/com/ediposouza/teslesgendstracker/manager/MetricsManager.kt b/app/src/debug/java/com/ediposouza/teslesgendstracker/util/MetricsManager.kt similarity index 81% rename from app/src/debug/java/com/ediposouza/teslesgendstracker/manager/MetricsManager.kt rename to app/src/debug/java/com/ediposouza/teslesgendstracker/util/MetricsManager.kt index 390e2ff..1f0e2c6 100644 --- a/app/src/debug/java/com/ediposouza/teslesgendstracker/manager/MetricsManager.kt +++ b/app/src/debug/java/com/ediposouza/teslesgendstracker/util/MetricsManager.kt @@ -1,9 +1,6 @@ -package com.ediposouza.teslesgendstracker.manager +package com.ediposouza.teslesgendstracker.util import android.content.Context -import com.ediposouza.teslesgendstracker.MetricAction -import com.ediposouza.teslesgendstracker.MetricScreen -import com.ediposouza.teslesgendstracker.MetricsConstants import com.ediposouza.teslesgendstracker.data.Card import com.google.firebase.auth.FirebaseUser import timber.log.Timber diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1112fcd..5adb704 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,7 +40,8 @@ android:screenOrientation="portrait" /> + android:screenOrientation="portrait" + android:windowSoftInputMode="adjustPan" /> + + + + - \ No newline at end of file diff --git a/app/src/main/assets/Cards/Core/Intelligence/battlereeveofdusk.png b/app/src/main/assets/Cards/Core/Intelligence/battlereeveofdusk.png new file mode 100644 index 0000000..3b7e379 Binary files /dev/null and b/app/src/main/assets/Cards/Core/Intelligence/battlereeveofdusk.png differ diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/App.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/App.kt index 49d93e0..bdb2969 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/App.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/App.kt @@ -1,10 +1,13 @@ package com.ediposouza.teslesgendstracker import android.app.Application +import android.content.Context import android.support.v7.app.AppCompatDelegate import com.ediposouza.teslesgendstracker.interactor.BaseInteractor -import com.ediposouza.teslesgendstracker.manager.LoggerManager -import com.ediposouza.teslesgendstracker.manager.MetricsManager +import com.ediposouza.teslesgendstracker.util.ConfigManager +import com.ediposouza.teslesgendstracker.util.LoggerManager +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.google.firebase.auth.FirebaseAuth import com.google.firebase.database.FirebaseDatabase import com.jakewharton.threetenabp.AndroidThreeTen import timber.log.Timber @@ -16,24 +19,35 @@ class App : Application() { companion object { - var hasUserLogged: Boolean = false + private var ctx: Context? = null + + var hasUserAlreadyLogged: Boolean = false + + fun hasUserLogged(): Boolean = FirebaseAuth.getInstance().currentUser != null + + fun getVersion() = ctx?.packageManager?.getPackageInfo(ctx?.packageName, 0)?.versionName ?: "" } override fun onCreate() { super.onCreate() + ctx = applicationContext AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) initializeDependencies() } private fun initializeDependencies() { + Timber.plant(LoggerManager()) MetricsManager.initialize(this) AndroidThreeTen.init(this) FirebaseDatabase.getInstance().apply { setPersistenceEnabled(true) - reference.child(BaseInteractor.NODE_CARDS).keepSynced(true) + ConfigManager.updateCaches { + val sync = !ConfigManager.isDBUpdating() && !ConfigManager.isVersionUnsupported() + reference.child(BaseInteractor.NODE_CARDS).keepSynced(sync) + reference.child(BaseInteractor.NODE_PATCHES).keepSynced(sync) + } } - Timber.plant(LoggerManager()) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/Constants.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/Constants.kt index 9342cff..6bc848e 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/Constants.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/Constants.kt @@ -3,4 +3,6 @@ package com.ediposouza.teslesgendstracker /** * Created by EdipoSouza on 11/15/16. */ -val TIME_PATTERN = "HH:mm" \ No newline at end of file +val TIME_PATTERN = "HH:mm" + +val DEFAULT_DELIMITER = ";" \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Card.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Card.kt index 465ab6a..81cdb3d 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Card.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Card.kt @@ -30,15 +30,15 @@ enum class CardSet(val db: String) { } -enum class Attribute(val color: Int, @IntegerRes val imageRes: Int) { +enum class Attribute(@IntegerRes val imageRes: Int) { - STRENGTH(Color.RED, R.drawable.attr_strength), - INTELLIGENCE(Color.BLUE, R.drawable.attr_intelligence), - WILLPOWER(Color.YELLOW, R.drawable.attr_willpower), - AGILITY(Color.GREEN, R.drawable.attr_agility), - ENDURANCE(Color.parseColor("purple"), R.drawable.attr_endurance), - NEUTRAL(Color.GRAY, R.drawable.attr_neutral), - DUAL(Color.LTGRAY, R.drawable.attr_dual) + STRENGTH(R.drawable.attr_strength), + INTELLIGENCE(R.drawable.attr_intelligence), + WILLPOWER(R.drawable.attr_willpower), + AGILITY(R.drawable.attr_agility), + ENDURANCE(R.drawable.attr_endurance), + NEUTRAL(R.drawable.attr_neutral), + DUAL(R.drawable.attr_dual) } @@ -90,7 +90,7 @@ enum class CardRarity(val color: Int, val soulCost: Int, @IntegerRes val imageRe } -enum class CardType() { +enum class CardType { ACTION, CREATURE, @@ -175,7 +175,7 @@ enum class CardRace(val desc: String) { } } -enum class CardKeyword() { +enum class CardKeyword { ACTIVATE, BREAKTHROUGH, @@ -205,7 +205,7 @@ enum class CardKeyword() { } } -enum class CardArenaTier() { +enum class CardArenaTier { TERRIBLE, POOR, @@ -231,7 +231,7 @@ data class CardMissing( val shortName: String, val rarity: CardRarity, - val qtd: Long + val qtd: Int ) @@ -262,7 +262,7 @@ data class Card( val arenaTier: CardArenaTier, val evolves: Boolean -) : Parcelable { +) : Comparable, Parcelable { private val CARD_BACK = "card_back.png" private val CARD_PATH = "Cards" @@ -314,4 +314,9 @@ data class Card( dest?.writeInt(arenaTier.ordinal) dest?.writeInt((if (evolves) 1 else 0)) } + + override fun compareTo(other: Card): Int { + val compareCost = cost.compareTo(other.cost) + return if (compareCost != 0) compareCost else name.compareTo(other.name) + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Deck.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Deck.kt index 4e2f084..94fd63f 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Deck.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/Deck.kt @@ -5,7 +5,7 @@ import android.os.Parcelable import org.threeten.bp.LocalDateTime import java.util.* -enum class DeckType() { +enum class DeckType { AGGRO, ARENA, @@ -82,7 +82,7 @@ data class Deck( val patch: String, val likes: List, val views: Int, - val cards: Map, + val cards: Map, val updates: List, val comments: List @@ -102,7 +102,7 @@ data class Deck( 1 == source.readInt(), DeckType.values()[source.readInt()], Class.values()[source.readInt()], source.readInt(), source.readSerializable() as LocalDateTime, source.readSerializable() as LocalDateTime, source.readString(), source.createStringArrayList(), source.readInt(), - hashMapOf().apply { source.readMap(this, Long::class.java.classLoader) }, + hashMapOf().apply { source.readMap(this, Int::class.java.classLoader) }, ArrayList().apply { source.readList(this, DeckUpdate::class.java.classLoader) }, ArrayList().apply { source.readList(this, DeckComment::class.java.classLoader) }) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/General.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/General.kt index 25bfa21..88cf258 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/General.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/data/General.kt @@ -1,14 +1,37 @@ package com.ediposouza.teslesgendstracker.data +import android.os.Parcel +import android.os.Parcelable + /** * Created by EdipoSouza on 10/31/16. */ data class CardSlot( val card: Card, - val qtd: Long + val qtd: Int + +) : Comparable, Parcelable { + + companion object { + @JvmField val CREATOR: Parcelable.Creator = object : Parcelable.Creator { + override fun createFromParcel(source: Parcel): CardSlot = CardSlot(source) + override fun newArray(size: Int): Array = arrayOfNulls(size) + } + } + + constructor(source: Parcel) : this(source.readParcelable(Card::class.java.classLoader), + source.readInt()) + + override fun compareTo(other: CardSlot): Int = card.compareTo(other.card) + + override fun describeContents() = 0 -) + override fun writeToParcel(dest: Parcel?, flags: Int) { + dest?.writeParcelable(card, 0) + dest?.writeInt(qtd) + } +} data class Patch( diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/BaseInteractor.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/BaseInteractor.kt index aae2355..bfb5639 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/BaseInteractor.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/BaseInteractor.kt @@ -2,16 +2,20 @@ package com.ediposouza.teslesgendstracker.interactor import com.ediposouza.teslesgendstracker.data.Attribute import com.ediposouza.teslesgendstracker.data.CardSet +import com.ediposouza.teslesgendstracker.util.ConfigManager +import com.google.firebase.database.DatabaseReference import com.google.firebase.database.FirebaseDatabase +import com.google.firebase.database.Query /** * Created by ediposouza on 01/11/16. */ -open class BaseInteractor() { +open class BaseInteractor { companion object { val NODE_CARDS = "cards" + val NODE_PATCHES = "patches" } @@ -26,11 +30,9 @@ open class BaseInteractor() { protected val KEY_DECK_CLASS = "cls" protected val KEY_DECK_UPDATE_AT = "updatedAt" - protected val database by lazy { FirebaseDatabase.getInstance().reference } - - protected val dbDecks by lazy { database.child(NODE_DECKS) } - - protected val dbUsers by lazy { database.child(NODE_USERS) } + protected val database: DatabaseReference by lazy { FirebaseDatabase.getInstance().reference } + protected val dbDecks: DatabaseReference by lazy { database.child(NODE_DECKS) } + protected val dbUsers: DatabaseReference by lazy { database.child(NODE_USERS) } fun getListFromSets(set: CardSet?, onSuccess: (List) -> Unit, getFromSet: (set: CardSet, onSuccess: (List) -> Unit) -> Unit) { @@ -88,4 +90,8 @@ open class BaseInteractor() { getFromSet(CardSet.values()[setIndex], attr, getSetsOnSuccess(attr, onSuccess)) } + fun Query.keepSynced() { + keepSynced(!ConfigManager.isDBUpdating() && !ConfigManager.isVersionUnsupported()) + } + } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/FirebaseParsers.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/FirebaseParsers.kt index 0ade3fc..e5a18f2 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/FirebaseParsers.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/FirebaseParsers.kt @@ -1,118 +1,121 @@ package com.ediposouza.teslesgendstracker.interactor import com.ediposouza.teslesgendstracker.data.* -import com.ediposouza.teslesgendstracker.toIntSafely +import com.ediposouza.teslesgendstracker.util.toIntSafely import org.threeten.bp.LocalDateTime -class CardParser() { - - val name: String = "" - val rarity: String = "" - val unique: Boolean = false - val cost: String = "" - val attack: String = "" - val health: String = "" - val type: String = "" - val race: String = CardRace.NONE.name - val keyword: String = "" - val arenaTier: String = CardArenaTier.NONE.name - val evolves: Boolean = false - val attr1: String = "" - val attr2: String = "" - - fun toCard(shortName: String, set: CardSet, attr: Attribute): Card { - var clsAttr1 = attr - var clsAttr2 = attr - if (attr == Attribute.DUAL) { - clsAttr1 = Attribute.valueOf(attr1.trim().toUpperCase()) - clsAttr2 = Attribute.valueOf(attr2.trim().toUpperCase()) +abstract class FirebaseParsers { + + class CardParser { + + val name: String = "" + val rarity: String = "" + val unique: Boolean = false + val cost: String = "" + val attack: String = "" + val health: String = "" + val type: String = "" + val race: String = CardRace.NONE.name + val keyword: String = "" + val arenaTier: String = CardArenaTier.NONE.name + val evolves: Boolean = false + val attr1: String = "" + val attr2: String = "" + + fun toCard(shortName: String, set: CardSet, attr: Attribute): Card { + var clsAttr1 = attr + var clsAttr2 = attr + if (attr == Attribute.DUAL) { + clsAttr1 = Attribute.valueOf(attr1.trim().toUpperCase()) + clsAttr2 = Attribute.valueOf(attr2.trim().toUpperCase()) + } + return Card(name, shortName, set, attr, clsAttr1, clsAttr2, CardRarity.of(rarity), unique, + cost.toIntSafely(), attack.toIntSafely(), health.toIntSafely(), + CardType.of(type), CardRace.of(race), + keyword.split(",") + .filter { it.trim().isNotEmpty() } + .mapTo(arrayListOf()) { + CardKeyword.of(it) + }, + CardArenaTier.of(arenaTier), + evolves) + } + + fun toCardStatistic(shortName: String): CardStatistic { + return CardStatistic(shortName, CardRarity.valueOf(rarity.trim().toUpperCase()), unique) } - return Card(name, shortName, set, attr, clsAttr1, clsAttr2, CardRarity.of(rarity), unique, - cost.toIntSafely(), attack.toIntSafely(), health.toIntSafely(), - CardType.of(type), CardRace.of(race), - keyword.split(",") - .filter { it.trim().isNotEmpty() } - .mapTo(arrayListOf()) { - CardKeyword.of(it) - }, - CardArenaTier.of(arenaTier), - evolves) - } - fun toCardStatistic(shortName: String): CardStatistic { - return CardStatistic(shortName, CardRarity.valueOf(rarity.trim().toUpperCase()), unique) } -} + class DeckParser( + val name: String = "", + val type: Int = 0, + val cls: Int = 0, + val cost: Int = 0, + val owner: String = "", + val createdAt: String = "", + val updatedAt: String = "", + val patch: String = "", + val views: Int = 0, + val likes: List = listOf(), + val cards: Map = mapOf(), + val updates: Map> = mapOf(), + val comments: Map> = mapOf() + ) { + + companion object { + + private val KEY_DECK_NAME = "owner" + private val KEY_DECK_TYPE = "type" + private val KEY_DECK_CLASS = "cls" + private val KEY_DECK_PATCH = "patch" + private val KEY_DECK_COMMENT_OWNER = "owner" + private val KEY_DECK_COMMENT_MSG = "comment" + private val KEY_DECK_COMMENT_CREATE_AT = "createdAt" + + fun toNewCommentMap(owner: String, comment: String): Map { + return mapOf(KEY_DECK_COMMENT_OWNER to owner, KEY_DECK_COMMENT_MSG to comment, + KEY_DECK_COMMENT_CREATE_AT to LocalDateTime.now().toString()) + } -class DeckParser( - val name: String = "", - val type: Int = 0, - val cls: Int = 0, - val cost: Int = 0, - val owner: String = "", - val createdAt: String = "", - val updatedAt: String = "", - val patch: String = "", - val views: Int = 0, - val likes: List = listOf(), - val cards: Map = mapOf(), - val updates: Map> = mapOf(), - val comments: Map> = mapOf() -) { - - companion object { - - private val KEY_DECK_NAME = "owner" - private val KEY_DECK_TYPE = "type" - private val KEY_DECK_CLASS = "cls" - private val KEY_DECK_PATCH = "patch" - private val KEY_DECK_COMMENT_OWNER = "owner" - private val KEY_DECK_COMMENT_MSG = "comment" - private val KEY_DECK_COMMENT_CREATE_AT = "createdAt" - - fun toNewCommentMap(owner: String, comment: String): Map { - return mapOf(KEY_DECK_COMMENT_OWNER to owner, KEY_DECK_COMMENT_MSG to comment, - KEY_DECK_COMMENT_CREATE_AT to LocalDateTime.now().toString()) } - } + fun toDeck(id: String, private: Boolean): Deck { + return Deck(id, name, owner, private, DeckType.values()[type], Class.values()[cls], cost, + LocalDateTime.parse(createdAt), LocalDateTime.parse(updatedAt), patch, likes, views, cards, + updates.map { DeckUpdate(LocalDateTime.parse(it.key), it.value) }, + comments.map { + DeckComment(it.key, it.value[KEY_DECK_COMMENT_OWNER] as String, + it.value[KEY_DECK_COMMENT_MSG] as String, + LocalDateTime.parse(it.value[KEY_DECK_COMMENT_CREATE_AT] as String)) + }) + } - fun toDeck(id: String, private: Boolean): Deck { - return Deck(id, name, owner, private, DeckType.values()[type], Class.values()[cls], cost, - LocalDateTime.parse(createdAt), LocalDateTime.parse(updatedAt), patch, likes, views, cards, - updates.map { DeckUpdate(LocalDateTime.parse(it.key), it.value) }, - comments.map { - DeckComment(it.key, it.value[KEY_DECK_COMMENT_OWNER] as String, - it.value[KEY_DECK_COMMENT_MSG] as String, - LocalDateTime.parse(it.value[KEY_DECK_COMMENT_CREATE_AT] as String)) - }) - } + fun fromDeck(deck: Deck): DeckParser { + return DeckParser(deck.name, deck.type.ordinal, deck.cls.ordinal, deck.cost, deck.owner, + deck.createdAt.toString(), deck.updatedAt.toString(), deck.patch, deck.views, + deck.likes, deck.cards, deck.updates.map { it.date.toString() to it.changes }.toMap(), + deck.comments.map { + it.id to mapOf( + KEY_DECK_COMMENT_OWNER to it.owner, + KEY_DECK_COMMENT_MSG to it.comment, + KEY_DECK_COMMENT_CREATE_AT to it.date.toString()) + }.toMap()) + } - fun fromDeck(deck: Deck): DeckParser { - return DeckParser(deck.name, deck.type.ordinal, deck.cls.ordinal, deck.cost, deck.owner, - deck.createdAt.toString(), deck.updatedAt.toString(), deck.patch, deck.views, - deck.likes, deck.cards, deck.updates.map { it.date.toString() to it.changes }.toMap(), - deck.comments.map { - it.id to mapOf( - KEY_DECK_COMMENT_OWNER to it.owner, - KEY_DECK_COMMENT_MSG to it.comment, - KEY_DECK_COMMENT_CREATE_AT to it.date.toString()) - }.toMap()) - } + fun toDeckUpdateMap(): Map { + return mapOf(KEY_DECK_NAME to name, KEY_DECK_TYPE to type, KEY_DECK_CLASS to cls, KEY_DECK_PATCH to patch) + } - fun toDeckUpdateMap(): Map { - return mapOf(KEY_DECK_NAME to name, KEY_DECK_TYPE to type, KEY_DECK_CLASS to cls, KEY_DECK_PATCH to patch) } -} + class PatchParser { -class PatchParser() { + val desc: String = "" - val desc: String = "" + fun toPatch(uidDate: String): Patch { + return Patch(uidDate, desc) + } - fun toPatch(uidDate: String): Patch { - return Patch(uidDate, desc) } - -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PrivateInteractor.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PrivateInteractor.kt index 4f778e4..a1574db 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PrivateInteractor.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PrivateInteractor.kt @@ -2,6 +2,7 @@ package com.ediposouza.teslesgendstracker.interactor import com.ediposouza.teslesgendstracker.data.* import com.ediposouza.teslesgendstracker.ui.base.CmdShowSnackbarMsg +import com.ediposouza.teslesgendstracker.util.ConfigManager import com.google.firebase.auth.FirebaseAuth import com.google.firebase.database.DataSnapshot import com.google.firebase.database.DatabaseError @@ -15,7 +16,7 @@ import java.util.* /** * Created by ediposouza on 01/11/16. */ -class PrivateInteractor() : BaseInteractor() { +class PrivateInteractor : BaseInteractor() { private val NODE_DECKS_PRIVATE = "private" private val NODE_FAVORITE = "favorite" @@ -23,7 +24,6 @@ class PrivateInteractor() : BaseInteractor() { private val KEY_CARD_FAVORITE = "favorite" private val KEY_CARD_QTD = "qtd" - private val KEY_DECK_RARITY = "rarity" private val KEY_DECK_OWNER = "owner" private val KEY_DECK_LIKES = "likes" private val KEY_DECK_COST = "cost" @@ -35,12 +35,13 @@ class PrivateInteractor() : BaseInteractor() { } private fun dbUser(): DatabaseReference? { - return if (getUserID().isNotEmpty()) dbUsers.child(getUserID()) else null + val userID = getUserID() + return if (userID.isEmpty() || ConfigManager.isDBUpdating()) null else dbUsers.child(userID) } private fun dbUserCards(set: CardSet, cls: Attribute): DatabaseReference? { val dbRef = dbUser()?.child(NODE_CARDS)?.child(set.db)?.child(cls.name.toLowerCase()) - dbRef?.keepSynced(true) + dbRef?.keepSynced() return dbRef } @@ -52,7 +53,7 @@ class PrivateInteractor() : BaseInteractor() { } } - fun setUserCardQtd(card: Card, qtd: Long, onComplete: () -> Unit) { + fun setUserCardQtd(card: Card, qtd: Int, onComplete: () -> Unit) { dbUserCards(card.set, card.attr)?.apply { child(card.shortName).child(KEY_CARD_QTD).setValue(qtd).addOnCompleteListener { onComplete.invoke() @@ -72,7 +73,7 @@ class PrivateInteractor() : BaseInteractor() { } } - fun getUserCollection(set: CardSet?, onSuccess: (Map) -> Unit) { + fun getUserCollection(set: CardSet?, onSuccess: (Map) -> Unit) { getMapFromSets(set, onSuccess) { set, onEachSuccess -> dbUser()?.child(NODE_CARDS)?.child(set.db)?.addListenerForSingleValueEvent(object : ValueEventListener { @@ -80,7 +81,7 @@ class PrivateInteractor() : BaseInteractor() { override fun onDataChange(ds: DataSnapshot) { val collection = ds.children.flatMap { it.children } .filter { it.hasChild(KEY_CARD_QTD) } - .map({ it.key to it.child(KEY_CARD_QTD).value as Long }) + .map({ it.key to (it.child(KEY_CARD_QTD).value as Long).toInt() }) .toMap() Timber.d(collection.toString()) onEachSuccess.invoke(collection) @@ -94,7 +95,27 @@ class PrivateInteractor() : BaseInteractor() { } } - fun getUserCollection(set: CardSet?, attr: Attribute, onSuccess: (Map) -> Unit) { + fun getUserCollection(set: CardSet?, vararg attrs: Attribute, onSuccess: (Map) -> Unit) { + var attrIndex = 0 + val collection = hashMapOf() + if (attrs.size == 1) { + return getUserCollection(set, attrs[0], onSuccess) + } + + fun getUserCollectionOnSuccess(onSuccess: (Map) -> Unit): (Map) -> Unit = { + collection.putAll(it) + attrIndex = attrIndex.inc() + if (attrIndex >= attrs.size) { + onSuccess.invoke(collection) + } else { + getUserCollection(set, attrs[attrIndex], getUserCollectionOnSuccess(onSuccess)) + } + } + + getUserCollection(set, attrs[attrIndex], getUserCollectionOnSuccess(onSuccess)) + } + + private fun getUserCollection(set: CardSet?, attr: Attribute, onSuccess: (Map) -> Unit) { getMapFromSets(set, attr, onSuccess) { set, attr, onEachSuccess -> dbUserCards(set, attr)?.addListenerForSingleValueEvent(object : ValueEventListener { @@ -102,7 +123,7 @@ class PrivateInteractor() : BaseInteractor() { override fun onDataChange(ds: DataSnapshot) { val collection = ds.children .filter { it.hasChild(KEY_CARD_QTD) } - .map({ it.key to it.child(KEY_CARD_QTD).value as Long }) + .map({ it.key to (it.child(KEY_CARD_QTD).value as Long).toInt() }) .toMap() Timber.d(collection.toString()) onEachSuccess.invoke(collection) @@ -147,13 +168,13 @@ class PrivateInteractor() : BaseInteractor() { private fun getOwnedPublicDecks(cls: Class?, onSuccess: (List) -> Unit) { with(dbDecks.child(NODE_DECKS_PUBLIC).orderByChild(KEY_DECK_OWNER).equalTo(getUserID())) { - keepSynced(true) + keepSynced() addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(ds: DataSnapshot) { Timber.d(ds.value?.toString()) val decks = ds.children.mapTo(arrayListOf()) { - it.getValue(DeckParser::class.java).toDeck(it.key, false) + it.getValue(FirebaseParsers.DeckParser::class.java).toDeck(it.key, false) }.filter { cls == null || it.cls == cls } Timber.d(decks.toString()) onSuccess.invoke(decks) @@ -169,12 +190,12 @@ class PrivateInteractor() : BaseInteractor() { private fun getOwnedPrivateDecks(cls: Class?, onSuccess: (List) -> Unit) { dbUser()?.child(NODE_DECKS)?.child(NODE_DECKS_PRIVATE)?.orderByChild(KEY_DECK_UPDATE_AT)?.apply { - keepSynced(true) + keepSynced() addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(ds: DataSnapshot) { val decks = ds.children.mapTo(arrayListOf()) { - it.getValue(DeckParser::class.java).toDeck(it.key, true) + it.getValue(FirebaseParsers.DeckParser::class.java).toDeck(it.key, true) }.filter { cls == null || it.cls == cls } Timber.d(decks.toString()) onSuccess.invoke(decks) @@ -192,7 +213,7 @@ class PrivateInteractor() : BaseInteractor() { PublicInteractor().getPublicDecks(cls) { val publicDecks = it dbUser()?.child(NODE_DECKS)?.child(NODE_FAVORITE)?.apply { - keepSynced(true) + keepSynced() addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(ds: DataSnapshot) { @@ -218,39 +239,27 @@ class PrivateInteractor() : BaseInteractor() { val publicInteractor = PublicInteractor() val attr1 = deck.cls.attr1 val attr2 = deck.cls.attr2 - val cards = hashMapOf() - val userCards = hashMapOf() - publicInteractor.getCards(null, Attribute.DUAL) { - cards.putAll(it.map { it.shortName to it.rarity }) - publicInteractor.getCards(null, Attribute.NEUTRAL) { - cards.putAll(it.map { it.shortName to it.rarity }) - publicInteractor.getCards(null, attr1) { - cards.putAll(it.map { it.shortName to it.rarity }) - publicInteractor.getCards(null, attr2) { - cards.putAll(it.map { it.shortName to it.rarity }) - getUserCollection(null, attr1) { - userCards.putAll(it) - getUserCollection(null, attr2) { - userCards.putAll(it) - val missing = deck.cards.map { it.key to it.value.minus(userCards[it.key] ?: 0) } - .map { CardMissing(it.first, cards[it.first]!!, it.second) } - Timber.d(missing.toString()) - onSuccess.invoke(missing) - } - } - } - } + publicInteractor.getCards(null, attr1, attr2, Attribute.DUAL, Attribute.NEUTRAL) { + val cards = it.map { it.shortName to it.rarity }.toMap() + getUserCollection(null, attr1, attr2, Attribute.DUAL, Attribute.NEUTRAL) { + val userCards = it + val missing = deck.cards.map { it.key to it.value.minus(userCards[it.key] ?: 0) } + .filter { it.second > 0 } + .map { CardMissing(it.first, cards[it.first]!!, it.second) } + .filter { it.qtd > 0 } + Timber.d(missing.toString()) + onSuccess.invoke(missing) } } } - fun saveDeck(name: String, cls: Class, type: DeckType, cost: Int, patch: String, cards: Map, + fun saveDeck(name: String, cls: Class, type: DeckType, cost: Int, patch: String, cards: Map, private: Boolean, onError: ((e: Exception?) -> Unit)? = null, onSuccess: (uid: String) -> Unit) { dbUser()?.apply { with(if (private) child(NODE_DECKS).child(NODE_DECKS_PRIVATE) else dbDecks.child(NODE_DECKS_PUBLIC)) { val deck = Deck(push().key, name, getUserID(), private, type, cls, cost, LocalDateTime.now(), LocalDateTime.now(), patch, ArrayList(), 0, cards, ArrayList(), ArrayList()) - child(deck.id).setValue(DeckParser().fromDeck(deck)).addOnCompleteListener({ + child(deck.id).setValue(FirebaseParsers.DeckParser().fromDeck(deck)).addOnCompleteListener({ Timber.d(it.toString()) if (it.isSuccessful) onSuccess.invoke(deck.id) else { @@ -280,12 +289,12 @@ class PrivateInteractor() : BaseInteractor() { dbUser()?.apply { with(if (deck.private) child(NODE_DECKS).child(NODE_DECKS_PRIVATE) else dbDecks.child(NODE_DECKS_PUBLIC)) { if (deck.private == oldPrivate) - child(deck.id).updateChildren(DeckParser().fromDeck(deck).toDeckUpdateMap()).addOnCompleteListener({ + child(deck.id).updateChildren(FirebaseParsers.DeckParser().fromDeck(deck).toDeckUpdateMap()).addOnCompleteListener({ Timber.d(it.toString()) if (it.isSuccessful) onSuccess.invoke() else onError?.invoke(it.exception) }) else - child(deck.id).setValue(DeckParser().fromDeck(deck)).addOnCompleteListener({ + child(deck.id).setValue(FirebaseParsers.DeckParser().fromDeck(deck)).addOnCompleteListener({ Timber.d(it.toString()) deleteDeck(deck, oldPrivate, onError, onSuccess) }) @@ -332,21 +341,26 @@ class PrivateInteractor() : BaseInteractor() { } } - fun addDeckComment(deck: Deck, msg: String, onError: ((e: Exception?) -> Unit)? = null, onSuccess: () -> Unit) { + fun addDeckComment(deck: Deck, msg: String, onError: ((e: Exception?) -> Unit)? = null, + onSuccess: (comment: DeckComment) -> Unit) { dbUser()?.apply { with(if (deck.private) child(NODE_DECKS).child(NODE_DECKS_PRIVATE) else dbDecks.child(NODE_DECKS_PUBLIC)) { - val comment = DeckParser.toNewCommentMap(getUserID(), msg) + val comment = FirebaseParsers.DeckParser.toNewCommentMap(getUserID(), msg) with(child(deck.id).child(KEY_DECK_COMMENTS)) { - child(push().key).setValue(comment).addOnCompleteListener({ + val commentKey = push().key + child(commentKey).setValue(comment).addOnCompleteListener({ Timber.d(it.toString()) - if (it.isSuccessful) onSuccess.invoke() else onError?.invoke(it.exception) + if (it.isSuccessful) { + onSuccess.invoke(DeckComment(commentKey, getUserID(), msg, LocalDateTime.now())) + } else + onError?.invoke(it.exception) }) } } } } - fun remDeckComment(deck: Deck, commentId: String, msg: String, onError: ((e: Exception?) -> Unit)? = null, onSuccess: () -> Unit) { + fun remDeckComment(deck: Deck, commentId: String, onError: ((e: Exception?) -> Unit)? = null, onSuccess: () -> Unit) { dbUser()?.apply { with(if (deck.private) child(NODE_DECKS).child(NODE_DECKS_PRIVATE) else dbDecks.child(NODE_DECKS_PUBLIC)) { child(deck.id).child(KEY_DECK_COMMENTS).child(commentId).removeValue().addOnCompleteListener({ diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PublicInteractor.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PublicInteractor.kt index 0b2bdba..09f1de3 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PublicInteractor.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/interactor/PublicInteractor.kt @@ -9,15 +9,33 @@ import timber.log.Timber /** * Created by ediposouza on 01/11/16. */ -class PublicInteractor() : BaseInteractor() { - - private val NODE_PATCHES = "patches" +class PublicInteractor : BaseInteractor() { private val KEY_CARD_EVOLVES = "evolves" private val KEY_DECK_VIEWS = "views" - fun getCards(set: CardSet?, attr: Attribute, onSuccess: (List) -> Unit) { - val onFinalSuccess: (List) -> Unit = { onSuccess(it.sortedBy(Card::cost)) } + fun getCards(set: CardSet?, vararg attrs: Attribute, onSuccess: (List) -> Unit) { + var attrIndex = 0 + val cards = arrayListOf() + if (attrs.size == 1) { + return getCards(set, attrs[0], onSuccess) + } + + fun getCardsOnSuccess(onSuccess: (List) -> Unit): (List) -> Unit = { + cards.addAll(it) + attrIndex = attrIndex.inc() + if (attrIndex >= attrs.size) { + onSuccess.invoke(cards) + } else { + getCards(set, attrs[attrIndex], getCardsOnSuccess(onSuccess)) + } + } + + getCards(set, attrs[attrIndex], getCardsOnSuccess(onSuccess)) + } + + private fun getCards(set: CardSet?, attr: Attribute, onSuccess: (List) -> Unit) { + val onFinalSuccess: (List) -> Unit = { onSuccess(it.sorted()) } getListFromSets(set, attr, onFinalSuccess) { set, attr, onEachSuccess -> val node_attr = attr.name.toLowerCase() database.child(NODE_CARDS).child(set.db).child(node_attr).orderByChild(KEY_CARD_COST) @@ -25,7 +43,7 @@ class PublicInteractor() : BaseInteractor() { override fun onDataChange(ds: DataSnapshot) { val cards = ds.children.mapTo(arrayListOf()) { - it.getValue(CardParser::class.java).toCard(it.key, set, attr) + it.getValue(FirebaseParsers.CardParser::class.java).toCard(it.key, set, attr) } Timber.d(cards.toString()) onEachSuccess.invoke(cards) @@ -48,7 +66,7 @@ class PublicInteractor() : BaseInteractor() { val cards = ds.children.flatMap { it.children } .filter { !it.hasChild(KEY_CARD_EVOLVES) } .mapTo(arrayListOf()) { - it.getValue(CardParser::class.java).toCardStatistic(it.key) + it.getValue(FirebaseParsers.CardParser::class.java).toCardStatistic(it.key) } Timber.d(cards.toString()) onEachSuccess.invoke(cards) @@ -72,7 +90,7 @@ class PublicInteractor() : BaseInteractor() { val cards = ds.children .filter { !it.hasChild(KEY_CARD_EVOLVES) } .mapTo(arrayListOf()) { - it.getValue(CardParser::class.java).toCardStatistic(it.key) + it.getValue(FirebaseParsers.CardParser::class.java).toCardStatistic(it.key) } Timber.d(cards.toString()) onEachSuccess.invoke(cards) @@ -88,7 +106,7 @@ class PublicInteractor() : BaseInteractor() { fun getPublicDecks(cls: Class?, onSuccess: (List) -> Unit) { val dbPublicDeck = dbDecks.child(NODE_DECKS_PUBLIC) - dbPublicDeck.keepSynced(true) + dbPublicDeck.keepSynced() var query = dbPublicDeck.orderByChild(KEY_DECK_UPDATE_AT) if (cls != null) { query = dbPublicDeck.orderByChild(KEY_DECK_CLASS).equalTo(cls.ordinal.toDouble()) @@ -98,7 +116,7 @@ class PublicInteractor() : BaseInteractor() { override fun onDataChange(ds: DataSnapshot) { Timber.d(ds.value?.toString()) val decks = ds.children.mapTo(arrayListOf()) { - it.getValue(DeckParser::class.java).toDeck(it.key, false) + it.getValue(FirebaseParsers.DeckParser::class.java).toDeck(it.key, false) } Timber.d(decks.toString()) onSuccess.invoke(decks) @@ -111,28 +129,22 @@ class PublicInteractor() : BaseInteractor() { }) } - fun incDeckView(deck: Deck, onSuccess: () -> Unit, onError: (e: Exception?) -> Unit) { + fun incDeckView(deck: Deck, onError: ((e: Exception?) -> Unit)? = null, onSuccess: () -> Unit) { with(dbDecks.child(NODE_DECKS_PUBLIC)) { child(deck.id).updateChildren(mapOf(KEY_DECK_VIEWS to deck.views.inc())).addOnCompleteListener({ Timber.d(it.toString()) - if (it.isSuccessful) onSuccess.invoke() else onError.invoke(it.exception) + if (it.isSuccessful) onSuccess.invoke() else onError?.invoke(it.exception) }) } } fun getDeckCards(deck: Deck, onError: ((e: Exception?) -> Unit)? = null, onSuccess: (List) -> Unit) { with(database.child(NODE_CARDS)) { - val cards = arrayListOf() - getCards(null, deck.cls.attr1) { - cards.addAll(it) - getCards(null, deck.cls.attr2) { - cards.addAll(it) - val deckCards = cards - .map { CardSlot(it, deck.cards[it.shortName] ?: 0) } - .filter { it.qtd > 0 } - Timber.d(deckCards.toString()) - onSuccess(deckCards) - } + getCards(null, deck.cls.attr1, deck.cls.attr2, Attribute.DUAL, Attribute.NEUTRAL) { + val deckCards = it.map { CardSlot(it, deck.cards[it.shortName] ?: 0) } + .filter { it.qtd > 0 } + Timber.d(deckCards.toString()) + onSuccess(deckCards) } } } @@ -162,7 +174,7 @@ class PublicInteractor() : BaseInteractor() { override fun onDataChange(ds: DataSnapshot) { val patches = ds.children.mapTo(arrayListOf()) { - it.getValue(PatchParser::class.java).toPatch(it.key) + it.getValue(FirebaseParsers.PatchParser::class.java).toPatch(it.key) } Timber.d(patches.toString()) onSuccess.invoke(patches) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/CardActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/CardActivity.kt index bfbfec1..be956a9 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/CardActivity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/CardActivity.kt @@ -7,13 +7,12 @@ import android.os.Bundle import android.support.design.widget.BottomSheetBehavior import android.support.v4.app.ActivityCompat import android.view.View -import com.ediposouza.teslesgendstracker.* +import com.ediposouza.teslesgendstracker.App +import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Card import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor -import com.ediposouza.teslesgendstracker.manager.MetricsManager import com.ediposouza.teslesgendstracker.ui.base.BaseActivity -import com.ediposouza.teslesgendstracker.ui.base.CmdShowLogin -import com.ediposouza.teslesgendstracker.ui.base.CmdShowSnackbarMsg +import com.ediposouza.teslesgendstracker.util.* import kotlinx.android.synthetic.main.activity_card.* import org.jetbrains.anko.intentFor import org.jetbrains.anko.toast @@ -22,8 +21,8 @@ class CardActivity : BaseActivity() { companion object { - private val EXTRA_CARD = "card" - private val EXTRA_FAVORITE = "favorite" + private val EXTRA_CARD = "cardExtra" + private val EXTRA_FAVORITE = "favoriteExtra" fun newIntent(context: Context, card: Card, favorite: Boolean = false): Intent { return context.intentFor(EXTRA_CARD to card, EXTRA_FAVORITE to favorite) @@ -31,12 +30,13 @@ class CardActivity : BaseActivity() { } - val card by lazy { intent.getParcelableExtra(EXTRA_CARD) } + val card: Card by lazy { intent.getParcelableExtra(EXTRA_CARD) } var favorite: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_card) + snackbarNeedMargin = false favorite = intent.getBooleanExtra(EXTRA_FAVORITE, false) card_all_image.setOnClickListener { @@ -56,6 +56,11 @@ class CardActivity : BaseActivity() { ads_view.load() } + override fun onSaveInstanceState(outState: Bundle?) { + super.onSaveInstanceState(outState) + ActivityCompat.finishAfterTransition(this) + } + private fun configureBottomSheet() { val sheetBehavior = BottomSheetBehavior.from(card_bottom_sheet) sheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { @@ -72,7 +77,7 @@ class CardActivity : BaseActivity() { } }) - card_bottom_sheet.setOnClickListener { sheetBehavior.toogleExpanded() } + card_bottom_sheet.setOnClickListener { sheetBehavior.toggleExpanded() } } private fun loadCardInfo() { @@ -87,7 +92,7 @@ class CardActivity : BaseActivity() { } private fun onFavoriteClick() { - if (App.hasUserLogged) { + if (App.hasUserLogged()) { PrivateInteractor().setUserCardFavorite(card, !favorite) { favorite = !favorite MetricsManager.trackAction(if (favorite) MetricAction.ACTION_CARD_DETAILS_FAVORITE() @@ -98,8 +103,7 @@ class CardActivity : BaseActivity() { setResult(Activity.RESULT_OK, Intent()) } } else { - eventBus.post(CmdShowSnackbarMsg(CmdShowSnackbarMsg.TYPE_ERROR, R.string.error_auth) - .withAction(R.string.action_login, { eventBus.post(CmdShowLogin()) })) + showErrorUserNotLogged() } } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DashActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DashActivity.kt index ca84f83..86358df 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DashActivity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DashActivity.kt @@ -1,14 +1,10 @@ package com.ediposouza.teslesgendstracker.ui -import android.animation.Animator -import android.animation.ValueAnimator import android.os.Bundle import android.support.design.widget.BottomSheetBehavior -import android.support.design.widget.CoordinatorLayout import android.support.design.widget.NavigationView import android.support.v4.app.Fragment import android.support.v7.app.ActionBarDrawerToggle -import android.text.format.DateUtils import android.view.Gravity import android.view.MenuItem import android.view.View @@ -16,33 +12,42 @@ import com.bumptech.glide.Glide import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor -import com.ediposouza.teslesgendstracker.ui.base.BaseActivity +import com.ediposouza.teslesgendstracker.ui.base.BaseFilterActivity import com.ediposouza.teslesgendstracker.ui.base.CmdShowTabs -import com.ediposouza.teslesgendstracker.ui.base.CmdUpdateRarityMagikaFiltersVisibility import com.ediposouza.teslesgendstracker.ui.cards.CardsFragment import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterMagika import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterRarity import com.ediposouza.teslesgendstracker.ui.decks.DecksFragment -import com.ediposouza.teslesgendstracker.ui.utils.CircleTransform +import com.ediposouza.teslesgendstracker.ui.util.CircleTransform +import com.ediposouza.teslesgendstracker.ui.widget.CollectionStatistics import com.google.firebase.auth.FirebaseAuth import kotlinx.android.synthetic.main.activity_dash.* -import kotlinx.android.synthetic.main.fragment_cards.* import kotlinx.android.synthetic.main.navigation_drawer_header.view.* import org.greenrobot.eventbus.Subscribe import org.jetbrains.anko.doAsync +import org.jetbrains.anko.itemsSequence import timber.log.Timber -class DashActivity : BaseActivity(), +class DashActivity : BaseFilterActivity(), NavigationView.OnNavigationItemSelectedListener { - val publicInteractor = PublicInteractor() - val privateInteractor = PrivateInteractor() + private val KEY_MENU_ITEM_SELECTED = "menu_index_key" + + private var menuItemSelected = 0 + private val publicInteractor = PublicInteractor() + private val privateInteractor = PrivateInteractor() + + private val statisticsSheetBehavior: BottomSheetBehavior by lazy { + BottomSheetBehavior.from(cards_collection_statistics) + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_dash) - dash_filter_rarity.filterClick = { eventBus.post(CmdFilterRarity(it)) } - dash_filter_magika.filterClick = { eventBus.post(CmdFilterMagika(it)) } + snackbarNeedMargin = false + decks_fab_add.hide() + filter_rarity.filterClick = { eventBus.post(CmdFilterRarity(it)) } + filter_magika.filterClick = { eventBus.post(CmdFilterMagika(it)) } } override fun onPostCreate(savedInstanceState: Bundle?) { @@ -64,36 +69,59 @@ class DashActivity : BaseActivity(), updateCollectionStatistics() } } - BottomSheetBehavior.from(collection_statistics).state = BottomSheetBehavior.STATE_COLLAPSED + with(statisticsSheetBehavior) { + if (state == BottomSheetBehavior.STATE_EXPANDED) { + state = BottomSheetBehavior.STATE_COLLAPSED + } + } } } dash_drawer_layout.addDrawerListener(drawerToggle) dash_navigation_view.setNavigationItemSelectedListener(this) - dash_navigation_view.menu.findItem(R.id.menu_cards)?.isChecked = true drawerToggle.syncState() - supportFragmentManager.beginTransaction() - .add(R.id.dash_content, CardsFragment()) - .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out) - .commit() + if (savedInstanceState == null) { + dash_navigation_view.setCheckedItem(R.id.menu_cards) + supportFragmentManager.beginTransaction() + .add(R.id.dash_content, CardsFragment()) + .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out) + .commit() + } + } + + override fun onSaveInstanceState(outState: Bundle?) { + outState?.apply { putInt(KEY_MENU_ITEM_SELECTED, menuItemSelected) } + super.onSaveInstanceState(outState) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle?) { + super.onRestoreInstanceState(savedInstanceState) + savedInstanceState?.apply { + menuItemSelected = getInt(KEY_MENU_ITEM_SELECTED) + dash_navigation_view.setCheckedItem(menuItemSelected) + } } override fun onBackPressed() { - val statisticsBottomSheet = BottomSheetBehavior.from(collection_statistics) - if (statisticsBottomSheet.state == BottomSheetBehavior.STATE_EXPANDED) { - statisticsBottomSheet.state = BottomSheetBehavior.STATE_COLLAPSED + if (statisticsSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) { + statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED return } if (dash_drawer_layout.isDrawerOpen(Gravity.START)) { dash_drawer_layout.closeDrawer(Gravity.START) return } - super.onBackPressed() + if (canExit || !dash_navigation_view.menu.findItem(R.id.menu_cards).isChecked) { + super.onBackPressed() + } else { + showExitConfirm() + } } override fun onNavigationItemSelected(item: MenuItem): Boolean { + menuItemSelected = dash_navigation_view.menu.itemsSequence().indexOf(item) dash_drawer_layout.closeDrawer(Gravity.START) - if (dash_navigation_view.menu.findItem(item.itemId).isChecked) { + if (item.isChecked) { return true } return when (item.itemId) { @@ -109,7 +137,8 @@ class DashActivity : BaseActivity(), } } - fun showFragment(frag: Fragment): Boolean { + private fun showFragment(frag: Fragment): Boolean { + statisticsSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN supportFragmentManager.beginTransaction() .replace(R.id.dash_content, frag) .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out) @@ -132,7 +161,7 @@ class DashActivity : BaseActivity(), privateInteractor.getUserCollection(null) { userCardsTotal += it.filter { allAttrCards.map { it.shortName }.contains(it.key) - }.values.sum().toInt() + }.values.sum() Timber.d("Out: ${it.filter { !allAttrCards.map { it.shortName }.contains(it.key) }}") val stringPercent = getString(R.string.statistics_percent, if (allCardsTotal > 0) @@ -152,45 +181,7 @@ class DashActivity : BaseActivity(), @Subscribe fun onCmdShowTabs(cmdShowTabs: CmdShowTabs) { - dash_app_bar_bayout.setExpanded(true, true) - } - - @Subscribe - fun onCmdUpdateRarityMagikaFilters(update: CmdUpdateRarityMagikaFiltersVisibility) { - val filterMagikaLP = dash_filter_magika.layoutParams as CoordinatorLayout.LayoutParams - val filterRarityLP = dash_filter_rarity.layoutParams as CoordinatorLayout.LayoutParams - val showBottomMargin = resources.getDimensionPixelSize(R.dimen.large_margin) - val hideBottomMargin = -resources.getDimensionPixelSize(R.dimen.filter_hide_height) - if (update.show && filterMagikaLP.bottomMargin == showBottomMargin || - !update.show && filterMagikaLP.bottomMargin == hideBottomMargin) { - return - } - val animFrom = if (update.show) hideBottomMargin else showBottomMargin - val animTo = if (update.show) showBottomMargin else hideBottomMargin - with(ValueAnimator.ofInt(animFrom, animTo)) { - duration = DateUtils.SECOND_IN_MILLIS - addUpdateListener { - filterRarityLP.bottomMargin = it.animatedValue as Int - filterMagikaLP.bottomMargin = it.animatedValue as Int - dash_filter_magika.layoutParams = filterMagikaLP - dash_filter_rarity.layoutParams = filterRarityLP - } - addListener(object : Animator.AnimatorListener { - override fun onAnimationRepeat(p0: Animator?) { - } - - override fun onAnimationEnd(p0: Animator?) { - } - - override fun onAnimationCancel(p0: Animator?) { - } - - override fun onAnimationStart(p0: Animator?) { - } - - }) - start() - } + dash_app_bar_layout.setExpanded(true, true) } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DeckActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DeckActivity.kt index 2b19856..040e155 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DeckActivity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/DeckActivity.kt @@ -3,28 +3,43 @@ package com.ediposouza.teslesgendstracker.ui import android.app.Activity import android.content.Context import android.content.Intent +import android.graphics.Rect import android.os.Build import android.os.Bundle import android.support.design.widget.BottomSheetBehavior import android.support.design.widget.CollapsingToolbarLayout import android.support.v4.app.ActivityCompat import android.support.v4.content.ContextCompat +import android.support.v7.widget.CardView +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.text.format.DateUtils import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.ViewGroup import com.bumptech.glide.Glide -import com.ediposouza.teslesgendstracker.MetricScreen +import com.ediposouza.teslesgendstracker.App import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.TIME_PATTERN import com.ediposouza.teslesgendstracker.data.Deck +import com.ediposouza.teslesgendstracker.data.DeckComment import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor -import com.ediposouza.teslesgendstracker.manager.MetricsManager -import com.ediposouza.teslesgendstracker.toogleExpanded import com.ediposouza.teslesgendstracker.ui.base.BaseActivity -import com.ediposouza.teslesgendstracker.ui.utils.CircleTransform +import com.ediposouza.teslesgendstracker.ui.base.CmdShowSnackbarMsg +import com.ediposouza.teslesgendstracker.ui.util.CircleTransform +import com.ediposouza.teslesgendstracker.util.MetricScreen +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.ediposouza.teslesgendstracker.util.inflate +import com.ediposouza.teslesgendstracker.util.toggleExpanded +import com.google.firebase.auth.FirebaseAuth +import io.fabric.sdk.android.services.common.CommonUtils +import jp.wasabeef.recyclerview.animators.SlideInLeftAnimator import kotlinx.android.synthetic.main.activity_deck.* import kotlinx.android.synthetic.main.include_deck_info.* +import kotlinx.android.synthetic.main.itemlist_deck_comment.view.* import org.jetbrains.anko.alert import org.jetbrains.anko.doAsync import org.jetbrains.anko.intentFor @@ -32,8 +47,9 @@ import org.jetbrains.anko.toast import org.threeten.bp.format.DateTimeFormatter import timber.log.Timber import java.text.NumberFormat +import java.util.* -class DeckActivity() : BaseActivity() { +class DeckActivity : BaseActivity() { companion object { @@ -49,14 +65,16 @@ class DeckActivity() : BaseActivity() { } - val deck by lazy { intent.getParcelableExtra(EXTRA_DECK) } - val deckOwned by lazy { intent.getBooleanExtra(EXTRA_OWNED, false) } - val numberInstance by lazy { NumberFormat.getNumberInstance() } - val privateInteractor by lazy { PrivateInteractor() } + private val publicInteractor by lazy { PublicInteractor() } + private val privateInteractor by lazy { PrivateInteractor() } + private val deckOwned by lazy { intent.getBooleanExtra(EXTRA_OWNED, false) } + private val deck: Deck by lazy { intent.getParcelableExtra(EXTRA_DECK) } + private val numberInstance: NumberFormat by lazy { NumberFormat.getNumberInstance() } + private val commentsSheetBehavior: BottomSheetBehavior by lazy { BottomSheetBehavior.from(deck_bottom_sheet) } - var favorite: Boolean = false - var like: Boolean = false - var menuLike: MenuItem? = null + private var favorite: Boolean = false + private var like: Boolean = false + private var menuLike: MenuItem? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,47 +87,67 @@ class DeckActivity() : BaseActivity() { favorite = intent.getBooleanExtra(EXTRA_FAVORITE, false) like = intent.getBooleanExtra(EXTRA_LIKE, false) - val sheetBehavior = BottomSheetBehavior.from(deck_bottom_sheet) deck_fab_favorite.setOnClickListener { - privateInteractor.setUserDeckFavorite(deck, !favorite) { - favorite = !favorite - updateFavoriteItem() - setResult(Activity.RESULT_OK, Intent()) + if (App.hasUserLogged()) { + privateInteractor.setUserDeckFavorite(deck, !favorite) { + favorite = !favorite + updateFavoriteItem() + } + } else { + showErrorUserNotLogged() } } - deck_bottom_sheet.setOnClickListener { sheetBehavior.toogleExpanded() } + deck_bottom_sheet.setOnClickListener { commentsSheetBehavior.toggleExpanded() } updateFavoriteItem() loadDeckInfo() - setResult(Activity.RESULT_CANCELED, Intent()) } override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) supportActionBar?.setDisplayHomeAsUpEnabled(true) - doAsync { - calculateMissingSoul(deck, privateInteractor) - PublicInteractor().getPatches { - val patch = it.find { it.uidDate == deck.patch } - runOnUiThread { - deck_details_patch.text = patch?.desc ?: "" - } - } - PublicInteractor().getUserInfo(deck.owner) { - val ownerUser = it - runOnUiThread { - deck_details_create_by.text = ownerUser.name - Glide.with(this@DeckActivity) - .load(ownerUser.photoUrl) - .transform(CircleTransform(this@DeckActivity)) - .into(deck_details_create_by_photo) + deck_comment_send?.setOnClickListener { + if (App.hasUserLogged()) { + if (deck_comment_new.text.toString().length < 4) { + eventBus.post(CmdShowSnackbarMsg(CmdShowSnackbarMsg.TYPE_ERROR, R.string.deck_comment_size_error) + .withAction(android.R.string.ok, {})) + } else { + PrivateInteractor().addDeckComment(deck, deck_comment_new.text.toString()) { + deck_comment_new.setText("") + addComment(it) + } } + } else { + showErrorUserNotLogged() } } + onKeyboardVisibilityChange = { + deck_comment_recycle_view.requestLayout() + } + if (!App.hasUserLogged()) { + deck_comment_new?.isEnabled = false + deck_comment_send?.isEnabled = false + deck_comment_new?.hint = getText(R.string.deck_comment_new_hint_anonymous) + } + loadDeckRemoteInfo() + if (savedInstanceState != null) { + deck_comment_new.postDelayed({ + CommonUtils.hideKeyboard(this, deck_comment_new) + }, DateUtils.SECOND_IN_MILLIS / 2) + } + setResult(Activity.RESULT_OK, Intent()) MetricsManager.trackScreen(MetricScreen.SCREEN_DECK_DETAILS()) } + override fun onBackPressed() { + if (commentsSheetBehavior.state == BottomSheetBehavior.STATE_EXPANDED) { + commentsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED + } else { + super.onBackPressed() + } + } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { - menuInflater.inflate(if (deckOwned) R.menu.menu_deck_owned else R.menu.menu_deck, menu) + menuInflater.inflate(if (deckOwned) R.menu.menu_deck_owner else R.menu.menu_deck, menu) menuLike = menu?.findItem(R.id.menu_like) updateLikeItem() return super.onCreateOptionsMenu(menu) @@ -122,10 +160,13 @@ class DeckActivity() : BaseActivity() { return true } R.id.menu_like -> { + if (!App.hasUserLogged()) { + showErrorUserNotLogged() + return false + } privateInteractor.setUserDeckLike(deck, !like) { like = !like updateLikeItem() - setResult(Activity.RESULT_OK, Intent()) val deckLikes = Integer.parseInt(deck_details_likes.text.toString()) deck_details_likes.text = numberInstance.format(deckLikes + if (like) 1 else -1) } @@ -137,7 +178,6 @@ class DeckActivity() : BaseActivity() { positiveButton(android.R.string.yes, { privateInteractor.deleteDeck(deck, deck.private) { toast(R.string.deck_deleted) - setResult(Activity.RESULT_OK, Intent()) ActivityCompat.finishAfterTransition(this@DeckActivity) } }) @@ -167,23 +207,73 @@ class DeckActivity() : BaseActivity() { deck_class_cover.setImageResource(deck.cls.imageRes) deck_class_attr1.setImageResource(deck.cls.attr1.imageRes) deck_class_attr2.setImageResource(deck.cls.attr2.imageRes) - deck_comment_qtd.text = numberInstance.format(deck.comments.size) deck_details_type.text = deck.type.name.toLowerCase().capitalize() deck_details_views.text = numberInstance.format(deck.views) deck_details_likes.text = numberInstance.format(deck.likes.size) deck_details_soul_cost.text = numberInstance.format(deck.cost) deck_details_create_at.text = deck.createdAt.toLocalDate().toString() + val updateDate = deck.updatedAt.toLocalDate() val updateTime = deck.updatedAt.toLocalTime().format(DateTimeFormatter.ofPattern(TIME_PATTERN)) - val updateText = "${deck.updatedAt.toLocalDate()} $updateTime" - deck_details_update_at.text = updateText - deck_details_cardlist.showDeck(deck) + deck_details_update_at.text = getString(R.string.deck_details_last_update_format, updateDate, updateTime) + deck_details_cardlist.showDeck(deck, false) + configDeckComments() + } + + private fun configDeckComments() { + with(deck_comment_recycle_view) { + adapter = DeckCommentAdapter(deck.comments, publicInteractor) { + privateInteractor.remDeckComment(deck, it) { + remComment(it) + } + } + layoutManager = object : LinearLayoutManager(this@DeckActivity) { + override fun setMeasuredDimension(childrenBounds: Rect, wSpec: Int, hSpec: Int) { + val maxHeight = resources.displayMetrics.heightPixels * getVisiblePercent() + with(childrenBounds) { + set(left, top, right, if (bottom < maxHeight) bottom else maxHeight.toInt()) + } + super.setMeasuredDimension(childrenBounds, wSpec, hSpec) + } + + private fun getVisiblePercent(): Float = if (keyboardVisible) 0.2f else 0.6f + + } + itemAnimator = SlideInLeftAnimator() + addItemDecoration(DividerItemDecoration(this@DeckActivity, DividerItemDecoration.VERTICAL)) + } + deck_comment_qtd.text = numberInstance.format(deck.comments.size) } - fun calculateMissingSoul(deck: Deck, interactor: PrivateInteractor) { + private fun loadDeckRemoteInfo() { + doAsync { + calculateMissingSoul(deck, privateInteractor) + publicInteractor.incDeckView(deck) { + deck_details_views.text = deck.views.inc().toString() + } + publicInteractor.getPatches { + val patch = it.find { it.uidDate == deck.patch } + runOnUiThread { + deck_details_patch.text = patch?.desc ?: "" + } + } + publicInteractor.getUserInfo(deck.owner) { + val ownerUser = it + runOnUiThread { + deck_details_create_by.text = ownerUser.name + Glide.with(this@DeckActivity) + .load(ownerUser.photoUrl) + .transform(CircleTransform(this@DeckActivity)) + .into(deck_details_create_by_photo) + } + } + } + } + + fun calculateMissingSoul(deck: Deck, privateInteractor: PrivateInteractor) { with(deck_details_soul_missing) { visibility = View.INVISIBLE deck_details_soul_missing_loading.visibility = View.VISIBLE - interactor.getMissingCards(deck, { deck_details_soul_missing_loading.visibility = View.VISIBLE }) { + privateInteractor.getMissingCards(deck, { deck_details_soul_missing_loading.visibility = View.VISIBLE }) { deck_details_soul_missing_loading.visibility = View.GONE val missingSoul = it.map { it.qtd * it.rarity.soulCost }.sum() Timber.d("Missing %d", missingSoul) @@ -194,4 +284,81 @@ class DeckActivity() : BaseActivity() { } } -} + private fun addComment(it: DeckComment) { + (deck_comment_recycle_view.adapter as DeckCommentAdapter).add(it) + deck_comment_recycle_view.scrollToPosition(0) + deck_comment_qtd.text = deck_comment_recycle_view.adapter.itemCount.toString() + deck_comment_recycle_view.requestLayout() + } + + private fun remComment(commentId: String) { + (deck_comment_recycle_view.adapter as DeckCommentAdapter).rem(commentId) + deck_comment_qtd.text = deck_comment_recycle_view.adapter.itemCount.toString() + deck_comment_recycle_view.requestLayout() + } + + class DeckCommentAdapter(val items: List, val publicInteractor: PublicInteractor, + val onRemComment: (commentId: String) -> Unit) : RecyclerView.Adapter() { + + init { + sortDeckComments() + } + + override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeckCommentViewHolder { + return DeckCommentViewHolder(parent?.inflate(R.layout.itemlist_deck_comment), onRemComment) + } + + override fun onBindViewHolder(holder: DeckCommentViewHolder?, position: Int) { + holder?.bind(items[position], publicInteractor) + } + + override fun getItemCount() = items.size + + fun add(deckComment: DeckComment) { + (items as ArrayList).add(0, deckComment) + notifyItemInserted(0) + } + + fun rem(commentId: String) { + val deckComment = items.find { it.id == commentId } + val deckCommentIndex = items.indexOf(deckComment) + (items as ArrayList).remove(deckComment) + notifyItemRemoved(deckCommentIndex) + } + + private fun sortDeckComments() { + Collections.sort(items, { dc1, dc2 -> dc2.date.compareTo(dc1.date) }) + } + + } + + class DeckCommentViewHolder(view: View?, val onRemComment: (commentId: String) -> Unit) : RecyclerView.ViewHolder(view) { + + fun bind(comment: DeckComment, publicInteractor: PublicInteractor) { + val timeFormatter = DateTimeFormatter.ofPattern(TIME_PATTERN) + itemView.deck_comment_msg.text = comment.comment + itemView.deck_comment_date.text = itemView.context.getString(R.string.deck_comment_date_format, + comment.date.toLocalDate(), comment.date.toLocalTime().format(timeFormatter)) + doAsync { + publicInteractor.getUserInfo(comment.owner) { + val ownerUser = it + itemView.post { + itemView.deck_comment_owner.text = ownerUser.name + with(itemView.deck_comment_delete) { + val owner = comment.owner == FirebaseAuth.getInstance().currentUser?.uid + visibility = if (owner) View.VISIBLE else View.GONE + setOnClickListener { onRemComment(comment.id) } + } + Glide.with(itemView.context) + .load(ownerUser.photoUrl) + .fallback(R.drawable.ic_user) + .transform(CircleTransform(itemView.context)) + .into(itemView.deck_comment_owner_photo) + } + } + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseActivity.kt index 53f8fa5..659ab12 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseActivity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseActivity.kt @@ -1,17 +1,26 @@ package com.ediposouza.teslesgendstracker.ui.base import android.content.Intent +import android.graphics.Rect +import android.net.Uri import android.os.Bundle +import android.os.Handler +import android.support.annotation.StringRes +import android.support.design.widget.CoordinatorLayout import android.support.design.widget.Snackbar import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar +import android.text.format.DateUtils +import android.view.View import android.widget.ProgressBar import com.ediposouza.teslesgendstracker.App import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor -import com.ediposouza.teslesgendstracker.manager.MetricsManager +import com.ediposouza.teslesgendstracker.util.ConfigManager +import com.ediposouza.teslesgendstracker.util.MetricAction +import com.ediposouza.teslesgendstracker.util.MetricsManager import com.google.android.gms.auth.api.Auth import com.google.android.gms.auth.api.signin.GoogleSignInAccount import com.google.android.gms.auth.api.signin.GoogleSignInOptions @@ -21,6 +30,9 @@ import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.GoogleAuthProvider import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe +import org.jetbrains.anko.alert +import org.jetbrains.anko.contentView +import org.jetbrains.anko.find import org.jetbrains.anko.toast import timber.log.Timber @@ -29,8 +41,6 @@ import timber.log.Timber */ open class BaseActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener, FirebaseAuth.AuthStateListener { - protected val eventBus by lazy { EventBus.getDefault() } - private val RC_SIGN_IN: Int = 235 private var loading: AlertDialog? = null @@ -38,54 +48,76 @@ open class BaseActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFaile private var googleApiClient: GoogleApiClient? = null private val firebaseAuth by lazy { FirebaseAuth.getInstance() } + protected var canExit = false + protected var keyboardVisible = false + protected var snackbarNeedMargin = true + protected var onKeyboardVisibilityChange: (() -> Unit)? = null + protected val handler = Handler() + protected val eventBus: EventBus by lazy { EventBus.getDefault() } + + val keyboardChangeListener = { + val r = Rect() + contentView?.getWindowVisibleDisplayFrame(r) + val screenHeight = contentView?.rootView?.height ?: 0 + // r.bottom is the position above soft keypad or device button. if keypad is shown, the r.bottom is smaller than that before. + val keypadHeight = screenHeight - r.bottom + val newKeyboardVisible = keypadHeight > (screenHeight * 0.15) // 0.15 ratio is perhaps enough to determine keypad height. + if (keyboardVisible != newKeyboardVisible) { + keyboardVisible == newKeyboardVisible + onKeyboardVisibilityChange?.invoke() + } + } + public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestIdToken(getString(R.string.default_web_client_id)) - .requestEmail() - .build() googleApiClient = GoogleApiClient.Builder(this) .enableAutoManage(this, this) - .addApi(Auth.GOOGLE_SIGN_IN_API, gso) + .addApi(Auth.GOOGLE_SIGN_IN_API, GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestIdToken(getString(R.string.default_web_client_id)) + .requestEmail() + .build()) .build() } - override fun onDestroy() { - MetricsManager.flush() - super.onDestroy() - } - - override fun onConnectionFailed(p0: ConnectionResult) { - } - override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) setSupportActionBar(findViewById(R.id.toolbar) as Toolbar?) supportActionBar?.title = "" supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back) + contentView?.viewTreeObserver?.addOnGlobalLayoutListener(keyboardChangeListener) } override fun onStart() { super.onStart() firebaseAuth.addAuthStateListener(this) - } - - override fun onResume() { - super.onResume() eventBus.register(this) - } - - override fun onPause() { - super.onPause() - eventBus.unregister(this) + ConfigManager.updateCaches { + if (ConfigManager.isVersionUnsupported()) { + alert(getString(R.string.app_version_unsupported)) { + okButton { + MetricsManager.trackAction(MetricAction.ACTION_VERSION_UNSUPPORTED()) + startActivity(Intent(Intent.ACTION_VIEW) + .setData(Uri.parse(getString(R.string.playstore_url_format, packageName)))) + System.exit(0) + } + setTheme(R.style.AppDialog) + }.show() + } + } } override fun onStop() { super.onStop() + eventBus.unregister(this) firebaseAuth.removeAuthStateListener(this) } + override fun onDestroy() { + contentView?.viewTreeObserver?.removeOnGlobalLayoutListener(keyboardChangeListener) + MetricsManager.flush() + super.onDestroy() + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == RC_SIGN_IN) { @@ -99,20 +131,34 @@ open class BaseActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFaile } } + override fun onConnectionFailed(p0: ConnectionResult) { + } + override fun onAuthStateChanged(firebaseAuth: FirebaseAuth) { val currentUser = firebaseAuth.currentUser if (currentUser != null) { Timber.d("onAuthStateChanged:signed_in:" + currentUser.uid) - if (!App.hasUserLogged) { + if (!App.hasUserAlreadyLogged) { MetricsManager.trackSignIn(currentUser, true) - App.hasUserLogged = true + App.hasUserAlreadyLogged = true } } else { Timber.d("onAuthStateChanged:signed_out") } } - fun firebaseAuthWithGoogle(acct: GoogleSignInAccount?) { + protected fun showExitConfirm(@StringRes exitMsg: Int = R.string.app_exit_confirm) { + canExit = true + handler.postDelayed({ canExit = false }, DateUtils.SECOND_IN_MILLIS * 2) + toast(exitMsg) + } + + protected fun showErrorUserNotLogged() { + eventBus.post(CmdShowSnackbarMsg(CmdShowSnackbarMsg.TYPE_ERROR, R.string.error_auth) + .withAction(R.string.action_login, { eventBus.post(CmdShowLogin()) })) + } + + private fun firebaseAuthWithGoogle(acct: GoogleSignInAccount?) { Timber.d("firebaseAuthWithGoogle:" + acct?.id) showLoading() val credential = GoogleAuthProvider.getCredential(acct?.idToken, null) @@ -158,12 +204,17 @@ open class BaseActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFaile snackbar?.dismiss() val msgRes = cmdShowSnackbarMsg.msgRes val msg = if (msgRes > 0) getString(msgRes) else cmdShowSnackbarMsg.msg - snackbar = Snackbar.make(findViewById(R.id.coordinatorLayout), msg, cmdShowSnackbarMsg.duration) + snackbar = Snackbar.make(find(R.id.coordinatorLayout), msg, cmdShowSnackbarMsg.duration) if (cmdShowSnackbarMsg.action != null) { val actionTextRes = cmdShowSnackbarMsg.actionTextRes val actionText = if (actionTextRes > 0) getString(actionTextRes) else cmdShowSnackbarMsg.actionText snackbar?.setAction(actionText, { cmdShowSnackbarMsg.action?.invoke() }) } + if (snackbarNeedMargin) { + val snackbarLP = snackbar?.view?.layoutParams as CoordinatorLayout.LayoutParams + snackbarLP.bottomMargin = resources.getDimensionPixelSize(R.dimen.navigation_bar_height) + snackbar?.view?.layoutParams = snackbarLP + } snackbar?.show() } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseAdsAdapter.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseAdsAdapter.kt index cfc32e0..f3faeb9 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseAdsAdapter.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseAdsAdapter.kt @@ -5,8 +5,8 @@ import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.RecyclerView import android.view.ViewGroup import com.ediposouza.teslesgendstracker.R -import com.ediposouza.teslesgendstracker.inflate -import com.ediposouza.teslesgendstracker.load +import com.ediposouza.teslesgendstracker.util.inflate +import com.ediposouza.teslesgendstracker.util.load import com.google.android.gms.ads.AdView import com.google.android.gms.ads.NativeExpressAdView diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFilterActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFilterActivity.kt new file mode 100644 index 0000000..39a859e --- /dev/null +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFilterActivity.kt @@ -0,0 +1,101 @@ +package com.ediposouza.teslesgendstracker.ui.base + +import android.animation.Animator +import android.animation.ValueAnimator +import android.os.Bundle +import android.support.design.widget.CoordinatorLayout +import android.text.format.DateUtils +import com.ediposouza.teslesgendstracker.R +import com.ediposouza.teslesgendstracker.ui.widget.filter.FilterMagika +import com.ediposouza.teslesgendstracker.ui.widget.filter.FilterRarity +import org.greenrobot.eventbus.Subscribe +import org.jetbrains.anko.find + +/** + * Created by EdipoSouza on 12/29/16. + */ + +open class BaseFilterActivity : BaseActivity() { + + private val KEY_FILTERS_GREAT_MARGIN = "filterGreatMarginKey" + private val KEY_FILTERS_BOTTOM_MARGIN = "filterMagikaBottomMarginKey" + private val UPDATE_FILTERS_POSITION_DURATION = DateUtils.SECOND_IN_MILLIS + private val UPDATE_FILTERS_VISIBILITY_DURATION = UPDATE_FILTERS_POSITION_DURATION / 2 + + var filterGreatMargin = false + + val fab_filter_magika by lazy { find(R.id.filter_magika) } + val fab_filter_rarity by lazy { find(R.id.filter_rarity) } + val filterMagikaLP by lazy { fab_filter_magika.layoutParams as CoordinatorLayout.LayoutParams } + val filterRarityLP by lazy { fab_filter_rarity.layoutParams as CoordinatorLayout.LayoutParams } + + override fun onSaveInstanceState(outState: Bundle?) { + outState?.apply { + putBoolean(KEY_FILTERS_GREAT_MARGIN, filterGreatMargin) + putInt(KEY_FILTERS_BOTTOM_MARGIN, filterMagikaLP.bottomMargin) + } + super.onSaveInstanceState(outState) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle?) { + super.onRestoreInstanceState(savedInstanceState) + savedInstanceState?.apply { + filterGreatMargin = getBoolean(KEY_FILTERS_GREAT_MARGIN) + updateFiltersMargins(getInt(KEY_FILTERS_BOTTOM_MARGIN)) + } + } + + @Synchronized fun updateRarityMagikaFiltersVisibility(show: Boolean) { + val margin = if (filterGreatMargin) R.dimen.filter_great_margin_bottom else R.dimen.large_margin + val showBottomMargin = resources.getDimensionPixelSize(margin) + val hideBottomMargin = -resources.getDimensionPixelSize(R.dimen.filter_hide_height) + if (show && filterMagikaLP.bottomMargin == showBottomMargin || + !show && filterMagikaLP.bottomMargin == hideBottomMargin) { + return + } + val animFrom = if (show) hideBottomMargin else showBottomMargin + val animTo = if (show) showBottomMargin else hideBottomMargin + with(ValueAnimator.ofInt(animFrom, animTo)) { + duration = UPDATE_FILTERS_VISIBILITY_DURATION + addUpdateListener { + updateFiltersMargins(it.animatedValue as Int) + } + addListener(object : Animator.AnimatorListener { + override fun onAnimationRepeat(p0: Animator?) { + } + + override fun onAnimationEnd(p0: Animator?) { + } + + override fun onAnimationCancel(p0: Animator?) { + } + + override fun onAnimationStart(p0: Animator?) { + } + + }) + start() + } + } + + @Subscribe + fun onCmdUpdateRarityMagikaFiltersPosition(update: CmdUpdateRarityMagikaFiltersPosition) { + filterGreatMargin = update.high + val endMargin = if (filterGreatMargin) R.dimen.filter_great_margin_bottom else R.dimen.large_margin + with(ValueAnimator.ofInt(filterMagikaLP.bottomMargin, resources.getDimensionPixelSize(endMargin))) { + duration = UPDATE_FILTERS_POSITION_DURATION + addUpdateListener { + updateFiltersMargins(it.animatedValue as Int) + } + start() + } + } + + private fun updateFiltersMargins(bottomMargin: Int) { + filterRarityLP.bottomMargin = bottomMargin + filterMagikaLP.bottomMargin = bottomMargin + fab_filter_magika.layoutParams = filterMagikaLP + fab_filter_rarity.layoutParams = filterRarityLP + } + +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFragment.kt index f2f8b40..b32cbf9 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/BaseFragment.kt @@ -1,8 +1,12 @@ package com.ediposouza.teslesgendstracker.ui.base import android.support.v4.app.Fragment -import com.ediposouza.teslesgendstracker.manager.MetricsManager +import com.ediposouza.teslesgendstracker.R +import com.ediposouza.teslesgendstracker.util.ConfigManager +import com.ediposouza.teslesgendstracker.util.MetricAction +import com.ediposouza.teslesgendstracker.util.MetricsManager import org.greenrobot.eventbus.EventBus +import org.jetbrains.anko.alert import timber.log.Timber /** @@ -11,9 +15,9 @@ import timber.log.Timber open class BaseFragment : Fragment() { - protected val eventBus by lazy { EventBus.getDefault() } + protected val eventBus: EventBus by lazy { EventBus.getDefault() } - protected var fragmentSelected: Boolean = false + protected var isFragmentSelected: Boolean = false override fun onStart() { super.onStart() @@ -22,6 +26,22 @@ open class BaseFragment : Fragment() { } catch (e: Exception) { Timber.i(e.message) } + ConfigManager.updateCaches {} + } + + override fun onResume() { + super.onResume() + ConfigManager.updateCaches { + if (ConfigManager.isDBUpdating()) { + activity.alert(getString(R.string.app_bd_under_updating)) { + okButton { + MetricsManager.trackAction(MetricAction.ACTION_NOTIFY_UPDATE()) + System.exit(0) + } + activity.setTheme(R.style.AppDialog) + }.show() + } + } } override fun onStop() { @@ -40,7 +60,7 @@ open class BaseFragment : Fragment() { override fun setMenuVisibility(menuVisible: Boolean) { super.setMenuVisibility(menuVisible) - fragmentSelected = menuVisible + isFragmentSelected = menuVisible } } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/Commands.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/Commands.kt index 16ec9ba..8921cc6 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/Commands.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/base/Commands.kt @@ -23,7 +23,9 @@ data class CmdShowCardsByAttr(val attr: Attribute) data class CmdShowDecksByClasses(val classes: List) -data class CmdUpdateRarityMagikaFiltersVisibility(val show: Boolean) +data class CmdUpdateRarityMagikaFiltersPosition(val high: Boolean) + +data class CmdUpdateVisibility(val show: Boolean) class CmdShowSnackbarMsg private constructor(type: Long) { diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/CardsFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/CardsFragment.kt index 0ec63ed..58b03e6 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/CardsFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/CardsFragment.kt @@ -12,18 +12,17 @@ import android.support.v7.widget.SearchView import android.text.format.DateUtils import android.view.* import android.view.inputmethod.InputMethodManager -import com.ediposouza.teslesgendstracker.MetricScreen import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Attribute -import com.ediposouza.teslesgendstracker.inflate -import com.ediposouza.teslesgendstracker.manager.MetricsManager -import com.ediposouza.teslesgendstracker.ui.base.BaseFragment -import com.ediposouza.teslesgendstracker.ui.base.CmdShowCardsByAttr -import com.ediposouza.teslesgendstracker.ui.base.CmdShowTabs -import com.ediposouza.teslesgendstracker.ui.base.CmdUpdateRarityMagikaFiltersVisibility +import com.ediposouza.teslesgendstracker.ui.base.* import com.ediposouza.teslesgendstracker.ui.cards.tabs.CardsAllFragment import com.ediposouza.teslesgendstracker.ui.cards.tabs.CardsCollectionFragment import com.ediposouza.teslesgendstracker.ui.cards.tabs.CardsFavoritesFragment +import com.ediposouza.teslesgendstracker.ui.widget.CollectionStatistics +import com.ediposouza.teslesgendstracker.util.MetricScreen +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.ediposouza.teslesgendstracker.util.inflate +import com.ediposouza.teslesgendstracker.util.toggleExpanded import kotlinx.android.synthetic.main.activity_dash.* import kotlinx.android.synthetic.main.fragment_cards.* @@ -32,32 +31,44 @@ import kotlinx.android.synthetic.main.fragment_cards.* */ class CardsFragment : BaseFragment(), SearchView.OnQueryTextListener { - var query: String? = null - val handler = Handler() - val trackSearch = Runnable { MetricsManager.trackSearch(query ?: "") } + private val KEY_PAGE_VIEW_POSITION = "pageViewPositionKey" + + private var query: String? = null + private val handler = Handler() + private val trackSearch = Runnable { MetricsManager.trackSearch(query ?: "") } + + val statisticsSheetBehavior: BottomSheetBehavior by lazy { + BottomSheetBehavior.from(activity.cards_collection_statistics) + } val pageChange = object : ViewPager.SimpleOnPageChangeListener() { override fun onPageSelected(position: Int) { - val title = when (position) { - 1 -> R.string.tab_cards_collection - 2 -> R.string.tab_cards_favorites - else -> R.string.app_name + updateActivityTitle(position) + (cards_view_pager.adapter as CardsPageAdapter).getItem(position).updateCardsList() + if (position == 1) { + statisticsSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED + activity.cards_collection_statistics.updateStatistics() + } else { + statisticsSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN } - activity.toolbar_title?.setText(title) - BottomSheetBehavior.from(activity.collection_statistics).state = BottomSheetBehavior.STATE_COLLAPSED + eventBus.post(CmdUpdateRarityMagikaFiltersPosition(position == 1)) MetricsManager.trackScreen(when (position) { 0 -> MetricScreen.SCREEN_CARDS_ALL() 1 -> MetricScreen.SCREEN_CARDS_COLLECTION() else -> MetricScreen.SCREEN_CARDS_FAVORED() }) - (cards_view_pager.adapter as CardsPageAdapter).getItem(position).updateCardsList() - if (position == 1) { - collection_statistics.updateStatistics() - } } } + private fun updateActivityTitle(position: Int) { + activity.toolbar_title?.setText(when (position) { + 1 -> R.string.title_tab_cards_collection + 2 -> R.string.title_tab_cards_favorites + else -> R.string.title_tab_cards_all + }) + } + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return container?.inflate(R.layout.fragment_cards) } @@ -66,6 +77,10 @@ class CardsFragment : BaseFragment(), SearchView.OnQueryTextListener { super.onViewCreated(view, savedInstanceState) setHasOptionsMenu(true) activity.dash_navigation_view.setCheckedItem(R.id.menu_cards) + activity.cards_collection_statistics.setOnClickListener { + statisticsSheetBehavior.toggleExpanded() + } + statisticsSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN cards_view_pager.adapter = CardsPageAdapter(context, childFragmentManager) cards_view_pager.addOnPageChangeListener(pageChange) attr_filter.filterClick = { @@ -80,20 +95,37 @@ class CardsFragment : BaseFragment(), SearchView.OnQueryTextListener { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - activity.toolbar_title.setText(R.string.app_name) + activity.toolbar_title.setText(R.string.app_name_full) activity.dash_tab_layout.setupWithViewPager(cards_view_pager) } + override fun onSaveInstanceState(outState: Bundle?) { + outState?.apply { putInt(KEY_PAGE_VIEW_POSITION, cards_view_pager?.currentItem ?: 0) } + super.onSaveInstanceState(outState) + } + + override fun onViewStateRestored(savedInstanceState: Bundle?) { + super.onViewStateRestored(savedInstanceState) + savedInstanceState?.apply { + cards_view_pager.currentItem = getInt(KEY_PAGE_VIEW_POSITION) + } + } + override fun onResume() { super.onResume() eventBus.post(CmdShowTabs()) - eventBus.post(CmdUpdateRarityMagikaFiltersVisibility(true)) + (activity as BaseFilterActivity).updateRarityMagikaFiltersVisibility(true) + } + + override fun onPause() { + super.onPause() + (activity as BaseFilterActivity).updateRarityMagikaFiltersVisibility(false) } override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { menu?.clear() - inflater?.inflate(R.menu.menu_sets, menu) inflater?.inflate(R.menu.menu_search, menu) + inflater?.inflate(R.menu.menu_sets, menu) with(MenuItemCompat.getActionView(menu?.findItem(R.id.menu_search)) as SearchView) { queryHint = getString(R.string.search_hint) setOnQueryTextListener(this@CardsFragment) @@ -118,33 +150,29 @@ class CardsFragment : BaseFragment(), SearchView.OnQueryTextListener { return true } -} - -class CardsPageAdapter(ctx: Context, fm: FragmentManager) : FragmentStatePagerAdapter(fm) { + class CardsPageAdapter(ctx: Context, fm: FragmentManager) : FragmentStatePagerAdapter(fm) { - var titles: Array - val cardsCollectionFragment by lazy { CardsCollectionFragment() } - val cardsFavoritesFragment by lazy { CardsFavoritesFragment() } - val cardsAllFragment by lazy { CardsAllFragment() } + var titles: Array = ctx.resources.getStringArray(R.array.cards_tabs) + val cardsCollectionFragment by lazy { CardsCollectionFragment() } + val cardsFavoritesFragment by lazy { CardsFavoritesFragment() } + val cardsAllFragment by lazy { CardsAllFragment() } - init { - titles = ctx.resources.getStringArray(R.array.cards_tabs) - } + override fun getItem(position: Int): CardsAllFragment { + return when (position) { + 1 -> cardsCollectionFragment + 2 -> cardsFavoritesFragment + else -> cardsAllFragment + } + } - override fun getItem(position: Int): CardsAllFragment { - return when (position) { - 1 -> cardsCollectionFragment - 2 -> cardsFavoritesFragment - else -> cardsAllFragment + override fun getCount(): Int { + return titles.size } - } - override fun getCount(): Int { - return titles.size - } + override fun getPageTitle(position: Int): CharSequence { + return titles[position] + } - override fun getPageTitle(position: Int): CharSequence { - return titles[position] } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsAllFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsAllFragment.kt index 108b044..d714790 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsAllFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsAllFragment.kt @@ -13,18 +13,18 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import com.ediposouza.teslesgendstracker.App -import com.ediposouza.teslesgendstracker.MetricAction import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.* -import com.ediposouza.teslesgendstracker.inflate import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor -import com.ediposouza.teslesgendstracker.manager.MetricsManager import com.ediposouza.teslesgendstracker.ui.CardActivity import com.ediposouza.teslesgendstracker.ui.base.* import com.ediposouza.teslesgendstracker.ui.cards.* -import com.ediposouza.teslesgendstracker.ui.utils.GridSpacingItemDecoration -import com.ediposouza.teslesgendstracker.ui.utils.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.ui.util.GridSpacingItemDecoration +import com.ediposouza.teslesgendstracker.ui.util.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.util.MetricAction +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.ediposouza.teslesgendstracker.util.inflate import jp.wasabeef.recyclerview.animators.ScaleInAnimator import kotlinx.android.synthetic.main.fragment_cards_list.* import kotlinx.android.synthetic.main.include_login_button.* @@ -53,6 +53,8 @@ open class CardsAllFragment : BaseFragment() { val privateInteractor: PrivateInteractor by lazy { PrivateInteractor() } val transitionName: String by lazy { getString(R.string.card_transition_name) } + open protected val isCardsCollection: Boolean = false + open val cardsAdapter by lazy { val gridLayoutManager = cards_recycler_view.layoutManager as GridLayoutManager CardsAllAdapter(ADS_EACH_ITEMS, gridLayoutManager, R.layout.itemlist_card_ads, R.dimen.card_height, @@ -68,16 +70,13 @@ open class CardsAllFragment : BaseFragment() { resources.getDimensionPixelSize(R.dimen.card_margin), true) } - init { - setHasOptionsMenu(true) - } - override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return container?.inflate(R.layout.fragment_cards_list) } override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setHasOptionsMenu(true) configRecycleView() } @@ -110,8 +109,15 @@ open class CardsAllFragment : BaseFragment() { fun configLoggedViews() { signin_button.setOnClickListener { EventBus.getDefault().post(CmdShowLogin()) } - signin_button.visibility = if (App.hasUserLogged) View.INVISIBLE else View.VISIBLE - cards_recycler_view.visibility = if (App.hasUserLogged) View.VISIBLE else View.INVISIBLE + signin_button.visibility = if (App.hasUserLogged()) View.INVISIBLE else View.VISIBLE + cards_recycler_view.visibility = if (App.hasUserLogged()) View.VISIBLE else View.INVISIBLE + } + + @Subscribe + fun onCmdUpdateRarityMagikaFiltersVisibility(update: CmdUpdateVisibility) { + if (isFragmentSelected) { + (activity as BaseFilterActivity).updateRarityMagikaFiltersVisibility(update.show) + } } @Subscribe @@ -123,7 +129,7 @@ open class CardsAllFragment : BaseFragment() { @Subscribe fun onCmdShowCardsByAttr(showCardsByAttr: CmdShowCardsByAttr) { loadCardsByAttr(showCardsByAttr.attr) - if (fragmentSelected) { + if (isFragmentSelected) { MetricsManager.trackAction(MetricAction.ACTION_CARD_FILTER_ATTR(), showCardsByAttr.attr.name) } } @@ -138,7 +144,7 @@ open class CardsAllFragment : BaseFragment() { fun onCmdFilterClass(filterClass: CmdFilterClass) { classFilter = filterClass.cls showCards() - if (fragmentSelected) { + if (isFragmentSelected) { MetricsManager.trackAction(MetricAction.ACTION_CARD_FILTER_SET(), setFilter?.name ?: MetricAction.ACTION_CARD_FILTER_SET.VALUE_CLEAR) } @@ -154,7 +160,7 @@ open class CardsAllFragment : BaseFragment() { fun onCmdFilterRarity(filterRarity: CmdFilterRarity) { rarityFilter = filterRarity.rarity showCards() - if (fragmentSelected) { + if (isFragmentSelected) { MetricsManager.trackAction(MetricAction.ACTION_CARD_FILTER_RARITY(), rarityFilter?.name ?: MetricAction.ACTION_CARD_FILTER_RARITY.VALUE_CLEAR) } @@ -164,7 +170,7 @@ open class CardsAllFragment : BaseFragment() { fun onCmdFilterMagika(filterMagika: CmdFilterMagika) { magikaFilter = filterMagika.magika showCards() - if (fragmentSelected) { + if (isFragmentSelected) { MetricsManager.trackAction(MetricAction.ACTION_CARD_FILTER_MAGIKA(), if (magikaFilter >= 0) magikaFilter.toString() else MetricAction.ACTION_CARD_FILTER_MAGIKA.VALUE_CLEAR) } @@ -172,10 +178,10 @@ open class CardsAllFragment : BaseFragment() { private fun loadCardsByAttr(attribute: Attribute) { currentAttr = attribute - PublicInteractor().getCards(setFilter, attribute, { + PublicInteractor().getCards(setFilter, attribute) { cardsLoaded = it showCards() - }) + } privateInteractor.getFavoriteCards(setFilter, currentAttr) { userFavorites = it } @@ -183,7 +189,7 @@ open class CardsAllFragment : BaseFragment() { open fun showCards() { cardsAdapter.showCards(filteredCards()) - cards_recycler_view.scrollToPosition(0) + cards_recycler_view?.scrollToPosition(0) } fun updateCardsList() { @@ -238,50 +244,50 @@ open class CardsAllFragment : BaseFragment() { ActivityOptionsCompat.makeSceneTransitionAnimation(activity, view, transitionName).toBundle()) } -} + class CardsAllAdapter(adsEachItems: Int, layoutManager: GridLayoutManager, @LayoutRes adsLayout: Int, + @DimenRes val cardHeight: Int, val itemClick: (View, Card) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : BaseAdsAdapter(adsEachItems, layoutManager, adsLayout) { -class CardsAllAdapter(adsEachItems: Int, layoutManager: GridLayoutManager, @LayoutRes adsLayout: Int, - @DimenRes val cardHeight: Int, val itemClick: (View, Card) -> Unit, - val itemLongClick: (View, Card) -> Boolean) : BaseAdsAdapter(adsEachItems, layoutManager, adsLayout) { + var items: List = ArrayList() - var items: List = ArrayList() + override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { + return CardsAllViewHolder(parent.inflate(R.layout.itemlist_card), cardHeight, itemClick, itemLongClick) + } - override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { - return CardsAllViewHolder(parent.inflate(R.layout.itemlist_card), cardHeight, itemClick, itemLongClick) - } + override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { + (holder as CardsAllViewHolder).bind(items[position]) + } - override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { - (holder as CardsAllViewHolder).bind(items[position]) + override fun getDefaultItemCount(): Int = items.size + + fun showCards(cards: List) { + val oldItems = items + items = cards + if (items.isEmpty() || items.minus(oldItems).isEmpty()) { + notifyDataSetChanged() + return + } + DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> + oldItem.shortName == newItem.shortName + }).dispatchUpdatesTo(this) + } } - override fun getDefaultItemCount(): Int = items.size + class CardsAllViewHolder(val view: View, @DimenRes val cardHeight: Int, val itemClick: (View, Card) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { - fun showCards(cards: List) { - val oldItems = items - items = cards - if (items.isEmpty() || items.minus(oldItems).isEmpty()) { - notifyDataSetChanged() - return + init { + val cardLayoutParams = itemView.card_all_image.layoutParams + cardLayoutParams.height = itemView.context.resources.getDimensionPixelSize(cardHeight) + itemView.card_all_image.layoutParams = cardLayoutParams } - DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> - oldItem.shortName == newItem.shortName - }).dispatchUpdatesTo(this) - } -} - -class CardsAllViewHolder(val view: View, @DimenRes val cardHeight: Int, val itemClick: (View, Card) -> Unit, - val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { - init { - val cardLayoutParams = itemView.card_all_image.layoutParams - cardLayoutParams.height = itemView.context.resources.getDimensionPixelSize(cardHeight) - itemView.card_all_image.layoutParams = cardLayoutParams - } + fun bind(card: Card) { + itemView.setOnClickListener { itemClick(itemView.card_all_image, card) } + itemView.setOnLongClickListener { itemLongClick(itemView.card_all_image, card) } + itemView.card_all_image.setImageBitmap(card.imageBitmap(itemView.context)) + } - fun bind(card: Card) { - itemView.setOnClickListener { itemClick(itemView.card_all_image, card) } - itemView.setOnLongClickListener { itemLongClick(itemView.card_all_image, card) } - itemView.card_all_image.setImageBitmap(card.imageBitmap(itemView.context)) } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsCollectionFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsCollectionFragment.kt index 2a1df56..ab85242 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsCollectionFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/cards/tabs/CardsCollectionFragment.kt @@ -7,16 +7,21 @@ import android.support.v4.content.ContextCompat import android.support.v7.util.DiffUtil import android.support.v7.widget.GridLayoutManager import android.support.v7.widget.RecyclerView -import android.view.* -import com.ediposouza.teslesgendstracker.* +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Card import com.ediposouza.teslesgendstracker.data.CardSlot -import com.ediposouza.teslesgendstracker.manager.MetricsManager import com.ediposouza.teslesgendstracker.ui.base.BaseAdsAdapter -import com.ediposouza.teslesgendstracker.ui.utils.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.ui.util.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.ui.widget.CollectionStatistics +import com.ediposouza.teslesgendstracker.util.MetricAction +import com.ediposouza.teslesgendstracker.util.MetricScreen +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.ediposouza.teslesgendstracker.util.inflate import jp.wasabeef.recyclerview.animators.ScaleInAnimator import kotlinx.android.synthetic.main.activity_dash.* -import kotlinx.android.synthetic.main.fragment_cards.* import kotlinx.android.synthetic.main.fragment_cards_list.* import kotlinx.android.synthetic.main.itemlist_card_collection.view.* import java.util.* @@ -26,8 +31,10 @@ import java.util.* */ class CardsCollectionFragment : CardsAllFragment() { - private val view_statistics by lazy { activity.collection_statistics } - private val statisticsSheetBehavior by lazy { + override val isCardsCollection: Boolean = true + + val view_statistics: CollectionStatistics by lazy { activity.cards_collection_statistics } + val statisticsSheetBehavior: BottomSheetBehavior by lazy { BottomSheetBehavior.from(view_statistics) } @@ -47,10 +54,9 @@ class CardsCollectionFragment : CardsAllFragment() { override fun onStateChanged(bottomSheet: View, newState: Int) { val expanded = newState == BottomSheetBehavior.STATE_EXPANDED || newState == BottomSheetBehavior.STATE_SETTLING - activity.dash_filter_rarity.visibility = if (expanded) View.INVISIBLE else View.VISIBLE - activity.dash_filter_magika.visibility = if (expanded) View.INVISIBLE else View.VISIBLE if (expanded) { - activity.collection_statistics.scrollToTop() + view_statistics.scrollToTop() + view_statistics.updateStatistics() } when (newState) { BottomSheetBehavior.STATE_EXPANDED -> { @@ -66,31 +72,14 @@ class CardsCollectionFragment : CardsAllFragment() { override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setHasOptionsMenu(true) - view_statistics.setOnClickListener { - statisticsSheetBehavior.toogleExpanded() + with(cards_recycler_view) { + setPadding(paddingLeft, paddingTop, paddingRight, resources.getDimensionPixelSize(R.dimen.huge_margin)) } statisticsSheetBehavior.setBottomSheetCallback(sheetBehaviorCallback) } - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - menu?.clear() - inflater?.inflate(R.menu.menu_sets, menu) - inflater?.inflate(R.menu.menu_cards_collection, menu) - super.onCreateOptionsMenu(menu, inflater) - } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item?.itemId) { - R.id.menu_statistics -> { - view_statistics?.updateStatistics() - statisticsSheetBehavior.toogleExpanded() - return true - } - else -> { - BottomSheetBehavior.from(activity.collection_statistics).state = BottomSheetBehavior.STATE_COLLAPSED - } - } + BottomSheetBehavior.from(view_statistics).state = BottomSheetBehavior.STATE_COLLAPSED return super.onOptionsItemSelected(item) } @@ -104,85 +93,86 @@ class CardsCollectionFragment : CardsAllFragment() { val cards = filteredCards() privateInteractor.getUserCollection(setFilter, currentAttr) { val userCards = it - val slots = cards.map { CardSlot(it, userCards[it.shortName] ?: 0L) } - cards_recycler_view.itemAnimator = ScaleInAnimator() + val slots = cards.map { CardSlot(it, userCards[it.shortName] ?: 0) } + cards_recycler_view?.itemAnimator = ScaleInAnimator() cardsCollectionAdapter.showCards(slots as ArrayList) - cards_recycler_view.scrollToPosition(0) + cards_recycler_view?.scrollToPosition(0) } } private fun changeUserCardQtd(cardSlot: CardSlot) { val newQtd = cardSlot.qtd.inc() - val finalQtd = if (newQtd <= 3) newQtd else 0 + val cardMaxQtd = if (cardSlot.card.unique) 1 else 3 + val finalQtd = if (newQtd <= cardMaxQtd) newQtd else 0 privateInteractor.setUserCardQtd(cardSlot.card, finalQtd) { cards_recycler_view?.itemAnimator = null cardsCollectionAdapter.updateSlot(cardSlot, finalQtd) - view_statistics?.updateStatistics(currentAttr) + view_statistics.updateStatistics(currentAttr) MetricsManager.trackAction(MetricAction.ACTION_COLLECTION_CARD_QTD_CHANGE(), finalQtd.toString()) } } -} - -class CardsCollectionAdapter(adsEachItems: Int, layoutManager: GridLayoutManager, - @LayoutRes adsLayout: Int, val itemClick: (CardSlot) -> Unit, - val itemLongClick: (View, Card) -> Boolean) : BaseAdsAdapter(adsEachItems, layoutManager, adsLayout) { + class CardsCollectionAdapter(adsEachItems: Int, layoutManager: GridLayoutManager, + @LayoutRes adsLayout: Int, val itemClick: (CardSlot) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : BaseAdsAdapter(adsEachItems, layoutManager, adsLayout) { - var items: ArrayList = ArrayList() + var items: ArrayList = ArrayList() - override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { - return CardsCollectionViewHolder(parent.inflate(R.layout.itemlist_card_collection), itemClick, itemLongClick) - } + override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { + return CardsCollectionViewHolder(parent.inflate(R.layout.itemlist_card_collection), itemClick, itemLongClick) + } - override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { - (holder as CardsCollectionViewHolder).bind(items[position]) - } + override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { + (holder as CardsCollectionViewHolder).bind(items[position]) + } - override fun getDefaultItemCount(): Int = items.size + override fun getDefaultItemCount(): Int = items.size - fun showCards(cardSlots: ArrayList) { - val oldItems = items - items = cardSlots - if (items.isEmpty() || items.minus(oldItems).isEmpty()) { - notifyDataSetChanged() - return + fun showCards(cardSlots: ArrayList) { + val oldItems = items + items = cardSlots + if (items.isEmpty() || items.minus(oldItems).isEmpty()) { + notifyDataSetChanged() + return + } + DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> + oldItem.card.shortName == newItem.card.shortName + }).dispatchUpdatesTo(this) } - DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> - oldItem.card.shortName == newItem.card.shortName - }).dispatchUpdatesTo(this) - } - fun updateSlot(cardSlot: CardSlot, newQtd: Long) { - val slotIndex = items.indexOf(cardSlot) - if (slotIndex > -1) { - items[slotIndex] = CardSlot(cardSlot.card, newQtd) - notifyItemChanged(slotIndex + getAdsQtdBeforeDefaultPosition(slotIndex)) + fun updateSlot(cardSlot: CardSlot, newQtd: Int) { + val slotIndex = items.indexOf(cardSlot) + if (slotIndex > -1) { + items[slotIndex] = CardSlot(cardSlot.card, newQtd) + notifyItemChanged(slotIndex + getAdsQtdBeforeDefaultPosition(slotIndex)) + } } - } -} + } -class CardsCollectionViewHolder(val view: View, val itemClick: (CardSlot) -> Unit, - val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { + class CardsCollectionViewHolder(val view: View, val itemClick: (CardSlot) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { - fun bind(cardSlot: CardSlot) { - itemView.setOnClickListener { itemClick(cardSlot) } - itemView.setOnLongClickListener { - itemLongClick(itemView.card_collection_image, cardSlot.card) - } - itemView.card_collection_image.setImageBitmap(cardSlot.card.imageBitmap(itemView.context)) - if (cardSlot.qtd == 0L) { - val color = ContextCompat.getColor(itemView.context, R.color.card_zero_qtd) - itemView.card_collection_image.setColorFilter(color) - } else { - itemView.card_collection_image.clearColorFilter() + fun bind(cardSlot: CardSlot) { + itemView.setOnClickListener { itemClick(cardSlot) } + itemView.setOnLongClickListener { + itemLongClick(itemView.card_collection_image, cardSlot.card) + } + itemView.card_collection_image.setImageBitmap(cardSlot.card.imageBitmap(itemView.context)) + if (cardSlot.qtd == 0) { + val color = ContextCompat.getColor(itemView.context, R.color.card_zero_qtd) + itemView.card_collection_image.setColorFilter(color) + } else { + itemView.card_collection_image.clearColorFilter() + } + itemView.card_collection_qtd.setImageResource(when (cardSlot.qtd) { + 0 -> R.drawable.ic_qtd_zero + 2 -> R.drawable.ic_qtd_two + else -> R.drawable.ic_qtd_three + }) + itemView.card_collection_qtd.visibility = if (cardSlot.qtd == 1) View.GONE else View.VISIBLE } - itemView.card_collection_qtd.setImageResource(when (cardSlot.qtd) { - 0L -> R.drawable.ic_qtd_zero - 2L -> R.drawable.ic_qtd_two - else -> R.drawable.ic_qtd_three - }) - itemView.card_collection_qtd.visibility = if (cardSlot.qtd == 1L) View.GONE else View.VISIBLE + } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/DecksFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/DecksFragment.kt index 24c796a..b293dcc 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/DecksFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/DecksFragment.kt @@ -14,19 +14,21 @@ import android.support.v7.widget.SearchView import android.text.format.DateUtils import android.view.* import android.view.inputmethod.InputMethodManager -import com.ediposouza.teslesgendstracker.MetricScreen import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Class -import com.ediposouza.teslesgendstracker.inflate -import com.ediposouza.teslesgendstracker.manager.MetricsManager +import com.ediposouza.teslesgendstracker.ui.DashActivity import com.ediposouza.teslesgendstracker.ui.base.* import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterSearch import com.ediposouza.teslesgendstracker.ui.decks.new.NewDeckActivity import com.ediposouza.teslesgendstracker.ui.decks.tabs.DecksFavoritedFragment import com.ediposouza.teslesgendstracker.ui.decks.tabs.DecksOwnerFragment import com.ediposouza.teslesgendstracker.ui.decks.tabs.DecksPublicFragment +import com.ediposouza.teslesgendstracker.util.MetricScreen +import com.ediposouza.teslesgendstracker.util.MetricsManager +import com.ediposouza.teslesgendstracker.util.inflate import kotlinx.android.synthetic.main.activity_dash.* import kotlinx.android.synthetic.main.fragment_decks.* +import org.greenrobot.eventbus.Subscribe import org.jetbrains.anko.intentFor /** @@ -34,19 +36,16 @@ import org.jetbrains.anko.intentFor */ class DecksFragment : BaseFragment(), SearchView.OnQueryTextListener { + private val KEY_FAB_NEW_DECK = "newDeckKey" + private val KEY_PAGE_VIEW_POSITION = "pageViewPositionKey" private val RC_NEW_DECK = 125 - val adapter by lazy { DecksPageAdapter(context, fragmentManager) } + private val adapter by lazy { DecksPageAdapter(context, fragmentManager) } - val pageChange = object : ViewPager.SimpleOnPageChangeListener() { + private val pageChange = object : ViewPager.SimpleOnPageChangeListener() { override fun onPageSelected(position: Int) { - val title = when (position) { - 1 -> R.string.tab_decks_owned - 2 -> R.string.tab_decks_favorites - else -> R.string.tab_decks_public - } - activity.toolbar_title?.setText(title) + updateActivityTitle(position) MetricsManager.trackScreen(when (position) { 0 -> MetricScreen.SCREEN_DECKS_PUBLIC() 1 -> MetricScreen.SCREEN_DECKS_OWNED() @@ -57,6 +56,14 @@ class DecksFragment : BaseFragment(), SearchView.OnQueryTextListener { } + private fun updateActivityTitle(position: Int) { + activity.toolbar_title?.setText(when (position) { + 1 -> R.string.title_tab_decks_owned + 2 -> R.string.title_tab_decks_favorites + else -> R.string.title_tab_decks_public + }) + } + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { return container?.inflate(R.layout.fragment_decks) } @@ -64,11 +71,11 @@ class DecksFragment : BaseFragment(), SearchView.OnQueryTextListener { override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setHasOptionsMenu(true) - activity.dash_navigation_view.setCheckedItem(R.id.menu_decks) decks_view_pager.adapter = adapter - decks_view_pager.addOnPageChangeListener(pageChange) activity.dash_tab_layout.setupWithViewPager(decks_view_pager) activity.dash_navigation_view.setCheckedItem(R.id.menu_decks) + activity.toolbar_title?.setText(R.string.title_tab_decks_public) + decks_view_pager.addOnPageChangeListener(pageChange) decks_attr_filter.filterClick = { if (decks_attr_filter.isAttrSelected(it)) { decks_attr_filter.unSelectAttr(it) @@ -77,18 +84,54 @@ class DecksFragment : BaseFragment(), SearchView.OnQueryTextListener { } requestDecks() } - decks_fab_add.setOnClickListener { - val anim = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_up, R.anim.slide_down) - startActivityForResult(context.intentFor(), RC_NEW_DECK, anim.toBundle()) - } Handler().postDelayed({ requestDecks() }, DateUtils.SECOND_IN_MILLIS) MetricsManager.trackScreen(MetricScreen.SCREEN_DECKS_PUBLIC()) } + override fun onSaveInstanceState(outState: Bundle?) { + outState?.apply { + putInt(KEY_PAGE_VIEW_POSITION, decks_view_pager?.currentItem ?: 0) + putBoolean(KEY_FAB_NEW_DECK, activity?.decks_fab_add?.isShown ?: false) + } + super.onSaveInstanceState(outState) + } + + override fun onViewStateRestored(savedInstanceState: Bundle?) { + super.onViewStateRestored(savedInstanceState) + savedInstanceState?.apply { + decks_view_pager.currentItem = getInt(KEY_PAGE_VIEW_POSITION) + if (getBoolean(KEY_FAB_NEW_DECK)) { + configFABNewDeck(activity as DashActivity) + } + } + } + + override fun onAttach(context: Context?) { + super.onAttach(context) + configFABNewDeck(context as DashActivity) + } + + private fun configFABNewDeck(dashActivity: DashActivity) { + dashActivity.decks_fab_add?.apply { + setOnClickListener { + val anim = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_up, R.anim.slide_down) + startActivityForResult(context.intentFor(), RC_NEW_DECK, anim.toBundle()) + } + postDelayed({ if (this@DecksFragment.isAdded) show() }, DateUtils.SECOND_IN_MILLIS * 2) + } + } + override fun onResume() { super.onResume() eventBus.post(CmdShowTabs()) - eventBus.post(CmdUpdateRarityMagikaFiltersVisibility(false)) + } + + override fun onDetach() { + super.onDetach() + with(activity.decks_fab_add) { + setOnClickListener { } + hide() + } } override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { @@ -127,33 +170,38 @@ class DecksFragment : BaseFragment(), SearchView.OnQueryTextListener { eventBus.post(CmdShowDecksByClasses(classesToShow)) } -} + @Subscribe + fun onCmdUpdateRarityMagikaFiltersVisibility(update: CmdUpdateVisibility) { + if (update.show) { + activity.decks_fab_add.show() + } else { + activity.decks_fab_add.hide() + } + } -class DecksPageAdapter(ctx: Context, fm: FragmentManager) : FragmentStatePagerAdapter(fm) { + class DecksPageAdapter(ctx: Context, fm: FragmentManager) : FragmentStatePagerAdapter(fm) { - var titles: Array - val decksPublicFragment by lazy { DecksPublicFragment() } - val decksMyFragment by lazy { DecksOwnerFragment() } - val decksSavedFragment by lazy { DecksFavoritedFragment() } + var titles: Array = ctx.resources.getStringArray(R.array.decks_tabs) + val decksPublicFragment by lazy { DecksPublicFragment() } + val decksMyFragment by lazy { DecksOwnerFragment() } + val decksSavedFragment by lazy { DecksFavoritedFragment() } - init { - titles = ctx.resources.getStringArray(R.array.decks_tabs) - } + override fun getItem(position: Int): BaseFragment { + return when (position) { + 1 -> decksMyFragment + 2 -> decksSavedFragment + else -> decksPublicFragment + } + } - override fun getItem(position: Int): BaseFragment { - return when (position) { - 1 -> decksMyFragment - 2 -> decksSavedFragment - else -> decksPublicFragment + override fun getCount(): Int { + return titles.size } - } - override fun getCount(): Int { - return titles.size - } + override fun getPageTitle(position: Int): CharSequence { + return titles[position] + } - override fun getPageTitle(position: Int): CharSequence { - return titles[position] } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckActivity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckActivity.kt index ab7d3b9..e352fa6 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckActivity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckActivity.kt @@ -1,12 +1,8 @@ package com.ediposouza.teslesgendstracker.ui.decks.new -import android.animation.Animator -import android.animation.ValueAnimator import android.app.Activity import android.content.Intent import android.os.Bundle -import android.os.Handler -import android.support.design.widget.CoordinatorLayout import android.support.v4.app.ActivityCompat import android.text.format.DateUtils import android.util.TypedValue @@ -14,31 +10,30 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.ArrayAdapter -import com.ediposouza.teslesgendstracker.MetricScreen +import com.ediposouza.teslesgendstracker.App import com.ediposouza.teslesgendstracker.R -import com.ediposouza.teslesgendstracker.data.Attribute -import com.ediposouza.teslesgendstracker.data.Class -import com.ediposouza.teslesgendstracker.data.DeckType -import com.ediposouza.teslesgendstracker.data.Patch +import com.ediposouza.teslesgendstracker.data.* import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor -import com.ediposouza.teslesgendstracker.manager.MetricsManager -import com.ediposouza.teslesgendstracker.ui.base.BaseActivity +import com.ediposouza.teslesgendstracker.ui.base.BaseFilterActivity import com.ediposouza.teslesgendstracker.ui.base.CmdShowCardsByAttr -import com.ediposouza.teslesgendstracker.ui.base.CmdUpdateRarityMagikaFiltersVisibility +import com.ediposouza.teslesgendstracker.ui.base.CmdShowSnackbarMsg import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterClass import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterMagika import com.ediposouza.teslesgendstracker.ui.cards.CmdFilterRarity import com.ediposouza.teslesgendstracker.ui.decks.CmdAddCard import com.ediposouza.teslesgendstracker.ui.decks.CmdRemAttr +import com.ediposouza.teslesgendstracker.util.MetricScreen +import com.ediposouza.teslesgendstracker.util.MetricsManager import kotlinx.android.synthetic.main.activity_new_deck.* import kotlinx.android.synthetic.main.dialog_new_deck.view.* import org.greenrobot.eventbus.Subscribe import org.jetbrains.anko.alert import org.jetbrains.anko.intentFor import org.jetbrains.anko.toast +import java.util.* -class NewDeckActivity : BaseActivity() { +class NewDeckActivity : BaseFilterActivity() { companion object { @@ -46,22 +41,18 @@ class NewDeckActivity : BaseActivity() { } - val ANIM_DURATION = 250L + private val ANIM_DURATION = 250L + private val DECK_MIN_CARDS_QTD = 50 + private val EXIT_CONFIRM_MIN_CARDS = 3 + private val KEY_DECK_CARDS = "deckCardsKey" - val attrFilterClick: (Attribute) -> Unit = { + private val attrFilterClick: (Attribute) -> Unit = { eventBus.post(CmdShowCardsByAttr(it)) new_deck_attr_filter.selectAttr(it, true) new_deck_attr_filter.lastAttrSelected = it updateDualFilter() } - val onCardlistChange = { - val cards = new_deck_cardlist.getCards() - new_deck_cardlist_costs.updateCosts(cards) - new_deck_cardlist_qtd.text = getString(R.string.new_deck_card_list_qtd, cards.sumBy { it.qtd.toInt() }) - new_deck_cardlist_soul.text = cards.map { it.card.rarity.soulCost * it.qtd }.sum().toString() - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_new_deck) @@ -72,6 +63,18 @@ class NewDeckActivity : BaseActivity() { super.onPostCreate(savedInstanceState) supportActionBar?.setDisplayHomeAsUpEnabled(true) toolbar_title.text = getString(R.string.new_deck_title) + new_deck_cardlist.editMode = true + configDeckFilters() + supportFragmentManager.beginTransaction() + .replace(R.id.new_deck_fragment_cards, NewDeckCardsListFragment()) + .commit() + handler.postDelayed({ + eventBus.post(CmdShowCardsByAttr(Attribute.STRENGTH)) + }, DateUtils.SECOND_IN_MILLIS) + MetricsManager.trackScreen(MetricScreen.SCREEN_NEW_DECKS()) + } + + private fun configDeckFilters() { with(new_deck_attr_filter) { filterClick = attrFilterClick onAttrLock = { attr1: Attribute, attr2: Attribute -> @@ -87,17 +90,32 @@ class NewDeckActivity : BaseActivity() { new_deck_class_cover.animate().alpha(0f).setDuration(ANIM_DURATION).start() } } - new_deck_cardlist.editMode = true - new_deck_cardlist.onCardListChange = onCardlistChange - new_deck_filter_rarity.filterClick = { eventBus.post(CmdFilterRarity(it)) } - new_deck_filter_magika.filterClick = { eventBus.post(CmdFilterMagika(it)) } - supportFragmentManager.beginTransaction() - .replace(R.id.new_deck_fragment_cards, NewDeckCardsListFragment()) - .commit() - Handler().postDelayed({ - eventBus.post(CmdShowCardsByAttr(Attribute.STRENGTH)) - }, DateUtils.SECOND_IN_MILLIS) - MetricsManager.trackScreen(MetricScreen.SCREEN_NEW_DECKS()) + filter_rarity.filterClick = { eventBus.post(CmdFilterRarity(it)) } + filter_magika.filterClick = { eventBus.post(CmdFilterMagika(it)) } + } + + override fun onSaveInstanceState(outState: Bundle?) { + outState?.apply { + val cardsArrayList = ArrayList() + cardsArrayList.addAll(new_deck_cardlist?.getCards() ?: listOf()) + putParcelableArrayList(KEY_DECK_CARDS, cardsArrayList) + } + super.onSaveInstanceState(outState) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle?) { + super.onRestoreInstanceState(savedInstanceState) + savedInstanceState?.apply { + new_deck_cardlist?.addCards(getParcelableArrayList(KEY_DECK_CARDS)) + } + } + + override fun onBackPressed() { + if (canExit || new_deck_cardlist.getCards().size < EXIT_CONFIRM_MIN_CARDS) { + super.onBackPressed() + } else { + showExitConfirm(R.string.deck_exit_confirm) + } } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -113,7 +131,16 @@ class NewDeckActivity : BaseActivity() { return true } R.id.menu_done -> { - showSaveDialog() + if (!App.hasUserLogged()) { + showErrorUserNotLogged() + return false + } + if (new_deck_cardlist.getCards().sumBy { it.qtd } >= DECK_MIN_CARDS_QTD) { + showSaveDialog() + } else { + eventBus.post(CmdShowSnackbarMsg(CmdShowSnackbarMsg.TYPE_ERROR, R.string.new_deck_save_error_incomplete) + .withAction(android.R.string.ok, {})) + } return true } } @@ -147,10 +174,9 @@ class NewDeckActivity : BaseActivity() { val deckTypeSelected = DeckType.valueOf(deckTypeText.toUpperCase()) val deckPatchDesc = view.new_deck_dialog_patch_spinner.selectedItem as String val deckPatchSelected = deckPatches.find { it.desc == deckPatchDesc } ?: deckPatches.last() - val deckCost = new_deck_cardlist_soul.text.toString().toInt() val deckCards = new_deck_cardlist.getCards().map { it.card.shortName to it.qtd }.toMap() val deckPrivate = !view.new_deck_dialog_public.isChecked - PrivateInteractor().saveDeck(deckName, deckCls, deckTypeSelected, deckCost, + PrivateInteractor().saveDeck(deckName, deckCls, deckTypeSelected, new_deck_cardlist.getSoulCost(), deckPatchSelected.uidDate, deckCards, deckPrivate) { toast(if (deckPrivate) R.string.new_deck_save_as_private else R.string.new_deck_save_as_public) val data = intentFor(DECK_PRIVATE_EXTRA to deckPrivate) @@ -171,53 +197,13 @@ class NewDeckActivity : BaseActivity() { fun onCmdCardAdd(cmdCardAdd: CmdAddCard) { new_deck_cardlist.addCard(cmdCardAdd.card) new_deck_attr_filter.lockAttrs(cmdCardAdd.card.dualAttr1, cmdCardAdd.card.dualAttr2) - new_deck_cardlist_costs.updateCosts(new_deck_cardlist.getCards()) updateDualFilter() } @Subscribe fun onCmdRemAttr(cmdRemAttr: CmdRemAttr) { new_deck_attr_filter.unlockAttr(cmdRemAttr.attr) - new_deck_cardlist_costs.updateCosts(new_deck_cardlist.getCards()) updateDualFilter() } - @Subscribe - fun onCmdUpdateRarityMagikaFilters(update: CmdUpdateRarityMagikaFiltersVisibility) { - val filterMagikaLP = new_deck_filter_magika.layoutParams as CoordinatorLayout.LayoutParams - val filterRarityLP = new_deck_filter_rarity.layoutParams as CoordinatorLayout.LayoutParams - val showBottomMargin = resources.getDimensionPixelSize(R.dimen.large_margin) - val hideBottomMargin = -resources.getDimensionPixelSize(R.dimen.filter_hide_height) - if (update.show && filterMagikaLP.bottomMargin == showBottomMargin || - !update.show && filterMagikaLP.bottomMargin == hideBottomMargin) { - return - } - val animFrom = if (update.show) hideBottomMargin else showBottomMargin - val animTo = if (update.show) showBottomMargin else hideBottomMargin - with(ValueAnimator.ofInt(animFrom, animTo)) { - duration = DateUtils.SECOND_IN_MILLIS - addUpdateListener { - filterRarityLP.bottomMargin = it.animatedValue as Int - filterMagikaLP.bottomMargin = it.animatedValue as Int - new_deck_filter_magika.layoutParams = filterMagikaLP - new_deck_filter_rarity.layoutParams = filterRarityLP - } - addListener(object : Animator.AnimatorListener { - override fun onAnimationRepeat(p0: Animator?) { - } - - override fun onAnimationEnd(p0: Animator?) { - } - - override fun onAnimationCancel(p0: Animator?) { - } - - override fun onAnimationStart(p0: Animator?) { - } - - }) - start() - } - } - } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckCardsListFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckCardsListFragment.kt index f30419d..e47e161 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckCardsListFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/new/NewDeckCardsListFragment.kt @@ -4,14 +4,13 @@ import android.support.v7.widget.GridLayoutManager import android.view.View import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Card -import com.ediposouza.teslesgendstracker.ui.cards.tabs.CardsAllAdapter import com.ediposouza.teslesgendstracker.ui.cards.tabs.CardsAllFragment import com.ediposouza.teslesgendstracker.ui.decks.CmdAddCard -import com.ediposouza.teslesgendstracker.ui.utils.GridSpacingItemDecoration +import com.ediposouza.teslesgendstracker.ui.util.GridSpacingItemDecoration import kotlinx.android.synthetic.main.fragment_cards_list.* import org.greenrobot.eventbus.EventBus -class NewDeckCardsListFragment() : CardsAllFragment() { +class NewDeckCardsListFragment : CardsAllFragment() { override val ADS_EACH_ITEMS = 20 //after 10 lines override val CARDS_PER_ROW = 2 @@ -37,7 +36,7 @@ class NewDeckCardsListFragment() : CardsAllFragment() { override fun configRecycleView() { super.configRecycleView() - configLoggedViews() + isFragmentSelected = true cards_recycler_view.setPadding(0, 0, 0, 0) } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksFavoritedFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksFavoritedFragment.kt index d52622a..ffc4e9a 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksFavoritedFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksFavoritedFragment.kt @@ -6,8 +6,8 @@ import android.view.View import android.view.ViewGroup import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Class -import com.ediposouza.teslesgendstracker.inflate import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor +import com.ediposouza.teslesgendstracker.util.inflate import timber.log.Timber /** diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksOwnerFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksOwnerFragment.kt index c96a9aa..fc2615a 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksOwnerFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksOwnerFragment.kt @@ -6,8 +6,8 @@ import android.widget.Switch import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Class import com.ediposouza.teslesgendstracker.data.Deck -import com.ediposouza.teslesgendstracker.inflate import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor +import com.ediposouza.teslesgendstracker.util.inflate import timber.log.Timber /** @@ -32,7 +32,7 @@ class DecksOwnerFragment : DecksPublicFragment() { override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { menu?.clear() - inflater?.inflate(R.menu.menu_decks_owner, menu) + inflater?.inflate(R.menu.menu_decks_owned, menu) onlyPrivate = menu?.findItem(R.id.menu_only_private)?.actionView as Switch onlyPrivate?.setOnCheckedChangeListener { button, checked -> showDecks() } super.onCreateOptionsMenu(menu, inflater) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksPublicFragment.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksPublicFragment.kt index 68557cc..1472e11 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksPublicFragment.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/tabs/DecksPublicFragment.kt @@ -16,12 +16,12 @@ import com.ediposouza.teslesgendstracker.App import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Class import com.ediposouza.teslesgendstracker.data.Deck -import com.ediposouza.teslesgendstracker.inflate import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor import com.ediposouza.teslesgendstracker.ui.DeckActivity import com.ediposouza.teslesgendstracker.ui.base.* -import com.ediposouza.teslesgendstracker.ui.utils.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.ui.util.SimpleDiffCallback +import com.ediposouza.teslesgendstracker.util.inflate import com.google.firebase.auth.FirebaseAuth import jp.wasabeef.recyclerview.animators.SlideInLeftAnimator import kotlinx.android.synthetic.main.fragment_decks_list.* @@ -94,8 +94,8 @@ open class DecksPublicFragment : BaseFragment() { fun configLoggedViews() { signin_button.setOnClickListener { EventBus.getDefault().post(CmdShowLogin()) } - signin_button.visibility = if (App.hasUserLogged) View.INVISIBLE else View.VISIBLE - decks_recycler_view.visibility = if (App.hasUserLogged) View.VISIBLE else View.INVISIBLE + signin_button.visibility = if (App.hasUserLogged()) View.INVISIBLE else View.VISIBLE + decks_recycler_view.visibility = if (App.hasUserLogged()) View.VISIBLE else View.INVISIBLE } @Subscribe @@ -129,89 +129,89 @@ open class DecksPublicFragment : BaseFragment() { open fun getDecks(cls: Class?, last: Boolean) { publicInteractor.getPublicDecks(cls, { it.forEach { Timber.d("Public: %s", it.toString()) } - decksAdapter.showDecks(it, last) + decksAdapter.showDecks(it.sortedByDescending(Deck::updatedAt), last) }) } -} + class DecksAllAdapter(adsEachItems: Int, @LayoutRes adsLayout: Int, val itemClick: (View, Deck) -> Unit, + val itemLongClick: (View, Deck) -> Boolean) : BaseAdsAdapter(adsEachItems, adsLayout) { -class DecksAllAdapter(adsEachItems: Int, @LayoutRes adsLayout: Int, val itemClick: (View, Deck) -> Unit, - val itemLongClick: (View, Deck) -> Boolean) : BaseAdsAdapter(adsEachItems, adsLayout) { + val privateInteractor = PrivateInteractor() - val privateInteractor = PrivateInteractor() + var items: List = listOf() + var newItems: ArrayList = ArrayList() - var items: List = listOf() - var newItems: ArrayList = ArrayList() - - override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { - return DecksAllViewHolder(parent.inflate(R.layout.itemlist_deck), itemClick, itemLongClick) - } - - override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { - val deck = items[position] - (holder as DecksAllViewHolder).bind(deck, privateInteractor) - } + override fun onCreateDefaultViewHolder(parent: ViewGroup): RecyclerView.ViewHolder { + return DecksAllViewHolder(parent.inflate(R.layout.itemlist_deck), itemClick, itemLongClick) + } - override fun getDefaultItemCount(): Int = items.size + override fun onBindDefaultViewHolder(holder: RecyclerView.ViewHolder?, position: Int) { + val deck = items[position] + (holder as DecksAllViewHolder).bind(deck, privateInteractor) + } - fun clearItems() { - newItems.clear() - } + override fun getDefaultItemCount(): Int = items.size - fun showDecks(decks: List, last: Boolean) { - newItems.addAll(decks) - if (!last) { - return + fun clearItems() { + newItems.clear() } - Collections.sort(newItems, { d1, d2 -> d2.updatedAt.compareTo(d1.updatedAt) }) - val oldItems = items - items = newItems - if (items.isEmpty() || items.minus(oldItems).isEmpty()) { - notifyDataSetChanged() - return + + fun showDecks(decks: List, last: Boolean) { + newItems.addAll(decks) + if (!last) { + return + } + Collections.sort(newItems, { d1, d2 -> d2.updatedAt.compareTo(d1.updatedAt) }) + val oldItems = items + items = newItems + if (items.isEmpty() || items.minus(oldItems).isEmpty()) { + notifyDataSetChanged() + return + } + DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> + oldItem.id == newItem.id + }).dispatchUpdatesTo(this) } - DiffUtil.calculateDiff(SimpleDiffCallback(items, oldItems) { oldItem, newItem -> - oldItem.id == newItem.id - }).dispatchUpdatesTo(this) - } -} - -class DecksAllViewHolder(val view: View, val itemClick: (View, Deck) -> Unit, - val itemLongClick: (View, Deck) -> Boolean) : RecyclerView.ViewHolder(view) { - - fun bind(deck: Deck, privateInteractor: PrivateInteractor) { - itemView.setOnClickListener { itemClick(itemView, deck) } - itemView.setOnLongClickListener { itemLongClick(itemView, deck) } - itemView.deck_cover.setImageResource(deck.cls.imageRes) - itemView.deck_private.layoutParams.width = if (deck.private) ViewGroup.LayoutParams.WRAP_CONTENT else 0 - itemView.deck_name.text = deck.name - itemView.deck_attr1.setImageResource(deck.cls.attr1.imageRes) - itemView.deck_attr2.setImageResource(deck.cls.attr2.imageRes) - itemView.deck_type.text = deck.type.name.toLowerCase().capitalize() - itemView.deck_date.setCompoundDrawablesWithIntrinsicBounds(if (deck.updates.isEmpty()) - R.drawable.ic_create_at else R.drawable.ic_updated_at, 0, 0, 0) - itemView.deck_date.text = deck.updatedAt.toLocalDate().toString() - val numberInstance = NumberFormat.getNumberInstance() - itemView.deck_soul_cost.text = numberInstance.format(deck.cost) - itemView.deck_comments.text = numberInstance.format(deck.comments.size) - itemView.deck_likes.text = numberInstance.format(deck.likes.size) - itemView.deck_views.text = numberInstance.format(deck.views) - calculateMissingSoul(deck, privateInteractor) } - fun calculateMissingSoul(deck: Deck, interactor: PrivateInteractor) { - with(itemView.deck_soul_missing) { - visibility = View.INVISIBLE - itemView.deck_soul_missing_loading.visibility = View.VISIBLE - interactor.getMissingCards(deck, { itemView.deck_soul_missing_loading.visibility = View.VISIBLE }) { - itemView.deck_soul_missing_loading.visibility = View.GONE - val missingSoul = it.map { it.qtd * it.rarity.soulCost }.sum() - Timber.d("Missing %d", missingSoul) - text = NumberFormat.getNumberInstance().format(missingSoul) - visibility = View.VISIBLE + class DecksAllViewHolder(val view: View, val itemClick: (View, Deck) -> Unit, + val itemLongClick: (View, Deck) -> Boolean) : RecyclerView.ViewHolder(view) { + + fun bind(deck: Deck, privateInteractor: PrivateInteractor) { + itemView.setOnClickListener { itemClick(itemView, deck) } + itemView.setOnLongClickListener { itemLongClick(itemView, deck) } + itemView.deck_cover.setImageResource(deck.cls.imageRes) + itemView.deck_private.layoutParams.width = if (deck.private) ViewGroup.LayoutParams.WRAP_CONTENT else 0 + itemView.deck_name.text = deck.name + itemView.deck_attr1.setImageResource(deck.cls.attr1.imageRes) + itemView.deck_attr2.setImageResource(deck.cls.attr2.imageRes) + itemView.deck_type.text = deck.type.name.toLowerCase().capitalize() + itemView.deck_date.setCompoundDrawablesWithIntrinsicBounds(if (deck.updates.isEmpty()) + R.drawable.ic_create_at else R.drawable.ic_updated_at, 0, 0, 0) + itemView.deck_date.text = deck.updatedAt.toLocalDate().toString() + val numberInstance = NumberFormat.getNumberInstance() + itemView.deck_soul_cost.text = numberInstance.format(deck.cost) + itemView.deck_comments.text = numberInstance.format(deck.comments.size) + itemView.deck_likes.text = numberInstance.format(deck.likes.size) + itemView.deck_views.text = numberInstance.format(deck.views) + calculateMissingSoul(deck, privateInteractor) + } + + fun calculateMissingSoul(deck: Deck, interactor: PrivateInteractor) { + with(itemView.deck_soul_missing) { + visibility = View.INVISIBLE + itemView.deck_soul_missing_loading.visibility = View.VISIBLE + interactor.getMissingCards(deck, { itemView.deck_soul_missing_loading.visibility = View.VISIBLE }) { + itemView.deck_soul_missing_loading.visibility = View.GONE + val missingSoul = it.map { it.qtd * it.rarity.soulCost }.sum() + Timber.d("Missing %d", missingSoul) + text = NumberFormat.getNumberInstance().format(missingSoul) + visibility = View.VISIBLE + } } } + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/DeckList.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/DeckList.kt index 62b0a4c..e64e580 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/DeckList.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/DeckList.kt @@ -14,16 +14,18 @@ import android.view.ViewGroup import android.widget.LinearLayout import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.* -import com.ediposouza.teslesgendstracker.inflate import com.ediposouza.teslesgendstracker.interactor.PrivateInteractor import com.ediposouza.teslesgendstracker.interactor.PublicInteractor import com.ediposouza.teslesgendstracker.ui.CardActivity import com.ediposouza.teslesgendstracker.ui.decks.CmdRemAttr +import com.ediposouza.teslesgendstracker.util.inflate +import jp.wasabeef.recyclerview.animators.SlideInLeftAnimator import kotlinx.android.synthetic.main.itemlist_decklist_slot.view.* import kotlinx.android.synthetic.main.widget_decklist.view.* import org.greenrobot.eventbus.EventBus import org.jetbrains.anko.doAsync import org.jetbrains.anko.runOnUiThread +import java.util.* /** * Created by EdipoSouza on 11/2/16. @@ -34,8 +36,6 @@ class DeckList(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : var userFavorites = arrayListOf() var editMode = false - var onCardListChange: (() -> Unit)? = null - private fun showExpandedCard(card: Card, view: View) { val favorite = userFavorites.contains(card.shortName) val transitionName = context.getString(R.string.card_transition_name) @@ -44,13 +44,14 @@ class DeckList(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } val deckListAdapter by lazy { - DeckListAdapter(itemClick = { view, card -> - if (editMode) { - remCard(card) - } else { - showExpandedCard(card, view) - } - }) { + DeckListAdapter({ index -> decklist_recycle_view.scrollToPosition(index) }, + itemClick = { view, card -> + if (editMode) { + remCard(card) + } else { + showExpandedCard(card, view) + } + }) { view, card -> showExpandedCard(card, view) true @@ -60,6 +61,7 @@ class DeckList(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : init { inflate(context, R.layout.widget_decklist, this) decklist_recycle_view.adapter = deckListAdapter + decklist_recycle_view.itemAnimator = SlideInLeftAnimator() decklist_recycle_view.layoutManager = LinearLayoutManager(context) decklist_recycle_view.setHasFixedSize(true) if (isInEditMode) { @@ -71,17 +73,17 @@ class DeckList(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) - fun showDeck(deck: Deck) { + fun showDeck(deck: Deck, showSoulCost: Boolean = true) { + decklist_soul.visibility = if (showSoulCost) View.VISIBLE else View.GONE doAsync { PublicInteractor().getDeckCards(deck) { context.runOnUiThread { (decklist_recycle_view.adapter as DeckListAdapter).showDeck(it) + onCardListChange() } userFavorites.clear() PrivateInteractor().getFavoriteCards(null, deck.cls.attr1) { @@ -100,138 +102,163 @@ class DeckList(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : fun addCard(card: Card) { deckListAdapter.addCard(card) - onCardListChange?.invoke() + onCardListChange() + } + + fun addCards(cards: List) { + deckListAdapter.addCards(cards) + onCardListChange() } fun remCard(card: Card) { deckListAdapter.remCard(card) - onCardListChange?.invoke() + onCardListChange() } - fun getCards(): List { - return deckListAdapter.getCards() - } + fun getCards(): List = deckListAdapter.getCards() -} + fun getSoulCost(): Int = getCards().sumBy { (it.card.rarity.soulCost * it.qtd).toInt() } -class DeckListAdapter(val itemClick: (View, Card) -> Unit, val itemLongClick: (View, Card) -> Boolean) : RecyclerView.Adapter() { + private fun onCardListChange() { + val cards = getCards() + decklist_costs.updateCosts(cards) + decklist_qtd.text = context.getString(R.string.new_deck_card_list_qtd, cards.sumBy { it.qtd.toInt() }) + decklist_soul.text = getSoulCost().toString() + } - private val items = arrayListOf() - private var missingCards: List = listOf() + class DeckListAdapter(val onAdd: (Int) -> Unit, val itemClick: (View, Card) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeckListViewHolder { - return DeckListViewHolder(parent?.inflate(R.layout.itemlist_decklist_slot), itemClick, itemLongClick) - } + private val items = arrayListOf() + private var missingCards: List = listOf() - override fun onBindViewHolder(holder: DeckListViewHolder?, position: Int) { - val cardSlot = items[position] - val cardMissing = missingCards.find { it.shortName == cardSlot.card.shortName } - holder?.bind(cardSlot, cardMissing?.qtd ?: 0) - } + override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): DeckListViewHolder { + return DeckListViewHolder(parent?.inflate(R.layout.itemlist_decklist_slot), itemClick, itemLongClick) + } - override fun getItemCount(): Int = items.size + override fun onBindViewHolder(holder: DeckListViewHolder?, position: Int) { + val cardSlot = items[position] + val cardMissing = missingCards.find { it.shortName == cardSlot.card.shortName } + holder?.bind(cardSlot, cardMissing?.qtd ?: 0) + } - fun showDeck(cards: List) { - items.clear() - items.addAll(cards) - notifyDataSetChanged() - } + override fun getItemCount(): Int = items.size - fun showMissingCards(missingCards: List) { - this.missingCards = missingCards - notifyDataSetChanged() - } + fun showDeck(cards: List) { + items.clear() + items.addAll(cards.sorted()) + notifyDataSetChanged() + } - fun addCard(card: Card) { - val cardSlot = items.find { it.card == card } - if (cardSlot == null) { - items.add(CardSlot(card, 1)) + fun showMissingCards(missingCards: List) { + this.missingCards = missingCards notifyDataSetChanged() - } else { - val newQtd = if (cardSlot.qtd < 3) cardSlot.qtd.inc() else 3 - val cardIndex = items.indexOf(cardSlot) - items[cardIndex] = CardSlot(card, if (card.unique) 1 else newQtd) - notifyItemChanged(cardIndex) } - } - fun remCard(card: Card) { - val cardSlot = items.find { it.card == card } - if (cardSlot != null) { - val newQtd = cardSlot.qtd.dec() - if (newQtd <= 0) { - items.remove(cardSlot) - notifyDataSetChanged() - notifyCardRemoved(card) + fun addCard(card: Card) { + val cardSlot = items.find { it.card == card } + if (cardSlot == null) { + val newCardSlot = CardSlot(card, 1) + items.add(newCardSlot) + Collections.sort(items) + val newCardIndex = items.indexOf(newCardSlot) + onAdd(newCardIndex) + notifyItemInserted(newCardIndex) } else { + val newQtd = if (cardSlot.qtd < 3) cardSlot.qtd.inc() else 3 val cardIndex = items.indexOf(cardSlot) - items[cardIndex] = CardSlot(card, newQtd) + items[cardIndex] = CardSlot(card, if (card.unique) 1 else newQtd) + onAdd(cardIndex) notifyItemChanged(cardIndex) } } - } - private fun notifyCardRemoved(card: Card) { - when { - card.attr == Attribute.DUAL && items.filter { it.card.attr == card.dualAttr1 }.isEmpty() -> { - EventBus.getDefault().post(CmdRemAttr(card.dualAttr1)) - } - card.attr == Attribute.DUAL && items.filter { it.card.attr == card.dualAttr2 }.isEmpty() -> { - EventBus.getDefault().post(CmdRemAttr(card.dualAttr2)) + + fun addCards(cards: List) { + items.addAll(cards) + notifyDataSetChanged() + } + + fun remCard(card: Card) { + val cardSlot = items.find { it.card == card } + if (cardSlot != null) { + val newQtd = cardSlot.qtd.dec() + if (newQtd <= 0) { + val cardRemovedIndex = items.indexOf(cardSlot) + items.remove(cardSlot) + notifyItemRemoved(cardRemovedIndex) + notifyCardRemoved(card) + } else { + val cardIndex = items.indexOf(cardSlot) + items[cardIndex] = CardSlot(card, newQtd) + notifyItemChanged(cardIndex) + } } - items.filter { it.card.dualAttr1 == card.attr || it.card.dualAttr2 == card.attr }.isEmpty() -> { - EventBus.getDefault().post(CmdRemAttr(card.attr)) + } + + private fun notifyCardRemoved(card: Card) { + when { + card.attr == Attribute.DUAL && items.filter { it.card.attr == card.dualAttr1 }.isEmpty() -> { + EventBus.getDefault().post(CmdRemAttr(card.dualAttr1)) + } + card.attr == Attribute.DUAL && items.filter { it.card.attr == card.dualAttr2 }.isEmpty() -> { + EventBus.getDefault().post(CmdRemAttr(card.dualAttr2)) + } + items.filter { it.card.dualAttr1 == card.attr || it.card.dualAttr2 == card.attr }.isEmpty() -> { + EventBus.getDefault().post(CmdRemAttr(card.attr)) + } } } - } - fun getCards(): List { - return items + fun getCards(): List { + return items + } + } -} + class DeckListViewHolder(view: View?, val itemClick: (View, Card) -> Unit, + val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { -class DeckListViewHolder(view: View?, val itemClick: (View, Card) -> Unit, - val itemLongClick: (View, Card) -> Boolean) : RecyclerView.ViewHolder(view) { - - fun bind(slot: CardSlot, missingQtd: Long) { - itemView.setOnClickListener { itemClick.invoke(itemView.deckslot_card_image, slot.card) } - itemView.setOnLongClickListener { itemLongClick.invoke(itemView.deckslot_card_image, slot.card) } - itemView.deckslot_card_image.setImageBitmap(getCroppedCardImage(slot)) - itemView.decl_slot_card_name.text = slot.card.name - itemView.deckslot_card_rarity.setImageResource(slot.card.rarity.imageRes) - itemView.deckslot_card_magika.setImageResource(when (slot.card.cost) { - 0 -> R.drawable.ic_magika_0 - 1 -> R.drawable.ic_magika_1 - 2 -> R.drawable.ic_magika_2 - 3 -> R.drawable.ic_magika_3 - 4 -> R.drawable.ic_magika_4 - 5 -> R.drawable.ic_magika_5 - 6 -> R.drawable.ic_magika_6 - else -> R.drawable.ic_magika_7plus - }) - itemView.deckslot_card_qtd.text = slot.qtd.toString() - itemView.deckslot_card_qtd.visibility = if (slot.qtd > 0) View.VISIBLE else View.INVISIBLE - itemView.deckslot_card_qtd_layout.visibility = if (slot.qtd > 0) View.VISIBLE else View.INVISIBLE - itemView.deckslot_card_qtd_missing.text = "-$missingQtd" - itemView.deckslot_card_qtd_missing.visibility = if (missingQtd > 0) View.VISIBLE else View.INVISIBLE - } + fun bind(slot: CardSlot, missingQtd: Int) { + itemView.setOnClickListener { itemClick.invoke(itemView.deckslot_card_image, slot.card) } + itemView.setOnLongClickListener { itemLongClick.invoke(itemView.deckslot_card_image, slot.card) } + itemView.deckslot_card_image.setImageBitmap(getCroppedCardImage(slot)) + itemView.decl_slot_card_name.text = slot.card.name + itemView.deckslot_card_rarity.setImageResource(slot.card.rarity.imageRes) + itemView.deckslot_card_magika.setImageResource(when (slot.card.cost) { + 0 -> R.drawable.ic_magika_0 + 1 -> R.drawable.ic_magika_1 + 2 -> R.drawable.ic_magika_2 + 3 -> R.drawable.ic_magika_3 + 4 -> R.drawable.ic_magika_4 + 5 -> R.drawable.ic_magika_5 + 6 -> R.drawable.ic_magika_6 + else -> R.drawable.ic_magika_7plus + }) + itemView.deckslot_card_qtd.text = slot.qtd.toString() + itemView.deckslot_card_qtd.visibility = if (slot.qtd > 0) View.VISIBLE else View.INVISIBLE + itemView.deckslot_card_qtd_layout.visibility = if (slot.qtd > 0) View.VISIBLE else View.INVISIBLE + itemView.deckslot_card_qtd_missing.text = "-$missingQtd" + itemView.deckslot_card_qtd_missing.visibility = if (missingQtd > 0) View.VISIBLE else View.INVISIBLE + } - private fun getCroppedCardImage(slot: CardSlot): Bitmap { - val resources = itemView.resources - var cardBitmap: Bitmap - try { - cardBitmap = slot.card.imageBitmap(itemView.context) - } catch (e: Exception) { - cardBitmap = BitmapFactory.decodeResource(resources, R.drawable.card) + private fun getCroppedCardImage(slot: CardSlot): Bitmap { + val resources = itemView.resources + var cardBitmap: Bitmap + try { + cardBitmap = slot.card.imageBitmap(itemView.context) + } catch (e: Exception) { + cardBitmap = BitmapFactory.decodeResource(resources, R.drawable.card) + } + val bmpWidth = cardBitmap.width + val bmpHeight = cardBitmap.height + val leftCropMargin = resources.getInteger(R.integer.decklist_slot_cover_left_crop_margin) + val rightCropMargin = resources.getInteger(R.integer.decklist_slot_cover_right_crop_margin) + val cropWidth = bmpWidth - leftCropMargin - rightCropMargin + val cropeBitmap = Bitmap.createBitmap(cardBitmap, leftCropMargin, 0, cropWidth, bmpHeight * 2 / 3) + return cropeBitmap } - val bmpWidth = cardBitmap.width - val bmpHeight = cardBitmap.height - val leftCropMargin = resources.getInteger(R.integer.decklist_slot_cover_left_crop_margin) - val rightCropMargin = resources.getInteger(R.integer.decklist_slot_cover_right_crop_margin) - val cropWidth = bmpWidth - leftCropMargin - rightCropMargin - val cropeBitmap = Bitmap.createBitmap(cardBitmap, leftCropMargin, 0, cropWidth, bmpHeight * 2 / 3) - return cropeBitmap + } -} \ No newline at end of file +} diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/MagikaCosts.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/MagikaCosts.kt index e9d5504..efbe49c 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/MagikaCosts.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/decks/widget/MagikaCosts.kt @@ -1,4 +1,4 @@ -package com.ediposouza.teslesgendstracker.ui.widget.filter +package com.ediposouza.teslesgendstracker.ui.decks.widget import android.content.Context import android.util.AttributeSet @@ -71,11 +71,9 @@ class MagikaCosts(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) fun updateCosts(cards: List) { magikaCost0Qtd = cards.filter { it.card.cost == 0 }.sumBy { it.qtd.toInt() } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/AutoHideBehaviour.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/AutoHideBehaviour.kt similarity index 77% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/AutoHideBehaviour.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/AutoHideBehaviour.kt index cd4adc2..3a2b57f 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/AutoHideBehaviour.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/AutoHideBehaviour.kt @@ -1,12 +1,13 @@ -package com.ediposouza.teslesgendstracker.ui.utils +package com.ediposouza.teslesgendstracker.ui.util import android.content.Context import android.support.design.widget.CoordinatorLayout import android.support.v4.view.ViewCompat import android.util.AttributeSet import android.view.View -import com.ediposouza.teslesgendstracker.ui.base.CmdUpdateRarityMagikaFiltersVisibility +import com.ediposouza.teslesgendstracker.ui.base.CmdUpdateVisibility import org.greenrobot.eventbus.EventBus +import timber.log.Timber /** @@ -15,10 +16,9 @@ import org.greenrobot.eventbus.EventBus class AutoHideBehaviour(context: Context?, attrs: AttributeSet?) : CoordinatorLayout.Behavior(context, attrs) { - val eventBus by lazy { EventBus.getDefault() } + val eventBus: EventBus by lazy { EventBus.getDefault() } - constructor() : this(null, null) { - } + constructor() : this(null, null) override fun onStartNestedScroll(coordinatorLayout: CoordinatorLayout, child: View, directTargetChild: View, target: View, nestedScrollAxes: Int): Boolean { @@ -32,10 +32,12 @@ class AutoHideBehaviour(context: Context?, attrs: AttributeSet?) : super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed) if (dyConsumed > 0) { // User scrolled down and the FAB is currently visible -> hide the FAB - eventBus.post(CmdUpdateRarityMagikaFiltersVisibility(false)) + Timber.d("Scroll Down") + eventBus.post(CmdUpdateVisibility(false)) } else if (dyConsumed < 0) { // User scrolled up and the FAB is currently not visible -> show the FAB - eventBus.post(CmdUpdateRarityMagikaFiltersVisibility(true)) + Timber.d("Scroll Up") + eventBus.post(CmdUpdateVisibility(true)) } } diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/CircleTransform.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/CircleTransform.kt similarity index 96% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/CircleTransform.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/CircleTransform.kt index 137e232..770b09d 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/CircleTransform.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/CircleTransform.kt @@ -4,7 +4,7 @@ * Copyright (c) 2016 Beauty Date. All rights reserved. */ -package com.ediposouza.teslesgendstracker.ui.utils +package com.ediposouza.teslesgendstracker.ui.util import android.content.Context import android.graphics.* diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/GridSpacingItemDecoration.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/GridSpacingItemDecoration.kt similarity index 96% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/GridSpacingItemDecoration.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/GridSpacingItemDecoration.kt index 886c4a9..2929818 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/GridSpacingItemDecoration.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/GridSpacingItemDecoration.kt @@ -1,4 +1,4 @@ -package com.ediposouza.teslesgendstracker.ui.utils +package com.ediposouza.teslesgendstracker.ui.util import android.graphics.Rect import android.support.v7.widget.RecyclerView diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/SimpleDiffCallback.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/SimpleDiffCallback.kt similarity index 93% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/SimpleDiffCallback.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/SimpleDiffCallback.kt index 5c50c1c..40bfb8f 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/utils/SimpleDiffCallback.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/util/SimpleDiffCallback.kt @@ -1,4 +1,4 @@ -package com.ediposouza.teslesgendstracker.ui.utils +package com.ediposouza.teslesgendstracker.ui.util import android.support.v7.util.DiffUtil diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatistics.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatistics.kt index 1d7d651..cbc8dd5 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatistics.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatistics.kt @@ -3,6 +3,7 @@ package com.ediposouza.teslesgendstracker.ui.widget import android.content.Context import android.os.Build import android.util.AttributeSet +import android.view.MotionEvent import android.widget.FrameLayout import com.ediposouza.teslesgendstracker.R import com.ediposouza.teslesgendstracker.data.Attribute @@ -31,10 +32,12 @@ class CollectionStatistics(ctx: Context?, attrs: AttributeSet?, defStyleAttr: In } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) + + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { + override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { + return true } fun scrollToTop() { @@ -82,7 +85,7 @@ class CollectionStatistics(ctx: Context?, attrs: AttributeSet?, defStyleAttr: In publicInteractor.getCardsForStatistics(null, attr) { val allAttrCards = it.groupBy { it.rarity } Timber.d(attr.name + allAttrCards.toString()) - privateInteractor.getUserCollection(null, attr) { collection: Map -> + privateInteractor.getUserCollection(null, attr) { collection: Map -> val userAttrCards = allAttrCards.map { it.key to it.value.filter { collection.containsKey(it.shortName) } .map { it to collection[it.shortName] } @@ -91,13 +94,13 @@ class CollectionStatistics(ctx: Context?, attrs: AttributeSet?, defStyleAttr: In val allRarityCards = it.value val userRarityCards = userAttrCards[it.key] Timber.d("${attr.name} - $it: $userRarityCards") - val owned = userRarityCards?.map { it.second ?: 0L }?.sum() ?: 0L + val owned = userRarityCards?.map { it.second ?: 0 }?.sum() ?: 0 when (it.key) { - CardRarity.COMMON -> statisticsAttr(attr).setCommon(owned, allRarityCards.size * 3L) - CardRarity.RARE -> statisticsAttr(attr).setRare(owned, allRarityCards.size * 3L) - CardRarity.EPIC -> statisticsAttr(attr).setEpic(owned, allRarityCards.size * 3L) + CardRarity.COMMON -> statisticsAttr(attr).setCommon(owned, allRarityCards.size * 3) + CardRarity.RARE -> statisticsAttr(attr).setRare(owned, allRarityCards.size * 3) + CardRarity.EPIC -> statisticsAttr(attr).setEpic(owned, allRarityCards.size * 3) CardRarity.LEGENDARY -> { - val legendaryTotal = allRarityCards.map { if (it.unique) 1L else 3L }.sum() + val legendaryTotal = allRarityCards.map { if (it.unique) 1 else 3 }.sum() statisticsAttr(attr).setLegendary(owned, legendaryTotal) } else -> { diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatisticsAttr.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatisticsAttr.kt index 054c330..9b35308 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatisticsAttr.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/CollectionStatisticsAttr.kt @@ -15,12 +15,12 @@ class CollectionStatisticsAttr(ctx: Context?, attrs: AttributeSet?, defStyleAttr LinearLayout(ctx, attrs, defStyleAttr) { private var attribute = Attribute.STRENGTH - private val cards = hashMapOf(CardRarity.COMMON to Pair(0L, 0L), CardRarity.RARE to Pair(0L, 0L), - CardRarity.EPIC to Pair(0L, 0L), CardRarity.LEGENDARY to Pair(0L, 0L)) + private val cards = hashMapOf(CardRarity.COMMON to Pair(0, 0), CardRarity.RARE to Pair(0, 0), + CardRarity.EPIC to Pair(0, 0), CardRarity.LEGENDARY to Pair(0, 0)) - var soulMissing: Long = 0 - var owned: Long = 0 - var total: Long = 0 + var soulMissing: Int = 0 + var owned: Int = 0 + var total: Int = 0 init { inflate(context, R.layout.widget_collection_statistics_attr, this) @@ -32,31 +32,29 @@ class CollectionStatisticsAttr(ctx: Context?, attrs: AttributeSet?, defStyleAttr } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) - fun setCommon(owned: Long, total: Long) { + fun setCommon(owned: Int, total: Int) { attr_statistics_common.text = context.getString(R.string.statistics_rarity, owned, total) cards[CardRarity.COMMON] = Pair(owned, total) updateTotal() } - fun setRare(owned: Long, total: Long) { + fun setRare(owned: Int, total: Int) { attr_statistics_rare.text = context.getString(R.string.statistics_rarity, owned, total) cards[CardRarity.RARE] = Pair(owned, total) updateTotal() } - fun setEpic(owned: Long, total: Long) { + fun setEpic(owned: Int, total: Int) { attr_statistics_epic.text = context.getString(R.string.statistics_rarity, owned, total) cards[CardRarity.EPIC] = Pair(owned, total) updateTotal() } - fun setLegendary(owned: Long, total: Long) { + fun setLegendary(owned: Int, total: Int) { attr_statistics_legendary.text = context.getString(R.string.statistics_rarity, owned, total) cards[CardRarity.LEGENDARY] = Pair(owned, total) updateTotal() diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/InsetFrameCoordinatorLayout.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/InsetFrameCoordinatorLayout.kt new file mode 100644 index 0000000..770f261 --- /dev/null +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/InsetFrameCoordinatorLayout.kt @@ -0,0 +1,32 @@ +package com.ediposouza.teslesgendstracker.ui.widget + +import android.content.Context +import android.os.Build.VERSION +import android.os.Build.VERSION_CODES +import android.support.design.widget.CoordinatorLayout +import android.util.AttributeSet +import android.view.WindowInsets + +/** + * Created by EdipoSouza on 12/28/16. + */ +class InsetFrameCoordinatorLayout(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : + CoordinatorLayout(ctx, attrs, defStyleAttr) { + + private val mInsets = IntArray(4) + + constructor(ctx: Context?) : this(ctx, null, 0) + + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) + + override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets { + if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + mInsets[0] = insets.systemWindowInsetLeft + mInsets[1] = insets.systemWindowInsetTop + mInsets[2] = insets.systemWindowInsetRight + return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom)) + } else { + return insets + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/NestedCoordinatorLayout.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/NestedCoordinatorLayout.kt index 24829f0..18a716c 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/NestedCoordinatorLayout.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/NestedCoordinatorLayout.kt @@ -15,16 +15,12 @@ import android.view.View /** * Created by ediposouza on 1/22/16. */ -class NestedCoordinatorLayout : CoordinatorLayout, NestedScrollingParent { +class NestedCoordinatorLayout(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : + CoordinatorLayout(context, attrs, defStyleAttr), NestedScrollingParent { - constructor(context: Context) : super(context) { - } - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - } + constructor(context: Context) : this(context, null, 0) - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - } + constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0) override fun onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int): Boolean { parentCoordinatorLayout.onStartNestedScroll(child, target, nestedScrollAxes) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttr.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttr.kt index c07aed9..36362e8 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttr.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttr.kt @@ -47,11 +47,9 @@ open class FilterAttr(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) open protected fun attrClick(attr: Attribute, lockable: Boolean) { filterClick?.invoke(attr) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttrLockable.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttrLockable.kt index 247fa92..2f3a470 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttrLockable.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterAttrLockable.kt @@ -20,11 +20,9 @@ class FilterAttrLockable(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) var onAttrLock: ((Attribute, Attribute) -> Unit)? = null var onAttrUnlock: (() -> Unit)? = null - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) override fun attrClick(attr: Attribute, lockable: Boolean) { if (isLocked() && isAttrBasic(attr) && lockable) { diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterMagika.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterMagika.kt index 72e0110..8d23cce 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterMagika.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterMagika.kt @@ -40,11 +40,9 @@ class FilterMagika(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) private fun magikaClick(magika: Int) { filterClick?.invoke(magika) diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterRarity.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterRarity.kt index a55a2e6..2cd33a9 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterRarity.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/ui/widget/filter/FilterRarity.kt @@ -44,11 +44,9 @@ class FilterRarity(ctx: Context?, attrs: AttributeSet?, defStyleAttr: Int) : } } - constructor(ctx: Context?) : this(ctx, null, 0) { - } + constructor(ctx: Context?) : this(ctx, null, 0) - constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) { - } + constructor(ctx: Context?, attrs: AttributeSet) : this(ctx, attrs, 0) private fun expand() { with(rootView) { diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/AppExtensions.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/AppExtensions.kt similarity index 83% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/AppExtensions.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/AppExtensions.kt index d1f36cf..7b6b29d 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/AppExtensions.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/AppExtensions.kt @@ -1,4 +1,4 @@ -package com.ediposouza.teslesgendstracker +package com.ediposouza.teslesgendstracker.util import android.content.Context import android.os.Bundle @@ -7,6 +7,7 @@ import android.support.design.widget.BottomSheetBehavior import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import com.ediposouza.teslesgendstracker.R import com.google.android.gms.ads.AdRequest import com.google.android.gms.ads.AdView import com.google.android.gms.ads.NativeExpressAdView @@ -29,17 +30,17 @@ fun ViewGroup.inflate(@IntegerRes resource: Int): View { return LayoutInflater.from(context).inflate(resource, this, false) } -fun BottomSheetBehavior<*>.toogleExpanded() { +fun BottomSheetBehavior<*>.toggleExpanded() { this.state = if (this.state == BottomSheetBehavior.STATE_COLLAPSED) BottomSheetBehavior.STATE_EXPANDED else BottomSheetBehavior.STATE_COLLAPSED } fun AdView.load() { - this.loadAd(createAdRequest(context)) + this.loadAd(com.ediposouza.teslesgendstracker.util.createAdRequest(context)) } fun NativeExpressAdView.load() { - this.loadAd(createAdRequest(context)) + this.loadAd(com.ediposouza.teslesgendstracker.util.createAdRequest(context)) } private fun createAdRequest(context: Context): AdRequest { diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/ConfigManager.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/ConfigManager.kt new file mode 100644 index 0000000..7d54b58 --- /dev/null +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/ConfigManager.kt @@ -0,0 +1,54 @@ +package com.ediposouza.teslesgendstracker.util + +import com.ediposouza.teslesgendstracker.App +import com.ediposouza.teslesgendstracker.BuildConfig +import com.ediposouza.teslesgendstracker.DEFAULT_DELIMITER +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings + +/** + * Created by EdipoSouza on 12/30/16. + */ +object ConfigManager { + + val DB_UPDATE_CONFIG = "db_update" + val VERSION_UNSUPPORTED_CONFIG = "version_unsupported" + + val remoteConfig: FirebaseRemoteConfig by lazy { FirebaseRemoteConfig.getInstance() } + + init { + with(remoteConfig) { + setConfigSettings(FirebaseRemoteConfigSettings.Builder() + .setDeveloperModeEnabled(BuildConfig.DEBUG) + .build()) + setDefaults(mapOf(DB_UPDATE_CONFIG to false, + VERSION_UNSUPPORTED_CONFIG to "")) + } + updateCaches {} + } + + fun updateCaches(onComplete: () -> Unit) { + with(remoteConfig) { + fetch(1).addOnCompleteListener { + if (it.isSuccessful) { + activateFetched() + onComplete() + } + } + } + } + + fun isDBUpdating() = remoteConfig.getBoolean(DB_UPDATE_CONFIG) + + fun isVersionUnsupported(): Boolean { + val unsupportedVersions = remoteConfig.getString(VERSION_UNSUPPORTED_CONFIG) + if (unsupportedVersions.isEmpty()) { + return false + } + if (!unsupportedVersions.contains(DEFAULT_DELIMITER)) { + return unsupportedVersions == App.getVersion() + } + return unsupportedVersions.split(DEFAULT_DELIMITER).map(String::trim).contains(App.getVersion()) + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/MetricsConstants.kt b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/MetricsConstants.kt similarity index 93% rename from app/src/main/kotlin/com/ediposouza/teslesgendstracker/MetricsConstants.kt rename to app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/MetricsConstants.kt index cfdaaae..2c9628f 100644 --- a/app/src/main/kotlin/com/ediposouza/teslesgendstracker/MetricsConstants.kt +++ b/app/src/main/kotlin/com/ediposouza/teslesgendstracker/util/MetricsConstants.kt @@ -1,9 +1,9 @@ -package com.ediposouza.teslesgendstracker +package com.ediposouza.teslesgendstracker.util /** * Created by ediposouza on 08/12/16. */ -abstract class MetricsConstants() { +abstract class MetricsConstants { companion object { @@ -71,6 +71,9 @@ sealed class MetricAction(val name: String) { } } + class ACTION_NOTIFY_UPDATE : MetricAction("NotifyUpdate") + class ACTION_VERSION_UNSUPPORTED : MetricAction("VersionUnsupported") + } sealed class MetricScreen(val name: String) { diff --git a/app/src/main/res/drawable-nodpi/ic_legend.png b/app/src/main/res/drawable-nodpi/ic_legend.png new file mode 100644 index 0000000..83d3d82 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/ic_legend.png differ diff --git a/app/src/main/res/drawable/ic_statistics.xml b/app/src/main/res/drawable/ic_delete_red.xml similarity index 66% rename from app/src/main/res/drawable/ic_statistics.xml rename to app/src/main/res/drawable/ic_delete_red.xml index 77fab7d..7d3c2b4 100644 --- a/app/src/main/res/drawable/ic_statistics.xml +++ b/app/src/main/res/drawable/ic_delete_red.xml @@ -1,4 +1,4 @@ - + diff --git a/app/src/main/res/drawable/ic_delete_red_svg.xml b/app/src/main/res/drawable/ic_delete_red_svg.xml new file mode 100644 index 0000000..17928bd --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_red_svg.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/drawable/ic_private_menu_checked_svg.xml b/app/src/main/res/drawable/ic_private_menu_checked_svg.xml index eaac636..d0ff80e 100644 --- a/app/src/main/res/drawable/ic_private_menu_checked_svg.xml +++ b/app/src/main/res/drawable/ic_private_menu_checked_svg.xml @@ -5,6 +5,6 @@ android:viewportHeight="12" android:viewportWidth="12"> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_private_svg.xml b/app/src/main/res/drawable/ic_private_svg.xml index eb7bb0a..26085d4 100644 --- a/app/src/main/res/drawable/ic_private_svg.xml +++ b/app/src/main/res/drawable/ic_private_svg.xml @@ -5,6 +5,6 @@ android:viewportHeight="24" android:viewportWidth="24"> \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_send.xml b/app/src/main/res/drawable/ic_send.xml new file mode 100644 index 0000000..e96cb7f --- /dev/null +++ b/app/src/main/res/drawable/ic_send.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/ic_send_svg.xml b/app/src/main/res/drawable/ic_send_svg.xml new file mode 100644 index 0000000..6dcc835 --- /dev/null +++ b/app/src/main/res/drawable/ic_send_svg.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/drawable/ic_statistics_svg.xml b/app/src/main/res/drawable/ic_statistics_svg.xml deleted file mode 100644 index 2936299..0000000 --- a/app/src/main/res/drawable/ic_statistics_svg.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/xml_switch.xml b/app/src/main/res/drawable/xml_switch.xml index 11f4645..5d0e232 100644 --- a/app/src/main/res/drawable/xml_switch.xml +++ b/app/src/main/res/drawable/xml_switch.xml @@ -1,5 +1,5 @@ -> + @@ -9,37 +9,32 @@ - + - - - - - - - - - + + + + + + + + - - - - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_card.xml b/app/src/main/res/layout/activity_card.xml index 25828b3..8b3694f 100644 --- a/app/src/main/res/layout/activity_card.xml +++ b/app/src/main/res/layout/activity_card.xml @@ -5,6 +5,7 @@ android:id="@+id/coordinatorLayout" android:layout_width="match_parent" android:layout_height="match_parent" + android:animateLayoutChanges="true" tools:context="com.ediposouza.teslesgendstracker.ui.CardActivity"> + tools:text="@string/app_name_full" /> @@ -44,7 +44,7 @@ android:layout_height="match_parent"> @@ -68,19 +68,39 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" /> + + + + diff --git a/app/src/main/res/layout/activity_deck.xml b/app/src/main/res/layout/activity_deck.xml index 0374ba6..c2cdedf 100644 --- a/app/src/main/res/layout/activity_deck.xml +++ b/app/src/main/res/layout/activity_deck.xml @@ -1,10 +1,11 @@ - @@ -90,9 +91,9 @@ android:id="@+id/deck_details_create_by_photo" android:layout_width="@dimen/size_small" android:layout_height="@dimen/size_small" - android:layout_marginStart="@dimen/large_margin" android:layout_alignBottom="@id/deck_class_attr2" android:layout_marginBottom="@dimen/nano_margin" + android:layout_marginStart="@dimen/large_margin" android:layout_toEndOf="@id/deck_class_attr2" android:src="@drawable/ic_user" /> @@ -101,9 +102,9 @@ style="@style/DeckInfoItem" android:layout_width="wrap_content" android:layout_height="@dimen/size_small" - android:layout_marginStart="@dimen/default_margin" android:layout_alignTop="@id/deck_class_attr2" android:layout_marginBottom="@dimen/default_margin" + android:layout_marginStart="@dimen/default_margin" android:layout_toEndOf="@id/deck_details_create_by_photo" tools:text="Édipo Souza" /> @@ -116,7 +117,7 @@ @@ -131,9 +132,10 @@ android:layout_marginStart="@dimen/large_margin" android:clickable="true" android:elevation="@dimen/cardview_default_elevation" + android:fitsSystemWindows="false" android:foreground="?attr/selectableItemBackground" app:behavior_hideable="true" - app:behavior_peekHeight="@dimen/card_bottom_sheet_peek_heigth" + app:behavior_peekHeight="@dimen/deck_comment_bottom_sheet_peek_height" app:layout_behavior="@string/bottom_sheet_behavior"> + + + android:layout_margin="@dimen/default_margin" + android:fadeScrollbars="false" + android:scrollbarSize="@dimen/small_margin" + android:scrollbarThumbVertical="@drawable/scrollbar_thumb" + android:scrollbars="vertical" + app:layoutManager="LinearLayoutManager" + tools:listitem="@layout/itemlist_deck_comment" /> + + + + @@ -186,4 +224,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_new_deck.xml b/app/src/main/res/layout/activity_new_deck.xml index 9c61c3b..f73f654 100644 --- a/app/src/main/res/layout/activity_new_deck.xml +++ b/app/src/main/res/layout/activity_new_deck.xml @@ -1,5 +1,5 @@ - + app:layout_behavior="com.ediposouza.teslesgendstracker.ui.util.AutoHideBehaviour"> + tools:text="@string/app_name_full" /> @@ -73,68 +73,35 @@ android:layout_below="@id/new_deck_attr_filter" app:layout_widthPercent="65%" /> - - - - - - - - - - - + app:layout_widthPercent="35%" /> - + android:layout_gravity="bottom|center" + android:paddingStart="@dimen/huge_margin" + android:layout_marginStart="@dimen/huge_margin" + android:layout_marginBottom="@dimen/large_margin" /> - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cards.xml b/app/src/main/res/layout/fragment_cards.xml index 421a823..67f48cb 100644 --- a/app/src/main/res/layout/fragment_cards.xml +++ b/app/src/main/res/layout/fragment_cards.xml @@ -1,35 +1,20 @@ - + android:orientation="vertical" + app:layout_behavior="com.ediposouza.teslesgendstracker.ui.util.AutoHideBehaviour"> - + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/default_margin" /> - - - - - - - + android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cards_list.xml b/app/src/main/res/layout/fragment_cards_list.xml index f02c1c8..44b38d5 100644 --- a/app/src/main/res/layout/fragment_cards_list.xml +++ b/app/src/main/res/layout/fragment_cards_list.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/default_margin" - android:scrollbarFadeDuration="0" + android:fadeScrollbars="false" android:scrollbarSize="@dimen/small_margin" android:scrollbarThumbVertical="@drawable/scrollbar_thumb" android:scrollbars="vertical" diff --git a/app/src/main/res/layout/fragment_decks.xml b/app/src/main/res/layout/fragment_decks.xml index a31c072..3a664a7 100644 --- a/app/src/main/res/layout/fragment_decks.xml +++ b/app/src/main/res/layout/fragment_decks.xml @@ -1,37 +1,21 @@ - + android:orientation="vertical" + app:layout_behavior="com.ediposouza.teslesgendstracker.ui.util.AutoHideBehaviour"> - - - - - - - - - + android:layout_marginTop="@dimen/default_margin" + app:deckMode="true" /> + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_decks_list.xml b/app/src/main/res/layout/fragment_decks_list.xml index b6f228d..6b0cb58 100644 --- a/app/src/main/res/layout/fragment_decks_list.xml +++ b/app/src/main/res/layout/fragment_decks_list.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/default_margin" - android:scrollbarFadeDuration="0" + android:fadeScrollbars="false" android:scrollbarSize="@dimen/small_margin" android:scrollbarThumbVertical="@drawable/scrollbar_thumb" android:scrollbars="vertical" diff --git a/app/src/main/res/layout/fragment_decks_list_owner.xml b/app/src/main/res/layout/fragment_decks_list_owner.xml index 9dc882a..ee15497 100644 --- a/app/src/main/res/layout/fragment_decks_list_owner.xml +++ b/app/src/main/res/layout/fragment_decks_list_owner.xml @@ -15,7 +15,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/default_margin" - android:scrollbarFadeDuration="0" + android:fadeScrollbars="false" android:scrollbars="vertical" app:layoutManager="LinearLayoutManager" tools:listitem="@layout/itemlist_deck" /> diff --git a/app/src/main/res/layout/include_deck_info.xml b/app/src/main/res/layout/include_deck_info.xml index e677046..95630ae 100644 --- a/app/src/main/res/layout/include_deck_info.xml +++ b/app/src/main/res/layout/include_deck_info.xml @@ -1,17 +1,23 @@ + android:layout_weight="1" + android:fadeScrollbars="false" + android:scrollbarSize="@dimen/small_margin" + android:scrollbarThumbVertical="@drawable/scrollbar_thumb" + android:scrollbars="vertical" + app:layout_widthPercent="50%"> \ No newline at end of file diff --git a/app/src/main/res/layout/itemlist_deck_comment.xml b/app/src/main/res/layout/itemlist_deck_comment.xml index 6065130..969d50d 100644 --- a/app/src/main/res/layout/itemlist_deck_comment.xml +++ b/app/src/main/res/layout/itemlist_deck_comment.xml @@ -2,41 +2,64 @@ + + + tools:text="Édipo da Silva Souza" + tools:textColor="@android:color/white" /> + android:maxLines="5" + android:textColor="@color/primary_text_dark" + tools:text="Amazing deck with some awesome features that I never expected" + tools:textColor="@android:color/white" /> + tools:text="10/11/2016\n18h35" + tools:textColor="@android:color/white" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_collection_statistics.xml b/app/src/main/res/layout/widget_collection_statistics.xml index 209b1e5..3ea8969 100644 --- a/app/src/main/res/layout/widget_collection_statistics.xml +++ b/app/src/main/res/layout/widget_collection_statistics.xml @@ -1,14 +1,12 @@ - @@ -16,7 +14,7 @@ android:id="@+id/collection_statistics_container" android:layout_width="match_parent" android:layout_height="match_parent" - android:scrollbarFadeDuration="0" + android:fadeScrollbars="false" android:scrollbars="vertical"> - \ No newline at end of file + android:gravity="center_horizontal" + android:orientation="vertical"> + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_cards_collection.xml b/app/src/main/res/menu/menu_cards_collection.xml deleted file mode 100644 index adb321b..0000000 --- a/app/src/main/res/menu/menu_cards_collection.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/menu/menu_deck_owned.xml b/app/src/main/res/menu/menu_deck_owner.xml similarity index 100% rename from app/src/main/res/menu/menu_deck_owned.xml rename to app/src/main/res/menu/menu_deck_owner.xml diff --git a/app/src/main/res/menu/menu_decks_owner.xml b/app/src/main/res/menu/menu_decks_owned.xml similarity index 100% rename from app/src/main/res/menu/menu_decks_owner.xml rename to app/src/main/res/menu/menu_decks_owned.xml diff --git a/app/src/main/res/values-hdpi/dimens.xml b/app/src/main/res/values-hdpi/dimens.xml index 121f4ee..f2d22f8 100644 --- a/app/src/main/res/values-hdpi/dimens.xml +++ b/app/src/main/res/values-hdpi/dimens.xml @@ -5,5 +5,6 @@ 6dp 10dp 14dp + 20dp diff --git a/app/src/main/res/values-xhdpi/dimens.xml b/app/src/main/res/values-xhdpi/dimens.xml index 3da5ab3..d923b4c 100644 --- a/app/src/main/res/values-xhdpi/dimens.xml +++ b/app/src/main/res/values-xhdpi/dimens.xml @@ -5,5 +5,6 @@ 7dp 11dp 15dp + 22dp diff --git a/app/src/main/res/values-xxhdpi/dimens.xml b/app/src/main/res/values-xxhdpi/dimens.xml index 2aef4ff..2b6e19e 100644 --- a/app/src/main/res/values-xxhdpi/dimens.xml +++ b/app/src/main/res/values-xxhdpi/dimens.xml @@ -5,5 +5,6 @@ 8dp 12dp 16dp + 24dp diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 6557e59..b12b153 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -31,18 +31,20 @@ @dimen/default_margin 56dp + 42dp 260dp 48dp @dimen/small_margin 48dp @dimen/default_margin 4dp - @dimen/default_margin + 32dp + @dimen/medium_margin 24dp @dimen/status_bar_height - 88dp + 84dp @dimen/navigation_bar_height @@ -54,6 +56,8 @@ 140dp 32dp + 88dp + 56dp 32dp 16dp 12dp diff --git a/app/src/main/res/values/numbers.xml b/app/src/main/res/values/numbers.xml index 7627a5b..96c55f2 100644 --- a/app/src/main/res/values/numbers.xml +++ b/app/src/main/res/values/numbers.xml @@ -1,7 +1,7 @@ 0.3 - 0.6 + 0.7 0.7 500 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17e827d..0df728a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ - TES Legends Tracker + TESL Tracker + TES Legends Tracker ca-app-pub-7881623561544201/7976661172 360x80 ca-app-pub-7881623561544201/1511325179 @@ -8,6 +9,10 @@ ca-app-pub-7881623561544201/2208682379 ca-app-pub-7881623561544201/6037962770 240x50 + Press again to exit + TESL Tracker database is under update. You will be notified when it is completed. + This TESL Tracker version became unsupported. Please update to continue using. + http://play.google.com/store/apps/details?id=%s Cards Decks @@ -26,10 +31,10 @@ Unlike Done + Are you sure? Open drawer Close drawer Name, race, type or keyword - Are you sure? Cards Collection @@ -38,6 +43,13 @@ Owned Favorites + @string/app_name_full + Cards Collection + Cards Favorites + Decks Public + Decks Owned + Decks Favorites + All Core Madhouse @@ -54,7 +66,7 @@ Unknown 0% - Favorite a card require user login. + This action require a logged user. Authentication failed. Sign in with Google Sign in with Twitter @@ -69,7 +81,14 @@ Create by Create at Last update + %1$s at %2$s Deck deleted! + Press back again to exit without save + Comments + Your comment! + Your comment! (Need login) + Message is too short! + %1$s\n%2$s deck_transition deck_name_transition deck_cover_transition @@ -87,5 +106,6 @@ Save Deck saved as Public Deck saved as Private + Please complete your deck before save it diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 7a385cf..60e58db 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -22,7 +22,7 @@ @color/primary_text_dark - +