aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/net/lacolaco
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-10-26 01:22:54 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-10-26 01:27:02 +0900
commit7ae78f41164b0333106945dcd611d039646f48e7 (patch)
tree12d7bd09af4f673e82a42acc640e02a1f5994f30 /app/src/main/java/net/lacolaco
parent40103f06c8e2798aad8f93c4da1d1b9aea0825f7 (diff)
downloadSmileEssence-7ae78f41164b0333106945dcd611d039646f48e7.tar.gz
de-listview
Diffstat (limited to 'app/src/main/java/net/lacolaco')
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/World.kt52
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt61
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt37
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/data/Pages.kt57
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt43
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt35
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt28
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/UnorderedCustomListAdapter.kt21
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt5
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt93
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt5
11 files changed, 206 insertions, 231 deletions
diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt
index 3b9a6c30..5beef673 100644
--- a/app/src/main/java/net/lacolaco/smileessence/World.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/World.kt
@@ -7,6 +7,7 @@ import android.graphics.drawable.Drawable
import android.support.annotation.StringRes
import android.support.design.widget.Snackbar
import android.view.View
+import com.beust.klaxon.*
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.SimpleTarget
@@ -38,7 +39,8 @@ import kotlin.coroutines.experimental.suspendCoroutine
*/
class World private constructor(private val persistentData: PersistentData) {
val id = persistentData.id
- val user: User = User.makeSkeletonForInternalUseOnly(id, persistentData.screenName, persistentData.profileImageUrl)
+ val user: User = User.makeSkeletonForInternalUseOnly(id, persistentData.screenName,
+ persistentData.profileImageUrl)
// XXX: Workaround for a bug in Android
var mainActivityIntent: Intent? = null
// Timelines
@@ -317,13 +319,13 @@ class World private constructor(private val persistentData: PersistentData) {
}
}
- private data class PersistentData(
+ private class PersistentData(
val id: Long,
var oauthToken: String,
var oauthTokenSecret: String,
var screenName: String,
var profileImageUrl: String = "https://abs.twimg.com/sticky/default_profile_images/default_profile.png",
- var pageInfos: List<PageInfo> = makeDefaultPageInfos(screenName),
+ var pageInfos: MutableList<PageInfo> = makeDefaultPageInfos(screenName),
var themeIndex: Int = 0,
var themeColor: Int = 0
) {
@@ -334,16 +336,32 @@ class World private constructor(private val persistentData: PersistentData) {
values.put("oauth_token_secret", oauthTokenSecret)
values.put("screen_name", screenName)
values.put("profile_image_url", profileImageUrl)
- Logger.error("pageinfo saving: ${PageInfo.stringifyList(pageInfos)}")
- values.put("page_infos", PageInfo.stringifyList(pageInfos))
+ values.put("page_infos", stringifyPageInfos())
values.put("theme", themeIndex)
values.put("theme_color", themeColor)
if (Application.instance.db.replaceOrThrow("profiles", null, values) == -1L)
throw RuntimeException("SQLiteDatabase#replaceOrThrow failed")
}
+ private fun stringifyPageInfos(): String {
+ return json {
+ array(pageInfos.mapNotNull {
+ if (it.ephemeral)
+ return@mapNotNull null
+ val kind = when (it) {
+ is PageInfo.ComposePageInfo -> "compose"
+ is PageInfo.TweetsPageInfo -> "tweets"
+ is PageInfo.EventsPageInfo -> "events"
+ is PageInfo.SearchPageInfo -> "search"
+ is PageInfo.ListPageInfo -> "list"
+ }
+ obj("kind" to kind, "data" to it.toJson())
+ })
+ }.toJsonString()
+ }
+
companion object {
- private fun makeDefaultPageInfos(screenName: String): List<PageInfo> {
+ private fun makeDefaultPageInfos(screenName: String): MutableList<PageInfo> {
val ret = arrayListOf<PageInfo>()
ret.add(PageInfo.EventsPageInfo())
ret.add(PageInfo.ComposePageInfo())
@@ -354,6 +372,26 @@ class World private constructor(private val persistentData: PersistentData) {
return ret
}
+ private fun parsePageInfos(input: String): MutableList<PageInfo> {
+ val parser = Parser()
+ val json = parser.parse(StringBuilder(input)) as JsonArray<*>
+ return json.mapNotNull {
+ it as JsonObject
+ val kind = it.string("kind")!!
+ if (kind == "message")
+ return@mapNotNull null
+ val data = it.obj("data")!!
+ when (kind) {
+ "compose" -> PageInfo.ComposePageInfo(data)
+ "tweets" -> PageInfo.TweetsPageInfo(data)
+ "events" -> PageInfo.EventsPageInfo(data)
+ "search" -> PageInfo.SearchPageInfo(data)
+ "list" -> PageInfo.ListPageInfo(data)
+ else -> throw RuntimeException("Recognized PageInfo kind: $kind")
+ }
+ }.toMutableList()
+ }
+
fun fetchAll(): List<PersistentData> {
val ret = arrayListOf<PersistentData>()
Application.instance.db.query("profiles", null, null, null, null, null, null).use { cursor ->
@@ -369,7 +407,7 @@ class World private constructor(private val persistentData: PersistentData) {
cursor.getColumnIndexOrThrow("screen_name")),
profileImageUrl = cursor.getString(
cursor.getColumnIndexOrThrow("profile_image_url")),
- pageInfos = PageInfo.parseList(cursor.getString(
+ pageInfos = parsePageInfos(cursor.getString(
cursor.getColumnIndexOrThrow("page_infos"))),
themeIndex = cursor.getInt(
cursor.getColumnIndexOrThrow("theme")),
diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt
index 506178ad..265652a0 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/EditExtractionActivity.kt
@@ -6,13 +6,72 @@ import android.support.v7.app.AppCompatActivity
import android.text.TextUtils
import android.view.*
import android.widget.AbsListView
+import android.widget.BaseAdapter
import android.widget.ListView
import kotlinx.android.synthetic.main.layout_edit_list.*
import kotlinx.android.synthetic.main.list_item_simple_text.view.*
import kotlinx.android.synthetic.main.part_edittext.view.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.data.ExtractionWord
-import net.lacolaco.smileessence.view.adapter.UnorderedCustomListAdapter
+import net.lacolaco.smileessence.util.UIHandler
+import java.util.*
+
+abstract class CustomListAdapter<out T> : BaseAdapter() {
+ private var isNotifiable = true
+ private var frozenList: List<T> = ArrayList()
+
+ fun setNotifiable(notifiable: Boolean) {
+ isNotifiable = notifiable
+ }
+
+ override fun getCount(): Int {
+ return frozenList.size
+ }
+
+ override fun getItem(position: Int): T {
+ return frozenList[position]
+ }
+
+ override fun getItemId(position: Int): Long {
+ return position.toLong()
+ }
+
+ override fun notifyDataSetChanged() {
+ frozenList = Collections.unmodifiableList(list)
+ super.notifyDataSetChanged()
+ }
+
+ protected abstract val list: List<T>
+
+ fun update() {
+ if (isNotifiable) {
+ updateForce()
+ }
+ }
+
+ fun updateForce() {
+ UIHandler().post { this.notifyDataSetChanged() }
+ }
+}
+
+
+abstract class UnorderedCustomListAdapter<T> constructor(override val list: ArrayList<T> = ArrayList()) : CustomListAdapter<T>() {
+ init {
+ update()
+ }
+
+ @Synchronized
+ fun add(item: T) = list.add(item)
+
+ @Synchronized
+ fun addAll(items: Collection<T>) = list.addAll(items)
+
+ @Synchronized
+ fun clear() = list.clear()
+
+ @Synchronized
+ fun remove(item: T): Boolean = list.remove(item)
+}
class EditExtractionActivity : AppCompatActivity() {
private val adapter by lazy {
diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt
index 75560f40..11019e72 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt
@@ -20,7 +20,7 @@ class ManagePagesActivity : AppCompatActivity() {
private val world by lazy {
World[intent.getLongExtra(INTENT_KEY_WORLD_ID, -1)]
}
- private lateinit var pages: MutableList<PageInfo>
+ private var changed = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -28,16 +28,14 @@ class ManagePagesActivity : AppCompatActivity() {
setContentView(R.layout.activity_page_manage)
setSupportActionBar(toolbar)
- pages = PageInfo.parseList(if (savedInstanceState == null)
- PageInfo.stringifyList(world.pages)
- else
- savedInstanceState.getString(KEY_SAVED_PAGES)
- ).toMutableList()
+ if (savedInstanceState != null)
+ changed = savedInstanceState.getBoolean(KEY_IS_CHANGED)
fab.setOnClickListener {
+ changed = true
val item = PageInfo.TweetsPageInfo("Tweets", listOf())
- pages.add(item)
- recycler_view.adapter.notifyItemInserted(pages.size - 1)
+ world.pages.add(item)
+ recycler_view.adapter.notifyItemInserted(world.pages.size - 1)
openItemEditor(item)
}
val helper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
@@ -66,15 +64,12 @@ class ManagePagesActivity : AppCompatActivity() {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
- outState.putString(KEY_SAVED_PAGES, PageInfo.stringifyList(pages))
+ outState.putBoolean(KEY_IS_CHANGED, changed)
}
override fun finish() {
// MainActivity will restart itself on RESULT_OK
- if (PageInfo.stringifyList(world.pages) == PageInfo.stringifyList(pages))
- setResult(RESULT_CANCELED)
- else
- setResult(RESULT_OK)
+ setResult(if (changed) RESULT_OK else RESULT_CANCELED)
super.finish()
}
@@ -84,12 +79,12 @@ class ManagePagesActivity : AppCompatActivity() {
companion object {
val INTENT_KEY_WORLD_ID = "WORLD_ID"
- private val KEY_SAVED_PAGES = "SAVED_PAGES"
+ private val KEY_IS_CHANGED = "IS_CHANGED"
}
private inner class PagesAdapter : RecyclerView.Adapter<PagesAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val item = pages[position]
+ val item = world.pages[position]
val view = holder.itemView
view.page_kind_text_view.text = item.name
view.page_name_text_view.text = item.describe()
@@ -101,7 +96,7 @@ class ManagePagesActivity : AppCompatActivity() {
}
override fun getItemCount(): Int {
- return pages.size
+ return world.pages.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -109,16 +104,18 @@ class ManagePagesActivity : AppCompatActivity() {
}
fun move(before: Int, after: Int): Boolean {
- val item = pages.removeAt(before)
- pages.add(after, item)
+ changed = true
+ val item = world.pages.removeAt(before)
+ world.pages.add(after, item)
notifyItemMoved(before, after)
return true
}
fun remove(position: Int) {
- pages.removeAt(position)
+ changed = true
+ world.pages.removeAt(position)
notifyItemRemoved(position)
- notifyItemRangeChanged(position, pages.size)
+ notifyItemRangeChanged(position, world.pages.size)
}
private inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
diff --git a/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt b/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt
index cc3c1ab1..1d898711 100644
--- a/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt
@@ -1,16 +1,21 @@
package net.lacolaco.smileessence.data
-import com.beust.klaxon.*
-import net.lacolaco.smileessence.Logger
+import com.beust.klaxon.JsonObject
+import com.beust.klaxon.array
+import com.beust.klaxon.json
+import com.beust.klaxon.string
import net.lacolaco.smileessence.view.page.*
sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
abstract val name: String
+ var ephemeral = false
+
abstract fun describe(): String
abstract fun toJson(): JsonObject
class ComposePageInfo() : PageInfo(ComposePageFragment::class.java) {
- override val name = "Compose"
+ override val name
+ get() = "Compose"
override fun describe(): String {
return ""
@@ -23,8 +28,9 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
}
}
- class TweetsPageInfo(override val name: String, val patternStrings: List<String>) :
+ data class TweetsPageInfo(override val name: String, val patternStrings: List<String>) :
PageInfo(TweetsPageFragment::class.java) {
+ @Transient
val patterns = patternStrings.map { Regex(it) }
override fun describe(): String {
@@ -33,7 +39,8 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
return sb.toString()
}
- constructor(json: JsonObject) : this(json.string("name")!!, json.array<String>("patterns")!!.toList())
+ constructor(json: JsonObject)
+ : this(json.string("name")!!, json.array<String>("patterns")!!)
override fun toJson() = json {
obj("name" to name, "patterns" to array(patternStrings))
@@ -41,7 +48,8 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
}
class EventsPageInfo() : PageInfo(EventsPageFragment::class.java) {
- override val name = "Events"
+ override val name
+ get() = "Events"
override fun describe(): String {
return ""
@@ -83,41 +91,4 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
obj("full_name" to fullName)
}
}
-
- // XXX: Yucks
- companion object {
- fun parseList(input: String): List<PageInfo> {
- Logger.error("parsing: $input")
- val parser = Parser()
- val json = parser.parse(StringBuilder(input)) as JsonArray<*>
- return json.map {
- val data: JsonObject = (it as JsonObject).obj("data")!!
- when (it.string("kind")) {
- "compose" -> ComposePageInfo(data)
- "tweets" -> TweetsPageInfo(data)
- "events" -> EventsPageInfo(data)
- "search" -> SearchPageInfo(data)
- "list" -> ListPageInfo(data)
- // FIXME: Remove this
- "messages" -> null
- else -> throw RuntimeException("invalid kind")
- }
- }.mapNotNull { it } // FIXME
- }
-
- fun stringifyList(input: List<PageInfo>): String {
- return json {
- array(input.map {
- val kind = when (it) {
- is ComposePageInfo -> "compose"
- is TweetsPageInfo -> "tweets"
- is EventsPageInfo -> "events"
- is SearchPageInfo -> "search"
- is ListPageInfo -> "list"
- }
- obj("kind" to kind, "data" to it.toJson())
- })
- }.toJsonString()
- }
- }
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt
deleted file mode 100644
index 612c14e5..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/CustomListAdapter.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.lacolaco.smileessence.view.adapter
-
-import android.widget.BaseAdapter
-import net.lacolaco.smileessence.util.UIHandler
-import java.util.*
-
-abstract class CustomListAdapter<out T> : BaseAdapter() {
- private var isNotifiable = true
- private var frozenList: List<T> = ArrayList()
-
- fun setNotifiable(notifiable: Boolean) {
- isNotifiable = notifiable
- }
-
- override fun getCount(): Int {
- return frozenList.size
- }
-
- override fun getItem(position: Int): T {
- return frozenList[position]
- }
-
- override fun getItemId(position: Int): Long {
- return position.toLong()
- }
-
- override fun notifyDataSetChanged() {
- frozenList = Collections.unmodifiableList(list)
- super.notifyDataSetChanged()
- }
-
- protected abstract val list: List<T>
-
- fun update() {
- if (isNotifiable) {
- updateForce()
- }
- }
-
- fun updateForce() {
- UIHandler().post { this.notifyDataSetChanged() }
- }
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt
deleted file mode 100644
index 53b1c824..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/OrderedCustomListAdapter.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.lacolaco.smileessence.view.adapter
-
-import net.lacolaco.smileessence.entity.IdObject
-
-import java.util.*
-
-abstract class OrderedCustomListAdapter<T : IdObject>
-constructor(comparator: Comparator<Long> = Comparator { x, y -> java.lang.Long.compare(x, y) }) : CustomListAdapter<T>() {
- private val treeMap: MutableMap<Long, T> = TreeMap(Collections.reverseOrder(comparator))
-
- override val list: List<T>
- @Synchronized get() = ArrayList(treeMap.values)
-
- @Synchronized
- fun add(item: T) {
- treeMap.put(item.id, item)
- }
-
- @Synchronized
- fun addAll(items: Collection<T>) {
- for (item in items) {
- treeMap.put(item.id, item)
- }
- }
-
- @Synchronized
- fun clear() {
- treeMap.clear()
- }
-
- @Synchronized
- fun remove(item: T): T {
- return treeMap.remove(item.id)!!
- }
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt
deleted file mode 100644
index f2b640c8..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/TimelineAdapter.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.lacolaco.smileessence.view.adapter
-
-import android.app.Activity
-import android.view.View
-import android.view.ViewGroup
-import net.lacolaco.smileessence.World
-import net.lacolaco.smileessence.entity.Tweet
-import net.lacolaco.smileessence.view.Partials
-
-class TimelineAdapter(private val activity: Activity, private val world: World) : OrderedCustomListAdapter<Tweet>() {
- val lastID: Long
- get() = if (count > 0) {
- getItem(count - 1).id
- } else {
- -1
- }
-
- val topID: Long
- get() = if (count > 0) {
- getItem(0).id
- } else {
- -1
- }
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
- return Partials.getTweetView(getItem(position), world, activity, convertView)
- }
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/UnorderedCustomListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/UnorderedCustomListAdapter.kt
deleted file mode 100644
index 46b40681..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/UnorderedCustomListAdapter.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.lacolaco.smileessence.view.adapter
-
-import java.util.*
-
-abstract class UnorderedCustomListAdapter<T> constructor(override val list: ArrayList<T> = ArrayList()) : CustomListAdapter<T>() {
- init {
- update()
- }
-
- @Synchronized
- fun add(item: T) = list.add(item)
-
- @Synchronized
- fun addAll(items: Collection<T>) = list.addAll(items)
-
- @Synchronized
- fun clear() = list.clear()
-
- @Synchronized
- fun remove(item: T): Boolean = list.remove(item)
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt
index 4ebd69f7..247a8cc3 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt
@@ -9,13 +9,14 @@ import net.lacolaco.smileessence.BuildConfig
import net.lacolaco.smileessence.R
class AppInfoDialogFragment : StackableDialogFragment() {
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.dialog_app_info, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- application_version.text = "${BuildConfig.VERSION_NAME} (revision ${BuildConfig.VERSION_CODE})"
+ app_version.text = "${BuildConfig.VERSION_NAME} (revision ${BuildConfig.VERSION_CODE})"
web_view.loadUrl("file:///android_asset/licenses.html")
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
index d53c887f..d212124f 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
@@ -1,6 +1,9 @@
package net.lacolaco.smileessence.view.dialog
import android.os.Bundle
+import android.support.v7.widget.DividerItemDecoration
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
@@ -11,17 +14,18 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirec
import kotlinx.android.synthetic.main.dialog_user_detail.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.activity.MainActivity
+import net.lacolaco.smileessence.entity.Tweet
import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.twitter.TwitterTaskException
import net.lacolaco.smileessence.twitter.task.*
+import net.lacolaco.smileessence.util.SortedList
import net.lacolaco.smileessence.util.browse
import net.lacolaco.smileessence.util.launchUi
+import net.lacolaco.smileessence.view.Partials
import net.lacolaco.smileessence.view.PopupMenu
-import net.lacolaco.smileessence.view.adapter.TimelineAdapter
import net.lacolaco.smileessence.view.confirm
class UserDetailDialogFragment : StackableDialogFragment() {
- private val adapter by lazy { TimelineAdapter(activity, world) }
private lateinit var user: User
private var isFollowedByMe = false
private var isFollowingMe = false
@@ -61,18 +65,26 @@ class UserDetailDialogFragment : StackableDialogFragment() {
user_detail_banner.setOnClickListener { user.profileBannerUrl?.let { browse(it) } }
toggle_follow.setOnClickListener { toggleFollowing() }
+ user_timeline.addItemDecoration(
+ DividerItemDecoration(activity, DividerItemDecoration.VERTICAL))
+ val lm = LinearLayoutManager(activity)
+ lm.orientation = LinearLayoutManager.VERTICAL
+ user_timeline.layoutManager = lm
+ val adapter = UserTimelineAdapter()
+ user_timeline.adapter = adapter
+
val refreshLayout = user_detail_refresh_layout
refreshLayout.setOnRefreshListener {
launchUi {
try {
if (it == SwipyRefreshLayoutDirection.TOP) {
- val tweets = world.getUserTimelineAsync(user.id, sinceId = adapter.topID).await()
+ val tweets = world.getUserTimelineAsync(user.id,
+ sinceId = adapter.getMaxIdOrNull()).await()
adapter.addAll(tweets)
- updateListView(true)
} else {
- val tweets = world.getUserTimelineAsync(user.id, maxId = adapter.lastID - 1).await()
+ val tweets = world.getUserTimelineAsync(user.id,
+ maxId = adapter.getMinIdMinusOneOrNull()).await()
adapter.addAll(tweets)
- updateListView(false)
}
} catch (e: TwitterTaskException) {
world.notifyError(R.string.notice_error_get_user_timeline)
@@ -81,23 +93,20 @@ class UserDetailDialogFragment : StackableDialogFragment() {
}
}
- refresh()
updateRelationship()
-
- // FIXME
- listview_user_detail_timeline.adapter = adapter
launchUi {
try {
val tweets = world.getUserTimelineAsync(user.id).await()
adapter.addAll(tweets)
- adapter.updateForce()
} catch (e: TwitterTaskException) {
world.notifyError(R.string.notice_error_get_user_timeline)
}
}
+
+ refreshViews()
}
- private fun refresh() {
+ private fun refreshViews() {
Glide.with(this).load(user.profileImageUrl).into(user_detail_icon)
Glide.with(this).load(user.profileBannerUrl).into(user_detail_banner)
user_detail_name.text = user.name
@@ -199,23 +208,6 @@ class UserDetailDialogFragment : StackableDialogFragment() {
}
}
- private fun updateListView(addedToTop: Boolean) {
- val absListView = listview_user_detail_timeline
- val before = adapter.count
- adapter.notifyDataSetChanged() // synchronized call (not adapter#updateForce())
- val after = adapter.count
- val increments = after - before
- if (increments > 0) {
- if (addedToTop) {
- absListView.setSelection(increments + 1)
- absListView.smoothScrollToPositionFromTop(increments, 0)
- absListView.setSelection(increments)
- } else {
- absListView.smoothScrollToPositionFromTop(before, 0)
- }
- }
- }
-
private fun updateRelationship() {
if (user !== world.user) {
toggle_follow.isEnabled = false
@@ -229,7 +221,7 @@ class UserDetailDialogFragment : StackableDialogFragment() {
} catch (e: TwitterTaskException) {
world.notifyError("Failed to fetch relationship")
}
- refresh()
+ refreshViews()
}
}
}
@@ -245,4 +237,45 @@ class UserDetailDialogFragment : StackableDialogFragment() {
return obj
}
}
+
+ private inner class UserTimelineAdapter :
+ RecyclerView.Adapter<UserTimelineAdapter.ViewHolder>() {
+ private val sortedList = SortedList<Tweet>(
+ { position -> notifyItemInserted(position) },
+ { position, count -> notifyItemRangeRemoved(position, count) }
+ )
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ Partials.getTweetView(sortedList[position], world, activity, holder.itemView)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val layoutInflater = LayoutInflater.from(parent.context)
+ return ViewHolder(layoutInflater.inflate(R.layout.list_item_status, parent, false))
+ }
+
+ override fun getItemCount(): Int {
+ return sortedList.size
+ }
+
+ fun addAll(items: Collection<Tweet>) {
+ sortedList.addAll(items)
+ }
+
+ fun getMaxIdOrNull(): Long? {
+ return if (sortedList.size > 0)
+ sortedList[0].id
+ else
+ null
+ }
+
+ fun getMinIdMinusOneOrNull(): Long? {
+ return if (sortedList.size > 0)
+ sortedList[sortedList.size - 1].id - 1
+ else
+ null
+ }
+
+ private inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
+ }
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt
index 15ca9449..bd25207f 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt
@@ -13,8 +13,11 @@ abstract class PageFragment<out T : PageInfo> : Fragment() {
World[arguments.getLong(KEY_WORLD_USER_ID)]
}
protected val pageInfo by lazy {
+ val pos = arguments.getInt(KEY_PAGE_POSITION, -2)
+ if (pos == -2)
+ throw IllegalStateException("KEY_PAGE_POSITION not specified")
@Suppress("UNCHECKED_CAST")
- world.pages[arguments.getInt(KEY_PAGE_POSITION)] as T
+ world.pages[pos] as T
}
val mainActivity