aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-10-05 15:58:59 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-10-05 15:58:59 +0900
commit9db537d339faa3ad44dfdcadb23f4c14bd8aceb4 (patch)
tree6b151cdfd0ca7dc44b9a189045b2b2cbc5aefc21 /app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
parent52ad6edcb217762154a80990c34ca94772393848 (diff)
downloadSmileEssence-9db537d339faa3ad44dfdcadb23f4c14bd8aceb4.tar.gz
kotlin work part. 1
Diffstat (limited to 'app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt')
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt390
1 files changed, 390 insertions, 0 deletions
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
new file mode 100644
index 00000000..228a000a
--- /dev/null
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
@@ -0,0 +1,390 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2012-2014 lacolaco.net
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package net.lacolaco.smileessence.view.dialog
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.os.Bundle
+import android.text.Html
+import android.text.TextUtils
+import android.text.method.LinkMovementMethod
+import android.view.View
+import android.widget.AbsListView
+import android.widget.ListView
+import android.widget.TabHost
+import android.widget.TextView
+import com.android.volley.toolbox.NetworkImageView
+import com.handmark.pulltorefresh.library.PullToRefreshBase
+import com.handmark.pulltorefresh.library.PullToRefreshListView
+import net.lacolaco.smileessence.R
+import net.lacolaco.smileessence.activity.MainActivity
+import net.lacolaco.smileessence.data.ImageCache
+import net.lacolaco.smileessence.entity.RBinding
+import net.lacolaco.smileessence.entity.User
+import net.lacolaco.smileessence.twitter.task.Timelines
+import net.lacolaco.smileessence.twitter.task.Users
+import net.lacolaco.smileessence.util.IntentUtils
+import net.lacolaco.smileessence.util.UIHandler
+import net.lacolaco.smileessence.util.UIObserverBundle
+import net.lacolaco.smileessence.view.DialogHelper
+import net.lacolaco.smileessence.view.ThreeStateButton
+import net.lacolaco.smileessence.view.adapter.TimelineAdapter
+
+class UserDetailDialogFragment : StackableDialogFragment(), View.OnClickListener, PullToRefreshBase.OnRefreshListener2<ListView> {
+ private lateinit var adapter: TimelineAdapter
+ private lateinit var textViewScreenName: TextView
+ private lateinit var textViewName: TextView
+ private lateinit var textViewURL: TextView
+ private lateinit var textViewLocate: TextView
+ private lateinit var textViewFollowed: TextView
+ private lateinit var textViewProtected: TextView
+ private lateinit var textViewDescription: TextView
+ private lateinit var textViewTweetCount: TextView
+ private lateinit var textViewFriendCount: TextView
+ private lateinit var textViewFollowerCount: TextView
+ private lateinit var textViewFavoriteCount: TextView
+ private lateinit var imageViewIcon: NetworkImageView
+ private lateinit var imageViewHeader: NetworkImageView
+ private lateinit var buttonFollow: ThreeStateButton
+ private lateinit var listViewTimeline: PullToRefreshListView
+ private lateinit var tabHost: TabHost
+ private lateinit var observerBundle: UIObserverBundle
+ private lateinit var user: User
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.imageview_user_detail_menu -> {
+ openUserMenu()
+ }
+ R.id.imageview_user_detail_icon -> {
+ IntentUtils.openUri(activity, user.profileImageUrl!!)
+ }
+ R.id.textview_user_detail_screenname, R.id.textview_user_detail_tweet_count -> {
+ IntentUtils.openUri(activity, user.userHomeURL)
+ }
+ R.id.textview_user_detail_friend_count -> {
+ IntentUtils.openUri(activity, String.format("%s/following", user.userHomeURL))
+ }
+ R.id.textview_user_detail_follower_count -> {
+ IntentUtils.openUri(activity, String.format("%s/followers", user.userHomeURL))
+ }
+ R.id.textview_user_detail_favorite_count -> {
+ IntentUtils.openUri(activity, String.format("%s/favorites", user.userHomeURL))
+ }
+ R.id.button_user_detail_follow -> {
+ ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) { this.toggleFollowing() }
+ }
+ }
+ }
+
+ // --------------------- Interface OnRefreshListener2 ---------------------
+
+ override fun onPullDownToRefresh(refreshView: PullToRefreshBase<ListView>) {
+ val currentAccount = world.account
+ Timelines.UserTimelineTask(currentAccount, user.id)
+ .setCount(200)
+ .setSinceId(adapter.topID)
+ .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) }
+ .onDoneUI { tweets ->
+ adapter.addAll(tweets)
+ updateListView(refreshView.refreshableView, adapter, true)
+ refreshView.onRefreshComplete()
+ }
+ .execute()
+ }
+
+ override fun onPullUpToRefresh(refreshView: PullToRefreshBase<ListView>) {
+ val currentAccount = world.account
+ Timelines.UserTimelineTask(currentAccount, user.id)
+ .setCount(200)
+ .setMaxId(adapter.lastID - 1)
+ .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) }
+ .onDoneUI { tweets ->
+ adapter.addAll(tweets)
+ updateListView(refreshView.refreshableView, adapter, false)
+ refreshView.onRefreshComplete()
+ }
+ .execute()
+ }
+
+ // ------------------------ OVERRIDE METHODS ------------------------
+
+ override fun onCreate(savedInstanceState: Bundle) {
+ super.onCreate(savedInstanceState)
+ observerBundle = UIObserverBundle()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ observerBundle.detachAll()
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val activity = activity as MainActivity
+ val found = User.fetch(arguments.getLong(KEY_USER_ID))
+ if (found == null) {
+ world.notify(R.string.notice_error_show_user)
+ return DisposeDialog(activity)
+ }
+ user = found
+
+ val v = activity.layoutInflater.inflate(R.layout.dialog_user_detail, null)
+ val menu = v.findViewById(R.id.imageview_user_detail_menu)
+ menu.setOnClickListener(this)
+ textViewScreenName = v.findViewById(R.id.textview_user_detail_screenname) as TextView
+ textViewScreenName.setOnClickListener(this)
+ textViewName = v.findViewById(R.id.textview_user_detail_name) as TextView
+ textViewURL = v.findViewById(R.id.textview_user_detail_url) as TextView
+ textViewLocate = v.findViewById(R.id.textview_user_detail_locate) as TextView
+ textViewFollowed = v.findViewById(R.id.textview_user_detail_followed) as TextView
+ textViewProtected = v.findViewById(R.id.texttview_user_detail_protected) as TextView
+ textViewDescription = v.findViewById(R.id.textview_user_detail_description) as TextView
+ textViewDescription.movementMethod = LinkMovementMethod.getInstance()
+ textViewTweetCount = v.findViewById(R.id.textview_user_detail_tweet_count) as TextView
+ textViewTweetCount.setOnClickListener(this)
+ textViewFriendCount = v.findViewById(R.id.textview_user_detail_friend_count) as TextView
+ textViewFriendCount.setOnClickListener(this)
+ textViewFollowerCount = v.findViewById(R.id.textview_user_detail_follower_count) as TextView
+ textViewFollowerCount.setOnClickListener(this)
+ textViewFavoriteCount = v.findViewById(R.id.textview_user_detail_favorite_count) as TextView
+ textViewFavoriteCount.setOnClickListener(this)
+ imageViewIcon = v.findViewById(R.id.imageview_user_detail_icon) as NetworkImageView
+ imageViewIcon.setOnClickListener(this)
+ imageViewHeader = v.findViewById(R.id.imageview_user_detail_header) as NetworkImageView
+ buttonFollow = v.findViewById(R.id.button_user_detail_follow) as ThreeStateButton
+ buttonFollow.setOnClickListener(this)
+ listViewTimeline = v.findViewById(R.id.listview_user_detail_timeline) as PullToRefreshListView
+ listViewTimeline.setOnRefreshListener(this)
+
+ tabHost = v.findViewById(android.R.id.tabhost) as TabHost
+ tabHost.setup()
+ val tab1 = tabHost.newTabSpec("tab1").setContent(R.id.tab1).setIndicator(getString(R.string.user_detail_tab_info))
+ tabHost.addTab(tab1)
+ val tab2 = tabHost.newTabSpec("tab2").setContent(R.id.tab2).setIndicator(getString(R.string.user_detail_tab_timeline))
+ tabHost.addTab(tab2)
+ tabHost.currentTab = 0
+
+ initUserData()
+
+ return AlertDialog.Builder(activity)
+ .setView(v)
+ .setCancelable(true)
+ .create()
+ }
+
+ private fun executeUserTimelineTask(adapter: TimelineAdapter) {
+ val account = world.account
+ tabHost.tabWidget.getChildTabViewAt(1).visibility = View.GONE
+ Timelines.UserTimelineTask(account, user.id)
+ .setCount(200)
+ .onFail { x -> world.notifyError(R.string.notice_error_get_user_timeline) }
+ .onDoneUI { tweets ->
+ adapter.addAll(tweets)
+ adapter.updateForce()
+ tabHost.tabWidget.getChildTabViewAt(1).visibility = View.VISIBLE
+ }
+ .execute()
+ }
+
+ private val htmlDescription: String?
+ get() {
+ val description = user.description
+ if (TextUtils.isEmpty(description)) {
+ return ""
+ }
+ var html = description
+ html = html!!.replace("https?://[\\w/:%#$&?()~.=+-]+".toRegex(), "<a href=\"$0\">$0</a>")
+ html = html.replace("@([a-zA-Z0-9_]+)".toRegex(), "<a href=\"https://twitter.com/$1\">$0</a>")
+ html = html.replace("\r\n".toRegex(), "<br />")
+ return html
+ }
+
+ private fun updateUserDataBasic() {
+ textViewName.text = user.name
+ textViewScreenName.text = user.screenName
+ textViewProtected.visibility = if (user.isProtected) View.VISIBLE else View.GONE
+ imageViewIcon.setImageUrl(user.profileImageUrl, ImageCache.getImageLoader())
+ }
+
+ private fun updateUserDataDetail() {
+ if (TextUtils.isEmpty(user.location)) {
+ textViewLocate.visibility = View.GONE
+ } else {
+ textViewLocate.text = user.location
+ textViewLocate.visibility = View.VISIBLE
+ }
+ if (TextUtils.isEmpty(user.url)) {
+ textViewURL.visibility = View.GONE
+ } else {
+ textViewURL.text = user.url
+ textViewURL.visibility = View.VISIBLE
+ }
+ textViewDescription.text = Html.fromHtml(htmlDescription)
+
+ textViewTweetCount.text = user.statusesCount.toString()
+ textViewFriendCount.text = user.friendsCount.toString()
+ textViewFollowerCount.text = user.followersCount.toString()
+ textViewFavoriteCount.text = user.favoritesCount.toString()
+
+ imageViewHeader.setImageUrl(user.profileBannerUrl, ImageCache.getImageLoader())
+ }
+
+ private fun initUserData() {
+ updateUserDataBasic()
+ updateUserDataDetail()
+
+ val activity = activity as MainActivity
+ adapter = TimelineAdapter(activity)
+ listViewTimeline.setAdapter(adapter)
+ executeUserTimelineTask(adapter)
+ updateRelationship()
+
+ observerBundle.attach(user) { changes ->
+ if (getActivity() != null) {
+ if (changes.contains(RBinding.BASIC))
+ updateUserDataBasic()
+ if (changes.contains(RBinding.DETAIL))
+ updateUserDataDetail()
+ }
+ }
+ }
+
+ private fun openUserMenu() {
+ val builder = AlertDialog.Builder(activity)
+ builder.setTitle("@" + user.screenName)
+ .setItems(R.array.user_commands) { dialog, which ->
+ // XXX
+ UIHandler().postDelayed({
+ if (this@UserDetailDialogFragment.isAdded) {
+ updateRelationship()
+ }
+ }, 1000)
+ when (which) {
+ 0 -> {
+ val text = String.format("@%s ", user.screenName)
+ world.postState.beginTransaction().insertText(0, text).moveCursor(text.length).commit()
+ world.notify(R.string.notice_add_to_reply)
+ }
+ 1 -> DialogHelper.showDialog(activity, SendMessageDialogFragment.newInstance(user))
+ 2 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) {
+ Users.BlockTask(world.account, user.id)
+ .onDone { user -> world.notify(R.string.notice_block_succeeded) }
+ .onFail { ex -> world.notifyError(R.string.notice_block_failed) }
+ .execute()
+ }
+ 3 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) {
+ Users.UnblockTask(world.account, user.id)
+ .onDone { user -> world.notify(R.string.notice_unblock_succeeded) }
+ .onFail { x -> world.notifyError(R.string.notice_unblock_failed) }
+ .execute()
+ }
+ 4 -> ConfirmDialogFragment.show(activity, getString(R.string.dialog_confirm_commands)) {
+ Users.ReportForSpamTask(world.account, user.id)
+ .onDone { user -> world.notify(R.string.notice_r4s_succeeded) }
+ .onFail { ex -> world.notifyError(R.string.notice_r4s_failed) }
+ .execute()
+ }
+ 5 -> IntentUtils.openUri(activity, user.aclogTimelineURL)
+ else -> throw IllegalStateException()
+ }
+ }
+ val dialog = builder.create()
+ dialog.show()
+ }
+
+ private fun setFollowButtonState(isFollowing: Boolean) {
+ if (activity != null) {
+ buttonFollow.state = if (isFollowing) ThreeStateButton.STATE_ON else ThreeStateButton.STATE_OFF
+ }
+ }
+
+ private fun toggleFollowing() {
+ val account = world.account
+ val isFollowing = buttonFollow.state == ThreeStateButton.STATE_ON
+ buttonFollow.state = ThreeStateButton.STATE_LOCKED
+ if (isFollowing) {
+ Users.UnfollowTask(account, user.id)
+ .onDoneUI { result ->
+ world.notify(R.string.notice_unfollow_succeeded)
+ updateRelationship()
+ }
+ .onFail { x -> world.notifyError(R.string.notice_unfollow_failed) }
+ .execute()
+ } else {
+ Users.FollowTask(account, user.id)
+ .onDoneUI { result ->
+ world.notify(R.string.notice_follow_succeeded)
+ updateRelationship()
+ }
+ .onFail { x -> world.notifyError(R.string.notice_follow_failed) }
+ .execute()
+ }
+ }
+
+ private fun updateListView(absListView: AbsListView, adapter: TimelineAdapter, addedToTop: Boolean) {
+ 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() {
+ val account = world.account
+ if (user === account.user) {
+ textViewFollowed.setText(R.string.user_detail_followed_is_me)
+ buttonFollow.visibility = View.GONE
+ } else {
+ buttonFollow.state = ThreeStateButton.STATE_LOCKED
+ textViewFollowed.setText(R.string.user_detail_loading)
+ Users.ShowFriendshipTask(account, user.id).onDoneUI { relationship ->
+ val isFollowing = relationship.isSourceFollowingTarget
+ val isFollowed = relationship.isSourceFollowedByTarget
+ setFollowButtonState(isFollowing)
+ textViewFollowed.setText(if (isFollowed) R.string.user_detail_followed else R.string.user_detail_not_followed)
+ }.execute()
+ }
+ }
+
+ companion object {
+ private val KEY_USER_ID = "userID"
+
+ fun newInstance(user: User): UserDetailDialogFragment {
+ val obj = UserDetailDialogFragment()
+ val bundle = Bundle()
+ bundle.putLong(KEY_USER_ID, user.id)
+ obj.arguments = bundle
+ return obj
+ }
+ }
+}