diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2019-03-25 23:29:17 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2019-03-25 23:29:17 +0900 |
commit | fedd5082d627a9f732887be26ce0a8f95eb5ca20 (patch) | |
tree | 23b705b29940c0fd952e170e7565d7da92103ca6 | |
parent | f783d6ab9afa579c91e73305ffdd66df60ce5efa (diff) | |
download | SmileEssence-fedd5082d627a9f732887be26ce0a8f95eb5ca20.tar.gz |
make everything a page
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" |