(試験対応)トレンドタグと検索v2
This commit is contained in:
parent
640fee04ac
commit
4d5173808f
|
@ -12,8 +12,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 27
|
||||
|
||||
versionCode 255
|
||||
versionName "2.5.5"
|
||||
versionCode 256
|
||||
versionName "2.5.6"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
// https://stackoverflow.com/questions/47791227/java-lang-illegalstateexception-dex-archives-setting-dex-extension-only-for
|
||||
|
|
|
@ -1008,6 +1008,12 @@ class ActMain : AppCompatActivity()
|
|||
false,
|
||||
Column.TYPE_FOLLOW_REQUESTS
|
||||
)
|
||||
R.id.nav_add_trend_tag ->Action_Account.timeline(
|
||||
this,
|
||||
defaultInsertPosition,
|
||||
true,
|
||||
Column.TYPE_TREND_TAG
|
||||
)
|
||||
|
||||
// トゥート検索
|
||||
R.id.mastodon_search_portal -> addColumn(
|
||||
|
|
|
@ -95,6 +95,7 @@ class Column(
|
|||
private const val PATH_STATUSES = "/api/v1/statuses/%d" // 1:status_id
|
||||
private const val PATH_STATUSES_CONTEXT = "/api/v1/statuses/%d/context" // 1:status_id
|
||||
const val PATH_SEARCH = "/api/v1/search?q=%s"
|
||||
const val PATH_SEARCH_V2 = "/api/v2/search?q=%s"
|
||||
// search args 1: query(urlencoded) , also, append "&resolve=1" if resolve non-local accounts
|
||||
private const val PATH_INSTANCE = "/api/v1/instance"
|
||||
private const val PATH_LIST_INFO = "/api/v1/lists/%s"
|
||||
|
@ -164,6 +165,7 @@ class Column(
|
|||
internal const val TYPE_LIST_MEMBER = 21
|
||||
internal const val TYPE_SEARCH_TS = 22
|
||||
internal const val TYPE_DIRECT_MESSAGES = 23
|
||||
internal const val TYPE_TREND_TAG = 24
|
||||
|
||||
internal const val TAB_STATUS = 0
|
||||
internal const val TAB_FOLLOWING = 1
|
||||
|
@ -210,6 +212,7 @@ class Column(
|
|||
TYPE_LIST_MEMBER -> context.getString(R.string.list_member)
|
||||
TYPE_LIST_TL -> context.getString(R.string.list_timeline)
|
||||
TYPE_DIRECT_MESSAGES -> context.getString(R.string.direct_messages)
|
||||
TYPE_TREND_TAG ->context.getString(R.string.trend_tag)
|
||||
else -> "?"
|
||||
}
|
||||
}
|
||||
|
@ -237,6 +240,7 @@ class Column(
|
|||
TYPE_LIST_MEMBER -> R.attr.ic_list_member
|
||||
TYPE_LIST_TL -> R.attr.ic_list_tl
|
||||
TYPE_DIRECT_MESSAGES -> R.attr.ic_mail
|
||||
TYPE_TREND_TAG -> R.attr.ic_hashtag
|
||||
else -> R.attr.ic_info
|
||||
}
|
||||
}
|
||||
|
@ -1878,11 +1882,57 @@ class Column(
|
|||
return result
|
||||
}
|
||||
|
||||
TYPE_TREND_TAG ->{
|
||||
result = client.request( "/api/v1/trends" )
|
||||
val src = parser.trendTagList(result?.jsonArray)
|
||||
src.sortBy { - it.history.first().uses }
|
||||
this.list_tmp = addAll(this.list_tmp, src)
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
TYPE_SEARCH -> {
|
||||
if(access_info.isPseudo) {
|
||||
// 1.5.0rc からマストドンの検索APIは認証を要求するようになった
|
||||
return TootApiResult(context.getString(R.string.search_is_not_available_on_pseudo_account))
|
||||
}
|
||||
|
||||
var instance = access_info.instance
|
||||
if( instance == null ){
|
||||
// まだ取得してない
|
||||
val r2 = getInstanceInformation(client, null)
|
||||
if(instance_tmp != null) {
|
||||
instance = instance_tmp
|
||||
access_info.instance = instance
|
||||
}
|
||||
}
|
||||
|
||||
if( instance != null && instance.versionGE(TootInstance.VERSION_2_4_0) ){
|
||||
// v2 api を試す
|
||||
var path = String.format(
|
||||
Locale.JAPAN,
|
||||
PATH_SEARCH_V2,
|
||||
search_query.encodePercent()
|
||||
)
|
||||
if(search_resolve) path += "&resolve=1"
|
||||
|
||||
result = client.request(path)
|
||||
val jsonObject = result?.jsonObject
|
||||
if( jsonObject != null ){
|
||||
val tmp = parser.resultsV2(jsonObject)
|
||||
if(tmp != null) {
|
||||
list_tmp = ArrayList()
|
||||
addAll(list_tmp, tmp.hashtags)
|
||||
addAll(list_tmp, tmp.accounts)
|
||||
addAll(list_tmp, tmp.statuses)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var path =
|
||||
String.format(
|
||||
Locale.JAPAN,
|
||||
|
@ -3510,7 +3560,12 @@ class Column(
|
|||
|
||||
fun canReloadWhenRefreshTop() : Boolean {
|
||||
return when(column_type) {
|
||||
TYPE_SEARCH, TYPE_SEARCH_MSP, TYPE_SEARCH_TS, TYPE_CONVERSATION, TYPE_LIST_LIST -> true
|
||||
TYPE_SEARCH,
|
||||
TYPE_SEARCH_MSP,
|
||||
TYPE_SEARCH_TS,
|
||||
TYPE_CONVERSATION,
|
||||
TYPE_LIST_LIST ,
|
||||
TYPE_TREND_TAG-> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -484,10 +484,10 @@ class ColumnViewHolder(
|
|||
|
||||
when(column.column_type) {
|
||||
|
||||
Column.TYPE_CONVERSATION, Column.TYPE_INSTANCE_INFORMATION -> refreshLayout.isEnabled =
|
||||
false
|
||||
Column.TYPE_CONVERSATION,
|
||||
Column.TYPE_INSTANCE_INFORMATION -> refreshLayout.isEnabled = false
|
||||
|
||||
Column.TYPE_SEARCH -> {
|
||||
Column.TYPE_SEARCH, Column.TYPE_TREND_TAG -> {
|
||||
refreshLayout.isEnabled = true
|
||||
refreshLayout.direction = SwipyRefreshLayoutDirection.TOP
|
||||
}
|
||||
|
|
|
@ -106,6 +106,11 @@ internal class ItemViewHolder(
|
|||
|
||||
private lateinit var llSearchTag : View
|
||||
private lateinit var btnSearchTag : Button
|
||||
private lateinit var llTrendTag : View
|
||||
private lateinit var tvTrendTagName : TextView
|
||||
private lateinit var tvTrendTagDesc : TextView
|
||||
private lateinit var tvTrendTagCount : TextView
|
||||
private lateinit var cvTrendTagHistory : TrendTagHistoryView
|
||||
|
||||
private lateinit var llList : View
|
||||
private lateinit var btnListTL : Button
|
||||
|
@ -181,6 +186,8 @@ internal class ItemViewHolder(
|
|||
|
||||
btnHideMedia.setOnClickListener(this)
|
||||
|
||||
llTrendTag.setOnClickListener(this)
|
||||
llTrendTag.setOnLongClickListener(this)
|
||||
|
||||
|
||||
this.content_color_default = tvContent.textColors.defaultColor
|
||||
|
@ -196,6 +203,8 @@ internal class ItemViewHolder(
|
|||
tvApplication.textSize = activity.timeline_font_size_sp
|
||||
tvMessageHolder.textSize = activity.timeline_font_size_sp
|
||||
btnListTL.textSize = activity.timeline_font_size_sp
|
||||
tvTrendTagName.textSize = activity.timeline_font_size_sp
|
||||
tvTrendTagCount.textSize = activity.timeline_font_size_sp
|
||||
}
|
||||
|
||||
if(! activity.acct_font_size_sp.isNaN()) {
|
||||
|
@ -204,6 +213,7 @@ internal class ItemViewHolder(
|
|||
tvFollowerAcct.textSize = activity.acct_font_size_sp
|
||||
tvAcct.textSize = activity.acct_font_size_sp
|
||||
tvTime.textSize = activity.acct_font_size_sp
|
||||
tvTrendTagDesc.textSize = activity.acct_font_size_sp
|
||||
}
|
||||
|
||||
ivThumbnail.layoutParams.height = activity.avatarIconSize
|
||||
|
@ -241,7 +251,11 @@ internal class ItemViewHolder(
|
|||
// ボタンは太字なので触らない
|
||||
} else if(v is TextView) {
|
||||
val typeface = when {
|
||||
v === tvName || v === tvFollowerName || v === tvBoosted -> activity.timeline_font_bold
|
||||
v === tvName ||
|
||||
v === tvFollowerName ||
|
||||
v === tvBoosted ||
|
||||
v === tvTrendTagCount ||
|
||||
v === tvTrendTagName -> activity.timeline_font_bold
|
||||
?: activity.timeline_font
|
||||
else -> activity.timeline_font ?: activity.timeline_font_bold
|
||||
}
|
||||
|
@ -321,6 +335,7 @@ internal class ItemViewHolder(
|
|||
llFollowRequest.visibility = View.GONE
|
||||
llExtra.removeAllViews()
|
||||
tvMessageHolder.visibility = View.GONE
|
||||
llTrendTag.visibility = View.GONE
|
||||
|
||||
var c : Int
|
||||
c = if(column.content_color != 0) column.content_color else content_color_default
|
||||
|
@ -333,6 +348,9 @@ internal class ItemViewHolder(
|
|||
//NSFWは文字色固定 btnShowMedia.setTextColor( c );
|
||||
tvApplication.setTextColor(c)
|
||||
tvMessageHolder.setTextColor(c)
|
||||
tvTrendTagName.setTextColor(c)
|
||||
tvTrendTagCount.setTextColor(c)
|
||||
cvTrendTagHistory.setColor(c)
|
||||
|
||||
c = if(column.acct_color != 0) column.acct_color else Styler.getAttributeColor(
|
||||
activity,
|
||||
|
@ -341,6 +359,7 @@ internal class ItemViewHolder(
|
|||
this.acct_color = c
|
||||
tvBoostedTime.setTextColor(c)
|
||||
tvTime.setTextColor(c)
|
||||
tvTrendTagDesc.setTextColor(c)
|
||||
// tvBoostedAcct.setTextColor( c );
|
||||
// tvFollowerAcct.setTextColor( c );
|
||||
// tvAcct.setTextColor( c );
|
||||
|
@ -366,18 +385,30 @@ internal class ItemViewHolder(
|
|||
|
||||
is TootNotification -> showNotification(item)
|
||||
|
||||
is TootTag -> showSearchTag(item)
|
||||
is TootGap -> showGap()
|
||||
is TootDomainBlock -> showDomainBlock(item)
|
||||
is TootList -> showList(item)
|
||||
|
||||
is TootMessageHolder -> showMessageHolder(item)
|
||||
|
||||
// TootTrendTag の後に TootTagを判定すること
|
||||
is TootTrendTag -> showTrendTag(item)
|
||||
is TootTag -> showSearchTag(item)
|
||||
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showTrendTag(item : TootTrendTag) {
|
||||
llTrendTag.visibility = View.VISIBLE
|
||||
tvTrendTagName.text = "#${item.name}"
|
||||
val latest = item.history.first()
|
||||
tvTrendTagDesc.text = activity.getString(R.string.people_talking, latest.accounts)
|
||||
tvTrendTagCount.text = latest.uses.toString()
|
||||
cvTrendTagHistory.setHistory(item.history)
|
||||
}
|
||||
|
||||
private fun showMessageHolder(item : TootMessageHolder) {
|
||||
tvMessageHolder.visibility = View.VISIBLE
|
||||
tvMessageHolder.text = item.text
|
||||
|
@ -945,7 +976,7 @@ internal class ItemViewHolder(
|
|||
DlgContextMenu(activity, column, who, null, notification).show()
|
||||
}
|
||||
|
||||
btnSearchTag -> when(item) {
|
||||
btnSearchTag, llTrendTag -> when(item) {
|
||||
is TootGap -> column.startGap(item)
|
||||
|
||||
is TootDomainBlock -> {
|
||||
|
@ -1098,7 +1129,7 @@ internal class ItemViewHolder(
|
|||
return true
|
||||
}
|
||||
|
||||
btnSearchTag -> {
|
||||
btnSearchTag, llTrendTag -> {
|
||||
val item = this.item
|
||||
when(item) {
|
||||
// is TootGap -> column.startGap(item)
|
||||
|
@ -1907,6 +1938,36 @@ internal class ItemViewHolder(
|
|||
}.lparams(matchParent, wrapContent)
|
||||
}
|
||||
|
||||
llTrendTag = linearLayout {
|
||||
lparams(matchParent, wrapContent)
|
||||
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
background = ContextCompat.getDrawable(context, R.drawable.btn_bg_transparent)
|
||||
|
||||
verticalLayout {
|
||||
lparams(0, wrapContent) {
|
||||
weight = 1f
|
||||
}
|
||||
tvTrendTagName = textView {
|
||||
}.lparams(matchParent, wrapContent)
|
||||
tvTrendTagDesc = textView {
|
||||
textColor = Styler.getAttributeColor(context, R.attr.colorTimeSmall)
|
||||
textSize = 12f // SP
|
||||
}.lparams(matchParent, wrapContent)
|
||||
}
|
||||
tvTrendTagCount = textView {
|
||||
|
||||
}.lparams(wrapContent, wrapContent) {
|
||||
startMargin = dip(6)
|
||||
endMargin = dip(6)
|
||||
}
|
||||
|
||||
cvTrendTagHistory = trendTagHistoryView {
|
||||
|
||||
}.lparams(dip(64), dip(32))
|
||||
|
||||
}
|
||||
|
||||
llList = linearLayout {
|
||||
lparams(matchParent, wrapContent)
|
||||
|
||||
|
|
|
@ -28,5 +28,8 @@ class TootParser(
|
|||
|
||||
fun results(src : JSONObject?) = parseItem(::TootResults, this, src)
|
||||
fun instance(src : JSONObject?) = parseItem(::TootInstance, this, src)
|
||||
fun trendTagList(array : JSONArray?)= parseList(::TootTrendTag, array)
|
||||
|
||||
fun resultsV2(src : JSONObject) = parseItem(::TootResultsV2, this, src)
|
||||
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ class TootInstance(parser : TootParser, src : JSONObject) {
|
|||
val VERSION_1_6 = VersionString("1.6")
|
||||
val VERSION_2_4_0_rc1 = VersionString("2.4.0rc1")
|
||||
val VERSION_2_4_0_rc2 = VersionString("2.4.0rc2")
|
||||
val VERSION_2_4_0 = VersionString("2.4.0")
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package jp.juggler.subwaytooter.api.entity
|
||||
|
||||
import org.json.JSONObject
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
import jp.juggler.subwaytooter.api.TootParser
|
||||
|
||||
class TootResultsV2(
|
||||
val accounts : ArrayList<TootAccountRef>, // An array of matched Accounts
|
||||
val statuses : ArrayList<TootStatus>, // An array of matched Statuses
|
||||
val hashtags : ArrayList<TootTrendTag> // An array of matched hashtags
|
||||
) {
|
||||
|
||||
constructor(parser : TootParser, src : JSONObject) : this(
|
||||
accounts = parser.accountList(src.optJSONArray("accounts")),
|
||||
statuses = parser.statusList( src.optJSONArray("statuses")),
|
||||
hashtags = parser.trendTagList(src.optJSONArray("hashtags"))
|
||||
)
|
||||
}
|
|
@ -6,14 +6,13 @@ import jp.juggler.subwaytooter.util.parseString
|
|||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
class TootTag(
|
||||
open class TootTag(
|
||||
// The hashtag, not including the preceding #
|
||||
val name : String,
|
||||
// The URL of the hashtag. may null if generated from TootContext
|
||||
val url : String? = null
|
||||
) : TimelineItem() {
|
||||
|
||||
|
||||
constructor(src : JSONObject) : this(
|
||||
name = src.notEmptyOrThrow("name"),
|
||||
url = src.parseString("url")
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package jp.juggler.subwaytooter.api.entity
|
||||
|
||||
import jp.juggler.subwaytooter.util.LogCategory
|
||||
import jp.juggler.subwaytooter.util.notEmptyOrThrow
|
||||
import jp.juggler.subwaytooter.util.parseLong
|
||||
import jp.juggler.subwaytooter.util.parseString
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
class TootTrendTag(
|
||||
name : String,
|
||||
url : String?,
|
||||
val history : ArrayList<History>
|
||||
) : TootTag(name, url) {
|
||||
|
||||
class History(src : JSONObject) {
|
||||
val day : Long
|
||||
val uses : Long
|
||||
val accounts : Long
|
||||
|
||||
init {
|
||||
day = src.parseLong("day")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing day")
|
||||
uses = src.parseLong("uses")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing uses")
|
||||
accounts = src.parseLong("accounts")
|
||||
?: throw RuntimeException("TootTrendTag.History: missing accounts")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
constructor(src : JSONObject) : this(
|
||||
name = src.notEmptyOrThrow("name"),
|
||||
url = src.parseString("url"),
|
||||
history = parseHistory(src.optJSONArray("history"))
|
||||
)
|
||||
|
||||
companion object {
|
||||
val log = LogCategory("TootTrendTag")
|
||||
|
||||
private fun parseHistory(src : JSONArray?) : ArrayList<History> {
|
||||
src ?: throw RuntimeException("TootTrendTag: missing history")
|
||||
|
||||
val dst = ArrayList<History>()
|
||||
for(i in 0 until src.length()) {
|
||||
try {
|
||||
dst.add(History(src.optJSONObject(i)))
|
||||
} catch(ex : Throwable) {
|
||||
log.e(ex, "history parse failed.")
|
||||
}
|
||||
}
|
||||
|
||||
if(dst.isEmpty()) {
|
||||
throw RuntimeException("TootTrendTag: empty history")
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package jp.juggler.subwaytooter.util
|
|||
import android.view.ViewManager
|
||||
import jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
import jp.juggler.subwaytooter.view.MyTextView
|
||||
import jp.juggler.subwaytooter.view.TrendTagHistoryView
|
||||
import org.jetbrains.anko.custom.ankoView
|
||||
|
||||
// Anko Layout中にカスタムビューを指定する為に拡張関数を定義する
|
||||
|
@ -11,7 +12,12 @@ inline fun ViewManager.myNetworkImageView(init: MyNetworkImageView.() -> Unit):
|
|||
return ankoView({ MyNetworkImageView(it) }, theme = 0, init = init)
|
||||
}
|
||||
|
||||
inline fun ViewManager.myTextView(init: MyTextView.() -> Unit): MyTextView {
|
||||
inline fun ViewManager.myTextView(init: MyTextView.() -> Unit) : MyTextView {
|
||||
return ankoView({ MyTextView(it) }, theme = 0, init = init)
|
||||
}
|
||||
|
||||
|
||||
inline fun ViewManager.trendTagHistoryView(init: TrendTagHistoryView.() -> Unit): TrendTagHistoryView {
|
||||
return ankoView({ TrendTagHistoryView(it) }, theme = 0, init = init)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
package jp.juggler.subwaytooter.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.PathInterpolator
|
||||
import jp.juggler.subwaytooter.api.entity.TootTrendTag
|
||||
import jp.juggler.subwaytooter.util.clipRange
|
||||
|
||||
class TrendTagHistoryView : View {
|
||||
|
||||
private val paint = Paint()
|
||||
private var values : List<Float>? = null
|
||||
private var delta : Float = 0f
|
||||
private val path = Path()
|
||||
private var lineWidth = 1f
|
||||
private var y_workarea : Array<Float>? = null
|
||||
|
||||
constructor(context : Context) : super(context) {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context : Context, attrs : AttributeSet?) : super(context, attrs) {
|
||||
init()
|
||||
}
|
||||
|
||||
constructor(context : Context, attrs : AttributeSet?, defStyleAttr : Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
) {
|
||||
init()
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
val density = context.resources.displayMetrics.density
|
||||
this.lineWidth = 2f * density
|
||||
paint.style = Paint.Style.STROKE
|
||||
paint.strokeWidth = lineWidth
|
||||
}
|
||||
|
||||
fun setColor(c : Int) {
|
||||
paint.color = c
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun setHistory(history : ArrayList<TootTrendTag.History>?) {
|
||||
if(history?.isEmpty() != false) {
|
||||
delta = 0f
|
||||
values = null
|
||||
} else {
|
||||
var min = Long.MAX_VALUE
|
||||
var max = Long.MIN_VALUE
|
||||
for(h in history) {
|
||||
min = Math.min(min, h.uses)
|
||||
max = Math.max(max, h.uses)
|
||||
}
|
||||
val delta = (max - min).toFloat()
|
||||
this.delta = delta
|
||||
if(delta == 0f) {
|
||||
values = null
|
||||
} else {
|
||||
values = history.map { (it.uses - min).toFloat() / delta }.reversed()
|
||||
y_workarea = Array(history.size) { 0f }
|
||||
}
|
||||
}
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onDraw(canvas : Canvas) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
val values = this.values ?: return
|
||||
|
||||
val view_w = width.toFloat()
|
||||
val view_h = height.toFloat()
|
||||
if(view_w < 1f || view_h < 1f) return
|
||||
|
||||
if(delta == 0f) {
|
||||
val y = height / 2f
|
||||
canvas.drawLine(0f, y, view_w, y, paint)
|
||||
return
|
||||
}
|
||||
|
||||
val size = values.size
|
||||
val x_step = view_w / (size - 1).toFloat()
|
||||
var x = 0f
|
||||
path.reset()
|
||||
var lastSlope = 0f
|
||||
var lastY = 0f
|
||||
var lastX = 0f
|
||||
val controlXStep = x_step / 2f
|
||||
val y_workarea = this.y_workarea ?: return
|
||||
val y_min = lineWidth * 2f
|
||||
val y_max = view_h - lineWidth * 2f
|
||||
val y_width = y_max - y_min
|
||||
for(i in 0 until size) {
|
||||
y_workarea[i] = (1f - values[i]) * y_width + y_min
|
||||
}
|
||||
for(i in 0 until size) {
|
||||
val y = y_workarea[i]
|
||||
when(i) {
|
||||
0 -> {
|
||||
path.moveTo(x, y)
|
||||
lastSlope = (y_workarea[i + 1] - y) / x_step
|
||||
}
|
||||
|
||||
size - 1 -> {
|
||||
// 制御点1
|
||||
val c1x = lastX + controlXStep
|
||||
val c1y = clipRange(y_min, y_max, lastY + controlXStep * lastSlope)
|
||||
// 制御点2
|
||||
val slope = (y - lastY) / x_step
|
||||
val c2x = x - controlXStep
|
||||
val c2y = y - controlXStep * slope
|
||||
path.cubicTo(c1x, c1y, c2x, c2y, x, y)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// 制御点1
|
||||
val c1x = lastX + controlXStep
|
||||
val c1y = clipRange(y_min, y_max, lastY + controlXStep * lastSlope)
|
||||
|
||||
// 制御点2
|
||||
val nextY = y_workarea[i + 1]
|
||||
val slope = if((y > lastY && y > nextY) || (y < lastY && y < nextY)) {
|
||||
// 極値は傾き0とみなす
|
||||
0f
|
||||
} else if(y == lastY || y == nextY) {
|
||||
// 左右のどちらかが平坦なら平坦とみなす
|
||||
0f
|
||||
} else {
|
||||
// 前後で同じように勾配しているなら傾きは平均とする
|
||||
val slope1 = (y - lastY) / x_step
|
||||
val slope2 = (nextY - y) / x_step
|
||||
(slope1 + slope2) / 2f
|
||||
}
|
||||
val c2x = x - controlXStep
|
||||
val c2y = clipRange(y_min, y_max, y - controlXStep * slope)
|
||||
|
||||
path.cubicTo(c1x, c1y, c2x, c2y, x, y)
|
||||
lastSlope = slope
|
||||
}
|
||||
}
|
||||
lastX = x
|
||||
lastY = y
|
||||
x += x_step
|
||||
}
|
||||
canvas.drawPath(path, paint)
|
||||
}
|
||||
|
||||
}
|
|
@ -4,17 +4,17 @@
|
|||
<group android:checkableBehavior="single">
|
||||
|
||||
<item android:title="@string/account">
|
||||
<menu>
|
||||
<menu>
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_account_add"
|
||||
android:icon="?attr/ic_account_add"
|
||||
android:title="@string/account_add"/>
|
||||
<item
|
||||
android:id="@+id/nav_account_setting"
|
||||
android:icon="?attr/ic_setting"
|
||||
android:title="@string/account_setting"/>
|
||||
</menu>
|
||||
<item
|
||||
android:id="@+id/nav_account_add"
|
||||
android:icon="?attr/ic_account_add"
|
||||
android:title="@string/account_add"/>
|
||||
<item
|
||||
android:id="@+id/nav_account_setting"
|
||||
android:icon="?attr/ic_setting"
|
||||
android:title="@string/account_setting"/>
|
||||
</menu>
|
||||
</item>
|
||||
<item android:title="@string/column">
|
||||
<menu>
|
||||
|
@ -31,6 +31,7 @@
|
|||
android:id="@+id/nav_add_notifications"
|
||||
android:icon="?attr/btn_notification"
|
||||
android:title="@string/notifications"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_add_direct_message"
|
||||
android:icon="?attr/ic_mail"
|
||||
|
@ -46,7 +47,6 @@
|
|||
android:icon="?attr/btn_federate_tl"
|
||||
android:title="@string/federate_timeline"/>
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_add_list"
|
||||
android:icon="?attr/ic_list_list"
|
||||
|
@ -57,6 +57,11 @@
|
|||
android:icon="?attr/ic_search"
|
||||
android:title="@string/search"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_add_trend_tag"
|
||||
android:icon="?attr/ic_hashtag"
|
||||
android:title="@string/trend_tag"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_add_favourites"
|
||||
android:icon="?attr/btn_favourite"
|
||||
|
@ -92,7 +97,6 @@
|
|||
<!--android:icon="?attr/btn_report"-->
|
||||
<!--android:title="@string/your_reports"/>-->
|
||||
|
||||
|
||||
<!--<item-->
|
||||
<!--android:id="@+id/nav_slideshow"-->
|
||||
<!--android:icon="?attr/ic_menu_slideshow"-->
|
||||
|
@ -116,7 +120,6 @@
|
|||
</menu>
|
||||
</item>
|
||||
|
||||
|
||||
<item android:title="@string/setting">
|
||||
<menu>
|
||||
|
||||
|
@ -149,9 +152,9 @@
|
|||
android:title="@string/app_about"/>
|
||||
|
||||
<!--<item-->
|
||||
<!--android:id="@+id/nav_translation"-->
|
||||
<!--android:icon="?attr/ic_info"-->
|
||||
<!--android:title="@string/help_translation"/>-->
|
||||
<!--android:id="@+id/nav_translation"-->
|
||||
<!--android:icon="?attr/ic_info"-->
|
||||
<!--android:title="@string/help_translation"/>-->
|
||||
|
||||
<item
|
||||
android:id="@+id/nav_oss_license"
|
||||
|
|
|
@ -678,8 +678,10 @@
|
|||
<string name="none_or_hidden_followers">There is no followers, or hidden by setting.</string>
|
||||
<string name="yourself_can_see_your_network">Even if you choose to hide social graphs, yourself can see it.</string>
|
||||
<string name="follow_follower_list_may_restrict">If remote user chooses to hide the social graph, only the followings/followers on this instance will be displayed.</string>
|
||||
<string name="trend_tag">Trending tags</string>
|
||||
<string name="people_talking">%1$d people talking</string>
|
||||
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->
|
||||
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
|
||||
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->
|
||||
|
|
|
@ -956,5 +956,7 @@
|
|||
<string name="none_or_hidden_followers">フォロワーはいません。または設定により隠されています。</string>
|
||||
<string name="yourself_can_see_your_network">もしあなたがソーシャルグラフを隠す選択をした場合でも、あなた自身はそれを見ることができます。</string>
|
||||
<string name="follow_follower_list_may_restrict">もしリモートのユーザがソーシャルグラフを隠す選択をした場合、表示されるのはこのタンスのユーザだけです。</string>
|
||||
<string name="trend_tag">トレンドタグ</string>
|
||||
<string name="people_talking">%1$d人がトゥート</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -663,4 +663,6 @@
|
|||
<string name="none_or_hidden_followers">There is no followers, or hidden by setting.</string>
|
||||
<string name="yourself_can_see_your_network">Even if you choose to hide social graphs, yourself can see it.</string>
|
||||
<string name="follow_follower_list_may_restrict">If remote user chooses to hide the social graph, only the followings/followers on this instance will be displayed.</string>
|
||||
<string name="trend_tag">Trending tags</string>
|
||||
<string name="people_talking">%1$d people talking</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue