投稿画面でメンションの入力補完
This commit is contained in:
parent
a4ef01503e
commit
92fa93fedd
|
@ -37,7 +37,7 @@
|
||||||
<ConfirmationsSetting value="0" id="Add" />
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
<ConfirmationsSetting value="0" id="Remove" />
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
@ -9,8 +9,8 @@ android {
|
||||||
applicationId "jp.juggler.subwaytooter"
|
applicationId "jp.juggler.subwaytooter"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 25
|
versionCode 26
|
||||||
versionName "0.2.5"
|
versionName "0.2.6"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,17 @@ public class ActMain extends AppCompatActivity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColumnViewHolder.ListItemPopup list_item_popup;
|
||||||
|
void closeListItemPopup(){
|
||||||
|
if( list_item_popup != null ){
|
||||||
|
list_item_popup.dismiss();
|
||||||
|
list_item_popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override protected void onPause(){
|
@Override protected void onPause(){
|
||||||
|
closeListItemPopup();
|
||||||
|
|
||||||
HTMLDecoder.link_callback = null;
|
HTMLDecoder.link_callback = null;
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,24 +4,34 @@ import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.provider.OpenableColumns;
|
import android.provider.OpenableColumns;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.os.AsyncTaskCompat;
|
import android.support.v4.os.AsyncTaskCompat;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
import android.text.Layout;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.CheckedTextView;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.volley.toolbox.NetworkImageView;
|
import com.android.volley.toolbox.NetworkImageView;
|
||||||
|
@ -41,9 +51,11 @@ import jp.juggler.subwaytooter.api.TootApiResult;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootAttachment;
|
import jp.juggler.subwaytooter.api.entity.TootAttachment;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootMention;
|
import jp.juggler.subwaytooter.api.entity.TootMention;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.table.AcctSet;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
import jp.juggler.subwaytooter.util.HTMLDecoder;
|
||||||
import jp.juggler.subwaytooter.util.LogCategory;
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
import jp.juggler.subwaytooter.util.MyEditText;
|
||||||
import jp.juggler.subwaytooter.util.Utils;
|
import jp.juggler.subwaytooter.util.Utils;
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.MultipartBody;
|
import okhttp3.MultipartBody;
|
||||||
|
@ -141,10 +153,13 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
super.onActivityResult( requestCode, resultCode, data );
|
super.onActivityResult( requestCode, resultCode, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedPreferences pref;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate( @Nullable Bundle savedInstanceState ){
|
protected void onCreate( @Nullable Bundle savedInstanceState ){
|
||||||
super.onCreate( savedInstanceState );
|
super.onCreate( savedInstanceState );
|
||||||
App1.setActivityTheme( this, true );
|
App1.setActivityTheme( this, true );
|
||||||
|
pref = Pref.pref( this );
|
||||||
initUI();
|
initUI();
|
||||||
|
|
||||||
if( account_list.isEmpty() ){
|
if( account_list.isEmpty() ){
|
||||||
|
@ -296,6 +311,12 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
showReplyTo();
|
showReplyTo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override protected void onDestroy(){
|
||||||
|
handler.removeCallbacks( proc_text_changed );
|
||||||
|
closeAcctPopup();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState( Bundle outState ){
|
protected void onSaveInstanceState( Bundle outState ){
|
||||||
if( account != null ){
|
if( account != null ){
|
||||||
|
@ -326,12 +347,13 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
View btnAttachment;
|
View btnAttachment;
|
||||||
View btnPost;
|
View btnPost;
|
||||||
View llAttachment;
|
View llAttachment;
|
||||||
final NetworkImageView[] ivMedia = new NetworkImageView[4];
|
final NetworkImageView[] ivMedia = new NetworkImageView[ 4 ];
|
||||||
CheckBox cbNSFW;
|
CheckBox cbNSFW;
|
||||||
CheckBox cbContentWarning;
|
CheckBox cbContentWarning;
|
||||||
EditText etContentWarning;
|
MyEditText etContentWarning;
|
||||||
EditText etContent;
|
MyEditText etContent;
|
||||||
TextView tvCharCount;
|
TextView tvCharCount;
|
||||||
|
Handler handler;
|
||||||
|
|
||||||
ArrayList< SavedAccount > account_list;
|
ArrayList< SavedAccount > account_list;
|
||||||
|
|
||||||
|
@ -342,20 +364,21 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
|
|
||||||
private void initUI(){
|
private void initUI(){
|
||||||
setContentView( R.layout.act_post );
|
setContentView( R.layout.act_post );
|
||||||
|
handler = new Handler();
|
||||||
|
|
||||||
btnAccount = (Button) findViewById( R.id.btnAccount );
|
btnAccount = (Button) findViewById( R.id.btnAccount );
|
||||||
btnVisibility = (ImageButton) findViewById( R.id.btnVisibility );
|
btnVisibility = (ImageButton) findViewById( R.id.btnVisibility );
|
||||||
btnAttachment = findViewById( R.id.btnAttachment );
|
btnAttachment = findViewById( R.id.btnAttachment );
|
||||||
btnPost = findViewById( R.id.btnPost );
|
btnPost = findViewById( R.id.btnPost );
|
||||||
llAttachment = findViewById( R.id.llAttachment );
|
llAttachment = findViewById( R.id.llAttachment );
|
||||||
ivMedia[0] = (NetworkImageView) findViewById( R.id.ivMedia1 );
|
ivMedia[ 0 ] = (NetworkImageView) findViewById( R.id.ivMedia1 );
|
||||||
ivMedia[1] = (NetworkImageView) findViewById( R.id.ivMedia2 );
|
ivMedia[ 1 ] = (NetworkImageView) findViewById( R.id.ivMedia2 );
|
||||||
ivMedia[2] = (NetworkImageView) findViewById( R.id.ivMedia3 );
|
ivMedia[ 2 ] = (NetworkImageView) findViewById( R.id.ivMedia3 );
|
||||||
ivMedia[3] = (NetworkImageView) findViewById( R.id.ivMedia4 );
|
ivMedia[ 3 ] = (NetworkImageView) findViewById( R.id.ivMedia4 );
|
||||||
cbNSFW = (CheckBox) findViewById( R.id.cbNSFW );
|
cbNSFW = (CheckBox) findViewById( R.id.cbNSFW );
|
||||||
cbContentWarning = (CheckBox) findViewById( R.id.cbContentWarning );
|
cbContentWarning = (CheckBox) findViewById( R.id.cbContentWarning );
|
||||||
etContentWarning = (EditText) findViewById( R.id.etContentWarning );
|
etContentWarning = (MyEditText) findViewById( R.id.etContentWarning );
|
||||||
etContent = (EditText) findViewById( R.id.etContent );
|
etContent = (MyEditText) findViewById( R.id.etContent );
|
||||||
tvCharCount = (TextView) findViewById( R.id.tvCharCount );
|
tvCharCount = (TextView) findViewById( R.id.tvCharCount );
|
||||||
|
|
||||||
llReply = findViewById( R.id.llReply );
|
llReply = findViewById( R.id.llReply );
|
||||||
|
@ -377,10 +400,10 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
btnPost.setOnClickListener( this );
|
btnPost.setOnClickListener( this );
|
||||||
btnRemoveReply.setOnClickListener( this );
|
btnRemoveReply.setOnClickListener( this );
|
||||||
|
|
||||||
for( NetworkImageView iv :ivMedia){
|
for( NetworkImageView iv : ivMedia ){
|
||||||
iv.setOnClickListener( this );
|
iv.setOnClickListener( this );
|
||||||
iv.setDefaultImageResId( Styler.getAttributeResourceId( this,R.attr.btn_refresh ));
|
iv.setDefaultImageResId( Styler.getAttributeResourceId( this, R.attr.btn_refresh ) );
|
||||||
// iv.setErrorImageResId( Styler.getAttributeResourceId( this,R.attr.btn_refresh ));
|
// iv.setErrorImageResId( Styler.getAttributeResourceId( this,R.attr.btn_refresh ));
|
||||||
}
|
}
|
||||||
|
|
||||||
cbContentWarning.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
cbContentWarning.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@ -398,7 +421,11 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTextChanged( CharSequence s, int start, int before, int count ){
|
public void onTextChanged( CharSequence s, int start, int before, int count ){
|
||||||
|
if( count > 0 ){
|
||||||
|
log.d( "onTextChanged" );
|
||||||
|
handler.removeCallbacks( proc_text_changed );
|
||||||
|
handler.postDelayed( proc_text_changed, 1500L );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -406,13 +433,176 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
updateTextCount();
|
updateTextCount();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
etContent.setOnSelectionChangeListener( new MyEditText.OnSelectionChangeListener() {
|
||||||
|
int last_selection = - 1;
|
||||||
|
|
||||||
|
@Override public void onSelectionChanged( int selStart, int selEnd ){
|
||||||
|
if( selStart != selEnd ){
|
||||||
|
// 範囲選択されてるならポップアップは閉じる
|
||||||
|
log.d( "onSelectionChanged: range selected" );
|
||||||
|
closeAcctPopup();
|
||||||
|
}else if( selStart > last_selection ){
|
||||||
|
// 文字挿入の直後かもしれないので何もしない
|
||||||
|
log.d( "onSelectionChanged: may after text input? " );
|
||||||
|
}else{
|
||||||
|
// 前方への移動ではないならポップアップは閉じる
|
||||||
|
log.d( "onSelectionChanged: not forward change" );
|
||||||
|
closeAcctPopup();
|
||||||
|
}
|
||||||
|
last_selection = selStart;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
final Runnable proc_text_changed = new Runnable() {
|
||||||
|
@Override public void run(){
|
||||||
|
int ss = etContent.getSelectionStart();
|
||||||
|
int se = etContent.getSelectionEnd();
|
||||||
|
if( ss != se ){
|
||||||
|
closeAcctPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int end = ss;
|
||||||
|
String src = etContent.getText().toString();
|
||||||
|
int start = ss;
|
||||||
|
int count_atMark = 0;
|
||||||
|
int[] pos_atMark = new int[ 2 ];
|
||||||
|
for( ; ; ){
|
||||||
|
if( start == 0 ) break;
|
||||||
|
if( count_atMark >= 2 ) break;
|
||||||
|
char c = src.charAt( start - 1 );
|
||||||
|
if( ( '0' <= c && c <= '9' )
|
||||||
|
|| ( 'A' <= c && c <= 'Z' )
|
||||||
|
|| ( 'a' <= c && c <= 'z' )
|
||||||
|
|| c == '_'
|
||||||
|
){
|
||||||
|
-- start;
|
||||||
|
continue;
|
||||||
|
}else if( c == '@' ){
|
||||||
|
-- start;
|
||||||
|
pos_atMark[ count_atMark++ ] = start;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( count_atMark == 0 ){
|
||||||
|
closeAcctPopup();
|
||||||
|
return;
|
||||||
|
}else if( count_atMark == 1 ){
|
||||||
|
start = pos_atMark[ 0 ];
|
||||||
|
}else if( count_atMark == 2 ){
|
||||||
|
start = pos_atMark[ 1 ];
|
||||||
|
}
|
||||||
|
if( end - start < 2 ){
|
||||||
|
closeAcctPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int limit = 10;
|
||||||
|
String s = src.substring( start, end );
|
||||||
|
ArrayList< String > acct_list = AcctSet.searchPrefix( s, limit );
|
||||||
|
log.d( "search for %s, result=%d", s, acct_list.size() );
|
||||||
|
if( acct_list.isEmpty() || acct_list.size() >= limit ){
|
||||||
|
closeAcctPopup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openAcctPopup( acct_list, start, end );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PopupWindow acct_popup;
|
||||||
|
|
||||||
|
private void closeAcctPopup(){
|
||||||
|
if( acct_popup != null ){
|
||||||
|
acct_popup.dismiss();
|
||||||
|
acct_popup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openAcctPopup( ArrayList< String > acct_list, final int start, final int end ){
|
||||||
|
closeAcctPopup();
|
||||||
|
View viewRoot = getLayoutInflater().inflate( R.layout.acct_complete_popup, null, false );
|
||||||
|
LinearLayout llItems = (LinearLayout) viewRoot.findViewById( R.id.llItems );
|
||||||
|
{
|
||||||
|
CheckedTextView v = (CheckedTextView) getLayoutInflater().inflate( R.layout.lv_spinner_dropdown, llItems, false );
|
||||||
|
v.setTextColor( Styler.getAttributeColor( this, android.R.attr.textColorPrimary ) );
|
||||||
|
v.setText( R.string.close );
|
||||||
|
v.setOnClickListener( new View.OnClickListener() {
|
||||||
|
@Override public void onClick( View v ){
|
||||||
|
closeAcctPopup();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
llItems.addView( v );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0 ; ; ++ i ){
|
||||||
|
if( i >= acct_list.size() ) break;
|
||||||
|
final String acct = acct_list.get( i );
|
||||||
|
CheckedTextView v = (CheckedTextView) getLayoutInflater().inflate( R.layout.lv_spinner_dropdown, llItems, false );
|
||||||
|
v.setTextColor( Styler.getAttributeColor( this, android.R.attr.textColorPrimary ) );
|
||||||
|
v.setText( acct );
|
||||||
|
v.setOnClickListener( new View.OnClickListener() {
|
||||||
|
@Override public void onClick( View v ){
|
||||||
|
String s = etContent.getText().toString();
|
||||||
|
s = s.substring( 0, start ) + acct + " " + ( end >= s.length() ? "" : s.substring( end ) );
|
||||||
|
etContent.setText( s );
|
||||||
|
etContent.setSelection( start + acct.length() + 1 );
|
||||||
|
closeAcctPopup();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
llItems.addView( v );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
acct_popup = new PopupWindow( this );
|
||||||
|
acct_popup.setBackgroundDrawable( ContextCompat.getDrawable( this, R.drawable.acct_popup_bg ) );
|
||||||
|
|
||||||
|
// Resources.Theme popupTheme = getResources().newTheme();
|
||||||
|
//
|
||||||
|
// int theme_idx = pref.getInt(Pref.KEY_UI_THEME,0);
|
||||||
|
// switch(theme_idx){
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// case 0:
|
||||||
|
// popupTheme.applyStyle( R.style.Theme_AppCompat_Light_Dialog, true);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case 1:
|
||||||
|
// popupTheme.applyStyle( R.style.Theme_AppCompat_Dialog, true);
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
|
||||||
|
acct_popup.setWidth( WindowManager.LayoutParams.WRAP_CONTENT );
|
||||||
|
acct_popup.setHeight( WindowManager.LayoutParams.WRAP_CONTENT );
|
||||||
|
acct_popup.setContentView( viewRoot );
|
||||||
|
acct_popup.setTouchable( true );
|
||||||
|
|
||||||
|
int[] location = new int[ 2 ];
|
||||||
|
|
||||||
|
etContent.getLocationOnScreen( location );
|
||||||
|
int y = location[ 1 ];
|
||||||
|
y += etContent.getTotalPaddingTop();
|
||||||
|
y -= etContent.getScrollY();
|
||||||
|
Layout layout = etContent.getLayout();
|
||||||
|
y += layout.getLineBottom( layout.getLineCount() - 1 );
|
||||||
|
|
||||||
|
acct_popup.showAtLocation(
|
||||||
|
etContent
|
||||||
|
, Gravity.CENTER_HORIZONTAL | Gravity.TOP
|
||||||
|
, 0
|
||||||
|
, y
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateTextCount(){
|
private void updateTextCount(){
|
||||||
String s = etContent.getText().toString();
|
String s = etContent.getText().toString();
|
||||||
int count = s.codePointCount( 0,s.length() );
|
int count_content = s.codePointCount( 0, s.length() );
|
||||||
int remain = 500 - count;
|
s = cbContentWarning.isChecked() ? etContentWarning.getText().toString() : "";
|
||||||
tvCharCount.setText( Integer.toString( remain ) );
|
int count_spoiler = s.codePointCount( 0, s.length() );
|
||||||
|
|
||||||
|
int remain = 500 - count_content - count_spoiler;
|
||||||
|
tvCharCount.setText( Integer.toString( remain ) );
|
||||||
int color = Styler.getAttributeColor( this, remain < 0 ? R.attr.colorRegexFilterError : android.R.attr.textColorPrimary );
|
int color = Styler.getAttributeColor( this, remain < 0 ? R.attr.colorRegexFilterError : android.R.attr.textColorPrimary );
|
||||||
tvCharCount.setTextColor( color );
|
tvCharCount.setTextColor( color );
|
||||||
}
|
}
|
||||||
|
@ -463,7 +653,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
@Override
|
@Override
|
||||||
public void onClick( DialogInterface dialog, int which ){
|
public void onClick( DialogInterface dialog, int which ){
|
||||||
if( which >= 0 && which < tmp_account_list.size() ){
|
if( which >= 0 && which < tmp_account_list.size() ){
|
||||||
SavedAccount account =tmp_account_list.get( which );
|
SavedAccount account = tmp_account_list.get( which );
|
||||||
setAccount( account );
|
setAccount( account );
|
||||||
try{
|
try{
|
||||||
if( account.visibility != null && TootStatus.compareVisibility( visibility, account.visibility ) > 0 ){
|
if( account.visibility != null && TootStatus.compareVisibility( visibility, account.visibility ) > 0 ){
|
||||||
|
@ -471,8 +661,8 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
visibility = account.visibility;
|
visibility = account.visibility;
|
||||||
showVisibility();
|
showVisibility();
|
||||||
}
|
}
|
||||||
}catch(Throwable ex){
|
}catch( Throwable ex ){
|
||||||
ex.printStackTrace( );
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -499,8 +689,8 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
llAttachment.setVisibility( View.GONE );
|
llAttachment.setVisibility( View.GONE );
|
||||||
}else{
|
}else{
|
||||||
llAttachment.setVisibility( View.VISIBLE );
|
llAttachment.setVisibility( View.VISIBLE );
|
||||||
for(int i=0,ie=ivMedia.length;i<ie;++i){
|
for( int i = 0, ie = ivMedia.length ; i < ie ; ++ i ){
|
||||||
showAttachment_sub( ivMedia[i], i );
|
showAttachment_sub( ivMedia[ i ], i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,7 +814,8 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
@Override
|
@Override
|
||||||
public void writeTo( BufferedSink sink ) throws IOException{
|
public void writeTo( BufferedSink sink ) throws IOException{
|
||||||
InputStream is = getContentResolver().openInputStream( uri );
|
InputStream is = getContentResolver().openInputStream( uri );
|
||||||
if( is == null ) throw new IOException( "openInputStream() failed. uri="+uri );
|
if( is == null )
|
||||||
|
throw new IOException( "openInputStream() failed. uri=" + uri );
|
||||||
try{
|
try{
|
||||||
byte[] tmp = new byte[ 4096 ];
|
byte[] tmp = new byte[ 4096 ];
|
||||||
for( ; ; ){
|
for( ; ; ){
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.android.volley.RequestQueue;
|
||||||
import com.android.volley.toolbox.ImageLoader;
|
import com.android.volley.toolbox.ImageLoader;
|
||||||
import com.android.volley.toolbox.Volley;
|
import com.android.volley.toolbox.Volley;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.table.AcctSet;
|
||||||
import jp.juggler.subwaytooter.table.MutedApp;
|
import jp.juggler.subwaytooter.table.MutedApp;
|
||||||
import jp.juggler.subwaytooter.table.ClientInfo;
|
import jp.juggler.subwaytooter.table.ClientInfo;
|
||||||
import jp.juggler.subwaytooter.table.ContentWarning;
|
import jp.juggler.subwaytooter.table.ContentWarning;
|
||||||
|
@ -33,11 +34,12 @@ public class App1 extends Application {
|
||||||
|
|
||||||
|
|
||||||
static final String DB_NAME = "app_db";
|
static final String DB_NAME = "app_db";
|
||||||
static final int DB_VERSION = 6;
|
static final int DB_VERSION = 7;
|
||||||
// 2017/4/25 v10 1=>2 SavedAccount に通知設定を追加
|
// 2017/4/25 v10 1=>2 SavedAccount に通知設定を追加
|
||||||
// 2017/4/25 v10 1=>2 NotificationTracking テーブルを追加
|
// 2017/4/25 v10 1=>2 NotificationTracking テーブルを追加
|
||||||
// 2017/4/29 v20 2=>5 MediaShown,ContentWarningのインデクスが間違っていたので貼り直す
|
// 2017/4/29 v20 2=>5 MediaShown,ContentWarningのインデクスが間違っていたので貼り直す
|
||||||
// 2017/4/29 v23 5=>6 MutedAppテーブルの追加、UserRelationテーブルの追加
|
// 2017/4/29 v23 5=>6 MutedAppテーブルの追加、UserRelationテーブルの追加
|
||||||
|
// 2017/5/01 v26 6=>7 AcctSetテーブルの追加
|
||||||
static DBOpenHelper db_open_helper;
|
static DBOpenHelper db_open_helper;
|
||||||
|
|
||||||
public static SQLiteDatabase getDB(){
|
public static SQLiteDatabase getDB(){
|
||||||
|
@ -77,6 +79,7 @@ public class App1 extends Application {
|
||||||
NotificationTracking.onDBCreate(db);
|
NotificationTracking.onDBCreate(db);
|
||||||
MutedApp.onDBCreate(db);
|
MutedApp.onDBCreate(db);
|
||||||
UserRelation.onDBCreate(db);
|
UserRelation.onDBCreate(db);
|
||||||
|
AcctSet.onDBCreate( db );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,6 +93,7 @@ public class App1 extends Application {
|
||||||
NotificationTracking.onDBUpgrade( db, oldVersion, newVersion );
|
NotificationTracking.onDBUpgrade( db, oldVersion, newVersion );
|
||||||
MutedApp.onDBUpgrade( db, oldVersion, newVersion );
|
MutedApp.onDBUpgrade( db, oldVersion, newVersion );
|
||||||
UserRelation.onDBUpgrade( db, oldVersion, newVersion );
|
UserRelation.onDBUpgrade( db, oldVersion, newVersion );
|
||||||
|
AcctSet.onDBUpgrade( db, oldVersion, newVersion );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +186,8 @@ public class App1 extends Application {
|
||||||
// SQLiteDatabase db = db_open_helper.getWritableDatabase();
|
// SQLiteDatabase db = db_open_helper.getWritableDatabase();
|
||||||
// db_open_helper.onCreate( db );
|
// db_open_helper.onCreate( db );
|
||||||
// }
|
// }
|
||||||
|
UserRelation.deleteOld(System.currentTimeMillis());
|
||||||
|
AcctSet.deleteOld(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
if( image_loader == null ){
|
if( image_loader == null ){
|
||||||
|
|
|
@ -31,6 +31,7 @@ import jp.juggler.subwaytooter.api.entity.TootRelationShip;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootReport;
|
import jp.juggler.subwaytooter.api.entity.TootReport;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootResults;
|
import jp.juggler.subwaytooter.api.entity.TootResults;
|
||||||
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
import jp.juggler.subwaytooter.api.entity.TootStatus;
|
||||||
|
import jp.juggler.subwaytooter.table.AcctSet;
|
||||||
import jp.juggler.subwaytooter.table.MutedApp;
|
import jp.juggler.subwaytooter.table.MutedApp;
|
||||||
import jp.juggler.subwaytooter.table.SavedAccount;
|
import jp.juggler.subwaytooter.table.SavedAccount;
|
||||||
import jp.juggler.subwaytooter.table.UserRelation;
|
import jp.juggler.subwaytooter.table.UserRelation;
|
||||||
|
@ -51,6 +52,7 @@ class Column {
|
||||||
private static final long LOOP_TIMEOUT = 10000L;
|
private static final long LOOP_TIMEOUT = 10000L;
|
||||||
private static final int LOOP_READ_ENOUGH = 30; // フィルタ後のデータ数がコレ以上ならループを諦めます
|
private static final int LOOP_READ_ENOUGH = 30; // フィルタ後のデータ数がコレ以上ならループを諦めます
|
||||||
private static final int RELATIONSHIP_LOAD_STEP = 40;
|
private static final int RELATIONSHIP_LOAD_STEP = 40;
|
||||||
|
private static final int ACCT_DB_STEP = 100;
|
||||||
|
|
||||||
// ステータスのリストを返すAPI
|
// ステータスのリストを返すAPI
|
||||||
private static final String PATH_HOME = "/api/v1/timelines/home?limit=" + READ_LIMIT;
|
private static final String PATH_HOME = "/api/v1/timelines/home?limit=" + READ_LIMIT;
|
||||||
|
@ -1879,6 +1881,7 @@ class Column {
|
||||||
private void updateRelation( TootApiClient client, ArrayList< Object > list_tmp ){
|
private void updateRelation( TootApiClient client, ArrayList< Object > list_tmp ){
|
||||||
if( list_tmp == null || list_tmp.isEmpty() ) return;
|
if( list_tmp == null || list_tmp.isEmpty() ) return;
|
||||||
HashSet< Long > who_set = new HashSet<>();
|
HashSet< Long > who_set = new HashSet<>();
|
||||||
|
HashSet<String> acct_set = new HashSet<>();
|
||||||
{
|
{
|
||||||
TootAccount a;
|
TootAccount a;
|
||||||
TootStatus s;
|
TootStatus s;
|
||||||
|
@ -1887,29 +1890,45 @@ class Column {
|
||||||
if( o instanceof TootAccount ){
|
if( o instanceof TootAccount ){
|
||||||
a = (TootAccount) o;
|
a = (TootAccount) o;
|
||||||
who_set.add( a.id );
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
}else if( o instanceof TootStatus ){
|
}else if( o instanceof TootStatus ){
|
||||||
s = (TootStatus) o;
|
s = (TootStatus) o;
|
||||||
a = s.account;
|
a = s.account;
|
||||||
if( a != null ) who_set.add( a.id );
|
if( a != null ){
|
||||||
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
|
}
|
||||||
s = s.reblog;
|
s = s.reblog;
|
||||||
if( s != null ){
|
if( s != null ){
|
||||||
a = s.account;
|
a = s.account;
|
||||||
if( a != null ) who_set.add( a.id );
|
if( a != null ){
|
||||||
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else if( o instanceof TootNotification ){
|
}else if( o instanceof TootNotification ){
|
||||||
n = (TootNotification) o;
|
n = (TootNotification) o;
|
||||||
//
|
//
|
||||||
a = n.account;
|
a = n.account;
|
||||||
if( a != null ) who_set.add( a.id );
|
if( a != null ){
|
||||||
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
|
}
|
||||||
//
|
//
|
||||||
s = n.status;
|
s = n.status;
|
||||||
if( s != null ){
|
if( s != null ){
|
||||||
a = s.account;
|
a = s.account;
|
||||||
if( a != null ) who_set.add( a.id );
|
if( a != null ){
|
||||||
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
|
}
|
||||||
s = s.reblog;
|
s = s.reblog;
|
||||||
if( s != null ){
|
if( s != null ){
|
||||||
a = s.account;
|
a = s.account;
|
||||||
if( a != null ) who_set.add( a.id );
|
if( a != null ){
|
||||||
|
who_set.add( a.id );
|
||||||
|
acct_set.add( "@" + access_info.getFullAcct( a ));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1925,6 +1944,7 @@ class Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while( n < size ){
|
while( n < size ){
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -1941,12 +1961,34 @@ class Column {
|
||||||
break;
|
break;
|
||||||
}else if( result.array != null ){
|
}else if( result.array != null ){
|
||||||
TootRelationShip.List list = TootRelationShip.parseList( log, result.array );
|
TootRelationShip.List list = TootRelationShip.parseList( log, result.array );
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
UserRelation.saveList( now, access_info.db_id, list );
|
UserRelation.saveList( now, access_info.db_id, list );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.d( "updateRelation: update %d relations.", n );
|
log.d( "updateRelation: update %d relations.", n );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
size = acct_set.size();
|
||||||
|
if( size > 0 ){
|
||||||
|
String[] acct_list = new String[ size ];
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
for( String l : acct_set ){
|
||||||
|
acct_list[ n++ ] = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
int n = 0;
|
||||||
|
while( n < size ){
|
||||||
|
int length = size-n;
|
||||||
|
if( length > ACCT_DB_STEP ) length = ACCT_DB_STEP;
|
||||||
|
AcctSet.saveList( now, acct_list, n,length );
|
||||||
|
n += length;
|
||||||
|
}
|
||||||
|
log.d( "updateRelation: update %d acct.", n );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,8 @@ class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback, S
|
||||||
saveScrollPosition();
|
saveScrollPosition();
|
||||||
log.d( "onPageDestroy:%s", column.getColumnName( true ) );
|
log.d( "onPageDestroy:%s", column.getColumnName( true ) );
|
||||||
column.removeVisualListener( this );
|
column.removeVisualListener( this );
|
||||||
|
|
||||||
|
activity.closeListItemPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextView tvLoading;
|
private TextView tvLoading;
|
||||||
|
@ -1047,13 +1049,15 @@ class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback, S
|
||||||
void onItemClick( View anchor ){
|
void onItemClick( View anchor ){
|
||||||
|
|
||||||
if( status != null ){
|
if( status != null ){
|
||||||
|
activity.closeListItemPopup();
|
||||||
// ポップアップを表示する
|
// ポップアップを表示する
|
||||||
ListItemPopup popup = new ListItemPopup();
|
activity.list_item_popup = new ListItemPopup();
|
||||||
popup.show( anchor, status );
|
activity.list_item_popup.show( anchor, status );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final ActMain.RelationChangedCallback favourite_complete_callback = new ActMain.RelationChangedCallback() {
|
private final ActMain.RelationChangedCallback favourite_complete_callback = new ActMain.RelationChangedCallback() {
|
||||||
@Override public void onRelationChanged(){
|
@Override public void onRelationChanged(){
|
||||||
Utils.showToast( activity, false, R.string.favourite_succeeded );
|
Utils.showToast( activity, false, R.string.favourite_succeeded );
|
||||||
|
@ -1147,7 +1151,7 @@ class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback, S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ListItemPopup {
|
class ListItemPopup {
|
||||||
final View viewRoot;
|
final View viewRoot;
|
||||||
final ButtonsForStatus buttons_for_status;
|
final ButtonsForStatus buttons_for_status;
|
||||||
|
|
||||||
|
@ -1215,5 +1219,9 @@ class ColumnViewHolder implements View.OnClickListener, Column.VisualCallback, S
|
||||||
, popup_y
|
, popup_y
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void dismiss(){
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
package jp.juggler.subwaytooter.table;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import jp.juggler.subwaytooter.App1;
|
||||||
|
import jp.juggler.subwaytooter.util.LogCategory;
|
||||||
|
|
||||||
|
public class AcctSet {
|
||||||
|
|
||||||
|
private static final LogCategory log = new LogCategory( "AcctSet" );
|
||||||
|
|
||||||
|
private static final String table = "acct_set";
|
||||||
|
private static final String COL_TIME_SAVE = "time_save";
|
||||||
|
private static final String COL_ACCT = "acct"; //@who@host ascii文字の大文字小文字は(sqliteにより)同一視される
|
||||||
|
|
||||||
|
public static void onDBCreate( SQLiteDatabase db ){
|
||||||
|
log.d( "onDBCreate!" );
|
||||||
|
db.execSQL(
|
||||||
|
"create table if not exists " + table
|
||||||
|
+ "(_id INTEGER PRIMARY KEY"
|
||||||
|
+ "," + COL_TIME_SAVE + " integer not null"
|
||||||
|
+ "," + COL_ACCT + " text not null"
|
||||||
|
+ ")"
|
||||||
|
);
|
||||||
|
db.execSQL(
|
||||||
|
"create unique index if not exists " + table + "_acct on " + table + "(" + COL_ACCT + ")"
|
||||||
|
);
|
||||||
|
db.execSQL(
|
||||||
|
"create index if not exists " + table + "_time on " + table + "(" + COL_TIME_SAVE + ")"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){
|
||||||
|
if( oldVersion < 7 && newVersion >= 7 ){
|
||||||
|
onDBCreate( db );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deleteOld( long now ){
|
||||||
|
try{
|
||||||
|
// 古いデータを掃除する
|
||||||
|
long expire = now - 86400000L * 365;
|
||||||
|
App1.getDB().delete( table, COL_TIME_SAVE + "<?", new String[]{ Long.toString( expire ) } );
|
||||||
|
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
log.e( ex, "deleteOld failed." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void save1( long now, String acct ){
|
||||||
|
// try{
|
||||||
|
//
|
||||||
|
// ContentValues cv = new ContentValues();
|
||||||
|
// cv.put( COL_TIME_SAVE, now );
|
||||||
|
// cv.put( COL_ACCT, acct );
|
||||||
|
// App1.getDB().replace( table, null, cv );
|
||||||
|
// }catch( Throwable ex ){
|
||||||
|
// log.e( ex, "save failed." );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static void saveList( long now, String[] src_list, int offset, int length ){
|
||||||
|
|
||||||
|
try{
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put( COL_TIME_SAVE, now );
|
||||||
|
|
||||||
|
boolean bOK = false;
|
||||||
|
SQLiteDatabase db = App1.getDB();
|
||||||
|
db.execSQL( "BEGIN TRANSACTION" );
|
||||||
|
try{
|
||||||
|
for( int i = 0 ; i < length ; ++ i ){
|
||||||
|
String acct = src_list[ i + offset ];
|
||||||
|
cv.put( COL_ACCT, acct );
|
||||||
|
db.replace( table, null, cv );
|
||||||
|
}
|
||||||
|
bOK = true;
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
log.e( ex, "saveList failed." );
|
||||||
|
}
|
||||||
|
if( bOK ){
|
||||||
|
db.execSQL( "COMMIT TRANSACTION" );
|
||||||
|
}else{
|
||||||
|
db.execSQL( "ROLLBACK TRANSACTION" );
|
||||||
|
}
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
log.e( ex, "saveList failed." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String prefix_search_where = COL_ACCT + " like ? escape '$'";
|
||||||
|
|
||||||
|
private static final ThreadLocal< String[] > prefix_search_where_arg = new ThreadLocal< String[] >() {
|
||||||
|
@Override protected String[] initialValue(){
|
||||||
|
return new String[ 1 ];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static String makePattern( String src ){
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for( int i = 0, ie = src.length() ; i < ie ; ++ i ){
|
||||||
|
char c = src.charAt( i );
|
||||||
|
if( c == '%' || c == '_' || c == '$' ){
|
||||||
|
sb.append( '$' );
|
||||||
|
}
|
||||||
|
sb.append( c );
|
||||||
|
}
|
||||||
|
// 前方一致検索にするため、末尾に%をつける
|
||||||
|
sb.append( '%' );
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull public static ArrayList< String > searchPrefix( @NonNull String prefix ,int limit){
|
||||||
|
try{
|
||||||
|
String[] where_arg = prefix_search_where_arg.get();
|
||||||
|
where_arg[ 0 ] = makePattern( prefix );
|
||||||
|
Cursor cursor = App1.getDB().query( table, null, prefix_search_where, where_arg, null, null, COL_ACCT + " asc limit "+limit );
|
||||||
|
if( cursor != null ){
|
||||||
|
try{
|
||||||
|
ArrayList< String > dst = new ArrayList<>( cursor.getCount() );
|
||||||
|
int idx_acct = cursor.getColumnIndex( COL_ACCT );
|
||||||
|
while( cursor.moveToNext() ){
|
||||||
|
dst.add( cursor.getString( idx_acct ) );
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}finally{
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch( Throwable ex ){
|
||||||
|
ex.printStackTrace();
|
||||||
|
log.e( ex, "searchPrefix failed." );
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package jp.juggler.subwaytooter.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.v7.widget.AppCompatEditText;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tateisu on 2017/05/01.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MyEditText extends AppCompatEditText {
|
||||||
|
public MyEditText( Context context ){
|
||||||
|
super( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyEditText( Context context, AttributeSet attrs ){
|
||||||
|
super( context, attrs );
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyEditText( Context context, AttributeSet attrs, int defStyleAttr ){
|
||||||
|
super( context, attrs, defStyleAttr );
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnSelectionChangeListener {
|
||||||
|
void onSelectionChanged( int selStart, int selEnd );
|
||||||
|
}
|
||||||
|
|
||||||
|
OnSelectionChangeListener mOnSelectionChangeListener;
|
||||||
|
|
||||||
|
public void setOnSelectionChangeListener( OnSelectionChangeListener listener ){
|
||||||
|
mOnSelectionChangeListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSelectionChanged( int selStart, int selEnd ){
|
||||||
|
super.onSelectionChanged( selStart, selEnd );
|
||||||
|
if( mOnSelectionChangeListener != null ){
|
||||||
|
mOnSelectionChangeListener.onSelectionChanged( selStart, selEnd );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle"
|
||||||
|
>
|
||||||
|
<solid android:color="?android:attr/colorBackground" />
|
||||||
|
<stroke
|
||||||
|
android:color="?android:attr/colorForeground"
|
||||||
|
android:width="1dp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</shape>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llItems"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</ScrollView>
|
|
@ -174,7 +174,7 @@
|
||||||
android:background="?attr/colorPostFormBackground"
|
android:background="?attr/colorPostFormBackground"
|
||||||
>
|
>
|
||||||
|
|
||||||
<EditText
|
<jp.juggler.subwaytooter.util.MyEditText
|
||||||
android:id="@+id/etContentWarning"
|
android:id="@+id/etContentWarning"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -196,7 +196,7 @@
|
||||||
android:background="?attr/colorPostFormBackground"
|
android:background="?attr/colorPostFormBackground"
|
||||||
>
|
>
|
||||||
|
|
||||||
<EditText
|
<jp.juggler.subwaytooter.util.MyEditText
|
||||||
android:id="@+id/etContent"
|
android:id="@+id/etContent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -202,4 +202,5 @@
|
||||||
<string name="follow_request_ng">Reject for follow request</string>
|
<string name="follow_request_ng">Reject for follow request</string>
|
||||||
<string name="follow_request_rejected">%1$s\'s follow request is rejected.</string>
|
<string name="follow_request_rejected">%1$s\'s follow request is rejected.</string>
|
||||||
<string name="follow_request_authorized">%1$s\'s follow request is authorized.</string>
|
<string name="follow_request_authorized">%1$s\'s follow request is authorized.</string>
|
||||||
|
<string name="close">Close</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue