Skip to content

Commit de5e9f8

Browse files
authored
Merge pull request #55 from gatheringhallstudios/talisman-bank
Talisman bank features and swipe to delete
2 parents 077084e + 7b635c7 commit de5e9f8

File tree

60 files changed

+1837
-999
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1837
-999
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@
178178

179179
<!-- ARMOR SET BUILDER ACTIVITY -->
180180
<activity
181-
android:name="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity"
181+
android:name="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity"
182182
android:label="@string/app_name"
183183
android:screenOrientation="portrait" />
184184
<activity
@@ -187,12 +187,16 @@
187187
android:screenOrientation="portrait">
188188
<meta-data
189189
android:name="android.support.PARENT_ACTIVITY"
190-
android:value="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity" />
190+
android:value="com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity" />
191191
</activity>
192192
<activity
193193
android:name="com.ghstudios.android.features.armorsetbuilder.armorselect.ArmorSelectActivity"
194194
android:label="@string/app_name"
195195
android:screenOrientation="portrait"/>
196+
<activity
197+
android:name="com.ghstudios.android.features.armorsetbuilder.talismans.TalismanSelectActivity"
198+
android:label="@string/app_name"
199+
android:screenOrientation="portrait"/>
196200

197201
<!-- WYPORIUM TRADE SECTION -->
198202
<activity
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.ghstudios.android.ClickListeners
2+
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.view.View
6+
import com.ghstudios.android.features.armorsetbuilder.detail.ASBDetailPagerActivity
7+
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListFragment
8+
9+
/**
10+
* Click listener used to navigate to an armor set.
11+
*/
12+
class ASBSetClickListener(
13+
val context: Context,
14+
val id: Long
15+
) : View.OnClickListener {
16+
17+
override fun onClick(v: View?) {
18+
val i = Intent(context, ASBDetailPagerActivity::class.java)
19+
i.putExtra(ASBSetListFragment.EXTRA_ASB_SET_ID, id)
20+
context.startActivity(i)
21+
}
22+
}

app/src/main/java/com/ghstudios/android/GenericActionBarActivity.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import android.os.Bundle;
1010
import android.os.Handler;
1111
import android.support.design.widget.NavigationView;
12-
import android.support.v4.app.FragmentManager;
1312
import android.support.v4.view.GravityCompat;
1413
import android.support.v4.widget.DrawerLayout;
1514
import android.support.v7.app.ActionBarDrawerToggle;
@@ -28,7 +27,7 @@
2827
import com.ghstudios.android.features.monsters.list.MonsterListPagerActivity;
2928
import com.ghstudios.android.features.meta.PreferencesActivity;
3029
import com.ghstudios.android.mhgendatabase.R;
31-
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListActivity;
30+
import com.ghstudios.android.features.armorsetbuilder.list.ASBSetListPagerActivity;
3231
import com.ghstudios.android.features.armor.list.ArmorListPagerActivity;
3332
import com.ghstudios.android.features.combining.CombiningListActivity;
3433
import com.ghstudios.android.features.decorations.list.DecorationListActivity;
@@ -227,7 +226,7 @@ public boolean onNavigationItemSelected(MenuItem item) {
227226
intent = new Intent(ctx, SkillTreeListActivity.class);
228227
break;
229228
case MenuSection.ARMOR_SET_BUILDER: // Armor Set Builder
230-
intent = new Intent(ctx, ASBSetListActivity.class);
229+
intent = new Intent(ctx, ASBSetListPagerActivity.class);
231230
break;
232231
case MenuSection.WISH_LISTS: // Wishlists
233232
intent = new Intent(ctx, WishlistListActivity.class);

app/src/main/java/com/ghstudios/android/RecyclerViewFragment.kt

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.ghstudios.android
22

33
import android.content.Context
44
import android.os.Bundle
5+
import android.support.design.widget.FloatingActionButton
56
import android.support.v4.app.Fragment
67
import android.support.v7.widget.DividerItemDecoration
78
import android.support.v7.widget.RecyclerView
@@ -43,6 +44,8 @@ class DetachingRecyclerView : RecyclerView {
4344
open class RecyclerViewFragment : Fragment() {
4445
lateinit var recyclerView: RecyclerView
4546
private set
47+
lateinit var fab: FloatingActionButton
48+
private set
4649

4750
private lateinit var recyclerViewContainer: View
4851
private lateinit var textField: EditText
@@ -63,6 +66,7 @@ open class RecyclerViewFragment : Fragment() {
6366
recyclerView = view.findViewById(R.id.content_recyclerview)
6467
textField = view.findViewById(R.id.input_search)
6568
emptyView = view.findViewById(R.id.empty_view)
69+
fab = view.findViewById(R.id.fab)
6670

6771
return view
6872
}
@@ -78,6 +82,16 @@ open class RecyclerViewFragment : Fragment() {
7882
}
7983
}
8084

85+
/**
86+
* Makes the floating action button visible and binds it to a callback
87+
*/
88+
fun enableFab(callback: () -> Unit) {
89+
fab.visibility = View.VISIBLE
90+
fab.setOnClickListener {
91+
callback.invoke()
92+
}
93+
}
94+
8195
/**
8296
* Sets the adapter of the internal recyclerview.
8397
* This function has to be called everytime the view is recreated
@@ -108,10 +122,15 @@ open class RecyclerViewFragment : Fragment() {
108122

109123
/**
110124
* Shows the empty view instead of the recycler view.
111-
* There is no way to revert. Only call this once you're SURE there is no data.
125+
* Recommended to wait until you're sure there is no data.
112126
*/
113-
fun showEmptyView() {
114-
recyclerViewContainer.visibility = View.GONE
115-
emptyView.visibility = View.VISIBLE
127+
fun showEmptyView(show: Boolean = true) {
128+
if (show) {
129+
recyclerViewContainer.visibility = View.GONE
130+
emptyView.visibility = View.VISIBLE
131+
} else {
132+
recyclerViewContainer.visibility = View.VISIBLE
133+
emptyView.visibility = View.GONE
134+
}
116135
}
117136
}

app/src/main/java/com/ghstudios/android/adapter/common/SimpleRecyclerViewAdapter.kt

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ import android.view.View
55
import android.view.ViewGroup
66
import kotlinx.android.extensions.LayoutContainer
77
import java.util.*
8+
import android.support.v7.recyclerview.extensions.AsyncListDiffer
9+
import android.icu.lang.UCharacter.GraphemeClusterBreak.T
10+
import android.support.v7.util.DiffUtil
11+
812

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

3539
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleViewHolder {
3640
val v = onCreateView(parent)
@@ -49,9 +53,54 @@ abstract class SimpleRecyclerViewAdapter<T>: RecyclerView.Adapter<SimpleViewHold
4953
/**
5054
* Updates the items in this adapter and calls notifyDataSetChanged
5155
*/
52-
fun setItems(items: List<T>) {
56+
open fun setItems(items: List<T>) {
5357
itemSource.clear()
5458
itemSource.addAll(items)
5559
notifyDataSetChanged()
5660
}
61+
}
62+
63+
/**
64+
* A subclass of the basic recyclerview adapter that performs list diffing for fast recyclerview updates.
65+
*/
66+
abstract class SimpleDiffRecyclerViewAdapter<T>: SimpleRecyclerViewAdapter<T>() {
67+
// suppressed since both will be gc'd at the same time.
68+
@Suppress("LeakingThis")
69+
private val mDiffer = AsyncListDiffer(this, DiffCallback())
70+
71+
/**
72+
* Returns a readonly collection of the current items in this adapter.
73+
*/
74+
override val items: List<T> get() = mDiffer.currentList
75+
76+
/**
77+
* Sets the list of items to be displayed.
78+
* Sends notifications to update the list
79+
*/
80+
override fun setItems(items: List<T>) {
81+
mDiffer.submitList(items)
82+
}
83+
84+
/**
85+
* Override to create a comparator for whether two items are the same
86+
*/
87+
protected abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean
88+
89+
/**
90+
* Called when an item has been confirmed to match, to determine if the view needs rerendering.
91+
* Defaults to always returning true.
92+
*/
93+
open fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
94+
return true
95+
}
96+
97+
// internal implementation of the diff callback. Differs to an astract method.
98+
inner class DiffCallback : DiffUtil.ItemCallback<T>() {
99+
override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
100+
return this@SimpleDiffRecyclerViewAdapter.areItemsTheSame(oldItem, newItem)
101+
}
102+
override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
103+
return this@SimpleDiffRecyclerViewAdapter.areContentsTheSame(oldItem, newItem)
104+
}
105+
}
57106
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.ghstudios.android.adapter.common
2+
3+
import android.support.v7.widget.RecyclerView
4+
import android.support.v7.widget.helper.ItemTouchHelper
5+
6+
/**
7+
* ItemTouchHelper used to add swipe and reorder functionality to recyclerviews.
8+
*/
9+
class SwipeReorderTouchHelper(
10+
val afterSwiped: (position: RecyclerView.ViewHolder) -> Unit
11+
) : ItemTouchHelper.SimpleCallback(
12+
0, //ItemTouchHelper.UP or ItemTouchHelper.DOWN,
13+
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
14+
) {
15+
override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
16+
// Called every time order is swapped mid-drag.
17+
// Update the recyclerview's backing data but don't actually call onMove until done (different callback)
18+
val originalIdx = viewHolder.adapterPosition
19+
val targetIdx = target.adapterPosition
20+
//Log.d("SWIPE", "MOVED $originalIdx to $targetIdx")
21+
// todo: actually implement
22+
//return true
23+
return false
24+
}
25+
26+
/**
27+
* Callback called every time an item has been swiped away
28+
*/
29+
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
30+
afterSwiped(viewHolder)
31+
}
32+
}

app/src/main/java/com/ghstudios/android/data/ASBManager.kt

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,27 @@ package com.ghstudios.android.data
22

33
import android.content.ContentValues
44
import android.content.Context
5+
import android.content.Context.MODE_PRIVATE
56
import android.util.Log
67
import com.ghstudios.android.data.classes.*
78
import com.ghstudios.android.data.cursors.ASBSessionCursor
89
import com.ghstudios.android.data.cursors.ASBSetCursor
910
import com.ghstudios.android.data.database.MonsterHunterDatabaseHelper
1011
import com.ghstudios.android.data.database.S
1112
import com.ghstudios.android.util.firstOrNull
13+
import org.json.JSONArray
14+
import org.json.JSONException
15+
import org.json.JSONObject
16+
import java.io.FileNotFoundException
17+
18+
/**
19+
* Extension used to build an iterator from a JSONArray. Each index is evaluated using transform.
20+
*/
21+
fun <T> JSONArray.iter(transform: JSONArray.(Int) -> T) = sequence {
22+
for (i in 0..(this@iter.length() - 1)) {
23+
yield(transform(i))
24+
}
25+
}
1226

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

3650
class ASBManager internal constructor(
3751
private val mAppContext: Context,
52+
private val dataManager: DataManager,
3853
private val mHelper: MonsterHunterDatabaseHelper
3954
) {
4055
val TAG = "ASBManager"
@@ -169,4 +184,104 @@ class ASBManager internal constructor(
169184

170185
return contentValuesFromMap(updatedColumns)
171186
}
187+
188+
/**
189+
* Returns a list of all talismans saved in the talismans.json file
190+
*/
191+
fun getTalismans(): List<ASBTalisman> {
192+
try {
193+
val stream = mAppContext.openFileInput("talismans.json")
194+
val contents = stream.use {
195+
it.bufferedReader().use { br -> br.readText() }
196+
}
197+
198+
// Micro optimization
199+
val cachedSkills = mutableMapOf<Long, SkillTree?>()
200+
201+
val talismanDataObj = JSONObject(contents)
202+
val talismanItems = talismanDataObj.getJSONArray("talismans")
203+
val results = mutableListOf<ASBTalisman>()
204+
205+
for (talismanObj in talismanItems.iter { getJSONObject(it)}) {
206+
val typeIdx = talismanObj.getInt("type")
207+
val skills = talismanObj.getJSONArray("skills").iter {
208+
val obj = getJSONObject(it)
209+
Pair(obj.getLong("id"), obj.getInt("points"))
210+
}
211+
212+
val talisman = ASBTalisman(typeIdx)
213+
talisman.id = talismanObj.getLong("id")
214+
talisman.numSlots = talismanObj.getInt("slots")
215+
for ((skillId, points) in skills) {
216+
val skillTree = cachedSkills.getOrPut(skillId) { dataManager.getSkillTree(skillId) }
217+
if (skillTree != null) {
218+
talisman.addSkill(skillTree, points)
219+
}
220+
}
221+
222+
results.add(talisman)
223+
}
224+
225+
return results
226+
227+
} catch (ex: FileNotFoundException) {
228+
return emptyList()
229+
} catch (ex: JSONException) {
230+
Log.e(javaClass.name, "JSON ERROR", ex)
231+
return emptyList()
232+
}
233+
}
234+
235+
/**
236+
* Adds a talisman to the talisman list, and returns the new list
237+
*/
238+
fun saveTalisman(talisman: ASBTalisman): List<ASBTalisman> {
239+
val list = getTalismans().toMutableList()
240+
241+
if (talisman.id == -1L) {
242+
// Adding talisman
243+
talisman.id = (list.maxBy { it.id }?.id ?: 0) + 1
244+
list.add(talisman)
245+
} else {
246+
// Editing talisman
247+
val existingIdx = list.indexOfFirst { it.id == talisman.id }
248+
if (existingIdx < 0) {
249+
list.add(talisman)
250+
} else {
251+
list[existingIdx] = talisman
252+
}
253+
}
254+
saveTalismans(list)
255+
256+
return list
257+
}
258+
259+
/**
260+
* Internal function to save talismans. Since talismans are JSON, we need to
261+
* overwrite all of them every time.
262+
*/
263+
fun saveTalismans(talismans: List<ASBTalisman>) {
264+
val talismanListObj = JSONArray(talismans.map {
265+
JSONObject()
266+
.put("id", it.id)
267+
.put("type", it.typeIndex)
268+
.put("slots", it.numSlots)
269+
.put("skills", JSONArray(it.skills.map {s ->
270+
JSONObject(mapOf(
271+
"id" to s.skillTree.id,
272+
"points" to s.points
273+
))
274+
}))
275+
})
276+
277+
val result = JSONObject(mapOf(
278+
"talismans" to talismanListObj
279+
))
280+
281+
val resultString = result.toString()
282+
val stream = mAppContext.openFileOutput("talismans.json", MODE_PRIVATE)
283+
stream.use {
284+
stream.bufferedWriter().use { it.write(resultString) }
285+
}
286+
}
172287
}

0 commit comments

Comments
 (0)