diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2017-10-05 15:58:59 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2017-10-05 15:58:59 +0900 |
commit | 9db537d339faa3ad44dfdcadb23f4c14bd8aceb4 (patch) | |
tree | 6b151cdfd0ca7dc44b9a189045b2b2cbc5aefc21 /app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt | |
parent | 52ad6edcb217762154a80990c34ca94772393848 (diff) | |
download | SmileEssence-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.kt | 390 |
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 + } + } +} |