カスタム絵文字4k個のタンスで絵文字ピッカーの挙動を最適化した
This commit is contained in:
parent
2d4b107879
commit
33584b5689
|
@ -16,6 +16,7 @@
|
||||||
<w>gifv</w>
|
<w>gifv</w>
|
||||||
<w>hashtag</w>
|
<w>hashtag</w>
|
||||||
<w>hashtags</w>
|
<w>hashtags</w>
|
||||||
|
<w>hohoemi</w>
|
||||||
<w>idempotency</w>
|
<w>idempotency</w>
|
||||||
<w>kenglxn</w>
|
<w>kenglxn</w>
|
||||||
<w>mailto</w>
|
<w>mailto</w>
|
||||||
|
|
|
@ -443,16 +443,22 @@ for(@fix_name){
|
||||||
updateCodeMap();
|
updateCodeMap();
|
||||||
updateNameMap();
|
updateNameMap();
|
||||||
|
|
||||||
|
my %name_chars;
|
||||||
my $bad_name = 0;
|
my $bad_name = 0;
|
||||||
for my $name (sort keys %name_map){
|
for my $name (sort keys %name_map){
|
||||||
|
for( split //,$name ){
|
||||||
|
$name_chars{$_}=1;
|
||||||
|
}
|
||||||
|
|
||||||
my $rh = $name_map{$name};
|
my $rh = $name_map{$name};
|
||||||
my @res_list = values %$rh;
|
my @res_list = values %$rh;
|
||||||
|
|
||||||
next if @res_list == 1;
|
next if @res_list == 1;
|
||||||
warn "name $name has multiple resource. ",join(',',map{ $_->{res_name} } @res_list),"\n";
|
warn "name $name has multiple resource. ",join(',',map{ $_->{res_name} } @res_list),"\n";
|
||||||
$bad_name = 1;
|
$bad_name = 1;
|
||||||
}
|
}
|
||||||
$bad_name and die "please fix name=>resource duplicate.\n";
|
$bad_name and die "please fix name=>resource duplicate.\n";
|
||||||
|
warn "name_chars: [",join('',sort keys %name_chars),"]\n";
|
||||||
|
|
||||||
sub decodeUnified($){
|
sub decodeUnified($){
|
||||||
my($chars) = @_;
|
my($chars) = @_;
|
||||||
|
@ -552,6 +558,8 @@ my $utf8 = Encode::find_encoding("utf8");
|
||||||
my $utf16 = Encode::find_encoding("UTF-16BE");
|
my $utf16 = Encode::find_encoding("UTF-16BE");
|
||||||
my $utf16_max_length = 0;
|
my $utf16_max_length = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 画像リソースIDとUnidoceシーケンスの関連付けを出力する
|
# 画像リソースIDとUnidoceシーケンスの関連付けを出力する
|
||||||
for my $res_name ( sort keys %res_map ){
|
for my $res_name ( sort keys %res_map ){
|
||||||
my $res_info = $res_map{$res_name};
|
my $res_info = $res_map{$res_name};
|
||||||
|
@ -576,12 +584,29 @@ for my $res_name ( sort keys %res_map ){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#for my $res_name ( sort keys %res_map ){
|
||||||
|
# my $res_info = $res_map{$res_name};
|
||||||
|
# for my $short_name ( sort keys %{$res_info->{shortname_map}} ){
|
||||||
|
# addCode( qq{name( R.drawable.$res_name, "$short_name" );});
|
||||||
|
# }
|
||||||
|
#}
|
||||||
|
|
||||||
# 画像リソースIDとshortcodeの関連付けを出力する
|
# 画像リソースIDとshortcodeの関連付けを出力する
|
||||||
for my $res_name ( sort keys %res_map ){
|
# 投稿時にshortcodeをユニコードに変換するため、shortcodeとUTF-16シーケンスの関連付けを出力する
|
||||||
my $res_info = $res_map{$res_name};
|
for my $name (sort keys %name_map){
|
||||||
for my $short_name ( sort keys %{$res_info->{shortname_map}} ){
|
my $rh = $name_map{$name};
|
||||||
addCode( qq{name( R.drawable.$res_name, "$short_name" );});
|
my @res_list = values %$rh;
|
||||||
}
|
my $res_info = $res_list[0];
|
||||||
|
|
||||||
|
my $chars = parseCodePoint( $res_info->{unified} );
|
||||||
|
# コードポイントのリストからperl内部表現の文字列にする
|
||||||
|
my $str = join '',map{ chr hex $_ } @$chars;
|
||||||
|
# perl内部表現からUTF-16に変換する
|
||||||
|
my $str_utf16 = $utf16->encode( $str );
|
||||||
|
my @utf16_chars = unpack("n*",$str_utf16);
|
||||||
|
# UTF-16の文字のリストをJavaのエスケープ表現に直す
|
||||||
|
my $java_chars = join('',map{ sprintf qq(\\u%04x),$_} @utf16_chars );
|
||||||
|
addCode( qq{name( "$name", R.drawable.$res_info->{res_name}, "$java_chars" );});
|
||||||
}
|
}
|
||||||
|
|
||||||
# カテゴリを書きだす
|
# カテゴリを書きだす
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -866,7 +866,7 @@ public class ActAccountSetting extends AppCompatActivity
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateCredential( "display_name=" + Uri.encode(sv ) );
|
updateCredential( "display_name=" + Uri.encode(EmojiDecoder.decodeShortCode(sv) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendNote(boolean bConfirmed){
|
private void sendNote(boolean bConfirmed){
|
||||||
|
@ -890,7 +890,7 @@ public class ActAccountSetting extends AppCompatActivity
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateCredential( "note=" + Uri.encode(sv ) );
|
updateCredential( "note=" + Uri.encode(EmojiDecoder.decodeShortCode(sv) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int PERMISSION_REQUEST_AVATAR = 1;
|
private static final int PERMISSION_REQUEST_AVATAR = 1;
|
||||||
|
|
|
@ -7,8 +7,9 @@ import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
import android.graphics.Typeface;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.GlideBuilder;
|
import com.bumptech.glide.GlideBuilder;
|
||||||
|
@ -43,11 +44,13 @@ import jp.juggler.subwaytooter.util.CustomEmojiCache;
|
||||||
import jp.juggler.subwaytooter.util.CustomEmojiLister;
|
import jp.juggler.subwaytooter.util.CustomEmojiLister;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
import okhttp3.Cache;
|
import okhttp3.Cache;
|
||||||
|
import okhttp3.CacheControl;
|
||||||
|
import okhttp3.Call;
|
||||||
import okhttp3.CipherSuite;
|
import okhttp3.CipherSuite;
|
||||||
import okhttp3.ConnectionSpec;
|
import okhttp3.ConnectionSpec;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Response;
|
||||||
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
|
import uk.co.chrisjenx.calligraphy.CalligraphyConfig;
|
||||||
import uk.co.chrisjenx.calligraphy.TypefaceUtils;
|
|
||||||
|
|
||||||
public class App1 extends Application {
|
public class App1 extends Application {
|
||||||
|
|
||||||
|
@ -215,10 +218,10 @@ public class App1 extends Application {
|
||||||
|
|
||||||
public static OkHttpClient ok_http_client;
|
public static OkHttpClient ok_http_client;
|
||||||
|
|
||||||
public static OkHttpClient ok_http_client2;
|
private static OkHttpClient ok_http_client2;
|
||||||
|
|
||||||
public static final boolean USE_OLD_EMOJIONE = false;
|
// public static final boolean USE_OLD_EMOJIONE = false;
|
||||||
public static Typeface typeface_emoji;
|
// public static Typeface typeface_emoji;
|
||||||
|
|
||||||
public static SharedPreferences pref;
|
public static SharedPreferences pref;
|
||||||
|
|
||||||
|
@ -292,11 +295,11 @@ public class App1 extends Application {
|
||||||
AcctSet.deleteOld( System.currentTimeMillis() );
|
AcctSet.deleteOld( System.currentTimeMillis() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( USE_OLD_EMOJIONE ){
|
// if( USE_OLD_EMOJIONE ){
|
||||||
if( typeface_emoji == null ){
|
// if( typeface_emoji == null ){
|
||||||
typeface_emoji = TypefaceUtils.load( app_context.getAssets(), "emojione_android.ttf" );
|
// typeface_emoji = TypefaceUtils.load( app_context.getAssets(), "emojione_android.ttf" );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if( image_loader == null ){
|
// if( image_loader == null ){
|
||||||
// image_loader = new MyImageLoader(
|
// image_loader = new MyImageLoader(
|
||||||
|
@ -406,4 +409,74 @@ public class App1 extends Application {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final CacheControl CACHE_5MIN = new CacheControl.Builder()
|
||||||
|
.maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS) // キャッシュをいつまで保持するか
|
||||||
|
//s .minFresh( 1, TimeUnit.HOURS ) // キャッシュが新鮮であると考えられる時間
|
||||||
|
.maxAge( 1, TimeUnit.HOURS ) // キャッシュが新鮮であると考えられる時間
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Nullable public static byte[] getHttpCached( @NonNull String url ){
|
||||||
|
Response response;
|
||||||
|
long t_start = SystemClock.elapsedRealtime();
|
||||||
|
try{
|
||||||
|
okhttp3.Request.Builder request_builder = new okhttp3.Request.Builder();
|
||||||
|
request_builder.url( url );
|
||||||
|
request_builder.cacheControl( CACHE_5MIN );
|
||||||
|
|
||||||
|
Call call = App1.ok_http_client2.newCall( request_builder.build() );
|
||||||
|
response = call.execute();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
log.e( ex, "getHttp network error." );
|
||||||
|
return null;
|
||||||
|
}finally{
|
||||||
|
long t_delta = SystemClock.elapsedRealtime() -t_start;
|
||||||
|
log.d("getHttp: time=%dms",t_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ! response.isSuccessful() ){
|
||||||
|
log.e( "getHttp response error. %s", response );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return response.body().bytes();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
log.e( ex, "getHttp content error." );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable public static String getHttpCachedString( @NonNull String url ){
|
||||||
|
Response response;
|
||||||
|
long t_start = SystemClock.elapsedRealtime();
|
||||||
|
try{
|
||||||
|
okhttp3.Request.Builder request_builder = new okhttp3.Request.Builder();
|
||||||
|
request_builder.url( url );
|
||||||
|
request_builder.cacheControl( CACHE_5MIN );
|
||||||
|
|
||||||
|
Call call = App1.ok_http_client2.newCall( request_builder.build() );
|
||||||
|
response = call.execute();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
log.e( ex, "getHttp network error." );
|
||||||
|
return null;
|
||||||
|
}finally{
|
||||||
|
long t_delta = SystemClock.elapsedRealtime() -t_start;
|
||||||
|
log.d("getHttp: time=%dms",t_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ! response.isSuccessful() ){
|
||||||
|
log.e( "getHttp response error. %s", response );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
return response.body().string();
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
log.e( ex, "getHttp content error." );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
import jp.juggler.subwaytooter.table.UserRelation;
|
import jp.juggler.subwaytooter.table.UserRelation;
|
||||||
import jp.juggler.subwaytooter.util.EmojiDecoder;
|
import jp.juggler.subwaytooter.util.EmojiDecoder;
|
||||||
|
import jp.juggler.subwaytooter.util.EmojiMap201709;
|
||||||
import jp.juggler.subwaytooter.view.MyLinkMovementMethod;
|
import jp.juggler.subwaytooter.view.MyLinkMovementMethod;
|
||||||
import jp.juggler.subwaytooter.view.MyNetworkImageView;
|
import jp.juggler.subwaytooter.view.MyNetworkImageView;
|
||||||
|
|
||||||
|
@ -37,20 +38,20 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||||
, arg_activity.getLayoutInflater().inflate( R.layout.lv_header_account, parent, false )
|
, arg_activity.getLayoutInflater().inflate( R.layout.lv_header_account, parent, false )
|
||||||
);
|
);
|
||||||
|
|
||||||
ivBackground = (MyNetworkImageView) viewRoot.findViewById( R.id.ivBackground );
|
ivBackground = viewRoot.findViewById( R.id.ivBackground );
|
||||||
llProfile = viewRoot.findViewById( R.id.llProfile );
|
llProfile = viewRoot.findViewById( R.id.llProfile );
|
||||||
tvCreated = (TextView) viewRoot.findViewById( R.id.tvCreated );
|
tvCreated = viewRoot.findViewById( R.id.tvCreated );
|
||||||
ivAvatar = (MyNetworkImageView) viewRoot.findViewById( R.id.ivAvatar );
|
ivAvatar = viewRoot.findViewById( R.id.ivAvatar );
|
||||||
tvDisplayName = (TextView) viewRoot.findViewById( R.id.tvDisplayName );
|
tvDisplayName = viewRoot.findViewById( R.id.tvDisplayName );
|
||||||
tvAcct = (TextView) viewRoot.findViewById( R.id.tvAcct );
|
tvAcct = viewRoot.findViewById( R.id.tvAcct );
|
||||||
btnFollowing = (Button) viewRoot.findViewById( R.id.btnFollowing );
|
btnFollowing = viewRoot.findViewById( R.id.btnFollowing );
|
||||||
btnFollowers = (Button) viewRoot.findViewById( R.id.btnFollowers );
|
btnFollowers = viewRoot.findViewById( R.id.btnFollowers );
|
||||||
btnStatusCount = (Button) viewRoot.findViewById( R.id.btnStatusCount );
|
btnStatusCount = viewRoot.findViewById( R.id.btnStatusCount );
|
||||||
tvNote = (TextView) viewRoot.findViewById( R.id.tvNote );
|
tvNote = viewRoot.findViewById( R.id.tvNote );
|
||||||
View btnMore = viewRoot.findViewById( R.id.btnMore );
|
View btnMore = viewRoot.findViewById( R.id.btnMore );
|
||||||
btnFollow = (ImageButton) viewRoot.findViewById( R.id.btnFollow );
|
btnFollow = viewRoot.findViewById( R.id.btnFollow );
|
||||||
ivFollowedBy = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy );
|
ivFollowedBy = viewRoot.findViewById( R.id.ivFollowedBy );
|
||||||
tvRemoteProfileWarning = (TextView) viewRoot.findViewById( R.id.tvRemoteProfileWarning );
|
tvRemoteProfileWarning = viewRoot.findViewById( R.id.tvRemoteProfileWarning );
|
||||||
|
|
||||||
ivBackground.setOnClickListener( this );
|
ivBackground.setOnClickListener( this );
|
||||||
btnFollowing.setOnClickListener( this );
|
btnFollowing.setOnClickListener( this );
|
||||||
|
@ -103,7 +104,7 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||||
|
|
||||||
String s = "@" + access_info.getFullAcct( who );
|
String s = "@" + access_info.getFullAcct( who );
|
||||||
if( who.locked ){
|
if( who.locked ){
|
||||||
s += " " + EmojiDecoder.map_name2unicode.get( "lock" );
|
s += " " + EmojiMap201709.sShortNameToImageId.get("lock" ).unified;
|
||||||
}
|
}
|
||||||
tvAcct.setText( EmojiDecoder.decodeEmoji( activity, s ,null) );
|
tvAcct.setText( EmojiDecoder.decodeEmoji( activity, s ,null) );
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,8 @@ public class EmojiPicker implements View.OnClickListener, CustomEmojiLister.Call
|
||||||
SkinTone tone = (SkinTone) viewRoot.findViewById( selected_tone ).getTag();
|
SkinTone tone = (SkinTone) viewRoot.findViewById( selected_tone ).getTag();
|
||||||
for( String suffix : tone.suffix_list ){
|
for( String suffix : tone.suffix_list ){
|
||||||
String new_name = name + suffix;
|
String new_name = name + suffix;
|
||||||
Integer value = EmojiMap201709.sShortNameToImageId.get( new_name );
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( new_name );
|
||||||
if( value != null ) return new_name;
|
if( info != null ) return new_name;
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -334,9 +334,9 @@ public class EmojiPicker implements View.OnClickListener, CustomEmojiLister.Call
|
||||||
view.setTag( item );
|
view.setTag( item );
|
||||||
ImageView iv = (ImageView) view;
|
ImageView iv = (ImageView) view;
|
||||||
if( page != null ){
|
if( page != null ){
|
||||||
Integer image_id = EmojiMap201709.sShortNameToImageId.get( item.name );
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( item.name );
|
||||||
if( image_id != null ){
|
if( info != null ){
|
||||||
iv.setImageResource( image_id );
|
iv.setImageResource( info.image_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
@ -361,8 +361,8 @@ public class EmojiPicker implements View.OnClickListener, CustomEmojiLister.Call
|
||||||
EmojiItem item = page.emoji_list.get( idx );
|
EmojiItem item = page.emoji_list.get( idx );
|
||||||
if( TextUtils.isEmpty( item.instance ) ){
|
if( TextUtils.isEmpty( item.instance ) ){
|
||||||
String name = item.name;
|
String name = item.name;
|
||||||
Integer image_id = EmojiMap201709.sShortNameToImageId.get( name );
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( name );
|
||||||
if( image_id == null ) return;
|
if( info == null ) return;
|
||||||
if( selected_tone != 0 ){
|
if( selected_tone != 0 ){
|
||||||
name = applySkinTone( name );
|
name = applySkinTone( name );
|
||||||
}
|
}
|
||||||
|
|
|
@ -459,7 +459,6 @@ import java.util.ArrayList;
|
||||||
if( result != null ) result.onParseComplete();
|
if( result != null ) result.onParseComplete();
|
||||||
return result;
|
return result;
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
log.trace( ex );
|
|
||||||
handler.dispose();
|
handler.dispose();
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,16 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.App1;
|
import jp.juggler.subwaytooter.App1;
|
||||||
import okhttp3.Call;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class CustomEmojiCache {
|
public class CustomEmojiCache {
|
||||||
|
@ -62,24 +62,41 @@ public class CustomEmojiCache {
|
||||||
// リクエスト
|
// リクエスト
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
void onAPNGLoadComplete( APNGFrames b );
|
void onAPNGLoadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Request {
|
static class Request {
|
||||||
@NonNull String url;
|
@NonNull final WeakReference<Object> refTarget;
|
||||||
@NonNull Callback callback;
|
@NonNull final String url;
|
||||||
|
@NonNull final Callback callback;
|
||||||
|
|
||||||
public Request( @NonNull String url, @NonNull Callback callback ){
|
public Request( @NonNull Object target_tag, @NonNull String url, @NonNull Callback callback ){
|
||||||
|
this.refTarget = new WeakReference<>( target_tag );
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ConcurrentLinkedQueue< Request > queue = new ConcurrentLinkedQueue<>();
|
final LinkedList< Request > queue = new LinkedList<>();
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
|
||||||
@Nullable public APNGFrames get( @NonNull String url, @NonNull Callback callback ){
|
public void cancelRequest( @NonNull Object target_tag){
|
||||||
|
synchronized( queue ){
|
||||||
|
Iterator<Request> it = queue.iterator();
|
||||||
|
while( it.hasNext() ){
|
||||||
|
Request request = it.next();
|
||||||
|
Object tag = request.refTarget.get();
|
||||||
|
if( tag == null || tag == target_tag ){
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable public APNGFrames get( @NonNull Object target_tag,@NonNull String url, @NonNull Callback callback ){
|
||||||
|
|
||||||
|
cancelRequest( target_tag );
|
||||||
|
|
||||||
synchronized( cache ){
|
synchronized( cache ){
|
||||||
long now = getNow();
|
long now = getNow();
|
||||||
|
@ -97,7 +114,9 @@ public class CustomEmojiCache {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queue.add( new Request( url, callback ) );
|
synchronized( queue ){
|
||||||
|
queue.addLast( new Request( target_tag, url, callback ) );
|
||||||
|
}
|
||||||
worker.notifyEx();
|
worker.notifyEx();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -124,19 +143,27 @@ public class CustomEmojiCache {
|
||||||
|
|
||||||
@Override public void run(){
|
@Override public void run(){
|
||||||
while( ! bCancelled.get() ){
|
while( ! bCancelled.get() ){
|
||||||
Request request = queue.poll();
|
Request request;
|
||||||
|
synchronized( queue ){
|
||||||
|
request = queue.isEmpty() ? null : queue.removeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
if( request == null ){
|
if( request == null ){
|
||||||
waitEx( 86400000L );
|
waitEx( 86400000L );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( request.refTarget.get() == null ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
long now = getNow();
|
long now = getNow();
|
||||||
synchronized( cache ){
|
synchronized( cache ){
|
||||||
|
|
||||||
// 成功キャッシュ
|
// 成功キャッシュ
|
||||||
CacheItem item = cache.get( request.url );
|
CacheItem item = cache.get( request.url );
|
||||||
if( item != null ){
|
if( item != null ){
|
||||||
fireCallback( request.callback, item.frames );
|
fireCallback( request.callback );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +178,7 @@ public class CustomEmojiCache {
|
||||||
|
|
||||||
APNGFrames frames = null;
|
APNGFrames frames = null;
|
||||||
try{
|
try{
|
||||||
byte[] data = getHttp( request.url );
|
byte[] data = App1.getHttpCached( request.url );
|
||||||
if( data != null ){
|
if( data != null ){
|
||||||
frames = decodeAPNG( data, request.url );
|
frames = decodeAPNG( data, request.url );
|
||||||
}
|
}
|
||||||
|
@ -169,7 +196,7 @@ public class CustomEmojiCache {
|
||||||
item.frames.dispose();
|
item.frames.dispose();
|
||||||
item.frames = frames;
|
item.frames = frames;
|
||||||
}
|
}
|
||||||
fireCallback( request.callback, frames );
|
fireCallback( request.callback );
|
||||||
}else{
|
}else{
|
||||||
cache_error.put( request.url, getNow() );
|
cache_error.put( request.url, getNow() );
|
||||||
}
|
}
|
||||||
|
@ -177,40 +204,15 @@ public class CustomEmojiCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireCallback( final Callback callback, final APNGFrames frames ){
|
private void fireCallback( final Callback callback ){
|
||||||
handler.post( new Runnable() {
|
handler.post( new Runnable() {
|
||||||
@Override public void run(){
|
@Override public void run(){
|
||||||
callback.onAPNGLoadComplete( frames );
|
callback.onAPNGLoadComplete();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getHttp( String url ){
|
|
||||||
Response response;
|
|
||||||
try{
|
|
||||||
okhttp3.Request.Builder request_builder = new okhttp3.Request.Builder();
|
|
||||||
request_builder.url( url );
|
|
||||||
Call call = App1.ok_http_client2.newCall( request_builder.build() );
|
|
||||||
response = call.execute();
|
|
||||||
}catch( Throwable ex ){
|
|
||||||
log.e( ex, "getHttp network error." );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! response.isSuccessful() ){
|
|
||||||
log.e( "getHttp response error. %s", response );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return response.body().bytes();
|
|
||||||
}catch( Throwable ex ){
|
|
||||||
log.e( ex, "getHttp content error." );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sweep_cache(){
|
private void sweep_cache(){
|
||||||
|
|
||||||
// キャッシュの掃除
|
// キャッシュの掃除
|
||||||
|
@ -244,7 +246,7 @@ public class CustomEmojiCache {
|
||||||
APNGFrames frames = APNGFrames.parseAPNG( new ByteArrayInputStream( data ), 64 );
|
APNGFrames frames = APNGFrames.parseAPNG( new ByteArrayInputStream( data ), 64 );
|
||||||
if( frames != null ) return frames;
|
if( frames != null ) return frames;
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
log.e( ex, "PNG decode failed. %s", url );
|
log.e( ex, "PNG decode failed. %s ", url );
|
||||||
// PngFeatureException Interlaced images are not yet supported
|
// PngFeatureException Interlaced images are not yet supported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package jp.juggler.subwaytooter.util;
|
package jp.juggler.subwaytooter.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -11,7 +9,6 @@ import android.text.TextUtils;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -21,8 +18,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.App1;
|
import jp.juggler.subwaytooter.App1;
|
||||||
import jp.juggler.subwaytooter.api.entity.CustomEmoji;
|
import jp.juggler.subwaytooter.api.entity.CustomEmoji;
|
||||||
import okhttp3.Call;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public class CustomEmojiLister {
|
public class CustomEmojiLister {
|
||||||
|
@ -175,7 +170,7 @@ public class CustomEmojiLister {
|
||||||
|
|
||||||
CustomEmoji.List list = null;
|
CustomEmoji.List list = null;
|
||||||
try{
|
try{
|
||||||
String data = getHttp( request.instance );
|
String data = App1.getHttpCachedString("https://"+ request.instance + "/api/v1/custom_emojis");
|
||||||
if( data != null ){
|
if( data != null ){
|
||||||
list = decodeEmojiList( data, request.instance );
|
list = decodeEmojiList( data, request.instance );
|
||||||
}
|
}
|
||||||
|
@ -209,31 +204,7 @@ public class CustomEmojiLister {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHttp( String instance ){
|
|
||||||
Response response;
|
|
||||||
try{
|
|
||||||
okhttp3.Request.Builder request_builder = new okhttp3.Request.Builder();
|
|
||||||
request_builder.url( "https://"+ instance + "/api/v1/custom_emojis" );
|
|
||||||
Call call = App1.ok_http_client2.newCall( request_builder.build() );
|
|
||||||
response = call.execute();
|
|
||||||
}catch( Throwable ex ){
|
|
||||||
log.e( ex, "getHttp network error." );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ! response.isSuccessful() ){
|
|
||||||
log.e( "getHttp response error. %s", response );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return response.body().string();
|
|
||||||
}catch( Throwable ex ){
|
|
||||||
log.e( ex, "getHttp content error." );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sweep_cache(){
|
private void sweep_cache(){
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package jp.juggler.subwaytooter.util;
|
package jp.juggler.subwaytooter.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.support.annotation.DrawableRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
@ -9,52 +10,20 @@ import android.text.Spanned;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.App1;
|
|
||||||
import jp.juggler.subwaytooter.R;
|
import jp.juggler.subwaytooter.R;
|
||||||
import jp.juggler.subwaytooter.api.entity.CustomEmoji;
|
import jp.juggler.subwaytooter.api.entity.CustomEmoji;
|
||||||
|
|
||||||
public abstract class EmojiDecoder {
|
@SuppressWarnings("WeakerAccess")
|
||||||
private static final Pattern SHORTNAME_PATTERN = Pattern.compile( ":([-+\\w]+):" );
|
public class EmojiDecoder {
|
||||||
|
|
||||||
public static final HashMap< String, String > map_name2unicode = EmojiMap._shortNameToUnicode;
|
|
||||||
private static final HashSet< String > set_unicode = EmojiMap._unicode_set;
|
|
||||||
|
|
||||||
private static class DecodeEnv {
|
private static class DecodeEnv {
|
||||||
@NonNull final Context context;
|
@NonNull final Context context;
|
||||||
|
@NonNull final SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||||
|
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
DecodeEnv( @NonNull Context context ){
|
||||||
int last_span_start = - 1;
|
|
||||||
int last_span_end = - 1;
|
|
||||||
|
|
||||||
@Nullable CustomEmoji.Map custom_map;
|
|
||||||
|
|
||||||
DecodeEnv( @NonNull Context context, @Nullable CustomEmoji.Map custom_map ){
|
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.custom_map = custom_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeSpan(){
|
|
||||||
if( last_span_start >= 0 ){
|
|
||||||
if( last_span_end > last_span_start && App1.typeface_emoji != null ){
|
|
||||||
EmojiSpan typefaceSpan = new EmojiSpan( App1.typeface_emoji );
|
|
||||||
sb.setSpan( typefaceSpan, last_span_start, last_span_end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
|
||||||
}
|
|
||||||
last_span_start = - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addEmoji( String s ){
|
|
||||||
if( last_span_start < 0 ){
|
|
||||||
last_span_start = sb.length();
|
|
||||||
}
|
|
||||||
sb.append( s );
|
|
||||||
last_span_end = sb.length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addUnicodeString( String s ){
|
void addUnicodeString( String s ){
|
||||||
|
@ -63,53 +32,36 @@ public abstract class EmojiDecoder {
|
||||||
while( i < end ){
|
while( i < end ){
|
||||||
int remain = end - i;
|
int remain = end - i;
|
||||||
String emoji = null;
|
String emoji = null;
|
||||||
if( App1.USE_OLD_EMOJIONE ){
|
Integer image_id = null;
|
||||||
for( int j = EmojiMap.max_length ; j > 0 ; -- j ){
|
for( int j = EmojiMap201709.utf16_max_length ; j > 0 ; -- j ){
|
||||||
if( j > remain ) continue;
|
if( j > remain ) continue;
|
||||||
String check = s.substring( i, i + j );
|
String check = s.substring( i, i + j );
|
||||||
if( set_unicode.contains( check ) ){
|
image_id = EmojiMap201709.sUTF16ToImageId.get( check );
|
||||||
emoji = check;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( emoji != null ){
|
|
||||||
addEmoji( emoji );
|
|
||||||
i += emoji.length();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Integer image_id = null;
|
|
||||||
for( int j = EmojiMap201709.utf16_max_length ; j > 0 ; -- j ){
|
|
||||||
if( j > remain ) continue;
|
|
||||||
String check = s.substring( i, i + j );
|
|
||||||
image_id = EmojiMap201709.sUTF16ToImageId.get( check );
|
|
||||||
if( image_id != null ){
|
|
||||||
if( j< remain && s.charAt( i+j ) == 0xFE0E){
|
|
||||||
// 絵文字バリエーション・シーケンス(EVS)のU+FE0E(VS-15)が直後にある場合
|
|
||||||
// その文字を絵文字化しない
|
|
||||||
emoji = s.substring( i, i + j +1);
|
|
||||||
image_id = 0;
|
|
||||||
}else{
|
|
||||||
emoji = check;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( image_id != null ){
|
if( image_id != null ){
|
||||||
if( image_id == 0 ){
|
if( j < remain && s.charAt( i + j ) == 0xFE0E ){
|
||||||
// 絵文字バリエーション・シーケンス(EVS)のU+FE0E(VS-15)が直後にある場合
|
// 絵文字バリエーション・シーケンス(EVS)のU+FE0E(VS-15)が直後にある場合
|
||||||
// その文字を絵文字化しない
|
// その文字を絵文字化しない
|
||||||
closeSpan();
|
emoji = s.substring( i, i + j + 1 );
|
||||||
sb.append( emoji );
|
image_id = 0;
|
||||||
}else{
|
}else{
|
||||||
addImageSpan( emoji, image_id );
|
emoji = check;
|
||||||
}
|
}
|
||||||
i += emoji.length();
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closeSpan();
|
|
||||||
|
if( image_id != null ){
|
||||||
|
if( image_id == 0 ){
|
||||||
|
// 絵文字バリエーション・シーケンス(EVS)のU+FE0E(VS-15)が直後にある場合
|
||||||
|
// その文字を絵文字化しない
|
||||||
|
sb.append( emoji );
|
||||||
|
}else{
|
||||||
|
addImageSpan( emoji, image_id );
|
||||||
|
}
|
||||||
|
i += emoji.length();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int length = Character.charCount( s.codePointAt( i ) );
|
int length = Character.charCount( s.codePointAt( i ) );
|
||||||
if( length == 1 ){
|
if( length == 1 ){
|
||||||
sb.append( s.charAt( i ) );
|
sb.append( s.charAt( i ) );
|
||||||
|
@ -121,8 +73,7 @@ public abstract class EmojiDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addImageSpan( String text, int res_id ){
|
void addImageSpan( String text, @DrawableRes int res_id ){
|
||||||
closeSpan();
|
|
||||||
int start = sb.length();
|
int start = sb.length();
|
||||||
sb.append( text );
|
sb.append( text );
|
||||||
int end = sb.length();
|
int end = sb.length();
|
||||||
|
@ -130,7 +81,6 @@ public abstract class EmojiDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
void addNetworkEmojiSpan( String text, @NonNull String url ){
|
void addNetworkEmojiSpan( String text, @NonNull String url ){
|
||||||
closeSpan();
|
|
||||||
int start = sb.length();
|
int start = sb.length();
|
||||||
sb.append( text );
|
sb.append( text );
|
||||||
int end = sb.length();
|
int end = sb.length();
|
||||||
|
@ -138,78 +88,191 @@ public abstract class EmojiDecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isWhitespaceBeforeEmoji( int cp ){
|
||||||
|
switch( cp ){
|
||||||
|
case 0x0009: // HORIZONTAL TABULATION
|
||||||
|
case 0x000A: // LINE FEED
|
||||||
|
case 0x000B: // VERTICAL TABULATION
|
||||||
|
case 0x000C: // FORM FEED
|
||||||
|
case 0x000D: // CARRIAGE RETURN
|
||||||
|
case 0x001C: // FILE SEPARATOR
|
||||||
|
case 0x001D: // GROUP SEPARATOR
|
||||||
|
case 0x001E: // RECORD SEPARATOR
|
||||||
|
case 0x001F: // UNIT SEPARATOR
|
||||||
|
case 0x0020:
|
||||||
|
case 0x00A0: //非区切りスペース
|
||||||
|
case 0x1680:
|
||||||
|
case 0x180E:
|
||||||
|
case 0x2000:
|
||||||
|
case 0x2001:
|
||||||
|
case 0x2002:
|
||||||
|
case 0x2003:
|
||||||
|
case 0x2004:
|
||||||
|
case 0x2005:
|
||||||
|
case 0x2006:
|
||||||
|
case 0x2007: //非区切りスペース
|
||||||
|
case 0x2008:
|
||||||
|
case 0x2009:
|
||||||
|
case 0x200A:
|
||||||
|
case 0x200B:
|
||||||
|
case 0x202F: //非区切りスペース
|
||||||
|
case 0x205F:
|
||||||
|
case 0x2060:
|
||||||
|
case 0x3000:
|
||||||
|
case 0x3164:
|
||||||
|
case 0xFEFF:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return Character.isWhitespace( cp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isShortCodeCharacter( int cp ){
|
||||||
|
return ( 'A' <= cp && cp <= 'Z' )
|
||||||
|
|| ( 'a' <= cp && cp <= 'z' )
|
||||||
|
|| ( '0' <= cp && cp <= '9' )
|
||||||
|
|| cp == '-'
|
||||||
|
|| cp == '+'
|
||||||
|
|| cp == '_'
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ShortCodeSplitterCallback {
|
||||||
|
void onString( @NonNull String part );
|
||||||
|
|
||||||
|
void onShortCode( @NonNull String part, @NonNull String name );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void splitShortCode( @NonNull String s, int start, int end, @NonNull ShortCodeSplitterCallback callback ){
|
||||||
|
int i = start;
|
||||||
|
while( i < end ){
|
||||||
|
// 絵文字パターンの開始位置を探索する
|
||||||
|
start = i;
|
||||||
|
while( i < end ){
|
||||||
|
int c = s.codePointAt( i );
|
||||||
|
if( c == ':' ){
|
||||||
|
// ショートコードの手前は始端か改行か空白文字でないとならない
|
||||||
|
// 空白文字の判定はサーバサイドのそれにあわせる
|
||||||
|
if( i == 0 || isWhitespaceBeforeEmoji( s.codePointBefore( i ) ) ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += Character.charCount( c );
|
||||||
|
}
|
||||||
|
if( i > start ){
|
||||||
|
callback.onString( s.substring( start, i ) );
|
||||||
|
}
|
||||||
|
if( i >= end ) break;
|
||||||
|
|
||||||
|
start = i++; // start=コロンの位置 i=その次の位置
|
||||||
|
|
||||||
|
int emoji_end = - 1;
|
||||||
|
while( i < end ){
|
||||||
|
int c = s.codePointAt( i );
|
||||||
|
if( c == ':' ){
|
||||||
|
emoji_end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( ! isShortCodeCharacter( c ) ){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += Character.charCount( c );
|
||||||
|
}
|
||||||
|
|
||||||
|
// 絵文字がみつからなかったら、startの位置のコロンだけを処理して残りは次のループで処理する
|
||||||
|
if( emoji_end == - 1 || emoji_end - start < 3 ){
|
||||||
|
callback.onString( ":" );
|
||||||
|
i = start + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.onShortCode(
|
||||||
|
s.substring( start, emoji_end + 1 ) // ":shortcode:"
|
||||||
|
, s.substring( start + 1, emoji_end ) // "shortcode"
|
||||||
|
);
|
||||||
|
|
||||||
|
i = emoji_end + 1;// コロンの次の位置
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final Pattern reNicoru = Pattern.compile( "\\Anicoru\\d*\\z", Pattern.CASE_INSENSITIVE );
|
private static final Pattern reNicoru = Pattern.compile( "\\Anicoru\\d*\\z", Pattern.CASE_INSENSITIVE );
|
||||||
private static final Pattern reHohoemi = Pattern.compile( "\\Ahohoemi\\d*\\z", Pattern.CASE_INSENSITIVE );
|
private static final Pattern reHohoemi = Pattern.compile( "\\Ahohoemi\\d*\\z", Pattern.CASE_INSENSITIVE );
|
||||||
|
|
||||||
public static Spannable decodeEmoji( Context context, String s, @Nullable CustomEmoji.Map custom_map ){
|
public static Spannable decodeEmoji( @NonNull final Context context, @NonNull final String s, @Nullable final CustomEmoji.Map custom_map ){
|
||||||
|
|
||||||
DecodeEnv decode_env = new DecodeEnv( context, custom_map );
|
final DecodeEnv decode_env = new DecodeEnv( context );
|
||||||
Matcher matcher = SHORTNAME_PATTERN.matcher( s );
|
splitShortCode( s, 0, s.length(), new ShortCodeSplitterCallback() {
|
||||||
int last_end = 0;
|
@Override public void onString( @NonNull String part ){
|
||||||
while( matcher.find() ){
|
decode_env.addUnicodeString( part );
|
||||||
int start = matcher.start();
|
|
||||||
int end = matcher.end();
|
|
||||||
if( start > last_end ){
|
|
||||||
decode_env.addUnicodeString( s.substring( last_end, start ) );
|
|
||||||
}
|
|
||||||
last_end = end;
|
|
||||||
//
|
|
||||||
if( App1.USE_OLD_EMOJIONE ){
|
|
||||||
String unicode = map_name2unicode.get( matcher.group( 1 ) );
|
|
||||||
if( unicode != null ){
|
|
||||||
decode_env.addEmoji( unicode );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
String name = matcher.group( 1 ).toLowerCase().replace( '-', '_' );
|
|
||||||
Integer image_id = EmojiMap201709.sShortNameToImageId.get( name );
|
|
||||||
if( image_id != null ){
|
|
||||||
decode_env.addImageSpan( s.substring( start, end ), image_id );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = ( custom_map == null ? null : custom_map.get( matcher.group( 1 ) ) );
|
@Override public void onShortCode( @NonNull String part, @NonNull String name ){
|
||||||
if( ! TextUtils.isEmpty( url ) ){
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( name.toLowerCase().replace( '-', '_' ) );
|
||||||
decode_env.addNetworkEmojiSpan( s.substring( start, end ), url );
|
if( info != null ){
|
||||||
|
decode_env.addImageSpan( part, info.image_id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}else if( reHohoemi.matcher( matcher.group( 1 ) ).find() ){
|
String url = ( custom_map == null ? null : custom_map.get( name ) );
|
||||||
decode_env.addImageSpan( s.substring( start, end ), R.drawable.emoji_hohoemi );
|
if( ! TextUtils.isEmpty( url ) ){
|
||||||
}else if( reNicoru.matcher( matcher.group( 1 ) ).find() ){
|
decode_env.addNetworkEmojiSpan( part, url );
|
||||||
decode_env.addImageSpan( s.substring( start, end ), R.drawable.emoji_nicoru );
|
return;
|
||||||
}else{
|
}
|
||||||
decode_env.addUnicodeString( s.substring( start, end ) );
|
|
||||||
|
if( reHohoemi.matcher( name ).find() ){
|
||||||
|
decode_env.addImageSpan( part, R.drawable.emoji_hohoemi );
|
||||||
|
}else if( reNicoru.matcher( name ).find() ){
|
||||||
|
decode_env.addImageSpan( part, R.drawable.emoji_nicoru );
|
||||||
|
}else{
|
||||||
|
decode_env.addUnicodeString( part );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
} );
|
||||||
// copy remain
|
|
||||||
int end = s.length();
|
|
||||||
if( end > last_end ){
|
|
||||||
decode_env.addUnicodeString( s.substring( last_end, end ) );
|
|
||||||
}
|
|
||||||
// close span
|
|
||||||
decode_env.closeSpan();
|
|
||||||
|
|
||||||
return decode_env.sb;
|
return decode_env.sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayList< CharSequence > searchShortCode( Context context, String prefix, int limit ){
|
// 投稿などの際、表示は不要だがショートコード=>Unicodeの解決を行いたい場合がある
|
||||||
ArrayList< CharSequence > dst = new ArrayList<>();
|
// カスタム絵文字の変換も行わない
|
||||||
if( ! App1.USE_OLD_EMOJIONE ){
|
public static String decodeShortCode( @NonNull final String s ){
|
||||||
for( String shortCode : EmojiMap201709.sShortNameList ){
|
|
||||||
if( dst.size() >= limit ) break;
|
final StringBuilder sb = new StringBuilder();
|
||||||
if( ! shortCode.contains( prefix )) continue;
|
|
||||||
|
splitShortCode( s, 0, s.length(), new ShortCodeSplitterCallback() {
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
@Override public void onString( @NonNull String part ){
|
||||||
sb.append( ' ' );
|
sb.append( part );
|
||||||
int start = 0;
|
|
||||||
int end = sb.length();
|
|
||||||
sb.setSpan( new EmojiImageSpan( context, EmojiMap201709.sShortNameToImageId.get( shortCode ) ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
|
||||||
sb.append( ' ' );
|
|
||||||
sb.append( ':' );
|
|
||||||
sb.append( shortCode );
|
|
||||||
sb.append( ':' );
|
|
||||||
dst.add( sb );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public void onShortCode( @NonNull String part, @NonNull String name ){
|
||||||
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( name.toLowerCase().replace( '-', '_' ) );
|
||||||
|
sb.append( info != null ? info.unified : part );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 入力補完用。絵文字ショートコード一覧を部分一致で絞り込む
|
||||||
|
static ArrayList< CharSequence > searchShortCode( Context context, String prefix, int limit ){
|
||||||
|
ArrayList< CharSequence > dst = new ArrayList<>();
|
||||||
|
for( String shortCode : EmojiMap201709.sShortNameList ){
|
||||||
|
if( dst.size() >= limit ) break;
|
||||||
|
if( ! shortCode.contains( prefix ) ) continue;
|
||||||
|
|
||||||
|
EmojiMap201709.EmojiInfo info = EmojiMap201709.sShortNameToImageId.get( shortCode );
|
||||||
|
if( info == null ) continue;
|
||||||
|
|
||||||
|
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||||
|
sb.append( ' ' );
|
||||||
|
int start = 0;
|
||||||
|
int end = sb.length();
|
||||||
|
|
||||||
|
sb.setSpan( new EmojiImageSpan( context, info.image_id ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||||
|
sb.append( ' ' );
|
||||||
|
sb.append( ':' );
|
||||||
|
sb.append( shortCode );
|
||||||
|
sb.append( ':' );
|
||||||
|
dst.add( sb );
|
||||||
}
|
}
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -164,10 +164,10 @@ public class HTMLDecoder {
|
||||||
, LinkClickContext account
|
, LinkClickContext account
|
||||||
, SpannableStringBuilder sb
|
, SpannableStringBuilder sb
|
||||||
, @NonNull DecodeOptions options
|
, @NonNull DecodeOptions options
|
||||||
){
|
){
|
||||||
if( TAG_TEXT.equals( tag ) ){
|
if( TAG_TEXT.equals( tag ) ){
|
||||||
if( options.bDecodeEmoji ){
|
if( options.bDecodeEmoji ){
|
||||||
sb.append( EmojiDecoder.decodeEmoji( context, decodeEntity( text ) ,options.customEmojiMap ) );
|
sb.append( EmojiDecoder.decodeEmoji( context, decodeEntity( text ), options.customEmojiMap ) );
|
||||||
}else{
|
}else{
|
||||||
sb.append( decodeEntity( text ) );
|
sb.append( decodeEntity( text ) );
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ public class HTMLDecoder {
|
||||||
sb_tmp.append( "<img/>" );
|
sb_tmp.append( "<img/>" );
|
||||||
}else{
|
}else{
|
||||||
for( Node child : child_nodes ){
|
for( Node child : child_nodes ){
|
||||||
child.encodeSpan( context, account, sb_tmp, options);
|
child.encodeSpan( context, account, sb_tmp, options );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,8 +205,8 @@ public class HTMLDecoder {
|
||||||
if( end > start && "a".equals( tag ) ){
|
if( end > start && "a".equals( tag ) ){
|
||||||
String href = getHref();
|
String href = getHref();
|
||||||
if( href != null ){
|
if( href != null ){
|
||||||
String link_text = sb.subSequence( start,end ).toString();
|
String link_text = sb.subSequence( start, end ).toString();
|
||||||
MyClickableSpan span = new MyClickableSpan( account, link_text, href, account.findAcctColor( href ),options.link_tag );
|
MyClickableSpan span = new MyClickableSpan( account, link_text, href, account.findAcctColor( href ), options.link_tag );
|
||||||
sb.setSpan( span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
|
sb.setSpan( span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,16 +281,12 @@ public class HTMLDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if( is_media_attachment( list_attachment, href ) ){
|
if( is_media_attachment( list_attachment, href ) ){
|
||||||
if( App1.USE_OLD_EMOJIONE ){
|
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||||
return EmojiDecoder.decodeEmoji( context, ":frame_photo:",null );
|
sb.append( href );
|
||||||
}else{
|
int start = 0;
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
int end = sb.length();
|
||||||
sb.append( href );
|
sb.setSpan( new EmojiImageSpan( context, R.drawable.emj_1f5bc ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||||
int start = 0;
|
return sb;
|
||||||
int end = sb.length();
|
|
||||||
sb.setSpan( new EmojiImageSpan( context, R.drawable.emj_1f5bc ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
@ -319,12 +315,11 @@ public class HTMLDecoder {
|
||||||
return Character.isWhitespace( c ) || c == 0x0a || c == 0x0d;
|
return Character.isWhitespace( c ) || c == 0x0a || c == 0x0d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static SpannableStringBuilder decodeHTML(
|
public static SpannableStringBuilder decodeHTML(
|
||||||
Context context
|
Context context
|
||||||
, LinkClickContext account
|
, LinkClickContext account
|
||||||
, String src
|
, String src
|
||||||
,@NonNull DecodeOptions options
|
, @NonNull DecodeOptions options
|
||||||
){
|
){
|
||||||
prepareTagInformation();
|
prepareTagInformation();
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||||
|
@ -336,7 +331,7 @@ public class HTMLDecoder {
|
||||||
rootNode.addChild( tracker, "" );
|
rootNode.addChild( tracker, "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
rootNode.encodeSpan( context, account, sb,options);
|
rootNode.encodeSpan( context, account, sb, options );
|
||||||
int end = sb.length();
|
int end = sb.length();
|
||||||
while( end > 0 && isWhitespace( sb.charAt( end - 1 ) ) ) -- end;
|
while( end > 0 && isWhitespace( sb.charAt( end - 1 ) ) ) -- end;
|
||||||
if( end < sb.length() ){
|
if( end < sb.length() ){
|
||||||
|
@ -376,7 +371,7 @@ public class HTMLDecoder {
|
||||||
// return sb;
|
// return sb;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public static Spannable decodeMentions( final SavedAccount access_info, TootMention.List src_list ,@Nullable Object link_tag ){
|
public static Spannable decodeMentions( final SavedAccount access_info, TootMention.List src_list, @Nullable Object link_tag ){
|
||||||
if( src_list == null || src_list.isEmpty() ) return null;
|
if( src_list == null || src_list.isEmpty() ) return null;
|
||||||
SpannableStringBuilder sb = new SpannableStringBuilder();
|
SpannableStringBuilder sb = new SpannableStringBuilder();
|
||||||
for( TootMention item : src_list ){
|
for( TootMention item : src_list ){
|
||||||
|
@ -390,8 +385,8 @@ public class HTMLDecoder {
|
||||||
}
|
}
|
||||||
int end = sb.length();
|
int end = sb.length();
|
||||||
if( end > start ){
|
if( end > start ){
|
||||||
String link_text = sb.subSequence( start,end ).toString();
|
String link_text = sb.subSequence( start, end ).toString();
|
||||||
MyClickableSpan span = new MyClickableSpan( access_info, link_text,item.url, access_info.findAcctColor( item.url ) ,link_tag );
|
MyClickableSpan span = new MyClickableSpan( access_info, link_text, item.url, access_info.findAcctColor( item.url ), link_tag );
|
||||||
|
|
||||||
sb.setSpan( span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
|
sb.setSpan( span, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package jp.juggler.subwaytooter.util;
|
package jp.juggler.subwaytooter.util;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
|
@ -36,4 +37,25 @@ public class NetworkEmojiInvalidator implements Runnable, NetworkEmojiSpan.Inval
|
||||||
view.postInvalidateOnAnimation();
|
view.postInvalidateOnAnimation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 最後に描画した時刻
|
||||||
|
private long t_last_draw;
|
||||||
|
|
||||||
|
// アニメーション開始時刻
|
||||||
|
private long t_start;
|
||||||
|
|
||||||
|
@Override public long getTimeFromStart(){
|
||||||
|
|
||||||
|
long now = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
// アニメーション開始時刻を計算する
|
||||||
|
if( t_start == 0L || now - t_last_draw >= 60000L ){
|
||||||
|
t_start = now;
|
||||||
|
}
|
||||||
|
t_last_draw = now;
|
||||||
|
|
||||||
|
return now - t_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -33,6 +33,7 @@ public class NetworkEmojiSpan extends ReplacementSpan implements CustomEmojiCach
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface InvalidateCallback {
|
public interface InvalidateCallback {
|
||||||
|
long getTimeFromStart();
|
||||||
void delayInvalidate( long delay );
|
void delayInvalidate( long delay );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ public class NetworkEmojiSpan extends ReplacementSpan implements CustomEmojiCach
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements CustomEmojiCache.Callback
|
// implements CustomEmojiCache.Callback
|
||||||
@Override public void onAPNGLoadComplete( APNGFrames b ){
|
@Override public void onAPNGLoadComplete(){
|
||||||
if( invalidate_callback != null ){
|
if( invalidate_callback != null ){
|
||||||
invalidate_callback.delayInvalidate( 0 );
|
invalidate_callback.delayInvalidate( 0 );
|
||||||
}
|
}
|
||||||
|
@ -73,11 +74,7 @@ public class NetworkEmojiSpan extends ReplacementSpan implements CustomEmojiCach
|
||||||
// フレーム探索結果を格納する構造体を確保しておく
|
// フレーム探索結果を格納する構造体を確保しておく
|
||||||
private final APNGFrames.FindFrameResult mFrameFindResult = new APNGFrames.FindFrameResult();
|
private final APNGFrames.FindFrameResult mFrameFindResult = new APNGFrames.FindFrameResult();
|
||||||
|
|
||||||
// 最後に描画した時刻
|
|
||||||
private long t_last_draw;
|
|
||||||
|
|
||||||
// アニメーション開始時刻
|
|
||||||
private long t_start;
|
|
||||||
|
|
||||||
@Override public void draw(
|
@Override public void draw(
|
||||||
@NonNull Canvas canvas
|
@NonNull Canvas canvas
|
||||||
|
@ -88,19 +85,13 @@ public class NetworkEmojiSpan extends ReplacementSpan implements CustomEmojiCach
|
||||||
if( invalidate_callback == null ) return;
|
if( invalidate_callback == null ) return;
|
||||||
|
|
||||||
// APNGデータの取得
|
// APNGデータの取得
|
||||||
APNGFrames frames = App1.custom_emoji_cache.get( url, this );
|
APNGFrames frames = App1.custom_emoji_cache.get( this, url, this );
|
||||||
if( frames == null ) return;
|
if( frames == null ) return;
|
||||||
|
|
||||||
long now = SystemClock.elapsedRealtime();
|
long t = invalidate_callback.getTimeFromStart();
|
||||||
|
|
||||||
// アニメーション開始時刻を計算する
|
|
||||||
if( t_start == 0L || now - t_last_draw >= 60000L ){
|
|
||||||
t_start = now;
|
|
||||||
}
|
|
||||||
t_last_draw = now;
|
|
||||||
|
|
||||||
// アニメーション開始時刻からの経過時間に応じたフレームを探索
|
// アニメーション開始時刻からの経過時間に応じたフレームを探索
|
||||||
frames.findFrame( mFrameFindResult, now - t_start );
|
frames.findFrame( mFrameFindResult, t );
|
||||||
|
|
||||||
Bitmap b = mFrameFindResult.bitmap;
|
Bitmap b = mFrameFindResult.bitmap;
|
||||||
if( b == null || b.isRecycled() ) return;
|
if( b == null || b.isRecycled() ) return;
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.util.ArrayList;
|
||||||
|
|
||||||
import jp.juggler.subwaytooter.R;
|
import jp.juggler.subwaytooter.R;
|
||||||
import jp.juggler.subwaytooter.Styler;
|
import jp.juggler.subwaytooter.Styler;
|
||||||
|
import jp.juggler.subwaytooter.view.MyEditText;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") class PopupAutoCompleteAcct {
|
@SuppressWarnings("WeakerAccess") class PopupAutoCompleteAcct {
|
||||||
final Activity activity;
|
final Activity activity;
|
||||||
|
@ -61,7 +62,8 @@ import jp.juggler.subwaytooter.Styler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setList(
|
void setList(
|
||||||
final int sel_start
|
final MyEditText et
|
||||||
|
, final int sel_start
|
||||||
, final int sel_end
|
, final int sel_end
|
||||||
, @Nullable ArrayList< CharSequence > acct_list
|
, @Nullable ArrayList< CharSequence > acct_list
|
||||||
, @Nullable String picker_caption
|
, @Nullable String picker_caption
|
||||||
|
@ -115,11 +117,11 @@ import jp.juggler.subwaytooter.Styler;
|
||||||
}
|
}
|
||||||
v.setOnClickListener( new View.OnClickListener() {
|
v.setOnClickListener( new View.OnClickListener() {
|
||||||
@Override public void onClick( View v ){
|
@Override public void onClick( View v ){
|
||||||
String s = etContent.getText().toString();
|
String s = et.getText().toString();
|
||||||
CharSequence svInsert = ( acct.charAt( 0 ) == ' ' ? acct.subSequence( 2, acct.length() ) : acct );
|
CharSequence svInsert = ( acct.charAt( 0 ) == ' ' ? acct.subSequence( 2, acct.length() ) : acct );
|
||||||
s = s.substring( 0, sel_start ) + svInsert + " " + ( sel_end >= s.length() ? "" : s.substring( sel_end ) );
|
s = s.substring( 0, sel_start ) + svInsert + " " + ( sel_end >= s.length() ? "" : s.substring( sel_end ) );
|
||||||
etContent.setText( s );
|
et.setText( s );
|
||||||
etContent.setSelection( sel_start + svInsert.length() + 1 );
|
et.setSelection( sel_start + svInsert.length() + 1 );
|
||||||
acct_popup.dismiss();
|
acct_popup.dismiss();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -251,7 +251,7 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append( "status=" );
|
sb.append( "status=" );
|
||||||
sb.append( Uri.encode( content ) );
|
sb.append( Uri.encode( EmojiDecoder.decodeShortCode(content ) ) );
|
||||||
|
|
||||||
if( visibility_checked != null ){
|
if( visibility_checked != null ){
|
||||||
sb.append( "&visibility=" );
|
sb.append( "&visibility=" );
|
||||||
|
@ -264,7 +264,7 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
|
|
||||||
if( spoiler_text != null ){
|
if( spoiler_text != null ){
|
||||||
sb.append( "&spoiler_text=" );
|
sb.append( "&spoiler_text=" );
|
||||||
sb.append( Uri.encode( spoiler_text ) );
|
sb.append( Uri.encode( EmojiDecoder.decodeShortCode(spoiler_text) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( in_reply_to_id != - 1L ){
|
if( in_reply_to_id != - 1L ){
|
||||||
|
@ -289,12 +289,12 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
|
|
||||||
JSONObject json = new JSONObject();
|
JSONObject json = new JSONObject();
|
||||||
try{
|
try{
|
||||||
json.put( "status", content );
|
json.put( "status", EmojiDecoder.decodeShortCode(content) );
|
||||||
if( visibility_checked != null ){
|
if( visibility_checked != null ){
|
||||||
json.put( "visibility", visibility_checked );
|
json.put( "visibility", visibility_checked );
|
||||||
}
|
}
|
||||||
json.put( "sensitive", bNSFW );
|
json.put( "sensitive", bNSFW );
|
||||||
json.put( "spoiler_text", TextUtils.isEmpty( spoiler_text ) ? "" : spoiler_text );
|
json.put( "spoiler_text", TextUtils.isEmpty( spoiler_text ) ? "" : EmojiDecoder.decodeShortCode(spoiler_text) );
|
||||||
json.put( "in_reply_to_id", in_reply_to_id == - 1L ? null : in_reply_to_id );
|
json.put( "in_reply_to_id", in_reply_to_id == - 1L ? null : in_reply_to_id );
|
||||||
JSONArray array = new JSONArray();
|
JSONArray array = new JSONArray();
|
||||||
if( attachment_list != null ){
|
if( attachment_list != null ){
|
||||||
|
@ -308,7 +308,7 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
json.put( "isEnquete", true );
|
json.put( "isEnquete", true );
|
||||||
array = new JSONArray();
|
array = new JSONArray();
|
||||||
for( String item : enquete_items ){
|
for( String item : enquete_items ){
|
||||||
array.put( item );
|
array.put( EmojiDecoder.decodeShortCode(item) );
|
||||||
}
|
}
|
||||||
json.put( "enquete_items", array );
|
json.put( "enquete_items", array );
|
||||||
}catch( JSONException ex ){
|
}catch( JSONException ex ){
|
||||||
|
@ -590,7 +590,7 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
if( popup == null || ! popup.isShowing() ){
|
if( popup == null || ! popup.isShowing() ){
|
||||||
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
||||||
}
|
}
|
||||||
popup.setList( start, end, acct_list, null, null );
|
popup.setList( et, start, end, acct_list, null, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,10 +622,12 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
if( popup == null || ! popup.isShowing() ){
|
if( popup == null || ! popup.isShowing() ){
|
||||||
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
||||||
}
|
}
|
||||||
popup.setList( last_sharp, end, tag_list, null, null );
|
popup.setList( et, last_sharp, end, tag_list, null, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void checkEmoji(){
|
private void checkEmoji(){
|
||||||
int end = et.getSelectionEnd();
|
int end = et.getSelectionEnd();
|
||||||
|
|
||||||
|
@ -644,12 +646,20 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// : の手前は始端か改行か空白でなければならない
|
||||||
|
if( last_colon > 0 && ! EmojiDecoder.isWhitespaceBeforeEmoji( src.codePointBefore( last_colon ) ) ){
|
||||||
|
log.d( "checkEmoji: invalid character before shortcode." );
|
||||||
|
closeAcctPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if( part.length() == 0 ){
|
if( part.length() == 0 ){
|
||||||
if( popup == null || ! popup.isShowing() ){
|
if( popup == null || ! popup.isShowing() ){
|
||||||
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
||||||
}
|
}
|
||||||
popup.setList(
|
popup.setList(
|
||||||
last_colon, end
|
et, last_colon, end
|
||||||
, null
|
, null
|
||||||
, picker_caption_emoji
|
, picker_caption_emoji
|
||||||
, open_picker_emoji
|
, open_picker_emoji
|
||||||
|
@ -684,12 +694,10 @@ public class PostHelper implements CustomEmojiLister.Callback, EmojiPicker.Callb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( code_list.isEmpty() ){
|
if( code_list.isEmpty() ){
|
||||||
closeAcctPopup();
|
|
||||||
}else{
|
|
||||||
if( popup == null || ! popup.isShowing() ){
|
if( popup == null || ! popup.isShowing() ){
|
||||||
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
popup = new PopupAutoCompleteAcct( activity, et, formRoot, bMainScreen );
|
||||||
}
|
}
|
||||||
popup.setList( last_colon, end, code_list, picker_caption_emoji, open_picker_emoji );
|
popup.setList( et, last_colon, end, code_list, picker_caption_emoji, open_picker_emoji );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class NetworkEmojiView extends View implements CustomEmojiCache.Callback
|
||||||
super.onDraw( canvas );
|
super.onDraw( canvas );
|
||||||
|
|
||||||
// APNGデータの取得
|
// APNGデータの取得
|
||||||
APNGFrames frames = App1.custom_emoji_cache.get( url, this );
|
APNGFrames frames = App1.custom_emoji_cache.get( this, url, this );
|
||||||
if( frames == null ) return;
|
if( frames == null ) return;
|
||||||
|
|
||||||
long now = SystemClock.elapsedRealtime();
|
long now = SystemClock.elapsedRealtime();
|
||||||
|
@ -87,7 +87,7 @@ public class NetworkEmojiView extends View implements CustomEmojiCache.Callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void onAPNGLoadComplete( APNGFrames b ){
|
@Override public void onAPNGLoadComplete(){
|
||||||
postInvalidateOnAnimation();;
|
postInvalidateOnAnimation();;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue