SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/table/AcctColor.java

214 lines
7.0 KiB
Java

package jp.juggler.subwaytooter.table;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import jp.juggler.subwaytooter.App1;
import jp.juggler.subwaytooter.util.LogCategory;
import jp.juggler.subwaytooter.util.Utils;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.LruCache;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import java.util.Locale;
public class AcctColor {
private static final LogCategory log = new LogCategory( "AcctColor" );
public static final String table = "acct_color";
private static final String COL_TIME_SAVE = "time_save";
private static final String COL_ACCT = "ac"; //@who@host ascii文字の大文字小文字は(sqliteにより)同一視される
private static final String COL_COLOR_FG = "cf"; // 未設定なら0、それ以外は色
private static final String COL_COLOR_BG = "cb"; // 未設定なら0、それ以外は色
private static final String COL_NICKNAME = "nick"; // 未設定ならnullか空文字列
private static final String COL_NOTIFICATION_SOUND = "notification_sound"; // 未設定ならnullか空文字列
public static void onDBCreate( SQLiteDatabase db ){
log.d( "onDBCreate!" );
db.execSQL(
"create table if not exists " + table
+ "(_id INTEGER PRIMARY KEY"
+ "," + COL_TIME_SAVE + " integer not null"
+ "," + COL_ACCT + " text not null"
+ "," + COL_COLOR_FG + " integer"
+ "," + COL_COLOR_BG + " integer"
+ "," + COL_NICKNAME + " text "
+ "," + COL_NOTIFICATION_SOUND + " text default ''"
+ ")"
);
db.execSQL(
"create unique index if not exists " + table + "_acct on " + table + "(" + COL_ACCT + ")"
);
db.execSQL(
"create index if not exists " + table + "_time on " + table + "(" + COL_TIME_SAVE + ")"
);
}
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
if( oldVersion < 9 && newVersion >= 9 ){
onDBCreate( db );
return;
}
if( oldVersion < 17 && newVersion >= 17 ){
try{
db.execSQL( "alter table " + table + " add column " + COL_NOTIFICATION_SOUND + " text default ''" );
}catch( Throwable ex ){
log.trace( ex );
}
}
}
@NonNull public String acct;
public int color_fg;
public int color_bg;
public String nickname;
public String notification_sound;
public AcctColor( @NonNull String acct, String nickname, int color_fg, int color_bg, String notification_sound ){
this.acct = acct;
this.nickname = nickname;
this.color_fg = color_fg;
this.color_bg = color_bg;
this.notification_sound = notification_sound;
}
private AcctColor( @NonNull String acct ){
this.acct = acct;
}
public void save( long now ){
acct = acct.toLowerCase( Locale.ENGLISH );
try{
ContentValues cv = new ContentValues();
cv.put( COL_TIME_SAVE, now );
cv.put( COL_ACCT, acct );
cv.put( COL_COLOR_FG, color_fg );
cv.put( COL_COLOR_BG, color_bg );
cv.put( COL_NICKNAME, nickname == null ? "" : nickname );
cv.put( COL_NOTIFICATION_SOUND, notification_sound == null ? "" : notification_sound );
App1.getDB().replace( table, null, cv );
mMemoryCache.remove( acct );
}catch( Throwable ex ){
log.trace( ex );
log.e( ex, "save failed." );
}
}
private static final String load_where = COL_ACCT + "=?";
private static final ThreadLocal< String[] > load_where_arg = new ThreadLocal< String[] >() {
@Override protected String[] initialValue(){
return new String[ 1 ];
}
};
private static final LruCache< String, AcctColor > mMemoryCache = new LruCache<>( 2048 );
@NonNull public static AcctColor load( @NonNull String acct ){
acct = acct.toLowerCase( Locale.ENGLISH );
AcctColor dst = mMemoryCache.get( acct );
if( dst != null ) return dst;
try{
String[] where_arg = load_where_arg.get();
where_arg[ 0 ] = acct;
Cursor cursor = App1.getDB().query( table, null, load_where, where_arg, null, null, null );
if( cursor != null ){
try{
if( cursor.moveToNext() ){
dst = new AcctColor( acct );
int idx;
idx = cursor.getColumnIndex( COL_COLOR_FG );
dst.color_fg = cursor.isNull( idx ) ? 0 : cursor.getInt( idx );
idx = cursor.getColumnIndex( COL_COLOR_BG );
dst.color_bg = cursor.isNull( idx ) ? 0 : cursor.getInt( idx );
idx = cursor.getColumnIndex( COL_NICKNAME );
dst.nickname = cursor.isNull( idx ) ? null : cursor.getString( idx );
idx = cursor.getColumnIndex( COL_NOTIFICATION_SOUND );
dst.notification_sound = cursor.isNull( idx ) ? null : cursor.getString( idx );
mMemoryCache.put( acct, dst );
return dst;
}
}finally{
cursor.close();
}
}
}catch( Throwable ex ){
log.trace( ex );
log.e( ex, "load failed." );
}
log.d( "lruCache size=%s,hit=%s,miss=%s", mMemoryCache.size(), mMemoryCache.hitCount(), mMemoryCache.missCount() );
dst = new AcctColor( acct );
mMemoryCache.put( acct, dst );
return dst;
}
@NonNull public static String getNickname( @NonNull String acct ){
AcctColor ac = load( acct );
return ! TextUtils.isEmpty( ac.nickname ) ? Utils.sanitizeBDI( ac.nickname ) : acct;
}
@Nullable public static String getNotificationSound( @NonNull String acct ){
AcctColor ac = load( acct );
return ! TextUtils.isEmpty( ac.notification_sound ) ? ac.notification_sound : null;
}
public static boolean hasNickname( @Nullable AcctColor ac ){
return ac != null && ! TextUtils.isEmpty( ac.nickname );
}
public static boolean hasColorForeground( @Nullable AcctColor ac ){
return ac != null && ac.color_fg != 0;
}
public static boolean hasColorBackground( @Nullable AcctColor ac ){
return ac != null && ac.color_bg != 0;
}
public static void clearMemoryCache(){
mMemoryCache.evictAll();
}
private static final char CHAR_REPLACE = 0x328A;
@NonNull
public static CharSequence getStringWithNickname( @NonNull Context context, int string_id, @NonNull String acct ){
AcctColor ac = load( acct );
String name = ! TextUtils.isEmpty( ac.nickname ) ? Utils.sanitizeBDI( ac.nickname ) : acct;
SpannableStringBuilder sb = new SpannableStringBuilder( context.getString( string_id, new String( new char[]{ CHAR_REPLACE } ) ) );
for( int i = sb.length() - 1 ; i >= 0 ; -- i ){
char c = sb.charAt( i );
if( c != CHAR_REPLACE ) continue;
sb.replace( i, i + 1, name );
if( ac.color_fg != 0 ){
sb.setSpan( new ForegroundColorSpan( ac.color_fg ), i, i + name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
}
if( ac.color_bg != 0 ){
sb.setSpan( new BackgroundColorSpan( ac.color_bg ), i, i + name.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
}
}
return sb;
}
}