aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2017-10-15 23:19:50 +0900
committerKazuki Yamaguchi <k@rhe.jp>2017-10-15 23:23:10 +0900
commit3d7252fd5337d9d1acbca2db92ed88b638986f1e (patch)
tree06e4f06572e4300ed6e1d91ac816d5991268eb2f
parent95de1cbdd911f0f003ca19ef1421004d315d0ef4 (diff)
downloadSmileEssence-3d7252fd5337d9d1acbca2db92ed88b638986f1e.tar.gz
poststate moved to postfragmetn
-rw-r--r--app/build.gradle3
-rw-r--r--app/licenses.yml4
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/World.kt4
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt121
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/data/PostState.kt143
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt61
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt140
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt12
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt4
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt3
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt231
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt3
13 files changed, 278 insertions, 453 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 4192c6e2..082033f9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -32,6 +32,9 @@ android {
applicationIdSuffix ".release"
}
}
+ androidExtensions {
+ experimental = true
+ }
}
repositories {
diff --git a/app/licenses.yml b/app/licenses.yml
index 3294e321..4bcfa3aa 100644
--- a/app/licenses.yml
+++ b/app/licenses.yml
@@ -12,6 +12,10 @@
license: The Apache License, Version 2.0
- artifact: org.jetbrains.kotlinx:kotlinx-coroutines-android:+
skip: true
+- artifact: org.jetbrains.kotlin:kotlin-android-extensions-runtime:+
+ name: kotlin-android-extensions-runtime
+ copyrightHolder: JetBrains s.r.o.
+ license: The Apache License, Version 2.0
- artifact: com.android.support:+:+
name: Android Support Libraries
copyrightHolder: The Android Open Source Project
diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt
index 4c38c653..e74c9fa8 100644
--- a/app/src/main/java/net/lacolaco/smileessence/World.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/World.kt
@@ -7,7 +7,6 @@ import kotlinx.android.synthetic.main.layout_main.*
import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.compat.Twitter4J
import net.lacolaco.smileessence.data.Account
-import net.lacolaco.smileessence.data.PostState
import net.lacolaco.smileessence.entity.DirectMessage
import net.lacolaco.smileessence.entity.Event
import net.lacolaco.smileessence.entity.SavedSearch
@@ -30,10 +29,7 @@ import java.util.concurrent.ConcurrentHashMap
* World contains data that are specific to an account.
*/
class World(val account: Account) {
- // XXX: Move to MainActivity
- val postState = PostState()
// XXX: Workaround for a bug in Android
- @Deprecated("A temporary workaround")
var mainActivityIntent: Intent? = null
// Timelines
private val tweets = ArrayList<Tweet>()
diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt
index b286003a..d738d6b4 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt
@@ -20,13 +20,15 @@ import net.lacolaco.smileessence.Application
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.World
import net.lacolaco.smileessence.data.ExtractionWord
+import net.lacolaco.smileessence.entity.Tweet
+import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.logging.Logger
import net.lacolaco.smileessence.twitter.TwitterTaskException
import net.lacolaco.smileessence.twitter.task.getTweetAsync
import net.lacolaco.smileessence.twitter.task.getUserAsync
import net.lacolaco.smileessence.util.*
import net.lacolaco.smileessence.view.DialogHelper
-import net.lacolaco.smileessence.view.adapter.PageListAdapter
+import net.lacolaco.smileessence.view.MainFragmentPagerAdapter
import net.lacolaco.smileessence.view.confirm
import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment
import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment
@@ -42,18 +44,32 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
val userIdValue = uri.getQueryParameter("user_id") ?: throw IllegalStateException("[BUG] user_id not set")
Application.getWorld(userIdValue.toLong())
}
- private val pagerAdapter by lazy { PageListAdapter(this) }
+ private lateinit var pagerAdapter: MainFragmentPagerAdapter
+
+ fun openHomePage() {
+ viewPager.setCurrentItem(pagerAdapter.getPageIndex(TAG_PAGE_HOME), true)
+ }
private fun setSelectedPageIndex(position: Int, smooth: Boolean = true) {
viewPager.setCurrentItem(position, smooth)
}
- fun openHomePage() {
- setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment::class.java))
+ fun openPostPageAndReplyTo(tweet: Tweet, prefix: String) {
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.setInReplyTo(tweet, prefix)
+ setSelectedPageIndex(pagerAdapter.getPageIndex(TAG_PAGE_POST), true)
+ }
+
+ fun openPostPageAndReplyTo(user: User) {
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.setInReplyTo(user)
+ setSelectedPageIndex(pagerAdapter.getPageIndex(TAG_PAGE_POST), true)
}
- fun openPostPage() {
- setSelectedPageIndex(pagerAdapter.getIndex(PostFragment::class.java))
+ fun openPostPageAndAppendText(text: String) {
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.appendText(text)
+ setSelectedPageIndex(pagerAdapter.getPageIndex(TAG_PAGE_POST), true)
}
private fun openPostPageWithImage(uri: Uri) {
@@ -61,9 +77,8 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
val c = contentResolver.query(uri, null, null, null, null)!!
c.moveToFirst()
val path = c.getString(c.getColumnIndex(MediaStore.MediaColumns.DATA))
- world.postState.beginTransaction()
- .setMediaFilePath(path)
- .commitWithOpen(this)
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.setMediaFilePath(path)
world.notify(R.string.notice_select_image_succeeded)
c.close()
} catch (e: Exception) {
@@ -74,23 +89,13 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
}
fun openSearchPage(query: String) {
- val fragment = pagerAdapter.getCachedFragment(pagerAdapter.getIndex(SearchFragment::class.java)) as SearchFragment?
- if (fragment != null) {
- fragment.startSearch(query)
- setSelectedPageIndex(pagerAdapter.getIndex(SearchFragment::class.java))
- }
- }
-
- fun openUserListPage(listFullName: String) {
- val fragment = pagerAdapter.getCachedFragment(pagerAdapter.getIndex(UserListFragment::class.java)) as UserListFragment?
- if (fragment != null) {
- fragment.startUserList(listFullName)
- setSelectedPageIndex(pagerAdapter.getIndex(UserListFragment::class.java))
- }
+ val fragment = pagerAdapter.getPageFragment(TAG_PAGE_SEARCH) as SearchFragment
+ fragment.startSearch(query)
+ setSelectedPageIndex(pagerAdapter.getPageIndex(TAG_PAGE_SEARCH))
}
private fun setTitle() {
- title = String.format("%s / %s", world.account.user.screenName, pagerAdapter.getName(viewPager.currentItem))
+ //title = String.format("%s / %s", world.account.user.screenName, pagerAdapter.getName(viewPager.currentItem))
val label = getString(R.string.app_name) + " - @" + world.account.user.screenName
if (android.os.Build.VERSION.SDK_INT >= 21) {
setTaskDescription(ActivityManager.TaskDescription(label, null, world.account.themeColor))
@@ -168,7 +173,9 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
val via = uri.getQueryParameter("via")
if (!TextUtils.isEmpty(via))
text += " via @" + via
- world.postState.beginTransaction().setText(text).commitWithOpen(this)
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.setText(text)
+ viewPager.setCurrentItem(pagerAdapter.getPageIndex(TAG_PAGE_POST), true)
return
}
val statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.path)
@@ -204,7 +211,9 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) {
text = extra.getCharSequence(Intent.EXTRA_SUBJECT).toString() + " " + text
}
- world.postState.beginTransaction().setText(text).commitWithOpen(this)
+ val postPage = pagerAdapter.getPageFragment(TAG_PAGE_POST) as PostFragment
+ postPage.setText(text)
+ viewPager.setCurrentItem(pagerAdapter.getPageIndex(TAG_PAGE_POST), true)
return
}
} else if (type != null && type.startsWith("image/")) {
@@ -217,16 +226,15 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
// ------------------------ OVERRIDE METHODS ------------------------
override fun onBackPressed() {
- this.finish()
+ finish()
}
override fun finish() {
- val homeIndex = pagerAdapter.getIndex(HomeFragment::class.java)
- if (viewPager.currentItem != homeIndex) {
+ val homeIndex = pagerAdapter.getPageIndex(TAG_PAGE_HOME)
+ if (viewPager.currentItem != homeIndex)
viewPager.setCurrentItem(homeIndex, true)
- } else {
+ else
confirm(R.string.dialog_confirm_finish_app) { super.finish() }
- }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -255,23 +263,31 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
setContentView(R.layout.layout_main)
setSupportActionBar(toolbar)
- viewPager.addOnPageChangeListener(this)
- //actionBar.setDisplayHomeAsUpEnabled(true)
-
- // TODO: tab order?
val args = Bundle()
args.putLong(PageFragment.KEY_WORLD_USER_ID, account.id)
- pagerAdapter.addPage(PostFragment::class.java, getString(R.string.page_name_post), args, false)
- pagerAdapter.addPage(HomeFragment::class.java, getString(R.string.page_name_home), args, false)
- pagerAdapter.addPage(MentionsFragment::class.java, getString(R.string.page_name_mentions), args, false)
- pagerAdapter.addPage(HistoryFragment::class.java, getString(R.string.page_name_history), args, false)
- pagerAdapter.addPage(MessagesFragment::class.java, getString(R.string.page_name_messages), args, false)
- pagerAdapter.addPage(SearchFragment::class.java, getString(R.string.page_name_search), args, false)
- pagerAdapter.addPage(UserListFragment::class.java, getString(R.string.page_name_list), args, false)
+ pagerAdapter = MainFragmentPagerAdapter(fragmentManager, viewPager)
+ pagerAdapter.addPage(TAG_PAGE_POST, PostFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_HOME, HomeFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_MENTIONS, MentionsFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_EVENTS, HistoryFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_MESSAGES, MessagesFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_SEARCH, SearchFragment::class.java, args)
+ pagerAdapter.addPage(TAG_PAGE_LIST, UserListFragment::class.java, args)
pagerAdapter.notifyDataSetChanged()
+
+ // TODO: tab order?
+ getString(R.string.page_name_post)
+ getString(R.string.page_name_home)
+ getString(R.string.page_name_mentions)
+ getString(R.string.page_name_history)
+ getString(R.string.page_name_messages)
+ getString(R.string.page_name_search)
+ getString(R.string.page_name_list)
+
+ viewPager.addOnPageChangeListener(this)
viewPager.offscreenPageLimit = pagerAdapter.count
viewPager.adapter = pagerAdapter
- setSelectedPageIndex(pagerAdapter.getIndex(HomeFragment::class.java), false)
+ viewPager.setCurrentItem(pagerAdapter.getPageIndex(TAG_PAGE_HOME), false)
ExtractionWord.load()
@@ -281,7 +297,7 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
world.refreshSavedSearches()
launchUi {
- val user = try {
+ try {
world.getUserAsync(world.account.id)
} catch (e: TwitterTaskException) {
return@launchUi
@@ -292,15 +308,6 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
// Set application title
setTitle()
- // refresh all pages
- for (i in 0 until pagerAdapter.count) {
- val pf = pagerAdapter.getCachedFragment(i)
- if (pf != null && pf.isAdded) {
- Logger.debug(String.format("PageFragment %s is already attached; refreshing", pf.javaClass.name))
- pf.refresh()
- }
- }
-
// start user stream
world.setupStreaming()
@@ -357,7 +364,8 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
override fun onPageSelected(position: Int) {
Logger.debug("Page selected: " + position)
- setTitle()
+ //title = String.format("%s / %s", world.account.user.screenName, pagerAdapter.getName(viewPager.currentItem))
+ //setTitle()
}
override fun onPageScrollStateChanged(state: Int) {}
@@ -370,5 +378,12 @@ class MainActivity : AppCompatActivity(), ViewPager.OnPageChangeListener {
private val TWITTER_STATUS_PATTERN = Pattern.compile("\\A(?:/#!)?/(?:\\w{1,15})/status(?:es)?/(\\d+)\\z", Pattern.CASE_INSENSITIVE)
private val TWITTER_USER_PATTERN = Pattern.compile("\\A(?:/#!)?/(\\w{1,15})/?\\z", Pattern.CASE_INSENSITIVE)
+ private val TAG_PAGE_POST = "PAGE_POST"
+ private val TAG_PAGE_HOME = "PAGE_HOME"
+ private val TAG_PAGE_MENTIONS = "PAGE_MENTIONS"
+ private val TAG_PAGE_EVENTS = "PAGE_EVENTS"
+ private val TAG_PAGE_MESSAGES = "PAGE_MESSAGES"
+ private val TAG_PAGE_SEARCH = "PAGE_SEARCH"
+ private val TAG_PAGE_LIST = "PAGE_LIST"
}
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt b/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt
index 9565f4c0..4012891c 100644
--- a/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/command/CommandAddHashtag.kt
@@ -18,7 +18,7 @@ class CommandAddHashtag
// -------------------------- OTHER METHODS --------------------------
override fun execute(): Boolean {
- activity.world.postState.beginTransaction().appendText(" #" + hashtag).commit()
+ activity.openPostPageAndAppendText(" #" + hashtag)
return true
}
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt b/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt
deleted file mode 100644
index 74a09179..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/data/PostState.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package net.lacolaco.smileessence.data
-
-import net.lacolaco.smileessence.activity.MainActivity
-import net.lacolaco.smileessence.entity.Tweet
-import net.lacolaco.smileessence.view.DialogHelper
-import twitter4j.StatusUpdate
-
-class PostState {
- var text = ""
- private set
- var inReplyTo: Tweet? = null
- private set
- var mediaFilePath = ""
- private set
- private var listener: OnPostStateChangeListener? = null
- var selectionStart: Int = 0
- get() {
- return if (field < 0) {
- text.length
- } else field
- }
- var selectionEnd: Int = 0
- get() {
- return if (field < 0) {
- text.length
- } else field
- }
-
- fun setListener(listener: OnPostStateChangeListener): PostState {
- this.listener = listener
- return this
- }
-
- fun beginTransaction(): PostStateTransaction {
- return PostStateTransaction(this)
- }
-
- fun removeListener() {
- this.listener = null
- }
-
- /**
- * Convert to StatusUpdate for tweet.
- *
- * @return StatusUpdate
- */
- fun toStatusUpdate(): StatusUpdate {
- val su = StatusUpdate(text)
- if (inReplyTo != null) {
- su.inReplyToStatusId = inReplyTo!!.id
- }
- return su
- }
-
- private fun copy(another: PostState): PostState {
- this.text = another.text
- this.inReplyTo = another.inReplyTo
- this.mediaFilePath = another.mediaFilePath
- this.selectionStart = another.selectionStart
- this.selectionEnd = another.selectionEnd
- this.listener = another.listener
- return this
- }
-
- private fun postStateChange() {
- if (listener != null) {
- listener!!.onPostStateChange(this)
- }
- }
-
- // -------------------------- INNER CLASSES --------------------------
-
- interface OnPostStateChangeListener {
-
- fun onPostStateChange(postState: PostState)
- }
-
- class PostStateTransaction constructor(private val origState: PostState) {
- private val state: PostState = PostState().copy(origState)
-
- fun setText(text: String): PostStateTransaction {
- state.text = text
- return this
- }
-
- fun appendText(text: String): PostStateTransaction {
- state.text = state.text + text
- return this
- }
-
- fun insertText(index: Int, text: String): PostStateTransaction {
- val builder = StringBuilder(state.text)
- builder.insert(index, text)
- state.text = builder.toString()
- return this
- }
-
- fun setInReplyTo(inReplyTo: Tweet?): PostStateTransaction {
- state.inReplyTo = inReplyTo
- return this
- }
-
- fun setMediaFilePath(mediaFilePath: String): PostStateTransaction {
- state.mediaFilePath = mediaFilePath
- return this
- }
-
- fun setCursor(cursor: Int): PostStateTransaction {
- state.selectionEnd = cursor
- state.selectionStart = state.selectionEnd
- return this
- }
-
- fun setSelection(start: Int, end: Int): PostStateTransaction {
- state.selectionStart = start
- state.selectionEnd = end
- return this
- }
-
- fun clear(): PostStateTransaction {
- state.text = ""
- state.selectionEnd = 0
- state.selectionStart = state.selectionEnd
- state.inReplyTo = null
- return this
- }
-
- fun commit() {
- origState.copy(state).postStateChange()
- }
-
- fun commitWithOpen(activity: MainActivity) {
- DialogHelper.closeAll(activity)
- origState.copy(state).postStateChange()
- activity.openPostPage()
- }
-
- fun moveCursor(length: Int): PostStateTransaction {
- val cursor = state.selectionEnd + length
- return setCursor(cursor)
- }
- }
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt
new file mode 100644
index 00000000..add4c958
--- /dev/null
+++ b/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt
@@ -0,0 +1,61 @@
+package net.lacolaco.smileessence.view
+
+import android.app.Fragment
+import android.app.FragmentManager
+import android.os.Bundle
+import android.support.v13.app.FragmentPagerAdapter
+import android.support.v4.util.ArrayMap
+import android.support.v4.view.ViewPager
+import android.view.ViewGroup
+import net.lacolaco.smileessence.view.page.PageFragment
+
+class MainFragmentPagerAdapter(fm: FragmentManager, private val viewPager: ViewPager) :
+ FragmentPagerAdapter(fm) {
+ private val pageTags = ArrayList<String>()
+ private val pages = ArrayMap<String, PageInfo>()
+
+ fun addPage(tag: String, clazz: Class<out PageFragment>, args: Bundle? = null) {
+ assert(pages[tag] == null)
+ pages[tag] = PageInfo(clazz, args)
+ pageTags.add(tag)
+ }
+
+ fun getPageFragment(tag: String): PageFragment {
+ // XXX: This is really an ugly workaround.
+ return pages[tag]!!.fragment ?: instantiateItem(viewPager, getPageIndex(tag)) as PageFragment
+ }
+
+ fun getPageIndex(tag: String): Int {
+ return pageTags.indexOf(tag)
+ }
+
+ override fun getItem(position: Int): Fragment {
+ val info = pages[pageTags[position]]!!
+ assert(info.fragment == null)
+ val fragment = info.clazz.newInstance()
+ if (info.args != null)
+ fragment.arguments = info.args
+ return fragment
+ }
+
+ override fun getCount(): Int {
+ return pages.size
+ }
+
+ override fun instantiateItem(container: ViewGroup, position: Int): Any {
+ val info = pages[pageTags[position]]!!
+ val fragment = super.instantiateItem(container, position)
+ info.fragment = fragment as PageFragment
+ return fragment
+ }
+
+ override fun destroyItem(container: ViewGroup?, position: Int, `object`: Any?) {
+ throw IllegalStateException("Fragments must not be destroyed by ViewPager")
+ }
+
+ private class PageInfo(
+ val clazz: Class<out PageFragment>,
+ val args: Bundle?,
+ var fragment: PageFragment? = null
+ )
+}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt
deleted file mode 100644
index 9589ffef..00000000
--- a/app/src/main/java/net/lacolaco/smileessence/view/adapter/PageListAdapter.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-package net.lacolaco.smileessence.view.adapter
-
-import android.app.Fragment
-import android.app.FragmentManager
-import android.app.FragmentTransaction
-import android.os.Bundle
-import android.support.v4.view.PagerAdapter
-import android.view.View
-import android.view.ViewGroup
-import net.lacolaco.smileessence.BuildConfig
-import net.lacolaco.smileessence.activity.MainActivity
-import net.lacolaco.smileessence.logging.Logger
-import net.lacolaco.smileessence.view.page.PageFragment
-import java.lang.ref.WeakReference
-import java.util.*
-
-class PageListAdapter(_activity: MainActivity) : PagerAdapter() {
- private val mFragmentManager: FragmentManager = _activity.fragmentManager
- private var mCurTransaction: FragmentTransaction? = null
- private var mCurrentPrimaryItem: Fragment? = null
- private val pages = ArrayList<PageInfo>()
- private val fragmentCache = HashMap<Int, WeakReference<PageFragment>>()
-
- @Synchronized
- fun getItem(position: Int): PageFragment {
- val pf: PageFragment
- val info = pages[position]
- try {
- pf = info.fragmentClass.newInstance()
- } catch (e: Exception) {
- Logger.error("should not happen: fragmentClass is private or Android is broken?")
- e.printStackTrace()
- throw RuntimeException(e)
- }
-
- pf.arguments = info.args
- fragmentCache.put(position, WeakReference(pf))
- return pf
- }
-
- @Synchronized
- fun getCachedFragment(pos: Int): PageFragment? {
- val wpf = fragmentCache[pos]
- return wpf?.get()
- }
-
- @Synchronized override fun getCount(): Int {
- return pages.size
- }
-
- fun addPage(klass: Class<out PageFragment>, name: String, args: Bundle, notifyChanged: Boolean) {
- pages.add(PageInfo(klass, name, args))
- if (notifyChanged) notifyDataSetChanged()
- }
-
- fun getName(pos: Int): String {
- return pages[pos].name
- }
-
- @Deprecated("")
- fun getIndex(fragmentClass: Class<out PageFragment>): Int {
- for (i in pages.indices) {
- if (pages[i].fragmentClass == fragmentClass) {
- return i
- }
- }
- return -1
- }
-
- private class PageInfo internal constructor(val fragmentClass: Class<out PageFragment>, val name: String, val args: Bundle)
-
- override fun startUpdate(container: ViewGroup) {
- assert(container.id != View.NO_ID)
- }
-
- override fun instantiateItem(container: ViewGroup, position: Int): Any {
- if (mCurTransaction == null) {
- mCurTransaction = mFragmentManager.beginTransaction()
- }
-
- val itemId = position.toLong()
-
- // Do we already have this fragment?
- val name = "android:switcher:${container.id}:$itemId"
- var fragment: Fragment? = mFragmentManager.findFragmentByTag(name)
- if (fragment != null) {
- if (BuildConfig.DEBUG)
- Logger.verbose("Attaching item #$itemId: f=$fragment")
- mCurTransaction!!.attach(fragment)
- } else {
- fragment = getItem(position)
- if (BuildConfig.DEBUG)
- Logger.verbose("Adding item #$itemId: f=$fragment")
- mCurTransaction!!.add(container.id, fragment, "android:switcher:${container.id}:$itemId")
- }
- if (fragment !== mCurrentPrimaryItem) {
- fragment.setMenuVisibility(false)
- fragment.userVisibleHint = false
- }
-
- return fragment
- }
-
- override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
- if (mCurTransaction == null) {
- mCurTransaction = mFragmentManager.beginTransaction()
- }
- if (BuildConfig.DEBUG)
- Logger.verbose("Detaching item #" + position + ": f=" + `object`
- + " v=" + (`object` as Fragment).view)
- mCurTransaction!!.detach(`object` as Fragment)
- }
-
- override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) {
- val fragment = `object` as Fragment?
- if (fragment !== mCurrentPrimaryItem) {
- if (mCurrentPrimaryItem != null) {
- mCurrentPrimaryItem!!.setMenuVisibility(false)
- mCurrentPrimaryItem!!.userVisibleHint = false
- }
- if (fragment != null) {
- fragment.setMenuVisibility(true)
- fragment.userVisibleHint = true
- }
- mCurrentPrimaryItem = fragment
- }
- }
-
- override fun finishUpdate(container: ViewGroup) {
- if (mCurTransaction != null) {
- mCurTransaction!!.commitAllowingStateLoss()
- mCurTransaction = null
- mFragmentManager.executePendingTransactions()
- }
- }
-
- override fun isViewFromObject(view: View, `object`: Any): Boolean {
- return (`object` as Fragment).view === view
- }
-}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt
index 97134ce4..78c67ce6 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt
@@ -6,7 +6,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.dialog_status_detail.view.*
-import kotlinx.android.synthetic.main.menu_item_simple_text.view.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.command.Command
@@ -109,12 +108,7 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
val text = builder.toString()
val selStart = originalTweet.user.screenName.length + 2 // "@" and " "
- world.postState.beginTransaction()
- .clear()
- .insertText(0, text)
- .setInReplyTo(originalTweet)
- .setSelection(selStart, text.length)
- .commitWithOpen(activity as MainActivity)
+ (activity as MainActivity).openPostPageAndReplyTo(originalTweet, text)
}
view.button_status_detail_retweet.setOnClickListener {
val account = world.account
@@ -181,7 +175,7 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
val popup = PopupMenu(activity, view.button_status_detail_menu)
popup.add(R.string.command_status_add_to_reply) {
val text = String.format("@%s ", tweet.originalTweet.user.screenName)
- world.postState.beginTransaction().insertText(0, text).moveCursor(text.length).commit()
+ (activity as MainActivity).openPostPageAndAppendText(text)
world.notify(R.string.notice_add_to_reply)
}
popup.add(R.string.command_status_open_talk_view) {
@@ -222,7 +216,7 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
val adapter = object : UnorderedCustomListAdapter<Command>(commands) {
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val itemView = convertView ?: activity.layoutInflater.inflate(R.layout.menu_item_simple_text, parent, false)
- itemView.list_item_textview.text = getItem(position).text
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.itemView.list_item_textview.text = getItem(position).text
return itemView
}
}
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 e68a38a1..d4bea45f 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
@@ -11,6 +11,7 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirec
import kotlinx.android.synthetic.main.dialog_user_detail.*
import kotlinx.android.synthetic.main.dialog_user_detail.view.*
import net.lacolaco.smileessence.R
+import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.data.ImageCache
import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.twitter.TwitterTaskException
@@ -30,8 +31,7 @@ class UserDetailDialogFragment : StackableDialogFragment() {
private fun showPopupMenu() {
val popup = PopupMenu(activity, imageview_user_detail_menu)
popup.add(R.string.command_user_add_to_reply) {
- val text = String.format("@%s ", user.screenName)
- world.postState.beginTransaction().insertText(0, text).moveCursor(text.length).commit()
+ (activity as MainActivity).openPostPageAndReplyTo(user)
world.notify(R.string.notice_add_to_reply)
}
popup.add(R.string.command_user_send_message) {
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 81db9412..f23a9edf 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
@@ -3,6 +3,9 @@ package net.lacolaco.smileessence.view.page
import android.app.Fragment
import net.lacolaco.smileessence.Application
+/**
+ * A PageFragment is always attached to a MainActivity.
+ */
abstract class PageFragment : Fragment() {
protected val world by lazy {
Application.getWorld(arguments.getLong(KEY_WORLD_USER_ID))
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt
index 044261f4..93cb670f 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/PostFragment.kt
@@ -1,8 +1,10 @@
package net.lacolaco.smileessence.view.page
+import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Bundle
+import android.os.Parcelable
import android.support.v4.content.ContextCompat
import android.text.Editable
import android.text.Spannable
@@ -12,12 +14,13 @@ import android.text.method.ArrowKeyMovementMethod
import android.view.*
import android.widget.TextView
import com.twitter.Validator
+import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_post.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.activity.MainActivity
-import net.lacolaco.smileessence.data.PostState
+import net.lacolaco.smileessence.entity.Tweet
+import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.logging.Logger
-import net.lacolaco.smileessence.preference.UserPreferenceHelper
import net.lacolaco.smileessence.twitter.TwitterTaskException
import net.lacolaco.smileessence.twitter.task.createTweetAsync
import net.lacolaco.smileessence.util.BitmapThumbnailTask
@@ -25,28 +28,60 @@ import net.lacolaco.smileessence.util.SystemServiceHelper
import net.lacolaco.smileessence.util.UIHandler
import net.lacolaco.smileessence.util.launchUi
import net.lacolaco.smileessence.view.Partials
+import twitter4j.StatusUpdate
import java.io.File
-class PostFragment : PageFragment(), TextWatcher, PostState.OnPostStateChangeListener {
+class PostFragment : PageFragment(), TextWatcher {
+ private lateinit var postState: PostState
+
override fun refresh() {}
- override fun onPostStateChange(postState: PostState) {
+ fun setMediaFilePath(path: String) {
+ postState.mediaFilePath = path
+ onPostStateChange()
+ }
+
+ fun setInReplyTo(tweet: Tweet, prefix: String) {
+ postState.inReplyTo = tweet
+ postState.text = prefix + postState.text
+ postState.selectionStart = prefix.length
+ postState.selectionEnd = prefix.length
+ onPostStateChange()
+ }
+
+ fun setInReplyTo(user: User) {
+ val prefix = "@${user.screenName} "
+ postState.text = prefix + postState.text
+ postState.selectionStart += prefix.length
+ postState.selectionEnd += prefix.length
+ onPostStateChange()
+ }
+
+ fun setText(text: String) {
+ postState.text = text
+ onPostStateChange()
+ }
+
+ fun appendText(text: String) {
+ postState.text += text
+ onPostStateChange()
+ }
+
+ private fun onPostStateChange() {
Logger.debug("onPostStateChange")
- val activity = activity as MainActivity
- val start = postState.selectionStart
- val end = postState.selectionEnd
post_edit_text.removeTextChangedListener(this)
post_edit_text.setTextKeepState(postState.text)
post_edit_text.addTextChangedListener(this)
updateTextCount(post_edit_text.text)
- UIHandler().postAtFrontOfQueue { post_edit_text.setSelection(start, end) }
+ UIHandler().postAtFrontOfQueue {
+ post_edit_text.setSelection(postState.selectionStart, postState.selectionEnd)
+ }
if (postState.inReplyTo != null) {
post_inreplyto_parent.visibility = View.VISIBLE
-
- val tweet = postState.inReplyTo
- val header = Partials.getTweetView(tweet!!, world, activity, layout_post_reply_status)
- header.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.transparent))
+ val header = Partials.getTweetView(postState.inReplyTo!!, world, activity,
+ layout_post_reply_status)
+ header.setBackgroundColor(ContextCompat.getColor(activity, R.color.transparent))
header.isClickable = false
} else {
post_inreplyto_parent.visibility = View.GONE
@@ -60,18 +95,19 @@ class PostFragment : PageFragment(), TextWatcher, PostState.OnPostStateChangeLis
BitmapThumbnailTask(postState.mediaFilePath, image_post_media).execute()
}
- // --------------------- Interface TextWatcher ---------------------
-
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
updateTextCount(s)
+ postState.text = s.toString()
}
+ override fun afterTextChanged(s: Editable) {}
+
private fun updateTextCount(s: CharSequence) {
val validator = Validator()
var length = validator.getTweetLength(s.toString())
- if (!TextUtils.isEmpty(world.postState.mediaFilePath))
+ if (!TextUtils.isEmpty(postState.mediaFilePath))
length += validator.shortUrlLength
post_text_count.text = length.toString()
@@ -81,12 +117,20 @@ class PostFragment : PageFragment(), TextWatcher, PostState.OnPostStateChangeLis
} else {
post_text_count.setTextAppearance(activity, android.R.style.TextAppearance_Widget_TextView)
}
- setStateFromView()
}
- override fun afterTextChanged(s: Editable) {}
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (savedInstanceState != null)
+ postState = savedInstanceState.getParcelable(KEY_POST_STATE)
+ else
+ postState = PostState()
+ }
- // ------------------------ OVERRIDE METHODS ------------------------
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putParcelable(KEY_POST_STATE, postState)
+ }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
@@ -94,14 +138,11 @@ class PostFragment : PageFragment(), TextWatcher, PostState.OnPostStateChangeLis
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- setHasOptionsMenu(true)
return inflater.inflate(R.layout.fragment_post, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- world.postState.setListener(this)
- button_post_tweet.setOnClickListener { submitPost() }
post_edit_text.addTextChangedListener(this)
post_edit_text.setOnFocusChangeListener { _, hasFocus ->
if (hasFocus)
@@ -111,92 +152,84 @@ class PostFragment : PageFragment(), TextWatcher, PostState.OnPostStateChangeLis
}
post_edit_text.movementMethod = object : ArrowKeyMovementMethod() {
override fun right(widget: TextView, buffer: Spannable): Boolean {
- //Don't back to Home
+ // Don't back to Home
return widget.selectionEnd == widget.length() || super.right(widget, buffer)
}
}
- button_post_delete.setOnClickListener { deletePost() }
- button_post_media.setOnClickListener { setImage() }
- //Reply view
- button_post_reply_delete.setOnClickListener { deleteReply() }
- //Media view
- image_post_media.setOnClickListener { displayImage() }
- button_post_media_delete.setOnClickListener { removeImage() }
- }
-
- override fun onDestroyView() {
- Logger.debug("onDestroyView")
- super.onDestroyView()
- setStateFromView()
- world.postState.removeListener()
- }
-
- override fun onViewStateRestored(savedInstanceState: Bundle?) {
- Logger.debug("onViewStateRestored")
- super.onViewStateRestored(savedInstanceState)
- val state = world.postState
- onPostStateChange(state)
- }
-
- private fun deletePost() {
- post_edit_text.setText("")
- world.postState.beginTransaction().setText("").setCursor(0).commit()
- deleteReply()
- }
-
- private fun deleteReply() {
- post_inreplyto_parent.visibility = View.GONE
- world.postState.beginTransaction().setInReplyTo(null).commit()
- }
-
- private fun displayImage() {
- val intent = Intent(Intent.ACTION_VIEW)
- intent.addCategory(Intent.CATEGORY_DEFAULT)
- intent.setDataAndType(Uri.fromFile(File(world.postState.mediaFilePath)), "image/*")
- startActivity(intent)
- }
+ button_post_tweet.setOnClickListener {
+ SystemServiceHelper.hideIM(activity, post_edit_text)
+ launchUi {
+ try {
+ val su = StatusUpdate(postState.text)
+ if (postState.inReplyTo != null) {
+ su.inReplyToStatusId = postState.inReplyTo!!.id
+ }
+ world.createTweetAsync(su, postState.mediaFilePath, false).await()
+ world.notify(R.string.notice_tweet_succeeded)
+ postState.clear()
+ } catch (e: TwitterTaskException) {
+ world.notifyError(R.string.notice_tweet_failed, e)
+ }
+ }
+ (activity as MainActivity).openHomePage()
+ }
+ button_post_reply_delete.setOnClickListener {
+ postState.inReplyTo = null
+ onPostStateChange()
+ }
+ button_post_delete.setOnClickListener {
+ postState.clear()
+ onPostStateChange()
+ }
+ button_post_media.setOnClickListener {
+ SystemServiceHelper.hideIM(activity, post_edit_text)
- private fun removeImage() {
- SystemServiceHelper.hideIM(activity, post_edit_text)
- post_media_parent.visibility = View.GONE
- image_post_media.setImageBitmap(null)
- world.postState.beginTransaction().setMediaFilePath("").commit()
+ val intent = Intent(Intent.ACTION_PICK)
+ intent.type = "image/*"
+ startActivityForResult(intent, MainActivity.REQUEST_GET_PICTURE_FROM_GALLERY)
+ }
+ image_post_media.setOnClickListener {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.addCategory(Intent.CATEGORY_DEFAULT)
+ intent.setDataAndType(Uri.fromFile(File(postState.mediaFilePath)), "image/*")
+ startActivity(intent)
+ }
+ button_post_media_delete.setOnClickListener {
+ SystemServiceHelper.hideIM(activity, post_edit_text)
+ post_media_parent.visibility = View.GONE
+ image_post_media.setImageBitmap(null)
+ postState.mediaFilePath = ""
+ onPostStateChange()
+ }
+ onPostStateChange()
}
- private fun setImage() {
- setStateFromView()
- SystemServiceHelper.hideIM(activity, post_edit_text)
-
- val intent = Intent(Intent.ACTION_PICK)
- intent.type = "image/*"
- startActivityForResult(intent, MainActivity.REQUEST_GET_PICTURE_FROM_GALLERY)
- }
+ // FIXME: Remove @SuppressList
+ @SuppressLint("ParcelCreator")
+ @Parcelize
+ private class PostState(
+ var text: String = "",
+ private var inReplyToId: Long = -1,
+ var mediaFilePath: String = "",
+ var selectionStart: Int = 0,
+ var selectionEnd: Int = 0
+ ) : Parcelable {
+ var inReplyTo: Tweet?
+ get() = if (inReplyToId != -1L) Tweet.fetch(inReplyToId) else null
+ set(value) {
+ inReplyToId = value?.id ?: -1
+ }
- private fun setStateFromView() {
- val state = world.postState
- state.removeListener()
- state.beginTransaction()
- .setText(post_edit_text.text.toString())
- .setSelection(post_edit_text.selectionStart, post_edit_text.selectionEnd)
- .commit()
- state.setListener(this)
+ fun clear() {
+ text = ""
+ inReplyTo = null
+ mediaFilePath = ""
+ selectionStart = 0
+ selectionEnd = 0
+ }
}
- private fun submitPost() {
- SystemServiceHelper.hideIM(activity, post_edit_text)
- setStateFromView()
- launchUi {
- val state = world.postState
- val resizeFlag = UserPreferenceHelper.instance[R.string.key_setting_resize_post_image, false]
- try {
- val t = world.createTweetAsync(state.toStatusUpdate(), state.mediaFilePath, resizeFlag).await()
- world.notify(R.string.notice_tweet_succeeded)
- world.postState.beginTransaction().clear().commit()
- } catch (e: TwitterTaskException) {
- world.notifyError(R.string.notice_tweet_failed, e)
- }
- }
- val mainActivity = activity as MainActivity
- mainActivity.openHomePage()
+ companion object {
+ val KEY_POST_STATE = "POST_STATE"
}
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt
index 2bedf71d..55193aea 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/UserListFragment.kt
@@ -9,7 +9,6 @@ import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
import kotlinx.android.synthetic.main.fragment_userlist.*
import kotlinx.coroutines.experimental.Deferred
import net.lacolaco.smileessence.R
-import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.entity.Tweet
import net.lacolaco.smileessence.preference.UserPreferenceHelper
import net.lacolaco.smileessence.twitter.TwitterTaskException
@@ -75,7 +74,7 @@ class UserListFragment : CustomListFragment<TimelineAdapter>() {
for (name in world.listSubscriptions) {
popup.add(name) {
textview_userlist_name.text = name
- (activity as MainActivity).openUserListPage(name)
+ startUserList(name)
}
}
popup.show()