SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/SideMenuAdapter.kt

466 lines
14 KiB
Kotlin
Raw Normal View History

2019-08-23 14:50:04 +02:00
package jp.juggler.subwaytooter
import android.content.Context
2019-08-23 14:50:04 +02:00
import android.content.Intent
import android.content.pm.PackageManager
2019-08-23 14:50:04 +02:00
import android.graphics.drawable.StateListDrawable
import android.os.Handler
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.ForegroundColorSpan
2019-08-23 14:50:04 +02:00
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.FrameLayout
import android.widget.ListView
import android.widget.TextView
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import jp.juggler.subwaytooter.action.Action_Account
import jp.juggler.subwaytooter.action.Action_App
import jp.juggler.subwaytooter.action.Action_Instance
2021-05-19 10:43:04 +02:00
import jp.juggler.subwaytooter.api.TootApiCallback
import jp.juggler.subwaytooter.api.TootApiClient
import jp.juggler.subwaytooter.api.entity.TootInstance
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.subwaytooter.dialog.AccountPicker
2019-08-23 14:50:04 +02:00
import jp.juggler.subwaytooter.table.SavedAccount
import jp.juggler.subwaytooter.util.VersionString
2020-09-29 19:44:56 +02:00
import jp.juggler.subwaytooter.util.openBrowser
import jp.juggler.util.*
2021-05-19 10:43:04 +02:00
import kotlinx.coroutines.*
2019-08-23 14:50:04 +02:00
import org.jetbrains.anko.backgroundColor
import java.lang.ref.WeakReference
2019-08-23 14:50:04 +02:00
class SideMenuAdapter(
private val actMain : ActMain,
val handler : Handler,
2019-09-12 17:13:00 +02:00
navigationView : ViewGroup,
2019-08-23 14:50:04 +02:00
private val drawer : DrawerLayout
) : BaseAdapter() {
companion object {
private val itemTypeCount = ItemType.values().size
private var lastVersionView : WeakReference<TextView>? = null
private var versionRow = SpannableStringBuilder("")
private var releaseInfo : JsonObject? = null
private fun clickableSpan(url : String) =
object : ClickableSpan() {
override fun onClick(widget : View) {
2020-09-29 19:44:56 +02:00
widget.activity?.openBrowser(url)
}
override fun updateDrawState(ds : TextPaint) {
super.updateDrawState(ds)
ds.isUnderlineText = false
}
}
private fun checkVersion(appContext : Context, handler : Handler) {
val currentVersion = try {
appContext.packageManager.getPackageInfo(appContext.packageName, 0).versionName
} catch(ex : PackageManager.NameNotFoundException) {
"??"
}
versionRow = SpannableStringBuilder().apply {
append(
appContext.getString(
R.string.app_name_with_version,
appContext.getString(R.string.app_name),
currentVersion
)
)
}
fun afterGet() {
versionRow = SpannableStringBuilder().apply {
append(
appContext.getString(
R.string.app_name_with_version,
appContext.getString(R.string.app_name),
currentVersion
)
)
2020-09-29 19:44:56 +02:00
val newRelease = releaseInfo?.jsonObject(
if(Pref.bpCheckBetaVersion(App1.pref)) "beta" else "stable"
)
val newVersion =
(newRelease?.string("name")?.notEmpty() ?: newRelease?.string("tag_name"))
?.replace("""(v|version)\s*""".toRegex(RegexOption.IGNORE_CASE), "")
?.trim()
if(newVersion == null || newVersion.isEmpty() || VersionString(currentVersion) >= VersionString(
newVersion
)) {
val url = "https://github.com/tateisu/SubwayTooter/releases"
append("\n")
val start = length
append(appContext.getString(R.string.release_note))
setSpan(
clickableSpan(url),
start, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
} else {
append("\n")
var start = length
append(
appContext.getString(
R.string.new_version_available,
newVersion
)
)
setSpan(
ForegroundColorSpan(
appContext.attrColor(R.attr.colorRegexFilterError)
),
start, length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
newRelease?.string("html_url")?.let { url ->
append("\n")
start = length
append(appContext.getString(R.string.release_note_with_assets))
setSpan(
clickableSpan(url),
start, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
handler.post { lastVersionView?.get()?.text = versionRow }
}
val lastUpdated = releaseInfo?.string("updated_at")?.let { TootStatus.parseTime(it) }
if(lastUpdated != null && System.currentTimeMillis() - lastUpdated < 86400000L) {
afterGet()
} else {
GlobalScope.launch(Dispatchers.IO) {
val json =
App1.getHttpCached("https://mastodon-msg.juggler.jp/appVersion/appVersion.json")
?.decodeUTF8()?.decodeJsonObject()
if(json != null) {
releaseInfo = json
afterGet()
}
}
}
}
}
private enum class ItemType(val id : Int) {
IT_NORMAL(0),
IT_GROUP_HEADER(1),
IT_DIVIDER(2),
IT_VERSION(3)
}
2019-08-23 14:50:04 +02:00
private class Item(
val title : Int = 0,
val icon : Int = 0,
val action : ActMain.() -> Unit = {}
) {
val itemType : ItemType
get() = when {
title == 0 -> ItemType.IT_DIVIDER
title == 1 -> ItemType.IT_VERSION
icon == 0 -> ItemType.IT_GROUP_HEADER
else -> ItemType.IT_NORMAL
}
}
2019-08-23 15:06:35 +02:00
2019-08-23 14:50:04 +02:00
/*
no title => section divider
else no icon => section header with title
else => menu item with icon and title
*/
private val list = arrayOf(
Item(icon = R.drawable.ic_info, title = 1),
Item(),
2019-08-23 14:50:04 +02:00
Item(title = R.string.account),
Item(title = R.string.account_add, icon = R.drawable.ic_account_add) {
Action_Account.add(this)
},
Item(icon = R.drawable.ic_settings, title = R.string.account_setting) {
Action_Account.setting(this)
},
Item(),
Item(title = R.string.column),
Item(icon = R.drawable.ic_list_numbered, title = R.string.column_list) {
Action_App.columnList(this)
},
Item(icon = R.drawable.ic_close, title = R.string.close_all_columns) {
closeColumnAll()
},
Item(icon = R.drawable.ic_home, title = R.string.home) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.HOME)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_announcement, title = R.string.notifications) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.NOTIFICATIONS)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_mail, title = R.string.direct_messages) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.DIRECT_MESSAGES)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_share, title = R.string.misskey_hybrid_timeline_long) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.MISSKEY_HYBRID)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_run, title = R.string.local_timeline) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.LOCAL)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_bike, title = R.string.federate_timeline) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.FEDERATE)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_list_list, title = R.string.lists) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.LIST_LIST)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_satellite, title = R.string.antenna_list_misskey) {
Action_Account.timeline(this, defaultInsertPosition, ColumnType.MISSKEY_ANTENNA_LIST)
},
2019-08-23 14:50:04 +02:00
Item(icon = R.drawable.ic_search, title = R.string.search) {
Action_Account.timeline(
2019-09-22 00:16:13 +02:00
this,
defaultInsertPosition,
ColumnType.SEARCH,
args = arrayOf("", false)
2019-08-23 14:50:04 +02:00
)
},
Item(icon = R.drawable.ic_hashtag, title = R.string.trend_tag) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.TREND_TAG)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_star, title = R.string.favourites) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.FAVOURITES)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_bookmark, title = R.string.bookmarks) {
Action_Account.timeline(this, defaultInsertPosition, ColumnType.BOOKMARKS)
},
2021-05-19 10:43:04 +02:00
Item(icon = R.drawable.ic_face, title = R.string.fedibird_reactions) {
Action_Account.getReactionableAccounts(this,allowMisskey = false){ list->
val columnType = ColumnType.REACTIONS
AccountPicker.pick(
this,
accountListArg = list,
bAuto = true,
message = getString(
R.string.account_picker_add_timeline_of,
columnType.name1(this)
)
) { ai ->
addColumn(defaultInsertPosition, ai, columnType )
2021-05-19 10:43:04 +02:00
}
}
},
2019-08-23 14:50:04 +02:00
Item(icon = R.drawable.ic_account_box, title = R.string.profile) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.PROFILE)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_follow_wait, title = R.string.follow_requests) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.FOLLOW_REQUESTS)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_follow_plus, title = R.string.follow_suggestion) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.FOLLOW_SUGGESTION)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_follow_plus, title = R.string.endorse_set) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.ENDORSEMENT)
},
Item(icon = R.drawable.ic_follow_plus, title = R.string.profile_directory) {
Action_Instance.profileDirectoryFromSideMenu(this)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_volume_off, title = R.string.muted_users) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.MUTES)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_block, title = R.string.blocked_users) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.BLOCKS)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_volume_off, title = R.string.keyword_filters) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.KEYWORD_FILTER)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_cloud_off, title = R.string.blocked_domains) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.DOMAIN_BLOCKS)
2019-08-23 14:50:04 +02:00
},
Item(icon = R.drawable.ic_timer, title = R.string.scheduled_status_list) {
2019-09-22 00:16:13 +02:00
Action_Account.timeline(this, defaultInsertPosition, ColumnType.SCHEDULED_STATUS)
2019-08-23 14:50:04 +02:00
},
Item(),
Item(title = R.string.toot_search),
Item(icon = R.drawable.ic_search, title = R.string.mastodon_search_portal) {
addColumn(defaultInsertPosition, SavedAccount.na, ColumnType.SEARCH_MSP, "")
},
2019-08-23 14:50:04 +02:00
Item(icon = R.drawable.ic_search, title = R.string.tootsearch) {
2019-09-22 00:16:13 +02:00
addColumn(defaultInsertPosition, SavedAccount.na, ColumnType.SEARCH_TS, "")
2019-08-23 14:50:04 +02:00
},
2020-12-07 13:23:14 +01:00
Item(icon = R.drawable.ic_search, title = R.string.notestock) {
addColumn(defaultInsertPosition, SavedAccount.na, ColumnType.SEARCH_NOTESTOCK, "")
},
2019-08-23 14:50:04 +02:00
Item(),
Item(title = R.string.setting),
Item(icon = R.drawable.ic_settings, title = R.string.app_setting) {
ActAppSetting.open(this, ActMain.REQUEST_CODE_APP_SETTING)
},
Item(icon = R.drawable.ic_settings, title = R.string.highlight_word) {
startActivity(Intent(this, ActHighlightWordList::class.java))
},
Item(icon = R.drawable.ic_volume_off, title = R.string.muted_app) {
startActivity(Intent(this, ActMutedApp::class.java))
},
Item(icon = R.drawable.ic_volume_off, title = R.string.muted_word) {
startActivity(Intent(this, ActMutedWord::class.java))
},
Item(icon = R.drawable.ic_volume_off, title = R.string.fav_muted_user) {
startActivity(Intent(this, ActFavMute::class.java))
},
Item(
icon = R.drawable.ic_volume_off,
title = R.string.muted_users_from_pseudo_account
) {
startActivity(Intent(this, ActMutedPseudoAccount::class.java))
},
Item(icon = R.drawable.ic_info, title = R.string.app_about) {
startActivityForResult(
Intent(this, ActAbout::class.java),
ActMain.REQUEST_APP_ABOUT
)
},
Item(icon = R.drawable.ic_info, title = R.string.oss_license) {
startActivity(Intent(this, ActOSSLicense::class.java))
},
Item(icon = R.drawable.ic_hot_tub, title = R.string.app_exit) {
finish()
}
)
private val iconColor = actMain.attrColor(R.attr.colorTimeSmall)
2019-08-23 15:06:35 +02:00
override fun getCount() : Int = list.size
override fun getItem(position : Int) : Any = list[position]
2019-08-23 14:50:04 +02:00
override fun getItemId(position : Int) : Long = 0L
override fun getViewTypeCount() : Int = itemTypeCount
override fun getItemViewType(position : Int) : Int = list[position].itemType.id
2019-08-23 14:50:04 +02:00
private inline fun <reified T : View> viewOrInflate(
view : View?,
parent : ViewGroup?,
resId : Int
2019-08-23 15:06:35 +02:00
) : T =
(view ?: actMain.layoutInflater.inflate(resId, parent, false))
2019-08-23 15:06:35 +02:00
as? T ?: error("invalid view type! ${T::class.java.simpleName}")
2019-08-23 14:50:04 +02:00
2019-08-23 15:06:35 +02:00
override fun getView(position : Int, view : View?, parent : ViewGroup?) : View =
list[position].run {
when(itemType) {
ItemType.IT_DIVIDER ->
viewOrInflate(view, parent, R.layout.lv_sidemenu_separator)
ItemType.IT_GROUP_HEADER ->
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_group).apply {
text = actMain.getString(title)
}
ItemType.IT_NORMAL ->
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
2019-08-23 15:06:35 +02:00
isAllCaps = false
text = actMain.getString(title)
val drawable = createColoredDrawable(actMain, icon, iconColor, 1f)
setCompoundDrawablesRelativeWithIntrinsicBounds(
drawable,
null,
null,
null
)
2019-08-23 15:06:35 +02:00
setOnClickListener {
action(actMain)
2019-08-23 15:06:35 +02:00
drawer.closeDrawer(GravityCompat.START)
}
2019-08-23 14:50:04 +02:00
}
ItemType.IT_VERSION ->
viewOrInflate<TextView>(view, parent, R.layout.lv_sidemenu_item).apply {
lastVersionView = WeakReference(this)
movementMethod = LinkMovementMethod.getInstance()
textSize = 18f
isAllCaps = false
background = null
text = versionRow
}
2019-08-23 15:06:35 +02:00
}
2019-08-23 14:50:04 +02:00
}
init {
checkVersion(actMain.applicationContext, handler)
ListView(actMain).apply {
2019-08-23 14:50:04 +02:00
adapter = this@SideMenuAdapter
layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
backgroundColor = actMain.attrColor(R.attr.colorWindowBackground)
2019-08-23 14:50:04 +02:00
selector = StateListDrawable()
divider = null
dividerHeight = 0
2020-12-22 05:27:39 +01:00
isScrollbarFadingEnabled = false
val pad_tb = (actMain.density * 12f + 0.5f).toInt()
2019-08-23 14:50:04 +02:00
setPadding(0, pad_tb, 0, pad_tb)
clipToPadding = false
scrollBarStyle = ListView.SCROLLBARS_OUTSIDE_OVERLAY
2019-08-23 15:06:35 +02:00
navigationView.addView(this)
}
2019-08-23 14:50:04 +02:00
}
}