Skip to content

Commit

Permalink
Merge pull request #55 from gatheringhallstudios/talisman-bank
Browse files Browse the repository at this point in the history
Talisman bank features and swipe to delete
  • Loading branch information
CarlosFdez authored Mar 26, 2019
2 parents 077084e + 7b635c7 commit de5e9f8
Show file tree
Hide file tree
Showing 60 changed files with 1,837 additions and 999 deletions.
8 changes: 6 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@

<!-- ARMOR SET BUILDER ACTIVITY -->
<activity
android:name="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity"
android:name="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity"
android:label="@string/app_name"
android:screenOrientation="portrait" />
<activity
Expand All @@ -187,12 +187,16 @@
android:screenOrientation="portrait">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity" />
android:value="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity" />
</activity>
<activity
android:name="com.ghstudios.android.features.armorsetbuilder.armorselect.ArmorSelectActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"/>
<activity
android:name="com.ghstudios.android.features.armorsetbuilder.talismans.TalismanSelectActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"/>

<!-- WYPORIUM TRADE SECTION -->
<activity
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ghstudios.android.ClickListeners

import android.content.Context
import android.content.Intent
import android.view.View
import com.ghstudios.android.features.armorsetbuilder.detail.ASBDetailPagerActivity
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListFragment

/**
* Click listener used to navigate to an armor set.
*/
class ASBSetClickListener(
val context: Context,
val id: Long
) : View.OnClickListener {

override fun onClick(v: View?) {
val i = Intent(context, ASBDetailPagerActivity::class.java)
i.putExtra(ASBSetListFragment.EXTRA_ASB_SET_ID, id)
context.startActivity(i)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.NavigationView;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
Expand All @@ -28,7 +27,7 @@
import com.ghstudios.android.features.monsters.list.MonsterListPagerActivity;
import com.ghstudios.android.features.meta.PreferencesActivity;
import com.ghstudios.android.mhgendatabase.R;
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity;
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity;
import com.ghstudios.android.features.armor.list.ArmorListPagerActivity;
import com.ghstudios.android.features.combining.CombiningListActivity;
import com.ghstudios.android.features.decorations.list.DecorationListActivity;
Expand Down Expand Up @@ -227,7 +226,7 @@ public boolean onNavigationItemSelected(MenuItem item) {
intent = new Intent(ctx, SkillTreeListActivity.class);
break;
case MenuSection.ARMOR_SET_BUILDER: // Armor Set Builder
intent = new Intent(ctx, ASBSetListActivity.class);
intent = new Intent(ctx, ASBSetListPagerActivity.class);
break;
case MenuSection.WISH_LISTS: // Wishlists
intent = new Intent(ctx, WishlistListActivity.class);
Expand Down
27 changes: 23 additions & 4 deletions app/src/main/java/com/ghstudios/android/RecyclerViewFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.ghstudios.android

import android.content.Context
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.v4.app.Fragment
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.RecyclerView
Expand Down Expand Up @@ -43,6 +44,8 @@ class DetachingRecyclerView : RecyclerView {
open class RecyclerViewFragment : Fragment() {
lateinit var recyclerView: RecyclerView
private set
lateinit var fab: FloatingActionButton
private set

private lateinit var recyclerViewContainer: View
private lateinit var textField: EditText
Expand All @@ -63,6 +66,7 @@ open class RecyclerViewFragment : Fragment() {
recyclerView = view.findViewById(R.id.content_recyclerview)
textField = view.findViewById(R.id.input_search)
emptyView = view.findViewById(R.id.empty_view)
fab = view.findViewById(R.id.fab)

return view
}
Expand All @@ -78,6 +82,16 @@ open class RecyclerViewFragment : Fragment() {
}
}

/**
* Makes the floating action button visible and binds it to a callback
*/
fun enableFab(callback: () -> Unit) {
fab.visibility = View.VISIBLE
fab.setOnClickListener {
callback.invoke()
}
}

/**
* Sets the adapter of the internal recyclerview.
* This function has to be called everytime the view is recreated
Expand Down Expand Up @@ -108,10 +122,15 @@ open class RecyclerViewFragment : Fragment() {

/**
* Shows the empty view instead of the recycler view.
* There is no way to revert. Only call this once you're SURE there is no data.
* Recommended to wait until you're sure there is no data.
*/
fun showEmptyView() {
recyclerViewContainer.visibility = View.GONE
emptyView.visibility = View.VISIBLE
fun showEmptyView(show: Boolean = true) {
if (show) {
recyclerViewContainer.visibility = View.GONE
emptyView.visibility = View.VISIBLE
} else {
recyclerViewContainer.visibility = View.VISIBLE
emptyView.visibility = View.GONE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import android.view.View
import android.view.ViewGroup
import kotlinx.android.extensions.LayoutContainer
import java.util.*
import android.support.v7.recyclerview.extensions.AsyncListDiffer
import android.icu.lang.UCharacter.GraphemeClusterBreak.T
import android.support.v7.util.DiffUtil


/**
* A simple container-only viewholder used by SimpleListDelegate and SimpleRecyclerViewAdapter.
Expand All @@ -30,7 +34,7 @@ abstract class SimpleRecyclerViewAdapter<T>: RecyclerView.Adapter<SimpleViewHold
/**
* A list of items contained in this adapter. Cannot be modified directly
*/
val items = Collections.unmodifiableList(itemSource)
open val items = Collections.unmodifiableList(itemSource)

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder {
val v = onCreateView(parent)
Expand All @@ -49,9 +53,54 @@ abstract class SimpleRecyclerViewAdapter<T>: RecyclerView.Adapter<SimpleViewHold
/**
* Updates the items in this adapter and calls notifyDataSetChanged
*/
fun setItems(items: List<T>) {
open fun setItems(items: List<T>) {
itemSource.clear()
itemSource.addAll(items)
notifyDataSetChanged()
}
}

/**
* A subclass of the basic recyclerview adapter that performs list diffing for fast recyclerview updates.
*/
abstract class SimpleDiffRecyclerViewAdapter<T>: SimpleRecyclerViewAdapter<T>() {
// suppressed since both will be gc'd at the same time.
@Suppress("LeakingThis")
private val mDiffer = AsyncListDiffer(this, DiffCallback())

/**
* Returns a readonly collection of the current items in this adapter.
*/
override val items: List<T> get() = mDiffer.currentList

/**
* Sets the list of items to be displayed.
* Sends notifications to update the list
*/
override fun setItems(items: List<T>) {
mDiffer.submitList(items)
}

/**
* Override to create a comparator for whether two items are the same
*/
protected abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean

/**
* Called when an item has been confirmed to match, to determine if the view needs rerendering.
* Defaults to always returning true.
*/
open fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return true
}

// internal implementation of the diff callback. Differs to an astract method.
inner class DiffCallback : DiffUtil.ItemCallback<T>() {
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
return this@SimpleDiffRecyclerViewAdapter.areItemsTheSame(oldItem, newItem)
}
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
return this@SimpleDiffRecyclerViewAdapter.areContentsTheSame(oldItem, newItem)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.ghstudios.android.adapter.common

import android.support.v7.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper

/**
* ItemTouchHelper used to add swipe and reorder functionality to recyclerviews.
*/
class SwipeReorderTouchHelper(
val afterSwiped: (position: RecyclerView.ViewHolder) -> Unit
) : ItemTouchHelper.SimpleCallback(
0, //ItemTouchHelper.UP or ItemTouchHelper.DOWN,
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
) {
override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
// Called every time order is swapped mid-drag.
// Update the recyclerview's backing data but don't actually call onMove until done (different callback)
val originalIdx = viewHolder.adapterPosition
val targetIdx = target.adapterPosition
//Log.d("SWIPE", "MOVED $originalIdx to $targetIdx")
// todo: actually implement
//return true
return false
}

/**
* Callback called every time an item has been swiped away
*/
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
afterSwiped(viewHolder)
}
}
115 changes: 115 additions & 0 deletions app/src/main/java/com/ghstudios/android/data/ASBManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@ package com.ghstudios.android.data

import android.content.ContentValues
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.util.Log
import com.ghstudios.android.data.classes.*
import com.ghstudios.android.data.cursors.ASBSessionCursor
import com.ghstudios.android.data.cursors.ASBSetCursor
import com.ghstudios.android.data.database.MonsterHunterDatabaseHelper
import com.ghstudios.android.data.database.S
import com.ghstudios.android.util.firstOrNull
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.io.FileNotFoundException

/**
* Extension used to build an iterator from a JSONArray. Each index is evaluated using transform.
*/
fun <T> JSONArray.iter(transform: JSONArray.(Int) -> T) = sequence {
for (i in 0..(this@iter.length() - 1)) {
yield(transform(i))
}
}

/**
* Creates a ContentValues object from a map of arbitrary value types.
Expand All @@ -35,6 +49,7 @@ private fun contentValuesFromMap(map: Map<String, Any>): ContentValues {

class ASBManager internal constructor(
private val mAppContext: Context,
private val dataManager: DataManager,
private val mHelper: MonsterHunterDatabaseHelper
) {
val TAG = "ASBManager"
Expand Down Expand Up @@ -169,4 +184,104 @@ class ASBManager internal constructor(

return contentValuesFromMap(updatedColumns)
}

/**
* Returns a list of all talismans saved in the talismans.json file
*/
fun getTalismans(): List<ASBTalisman> {
try {
val stream = mAppContext.openFileInput("talismans.json")
val contents = stream.use {
it.bufferedReader().use { br -> br.readText() }
}

// Micro optimization
val cachedSkills = mutableMapOf<Long, SkillTree?>()

val talismanDataObj = JSONObject(contents)
val talismanItems = talismanDataObj.getJSONArray("talismans")
val results = mutableListOf<ASBTalisman>()

for (talismanObj in talismanItems.iter { getJSONObject(it)}) {
val typeIdx = talismanObj.getInt("type")
val skills = talismanObj.getJSONArray("skills").iter {
val obj = getJSONObject(it)
Pair(obj.getLong("id"), obj.getInt("points"))
}

val talisman = ASBTalisman(typeIdx)
talisman.id = talismanObj.getLong("id")
talisman.numSlots = talismanObj.getInt("slots")
for ((skillId, points) in skills) {
val skillTree = cachedSkills.getOrPut(skillId) { dataManager.getSkillTree(skillId) }
if (skillTree != null) {
talisman.addSkill(skillTree, points)
}
}

results.add(talisman)
}

return results

} catch (ex: FileNotFoundException) {
return emptyList()
} catch (ex: JSONException) {
Log.e(javaClass.name, "JSON ERROR", ex)
return emptyList()
}
}

/**
* Adds a talisman to the talisman list, and returns the new list
*/
fun saveTalisman(talisman: ASBTalisman): List<ASBTalisman> {
val list = getTalismans().toMutableList()

if (talisman.id == -1L) {
// Adding talisman
talisman.id = (list.maxBy { it.id }?.id ?: 0) + 1
list.add(talisman)
} else {
// Editing talisman
val existingIdx = list.indexOfFirst { it.id == talisman.id }
if (existingIdx < 0) {
list.add(talisman)
} else {
list[existingIdx] = talisman
}
}
saveTalismans(list)

return list
}

/**
* Internal function to save talismans. Since talismans are JSON, we need to
* overwrite all of them every time.
*/
fun saveTalismans(talismans: List<ASBTalisman>) {
val talismanListObj = JSONArray(talismans.map {
JSONObject()
.put("id", it.id)
.put("type", it.typeIndex)
.put("slots", it.numSlots)
.put("skills", JSONArray(it.skills.map {s ->
JSONObject(mapOf(
"id" to s.skillTree.id,
"points" to s.points
))
}))
})

val result = JSONObject(mapOf(
"talismans" to talismanListObj
))

val resultString = result.toString()
val stream = mAppContext.openFileOutput("talismans.json", MODE_PRIVATE)
stream.use {
stream.bufferedWriter().use { it.write(resultString) }
}
}
}
Loading

0 comments on commit de5e9f8

Please sign in to comment.