v1.1.9
- リモートユーザのプロフィールに警告を表示 - トゥートの公開範囲をTL中に表示する - アカウント設定にプロフィール編集を追加
@ -9,8 +9,8 @@ android {
|
||||
applicationId "jp.juggler.subwaytooter"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 25
|
||||
versionCode 118
|
||||
versionName "1.1.8"
|
||||
versionCode 119
|
||||
versionName "1.1.9"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
|
@ -1,34 +1,58 @@
|
||||
package jp.juggler.subwaytooter;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ContentValues;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Base64OutputStream;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import jp.juggler.subwaytooter.api.TootApiClient;
|
||||
import jp.juggler.subwaytooter.api.TootApiResult;
|
||||
import jp.juggler.subwaytooter.api.entity.TootAccount;
|
||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||
import jp.juggler.subwaytooter.dialog.DlgAccessToken;
|
||||
import jp.juggler.subwaytooter.dialog.ActionsDialog;
|
||||
import jp.juggler.subwaytooter.table.AcctColor;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.util.Emojione;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.util.Utils;
|
||||
import jp.juggler.subwaytooter.view.MyNetworkImageView;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
@ -50,16 +74,22 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
}
|
||||
|
||||
SavedAccount account;
|
||||
SharedPreferences pref;
|
||||
|
||||
@Override
|
||||
protected void onCreate( @Nullable Bundle savedInstanceState ){
|
||||
super.onCreate( savedInstanceState );
|
||||
|
||||
App1.setActivityTheme( this, false );
|
||||
this.pref = App1.pref;
|
||||
|
||||
initUI();
|
||||
account = SavedAccount.loadAccount( this, log, getIntent().getLongExtra( KEY_ACCOUNT_DB_ID, - 1L ) );
|
||||
if( account == null ) finish();
|
||||
loadUIFromData( account );
|
||||
|
||||
initializeProfile();
|
||||
|
||||
btnOpenBrowser.setText( getString( R.string.open_instance_website, account.host ) );
|
||||
}
|
||||
|
||||
@ -70,26 +100,89 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
|
||||
static final int REQUEST_CODE_ACCT_CUSTOMIZE = 1;
|
||||
static final int REQUEST_CODE_NOTIFICATION_SOUND = 2;
|
||||
private static final int REQUEST_CODE_AVATAR_ATTACHMENT = 3;
|
||||
private static final int REQUEST_CODE_HEADER_ATTACHMENT = 4;
|
||||
private static final int REQUEST_CODE_AVATAR_CAMERA = 5;
|
||||
private static final int REQUEST_CODE_HEADER_CAMERA = 6;
|
||||
|
||||
@Override protected void onActivityResult( int requestCode, int resultCode, Intent data ){
|
||||
if( requestCode == REQUEST_CODE_ACCT_CUSTOMIZE && resultCode == RESULT_OK ){
|
||||
showAcctColor();
|
||||
}else if( resultCode == RESULT_OK && requestCode == REQUEST_CODE_NOTIFICATION_SOUND ){
|
||||
// RINGTONE_PICKERからの選択されたデータを取得する
|
||||
Uri uri = (Uri) data.getExtras().get( RingtoneManager.EXTRA_RINGTONE_PICKED_URI );
|
||||
if( uri != null ){
|
||||
notification_sound_uri = uri.toString();
|
||||
saveUIToData();
|
||||
// Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri);
|
||||
// TextView ringView = (TextView) findViewById(R.id.ringtone);
|
||||
// ringView.setText(ringtone.getTitle(getApplicationContext()));
|
||||
// ringtone.setStreamType(AudioManager.STREAM_ALARM);
|
||||
// ringtone.play();
|
||||
// SystemClock.sleep(1000);
|
||||
// ringtone.stop();
|
||||
switch( requestCode ){
|
||||
default:
|
||||
super.onActivityResult( requestCode, resultCode, data );
|
||||
break;
|
||||
case REQUEST_CODE_ACCT_CUSTOMIZE:{
|
||||
if( resultCode == RESULT_OK ){
|
||||
showAcctColor();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_NOTIFICATION_SOUND:{
|
||||
if( resultCode == RESULT_OK ){
|
||||
// RINGTONE_PICKERからの選択されたデータを取得する
|
||||
Uri uri = (Uri) data.getExtras().get( RingtoneManager.EXTRA_RINGTONE_PICKED_URI );
|
||||
if( uri != null ){
|
||||
notification_sound_uri = uri.toString();
|
||||
saveUIToData();
|
||||
// Ringtone ringtone = RingtoneManager.getRingtone(getApplicationContext(), uri);
|
||||
// TextView ringView = (TextView) findViewById(R.id.ringtone);
|
||||
// ringView.setText(ringtone.getTitle(getApplicationContext()));
|
||||
// ringtone.setStreamType(AudioManager.STREAM_ALARM);
|
||||
// ringtone.play();
|
||||
// SystemClock.sleep(1000);
|
||||
// ringtone.stop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_AVATAR_ATTACHMENT:
|
||||
case REQUEST_CODE_HEADER_ATTACHMENT:{
|
||||
|
||||
if( resultCode == RESULT_OK && data != null ){
|
||||
Uri uri = data.getData();
|
||||
if( uri != null ){
|
||||
// 単一選択
|
||||
String type = data.getType();
|
||||
if( TextUtils.isEmpty( type ) ){
|
||||
type = getContentResolver().getType( uri );
|
||||
}
|
||||
addAttachment( requestCode, uri, type );
|
||||
break;
|
||||
}
|
||||
ClipData cd = data.getClipData();
|
||||
if( cd != null ){
|
||||
int count = cd.getItemCount();
|
||||
if( count > 0 ){
|
||||
ClipData.Item item = cd.getItemAt( 0 );
|
||||
uri = item.getUri();
|
||||
String type = getContentResolver().getType( uri );
|
||||
addAttachment( requestCode, uri, type );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_CODE_AVATAR_CAMERA:
|
||||
case REQUEST_CODE_HEADER_CAMERA:{
|
||||
|
||||
if( resultCode != RESULT_OK ){
|
||||
// 失敗したら DBからデータを削除
|
||||
if( uriCameraImage != null ){
|
||||
getContentResolver().delete( uriCameraImage, null, null );
|
||||
uriCameraImage = null;
|
||||
}
|
||||
}else{
|
||||
// 画像のURL
|
||||
Uri uri = ( data == null ? null : data.getData() );
|
||||
if( uri == null ) uri = uriCameraImage;
|
||||
|
||||
if( uri != null ){
|
||||
String type = getContentResolver().getType( uri );
|
||||
addAttachment( requestCode, uri, type );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
super.onActivityResult( requestCode, resultCode, data );
|
||||
}
|
||||
|
||||
TextView tvInstance;
|
||||
@ -120,6 +213,15 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
|
||||
String notification_sound_uri;
|
||||
|
||||
MyNetworkImageView ivProfileHeader;
|
||||
MyNetworkImageView ivProfileAvatar;
|
||||
View btnProfileAvatar;
|
||||
View btnProfileHeader;
|
||||
EditText etDisplayName;
|
||||
View btnDisplayName;
|
||||
EditText etNote;
|
||||
View btnNote;
|
||||
|
||||
private void initUI(){
|
||||
setContentView( R.layout.act_account_setting );
|
||||
|
||||
@ -147,12 +249,25 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
tvUserCustom = (TextView) findViewById( R.id.tvUserCustom );
|
||||
btnUserCustom = findViewById( R.id.btnUserCustom );
|
||||
|
||||
ivProfileHeader = (MyNetworkImageView) findViewById( R.id.ivProfileHeader );
|
||||
ivProfileAvatar = (MyNetworkImageView) findViewById( R.id.ivProfileAvatar );
|
||||
btnProfileAvatar = findViewById( R.id.btnProfileAvatar );
|
||||
btnProfileHeader = findViewById( R.id.btnProfileHeader );
|
||||
etDisplayName = (EditText) findViewById( R.id.etDisplayName );
|
||||
btnDisplayName = findViewById( R.id.btnDisplayName );
|
||||
etNote = (EditText) findViewById( R.id.etNote );
|
||||
btnNote = findViewById( R.id.btnNote );
|
||||
|
||||
btnOpenBrowser.setOnClickListener( this );
|
||||
btnAccessToken.setOnClickListener( this );
|
||||
btnInputAccessToken.setOnClickListener( this );
|
||||
btnAccountRemove.setOnClickListener( this );
|
||||
btnVisibility.setOnClickListener( this );
|
||||
btnUserCustom.setOnClickListener( this );
|
||||
btnProfileAvatar.setOnClickListener( this );
|
||||
btnProfileHeader.setOnClickListener( this );
|
||||
btnDisplayName.setOnClickListener( this );
|
||||
btnNote.setOnClickListener( this );
|
||||
|
||||
swNSFWOpen.setOnCheckedChangeListener( this );
|
||||
cbNotificationMention.setOnCheckedChangeListener( this );
|
||||
@ -290,6 +405,23 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
notification_sound_uri = "";
|
||||
saveUIToData();
|
||||
break;
|
||||
|
||||
case R.id.btnProfileAvatar:
|
||||
pickAvatarImage();
|
||||
break;
|
||||
|
||||
case R.id.btnProfileHeader:
|
||||
pickHeaderImage();
|
||||
break;
|
||||
|
||||
case R.id.btnDisplayName:
|
||||
sendDisplayName();
|
||||
break;
|
||||
|
||||
case R.id.btnNote:
|
||||
sendNote();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,5 +650,437 @@ public class ActAccountSetting extends AppCompatActivity
|
||||
startActivityForResult( chooser, REQUEST_CODE_NOTIFICATION_SOUND );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void initializeProfile(){
|
||||
// 初期状態
|
||||
ivProfileAvatar.setErrorImageResId( Styler.getAttributeResourceId( this, R.attr.ic_question ) );
|
||||
ivProfileAvatar.setDefaultImageResId( Styler.getAttributeResourceId( this, R.attr.ic_question ) );
|
||||
etDisplayName.setText( "(loading...)" );
|
||||
etNote.setText( "(loading...)" );
|
||||
// 初期状態では編集不可能
|
||||
btnProfileAvatar.setEnabled( false );
|
||||
btnProfileHeader.setEnabled( false );
|
||||
etDisplayName.setEnabled( false );
|
||||
btnDisplayName.setEnabled( false );
|
||||
etNote.setEnabled( false );
|
||||
btnNote.setEnabled( false );
|
||||
// 疑似アカウントなら編集不可のまま
|
||||
if( account.isPseudo() ) return;
|
||||
|
||||
loadProfile();
|
||||
}
|
||||
|
||||
void loadProfile(){
|
||||
// サーバから情報をロードする
|
||||
|
||||
final ProgressDialog progress = new ProgressDialog( this );
|
||||
|
||||
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
|
||||
|
||||
TootAccount data;
|
||||
|
||||
@Override protected TootApiResult doInBackground( Void... params ){
|
||||
TootApiClient client = new TootApiClient( ActAccountSetting.this, new TootApiClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return isCancelled();
|
||||
}
|
||||
|
||||
@Override public void publishApiProgress( final String s ){
|
||||
}
|
||||
} );
|
||||
client.setAccount( account );
|
||||
|
||||
TootApiResult result = client.request( "/api/v1/accounts/verify_credentials" );
|
||||
if( result != null && result.object != null ){
|
||||
data = TootAccount.parse( ActAccountSetting.this, account, result.object );
|
||||
if( data == null ) return new TootApiResult( "TootAccount parse failed." );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled( TootApiResult result ){
|
||||
super.onPostExecute( result );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
try{
|
||||
progress.dismiss();
|
||||
}catch( Throwable ignored ){
|
||||
}
|
||||
if( result == null ){
|
||||
// cancelled.
|
||||
}else if( data != null ){
|
||||
showProfile( data );
|
||||
}else{
|
||||
Utils.showToast( ActAccountSetting.this, true, result.error );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
task.executeOnExecutor( App1.task_executor );
|
||||
progress.setIndeterminate( true );
|
||||
progress.setOnDismissListener( new DialogInterface.OnDismissListener() {
|
||||
@Override public void onDismiss( DialogInterface dialog ){
|
||||
task.cancel( true );
|
||||
}
|
||||
} );
|
||||
progress.show();
|
||||
}
|
||||
|
||||
void showProfile( TootAccount src ){
|
||||
ivProfileAvatar.setImageUrl( App1.pref, 16f, src.avatar_static, src.avatar );
|
||||
ivProfileHeader.setImageUrl( App1.pref, 0f, src.header_static, src.header );
|
||||
|
||||
etDisplayName.setText( Emojione.decodeEmoji( this, src.display_name == null ? "" : src.display_name ) );
|
||||
|
||||
String note;
|
||||
if( src.source != null && src.source.note != null ){
|
||||
note = src.source.note;
|
||||
}else{
|
||||
note = src.note;
|
||||
}
|
||||
etNote.setText( Emojione.decodeEmoji( this, note == null ? "" : note ) );
|
||||
|
||||
// 編集可能にする
|
||||
btnProfileAvatar.setEnabled( true );
|
||||
btnProfileHeader.setEnabled( true );
|
||||
etDisplayName.setEnabled( true );
|
||||
btnDisplayName.setEnabled( true );
|
||||
etNote.setEnabled( true );
|
||||
btnNote.setEnabled( true );
|
||||
}
|
||||
|
||||
void updateCredential( final String form_data ){
|
||||
final ProgressDialog progress = new ProgressDialog( this );
|
||||
|
||||
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
|
||||
|
||||
TootAccount data;
|
||||
|
||||
@Override protected TootApiResult doInBackground( Void... params ){
|
||||
TootApiClient client = new TootApiClient( ActAccountSetting.this, new TootApiClient.Callback() {
|
||||
@Override public boolean isApiCancelled(){
|
||||
return isCancelled();
|
||||
}
|
||||
|
||||
@Override public void publishApiProgress( final String s ){
|
||||
}
|
||||
} );
|
||||
client.setAccount( account );
|
||||
|
||||
Request.Builder request_builder = new Request.Builder()
|
||||
.patch( RequestBody.create(
|
||||
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED
|
||||
, form_data
|
||||
) );
|
||||
|
||||
TootApiResult result = client.request( "/api/v1/accounts/update_credentials", request_builder );
|
||||
if( result != null && result.object != null ){
|
||||
data = TootAccount.parse( ActAccountSetting.this, account, result.object );
|
||||
if( data == null ) return new TootApiResult( "TootAccount parse failed." );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled( TootApiResult result ){
|
||||
super.onPostExecute( result );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( TootApiResult result ){
|
||||
try{
|
||||
progress.dismiss();
|
||||
}catch( Throwable ignored ){
|
||||
}
|
||||
loadProfile();
|
||||
if( result == null ){
|
||||
// cancelled.
|
||||
}else if( data != null ){
|
||||
showProfile( data );
|
||||
}else{
|
||||
Utils.showToast( ActAccountSetting.this, true, result.error );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
task.executeOnExecutor( App1.task_executor );
|
||||
progress.setIndeterminate( true );
|
||||
progress.setOnDismissListener( new DialogInterface.OnDismissListener() {
|
||||
@Override public void onDismiss( DialogInterface dialog ){
|
||||
task.cancel( true );
|
||||
}
|
||||
} );
|
||||
progress.show();
|
||||
}
|
||||
|
||||
private void sendDisplayName(){
|
||||
updateCredential( "display_name=" + Uri.encode( etDisplayName.getText().toString() ) );
|
||||
}
|
||||
|
||||
private void sendNote(){
|
||||
updateCredential( "note=" + Uri.encode( etNote.getText().toString() ) );
|
||||
}
|
||||
|
||||
private static final int PERMISSION_REQUEST_AVATAR = 1;
|
||||
private static final int PERMISSION_REQUEST_HEADER = 2;
|
||||
|
||||
private void pickAvatarImage(){
|
||||
openPicker( PERMISSION_REQUEST_AVATAR );
|
||||
}
|
||||
|
||||
private void pickHeaderImage(){
|
||||
openPicker( PERMISSION_REQUEST_HEADER );
|
||||
}
|
||||
|
||||
void openPicker( final int permission_request_code ){
|
||||
int permissionCheck = ContextCompat.checkSelfPermission( this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE );
|
||||
if( permissionCheck != PackageManager.PERMISSION_GRANTED ){
|
||||
preparePermission( permission_request_code );
|
||||
return;
|
||||
}
|
||||
|
||||
ActionsDialog a = new ActionsDialog();
|
||||
a.addAction( getString( R.string.image_pick ), new Runnable() {
|
||||
@Override public void run(){
|
||||
performAttachment( permission_request_code == PERMISSION_REQUEST_AVATAR ? REQUEST_CODE_AVATAR_ATTACHMENT : REQUEST_CODE_HEADER_ATTACHMENT );
|
||||
}
|
||||
} );
|
||||
a.addAction( getString( R.string.image_capture ), new Runnable() {
|
||||
@Override public void run(){
|
||||
performCamera( permission_request_code == PERMISSION_REQUEST_AVATAR ? REQUEST_CODE_AVATAR_CAMERA : REQUEST_CODE_HEADER_CAMERA );
|
||||
}
|
||||
} );
|
||||
a.show( this, null );
|
||||
}
|
||||
|
||||
private void preparePermission( int request_code ){
|
||||
if( Build.VERSION.SDK_INT >= 23 ){
|
||||
// No explanation needed, we can request the permission.
|
||||
|
||||
ActivityCompat.requestPermissions( this
|
||||
, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE }
|
||||
, request_code
|
||||
);
|
||||
return;
|
||||
}
|
||||
Utils.showToast( this, true, R.string.missing_storage_permission );
|
||||
}
|
||||
|
||||
@Override public void onRequestPermissionsResult(
|
||||
int requestCode
|
||||
, @NonNull String permissions[]
|
||||
, @NonNull int[] grantResults
|
||||
){
|
||||
switch( requestCode ){
|
||||
case PERMISSION_REQUEST_AVATAR:
|
||||
case PERMISSION_REQUEST_HEADER:
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if( grantResults.length > 0 &&
|
||||
grantResults[ 0 ] == PackageManager.PERMISSION_GRANTED
|
||||
){
|
||||
openPicker( requestCode );
|
||||
}else{
|
||||
Utils.showToast( this, true, R.string.missing_storage_permission );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void performAttachment( final int request_code ){
|
||||
// SAFのIntentで開く
|
||||
try{
|
||||
Intent intent = new Intent( Intent.ACTION_OPEN_DOCUMENT );
|
||||
intent.addCategory( Intent.CATEGORY_OPENABLE );
|
||||
intent.setType( "*/*" );
|
||||
intent.putExtra( Intent.EXTRA_ALLOW_MULTIPLE, false );
|
||||
intent.putExtra( Intent.EXTRA_MIME_TYPES, new String[]{ "image/*", "video/*" } );
|
||||
startActivityForResult( intent
|
||||
, request_code );
|
||||
}catch( Throwable ex ){
|
||||
log.trace( ex );
|
||||
Utils.showToast( this, ex, "ACTION_OPEN_DOCUMENT failed." );
|
||||
}
|
||||
}
|
||||
|
||||
Uri uriCameraImage;
|
||||
|
||||
private void performCamera( final int request_code ){
|
||||
|
||||
try{
|
||||
// カメラで撮影
|
||||
String filename = System.currentTimeMillis() + ".jpg";
|
||||
ContentValues values = new ContentValues();
|
||||
values.put( MediaStore.Images.Media.TITLE, filename );
|
||||
values.put( MediaStore.Images.Media.MIME_TYPE, "image/jpeg" );
|
||||
uriCameraImage = getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values );
|
||||
|
||||
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
|
||||
intent.putExtra( MediaStore.EXTRA_OUTPUT, uriCameraImage );
|
||||
|
||||
startActivityForResult( intent, request_code );
|
||||
}catch( Throwable ex ){
|
||||
log.trace( ex );
|
||||
Utils.showToast( this, ex, "opening camera app failed." );
|
||||
}
|
||||
}
|
||||
|
||||
interface InputStreamOpener {
|
||||
InputStream open() throws IOException;
|
||||
|
||||
String getMimeType();
|
||||
|
||||
void deleteTempFile();
|
||||
}
|
||||
|
||||
static final String MIME_TYPE_JPEG = "image/jpeg";
|
||||
static final String MIME_TYPE_PNG = "image/png";
|
||||
|
||||
private InputStreamOpener createOpener( final Uri uri, final String mime_type ){
|
||||
//noinspection LoopStatementThatDoesntLoop
|
||||
for( ; ; ){
|
||||
try{
|
||||
|
||||
// 画像の種別
|
||||
boolean is_jpeg = MIME_TYPE_JPEG.equals( mime_type );
|
||||
boolean is_png = MIME_TYPE_PNG.equals( mime_type );
|
||||
if( ! is_jpeg && ! is_png ){
|
||||
log.d( "createOpener: source is not jpeg or png" );
|
||||
break;
|
||||
}
|
||||
|
||||
// 設定からリサイズ指定を読む
|
||||
int resize_to = 1280;
|
||||
|
||||
Bitmap bitmap = Utils.createResizedBitmap( log, this, uri, false, resize_to );
|
||||
if( bitmap != null ){
|
||||
try{
|
||||
File cache_dir = getExternalCacheDir();
|
||||
if( cache_dir == null ){
|
||||
Utils.showToast( this, false, "getExternalCacheDir returns null." );
|
||||
break;
|
||||
}
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cache_dir.mkdir();
|
||||
|
||||
final File temp_file = new File( cache_dir, "tmp." + Thread.currentThread().getId() );
|
||||
FileOutputStream os = new FileOutputStream( temp_file );
|
||||
try{
|
||||
if( is_jpeg ){
|
||||
bitmap.compress( Bitmap.CompressFormat.JPEG, 95, os );
|
||||
}else{
|
||||
bitmap.compress( Bitmap.CompressFormat.PNG, 100, os );
|
||||
}
|
||||
}finally{
|
||||
os.close();
|
||||
}
|
||||
|
||||
return new InputStreamOpener() {
|
||||
@Override public InputStream open() throws IOException{
|
||||
return new FileInputStream( temp_file );
|
||||
}
|
||||
|
||||
@Override public String getMimeType(){
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
@Override public void deleteTempFile(){
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
temp_file.delete();
|
||||
}
|
||||
};
|
||||
}finally{
|
||||
bitmap.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
}catch( Throwable ex ){
|
||||
log.trace( ex );
|
||||
Utils.showToast( this, ex, "Resizing image failed." );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return new InputStreamOpener() {
|
||||
@Override public InputStream open() throws IOException{
|
||||
return getContentResolver().openInputStream( uri );
|
||||
}
|
||||
|
||||
@Override public String getMimeType(){
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
@Override public void deleteTempFile(){
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void addAttachment( final int request_code, final Uri uri, final String mime_type ){
|
||||
|
||||
if( mime_type == null ){
|
||||
Utils.showToast( this, false, "mime type is not provided." );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! mime_type.startsWith( "image/" ) ){
|
||||
Utils.showToast( this, false, "mime type is not image." );
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask< Void, Void, String >() {
|
||||
|
||||
@Override protected String doInBackground( Void... params ){
|
||||
try{
|
||||
final InputStreamOpener opener = createOpener( uri, mime_type );
|
||||
try{
|
||||
InputStream is = opener.open();
|
||||
try{
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
//
|
||||
bao.write( Utils.encodeUTF8( "data:" + opener.getMimeType() + ";base64," ) );
|
||||
//
|
||||
Base64OutputStream base64 = new Base64OutputStream( bao, Base64.NO_WRAP );
|
||||
try{
|
||||
IOUtils.copy( is, base64 );
|
||||
}finally{
|
||||
base64.close();
|
||||
}
|
||||
String value = Utils.decodeUTF8( bao.toByteArray() );
|
||||
|
||||
switch( request_code ){
|
||||
case REQUEST_CODE_AVATAR_ATTACHMENT:
|
||||
case REQUEST_CODE_AVATAR_CAMERA:
|
||||
return "avatar=" + Uri.encode( value );
|
||||
case REQUEST_CODE_HEADER_ATTACHMENT:
|
||||
case REQUEST_CODE_HEADER_CAMERA:
|
||||
return "header=" + Uri.encode( value );
|
||||
}
|
||||
}finally{
|
||||
IOUtils.closeQuietly( is );
|
||||
}
|
||||
}finally{
|
||||
opener.deleteTempFile();
|
||||
}
|
||||
|
||||
}catch( Throwable ex ){
|
||||
Utils.showToast( ActAccountSetting.this, ex, "image converting failed." );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute( String form_data ){
|
||||
if( form_data != null ){
|
||||
updateCredential( form_data );
|
||||
}
|
||||
}
|
||||
|
||||
}.executeOnExecutor( App1.task_executor );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1323,10 +1323,10 @@ class Column implements StreamReader.Callback {
|
||||
return getStatuses( client, PATH_FEDERATE );
|
||||
|
||||
case TYPE_PROFILE:
|
||||
if( who_account == null ){
|
||||
parseAccount1( client, String.format( Locale.JAPAN, PATH_ACCOUNT, profile_id ) );
|
||||
client.callback.publishApiProgress( "" );
|
||||
}
|
||||
|
||||
parseAccount1( client, String.format( Locale.JAPAN, PATH_ACCOUNT, profile_id ) );
|
||||
client.callback.publishApiProgress( "" );
|
||||
|
||||
switch( profile_tab ){
|
||||
|
||||
default:
|
||||
|
@ -28,6 +28,7 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
private final ImageButton btnFollow;
|
||||
private final ImageView ivFollowedBy;
|
||||
private final View llProfile;
|
||||
private final TextView tvRemoteProfileWarning;
|
||||
|
||||
private TootAccount who;
|
||||
|
||||
@ -49,13 +50,15 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
View btnMore = viewRoot.findViewById( R.id.btnMore );
|
||||
btnFollow = (ImageButton) viewRoot.findViewById( R.id.btnFollow );
|
||||
ivFollowedBy = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy );
|
||||
|
||||
tvRemoteProfileWarning = (TextView) viewRoot.findViewById( R.id.tvRemoteProfileWarning );
|
||||
|
||||
ivBackground.setOnClickListener( this );
|
||||
btnFollowing.setOnClickListener( this );
|
||||
btnFollowers.setOnClickListener( this );
|
||||
btnStatusCount.setOnClickListener( this );
|
||||
btnMore.setOnClickListener( this );
|
||||
btnFollow.setOnClickListener( this );
|
||||
tvRemoteProfileWarning.setOnClickListener( this );
|
||||
|
||||
btnFollow.setOnLongClickListener( this );
|
||||
|
||||
@ -77,6 +80,7 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
|
||||
showColor();
|
||||
|
||||
|
||||
if( who == null ){
|
||||
tvCreated.setText( "" );
|
||||
ivBackground.setImageDrawable( null );
|
||||
@ -89,11 +93,14 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + "?" );
|
||||
|
||||
btnFollow.setImageDrawable( null );
|
||||
tvRemoteProfileWarning.setVisibility( View.GONE );
|
||||
}else{
|
||||
tvCreated.setText( TootStatus.formatTime( who.time_created_at ) );
|
||||
ivBackground.setImageUrl( activity.pref, 0f,access_info.supplyBaseUrl( who.header_static ) );
|
||||
ivAvatar.setImageUrl( activity.pref, 16f,access_info.supplyBaseUrl( who.avatar_static ) , access_info.supplyBaseUrl( who.avatar ));
|
||||
tvDisplayName.setText( who.decoded_display_name );
|
||||
|
||||
tvRemoteProfileWarning.setVisibility( column.access_info.isRemoteUser(who) ? View.VISIBLE : View.GONE );
|
||||
|
||||
String s = "@" + access_info.getFullAcct( who );
|
||||
if( who.locked ){
|
||||
@ -117,6 +124,7 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
switch( v.getId() ){
|
||||
|
||||
case R.id.ivBackground:
|
||||
case R.id.tvRemoteProfileWarning:
|
||||
if( who != null ){
|
||||
// 強制的にブラウザで開く
|
||||
activity.openChromeTab( activity.nextPosition( column ), access_info, who.url, true );
|
||||
@ -152,6 +160,7 @@ class HeaderViewHolderProfile extends HeaderViewHolderBase implements View.OnCli
|
||||
new DlgContextMenu( activity, column, who, null, null ).show();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -27,6 +29,7 @@ import jp.juggler.subwaytooter.table.ContentWarning;
|
||||
import jp.juggler.subwaytooter.table.MediaShown;
|
||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||
import jp.juggler.subwaytooter.table.UserRelation;
|
||||
import jp.juggler.subwaytooter.util.EmojiImageSpan;
|
||||
import jp.juggler.subwaytooter.util.LogCategory;
|
||||
import jp.juggler.subwaytooter.view.MyLinkMovementMethod;
|
||||
import jp.juggler.subwaytooter.view.MyListView;
|
||||
@ -377,7 +380,21 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||
this.status = status;
|
||||
llStatus.setVisibility( View.VISIBLE );
|
||||
|
||||
tvTime.setText( TootStatus.formatTime( status.time_created_at ) );
|
||||
if( status instanceof MSPToot ){
|
||||
tvTime.setText( TootStatus.formatTime( status.time_created_at ) );
|
||||
}else if( status instanceof TootStatus ){
|
||||
TootStatus ts = (TootStatus) status;
|
||||
int icon_id = Styler.getVisibilityIcon( activity, ts.visibility );
|
||||
|
||||
SpannableStringBuilder sb = new SpannableStringBuilder( );
|
||||
int start = sb.length();
|
||||
sb.append(ts.visibility);
|
||||
int end = sb.length();
|
||||
sb.setSpan( new EmojiImageSpan( activity, icon_id ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
|
||||
sb.append(' ');
|
||||
sb.append(TootStatus.formatTime( status.time_created_at ));
|
||||
tvTime.setText(sb);
|
||||
}
|
||||
|
||||
account_thumbnail = status.account;
|
||||
setAcct( tvAcct, access_info.getFullAcct( status.account ) );
|
||||
|
@ -464,6 +464,24 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
return "?@?";
|
||||
}
|
||||
|
||||
public boolean isLocalUser( @NonNull TootAccount who ){
|
||||
return isLocalUser(who.acct);
|
||||
}
|
||||
|
||||
public boolean isLocalUser( @NonNull String acct ){
|
||||
int delm = acct.indexOf( '@' );
|
||||
if( delm == -1 ) return true;
|
||||
return host.equalsIgnoreCase( acct.substring( delm+1 ) );
|
||||
}
|
||||
|
||||
public boolean isRemoteUser( @NonNull TootAccount who ){
|
||||
return ! isLocalUser(who);
|
||||
}
|
||||
|
||||
public boolean isRemoteUser( @NonNull String acct ){
|
||||
return ! isLocalUser(acct);
|
||||
}
|
||||
|
||||
public String getUserUrl( @NonNull String who_acct ){
|
||||
int p = who_acct.indexOf( '@' );
|
||||
if( - 1 != p ){
|
||||
@ -581,4 +599,5 @@ public class SavedAccount extends TootAccount implements LinkClickContext {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import android.text.style.ReplacementSpan;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
class EmojiImageSpan extends ReplacementSpan {
|
||||
public class EmojiImageSpan extends ReplacementSpan {
|
||||
|
||||
static DynamicDrawableSpan x = null;
|
||||
|
||||
@ -28,7 +28,7 @@ class EmojiImageSpan extends ReplacementSpan {
|
||||
private final int res_id;
|
||||
private WeakReference< Drawable > mDrawableRef;
|
||||
|
||||
EmojiImageSpan( @NonNull Context context, int res_id ){
|
||||
public EmojiImageSpan( @NonNull Context context, int res_id ){
|
||||
super();
|
||||
this.context = context.getApplicationContext();
|
||||
this.res_id = res_id;
|
||||
|
@ -53,6 +53,7 @@ public class MyNetworkImageView extends AppCompatImageView {
|
||||
|
||||
public void setDefaultImageResId( int defaultImage ){
|
||||
mDefaultImageId = defaultImage;
|
||||
loadImageIfNecessary();
|
||||
}
|
||||
|
||||
// エラー時に表示するDrawableのリソースID
|
||||
@ -60,6 +61,7 @@ public class MyNetworkImageView extends AppCompatImageView {
|
||||
|
||||
public void setErrorImageResId( int errorImage ){
|
||||
mErrorImageId = errorImage;
|
||||
loadImageIfNecessary();
|
||||
}
|
||||
|
||||
// 角丸の半径。元画像の短辺に対する割合を指定するらしい
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_question.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_question_dark.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_question.png
Normal file
After Width: | Height: | Size: 732 B |
BIN
app/src/main/res/drawable-mdpi/ic_question_dark.png
Normal file
After Width: | Height: | Size: 648 B |
BIN
app/src/main/res/drawable-xhdpi/ic_question.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_question_dark.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_question.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_question_dark.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
@ -2,15 +2,15 @@
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/svContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:id="@+id/svContent"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingBottom="128dp"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingBottom="128dp"
|
||||
android:paddingTop="12dp"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
|
||||
>
|
||||
|
||||
@ -60,25 +60,128 @@
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/nickname_label"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvUserCustom"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:padding="4dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
|
||||
android:padding="4dp"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_marginStart="4dp"
|
||||
android:id="@+id/btnUserCustom"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/btn_bg_transparent"
|
||||
android:contentDescription="@string/edit"
|
||||
android:src="?attr/ic_edit"
|
||||
android:id="@+id/btnUserCustom"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<View style="@style/setting_divider"/>
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:text="@string/public_profile"
|
||||
/>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
<FrameLayout
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:layout_height="64dp"
|
||||
>
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
android:id="@+id/ivProfileHeader"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
<jp.juggler.subwaytooter.view.MyNetworkImageView
|
||||
android:id="@+id/ivProfileAvatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitCenter"
|
||||
/>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnProfileAvatar"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:text="@string/change_avatar"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnProfileHeader"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:text="@string/change_header"
|
||||
android:textAllCaps="false"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:labelFor="@+id/etDisplayName"
|
||||
android:text="@string/display_name"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etDisplayName"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:inputType="text"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnDisplayName"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/btn_bg_transparent"
|
||||
android:contentDescription="@string/post"
|
||||
android:src="?attr/btn_post"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<TextView
|
||||
style="@style/setting_row_label"
|
||||
android:labelFor="@+id/etNote"
|
||||
android:text="@string/note"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/etNote"
|
||||
style="@style/setting_horizontal_stretch"
|
||||
android:inputType="textMultiLine"
|
||||
/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btnNote"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="@drawable/btn_bg_transparent"
|
||||
android:contentDescription="@string/post"
|
||||
android:src="?attr/btn_post"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
@ -112,6 +215,7 @@
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
@ -123,6 +227,7 @@
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout style="@style/setting_row_form">
|
||||
|
||||
<Button
|
||||
|
@ -153,5 +153,13 @@
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:text="@string/remote_profile_warning"
|
||||
android:id="@+id/tvRemoteProfileWarning"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/btn_bg_transparent"
|
||||
/>
|
||||
</LinearLayout>
|
@ -414,8 +414,14 @@
|
||||
<string name="enable_gif_animation">Enable GIF animation (It wastes the battery very much)</string>
|
||||
<string name="acct_sample">(sample)username@instance</string>
|
||||
<string name="mention_full_acct">Show mention as full acct (app restart required)</string>
|
||||
<string name="remote_profile_warning">Remote users\' profile may be inadequate information. You can check more accurate information on the web page.</string>
|
||||
<string name="public_profile">Public profile</string>
|
||||
<string name="change_avatar">Change avatar icon</string>
|
||||
<string name="change_header">Change header image</string>
|
||||
<string name="display_name">Display name</string>
|
||||
<string name="note">Note</string>
|
||||
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
|
||||
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->
|
||||
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
|
||||
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->
|
||||
|
@ -701,5 +701,11 @@
|
||||
<string name="acct_sample">(見本)username@instance</string>
|
||||
<string name="enable_gif_animation">GIFアニメーションを有効にする(バッテリーをとても浪費します)</string>
|
||||
<string name="mention_full_acct">メンションのインスタンス名部分を省略しない(アプリ再起動が必要)</string>
|
||||
<string name="remote_profile_warning">リモートユーザのプロフィールは情報が不十分な可能性があります。より正確な情報をWebページで確認することができます。</string>
|
||||
<string name="change_avatar">アバター画像を変更</string>
|
||||
<string name="change_header">ヘッダー画像を変更</string>
|
||||
<string name="display_name">表示名</string>
|
||||
<string name="note">ノート</string>
|
||||
<string name="public_profile">公開プロフィール</string>
|
||||
|
||||
</resources>
|
||||
|
@ -117,5 +117,6 @@
|
||||
<attr name="ic_domain_block" format="reference" />
|
||||
|
||||
<attr name="ic_nicoru" format="reference" />
|
||||
<attr name="ic_question" format="reference" />
|
||||
|
||||
</resources>
|
@ -409,5 +409,11 @@
|
||||
<string name="enable_gif_animation">Enable GIF animation (It wastes the battery very much)</string>
|
||||
<string name="acct_sample">(sample)username@instance</string>
|
||||
<string name="mention_full_acct">Show mention as full acct (app restart required)</string>
|
||||
<string name="remote_profile_warning">Remote users\' profile may be inadequate information. You can check more accurate information on the web page.</string>
|
||||
<string name="public_profile">Public profile</string>
|
||||
<string name="change_avatar">Change avatar icon</string>
|
||||
<string name="change_header">Change header image</string>
|
||||
<string name="display_name">Display name</string>
|
||||
<string name="note">Note</string>
|
||||
|
||||
</resources>
|
||||
|
@ -87,6 +87,7 @@
|
||||
<item name="ic_domain_block">@drawable/ic_domain_block</item>
|
||||
|
||||
<item name="ic_nicoru">@drawable/ic_nicoru</item>
|
||||
<item name="ic_question">@drawable/ic_question</item>
|
||||
|
||||
|
||||
</style>
|
||||
@ -179,6 +180,7 @@
|
||||
<item name="ic_domain_block">@drawable/ic_domain_block_dark</item>
|
||||
|
||||
<item name="ic_nicoru">@drawable/ic_nicoru_dark</item>
|
||||
<item name="ic_question">@drawable/ic_question_dark</item>
|
||||
|
||||
</style>
|
||||
|
||||
|