aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2019-03-25 23:29:17 +0900
committerKazuki Yamaguchi <k@rhe.jp>2019-03-25 23:29:17 +0900
commitfedd5082d627a9f732887be26ce0a8f95eb5ca20 (patch)
tree23b705b29940c0fd952e170e7565d7da92103ca6
parentf783d6ab9afa579c91e73305ffdd66df60ce5efa (diff)
downloadSmileEssence-fedd5082d627a9f732887be26ce0a8f95eb5ca20.tar.gz
make everything a page
-rw-r--r--app/src/main/AndroidManifest.xml3
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/Application.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/World.kt22
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt109
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt26
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/ManageProfilesActivity.kt20
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/data/Pages.kt36
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt3
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/util/IntentHelper.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/Confirmation.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt154
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/Partials.kt7
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/AppInfoDialogFragment.kt10
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTweetsPageDialogFragment.kt6
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt2
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/ComposePageFragment.kt6
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/EventsPageFragment.kt6
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/PageFragment.kt10
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/TimelinePageFragment.kt6
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/TweetPageFragment.kt (renamed from app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt)40
-rw-r--r--app/src/main/java/net/lacolaco/smileessence/view/page/UserPageFragment.kt (renamed from app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt)134
-rw-r--r--app/src/main/res/drawable/follow_button.xml3
-rw-r--r--app/src/main/res/drawable/ic_add_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_clear_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_delete_forever_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_image_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_lock_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_more_vert_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_repeat_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_reply_all_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_save_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_search_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_star_black_24dp.xml3
-rw-r--r--app/src/main/res/drawable/ic_view_list_black_24dp.xml3
-rw-r--r--app/src/main/res/layout/activity_main.xml3
-rw-r--r--app/src/main/res/layout/activity_manage_pages.xml3
-rw-r--r--app/src/main/res/layout/activity_manage_profiles.xml3
-rw-r--r--app/src/main/res/layout/dialog_app_info.xml3
-rw-r--r--app/src/main/res/layout/dialog_edit_tweets_page.xml3
-rw-r--r--app/src/main/res/layout/item_compose_media.xml3
-rw-r--r--app/src/main/res/layout/item_status_base.xml3
-rw-r--r--app/src/main/res/layout/layout_oauth.xml3
-rw-r--r--app/src/main/res/layout/list_item_event.xml6
-rw-r--r--app/src/main/res/layout/list_item_page.xml3
-rw-r--r--app/src/main/res/layout/list_item_profile.xml3
-rw-r--r--app/src/main/res/layout/list_item_simple_text.xml3
-rw-r--r--app/src/main/res/layout/list_item_tweet.xml3
-rw-r--r--app/src/main/res/layout/menu_item_simple_text.xml5
-rw-r--r--app/src/main/res/layout/page_fragment_compose.xml3
-rw-r--r--app/src/main/res/layout/page_fragment_list.xml3
-rw-r--r--app/src/main/res/layout/page_fragment_refreshable_timeline.xml3
-rw-r--r--app/src/main/res/layout/page_fragment_search.xml3
-rw-r--r--app/src/main/res/layout/page_fragment_timeline.xml3
-rw-r--r--app/src/main/res/layout/page_fragment_tweet.xml (renamed from app/src/main/res/layout/dialog_status_detail.xml)3
-rw-r--r--app/src/main/res/layout/page_fragment_user.xml (renamed from app/src/main/res/layout/dialog_user_detail.xml)24
-rw-r--r--app/src/main/res/menu/main.xml3
58 files changed, 412 insertions, 329 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3799bfe5..5c304421 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,4 @@
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.lacolaco.smileessence">
<uses-permission android:name="android.permission.INTERNET" />
diff --git a/app/src/main/java/net/lacolaco/smileessence/Application.kt b/app/src/main/java/net/lacolaco/smileessence/Application.kt
index 9158a6b8..e483405b 100644
--- a/app/src/main/java/net/lacolaco/smileessence/Application.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/Application.kt
@@ -3,8 +3,8 @@ package net.lacolaco.smileessence
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
-import androidx.annotation.StringRes
import android.widget.Toast
+import androidx.annotation.StringRes
import com.squareup.leakcanary.LeakCanary
class Application : android.app.Application() {
diff --git a/app/src/main/java/net/lacolaco/smileessence/World.kt b/app/src/main/java/net/lacolaco/smileessence/World.kt
index aa37a6a6..0bffb03b 100644
--- a/app/src/main/java/net/lacolaco/smileessence/World.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/World.kt
@@ -4,9 +4,8 @@ import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
-import androidx.annotation.StringRes
-import com.google.android.material.snackbar.Snackbar
import android.view.View
+import androidx.annotation.StringRes
import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
@@ -17,6 +16,7 @@ import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.SizeReadyCallback
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
+import com.google.android.material.snackbar.Snackbar
import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.data.PageInfo
import net.lacolaco.smileessence.entity.Event
@@ -32,7 +32,9 @@ import twitter4j.auth.AccessToken
import twitter4j.conf.ConfigurationBuilder
import java.lang.ref.WeakReference
import java.util.*
-import kotlin.coroutines.*
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
+import kotlin.coroutines.suspendCoroutine
/**
* World contains data that are specific to a profile.
@@ -60,8 +62,12 @@ class World private constructor(private val persistentData: PersistentData) {
// Notification
private var mainActivity: WeakReference<MainActivity>? = null
private var isMainActivityActive: Boolean = false
- // Pages
- val pages = persistentData.pageInfos
+
+ // Pages; pageInfos can be modified through MainFragmentPagerAdapter only
+ val pageInfos = persistentData.pageInfos
+
+ // FIXME: This is inefficient
+ fun getPageById(uid: Long) = pageInfos.first { it.uniqueId == uid }
// Startup
@@ -116,11 +122,11 @@ class World private constructor(private val persistentData: PersistentData) {
private var refreshUserCallback: (() -> Unit)? = null
fun refreshUser(callback: () -> Unit) {
synchronized(this) {
- if (refreshUserCallback == null) {
- refreshUserCallback = callback
+ refreshUserCallback = if (refreshUserCallback == null) {
+ callback
} else {
val orig = refreshUserCallback!!
- refreshUserCallback = { orig(); callback() }
+ { orig(); callback() }
}
}
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 9659d59f..3f575dd7 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.kt
@@ -4,12 +4,12 @@ import android.app.ActivityManager
import android.content.Intent
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
-import androidx.viewpager.widget.ViewPager
-import androidx.appcompat.app.AppCompatActivity
-import androidx.palette.graphics.Palette
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
+import androidx.appcompat.app.AppCompatActivity
+import androidx.palette.graphics.Palette
+import androidx.viewpager.widget.ViewPager
import kotlinx.android.synthetic.main.activity_main.*
import net.lacolaco.smileessence.Application
import net.lacolaco.smileessence.Logger
@@ -21,16 +21,14 @@ import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.twitter.getTweetAsync
import net.lacolaco.smileessence.twitter.getUserAsync
import net.lacolaco.smileessence.util.bg
-import net.lacolaco.smileessence.util.getMainActivityOrCancel
import net.lacolaco.smileessence.util.launchUi
-import net.lacolaco.smileessence.view.DialogHelper
import net.lacolaco.smileessence.view.MainFragmentPagerAdapter
import net.lacolaco.smileessence.view.confirm
import net.lacolaco.smileessence.view.dialog.AppInfoDialogFragment
-import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment
-import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment
import net.lacolaco.smileessence.view.page.ComposePageFragment
+import net.lacolaco.smileessence.view.page.PageFragment
import java.util.regex.Pattern
+import kotlin.math.max
class MainActivity : AppCompatActivity() {
val world by lazy {
@@ -41,33 +39,56 @@ class MainActivity : AppCompatActivity() {
}
private lateinit var pagerAdapter: MainFragmentPagerAdapter
- fun openHomePage() {
- view_pager.setCurrentItem(world.pages.indexOfFirst { it is PageInfo.TweetsPageInfo }, true)
+ private fun addEphemeralPage(pageInfo: PageInfo) {
+ pageInfo.ephemeral = true
+ val insertPos = view_pager.currentItem + 1
+ pagerAdapter.addPage(insertPos, pageInfo)
+ view_pager.setCurrentItem(insertPos, true)
+ }
+
+ fun closeCurrentEphemeralPage() {
+ val currentItem = view_pager.currentItem
+ assert(world.pageInfos[currentItem].ephemeral)
+ pagerAdapter.removePage(currentItem)
+ view_pager.setCurrentItem(max(0, currentItem - 1), true)
}
- private fun setSelectedPageIndex(position: Int, smooth: Boolean = true) {
- view_pager.setCurrentItem(position, smooth)
+ fun addEphemeralUserPage(userId: Long) {
+ addEphemeralPage(PageInfo.UserPageInfo(userId))
}
+ fun addEphemeralTweetPage(statusId: Long) {
+ addEphemeralPage(PageInfo.TweetPageInfo(statusId))
+ }
+
+ fun openHomePage() {
+ view_pager.setCurrentItem(world.pageInfos.indexOfFirst { it is PageInfo.TweetsPageInfo }, true)
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ fun getPageFragmentAt(position: Int): PageFragment<*> =
+ pagerAdapter.getCachedFragment(position)
+ ?: pagerAdapter.instantiateItem(view_pager, position) as PageFragment<*>
+
fun openPostPageAndReplyTo(tweet: Tweet, prefix: String) {
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment).setInReplyTo(tweet, prefix)
- setSelectedPageIndex(postPagePosition, true)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment).setInReplyTo(tweet, prefix)
+ view_pager.setCurrentItem(postPagePosition, true)
}
fun openPostPageAndReplyTo(user: User) {
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment).setInReplyTo(user)
- setSelectedPageIndex(postPagePosition, true)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment).setInReplyTo(user)
+ view_pager.setCurrentItem(postPagePosition, true)
}
fun openPostPageAndAppendText(text: String) {
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment).appendText(text)
- setSelectedPageIndex(postPagePosition, true)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment).appendText(text)
+ view_pager.setCurrentItem(postPagePosition, true)
}
private fun setTitle() {
@@ -120,10 +141,10 @@ class MainActivity : AppCompatActivity() {
val via = uri.getQueryParameter("via")
if (!TextUtils.isEmpty(via))
text += " via @$via"
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment).setText(text)
- setSelectedPageIndex(postPagePosition, true)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment).setText(text)
+ view_pager.setCurrentItem(postPagePosition, true)
return
}
val statusMatcher = TWITTER_STATUS_PATTERN.matcher(uri.path)
@@ -132,8 +153,7 @@ class MainActivity : AppCompatActivity() {
val id = statusMatcher.group(1)
try {
val tweet = world.getTweetAsync(id.toLong()).await()
- DialogHelper.showDialog(world.getMainActivityOrCancel(),
- StatusDetailDialogFragment.newInstance(tweet))
+ addEphemeralTweetPage(tweet.id)
} catch (e: Exception) {
world.notifyError("Could not retrieve tweet id=$id")
}
@@ -146,8 +166,7 @@ class MainActivity : AppCompatActivity() {
val username = userMatcher.group(1)
try {
val user = world.getUserAsync(username).await()
- DialogHelper.showDialog(world.getMainActivityOrCancel(),
- UserDetailDialogFragment.newInstance(user))
+ addEphemeralUserPage(user.id)
} catch (e: Exception) {
world.notifyError("Could not retrieve user screen_name=$username")
}
@@ -165,16 +184,16 @@ class MainActivity : AppCompatActivity() {
if (!TextUtils.isEmpty(extra.getCharSequence(Intent.EXTRA_SUBJECT))) {
text = extra.getCharSequence(Intent.EXTRA_SUBJECT)!!.toString() + " " + text
}
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment).setText(text)
- setSelectedPageIndex(postPagePosition, true)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment).setText(text)
+ view_pager.setCurrentItem(postPagePosition, true)
return
}
} else if (type != null && type.startsWith("image/")) {
- val postPagePosition = world.pages.indexOfFirst { it is PageInfo.ComposePageInfo }
+ val postPagePosition = world.pageInfos.indexOfFirst { it is PageInfo.ComposePageInfo }
assert(postPagePosition != -1)
- (pagerAdapter.getPageFragmentAt(postPagePosition) as ComposePageFragment)
+ (getPageFragmentAt(postPagePosition) as ComposePageFragment)
.setMediaFile(intent.getParcelableExtra(Intent.EXTRA_STREAM))
}
}
@@ -182,8 +201,13 @@ class MainActivity : AppCompatActivity() {
}
override fun onBackPressed() {
- val homeIndex = world.pages.indexOfFirst { it is PageInfo.TweetsPageInfo }
- if (view_pager.currentItem != homeIndex)
+ val currentItem = view_pager.currentItem
+ if (world.pageInfos[currentItem].ephemeral) {
+ closeCurrentEphemeralPage()
+ return
+ }
+ val homeIndex = world.pageInfos.indexOfFirst { it is PageInfo.TweetsPageInfo }
+ if (currentItem != homeIndex)
view_pager.setCurrentItem(homeIndex, true)
else
confirm("Are you sure you want to exit?") { finish() }
@@ -211,20 +235,22 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
- pagerAdapter = MainFragmentPagerAdapter(world, view_pager, supportFragmentManager)
- view_pager.offscreenPageLimit = pagerAdapter.count
- view_pager.adapter = pagerAdapter
- view_pager.setCurrentItem(world.pages.indexOfFirst { it is PageInfo.TweetsPageInfo }, false)
+ pagerAdapter = MainFragmentPagerAdapter(world, supportFragmentManager)
view_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {
- Logger.verbose("Page #$position selected (${world.pages[position].name})")
- title = "${world.user.screenName} / ${world.pages[position].name}"
+ val pageInfo = world.pageInfos[position]
+ Logger.verbose("Page #$position selected (${pageInfo.name})")
+ val base = "${world.user.screenName} / ${pageInfo.name}"
+ title = if (!pageInfo.ephemeral) base else "[$base]"
}
})
+ view_pager.offscreenPageLimit = 1000
+ view_pager.adapter = pagerAdapter
+ view_pager.setCurrentItem(world.pageInfos.indexOfFirst { it is PageInfo.TweetsPageInfo }, false)
// Set application title
setTitle()
@@ -250,7 +276,8 @@ class MainActivity : AppCompatActivity() {
intent.putExtra(ManagePagesActivity.INTENT_KEY_WORLD_ID, world.id)
startActivityForResult(intent, REQUEST_CODE_MANAGE_PAGES)
}
- R.id.open_version_dialog -> DialogHelper.showDialog(this, AppInfoDialogFragment.newInstance())
+ R.id.open_version_dialog -> AppInfoDialogFragment.newInstance()
+ .show(supportFragmentManager, "app-info-dialog")
else -> return super.onOptionsItemSelected(item)
}
return true
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 ee67d8a4..116e5d5f 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManagePagesActivity.kt
@@ -2,15 +2,14 @@ package net.lacolaco.smileessence.activity
import android.app.ActivityManager
import android.os.Bundle
-import com.google.android.material.snackbar.Snackbar
+import android.view.View
+import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.ItemTouchHelper
-import android.view.View
-import android.view.ViewGroup
-
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_manage_pages.*
import kotlinx.android.synthetic.main.list_item_page.view.*
import net.lacolaco.smileessence.R
@@ -88,8 +87,8 @@ class ManagePagesActivity : AppCompatActivity() {
di.dismiss()
mainActivityNeedsRestart = true
val item = types[i].second()
- world.pages.add(item)
- recycler_view.adapter!!.notifyItemInserted(world.pages.size - 1)
+ world.pageInfos.add(item)
+ recycler_view.adapter!!.notifyItemInserted(world.pageInfos.size - 1)
openItemEditor(item)
}.show()
}
@@ -97,6 +96,7 @@ class ManagePagesActivity : AppCompatActivity() {
private fun openItemEditor(item: PageInfo) {
if (item is PageInfo.TweetsPageInfo) {
EditTweetsPageDialogFragment.newInstance(world, item)
+ .show(supportFragmentManager, "edit-tweets-page-dialog")
} else
Snackbar.make(fab, "Nothing to configure", Snackbar.LENGTH_SHORT).show()
}
@@ -108,7 +108,7 @@ class ManagePagesActivity : AppCompatActivity() {
private inner class PagesAdapter : RecyclerView.Adapter<PagesAdapter.ViewHolder>() {
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- val item = world.pages[position]
+ val item = world.pageInfos[position]
val view = holder.itemView
view.page_kind_text_view.text = item.name
@@ -117,7 +117,7 @@ class ManagePagesActivity : AppCompatActivity() {
}
override fun getItemCount(): Int {
- return world.pages.size
+ return world.pageInfos.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
@@ -126,17 +126,17 @@ class ManagePagesActivity : AppCompatActivity() {
fun move(before: Int, after: Int): Boolean {
mainActivityNeedsRestart = true
- val item = world.pages.removeAt(before)
- world.pages.add(after, item)
+ val item = world.pageInfos.removeAt(before)
+ world.pageInfos.add(after, item)
notifyItemMoved(before, after)
return true
}
fun remove(position: Int) {
mainActivityNeedsRestart = true
- world.pages.removeAt(position)
+ world.pageInfos.removeAt(position)
notifyItemRemoved(position)
- notifyItemRangeChanged(position, world.pages.size)
+ notifyItemRangeChanged(position, world.pageInfos.size)
}
private inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManageProfilesActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/ManageProfilesActivity.kt
index d9961700..2f578398 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/ManageProfilesActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManageProfilesActivity.kt
@@ -6,24 +6,26 @@ import android.content.pm.PackageManager
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
-import com.google.android.material.snackbar.Snackbar
-import androidx.core.app.ActivityCompat
-import androidx.core.content.ContextCompat
-import androidx.core.content.pm.ShortcutInfoCompat
-import androidx.core.content.pm.ShortcutManagerCompat
-import androidx.core.graphics.drawable.IconCompat
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
-import androidx.appcompat.widget.*
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.Toast
+import androidx.appcompat.app.AlertDialog
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.widget.AppCompatEditText
+import androidx.appcompat.widget.AppCompatTextView
+import androidx.appcompat.widget.SwitchCompat
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.core.content.pm.ShortcutInfoCompat
+import androidx.core.content.pm.ShortcutManagerCompat
+import androidx.core.graphics.drawable.IconCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
+import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_manage_profiles.*
import kotlinx.android.synthetic.main.list_item_profile.view.*
import net.lacolaco.smileessence.Application
diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt
index ecffaa0b..53960219 100644
--- a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.kt
@@ -1,13 +1,13 @@
package net.lacolaco.smileessence.activity
import android.annotation.SuppressLint
-import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.text.Editable
import android.text.TextWatcher
import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.layout_oauth.*
import net.lacolaco.smileessence.R
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 9ede4c76..20c45036 100644
--- a/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/data/Pages.kt
@@ -1,9 +1,11 @@
package net.lacolaco.smileessence.data
-import com.beust.klaxon.*
+import com.beust.klaxon.JsonObject
+import com.beust.klaxon.json
import net.lacolaco.smileessence.view.page.*
sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
+ val uniqueId = uidBase++
abstract val name: String
var ephemeral = false
@@ -11,6 +13,8 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
protected abstract fun toJson(): JsonObject
companion object {
+ private var uidBase = 0L
+
fun fromJsonObject(obj: JsonObject): PageInfo {
val kind = obj.string("kind")
return when (kind) {
@@ -19,6 +23,8 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
"events" -> PageInfo.EventsPageInfo
"search" -> PageInfo.SearchPageInfo
"list" -> PageInfo.ListPageInfo
+ "user" -> PageInfo.UserPageInfo
+ "tweet" -> PageInfo.TweetPageInfo
else -> throw RuntimeException("Recognized PageInfo kind: $kind")
}.fromJson(obj.obj("data")!!)
}
@@ -30,6 +36,8 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
is PageInfo.EventsPageInfo -> "events"
is PageInfo.SearchPageInfo -> "search"
is PageInfo.ListPageInfo -> "list"
+ is PageInfo.UserPageInfo -> "user"
+ is PageInfo.TweetPageInfo -> "tweet"
}
return json { obj("kind" to kind, "data" to pageInfo.toJson()) }
}
@@ -132,4 +140,30 @@ sealed class PageInfo(val fragmentClass: Class<out PageFragment<*>>) {
override fun fromJson(json: JsonObject) = ListPageInfo(json.string("full_name"))
}
}
+
+ class UserPageInfo(val userId: Long) : PageInfo(UserPageFragment::class.java) {
+ override val name: String
+ get() = "User"
+
+ override fun describe() = "User ID: $userId"
+
+ override fun toJson() = json { obj("user_id" to userId) }
+
+ companion object : FromJson {
+ override fun fromJson(json: JsonObject) = UserPageInfo(json.long("user_id")!!)
+ }
+ }
+
+ class TweetPageInfo(val statusId: Long) : PageInfo(TweetPageFragment::class.java) {
+ override val name: String
+ get() = "Tweet"
+
+ override fun describe() = "Tweet ID: $statusId"
+
+ override fun toJson() = json { obj("status_id" to statusId) }
+
+ companion object : FromJson {
+ override fun fromJson(json: JsonObject) = TweetPageInfo(json.long("status_id")!!)
+ }
+ }
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt
index 3140ed9e..c53917be 100644
--- a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.kt
@@ -60,7 +60,8 @@ class Tweet private constructor(
User.fromTwitter(st.user),
st.createdAt,
st.source,
- st.inReplyToStatusId.takeIf { it != -1L },
+ retweetedTweet?.inReplyToStatusId
+ ?: st.inReplyToStatusId.takeIf { it != -1L },
retweetedTweet,
entities,
retweetedTweet?.text ?: entities.extractText(st, st.text)
diff --git a/app/src/main/java/net/lacolaco/smileessence/util/IntentHelper.kt b/app/src/main/java/net/lacolaco/smileessence/util/IntentHelper.kt
index b334f717..d977078c 100644
--- a/app/src/main/java/net/lacolaco/smileessence/util/IntentHelper.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/util/IntentHelper.kt
@@ -1,10 +1,10 @@
package net.lacolaco.smileessence.util
-import androidx.fragment.app.Fragment
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
+import androidx.fragment.app.Fragment
fun Context.browse(uri: Uri, type: String? = null) {
try {
diff --git a/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt b/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt
index 765aec58..4e99796d 100644
--- a/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/util/SystemServiceHelper.kt
@@ -1,11 +1,11 @@
package net.lacolaco.smileessence.util
-import androidx.appcompat.app.AppCompatActivity
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
+import androidx.appcompat.app.AppCompatActivity
object SystemServiceHelper {
fun hideIM(context: Context, view: View) {
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/Confirmation.kt b/app/src/main/java/net/lacolaco/smileessence/view/Confirmation.kt
index 91c71264..26fe3c28 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/Confirmation.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/Confirmation.kt
@@ -1,8 +1,8 @@
package net.lacolaco.smileessence.view
-import androidx.fragment.app.Fragment
import android.content.Context
import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.Fragment
import net.lacolaco.smileessence.R
fun Context.confirm(text: String, onOk: () -> Unit) {
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt b/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt
index 0b10063e..3f35d478 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/MainFragmentPagerAdapter.kt
@@ -1,48 +1,154 @@
package net.lacolaco.smileessence.view
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentManager
import android.os.Bundle
-import androidx.viewpager.widget.ViewPager
+import android.util.SparseBooleanArray
+import android.view.View
import android.view.ViewGroup
-import androidx.fragment.app.FragmentPagerAdapter
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.fragment.app.FragmentTransaction
+import androidx.viewpager.widget.PagerAdapter
+import net.lacolaco.smileessence.Logger
import net.lacolaco.smileessence.World
import net.lacolaco.smileessence.data.PageInfo
import net.lacolaco.smileessence.view.page.PageFragment
-import java.util.*
-class MainFragmentPagerAdapter(private val world: World, private val viewPager: ViewPager, fm: FragmentManager) :
- FragmentPagerAdapter(fm) {
- private val pages = Collections.unmodifiableList(world.pages.map { Page(it) })
+class MainFragmentPagerAdapter(
+ private val world: World,
+ private val fragmentManager: FragmentManager
+) : PagerAdapter() {
+ private var currentTransaction: FragmentTransaction? = null
+ private var currentPrimaryItem: Fragment? = null
- @Suppress("UNCHECKED_CAST")
- fun getPageFragmentAt(position: Int): PageFragment<*> =
- pages[position].fragment ?: instantiateItem(viewPager, position) as PageFragment<*>
+ private val pages = world.pageInfos.map { Page(it) }.toMutableList()
+ private var itemPositionChangeChecked = SparseBooleanArray(pages.size)
- override fun getItem(position: Int): Fragment {
- val args = Bundle()
- args.putLong(PageFragment.KEY_WORLD_USER_ID, world.id)
- args.putInt(PageFragment.KEY_PAGE_POSITION, position)
+ @Deprecated("UAUA")
+ fun getCachedFragment(position: Int) = pages[position].fragment
+
+ override fun instantiateItem(container: ViewGroup, position: Int): Any {
+ if (currentTransaction == null) {
+ currentTransaction = fragmentManager.beginTransaction()
+ }
+
+ val item = pages[position]
+
+ // Do we already have this fragment?
+ val name = item.fragmentName
+ var fragment = fragmentManager.findFragmentByTag(name)
+ if (fragment != null) {
+ Logger.debug("Attaching item #$item: f=$fragment")
+ currentTransaction!!.attach(fragment)
+ } else {
+ fragment = getItem(position)
+ Logger.debug("Adding item #$item: f=$fragment")
+ currentTransaction!!.add(container.id, fragment, name)
+ }
+ if (fragment !== currentPrimaryItem) {
+ fragment.setMenuVisibility(false)
+ fragment.userVisibleHint = false
+ }
+ // CAN BE REMOVED
+ item.fragment = fragment as PageFragment<*>
+
+ return item
+ }
+
+ override fun destroyItem(container: ViewGroup, position: Int, item: Any) {
+ if (currentTransaction == null) {
+ currentTransaction = fragmentManager.beginTransaction()
+ }
+ val name = (item as Page).fragmentName
+ val f = fragmentManager.findFragmentByTag(name)
+ if (f != null) {
+ Logger.debug("Detaching item #$item: f=$f v=${f.view}")
+ currentTransaction!!.detach(f)
+ }
+ }
+
+ override fun setPrimaryItem(container: ViewGroup, position: Int, item: Any) {
+ val fragment = fragmentManager.findFragmentByTag((item as Page).fragmentName)
+ if (fragment !== currentPrimaryItem) {
+ currentPrimaryItem?.setMenuVisibility(false)
+ currentPrimaryItem?.userVisibleHint = false
+ fragment?.setMenuVisibility(true)
+ fragment?.userVisibleHint = true
+ currentPrimaryItem = fragment
+ }
+ }
+
+ override fun finishUpdate(container: ViewGroup) {
+ if (currentTransaction != null) {
+ currentTransaction!!.commitAllowingStateLoss()
+ currentTransaction = null
+ fragmentManager.executePendingTransactions()
+ }
+ }
+
+ override fun isViewFromObject(view: View, item: Any): Boolean {
+ for (fragment in fragmentManager.fragments) {
+ if (fragment != null) {
+ val v = fragment.view
+ if (v != null && v === view &&
+ (item as Page).fragmentName == fragment.tag) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+ private fun getItem(position: Int): Fragment {
val info = pages[position]
assert(info.fragment == null)
- return info.pageInfo.fragmentClass.newInstance().apply { arguments = args }
+ val fragment = info.pageInfo.fragmentClass.newInstance() as PageFragment<*>
+
+ val args = Bundle()
+ args.putLong(PageFragment.KEY_WORLD_USER_ID, world.id)
+ args.putLong(PageFragment.KEY_PAGEINFO_UNIQUE_ID, info.pageInfo.uniqueId)
+ fragment.arguments = args
+
+ return fragment
+ }
+
+ override fun getItemPosition(item_: Any): Int {
+ val item = item_ as Page
+ if (!pages.contains(item))
+ return PagerAdapter.POSITION_NONE
+
+ val position = pages.indexOf(item)
+ val ret = if (itemPositionChangeChecked.get(position))
+ PagerAdapter.POSITION_UNCHANGED
+ else
+ position
+ itemPositionChangeChecked.put(position, true)
+ return ret
+ }
+
+ override fun getPageTitle(position: Int): CharSequence? {
+ return pages[position].pageInfo.name
}
override fun getCount(): Int {
return pages.size
}
- override fun instantiateItem(container: ViewGroup, position: Int): Any {
- val info = pages[position]
- val fragment = super.instantiateItem(container, position)
- info.fragment = fragment as PageFragment<*>
- return fragment
+ fun addPage(position: Int, pageInfo: PageInfo) {
+ world.pageInfos.add(position, pageInfo)
+ pages.add(position, Page(pageInfo))
+ itemPositionChangeChecked = SparseBooleanArray(pages.size)
+ notifyDataSetChanged()
}
- override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
- throw IllegalStateException("Fragments must not be destroyed by ViewPager")
+ fun removePage(position: Int) {
+ pages.removeAt(position)
+ world.pageInfos.removeAt(position)
+ itemPositionChangeChecked = SparseBooleanArray(pages.size)
+ notifyDataSetChanged()
}
- private class Page(var pageInfo: PageInfo, var fragment: PageFragment<*>? = null)
+ private class Page(var pageInfo: PageInfo) {
+ val fragmentName = "android:switcher:${pageInfo.uniqueId}"
+ var fragment: PageFragment<*>? = null
+ }
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt b/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt
index 92dd7a91..fd73b447 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/Partials.kt
@@ -8,26 +8,25 @@ import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.item_status_base.view.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.World
+import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.entity.Tweet
import net.lacolaco.smileessence.twitter.TwitterTaskException
import net.lacolaco.smileessence.twitter.getTweetAsync
import net.lacolaco.smileessence.util.launchUi
import net.lacolaco.smileessence.util.toCompactString
-import net.lacolaco.smileessence.view.dialog.StatusDetailDialogFragment
-import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment
object Partials {
fun getTweetView(tweet: Tweet, world: World, activity: FragmentActivity, view: View,
maxRecursion: Int = 2): View {
view.setOnClickListener {
- DialogHelper.showDialog(activity, StatusDetailDialogFragment.newInstance(tweet))
+ (activity as MainActivity).addEphemeralTweetPage(tweet.id)
}
// Display source
val user = tweet.originalTweet.user
Glide.with(view).load(user.profileImageUrl).into(view.imageview_status_icon)
view.imageview_status_icon.setOnClickListener {
- DialogHelper.showDialog(activity, UserDetailDialogFragment.newInstance(user))
+ (activity as MainActivity).addEphemeralUserPage(user.id)
}
view.source_user_protected.visibility =
if (user.isProtected) View.VISIBLE else View.INVISIBLE
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 1a1d45d3..6af38513 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
@@ -1,14 +1,22 @@
package net.lacolaco.smileessence.view.dialog
+import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.view.Window
+import androidx.appcompat.app.AppCompatDialog
+import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_app_info.*
import net.lacolaco.smileessence.BuildConfig
import net.lacolaco.smileessence.R
-class AppInfoDialogFragment : StackableDialogFragment() {
+class AppInfoDialogFragment : DialogFragment() {
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return AppCompatDialog(activity).apply { requestWindowFeature(Window.FEATURE_NO_TITLE) }
+ }
+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.dialog_app_info, container, false)
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTweetsPageDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTweetsPageDialogFragment.kt
index cec053c5..d12792f1 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTweetsPageDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/EditTweetsPageDialogFragment.kt
@@ -1,13 +1,13 @@
package net.lacolaco.smileessence.view.dialog
import android.os.Bundle
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import com.beust.klaxon.JsonObject
import com.beust.klaxon.Parser
import kotlinx.android.synthetic.main.dialog_edit_tweets_page.*
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt
index 03e8b2b3..ed4b3856 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StackableDialogFragment.kt
@@ -2,8 +2,8 @@ package net.lacolaco.smileessence.view.dialog
import android.app.Dialog
import android.os.Bundle
-import androidx.appcompat.app.AppCompatDialog
import android.view.Window
+import androidx.appcompat.app.AppCompatDialog
import androidx.fragment.app.DialogFragment
import net.lacolaco.smileessence.World
import net.lacolaco.smileessence.activity.MainActivity
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/ComposePageFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/ComposePageFragment.kt
index 525bd9a0..417e6174 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/ComposePageFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/ComposePageFragment.kt
@@ -1,20 +1,20 @@
package net.lacolaco.smileessence.view.page
import android.annotation.SuppressLint
-import androidx.appcompat.app.AppCompatActivity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.provider.MediaStore
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import android.text.Editable
import android.text.Spannable
import android.text.TextWatcher
import android.text.method.ArrowKeyMovementMethod
import android.view.*
import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.item_compose_media.view.*
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/EventsPageFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/EventsPageFragment.kt
index fe25863c..50a9143e 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/EventsPageFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/EventsPageFragment.kt
@@ -7,13 +7,12 @@ import android.view.ViewGroup
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.list_item_event.view.*
import net.lacolaco.smileessence.R
+import net.lacolaco.smileessence.activity.MainActivity
import net.lacolaco.smileessence.data.PageInfo
import net.lacolaco.smileessence.entity.Event
import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.util.launchUi
import net.lacolaco.smileessence.util.toCompactString
-import net.lacolaco.smileessence.view.DialogHelper
-import net.lacolaco.smileessence.view.dialog.UserDetailDialogFragment
class EventsPageFragment : TimelinePageFragment<Event, PageInfo.EventsPageInfo>() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -29,8 +28,7 @@ class EventsPageFragment : TimelinePageFragment<Event, PageInfo.EventsPageInfo>(
itemView.textview_status_footer.text = item.createdAt.toCompactString()
itemView.setOnClickListener {
if (item.source != null)
- DialogHelper.showDialog(activity!!,
- UserDetailDialogFragment.newInstance(item.source!!))
+ (activity as MainActivity).addEphemeralUserPage(item.source!!.id)
}
}
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 a0f15bd8..49ffad87 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,11 +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")
+ val uid = arguments!!.getLong(KEY_PAGEINFO_UNIQUE_ID, -2)
+ if (uid == -2L)
+ throw IllegalStateException("KEY_PAGEINFO_UNIQUE_ID not specified")
@Suppress("UNCHECKED_CAST")
- world.pages[pos] as T
+ world.getPageById(uid) as T
}
val mainActivity
@@ -28,6 +28,6 @@ abstract class PageFragment<out T : PageInfo> : Fragment() {
companion object {
const val KEY_WORLD_USER_ID = "KEY_WORLD_USER_ID"
- const val KEY_PAGE_POSITION = "KEY_PAGE_POSITION"
+ const val KEY_PAGEINFO_UNIQUE_ID = "KEY_PAGEINFO_UNIQUE_ID"
}
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/page/TimelinePageFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/TimelinePageFragment.kt
index 354f0545..781473f5 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/page/TimelinePageFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/TimelinePageFragment.kt
@@ -1,12 +1,12 @@
package net.lacolaco.smileessence.view.page
import android.os.Bundle
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.page_fragment_timeline.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.data.PageInfo
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/TweetPageFragment.kt
index 1f38817d..cbe8ea80 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/TweetPageFragment.kt
@@ -1,39 +1,40 @@
-package net.lacolaco.smileessence.view.dialog
+package net.lacolaco.smileessence.view.page
import android.os.Bundle
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.page_fragment_tweet.view.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.activity.MainActivity
+import net.lacolaco.smileessence.data.PageInfo
import net.lacolaco.smileessence.entity.Tweet
import net.lacolaco.smileessence.twitter.*
import net.lacolaco.smileessence.util.*
-import net.lacolaco.smileessence.view.DialogHelper
import net.lacolaco.smileessence.view.Partials
import net.lacolaco.smileessence.view.PopupMenu
import net.lacolaco.smileessence.view.confirm
-class StatusDetailDialogFragment : StackableDialogFragment() {
+class TweetPageFragment : PageFragment<PageInfo.TweetPageInfo>() {
private lateinit var tweet: Tweet
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val id = arguments!!.getLong(KEY_STATUS_ID)
- val found = Tweet.cached(id)
+ val id = pageInfo.statusId
+ var found = Tweet.cached(id)
if (found == null) {
world.notifyError("Tweet id=$id not found")
- dismissAllowingStateLoss()
- // NB: It seems onCreateView() is called even if dismiss() is called.
- tweet = Tweet.placeHolder
- return
+ found = Tweet.placeHolder
}
tweet = found
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
- val view = inflater.inflate(R.layout.dialog_status_detail, container, false)
+ return inflater.inflate(R.layout.page_fragment_tweet, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
val statusHeader = Partials.getTweetView(tweet, world, activity!!, view.detail_current_status)
statusHeader.isClickable = false
@@ -64,7 +65,6 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
view.tweet_in_reply_to.visibility = View.GONE
view.detail_dialog_divider_top.visibility = View.GONE
}
- return view
}
private fun updateViewButtons(view: View) {
@@ -141,7 +141,7 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
world.notifyError(R.string.notice_status_delete_failed)
}
}
- dismiss()
+ (activity as MainActivity).closeCurrentEphemeralPage()
}
}
view.button_status_detail_menu.setOnClickListener {
@@ -173,7 +173,7 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
launchUi {
try {
val user = world.getUserAsync(screenName).await()
- DialogHelper.showDialog(ref.get(), UserDetailDialogFragment.newInstance(user))
+ (activity as MainActivity).addEphemeralUserPage(user.id)
} catch (e: TwitterTaskException) {
world.notifyError(R.string.notice_error_show_user)
}
@@ -202,16 +202,4 @@ class StatusDetailDialogFragment : StackableDialogFragment() {
view.embedded_menu_items.visibility = View.GONE
}
}
-
- companion object {
- private const val KEY_STATUS_ID = "status_id"
-
- fun newInstance(tweet: Tweet): StatusDetailDialogFragment {
- val obj = StatusDetailDialogFragment()
- val args = Bundle()
- args.putLong(KEY_STATUS_ID, tweet.id)
- obj.arguments = args
- return obj
- }
- }
}
diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt b/app/src/main/java/net/lacolaco/smileessence/view/page/UserPageFragment.kt
index de916aec..f417aeb8 100644
--- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.kt
+++ b/app/src/main/java/net/lacolaco/smileessence/view/page/UserPageFragment.kt
@@ -1,52 +1,49 @@
-package net.lacolaco.smileessence.view.dialog
+package net.lacolaco.smileessence.view.page
import android.os.Bundle
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import android.text.Html
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bumptech.glide.Glide
-import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayoutDirection
-import kotlinx.android.synthetic.main.dialog_user_detail.*
+import com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
+import kotlinx.android.synthetic.main.page_fragment_user.*
import net.lacolaco.smileessence.R
import net.lacolaco.smileessence.activity.MainActivity
+import net.lacolaco.smileessence.data.PageInfo
import net.lacolaco.smileessence.entity.Tweet
import net.lacolaco.smileessence.entity.User
import net.lacolaco.smileessence.twitter.*
-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.confirm
-class UserDetailDialogFragment : StackableDialogFragment() {
+class UserPageFragment : RefreshableTimelinePageFragment<Tweet, PageInfo.UserPageInfo>() {
private lateinit var user: User
private var isFollowedByMe = false
private var isFollowingMe = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val found = User.cached(arguments!!.getLong(KEY_USER_ID))
+ var found = User.cached(pageInfo.userId)
if (found == null) {
world.notify(R.string.notice_error_show_user)
- dismiss()
- return
+ found = User.placeHolder
}
user = found
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View {
- return inflater.inflate(R.layout.dialog_user_detail, container, false)
+ return inflater.inflate(R.layout.page_fragment_user, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
imageview_user_detail_menu.setOnClickListener { showPopupMenu() }
user_detail_screenname.setOnClickListener { browse(user.userHomeURL) }
textview_user_detail_description.movementMethod = LinkMovementMethod.getInstance()
@@ -64,45 +61,15 @@ 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.getMaxIdOrNull()).await()
- adapter.addAll(tweets)
- } else {
- val tweets = world.getUserTimelineAsync(user.id,
- maxId = adapter.getMinIdMinusOneOrNull()).await()
- adapter.addAll(tweets)
- }
- } catch (e: TwitterTaskException) {
- world.notifyError("Could not retrieve user timeline")
- }
- refreshLayout.isRefreshing = false
- }
- }
+ refresh()
+ }
+ override fun refresh() {
+ setSwipeRefreshEnabled(user.id == pageInfo.userId)
+ adapter.sortedList.clear()
updateRelationship()
- launchUi {
- try {
- val tweets = world.getUserTimelineAsync(user.id).await()
- adapter.addAll(tweets)
- } catch (e: TwitterTaskException) {
- world.notifyError("Could not retrieve user timeline")
- }
- }
-
refreshViews()
+ runRefreshTask { }
}
private fun refreshViews() {
@@ -112,7 +79,6 @@ class UserDetailDialogFragment : StackableDialogFragment() {
user_detail_screenname.text = "@${user.screenName}"
user_protected_indicator.visibility = if (user.isProtected) View.VISIBLE else View.INVISIBLE
-
user_detail_location.text = user.location
user_detail_url.text = user.url
textview_user_detail_description.text = Html.fromHtml(user.decoratedDescription)
@@ -226,56 +192,40 @@ class UserDetailDialogFragment : StackableDialogFragment() {
}
}
- companion object {
- private const 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
+ override fun onSwipeDown(view: SwipyRefreshLayout) {
+ val sinceId = if (adapter.sortedList.size > 0) adapter.sortedList[0].id else null
+ runRefreshTask(sinceId = sinceId) {
+ view.isRefreshing = false
}
}
- 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_tweet, parent, false))
- }
-
- override fun getItemCount(): Int {
- return sortedList.size
- }
-
- fun addAll(items: Collection<Tweet>) {
- sortedList.addAll(items)
+ override fun onSwipeUp(view: SwipyRefreshLayout) {
+ val maxId = if (adapter.sortedList.size > 0)
+ adapter.sortedList[adapter.sortedList.size - 1].id - 1
+ else
+ null
+ runRefreshTask(maxId = maxId) {
+ view.isRefreshing = false
}
+ }
- fun getMaxIdOrNull(): Long? {
- return if (sortedList.size > 0)
- sortedList[0].id
- else
- null
+ private fun runRefreshTask(sinceId: Long? = null, maxId: Long? = null,
+ onFinish: () -> Unit) = launchUi {
+ try {
+ val tweets = world.getUserTimelineAsync(user.id, sinceId = sinceId, maxId = maxId).await()
+ adapter.sortedList.addAll(tweets)
+ onFinish()
+ } catch (e: TwitterTaskException) {
+ world.notifyError("Could not retrieve user timeline")
}
+ }
- fun getMinIdMinusOneOrNull(): Long? {
- return if (sortedList.size > 0)
- sortedList[sortedList.size - 1].id - 1
- else
- null
- }
+ override fun onBindItemView(item: Tweet, itemView: View) {
+ Partials.getTweetView(item, world, activity!!, itemView)
+ }
- private inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
+ override fun onCreateItemView(parent: ViewGroup): View {
+ val layoutInflater = LayoutInflater.from(parent.context)
+ return layoutInflater.inflate(R.layout.list_item_tweet, parent, false)
}
}
diff --git a/app/src/main/res/drawable/follow_button.xml b/app/src/main/res/drawable/follow_button.xml
index 66fca8c7..f23eef8b 100644
--- a/app/src/main/res/drawable/follow_button.xml
+++ b/app/src/main/res/drawable/follow_button.xml
@@ -1,5 +1,4 @@
-<ripple
- xmlns:android="http://schemas.android.com/apk/res/android"
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?colorControlHighlight">
<item>
<selector>
diff --git a/app/src/main/res/drawable/ic_add_black_24dp.xml b/app/src/main/res/drawable/ic_add_black_24dp.xml
index 5c46312b..0c88b7ce 100644
--- a/app/src/main/res/drawable/ic_add_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_add_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_clear_black_24dp.xml b/app/src/main/res/drawable/ic_clear_black_24dp.xml
index 19ecb55f..56da9615 100644
--- a/app/src/main/res/drawable/ic_clear_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_clear_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml b/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml
index 852f5f6c..d72e3fcf 100644
--- a/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_delete_forever_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_image_black_24dp.xml b/app/src/main/res/drawable/ic_image_black_24dp.xml
index 0034fdaa..7c62bb30 100644
--- a/app/src/main/res/drawable/ic_image_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_image_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_lock_black_24dp.xml b/app/src/main/res/drawable/ic_lock_black_24dp.xml
index 9a639247..2fa319f5 100644
--- a/app/src/main/res/drawable/ic_lock_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_lock_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_more_vert_black_24dp.xml b/app/src/main/res/drawable/ic_more_vert_black_24dp.xml
index 09cc0de7..26773b64 100644
--- a/app/src/main/res/drawable/ic_more_vert_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_more_vert_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_repeat_black_24dp.xml b/app/src/main/res/drawable/ic_repeat_black_24dp.xml
index 07f865c7..7f4b0523 100644
--- a/app/src/main/res/drawable/ic_repeat_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_repeat_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_reply_all_black_24dp.xml b/app/src/main/res/drawable/ic_reply_all_black_24dp.xml
index 33d4504d..2d18c857 100644
--- a/app/src/main/res/drawable/ic_reply_all_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_reply_all_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_save_black_24dp.xml b/app/src/main/res/drawable/ic_save_black_24dp.xml
index 8f53a6a7..b7ee1df2 100644
--- a/app/src/main/res/drawable/ic_save_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_save_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_search_black_24dp.xml b/app/src/main/res/drawable/ic_search_black_24dp.xml
index a2bed426..6fafa170 100644
--- a/app/src/main/res/drawable/ic_search_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_search_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_star_black_24dp.xml b/app/src/main/res/drawable/ic_star_black_24dp.xml
index be5b2894..3365473a 100644
--- a/app/src/main/res/drawable/ic_star_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_star_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/drawable/ic_view_list_black_24dp.xml b/app/src/main/res/drawable/ic_view_list_black_24dp.xml
index f029bc47..48db7310 100644
--- a/app/src/main/res/drawable/ic_view_list_black_24dp.xml
+++ b/app/src/main/res/drawable/ic_view_list_black_24dp.xml
@@ -1,5 +1,4 @@
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 69b0df45..32423205 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,5 +1,4 @@
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
diff --git a/app/src/main/res/layout/activity_manage_pages.xml b/app/src/main/res/layout/activity_manage_pages.xml
index 27909d8b..84c90c1c 100644
--- a/app/src/main/res/layout/activity_manage_pages.xml
+++ b/app/src/main/res/layout/activity_manage_pages.xml
@@ -1,5 +1,4 @@
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/activity_manage_profiles.xml b/app/src/main/res/layout/activity_manage_profiles.xml
index fc75afe9..c095147d 100644
--- a/app/src/main/res/layout/activity_manage_profiles.xml
+++ b/app/src/main/res/layout/activity_manage_profiles.xml
@@ -1,5 +1,4 @@
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/dialog_app_info.xml b/app/src/main/res/layout/dialog_app_info.xml
index e7ea9d4c..dbe6b23d 100644
--- a/app/src/main/res/layout/dialog_app_info.xml
+++ b/app/src/main/res/layout/dialog_app_info.xml
@@ -1,5 +1,4 @@
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/dialog_edit_tweets_page.xml b/app/src/main/res/layout/dialog_edit_tweets_page.xml
index f4b7f667..28a3ee83 100644
--- a/app/src/main/res/layout/dialog_edit_tweets_page.xml
+++ b/app/src/main/res/layout/dialog_edit_tweets_page.xml
@@ -1,5 +1,4 @@
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/item_compose_media.xml b/app/src/main/res/layout/item_compose_media.xml
index ac930c4e..9f715262 100644
--- a/app/src/main/res/layout/item_compose_media.xml
+++ b/app/src/main/res/layout/item_compose_media.xml
@@ -1,5 +1,4 @@
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="120dp"
android:layout_height="120dp"
diff --git a/app/src/main/res/layout/item_status_base.xml b/app/src/main/res/layout/item_status_base.xml
index 25a1129b..337628c7 100644
--- a/app/src/main/res/layout/item_status_base.xml
+++ b/app/src/main/res/layout/item_status_base.xml
@@ -1,5 +1,4 @@
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/layout_oauth.xml b/app/src/main/res/layout/layout_oauth.xml
index 61911a30..4618301c 100644
--- a/app/src/main/res/layout/layout_oauth.xml
+++ b/app/src/main/res/layout/layout_oauth.xml
@@ -1,5 +1,4 @@
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
diff --git a/app/src/main/res/layout/list_item_event.xml b/app/src/main/res/layout/list_item_event.xml
index 5cde5a56..cc6d132e 100644
--- a/app/src/main/res/layout/list_item_event.xml
+++ b/app/src/main/res/layout/list_item_event.xml
@@ -1,13 +1,11 @@
-<net.lacolaco.smileessence.view.TweetStateFrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<net.lacolaco.smileessence.view.TweetStateFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?status_item_background"
android:descendantFocusability="blocksDescendants"
android:foreground="?attr/selectableItemBackground">
- <androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/list_item_page.xml b/app/src/main/res/layout/list_item_page.xml
index 87b1397a..9bc36feb 100644
--- a/app/src/main/res/layout/list_item_page.xml
+++ b/app/src/main/res/layout/list_item_page.xml
@@ -1,5 +1,4 @@
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants">
diff --git a/app/src/main/res/layout/list_item_profile.xml b/app/src/main/res/layout/list_item_profile.xml
index 5da74973..f6425cc2 100644
--- a/app/src/main/res/layout/list_item_profile.xml
+++ b/app/src/main/res/layout/list_item_profile.xml
@@ -1,5 +1,4 @@
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/list_item_simple_text.xml b/app/src/main/res/layout/list_item_simple_text.xml
index c2b67be6..049f7e56 100644
--- a/app/src/main/res/layout/list_item_simple_text.xml
+++ b/app/src/main/res/layout/list_item_simple_text.xml
@@ -1,5 +1,4 @@
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/app/src/main/res/layout/list_item_tweet.xml b/app/src/main/res/layout/list_item_tweet.xml
index f7495020..75ae6d93 100644
--- a/app/src/main/res/layout/list_item_tweet.xml
+++ b/app/src/main/res/layout/list_item_tweet.xml
@@ -1,5 +1,4 @@
-<net.lacolaco.smileessence.view.TweetStateFrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<net.lacolaco.smileessence.view.TweetStateFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?status_item_background"
diff --git a/app/src/main/res/layout/menu_item_simple_text.xml b/app/src/main/res/layout/menu_item_simple_text.xml
index 9a534e4d..f3541578 100644
--- a/app/src/main/res/layout/menu_item_simple_text.xml
+++ b/app/src/main/res/layout/menu_item_simple_text.xml
@@ -1,9 +1,9 @@
-<RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground">
+
<TextView
android:id="@+id/text_view_content"
android:layout_width="wrap_content"
@@ -14,6 +14,7 @@
android:padding="10dp"
android:textSize="@dimen/status_text_size"
tools:text="@tools:sample/lorem" />
+
<TextView
android:id="@+id/text_view_title"
android:layout_width="wrap_content"
diff --git a/app/src/main/res/layout/page_fragment_compose.xml b/app/src/main/res/layout/page_fragment_compose.xml
index c8ce1ac6..4426c6da 100644
--- a/app/src/main/res/layout/page_fragment_compose.xml
+++ b/app/src/main/res/layout/page_fragment_compose.xml
@@ -1,5 +1,4 @@
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/page_fragment_list.xml b/app/src/main/res/layout/page_fragment_list.xml
index 0663f93c..aba95618 100644
--- a/app/src/main/res/layout/page_fragment_list.xml
+++ b/app/src/main/res/layout/page_fragment_list.xml
@@ -1,5 +1,4 @@
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/page_fragment_refreshable_timeline.xml b/app/src/main/res/layout/page_fragment_refreshable_timeline.xml
index a7ca3c5f..cebab61f 100644
--- a/app/src/main/res/layout/page_fragment_refreshable_timeline.xml
+++ b/app/src/main/res/layout/page_fragment_refreshable_timeline.xml
@@ -1,5 +1,4 @@
-<com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fragment_list_refresh_layout"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/page_fragment_search.xml b/app/src/main/res/layout/page_fragment_search.xml
index 628b594b..e0fbd7f0 100644
--- a/app/src/main/res/layout/page_fragment_search.xml
+++ b/app/src/main/res/layout/page_fragment_search.xml
@@ -1,5 +1,4 @@
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/page_fragment_timeline.xml b/app/src/main/res/layout/page_fragment_timeline.xml
index bbf8b82b..994fea83 100644
--- a/app/src/main/res/layout/page_fragment_timeline.xml
+++ b/app/src/main/res/layout/page_fragment_timeline.xml
@@ -1,5 +1,4 @@
-<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tweets_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/app/src/main/res/layout/dialog_status_detail.xml b/app/src/main/res/layout/page_fragment_tweet.xml
index 87462f53..41fcac1f 100644
--- a/app/src/main/res/layout/dialog_status_detail.xml
+++ b/app/src/main/res/layout/page_fragment_tweet.xml
@@ -1,5 +1,4 @@
-<ScrollView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/app/src/main/res/layout/dialog_user_detail.xml b/app/src/main/res/layout/page_fragment_user.xml
index 7f255c29..25225613 100644
--- a/app/src/main/res/layout/dialog_user_detail.xml
+++ b/app/src/main/res/layout/page_fragment_user.xml
@@ -1,5 +1,4 @@
-<androidx.coordinatorlayout.widget.CoordinatorLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -56,6 +55,7 @@
android:layout_marginTop="8dp"
android:textAppearance="@style/TextAppearance.AppCompat"
android:textColor="@android:color/background_light"
+ android:background="?status_item_background"
app:layout_constraintStart_toEndOf="@+id/user_detail_icon"
app:layout_constraintTop_toTopOf="parent"
tools:text="name" />
@@ -68,6 +68,7 @@
android:layout_marginTop="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?colorAccent"
+ android:background="?status_item_background"
app:layout_constraintStart_toEndOf="@+id/user_detail_icon"
app:layout_constraintTop_toBottomOf="@+id/user_detail_name"
tools:text="screen_name" />
@@ -80,6 +81,7 @@
android:layout_marginTop="8dp"
android:textColor="@android:color/background_light"
android:textSize="@dimen/status_text_size"
+ android:background="?status_item_background"
app:layout_constraintStart_toEndOf="@+id/user_detail_icon"
app:layout_constraintTop_toBottomOf="@+id/user_detail_screenname"
tools:text="location" />
@@ -92,6 +94,7 @@
android:layout_marginTop="8dp"
android:autoLink="web"
android:textSize="@dimen/status_text_size"
+ android:background="?status_item_background"
app:layout_constraintStart_toEndOf="@+id/user_detail_location"
app:layout_constraintTop_toBottomOf="@+id/user_detail_screenname"
tools:text="url" />
@@ -99,14 +102,14 @@
<TextView
android:id="@+id/textview_user_detail_description"
android:layout_width="0dp"
- android:layout_height="0dp"
+ android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:autoLink="web"
android:textSize="@dimen/status_text_size"
- app:layout_constraintBottom_toBottomOf="@+id/user_detail_banner"
+ android:background="?status_item_background"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/user_detail_icon"
@@ -269,16 +272,11 @@
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
- <com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout
- android:id="@+id/user_detail_refresh_layout"
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:layout_behavior="@string/appbar_scrolling_view_behavior"
- app:srl_direction="both">
+ app:layout_behavior="@string/appbar_scrolling_view_behavior">
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/user_timeline"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
- </com.omadahealth.github.swipyrefreshlayout.library.SwipyRefreshLayout>
+ <include layout="@layout/page_fragment_refreshable_timeline" />
+ </FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
index 33aac8ec..0d5dd789 100644
--- a/app/src/main/res/menu/main.xml
+++ b/app/src/main/res/menu/main.xml
@@ -1,5 +1,4 @@
-<menu
- xmlns:android="http://schemas.android.com/apk/res/android"
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/actionbar_manage_pages"