more clean up

This commit is contained in:
tateisu 2021-06-28 06:55:52 +09:00
parent e94389c4d2
commit 8bcc0531f2
12 changed files with 337 additions and 494 deletions

View File

@ -166,9 +166,7 @@ class ActAppSetting : AppCompatActivity(), ColorPickerDialogListener, View.OnCli
})
}
findViewById<View>(R.id.btnSearchReset).apply {
setOnClickListener(this@ActAppSetting)
}
findViewById<View>(R.id.btnSearchReset).setOnClickListener(this@ActAppSetting)
}
private fun removeDefaultPref() {

View File

@ -106,8 +106,8 @@ class ActMutedPseudoAccount : AppCompatActivity() {
val tmpList = ArrayList<MyItem>()
try {
UserRelation.createCursorPseudo().use { cursor ->
val idxId = cursor.getColumnIndex(UserRelation.COL_ID)
val idxName = cursor.getColumnIndex(UserRelation.COL_WHO_ID)
val idxId = UserRelation.COL_ID.getIndex(cursor)
val idxName = UserRelation.COL_WHO_ID.getIndex(cursor)
while (cursor.moveToNext()) {
val id = cursor.getLong(idxId)
val name = cursor.getString(idxName)

View File

@ -16,7 +16,7 @@ import jp.juggler.util.loadRawResource
private val log = LogCategory("ActPostMushroom")
fun ActPost.resetMushroom(){
fun ActPost.resetMushroom() {
states.mushroomInput = 0
states.mushroomStart = 0
states.mushroomEnd = 0

View File

@ -18,7 +18,7 @@ import jp.juggler.util.showToast
private val log = LogCategory("ActPostReply")
fun ActPost.resetReply(){
fun ActPost.resetReply() {
states.inReplyToId = null
states.inReplyToText = null
states.inReplyToImage = null

View File

@ -105,7 +105,7 @@ class UpdateRelationEnv(val column: Column) {
for (i in 0 until list.size) {
list[i].id = userIdList[i]
}
UserRelation.saveList2(now, column.accessInfo.db_id, list)
UserRelation.saveListMisskeyRelationApi(now, column.accessInfo.db_id, list)
}
}
Column.log.d("updateRelation: update $n relations.")

View File

@ -2,106 +2,41 @@ package jp.juggler.subwaytooter.table
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.provider.BaseColumns
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.util.LogCategory
import jp.juggler.util.TableCompanion
import jp.juggler.util.b2i
import jp.juggler.util.getInt
import jp.juggler.util.*
object ContentWarning : TableCompanion {
private val log = LogCategory("ContentWarning")
private const val table = "content_warning"
private const val COL_STATUS_URI = "su"
private const val COL_SHOWN = "sh"
private const val COL_TIME_SAVE = "time_save"
private val projection_shown = arrayOf(COL_SHOWN)
override fun onDBCreate(db: SQLiteDatabase) {
log.d("onDBCreate!")
db.execSQL(
"""
create table if not exists $table
(_id INTEGER PRIMARY KEY
,$COL_STATUS_URI text not null
,$COL_SHOWN integer not null
,$COL_TIME_SAVE integer default 0
)
""".trimIndent()
)
db.execSQL(
"create unique index if not exists ${table}_status_uri on $table($COL_STATUS_URI)"
)
db.execSQL(
"create index if not exists ${table}_time_save on $table($COL_TIME_SAVE)"
)
val columnList: ColumnMeta.List = ColumnMeta.List(table, 0).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
deleteBeforeCreate = true
createExtra = {
arrayOf(
"create unique index if not exists ${table}_status_uri on $table($COL_STATUS_URI)",
"create index if not exists ${table}_time_save on $table($COL_TIME_SAVE)",
)
}
}
private val COL_STATUS_URI = ColumnMeta(columnList, 0, "su", "text not null")
private val COL_SHOWN = ColumnMeta(columnList, 0, "sh", "integer not null")
private val COL_TIME_SAVE = ColumnMeta(columnList, 0, "time_save", "integer default 0")
private val projection_shown = arrayOf(COL_SHOWN.name)
override fun onDBCreate(db: SQLiteDatabase) =
columnList.onDBCreate(db)
override fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
// 特定バージョンと交差したらテーブルを削除して作り直す
fun intersect(x: Int) = (oldVersion < x && newVersion >= x)
if (intersect(36) || intersect(31) || intersect(5)) {
db.execSQL("drop table if exists $table")
onDBCreate(db)
}
}
fun isShown(uri: String, defaultValue: Boolean): Boolean {
try {
App1.database.query(
table,
projection_shown,
"$COL_STATUS_URI=?",
arrayOf(uri),
null,
null,
null
).use { cursor ->
if (cursor.moveToFirst()) {
return 0 != cursor.getInt(COL_SHOWN)
}
}
} catch (ex: Throwable) {
log.e(ex, "load failed.")
}
return defaultValue
}
fun isShown(status: TootStatus, defaultValue: Boolean): Boolean {
return isShown(status.uri, defaultValue)
}
fun save(uri: String, isShown: Boolean) {
try {
val now = System.currentTimeMillis()
val cv = ContentValues()
cv.put(COL_STATUS_URI, uri)
cv.put(COL_SHOWN, isShown.b2i())
cv.put(COL_TIME_SAVE, now)
App1.database.replace(table, null, cv)
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
}
fun save(status: TootStatus, isShown: Boolean) {
try {
val now = System.currentTimeMillis()
val cv = ContentValues()
cv.put(COL_STATUS_URI, status.uri)
cv.put(COL_SHOWN, isShown.b2i())
cv.put(COL_TIME_SAVE, now)
App1.database.replace(table, null, cv)
} catch (ex: Throwable) {
log.e(ex, "save failed.")
columnList.onDBCreate(db)
}
}
@ -114,4 +49,50 @@ object ContentWarning : TableCompanion {
log.e(ex, "deleteOld failed.")
}
}
private fun saveImpl(uri: String, isShown: Boolean) {
try {
ContentValues().apply {
put(COL_STATUS_URI, uri)
put(COL_SHOWN, isShown)
put(COL_TIME_SAVE, System.currentTimeMillis())
}.let { App1.database.replace(table, null, it) }
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
}
private fun isShownImpl(uri: String, defaultValue: Boolean): Boolean {
try {
App1.database.query(
table,
projection_shown,
"$COL_STATUS_URI=?",
arrayOf(uri),
null,
null,
null
).use { cursor ->
if (cursor.moveToFirst()) {
return cursor.getBoolean(COL_SHOWN)
}
}
} catch (ex: Throwable) {
log.e(ex, "load failed.")
}
return defaultValue
}
fun save(uri: String, isShown: Boolean) =
saveImpl(uri, isShown)
fun isShown(uri: String, defaultValue: Boolean) =
isShownImpl(uri, defaultValue)
fun save(status: TootStatus, isShown: Boolean) =
saveImpl(status.uri, isShown)
fun isShown(status: TootStatus, defaultValue: Boolean) =
isShownImpl(status.uri, defaultValue)
}

View File

@ -2,46 +2,42 @@ package jp.juggler.subwaytooter.table
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.provider.BaseColumns
import jp.juggler.subwaytooter.App1
import jp.juggler.subwaytooter.api.entity.TootStatus
import jp.juggler.util.LogCategory
import jp.juggler.util.TableCompanion
import jp.juggler.util.b2i
import jp.juggler.util.getInt
import jp.juggler.util.*
object MediaShown : TableCompanion {
private val log = LogCategory("MediaShown")
private const val table = "media_shown_misskey"
private const val COL_HOST = "h"
private const val COL_STATUS_ID = "si"
private const val COL_SHOWN = "sh"
private const val COL_TIME_SAVE = "time_save"
private val projection_shown = arrayOf(COL_SHOWN)
override fun onDBCreate(db: SQLiteDatabase) {
log.d("onDBCreate!")
db.execSQL(
"""
create table if not exists $table
(_id INTEGER PRIMARY KEY
,$COL_HOST text not null
,$COL_STATUS_ID text not null
,$COL_SHOWN integer not null
,$COL_TIME_SAVE integer default 0
)
""".trimIndent()
)
db.execSQL(
"create unique index if not exists ${table}_status_id on $table($COL_HOST,$COL_STATUS_ID)"
)
val columnList: ColumnMeta.List = ColumnMeta.List(table, 30).apply {
ColumnMeta(this, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
deleteBeforeCreate = true
createExtra = {
arrayOf(
"create unique index if not exists ${table}_status_id on $table($COL_HOST,$COL_STATUS_ID)",
"create index if not exists ${table}_time_save on $table($COL_TIME_SAVE)",
)
}
}
private val COL_HOST = ColumnMeta(columnList, 0, "h", "")
private val COL_STATUS_ID = ColumnMeta(columnList, 0, "si", "")
private val COL_SHOWN = ColumnMeta(columnList, 0, "sh", "")
private val COL_TIME_SAVE = ColumnMeta(columnList, 0, "time_save", "")
private val projection_shown = arrayOf(COL_SHOWN.name)
override fun onDBCreate(db: SQLiteDatabase) =
columnList.onDBCreate(db)
override fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
columnList.onDBUpgrade(db, oldVersion, newVersion)
// 特定バージョンを交差したらテーブルを作り直す
if (oldVersion < 30 && newVersion >= 30) {
db.execSQL("drop table if exists $table")
onDBCreate(db)
columnList.onDBCreate(db)
}
}
@ -63,75 +59,47 @@ object MediaShown : TableCompanion {
}
}
fun isShown(uri: String, defaultValue: Boolean): Boolean {
private fun saveImpl(host: String, id: String, isShown: Boolean) {
try {
ContentValues().apply {
put(COL_HOST, host)
put(COL_STATUS_ID, id)
put(COL_SHOWN, isShown)
put(COL_TIME_SAVE, System.currentTimeMillis())
}.let { App1.database.replace(table, null, it) }
} catch (ex: Throwable) {
log.e(ex, "saveImpl failed.")
}
}
private fun isShownImpl(host: String, id: String, defaultValue: Boolean): Boolean {
try {
App1.database.query(
table,
projection_shown,
"h=? and si=?",
arrayOf(uri, uri),
arrayOf(host, id),
null,
null,
null
).use { cursor ->
if (cursor.moveToFirst()) {
return 0 != cursor.getInt(COL_SHOWN)
}
if (cursor.moveToFirst()) return cursor.getBoolean(COL_SHOWN)
}
} catch (ex: Throwable) {
log.e(ex, "load failed.")
log.e(ex, "isShownImpl failed.")
}
return defaultValue
}
fun isShown(status: TootStatus, defaultValue: Boolean): Boolean {
try {
App1.database.query(
table,
projection_shown,
"h=? and si=?",
arrayOf(status.hostAccessOrOriginal.ascii, status.id.toString()),
null,
null,
null
).use { cursor ->
if (cursor.moveToFirst()) {
return 0 != cursor.getInt(COL_SHOWN)
}
}
} catch (ex: Throwable) {
log.e(ex, "load failed.")
}
fun save(uri: String, isShown: Boolean) =
saveImpl(uri, uri, isShown)
return defaultValue
}
fun isShown(uri: String, defaultValue: Boolean) =
isShownImpl(uri, uri, defaultValue)
fun save(uri: String, isShown: Boolean) {
try {
val now = System.currentTimeMillis()
val cv = ContentValues()
cv.put(COL_HOST, uri)
cv.put(COL_STATUS_ID, uri)
cv.put(COL_SHOWN, isShown.b2i())
cv.put(COL_TIME_SAVE, now)
App1.database.replace(table, null, cv)
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
}
fun save(status: TootStatus, isShown: Boolean) =
saveImpl(status.hostAccessOrOriginal.ascii, status.id.toString(), isShown)
fun save(status: TootStatus, isShown: Boolean) {
try {
val now = System.currentTimeMillis()
val cv = ContentValues()
cv.put(COL_HOST, status.hostAccessOrOriginal.ascii)
cv.put(COL_STATUS_ID, status.id.toString())
cv.put(COL_SHOWN, isShown.b2i())
cv.put(COL_TIME_SAVE, now)
App1.database.replace(table, null, cv)
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
}
fun isShown(status: TootStatus, defaultValue: Boolean) =
isShownImpl(status.hostAccessOrOriginal.ascii, status.id.toString(), defaultValue)
}

View File

@ -195,56 +195,55 @@ class SavedAccount(
val token_info = tokenInfoArg ?: JsonObject()
this.token_info = token_info
val cv = ContentValues()
COL_TOKEN.putTo(cv, token_info.toString())
App1.database.update(table, cv, "$COL_ID=?", arrayOf(db_id.toString()))
ContentValues().apply {
put(COL_TOKEN, token_info.toString())
}.let { App1.database.update(table, it, "$COL_ID=?", arrayOf(db_id.toString())) }
}
fun saveSetting() {
if (db_id == INVALID_DB_ID) error("saveSetting: missing db_id")
val cv = ContentValues()
COL_VISIBILITY.putTo(cv, visibility.id.toString())
COL_CONFIRM_BOOST.putTo(cv, confirm_boost.b2i())
COL_CONFIRM_FAVOURITE.putTo(cv, confirm_favourite.b2i())
COL_CONFIRM_UNBOOST.putTo(cv, confirm_unboost.b2i())
COL_CONFIRM_UNFAVOURITE.putTo(cv, confirm_unfavourite.b2i())
ContentValues().apply {
put(COL_VISIBILITY, visibility.id.toString())
put(COL_CONFIRM_BOOST, confirm_boost)
put(COL_CONFIRM_FAVOURITE, confirm_favourite)
put(COL_CONFIRM_UNBOOST, confirm_unboost)
put(COL_CONFIRM_UNFAVOURITE, confirm_unfavourite)
COL_DONT_HIDE_NSFW.putTo(cv, dont_hide_nsfw.b2i())
COL_DONT_SHOW_TIMEOUT.putTo(cv, dont_show_timeout.b2i())
COL_NOTIFICATION_MENTION.putTo(cv, notification_mention.b2i())
COL_NOTIFICATION_BOOST.putTo(cv, notification_boost.b2i())
COL_NOTIFICATION_FAVOURITE.putTo(cv, notification_favourite.b2i())
COL_NOTIFICATION_FOLLOW.putTo(cv, notification_follow.b2i())
COL_NOTIFICATION_FOLLOW_REQUEST.putTo(cv, notification_follow_request.b2i())
COL_NOTIFICATION_REACTION.putTo(cv, notification_reaction.b2i())
COL_NOTIFICATION_VOTE.putTo(cv, notification_vote.b2i())
COL_NOTIFICATION_POST.putTo(cv, notification_post.b2i())
put(COL_DONT_HIDE_NSFW, dont_hide_nsfw)
put(COL_DONT_SHOW_TIMEOUT, dont_show_timeout)
put(COL_NOTIFICATION_MENTION, notification_mention)
put(COL_NOTIFICATION_BOOST, notification_boost)
put(COL_NOTIFICATION_FAVOURITE, notification_favourite)
put(COL_NOTIFICATION_FOLLOW, notification_follow)
put(COL_NOTIFICATION_FOLLOW_REQUEST, notification_follow_request)
put(COL_NOTIFICATION_REACTION, notification_reaction)
put(COL_NOTIFICATION_VOTE, notification_vote)
put(COL_NOTIFICATION_POST, notification_post)
COL_CONFIRM_FOLLOW.putTo(cv, confirm_follow.b2i())
COL_CONFIRM_FOLLOW_LOCKED.putTo(cv, confirm_follow_locked.b2i())
COL_CONFIRM_UNFOLLOW.putTo(cv, confirm_unfollow.b2i())
COL_CONFIRM_POST.putTo(cv, confirm_post.b2i())
COL_CONFIRM_REACTION.putTo(cv, confirm_reaction.b2i())
put(COL_CONFIRM_FOLLOW, confirm_follow)
put(COL_CONFIRM_FOLLOW_LOCKED, confirm_follow_locked)
put(COL_CONFIRM_UNFOLLOW, confirm_unfollow)
put(COL_CONFIRM_POST, confirm_post)
put(COL_CONFIRM_REACTION, confirm_reaction)
COL_SOUND_URI.putTo(cv, sound_uri)
COL_DEFAULT_TEXT.putTo(cv, default_text)
put(COL_SOUND_URI, sound_uri)
put(COL_DEFAULT_TEXT, default_text)
COL_DEFAULT_SENSITIVE.putTo(cv, default_sensitive.b2i())
COL_EXPAND_CW.putTo(cv, expand_cw.b2i())
COL_MAX_TOOT_CHARS.putTo(cv, max_toot_chars)
put(COL_DEFAULT_SENSITIVE, default_sensitive)
put(COL_EXPAND_CW, expand_cw)
put(COL_MAX_TOOT_CHARS, max_toot_chars)
COL_IMAGE_RESIZE.putTo(cv, image_resize)
COL_IMAGE_MAX_MEGABYTES.putTo(cv, image_max_megabytes)
COL_MOVIE_MAX_MEGABYTES.putTo(cv, movie_max_megabytes)
COL_PUSH_POLICY.putTo(cv, push_policy)
put(COL_IMAGE_RESIZE, image_resize)
put(COL_IMAGE_MAX_MEGABYTES, image_max_megabytes)
put(COL_MOVIE_MAX_MEGABYTES, movie_max_megabytes)
put(COL_PUSH_POLICY, push_policy)
// UIからは更新しない
// notification_tag
// register_key
App1.database.update(table, cv, "$COL_ID=?", arrayOf(db_id.toString()))
// 以下のデータはUIからは更新しない
// notification_tag
// register_key
}.let { App1.database.update(table, it, "$COL_ID=?", arrayOf(db_id.toString())) }
}
// fun saveNotificationTag() {
@ -466,17 +465,16 @@ class SavedAccount(
// 横断検索用の、何とも紐ついていないアカウント
// 保存しない。
val na: SavedAccount by lazy {
val dst = SavedAccount(-1L, "?@?")
dst.notification_follow = false
dst.notification_follow_request = false
dst.notification_favourite = false
dst.notification_boost = false
dst.notification_mention = false
dst.notification_reaction = false
dst.notification_vote = false
dst.notification_post = false
dst
SavedAccount(-1L, "?@?").apply {
notification_follow = false
notification_follow_request = false
notification_favourite = false
notification_boost = false
notification_mention = false
notification_reaction = false
notification_vote = false
notification_post = false
}
}
private fun parse(context: Context, cursor: Cursor): SavedAccount? {
@ -498,14 +496,14 @@ class SavedAccount(
misskeyVersion: Int = 0,
): Long {
try {
val cv = ContentValues()
COL_USER.putTo(cv, acct)
COL_HOST.putTo(cv, host)
COL_DOMAIN.putTo(cv, domain)
COL_ACCOUNT.putTo(cv, account.toString())
COL_TOKEN.putTo(cv, token.toString())
COL_MISSKEY_VERSION.putTo(cv, misskeyVersion)
return App1.database.insert(table, null, cv)
return ContentValues().apply {
put(COL_USER, acct)
put(COL_HOST, host)
put(COL_DOMAIN, domain)
put(COL_ACCOUNT, account.toString())
put(COL_TOKEN, token.toString())
put(COL_MISSKEY_VERSION, misskeyVersion)
}.let { App1.database.insert(table, null, it) }
} catch (ex: Throwable) {
log.trace(ex)
errorEx(ex, "SavedAccount.insert failed.")
@ -515,10 +513,10 @@ class SavedAccount(
private const val REGISTER_KEY_UNREGISTERED = "unregistered"
fun clearRegistrationCache() {
val cv = ContentValues()
COL_REGISTER_KEY.putTo(cv, REGISTER_KEY_UNREGISTERED)
COL_REGISTER_TIME.putTo(cv, 0L)
App1.database.update(table, cv, null, null)
ContentValues().apply {
put(COL_REGISTER_KEY, REGISTER_KEY_UNREGISTERED)
put(COL_REGISTER_TIME, 0L)
}.let { App1.database.update(table, it, null, null) }
}
fun loadAccount(context: Context, dbId: Long): SavedAccount? {
@ -827,9 +825,9 @@ class SavedAccount(
val ta = TootParser(context, this).account(result.jsonObject)
if (ta != null) {
this.loginAccount = ta
val cv = ContentValues()
COL_ACCOUNT.putTo(cv, result.jsonObject.toString())
App1.database.update(table, cv, "$COL_ID=?", arrayOf(db_id.toString()))
ContentValues().apply {
put(COL_ACCOUNT, result.jsonObject.toString())
}.let { App1.database.update(table, it, "$COL_ID=?", arrayOf(db_id.toString())) }
PollingWorker.queueUpdateNotification(context)
}
}
@ -843,9 +841,9 @@ class SavedAccount(
private fun updateSingleString(col: ColumnMeta, value: String?) {
if (db_id != INVALID_DB_ID) {
val cv = ContentValues()
col.putTo(cv, value)
App1.database.update(table, cv, "$COL_ID=?", arrayOf(db_id.toString()))
ContentValues()
.apply { put(col, value) }
.let { App1.database.update(table, it, "$COL_ID=?", arrayOf(db_id.toString())) }
}
}

View File

@ -49,95 +49,44 @@ class UserRelation {
private val log = LogCategory("UserRelationMisskey")
private const val table = "user_relation_misskey"
const val COL_ID = BaseColumns._ID
private const val COL_TIME_SAVE = "time_save"
private const val COL_DB_ID = "db_id" // SavedAccount のDB_ID。 疑似アカウント用のエントリは -2L
const val COL_WHO_ID = "who_id" // ターゲットアカウントのID
private const val COL_FOLLOWING = "following"
private const val COL_FOLLOWED_BY = "followed_by"
private const val COL_BLOCKING = "blocking"
private const val COL_MUTING = "muting"
private const val COL_REQUESTED = "requested"
private const val COL_FOLLOWING_REBLOGS = "following_reblogs"
private const val COL_ENDORSED = "endorsed"
private const val COL_BLOCKED_BY = "blocked_by"
private const val COL_REQUESTED_BY = "requested_by"
private const val COL_NOTE = "note"
private const val COL_NOTIFYING = "notifying"
val columnList: ColumnMeta.List = ColumnMeta.List(table, 30).apply {
createExtra = {
arrayOf(
"create unique index if not exists ${table}_id on $table($COL_DB_ID,$COL_WHO_ID)",
"create index if not exists ${table}_time on $table($COL_TIME_SAVE)",
)
}
deleteBeforeCreate = true
}
val COL_ID = ColumnMeta(columnList, 0, BaseColumns._ID, "INTEGER PRIMARY KEY", primary = true)
private val COL_TIME_SAVE = ColumnMeta(columnList, 0, "time_save", "integer not null")
// SavedAccount のDB_ID。 疑似アカウント用のエントリは -2L
private val COL_DB_ID = ColumnMeta(columnList, 0, "db_id", "integer not null")
// ターゲットアカウントのID
val COL_WHO_ID = ColumnMeta(columnList, 0, "who_id", "text not null")
private val COL_FOLLOWING = ColumnMeta(columnList, 0, "following", "integer not null")
private val COL_FOLLOWED_BY = ColumnMeta(columnList, 0, "followed_by", "integer not null")
private val COL_BLOCKING = ColumnMeta(columnList, 0, "blocking", "integer not null")
private val COL_MUTING = ColumnMeta(columnList, 0, "muting", "integer not null")
private val COL_REQUESTED = ColumnMeta(columnList, 0, "requested", "integer not null")
private val COL_FOLLOWING_REBLOGS = ColumnMeta(columnList, 0, "following_reblogs", "integer not null")
private val COL_ENDORSED = ColumnMeta(columnList, 32, "endorsed", "integer default 0")
private val COL_BLOCKED_BY = ColumnMeta(columnList, 34, "blocked_by", "integer default 0")
private val COL_REQUESTED_BY = ColumnMeta(columnList, 35, "requested_by", "integer default 0")
private val COL_NOTE = ColumnMeta(columnList, 55, "note", "text default null")
private val COL_NOTIFYING = ColumnMeta(columnList, 58, "notifying", "integer default 0")
private const val DB_ID_PSEUDO = -2L
override fun onDBCreate(db: SQLiteDatabase) {
log.d("onDBCreate!")
db.execSQL(
"""
create table if not exists $table
($COL_ID INTEGER PRIMARY KEY
,$COL_TIME_SAVE integer not null
,$COL_DB_ID integer not null
,$COL_WHO_ID text not null
,$COL_FOLLOWING integer not null
,$COL_FOLLOWED_BY integer not null
,$COL_BLOCKING integer not null
,$COL_MUTING integer not null
,$COL_REQUESTED integer not null
,$COL_FOLLOWING_REBLOGS integer not null
,$COL_ENDORSED integer default 0
,$COL_BLOCKED_BY integer default 0
,$COL_REQUESTED_BY integer default 0
,$COL_NOTE text default null
,$COL_NOTIFYING integer default 0
)"""
)
db.execSQL(
"create unique index if not exists ${table}_id on $table ($COL_DB_ID,$COL_WHO_ID)"
)
db.execSQL(
"create index if not exists ${table}_time on $table ($COL_TIME_SAVE)"
)
}
override fun onDBCreate(db: SQLiteDatabase) =
columnList.onDBCreate(db)
override fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion < 30 && newVersion >= 30) {
db.execSQL("drop table if exists $table")
onDBCreate(db)
}
if (oldVersion < 32 && newVersion >= 32) {
try {
db.execSQL("alter table $table add column $COL_ENDORSED integer default 0")
} catch (ex: Throwable) {
log.trace(ex)
}
}
if (oldVersion < 34 && newVersion >= 34) {
try {
db.execSQL("alter table $table add column $COL_BLOCKED_BY integer default 0")
} catch (ex: Throwable) {
log.trace(ex)
}
}
if (oldVersion < 35 && newVersion >= 35) {
try {
db.execSQL("alter table $table add column $COL_REQUESTED_BY integer default 0")
} catch (ex: Throwable) {
log.trace(ex)
}
}
if (oldVersion < 55 && newVersion >= 55) {
try {
db.execSQL("alter table $table add column $COL_NOTE text default null")
} catch (ex: Throwable) {
log.trace(ex)
}
}
if (oldVersion < 58 && newVersion >= 58) {
try {
db.execSQL("alter table $table add column $COL_NOTIFYING integer default 0")
} catch (ex: Throwable) {
log.trace(ex)
}
}
}
override fun onDBUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) =
columnList.onDBUpgrade(db, oldVersion, newVersion)
fun deleteOld(now: Long) {
try {
@ -160,105 +109,96 @@ class UserRelation {
private fun key(dbId: Long, whoId: String) = "$dbId:$whoId"
private fun key(dbId: Long, whoId: EntityId) = key(dbId, whoId.toString())
fun save1Misskey(now: Long, dbId: Long, whoId: String, src: UserRelation?) {
src ?: return
try {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
cv.put(COL_WHO_ID, whoId)
cv.put(COL_FOLLOWING, src.following.b2i())
cv.put(COL_FOLLOWED_BY, src.followed_by.b2i())
cv.put(COL_BLOCKING, src.blocking.b2i())
cv.put(COL_MUTING, src.muting.b2i())
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.following_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
private fun ContentValues.fromUserRelation(src: UserRelation) {
put(COL_FOLLOWING, src.following)
put(COL_FOLLOWED_BY, src.followed_by)
put(COL_BLOCKING, src.blocking)
put(COL_MUTING, src.muting)
put(COL_REQUESTED, src.requested)
put(COL_FOLLOWING_REBLOGS, src.following_reblogs)
put(COL_ENDORSED, src.endorsed)
put(COL_BLOCKED_BY, src.blocked_by)
put(COL_REQUESTED_BY, src.requested_by)
put(COL_NOTIFYING, src.notifying)
put(COL_NOTE, src.note) // may null
}
cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
val key = key(dbId, whoId)
mMemoryCache.remove(key)
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
private fun ContentValues.fromTootRelationShip(src: TootRelationShip) {
put(COL_FOLLOWING, src.following)
put(COL_FOLLOWED_BY, src.followed_by)
put(COL_BLOCKING, src.blocking)
put(COL_MUTING, src.muting)
put(COL_REQUESTED, src.requested)
put(COL_FOLLOWING_REBLOGS, src.showing_reblogs)
put(COL_ENDORSED, src.endorsed)
put(COL_BLOCKED_BY, src.blocked_by)
put(COL_REQUESTED_BY, src.requested_by)
put(COL_NOTIFYING, src.notifying)
put(COL_NOTE, src.note) // may null
}
// マストドン用
fun save1Mastodon(now: Long, dbId: Long, src: TootRelationShip): UserRelation {
val id: String = src.id.toString()
try {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
cv.put(COL_WHO_ID, id)
cv.put(COL_FOLLOWING, src.following.b2i())
cv.put(COL_FOLLOWED_BY, src.followed_by.b2i())
cv.put(COL_BLOCKING, src.blocking.b2i())
cv.put(COL_MUTING, src.muting.b2i())
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.showing_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
App1.database.replaceOrThrow(table, null, cv)
val key = key(dbId, id)
mMemoryCache.remove(key)
ContentValues().apply {
put(COL_TIME_SAVE, now)
put(COL_DB_ID, dbId)
put(COL_WHO_ID, id)
fromTootRelationShip(src)
}.let { App1.database.replaceOrThrow(table, null, it) }
mMemoryCache.remove(key(dbId, id))
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
return load(dbId, id)
}
// マストドン用
fun saveListMastodon(now: Long, dbId: Long, srcList: ArrayList<TootRelationShip>) {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
var bOK = false
fun saveListMastodon(now: Long, dbId: Long, srcList: Iterable<TootRelationShip>) {
val db = App1.database
db.execSQL("BEGIN TRANSACTION")
try {
val bOK = try {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
for (src in srcList) {
val id = src.id.toString()
cv.put(COL_WHO_ID, id)
cv.put(COL_FOLLOWING, src.following.b2i())
cv.put(COL_FOLLOWED_BY, src.followed_by.b2i())
cv.put(COL_BLOCKING, src.blocking.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_MUTING, src.muting.b2i())
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.showing_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.putOrNull(COL_NOTE, src.note)
cv.fromTootRelationShip(src)
db.replaceOrThrow(table, null, cv)
}
bOK = true
true
} catch (ex: Throwable) {
log.trace(ex)
log.e(ex, "saveList failed.")
false
}
if (bOK) {
db.execSQL("COMMIT TRANSACTION")
for (src in srcList) {
val key = key(dbId, src.id)
mMemoryCache.remove(key)
when {
!bOK -> db.execSQL("ROLLBACK TRANSACTION")
else -> {
db.execSQL("COMMIT TRANSACTION")
for (src in srcList) {
mMemoryCache.remove(key(dbId, src.id))
}
}
} else {
db.execSQL("ROLLBACK TRANSACTION")
}
}
fun save1Misskey(now: Long, dbId: Long, whoId: String, src: UserRelation?) {
src ?: return
try {
ContentValues().apply {
put(COL_TIME_SAVE, now)
put(COL_DB_ID, dbId)
put(COL_WHO_ID, whoId)
fromUserRelation(src)
}.let { App1.database.replaceOrThrow(table, null, it) }
mMemoryCache.remove(key(dbId, whoId))
} catch (ex: Throwable) {
log.e(ex, "save failed.")
}
}
@ -267,102 +207,77 @@ class UserRelation {
dbId: Long,
srcList: List<Map.Entry<EntityId, UserRelation>>,
start: Int,
end: Int
end: Int,
) {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
var bOK = false
val db = App1.database
db.execSQL("BEGIN TRANSACTION")
try {
val bOK = try {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
for (i in start until end) {
val entry = srcList[i]
val id = entry.key
val src = entry.value
cv.put(COL_WHO_ID, id.toString())
cv.put(COL_FOLLOWING, src.following.b2i())
cv.put(COL_FOLLOWED_BY, src.followed_by.b2i())
cv.put(COL_BLOCKING, src.blocking.b2i())
cv.put(COL_MUTING, src.muting.b2i())
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.following_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
cv.fromUserRelation(src)
db.replaceOrThrow(table, null, cv)
}
bOK = true
true
} catch (ex: Throwable) {
log.trace(ex)
log.e(ex, "saveList failed.")
false
}
if (bOK) {
db.execSQL("COMMIT TRANSACTION")
for (i in start until end) {
val entry = srcList[i]
val key = key(dbId, entry.key)
mMemoryCache.remove(key)
when {
!bOK -> db.execSQL("ROLLBACK TRANSACTION")
else -> {
db.execSQL("COMMIT TRANSACTION")
for (i in start until end) {
val entry = srcList[i]
val key = key(dbId, entry.key)
mMemoryCache.remove(key)
}
}
} else {
db.execSQL("ROLLBACK TRANSACTION")
}
}
fun saveList2(now: Long, dbId: Long, list: ArrayList<TootRelationShip>) {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
var bOK = false
// Misskeyのリレーション取得APIから
fun saveListMisskeyRelationApi(now: Long, dbId: Long, list: ArrayList<TootRelationShip>) {
val db = App1.database
db.execSQL("BEGIN TRANSACTION")
try {
val bOK = try {
val cv = ContentValues()
cv.put(COL_TIME_SAVE, now)
cv.put(COL_DB_ID, dbId)
for (src in list) {
cv.put(COL_WHO_ID, src.id.toString())
cv.put(COL_FOLLOWING, src.following.b2i())
cv.put(COL_FOLLOWED_BY, src.followed_by.b2i())
cv.put(COL_BLOCKING, src.blocking.b2i())
cv.put(COL_MUTING, src.muting.b2i())
cv.put(COL_REQUESTED, src.requested.b2i())
cv.put(COL_FOLLOWING_REBLOGS, src.showing_reblogs)
cv.put(COL_ENDORSED, src.endorsed.b2i())
cv.put(COL_BLOCKED_BY, src.blocked_by.b2i())
cv.put(COL_REQUESTED_BY, src.requested_by.b2i())
cv.put(COL_NOTIFYING, src.notifying.b2i())
cv.putOrNull(COL_NOTE, src.note)
val id = src.id.toString()
cv.put(COL_WHO_ID, id)
cv.fromTootRelationShip(src)
db.replace(table, null, cv)
}
bOK = true
true
} catch (ex: Throwable) {
log.trace(ex)
log.e(ex, "saveList2 failed.")
log.e(ex, "saveListMisskeyRelationApi failed.")
false
}
if (bOK) {
db.execSQL("COMMIT TRANSACTION")
for (src in list) {
val key = key(dbId, src.id)
mMemoryCache.remove(key)
when {
!bOK -> db.execSQL("ROLLBACK TRANSACTION")
else -> {
db.execSQL("COMMIT TRANSACTION")
for (src in list) {
mMemoryCache.remove(key(dbId, src.id))
}
}
} else {
db.execSQL("ROLLBACK TRANSACTION")
}
}
private const val loadWhere = "$COL_DB_ID=? and $COL_WHO_ID=?"
private val loadWhere = "$COL_DB_ID=? and $COL_WHO_ID=?"
private val loadWhereArg = object : ThreadLocal<Array<String?>>() {
override fun initialValue(): Array<String?> {
return Array(2) { null }
}
override fun initialValue(): Array<String?> = Array(2) { null }
}
fun load(dbId: Long, whoId: EntityId): UserRelation {
@ -439,7 +354,7 @@ class UserRelation {
fun createCursorPseudo(): Cursor =
App1.database.query(
table,
arrayOf(COL_ID, COL_WHO_ID),
arrayOf(COL_ID.name, COL_WHO_ID.name),
"$COL_DB_ID=$DB_ID_PSEUDO and ( $COL_MUTING=1 or $COL_BLOCKING=1 )",
null,
null,

View File

@ -3,7 +3,6 @@ package jp.juggler.util
import android.content.ContentValues
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import jp.juggler.subwaytooter.table.SavedAccount
/////////////////////////////////////////////////////////////
// SQLite にBooleanをそのまま保存することはできないのでInt型との変換が必要になる
@ -14,11 +13,10 @@ fun Boolean.b2i() = if (this) 1 else 0
// integer to boolean
fun Int.i2b() = this != 0
fun Cursor.getBoolean(keyIdx: Int) =
getInt(keyIdx).i2b()
fun Cursor.getBoolean(key: String) =
getBoolean(getColumnIndex(key))
//fun Cursor.getBoolean(keyIdx: Int) =
// getInt(keyIdx).i2b()
//fun Cursor.getBoolean(key: String) =
// getBoolean(getColumnIndex(key))
fun Cursor.getInt(key: String) =
getInt(getColumnIndex(key))
@ -47,9 +45,6 @@ fun Cursor.getStringOrNull(keyIdx: Int) =
fun Cursor.getStringOrNull(key: String) =
getStringOrNull(getColumnIndex(key))
fun ContentValues.putOrNull(key: String, value: String?) =
if (value == null) putNull(key) else put(key, value)
/////////////////////////////////////////////////////////////
interface TableCompanion {
@ -76,13 +71,14 @@ class ColumnMeta(
val table: String,
val initialVersion: Int,
var createExtra: () -> Array<String> = { emptyArray() },
var deleteBeforeCreate: Boolean = false,
) : ArrayList<ColumnMeta>() {
val maxVersion: Int
get() = this.maxOfOrNull { it.version } ?: 0
fun createTableSql() =
listOf(
"create table if not exists ${SavedAccount.table} (${sorted().joinToString(",") { "${it.name} ${it.typeSpec}" }})",
"create table if not exists $table (${sorted().joinToString(",") { "${it.name} ${it.typeSpec}" }})",
*(createExtra())
)
@ -93,6 +89,7 @@ class ColumnMeta(
fun onDBCreate(db: SQLiteDatabase) {
log.d("onDBCreate table=$table")
if (deleteBeforeCreate) db.execSQL("drop table if exists $table")
createTableSql().forEach { db.execSQL(it) }
}
@ -114,10 +111,7 @@ class ColumnMeta(
// テーブル作成時のソート
override fun compareTo(other: ColumnMeta): Int {
// プライマリキーを先頭にする
val ia = if (this.primary) -1 else 0
val ib = if (other.primary) -1 else 0
ia.compareTo(ib).notZero()?.let { return it }
(other.primary.b2i() - primary.b2i()).notZero()?.let { return it }
// 残りはカラム名順
return name.compareTo(other.name)
}
@ -134,24 +128,12 @@ class ColumnMeta(
list.add(this)
}
@Suppress("unused")
fun putNullTo(cv: ContentValues) = cv.putNull(name)
fun putTo(cv: ContentValues, v: Boolean?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: String?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Byte?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Short?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Int?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Long?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Float?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: Double?) = cv.put(name, v)
fun putTo(cv: ContentValues, v: ByteArray?) = cv.put(name, v)
fun getIndex(cursor: Cursor) = cursor.getColumnIndex(name)
fun getLong(cursor: Cursor) = cursor.getLong(getIndex(cursor))
}
fun ContentValues.putNull(key: ColumnMeta) = putNull(key.name)
fun ContentValues.put(key: ColumnMeta, v: Boolean?) = put(key.name, v)
fun ContentValues.put(key: ColumnMeta, v: Boolean?) = put(key.name, v?.b2i())
fun ContentValues.put(key: ColumnMeta, v: String?) = put(key.name, v)
fun ContentValues.put(key: ColumnMeta, v: Byte?) = put(key.name, v)
fun ContentValues.put(key: ColumnMeta, v: Short?) = put(key.name, v)
@ -163,7 +145,7 @@ fun ContentValues.put(key: ColumnMeta, v: ByteArray?) = put(key.name, v)
fun Cursor.getInt(key: ColumnMeta) = getInt(getColumnIndex(key.name))
fun Cursor.getBoolean(key: ColumnMeta) = getBoolean(getColumnIndex(key.name))
fun Cursor.getBoolean(key: ColumnMeta) = getInt(key).i2b()
fun Cursor.getLong(key: ColumnMeta) = getLong(getColumnIndex(key.name))
@Suppress("unused")

View File

@ -329,8 +329,8 @@ fun defaultLocale(context: Context): Locale =
fun Matcher.findOrNull() = if (find()) this else null
fun String.formatEx(vararg args: Any?): String =
java.lang.String.format(Locale.JAPANESE, this, *args)
//fun String.formatEx(vararg args: Any?): String =
// java.lang.String.format(Locale.JAPANESE, this, *args)
fun Float.toString(format: String): String =
java.lang.String.format(Locale.JAPANESE, format, this)

View File

@ -558,7 +558,7 @@ potential-bugs:
UnreachableCode:
active: true
UnsafeCallOnNullableType:
active: true
active: false
UnsafeCast:
active: true
UnusedUnaryOperator:
@ -609,6 +609,7 @@ style:
- 'java.lang.String.format'
- 'kotlin.text.String.format'
- 'kotlin.text.String.Companion.format'
- 'android.content.ContentValues.put(java.lang.String,java.lang.Boolean)'
excludes:
- '**/test/**'
- '**/androidTest/**'