2018-01-04 19:52:25 +01:00
|
|
|
|
package jp.juggler.subwaytooter.table
|
|
|
|
|
|
|
|
|
|
import android.content.ContentValues
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.database.Cursor
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase
|
|
|
|
|
import android.provider.BaseColumns
|
|
|
|
|
|
|
|
|
|
import org.json.JSONObject
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList
|
|
|
|
|
import java.util.Collections
|
|
|
|
|
import java.util.Comparator
|
|
|
|
|
import java.util.concurrent.atomic.AtomicReference
|
|
|
|
|
import java.util.regex.Pattern
|
|
|
|
|
|
|
|
|
|
import jp.juggler.subwaytooter.App1
|
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootAccount
|
|
|
|
|
import jp.juggler.subwaytooter.api.entity.TootInstance
|
|
|
|
|
import jp.juggler.subwaytooter.util.LinkClickContext
|
|
|
|
|
import jp.juggler.subwaytooter.util.LogCategory
|
|
|
|
|
import jp.juggler.subwaytooter.util.Utils
|
|
|
|
|
|
|
|
|
|
class SavedAccount(
|
2018-01-10 16:47:35 +01:00
|
|
|
|
val db_id : Long,
|
|
|
|
|
val acct : String,
|
2018-01-13 07:15:52 +01:00
|
|
|
|
hostArg : String? = null,
|
|
|
|
|
var token_info : JSONObject? = null,
|
|
|
|
|
var loginAccount : TootAccount? = null // 疑似アカウントではnull
|
2018-01-04 19:52:25 +01:00
|
|
|
|
) : LinkClickContext {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
|
|
|
|
val username : String
|
2018-01-04 19:52:25 +01:00
|
|
|
|
|
2018-01-10 16:47:35 +01:00
|
|
|
|
override val host : String
|
2018-01-04 19:52:25 +01:00
|
|
|
|
|
|
|
|
|
var visibility : String? = null
|
|
|
|
|
var confirm_boost : Boolean = false
|
|
|
|
|
|
|
|
|
|
var dont_hide_nsfw : Boolean = false
|
|
|
|
|
var dont_show_timeout : Boolean = false
|
|
|
|
|
|
|
|
|
|
var notification_mention : Boolean = false
|
|
|
|
|
var notification_boost : Boolean = false
|
|
|
|
|
var notification_favourite : Boolean = false
|
|
|
|
|
var notification_follow : Boolean = false
|
|
|
|
|
var sound_uri = ""
|
|
|
|
|
|
|
|
|
|
var confirm_follow : Boolean = false
|
|
|
|
|
var confirm_follow_locked : Boolean = false
|
|
|
|
|
var confirm_unfollow : Boolean = false
|
|
|
|
|
var confirm_post : Boolean = false
|
|
|
|
|
|
|
|
|
|
var notification_tag : String? = null
|
|
|
|
|
var register_key : String? = null
|
|
|
|
|
var register_time : Long = 0
|
|
|
|
|
|
|
|
|
|
private val refInstance = AtomicReference<TootInstance>(null)
|
|
|
|
|
|
|
|
|
|
// DBには保存しない
|
|
|
|
|
var instance : TootInstance?
|
|
|
|
|
get() {
|
|
|
|
|
val instance = refInstance.get()
|
|
|
|
|
return when {
|
|
|
|
|
instance == null -> null
|
|
|
|
|
System.currentTimeMillis() - instance.time_parse > INSTANCE_INFORMATION_EXPIRE -> null
|
|
|
|
|
else -> instance
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
set(instance) = refInstance.set(instance)
|
|
|
|
|
|
2018-01-10 16:47:35 +01:00
|
|
|
|
init {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val pos = acct.indexOf('@')
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(pos == - 1) {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
this.username = acct
|
2018-01-10 16:47:35 +01:00
|
|
|
|
} else {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
this.username = acct.substring(0, pos)
|
|
|
|
|
}
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(username.isEmpty()) throw RuntimeException("missing username in acct")
|
2018-01-04 19:52:25 +01:00
|
|
|
|
|
2018-01-10 16:47:35 +01:00
|
|
|
|
this.host = if(hostArg != null && hostArg.isNotEmpty()) {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
hostArg
|
2018-01-10 16:47:35 +01:00
|
|
|
|
} else {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val hostInAcct = if(pos == - 1) "" else acct.substring(pos + 1)
|
|
|
|
|
if(hostInAcct.isEmpty()) throw RuntimeException("missing host in acct")
|
|
|
|
|
hostInAcct
|
|
|
|
|
}.toLowerCase()
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-10 16:47:35 +01:00
|
|
|
|
constructor(context : Context, cursor : Cursor) : this(
|
2018-01-04 19:52:25 +01:00
|
|
|
|
cursor.getLong(cursor.getColumnIndex(COL_ID)), // db_id
|
|
|
|
|
cursor.getString(cursor.getColumnIndex(COL_USER)), // acct
|
|
|
|
|
cursor.getString(cursor.getColumnIndex(COL_HOST)) // host
|
2018-01-10 16:47:35 +01:00
|
|
|
|
) {
|
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val jsonAccount = JSONObject(cursor.getString(cursor.getColumnIndex(COL_ACCOUNT)))
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
|
|
|
|
val loginAccount = TootAccount.parse(
|
|
|
|
|
context,
|
|
|
|
|
object : LinkClickContext {
|
|
|
|
|
override val host : String?
|
|
|
|
|
get() = this@SavedAccount.host
|
|
|
|
|
},
|
|
|
|
|
jsonAccount
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if( loginAccount == null ){
|
|
|
|
|
log.e("missing loginAccount for %s",cursor.getString(cursor.getColumnIndex(COL_ACCOUNT)))
|
|
|
|
|
}
|
|
|
|
|
this.loginAccount = loginAccount
|
|
|
|
|
|
|
|
|
|
val colIdx_visibility = cursor.getColumnIndex(COL_VISIBILITY)
|
|
|
|
|
this.visibility = if(cursor.isNull(colIdx_visibility)) null else cursor.getString(colIdx_visibility)
|
|
|
|
|
|
|
|
|
|
this.confirm_boost = cursor.getInt(cursor.getColumnIndex(COL_CONFIRM_BOOST)).i2b()
|
|
|
|
|
this.dont_hide_nsfw = cursor.getInt(cursor.getColumnIndex(COL_DONT_HIDE_NSFW)).i2b()
|
|
|
|
|
this.dont_show_timeout = cursor.getInt(cursor.getColumnIndex(COL_DONT_SHOW_TIMEOUT)).i2b()
|
|
|
|
|
|
|
|
|
|
this.notification_mention = cursor.getInt(cursor.getColumnIndex(COL_NOTIFICATION_MENTION)).i2b()
|
|
|
|
|
this.notification_boost = cursor.getInt(cursor.getColumnIndex(COL_NOTIFICATION_BOOST)).i2b()
|
|
|
|
|
this.notification_favourite = cursor.getInt(cursor.getColumnIndex(COL_NOTIFICATION_FAVOURITE)).i2b()
|
|
|
|
|
this.notification_follow = cursor.getInt(cursor.getColumnIndex(COL_NOTIFICATION_FOLLOW)).i2b()
|
|
|
|
|
|
|
|
|
|
this.confirm_follow = cursor.getInt(cursor.getColumnIndex(COL_CONFIRM_FOLLOW)).i2b()
|
|
|
|
|
this.confirm_follow_locked = cursor.getInt(cursor.getColumnIndex(COL_CONFIRM_FOLLOW_LOCKED)).i2b()
|
|
|
|
|
this.confirm_unfollow = cursor.getInt(cursor.getColumnIndex(COL_CONFIRM_UNFOLLOW)).i2b()
|
|
|
|
|
this.confirm_post = cursor.getInt(cursor.getColumnIndex(COL_CONFIRM_POST)).i2b()
|
|
|
|
|
|
|
|
|
|
val idx_notification_tag = cursor.getColumnIndex(COL_NOTIFICATION_TAG)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
this.notification_tag = if(cursor.isNull(idx_notification_tag)) null else cursor.getString(idx_notification_tag)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
|
|
|
|
val idx_register_key = cursor.getColumnIndex(COL_REGISTER_KEY)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
this.register_key = if(cursor.isNull(idx_register_key)) null else cursor.getString(idx_register_key)
|
|
|
|
|
|
|
|
|
|
this.register_time = cursor.getLong(cursor.getColumnIndex(COL_REGISTER_TIME))
|
|
|
|
|
|
|
|
|
|
this.token_info = JSONObject(cursor.getString(cursor.getColumnIndex(COL_TOKEN)))
|
|
|
|
|
|
|
|
|
|
this.sound_uri = cursor.getString(cursor.getColumnIndex(COL_SOUND_URI))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val isNA : Boolean
|
|
|
|
|
get() = "?@?" == acct
|
|
|
|
|
|
|
|
|
|
val isPseudo : Boolean
|
|
|
|
|
get() = username == "?"
|
|
|
|
|
|
|
|
|
|
fun delete() {
|
|
|
|
|
try {
|
|
|
|
|
App1.database.delete(table, COL_ID + "=?", arrayOf(db_id.toString()))
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
throw RuntimeException("SavedAccount.delete failed.", ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun updateTokenInfo(tokenInfoArg : JSONObject?) {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(db_id == INVALID_DB_ID) throw RuntimeException("updateTokenInfo: missing db_id")
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val token_info = tokenInfoArg ?: JSONObject()
|
|
|
|
|
this.token_info = token_info
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_TOKEN, token_info.toString())
|
|
|
|
|
App1.database.update(table, cv, COL_ID + "=?", arrayOf(db_id.toString()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun saveSetting() {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(db_id == INVALID_DB_ID) throw RuntimeException("saveSetting: missing db_id")
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_VISIBILITY, visibility)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
cv.put(COL_CONFIRM_BOOST, confirm_boost.b2i())
|
|
|
|
|
cv.put(COL_DONT_HIDE_NSFW, dont_hide_nsfw.b2i())
|
|
|
|
|
cv.put(COL_DONT_SHOW_TIMEOUT, dont_show_timeout.b2i())
|
|
|
|
|
cv.put(COL_NOTIFICATION_MENTION, notification_mention.b2i())
|
|
|
|
|
cv.put(COL_NOTIFICATION_BOOST, notification_boost.b2i())
|
|
|
|
|
cv.put(COL_NOTIFICATION_FAVOURITE, notification_favourite.b2i())
|
|
|
|
|
cv.put(COL_NOTIFICATION_FOLLOW, notification_follow.b2i())
|
|
|
|
|
|
|
|
|
|
cv.put(COL_CONFIRM_FOLLOW, confirm_follow.b2i())
|
|
|
|
|
cv.put(COL_CONFIRM_FOLLOW_LOCKED, confirm_follow_locked.b2i())
|
|
|
|
|
cv.put(COL_CONFIRM_UNFOLLOW, confirm_unfollow.b2i())
|
|
|
|
|
cv.put(COL_CONFIRM_POST, confirm_post.b2i())
|
2018-01-04 19:52:25 +01:00
|
|
|
|
|
|
|
|
|
cv.put(COL_SOUND_URI, sound_uri)
|
|
|
|
|
|
|
|
|
|
// UIからは更新しない
|
|
|
|
|
// notification_tag
|
|
|
|
|
// register_key
|
|
|
|
|
|
|
|
|
|
App1.database.update(table, cv, COL_ID + "=?", arrayOf(db_id.toString()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun saveNotificationTag() {
|
|
|
|
|
if(db_id == INVALID_DB_ID)
|
|
|
|
|
throw RuntimeException("SavedAccount.saveNotificationTag missing db_id")
|
|
|
|
|
|
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_NOTIFICATION_TAG, notification_tag)
|
|
|
|
|
|
|
|
|
|
App1.database.update(table, cv, COL_ID + "=?", arrayOf(db_id.toString()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun saveRegisterKey() {
|
|
|
|
|
if(db_id == INVALID_DB_ID)
|
|
|
|
|
throw RuntimeException("SavedAccount.saveRegisterKey missing db_id")
|
|
|
|
|
|
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_REGISTER_KEY, register_key)
|
|
|
|
|
cv.put(COL_REGISTER_TIME, register_time)
|
|
|
|
|
|
|
|
|
|
App1.database.update(table, cv, COL_ID + "=?", arrayOf(db_id.toString()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// onResumeの時に設定を読み直す
|
|
|
|
|
fun reloadSetting(context : Context) {
|
|
|
|
|
if(db_id == INVALID_DB_ID)
|
|
|
|
|
throw RuntimeException("SavedAccount.reloadSetting missing db_id")
|
|
|
|
|
val b = loadAccount(context, db_id) ?: return
|
|
|
|
|
// DBから削除されてる?
|
|
|
|
|
this.visibility = b.visibility
|
|
|
|
|
this.confirm_boost = b.confirm_boost
|
|
|
|
|
this.dont_hide_nsfw = b.dont_hide_nsfw
|
|
|
|
|
this.dont_show_timeout = b.dont_show_timeout
|
|
|
|
|
this.token_info = b.token_info
|
|
|
|
|
this.notification_mention = b.notification_follow
|
|
|
|
|
this.notification_boost = b.notification_boost
|
|
|
|
|
this.notification_favourite = b.notification_favourite
|
|
|
|
|
this.notification_follow = b.notification_follow
|
|
|
|
|
this.notification_tag = b.notification_tag
|
|
|
|
|
|
|
|
|
|
this.sound_uri = b.sound_uri
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun getFullAcct(acct : String?) : String {
|
|
|
|
|
return when {
|
|
|
|
|
acct == null -> "?@?"
|
|
|
|
|
acct.indexOf('@') == - 1 -> acct + "@" + this.host
|
|
|
|
|
else -> acct
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun getFullAcct(who : TootAccount?) : String {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
return getFullAcct(who?.acct)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun isLocalUser(acct : String?) : Boolean {
|
|
|
|
|
acct ?: return false
|
|
|
|
|
val pos = acct.indexOf('@')
|
|
|
|
|
return pos == - 1 || host.equals(acct.substring(pos + 1), ignoreCase = true)
|
|
|
|
|
}
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
fun isLocalUser(who : TootAccount?) : Boolean {
|
|
|
|
|
return isLocalUser(who?.acct)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isRemoteUser(who : TootAccount) : Boolean {
|
|
|
|
|
return ! isLocalUser(who)
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-10 16:47:35 +01:00
|
|
|
|
// fun isRemoteUser(acct : String) : Boolean {
|
|
|
|
|
// return ! isLocalUser(acct)
|
|
|
|
|
// }
|
2018-01-04 19:52:25 +01:00
|
|
|
|
|
|
|
|
|
fun getUserUrl(who_acct : String) : String {
|
|
|
|
|
val p = who_acct.indexOf('@')
|
|
|
|
|
return if(- 1 != p) {
|
|
|
|
|
"https://" + who_acct.substring(p + 1) + "/@" + who_acct.substring(0, p)
|
|
|
|
|
} else {
|
|
|
|
|
"https://$host/@$who_acct"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isMe(who : TootAccount?) : Boolean {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(who == null || who.username != this.username) return false
|
2018-01-04 19:52:25 +01:00
|
|
|
|
//
|
|
|
|
|
val who_acct = who.acct
|
|
|
|
|
val pos = who_acct.indexOf('@')
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(pos == - 1) return true // local user have no acct
|
|
|
|
|
return who_acct.substring(pos + 1).equals(this.host, ignoreCase = true)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isMe(who_acct : String) : Boolean {
|
|
|
|
|
// 自分のユーザ名部分
|
|
|
|
|
var pos = this.acct.indexOf('@')
|
|
|
|
|
val me_user = this.acct.substring(0, pos)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
//
|
|
|
|
|
pos = who_acct.indexOf('@')
|
|
|
|
|
// ローカルユーザは@以降を持たない
|
|
|
|
|
if(pos == - 1) return who_acct == me_user
|
|
|
|
|
// リモートユーザならホスト名部分の比較も必要
|
|
|
|
|
val who_user = who_acct.substring(0, pos)
|
|
|
|
|
val who_host = who_acct.substring(pos + 1)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
return who_user == me_user && who_host.equals(this.host, ignoreCase = true)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun supplyBaseUrl(url : String?) : String? {
|
|
|
|
|
return when {
|
|
|
|
|
url == null || url.isEmpty() -> return null
|
|
|
|
|
url[0] == '/' -> "https://" + host + url
|
|
|
|
|
else -> url
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isNicoru(account : TootAccount?) : Boolean {
|
|
|
|
|
var host = this.host
|
|
|
|
|
var host_start = 0
|
|
|
|
|
val acct = account?.acct
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(acct != null) {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
val pos = acct.indexOf('@')
|
|
|
|
|
if(pos != - 1) {
|
|
|
|
|
host = account.acct
|
|
|
|
|
host_start = pos + 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return host_match(strNicoruHost, 0, host, host_start)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// implements LinkClickContext
|
|
|
|
|
override fun findAcctColor(url : String?) : AcctColor? {
|
|
|
|
|
if(url != null) {
|
|
|
|
|
val m = TootAccount.reAccountUrl.matcher(url)
|
|
|
|
|
if(m.find()) return AcctColor.load(m.group(2) + "@" + m.group(1))
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
private val log = LogCategory("SavedAccount")
|
|
|
|
|
|
|
|
|
|
const val table = "access_info"
|
|
|
|
|
private const val strNicoruHost = "friends.nico"
|
|
|
|
|
private val reAtNicoruHost = Pattern.compile("@friends\\.nico\\z", Pattern.CASE_INSENSITIVE)
|
|
|
|
|
|
|
|
|
|
private const val COL_ID = BaseColumns._ID
|
|
|
|
|
private const val COL_HOST = "h"
|
|
|
|
|
private const val COL_USER = "u"
|
|
|
|
|
private const val COL_ACCOUNT = "a"
|
|
|
|
|
private const val COL_TOKEN = "t"
|
|
|
|
|
|
|
|
|
|
private const val COL_VISIBILITY = "visibility"
|
|
|
|
|
private const val COL_CONFIRM_BOOST = "confirm_boost"
|
|
|
|
|
private const val COL_DONT_HIDE_NSFW = "dont_hide_nsfw"
|
|
|
|
|
// スキーマ2から
|
|
|
|
|
private const val COL_NOTIFICATION_MENTION = "notification_mention"
|
|
|
|
|
private const val COL_NOTIFICATION_BOOST = "notification_boost"
|
|
|
|
|
private const val COL_NOTIFICATION_FAVOURITE = "notification_favourite"
|
|
|
|
|
private const val COL_NOTIFICATION_FOLLOW = "notification_follow"
|
|
|
|
|
// スキーマ10から
|
|
|
|
|
private const val COL_CONFIRM_FOLLOW = "confirm_follow"
|
|
|
|
|
private const val COL_CONFIRM_FOLLOW_LOCKED = "confirm_follow_locked"
|
|
|
|
|
private const val COL_CONFIRM_UNFOLLOW = "confirm_unfollow"
|
|
|
|
|
private const val COL_CONFIRM_POST = "confirm_post"
|
|
|
|
|
|
|
|
|
|
// スキーマ13から
|
|
|
|
|
const val COL_NOTIFICATION_TAG = "notification_server"
|
|
|
|
|
|
|
|
|
|
// スキーマ14から
|
|
|
|
|
const val COL_REGISTER_KEY = "register_key"
|
|
|
|
|
const val COL_REGISTER_TIME = "register_time"
|
|
|
|
|
|
|
|
|
|
// スキーマ16から
|
|
|
|
|
private const val COL_SOUND_URI = "sound_uri"
|
|
|
|
|
|
|
|
|
|
// スキーマ18から
|
|
|
|
|
private const val COL_DONT_SHOW_TIMEOUT = "dont_show_timeout"
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////
|
|
|
|
|
// login information
|
|
|
|
|
const val INVALID_DB_ID = - 1L
|
|
|
|
|
private const val INSTANCE_INFORMATION_EXPIRE = 60000L * 5
|
|
|
|
|
|
|
|
|
|
// アプリデータのインポート時に呼ばれる
|
|
|
|
|
fun onDBDelete(db : SQLiteDatabase) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("drop table if exists " + table)
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onDBCreate(db : SQLiteDatabase) {
|
|
|
|
|
db.execSQL(
|
|
|
|
|
"create table if not exists " + table
|
|
|
|
|
+ "(_id INTEGER PRIMARY KEY"
|
|
|
|
|
+ ",u text not null"
|
|
|
|
|
+ ",h text not null"
|
|
|
|
|
+ ",a text not null"
|
|
|
|
|
+ ",t text not null"
|
|
|
|
|
+ ",visibility text"
|
|
|
|
|
+ ",confirm_boost integer default 1"
|
|
|
|
|
+ ",dont_hide_nsfw integer default 0"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ2で追加
|
|
|
|
|
+ ",notification_mention integer default 1"
|
|
|
|
|
+ ",notification_boost integer default 1"
|
|
|
|
|
+ ",notification_favourite integer default 1"
|
|
|
|
|
+ ",notification_follow integer default 1"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ10で更新
|
|
|
|
|
+ "," + COL_CONFIRM_FOLLOW + " integer default 1"
|
|
|
|
|
+ "," + COL_CONFIRM_FOLLOW_LOCKED + " integer default 1"
|
|
|
|
|
+ "," + COL_CONFIRM_UNFOLLOW + " integer default 1"
|
|
|
|
|
+ "," + COL_CONFIRM_POST + " integer default 1"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ13で更新
|
|
|
|
|
+ "," + COL_NOTIFICATION_TAG + " text default ''"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ14で更新
|
|
|
|
|
+ "," + COL_REGISTER_KEY + " text default ''"
|
|
|
|
|
+ "," + COL_REGISTER_TIME + " integer default 0"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ16で更新
|
|
|
|
|
+ "," + COL_SOUND_URI + " text default ''"
|
|
|
|
|
|
|
|
|
|
// 以下はDBスキーマ18で更新
|
|
|
|
|
+ "," + COL_DONT_SHOW_TIMEOUT + " integer default 0"
|
|
|
|
|
|
|
|
|
|
+ ")"
|
|
|
|
|
)
|
|
|
|
|
db.execSQL("create index if not exists " + table + "_user on " + table + "(u)")
|
|
|
|
|
db.execSQL("create index if not exists " + table + "_host on " + table + "(h,u)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onDBUpgrade(db : SQLiteDatabase, oldVersion : Int, newVersion : Int) {
|
|
|
|
|
if(oldVersion < 2 && newVersion >= 2) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column notification_mention integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column notification_boost integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column notification_favourite integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column notification_follow integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(oldVersion < 10 && newVersion >= 10) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_CONFIRM_FOLLOW integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_CONFIRM_FOLLOW_LOCKED integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_CONFIRM_UNFOLLOW integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_CONFIRM_POST integer default 1")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(oldVersion < 13 && newVersion >= 13) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_NOTIFICATION_TAG text default ''")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(oldVersion < 14 && newVersion >= 14) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_REGISTER_KEY text default ''")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_REGISTER_TIME integer default 0")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(oldVersion < 16 && newVersion >= 16) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_SOUND_URI text default ''")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if(oldVersion < 18 && newVersion >= 18) {
|
|
|
|
|
try {
|
|
|
|
|
db.execSQL("alter table $table add column $COL_DONT_SHOW_TIMEOUT integer default 0")
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 横断検索用の、何とも紐ついていないアカウント
|
|
|
|
|
// 保存しない。
|
|
|
|
|
val na : SavedAccount by lazy {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
val dst = SavedAccount(- 1L, "?@?")
|
2018-01-04 19:52:25 +01:00
|
|
|
|
dst.notification_follow = false
|
|
|
|
|
dst.notification_favourite = false
|
|
|
|
|
dst.notification_boost = false
|
|
|
|
|
dst.notification_mention = false
|
|
|
|
|
|
|
|
|
|
dst
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun parse(context : Context, cursor : Cursor) : SavedAccount? {
|
|
|
|
|
return try {
|
|
|
|
|
SavedAccount(context, cursor)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
} catch(ex : Throwable) {
|
2018-01-04 19:52:25 +01:00
|
|
|
|
log.trace(ex)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
log.e(ex, "parse failed.")
|
2018-01-04 19:52:25 +01:00
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun insert(
|
|
|
|
|
host : String,
|
|
|
|
|
acct : String,
|
|
|
|
|
account : JSONObject,
|
|
|
|
|
token : JSONObject
|
|
|
|
|
) : Long {
|
|
|
|
|
try {
|
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_HOST, host)
|
|
|
|
|
cv.put(COL_USER, acct)
|
|
|
|
|
cv.put(COL_ACCOUNT, account.toString())
|
|
|
|
|
cv.put(COL_TOKEN, token.toString())
|
|
|
|
|
return App1.database.insert(table, null, cv)
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
throw RuntimeException("SavedAccount.insert failed.", ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val REGISTER_KEY_UNREGISTERED = "unregistered"
|
|
|
|
|
|
|
|
|
|
fun clearRegistrationCache() {
|
|
|
|
|
val cv = ContentValues()
|
|
|
|
|
cv.put(COL_REGISTER_KEY, REGISTER_KEY_UNREGISTERED)
|
|
|
|
|
cv.put(COL_REGISTER_TIME, 0L)
|
|
|
|
|
App1.database.update(table, cv, null, null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun loadAccount(context : Context, db_id : Long) : SavedAccount? {
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, null, COL_ID + "=?", arrayOf(db_id.toString()), null, null, null)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
.use { cursor ->
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(cursor.moveToFirst()) {
|
|
|
|
|
return parse(context, cursor)
|
|
|
|
|
}
|
2018-01-10 16:47:35 +01:00
|
|
|
|
log.e("moveToFirst failed. db_id=$db_id")
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "loadAccount failed.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun loadAccountList(context : Context) : ArrayList<SavedAccount> {
|
|
|
|
|
val result = ArrayList<SavedAccount>()
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, null, null, null, null, null, null)
|
|
|
|
|
.use { cursor ->
|
|
|
|
|
while(cursor.moveToNext()) {
|
|
|
|
|
val a = parse(context, cursor)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(a != null) result.add(a)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "loadAccountList failed.")
|
|
|
|
|
throw RuntimeException("SavedAccount.loadAccountList failed.", ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun loadByTag(context : Context, tag : String) : ArrayList<SavedAccount> {
|
|
|
|
|
val result = ArrayList<SavedAccount>()
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, null, COL_NOTIFICATION_TAG + "=?", arrayOf(tag), null, null, null)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
.use { cursor ->
|
2018-01-04 19:52:25 +01:00
|
|
|
|
while(cursor.moveToNext()) {
|
|
|
|
|
val a = parse(context, cursor)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
if(a != null) result.add(a)
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "loadByTag failed.")
|
|
|
|
|
throw RuntimeException("SavedAccount.loadByTag failed.", ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun loadAccountByAcct(context : Context, full_acct : String) : SavedAccount? {
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, null, COL_USER + "=?", arrayOf(full_acct), null, null, null)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
.use { cursor ->
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(cursor.moveToNext()) {
|
|
|
|
|
return parse(context, cursor)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "loadAccountByAcct failed.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun hasRealAccount() : Boolean {
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, null, COL_USER + " NOT LIKE '?@%'", null, null, null, null, "1")
|
2018-01-10 16:47:35 +01:00
|
|
|
|
.use { cursor ->
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(cursor.moveToNext()) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "hasNonPseudoAccount failed.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val count : Long
|
|
|
|
|
get() {
|
|
|
|
|
try {
|
|
|
|
|
App1.database.query(table, arrayOf("count(*)"), null, null, null, null, null)
|
2018-01-10 16:47:35 +01:00
|
|
|
|
.use { cursor ->
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(cursor.moveToNext()) {
|
|
|
|
|
return cursor.getLong(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch(ex : Throwable) {
|
|
|
|
|
log.trace(ex)
|
|
|
|
|
log.e(ex, "getCount failed.")
|
|
|
|
|
throw RuntimeException("SavedAccount.getCount failed.", ex)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0L
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isNicoru(acct : String?) : Boolean {
|
|
|
|
|
return acct != null && reAtNicoruHost.matcher(acct).find()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun charAtLower(src : CharSequence, pos : Int) : Char {
|
|
|
|
|
val c = src[pos]
|
|
|
|
|
return if(c >= 'a' && c <= 'z') c - ('a' - 'A') else c
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun host_match(a : CharSequence, a_startArg : Int, b : CharSequence, b_startArg : Int) : Boolean {
|
|
|
|
|
var a_start = a_startArg
|
|
|
|
|
var b_start = b_startArg
|
|
|
|
|
|
|
|
|
|
val a_end = a.length
|
|
|
|
|
val b_end = b.length
|
|
|
|
|
|
|
|
|
|
var a_remain = a_end - a_start
|
|
|
|
|
val b_remain = b_end - b_start
|
|
|
|
|
|
|
|
|
|
// 文字数が違う
|
|
|
|
|
if(a_remain != b_remain) return false
|
|
|
|
|
|
|
|
|
|
// 文字数がゼロ
|
|
|
|
|
if(a_remain <= 0) return true
|
|
|
|
|
|
|
|
|
|
// 末尾の文字が違う
|
|
|
|
|
if(charAtLower(a, a_end - 1) != charAtLower(b, b_end - 1)) return false
|
|
|
|
|
|
|
|
|
|
// 先頭からチェック
|
|
|
|
|
while(a_remain -- > 0) {
|
|
|
|
|
if(charAtLower(a, a_start ++) != charAtLower(b, b_start ++)) return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val account_comparator = Comparator<SavedAccount> { a, b ->
|
|
|
|
|
var i : Int
|
|
|
|
|
|
|
|
|
|
// NA > !NA
|
2018-01-10 16:47:35 +01:00
|
|
|
|
i = a.isNA.b2i() - b.isNA.b2i()
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(i != 0) return@Comparator i
|
|
|
|
|
|
|
|
|
|
// pseudo > real
|
2018-01-10 16:47:35 +01:00
|
|
|
|
i = a.isPseudo.b2i() - b.isPseudo.b2i()
|
2018-01-04 19:52:25 +01:00
|
|
|
|
if(i != 0) return@Comparator i
|
|
|
|
|
|
|
|
|
|
val sa = AcctColor.getNickname(a.acct)
|
|
|
|
|
val sb = AcctColor.getNickname(b.acct)
|
|
|
|
|
sa.compareTo(sb, ignoreCase = true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun sort(account_list : ArrayList<SavedAccount>) {
|
|
|
|
|
Collections.sort(account_list, account_comparator)
|
|
|
|
|
}
|
2018-01-10 16:47:35 +01:00
|
|
|
|
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun getAccessToken() : String? {
|
2018-01-10 16:47:35 +01:00
|
|
|
|
return token_info?.let { Utils.optStringX(it, "access_token") }
|
2018-01-04 19:52:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|