メンション入力補完のバグ修正と表示改善
This commit is contained in:
parent
d6e2cefbc5
commit
c668bb5d7d
|
@ -9,8 +9,8 @@ android {
|
||||||
applicationId "jp.juggler.subwaytooter"
|
applicationId "jp.juggler.subwaytooter"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 26
|
versionCode 27
|
||||||
versionName "0.2.6"
|
versionName "0.2.7"
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,33 +5,26 @@ 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.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.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.view.ViewTreeObserver;
|
||||||
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.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.ScrollView;
|
||||||
import android.widget.PopupWindow;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.volley.toolbox.NetworkImageView;
|
import com.android.volley.toolbox.NetworkImageView;
|
||||||
|
@ -63,6 +56,8 @@ import okhttp3.Request;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
|
|
||||||
|
import static jp.juggler.subwaytooter.R.id.viewRoot;
|
||||||
|
|
||||||
public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
static final LogCategory log = new LogCategory( "ActPost" );
|
static final LogCategory log = new LogCategory( "ActPost" );
|
||||||
|
|
||||||
|
@ -229,19 +224,19 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
sv = intent.getStringExtra( KEY_REPLY_STATUS );
|
sv = intent.getStringExtra( KEY_REPLY_STATUS );
|
||||||
if( sv != null ){
|
if( sv != null ){
|
||||||
try{
|
try{
|
||||||
TootStatus repley_status = TootStatus.parse( log, account, new JSONObject( sv ) );
|
TootStatus reply_status = TootStatus.parse( log, account, new JSONObject( sv ) );
|
||||||
|
|
||||||
// CW をリプライ元に合わせる
|
// CW をリプライ元に合わせる
|
||||||
if( ! TextUtils.isEmpty( repley_status.spoiler_text ) ){
|
if( ! TextUtils.isEmpty( reply_status.spoiler_text ) ){
|
||||||
cbContentWarning.setChecked( true );
|
cbContentWarning.setChecked( true );
|
||||||
etContentWarning.setText( repley_status.spoiler_text );
|
etContentWarning.setText( reply_status.spoiler_text );
|
||||||
}
|
}
|
||||||
|
|
||||||
// mention を自動設定する
|
// mention を自動設定する
|
||||||
ArrayList< String > mention_list = new ArrayList<>();
|
ArrayList< String > mention_list = new ArrayList<>();
|
||||||
mention_list.add( "@" + account.getFullAcct( repley_status.account ) );
|
mention_list.add( "@" + account.getFullAcct( reply_status.account ) );
|
||||||
if( repley_status.mentions != null ){
|
if( reply_status.mentions != null ){
|
||||||
for( TootMention mention : repley_status.mentions ){
|
for( TootMention mention : reply_status.mentions ){
|
||||||
|
|
||||||
if( account.isMe( mention.acct ) ) continue;
|
if( account.isMe( mention.acct ) ) continue;
|
||||||
|
|
||||||
|
@ -263,9 +258,9 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// リプライ表示をつける
|
// リプライ表示をつける
|
||||||
in_reply_to_id = repley_status.id;
|
in_reply_to_id = reply_status.id;
|
||||||
in_reply_to_text = repley_status.content;
|
in_reply_to_text = reply_status.content;
|
||||||
in_reply_to_image = repley_status.account.avatar_static;
|
in_reply_to_image = reply_status.account.avatar_static;
|
||||||
|
|
||||||
// 公開範囲
|
// 公開範囲
|
||||||
try{
|
try{
|
||||||
|
@ -278,9 +273,9 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// デフォルトの方が公開範囲が大きい場合、リプライ元に合わせて公開範囲を狭める
|
// デフォルトの方が公開範囲が大きい場合、リプライ元に合わせて公開範囲を狭める
|
||||||
int i = TootStatus.compareVisibility( this.visibility, repley_status.visibility );
|
int i = TootStatus.compareVisibility( this.visibility, reply_status.visibility );
|
||||||
if( i > 0 ){ // より大きい=>より公開範囲が広い
|
if( i > 0 ){ // より大きい=>より公開範囲が広い
|
||||||
this.visibility = repley_status.visibility;
|
this.visibility = reply_status.visibility;
|
||||||
}
|
}
|
||||||
}catch( Throwable ex ){
|
}catch( Throwable ex ){
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
|
@ -354,6 +349,8 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
MyEditText etContent;
|
MyEditText etContent;
|
||||||
TextView tvCharCount;
|
TextView tvCharCount;
|
||||||
Handler handler;
|
Handler handler;
|
||||||
|
View formRoot;
|
||||||
|
float density;
|
||||||
|
|
||||||
ArrayList< SavedAccount > account_list;
|
ArrayList< SavedAccount > account_list;
|
||||||
|
|
||||||
|
@ -361,11 +358,16 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
TextView tvReplyTo;
|
TextView tvReplyTo;
|
||||||
View btnRemoveReply;
|
View btnRemoveReply;
|
||||||
NetworkImageView ivReply;
|
NetworkImageView ivReply;
|
||||||
|
ScrollView scrollView;
|
||||||
|
|
||||||
private void initUI(){
|
private void initUI(){
|
||||||
setContentView( R.layout.act_post );
|
|
||||||
handler = new Handler();
|
handler = new Handler();
|
||||||
|
density = getResources().getDisplayMetrics().density;
|
||||||
|
|
||||||
|
setContentView( R.layout.act_post );
|
||||||
|
|
||||||
|
formRoot = findViewById( viewRoot );
|
||||||
|
scrollView = (ScrollView) findViewById( R.id.scrollView );
|
||||||
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 );
|
||||||
|
@ -421,11 +423,8 @@ 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 ){
|
handler.removeCallbacks( proc_text_changed );
|
||||||
log.d( "onTextChanged" );
|
handler.postDelayed( proc_text_changed, (popup!= null && popup.isShowing() ? 100L : 1000L ));
|
||||||
handler.removeCallbacks( proc_text_changed );
|
|
||||||
handler.postDelayed( proc_text_changed, 1500L );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -433,58 +432,62 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
updateTextCount();
|
updateTextCount();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
etContent.setOnSelectionChangeListener( new MyEditText.OnSelectionChangeListener() {
|
etContent.setOnSelectionChangeListener( new MyEditText.OnSelectionChangeListener() {
|
||||||
int last_selection = - 1;
|
|
||||||
|
|
||||||
@Override public void onSelectionChanged( int selStart, int selEnd ){
|
@Override public void onSelectionChanged( int selStart, int selEnd ){
|
||||||
if( selStart != selEnd ){
|
if( selStart != selEnd ){
|
||||||
// 範囲選択されてるならポップアップは閉じる
|
// 範囲選択されてるならポップアップは閉じる
|
||||||
log.d( "onSelectionChanged: range selected" );
|
log.d( "onSelectionChanged: range selected" );
|
||||||
closeAcctPopup();
|
closeAcctPopup();
|
||||||
}else if( selStart > last_selection ){
|
|
||||||
// 文字挿入の直後かもしれないので何もしない
|
|
||||||
log.d( "onSelectionChanged: may after text input? " );
|
|
||||||
}else{
|
|
||||||
// 前方への移動ではないならポップアップは閉じる
|
|
||||||
log.d( "onSelectionChanged: not forward change" );
|
|
||||||
closeAcctPopup();
|
|
||||||
}
|
}
|
||||||
last_selection = selStart;
|
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
scrollView.getViewTreeObserver().addOnScrollChangedListener( scroll_listener );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ViewTreeObserver.OnScrollChangedListener scroll_listener = new ViewTreeObserver.OnScrollChangedListener() {
|
||||||
|
@Override public void onScrollChanged(){
|
||||||
|
if( popup != null && popup.isShowing() ){
|
||||||
|
popup.updatePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
final Runnable proc_text_changed = new Runnable() {
|
final Runnable proc_text_changed = new Runnable() {
|
||||||
@Override public void run(){
|
@Override public void run(){
|
||||||
int ss = etContent.getSelectionStart();
|
int start = etContent.getSelectionStart();
|
||||||
int se = etContent.getSelectionEnd();
|
int end = etContent.getSelectionEnd();
|
||||||
if( ss != se ){
|
if( start != end ){
|
||||||
closeAcctPopup();
|
closeAcctPopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int end = ss;
|
|
||||||
String src = etContent.getText().toString();
|
String src = etContent.getText().toString();
|
||||||
int start = ss;
|
|
||||||
int count_atMark = 0;
|
int count_atMark = 0;
|
||||||
int[] pos_atMark = new int[ 2 ];
|
int[] pos_atMark = new int[ 2 ];
|
||||||
for( ; ; ){
|
for( ; ; ){
|
||||||
if( start == 0 ) break;
|
|
||||||
if( count_atMark >= 2 ) break;
|
if( count_atMark >= 2 ) break;
|
||||||
|
|
||||||
|
if( start == 0 ) break;
|
||||||
char c = src.charAt( start - 1 );
|
char c = src.charAt( start - 1 );
|
||||||
if( ( '0' <= c && c <= '9' )
|
|
||||||
|| ( 'A' <= c && c <= 'Z' )
|
if( c == '@' ){
|
||||||
|| ( 'a' <= c && c <= 'z' )
|
|
||||||
|| c == '_'
|
|
||||||
){
|
|
||||||
-- start;
|
|
||||||
continue;
|
|
||||||
}else if( c == '@' ){
|
|
||||||
-- start;
|
-- start;
|
||||||
pos_atMark[ count_atMark++ ] = start;
|
pos_atMark[ count_atMark++ ] = start;
|
||||||
continue;
|
continue;
|
||||||
|
}else if( ( '0' <= c && c <= '9' )
|
||||||
|
|| ( 'A' <= c && c <= 'Z' )
|
||||||
|
|| ( 'a' <= c && c <= 'z' )
|
||||||
|
|| c == '_' || c == '-' || c == '.'
|
||||||
|
){
|
||||||
|
-- start;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
// その他の文字種が出たら探索打ち切り
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// 登場した@の数
|
||||||
if( count_atMark == 0 ){
|
if( count_atMark == 0 ){
|
||||||
closeAcctPopup();
|
closeAcctPopup();
|
||||||
return;
|
return;
|
||||||
|
@ -493,108 +496,35 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
}else if( count_atMark == 2 ){
|
}else if( count_atMark == 2 ){
|
||||||
start = pos_atMark[ 1 ];
|
start = pos_atMark[ 1 ];
|
||||||
}
|
}
|
||||||
|
// 最低でも2文字ないと補完しない
|
||||||
if( end - start < 2 ){
|
if( end - start < 2 ){
|
||||||
closeAcctPopup();
|
closeAcctPopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int limit = 10;
|
int limit = 100;
|
||||||
String s = src.substring( start, end );
|
String s = src.substring( start, end );
|
||||||
ArrayList< String > acct_list = AcctSet.searchPrefix( s, limit );
|
ArrayList< String > acct_list = AcctSet.searchPrefix( s, limit );
|
||||||
log.d( "search for %s, result=%d", s, acct_list.size() );
|
log.d( "search for %s, result=%d", s, acct_list.size() );
|
||||||
if( acct_list.isEmpty() ){
|
if( acct_list.isEmpty() ){
|
||||||
closeAcctPopup();
|
closeAcctPopup();
|
||||||
return;
|
}else{
|
||||||
|
if( popup == null || ! popup.isShowing() ){
|
||||||
|
popup = new PopupAutoCompleteAcct( ActPost.this, etContent ,formRoot);
|
||||||
|
}
|
||||||
|
popup.setList( acct_list, start, end );
|
||||||
}
|
}
|
||||||
openAcctPopup( acct_list, start, end );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PopupWindow acct_popup;
|
PopupAutoCompleteAcct popup;
|
||||||
|
|
||||||
private void closeAcctPopup(){
|
private void closeAcctPopup(){
|
||||||
if( acct_popup != null ){
|
if( popup != null ){
|
||||||
acct_popup.dismiss();
|
popup.dismiss();
|
||||||
acct_popup = null;
|
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_content = s.codePointCount( 0, s.length() );
|
int count_content = s.codePointCount( 0, s.length() );
|
||||||
|
@ -677,7 +607,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
static final int ATTACHMENT_UPLOADING = 1;
|
static final int ATTACHMENT_UPLOADING = 1;
|
||||||
static final int ATTACHMENT_UPLOADED = 2;
|
static final int ATTACHMENT_UPLOADED = 2;
|
||||||
|
|
||||||
static class PostAttachment {
|
private static class PostAttachment {
|
||||||
int status;
|
int status;
|
||||||
TootAttachment attachment;
|
TootAttachment attachment;
|
||||||
}
|
}
|
||||||
|
@ -752,7 +682,7 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static final byte[] hex = Utils.encodeUTF8( "0123456789abcdef" );
|
// static final byte[] hex = Utils.encodeUTF8( "0123456789abcdef" );
|
||||||
|
|
||||||
void addAttachment( final Uri uri, final String mime_type ){
|
void addAttachment( final Uri uri, final String mime_type ){
|
||||||
if( attachment_list.size() >= 4 ){
|
if( attachment_list.size() >= 4 ){
|
||||||
|
@ -885,14 +815,16 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener {
|
||||||
public String getDocumentName( Uri uri ){
|
public String getDocumentName( Uri uri ){
|
||||||
|
|
||||||
Cursor cursor = getContentResolver().query( uri, null, null, null, null, null );
|
Cursor cursor = getContentResolver().query( uri, null, null, null, null, null );
|
||||||
try{
|
if( cursor != null){
|
||||||
if( cursor != null && cursor.moveToFirst() ){
|
try{
|
||||||
return cursor.getString( cursor.getColumnIndex( OpenableColumns.DISPLAY_NAME ) );
|
if( cursor.moveToFirst() ){
|
||||||
|
return cursor.getString( cursor.getColumnIndex( OpenableColumns.DISPLAY_NAME ) );
|
||||||
|
}
|
||||||
|
}finally{
|
||||||
|
cursor.close();
|
||||||
}
|
}
|
||||||
}finally{
|
|
||||||
cursor.close();
|
|
||||||
}
|
}
|
||||||
return null;
|
return "no_name";
|
||||||
}
|
}
|
||||||
|
|
||||||
long getStreamSize( boolean bClose, InputStream is ) throws IOException{
|
long getStreamSize( boolean bClose, InputStream is ) throws IOException{
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
package jp.juggler.subwaytooter;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.CheckedTextView;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
class PopupAutoCompleteAcct {
|
||||||
|
final Activity activity;
|
||||||
|
private final EditText etContent;
|
||||||
|
private final PopupWindow acct_popup;
|
||||||
|
private final LinearLayout llItems;
|
||||||
|
private final View formRoot;
|
||||||
|
private final float density;
|
||||||
|
private final int popup_width;
|
||||||
|
|
||||||
|
private int popup_rows;
|
||||||
|
|
||||||
|
void dismiss(){
|
||||||
|
acct_popup.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isShowing(){
|
||||||
|
return acct_popup.isShowing();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupAutoCompleteAcct( Activity activity, EditText etContent, View formRoot ){
|
||||||
|
this.activity = activity;
|
||||||
|
this.etContent = etContent;
|
||||||
|
this.formRoot = formRoot;
|
||||||
|
this.density = activity.getResources().getDisplayMetrics().density;
|
||||||
|
|
||||||
|
popup_width = (int)(0.5f +240f * density );
|
||||||
|
|
||||||
|
@SuppressLint("InflateParams") View viewRoot =
|
||||||
|
activity.getLayoutInflater().inflate( R.layout.acct_complete_popup, null, false );
|
||||||
|
llItems = (LinearLayout) viewRoot.findViewById( R.id.llItems );
|
||||||
|
//
|
||||||
|
acct_popup = new PopupWindow( activity );
|
||||||
|
acct_popup.setBackgroundDrawable( ContextCompat.getDrawable( activity, R.drawable.acct_popup_bg ) );
|
||||||
|
acct_popup.setContentView( viewRoot );
|
||||||
|
acct_popup.setTouchable( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void setList( ArrayList< String > acct_list, final int sel_start, final int sel_end ){
|
||||||
|
|
||||||
|
llItems.removeAllViews();
|
||||||
|
|
||||||
|
popup_rows = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
CheckedTextView v = (CheckedTextView) activity.getLayoutInflater()
|
||||||
|
.inflate( R.layout.lv_spinner_dropdown, llItems, false );
|
||||||
|
v.setTextColor( Styler.getAttributeColor( activity, android.R.attr.textColorPrimary ) );
|
||||||
|
v.setText( R.string.close );
|
||||||
|
v.setOnClickListener( new View.OnClickListener() {
|
||||||
|
@Override public void onClick( View v ){
|
||||||
|
acct_popup.dismiss();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
llItems.addView( v );
|
||||||
|
++ popup_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( int i = 0 ; ; ++ i ){
|
||||||
|
if( i >= acct_list.size() ) break;
|
||||||
|
final String acct = acct_list.get( i );
|
||||||
|
CheckedTextView v = (CheckedTextView) activity.getLayoutInflater()
|
||||||
|
.inflate( R.layout.lv_spinner_dropdown, llItems, false );
|
||||||
|
v.setTextColor( Styler.getAttributeColor( activity, 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, sel_start ) + acct + " "
|
||||||
|
+ ( sel_end >= s.length() ? "" : s.substring( sel_end ) );
|
||||||
|
etContent.setText( s );
|
||||||
|
etContent.setSelection( sel_start + acct.length() + 1 );
|
||||||
|
acct_popup.dismiss();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
llItems.addView( v );
|
||||||
|
++ popup_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePosition(){
|
||||||
|
if( acct_popup == null ) return;
|
||||||
|
|
||||||
|
int[] location = new int[ 2 ];
|
||||||
|
etContent.getLocationOnScreen( location );
|
||||||
|
int text_top = location[ 1 ];
|
||||||
|
|
||||||
|
formRoot.getLocationOnScreen( location );
|
||||||
|
int form_top = location[ 1 ];
|
||||||
|
int form_bottom = location[ 1 ] + formRoot.getHeight();
|
||||||
|
|
||||||
|
Layout layout = etContent.getLayout();
|
||||||
|
|
||||||
|
int popup_top = text_top
|
||||||
|
+ etContent.getTotalPaddingTop()
|
||||||
|
+ layout.getLineBottom( layout.getLineCount() - 1 )
|
||||||
|
- etContent.getScrollY();
|
||||||
|
|
||||||
|
if( popup_top < form_top ) popup_top = form_top;
|
||||||
|
|
||||||
|
int popup_height = form_bottom - popup_top;
|
||||||
|
|
||||||
|
int min = (int) ( 0.5f + 48f * 2f * density );
|
||||||
|
if( popup_height < min ) popup_height = min;
|
||||||
|
|
||||||
|
int max = (int) ( 0.5f + 48f * popup_rows * density );
|
||||||
|
if( popup_height > max ) popup_height = max;
|
||||||
|
|
||||||
|
if( acct_popup.isShowing() ){
|
||||||
|
acct_popup.update( 0, popup_top, popup_width, popup_height );
|
||||||
|
}else{
|
||||||
|
acct_popup.setWidth( popup_width );
|
||||||
|
acct_popup.setHeight( popup_height );
|
||||||
|
acct_popup.showAtLocation(
|
||||||
|
etContent
|
||||||
|
, Gravity.CENTER_HORIZONTAL | Gravity.TOP
|
||||||
|
, 0
|
||||||
|
, popup_top
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:fadeScrollbars="false"
|
||||||
|
android:scrollbarStyle="outsideOverlay"
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:id="@+id/viewRoot"
|
||||||
>
|
>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
@ -17,13 +18,17 @@
|
||||||
android:cacheColorHint="#00000000"
|
android:cacheColorHint="#00000000"
|
||||||
android:scrollbarStyle="outsideOverlay"
|
android:scrollbarStyle="outsideOverlay"
|
||||||
android:fadeScrollbars="false"
|
android:fadeScrollbars="false"
|
||||||
|
android:id="@+id/scrollView"
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="12dp"
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:paddingTop="12dp"
|
||||||
|
android:paddingBottom="320dp"
|
||||||
>
|
>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
style="?android:attr/spinnerDropDownItemStyle"
|
style="?android:attr/spinnerDropDownItemStyle"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="48dp"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="marquee"
|
android:minHeight="48dp"
|
||||||
|
android:background="@drawable/btn_bg_transparent"
|
||||||
/>
|
/>
|
Loading…
Reference in New Issue