diff --git a/_ArtWork/ic_follow_cross.png b/_ArtWork/ic_follow_cross.png new file mode 100644 index 000000000..96783cdc5 Binary files /dev/null and b/_ArtWork/ic_follow_cross.png differ diff --git a/_ArtWork/ic_follow_cross_dark.png b/_ArtWork/ic_follow_cross_dark.png new file mode 100644 index 000000000..18ff50df4 Binary files /dev/null and b/_ArtWork/ic_follow_cross_dark.png differ diff --git a/_ArtWork/ic_follow_plus.png b/_ArtWork/ic_follow_plus.png new file mode 100644 index 000000000..3c94ac5e4 Binary files /dev/null and b/_ArtWork/ic_follow_plus.png differ diff --git a/_ArtWork/ic_follow_plus_dark.png b/_ArtWork/ic_follow_plus_dark.png new file mode 100644 index 000000000..558d61506 Binary files /dev/null and b/_ArtWork/ic_follow_plus_dark.png differ diff --git a/_ArtWork/ic_followed_by.png b/_ArtWork/ic_followed_by.png new file mode 100644 index 000000000..8af6b18f0 Binary files /dev/null and b/_ArtWork/ic_followed_by.png differ diff --git a/_ArtWork/ic_followed_by_dark.png b/_ArtWork/ic_followed_by_dark.png new file mode 100644 index 000000000..edfd5ae73 Binary files /dev/null and b/_ArtWork/ic_followed_by_dark.png differ diff --git a/ic_hourglass.png b/_ArtWork/ic_hourglass.png similarity index 100% rename from ic_hourglass.png rename to _ArtWork/ic_hourglass.png diff --git a/ic_hourglass_dark.png b/_ArtWork/ic_hourglass_dark.png similarity index 100% rename from ic_hourglass_dark.png rename to _ArtWork/ic_hourglass_dark.png diff --git a/ic_launcher-1024.png b/_ArtWork/ic_launcher-1024.png similarity index 100% rename from ic_launcher-1024.png rename to _ArtWork/ic_launcher-1024.png diff --git a/ic_launcher-512.png b/_ArtWork/ic_launcher-512.png similarity index 100% rename from ic_launcher-512.png rename to _ArtWork/ic_launcher-512.png diff --git a/ic_launcher.xcf b/_ArtWork/ic_launcher.xcf similarity index 100% rename from ic_launcher.xcf rename to _ArtWork/ic_launcher.xcf diff --git a/ic_notification-817.png b/_ArtWork/ic_notification-817.png similarity index 100% rename from ic_notification-817.png rename to _ArtWork/ic_notification-817.png diff --git a/store-header-1024.png b/_ArtWork/store-header-1024.png similarity index 100% rename from store-header-1024.png rename to _ArtWork/store-header-1024.png diff --git a/store-promo.png b/_ArtWork/store-promo.png similarity index 100% rename from store-promo.png rename to _ArtWork/store-promo.png diff --git a/app/build.gradle b/app/build.gradle index 28de1f1b1..d28066cc9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "jp.juggler.subwaytooter" minSdkVersion 21 targetSdkVersion 25 - versionCode 32 - versionName "0.3.2" + versionCode 33 + versionName "0.3.3" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.java b/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.java index dbecdd946..263b11303 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActAccountSetting.java @@ -29,8 +29,7 @@ public class ActAccountSetting extends AppCompatActivity implements View.OnClickListener - , CompoundButton.OnCheckedChangeListener - { + , CompoundButton.OnCheckedChangeListener { static final LogCategory log = new LogCategory( "ActAccountSetting" ); @@ -64,7 +63,7 @@ protected void onCreate( @Nullable Bundle savedInstanceState ){ static final int REQUEST_CODE_ACCT_CUSTOMIZE = 1; @Override protected void onActivityResult( int requestCode, int resultCode, Intent data ){ - if( requestCode== REQUEST_CODE_ACCT_CUSTOMIZE && resultCode == RESULT_OK ){ + if( requestCode == REQUEST_CODE_ACCT_CUSTOMIZE && resultCode == RESULT_OK ){ showAcctColor(); } super.onActivityResult( requestCode, resultCode, data ); @@ -75,7 +74,6 @@ protected void onCreate( @Nullable Bundle savedInstanceState ){ View btnAccessToken; View btnAccountRemove; Button btnVisibility; - Switch swConfirmBeforeBoost; Switch swNSFWOpen; Button btnOpenBrowser; CheckBox cbNotificationMention; @@ -83,6 +81,12 @@ protected void onCreate( @Nullable Bundle savedInstanceState ){ CheckBox cbNotificationFavourite; CheckBox cbNotificationFollow; + CheckBox cbConfirmFollow; + CheckBox cbConfirmFollowLockedUser; + CheckBox cbConfirmUnfollow; + CheckBox cbConfirmBoost; + CheckBox cbConfirmToot; + TextView tvUserCustom; View btnUserCustom; String full_acct; @@ -94,14 +98,19 @@ private void initUI(){ btnAccessToken = findViewById( R.id.btnAccessToken ); btnAccountRemove = findViewById( R.id.btnAccountRemove ); btnVisibility = (Button) findViewById( R.id.btnVisibility ); - swConfirmBeforeBoost = (Switch) findViewById( R.id.swConfirmBeforeBoost ); swNSFWOpen = (Switch) findViewById( R.id.swNSFWOpen ); btnOpenBrowser = (Button) findViewById( R.id.btnOpenBrowser ); cbNotificationMention = (CheckBox) findViewById( R.id.cbNotificationMention ); cbNotificationBoost = (CheckBox) findViewById( R.id.cbNotificationBoost ); cbNotificationFavourite = (CheckBox) findViewById( R.id.cbNotificationFavourite ); cbNotificationFollow = (CheckBox) findViewById( R.id.cbNotificationFollow ); - + + cbConfirmFollow = (CheckBox) findViewById( R.id.cbConfirmFollow ); + cbConfirmFollowLockedUser = (CheckBox) findViewById( R.id.cbConfirmFollowLockedUser ); + cbConfirmUnfollow = (CheckBox) findViewById( R.id.cbConfirmUnfollow ); + cbConfirmBoost = (CheckBox) findViewById( R.id.cbConfirmBoost ); + cbConfirmToot = (CheckBox) findViewById( R.id.cbConfirmToot ); + tvUserCustom = (TextView) findViewById( R.id.tvUserCustom ); btnUserCustom = findViewById( R.id.btnUserCustom ); @@ -112,11 +121,16 @@ private void initUI(){ btnUserCustom.setOnClickListener( this ); swNSFWOpen.setOnCheckedChangeListener( this ); - swConfirmBeforeBoost.setOnCheckedChangeListener( this ); cbNotificationMention.setOnCheckedChangeListener( this ); cbNotificationBoost.setOnCheckedChangeListener( this ); cbNotificationFavourite.setOnCheckedChangeListener( this ); cbNotificationFollow.setOnCheckedChangeListener( this ); + + cbConfirmFollow.setOnCheckedChangeListener( this ); + cbConfirmFollowLockedUser.setOnCheckedChangeListener( this ); + cbConfirmUnfollow.setOnCheckedChangeListener( this ); + cbConfirmBoost.setOnCheckedChangeListener( this ); + cbConfirmToot.setOnCheckedChangeListener( this ); } boolean loading = false; @@ -134,44 +148,62 @@ private void loadUIFromData( SavedAccount a ){ loading = true; - swConfirmBeforeBoost.setChecked( a.confirm_boost ); + swNSFWOpen.setChecked( a.dont_hide_nsfw ); cbNotificationMention.setChecked( a.notification_mention ); cbNotificationBoost.setChecked( a.notification_boost ); cbNotificationFavourite.setChecked( a.notification_favourite ); cbNotificationFollow.setChecked( a.notification_follow ); - + + cbConfirmFollow.setChecked( a.confirm_follow ); + cbConfirmFollowLockedUser.setChecked( a.confirm_follow_locked ); + cbConfirmUnfollow.setChecked( a.confirm_unfollow ); + cbConfirmBoost.setChecked( a.confirm_boost ); + cbConfirmToot.setChecked( a.confirm_post ); + loading = false; boolean enabled = ! a.isPseudo(); btnAccessToken.setEnabled( enabled ); btnVisibility.setEnabled( enabled ); - swConfirmBeforeBoost.setEnabled( enabled ); + cbNotificationMention.setEnabled( enabled ); cbNotificationBoost.setEnabled( enabled ); cbNotificationFavourite.setEnabled( enabled ); cbNotificationFollow.setEnabled( enabled ); + cbConfirmFollow.setEnabled( enabled ); + cbConfirmFollowLockedUser.setEnabled( enabled ); + cbConfirmUnfollow.setEnabled( enabled ); + cbConfirmBoost.setEnabled( enabled ); + cbConfirmToot.setEnabled( enabled ); + updateVisibility(); showAcctColor(); } private void showAcctColor(){ AcctColor ac = AcctColor.load( full_acct ); - tvUserCustom.setText( ac!=null && !TextUtils.isEmpty( ac.nickname) ? ac.nickname : full_acct ); + tvUserCustom.setText( ac != null && ! TextUtils.isEmpty( ac.nickname ) ? ac.nickname : full_acct ); tvUserCustom.setTextColor( ac != null && ac.color_fg != 0 ? ac.color_fg : Styler.getAttributeColor( this, R.attr.colorAcctSmall ) ); - tvUserCustom.setBackgroundColor( ac != null && ac.color_bg != 0 ? ac.color_bg : 0 ); + tvUserCustom.setBackgroundColor( ac != null && ac.color_bg != 0 ? ac.color_bg : 0 ); } private void saveUIToData(){ if( loading ) return; account.visibility = visibility; - account.confirm_boost = swConfirmBeforeBoost.isChecked(); account.dont_hide_nsfw = swNSFWOpen.isChecked(); account.notification_mention = cbNotificationMention.isChecked(); account.notification_boost = cbNotificationBoost.isChecked(); account.notification_favourite = cbNotificationFavourite.isChecked(); account.notification_follow = cbNotificationFollow.isChecked(); + + account.confirm_follow = cbConfirmFollow.isChecked(); + account.confirm_follow_locked = cbConfirmFollowLockedUser.isChecked(); + account.confirm_unfollow = cbConfirmUnfollow.isChecked(); + account.confirm_boost = cbConfirmBoost.isChecked(); + account.confirm_post = cbConfirmToot.isChecked(); + account.saveSetting(); } @@ -195,9 +227,9 @@ private void saveUIToData(){ open_browser( "https://" + account.host + "/" ); break; case R.id.btnUserCustom: - ActNickname.open( this, full_acct, REQUEST_CODE_ACCT_CUSTOMIZE); + ActNickname.open( this, full_acct, REQUEST_CODE_ACCT_CUSTOMIZE ); break; - + } } @@ -345,6 +377,6 @@ public void onCancel( DialogInterface dialog ){ progress.show(); AsyncTaskCompat.executeParallel( task ); } - + } diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.java b/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.java index 150c56e7a..48c1373bf 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActAppSetting.java @@ -38,6 +38,7 @@ protected void onCreate( @Nullable Bundle savedInstanceState ){ Switch swDisableFastScroller; Switch swSimpleList; Switch swExitAppWhenCloseProtectedColumn; + Switch swShowFollowButtonInButtonBar; Spinner spBackButtonAction; Spinner spUITheme; @@ -69,6 +70,9 @@ private void initUI(){ swExitAppWhenCloseProtectedColumn = (Switch) findViewById( R.id.swExitAppWhenCloseProtectedColumn ); swExitAppWhenCloseProtectedColumn.setOnCheckedChangeListener( this ); + swShowFollowButtonInButtonBar = (Switch) findViewById( R.id.swShowFollowButtonInButtonBar ); + swShowFollowButtonInButtonBar.setOnCheckedChangeListener( this ); + cbNotificationSound = (CheckBox) findViewById( R.id.cbNotificationSound ); cbNotificationVibration = (CheckBox) findViewById( R.id.cbNotificationVibration ); cbNotificationLED = (CheckBox) findViewById( R.id.cbNotificationLED ); @@ -130,6 +134,7 @@ private void loadUIFromData(){ swDisableFastScroller.setChecked( pref.getBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, true ) ); swSimpleList.setChecked( pref.getBoolean( Pref.KEY_SIMPLE_LIST, false ) ); swExitAppWhenCloseProtectedColumn.setChecked( pref.getBoolean( Pref.KEY_EXIT_APP_WHEN_CLOSE_PROTECTED_COLUMN, false ) ); + swShowFollowButtonInButtonBar.setChecked( pref.getBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, false ) ); cbNotificationSound.setChecked( pref.getBoolean( Pref.KEY_NOTIFICATION_SOUND, true ) ); cbNotificationVibration.setChecked( pref.getBoolean( Pref.KEY_NOTIFICATION_VIBRATION, true ) ); @@ -150,6 +155,7 @@ private void saveUIToData(){ .putBoolean( Pref.KEY_DISABLE_FAST_SCROLLER, swDisableFastScroller.isChecked() ) .putBoolean( Pref.KEY_SIMPLE_LIST, swSimpleList.isChecked() ) .putBoolean( Pref.KEY_EXIT_APP_WHEN_CLOSE_PROTECTED_COLUMN, swExitAppWhenCloseProtectedColumn.isChecked() ) + .putBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, swShowFollowButtonInButtonBar.isChecked() ) .putBoolean( Pref.KEY_NOTIFICATION_SOUND, cbNotificationSound.isChecked() ) .putBoolean( Pref.KEY_NOTIFICATION_VIBRATION, cbNotificationVibration.isChecked() ) diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActColumnList.java b/app/src/main/java/jp/juggler/subwaytooter/ActColumnList.java index 8d0377271..640b86d17 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActColumnList.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActColumnList.java @@ -26,6 +26,9 @@ import jp.juggler.subwaytooter.util.Utils; public class ActColumnList extends AppCompatActivity { + + static final String TMP_FILE_COLUMN_LIST = "tmp_column_list"; + public static final String EXTRA_ORDER = "order"; public static final String EXTRA_SELECTION = "selection"; @@ -36,31 +39,25 @@ protected void onCreate( @Nullable Bundle savedInstanceState ){ initUI(); if( savedInstanceState != null ){ - restoreData( - savedInstanceState.getString( EXTRA_ORDER ) - , savedInstanceState.getInt( EXTRA_SELECTION ) - ); + restoreData( savedInstanceState.getInt( EXTRA_SELECTION ) ); }else{ Intent intent = getIntent(); - restoreData( - intent.getStringExtra( EXTRA_ORDER ) - , intent.getIntExtra( EXTRA_SELECTION, - 1 ) - ); + restoreData( intent.getIntExtra( EXTRA_SELECTION, - 1 ) ); } } @Override protected void onSaveInstanceState( Bundle outState ){ super.onSaveInstanceState( outState ); - // outState.putInt( EXTRA_SELECTION, old_selection ); + // JSONArray array = new JSONArray(); List< MyItem > item_list = listAdapter.getItemList(); for( int i = 0, ie = item_list.size() ; i < ie ; ++ i ){ array.put( item_list.get( i ).json ); } - outState.putString( EXTRA_ORDER, array.toString() ); + App1.saveColumnList( this,TMP_FILE_COLUMN_LIST,array ); } @Override @@ -133,25 +130,27 @@ public void onItemSwipeEnded( ListSwipeItem item, ListSwipeItem.SwipeDirection s } ); } - void restoreData( String svColumnList, int ivSelection ){ + void restoreData( int ivSelection ){ this.old_selection = ivSelection; ArrayList< MyItem > tmp_list = new ArrayList<>(); try{ - JSONArray array = new JSONArray( svColumnList ); - for( int i = 0, ie = array.length() ; i < ie ; ++ i ){ - try{ - JSONObject src = array.optJSONObject( i ); - MyItem item = new MyItem( src, i, this ); - if( src != null ){ - tmp_list.add( item ); - if( old_selection == item.old_index ){ - item.setOldSelection( true ); + JSONArray array = App1.loadColumnList( this, TMP_FILE_COLUMN_LIST ); + if( array != null ){ + for( int i = 0, ie = array.length() ; i < ie ; ++ i ){ + try{ + JSONObject src = array.optJSONObject( i ); + MyItem item = new MyItem( src, i, this ); + if( src != null ){ + tmp_list.add( item ); + if( old_selection == item.old_index ){ + item.setOldSelection( true ); + } } + }catch( Throwable ex2 ){ + ex2.printStackTrace(); } - }catch( Throwable ex2 ){ - ex2.printStackTrace(); } } }catch( Throwable ex ){ diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMain.java b/app/src/main/java/jp/juggler/subwaytooter/ActMain.java index 74d48dcf3..04118a667 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActMain.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActMain.java @@ -31,10 +31,6 @@ import org.json.JSONException; import org.json.JSONObject; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -49,6 +45,7 @@ import jp.juggler.subwaytooter.api.entity.TootRelationShip; import jp.juggler.subwaytooter.api.entity.TootStatus; import jp.juggler.subwaytooter.dialog.AccountPicker; +import jp.juggler.subwaytooter.dialog.DlgConfirm; import jp.juggler.subwaytooter.dialog.LoginForm; import jp.juggler.subwaytooter.dialog.ReportForm; import jp.juggler.subwaytooter.table.AcctColor; @@ -171,6 +168,7 @@ boolean isOrderChanged( ArrayList< Integer > new_order ){ static final int REQUEST_CODE_ACCOUNT_SETTING = 2; static final int REQUEST_APP_ABOUT = 3; static final int REQUEST_CODE_NICKNAME = 4; + static final int REQUEST_CODE_POST = 5; @Override protected void onActivityResult( int requestCode, int resultCode, Intent data ){ if( resultCode == RESULT_OK ){ @@ -205,9 +203,11 @@ boolean isOrderChanged( ArrayList< Integer > new_order ){ return; } }else if( requestCode == REQUEST_CODE_NICKNAME ){ - for( Column column: pager_adapter.column_list ){ + for( Column column : pager_adapter.column_list ){ column.onNicknameUpdated(); } + }else if( requestCode == REQUEST_CODE_POST ){ + reloadAccountSetting(); } } super.onActivityResult( requestCode, resultCode, data ); @@ -718,7 +718,17 @@ void reloadAccountSetting(){ column.fireVisualCallback2(); } } - + void reloadAccountSetting(SavedAccount account){ + ArrayList< SavedAccount > done_list = new ArrayList<>(); + for( Column column : pager_adapter.column_list ){ + SavedAccount a = column.access_info; + if( ! Utils.equalsNullable( a.acct ,account.acct ) ) continue; + if( done_list.contains( a ) ) continue; + done_list.add( a ); + a.reloadSetting(); + column.fireVisualCallback2(); + } + } public void performColumnClose( boolean bConfirm, final Column column ){ if( column.dont_close ){ Utils.showToast( this, false, R.string.column_has_dont_close_option ); @@ -979,7 +989,7 @@ private void openHashTagOtherInstance( final SavedAccount access_info, final Str // ソートする Collections.sort( account_list, new Comparator< SavedAccount >() { @Override public int compare( SavedAccount a, SavedAccount b ){ - return String.CASE_INSENSITIVE_ORDER.compare( AcctColor.getNickname(a.acct), AcctColor.getNickname(b.acct) ); + return String.CASE_INSENSITIVE_ORDER.compare( AcctColor.getNickname( a.acct ), AcctColor.getNickname( b.acct ) ); } } ); @@ -1011,24 +1021,24 @@ private void performTootButton(){ if( c.access_info.isPseudo() ){ Utils.showToast( this, false, R.string.not_available_for_pseudo_account ); }else{ - ActPost.open( this, c.access_info.db_id, "" ); + ActPost.open( this, REQUEST_CODE_POST,c.access_info.db_id, "" ); } } } public void performReply( SavedAccount account, TootStatus status ){ - ActPost.open( this, account.db_id, status ); + ActPost.open( this, REQUEST_CODE_POST,account.db_id, status ); } public void performMention( SavedAccount account, TootAccount who ){ - ActPost.open( this, account.db_id, "@" + account.getFullAcct( who ) + " " ); + ActPost.open( this, REQUEST_CODE_POST,account.db_id, "@" + account.getFullAcct( who ) + " " ); } public void performMentionFromAnotherAccount( SavedAccount access_info, final TootAccount who, ArrayList< SavedAccount > account_list_non_pseudo ){ final String initial_text = "@" + access_info.getFullAcct( who ) + " "; AccountPicker.pick( this, false, false, account_list_non_pseudo, new AccountPicker.AccountPickerCallback() { @Override public void onAccountPicked( SavedAccount ai ){ - ActPost.open( ActMain.this, ai.db_id, initial_text); + ActPost.open( ActMain.this, REQUEST_CODE_POST,ai.db_id, initial_text ); } } ); } @@ -1160,9 +1170,9 @@ boolean isBusyBoost( SavedAccount account, TootStatus status ){ return map_busy_boost.contains( busy_key ); } - public void performBoost( final SavedAccount account, final TootStatus status, boolean bConfirmed, final RelationChangedCallback callback ){ + public void performBoost( final SavedAccount access_info, final TootStatus status, boolean bConfirmed, final RelationChangedCallback callback ){ // - final String busy_key = account.host + ":" + status.id; + final String busy_key = access_info.host + ":" + status.id; // if( map_busy_boost.contains( busy_key ) ){ Utils.showToast( this, false, R.string.wait_previous_operation ); @@ -1171,24 +1181,27 @@ public void performBoost( final SavedAccount account, final TootStatus status, b if( status.reblogged ){ // FAVがついているか、FAV操作中はBoostを外せない - if( isBusyFav( account, status ) || status.favourited ){ + if( isBusyFav( access_info, status ) || status.favourited ){ Utils.showToast( this, false, R.string.cant_remove_boost_while_favourited ); return; } - }else{ - if( ! bConfirmed && account.confirm_boost ){ - new AlertDialog.Builder( this ) - .setTitle( R.string.confirm ) - .setMessage( R.string.confirm_boost ) - .setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() { - @Override public void onClick( DialogInterface dialog, int which ){ - performBoost( account, status, true, callback ); - } - } ) - .setNegativeButton( R.string.cancel, null ) - .show(); - return; - } + }else if( ! bConfirmed ){ + DlgConfirm.open( this, getString( R.string.confirm_boost_from,AcctColor.getNickname( access_info.acct ) ), new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_boost; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_boost = bv; + access_info.saveSetting(); + reloadAccountSetting(access_info); + } + + @Override public void onOK(){ + performBoost( access_info, status, true, callback ); + } + } ); + return; } // @@ -1207,7 +1220,7 @@ public void performBoost( final SavedAccount account, final TootStatus status, b @Override public void publishApiProgress( final String s ){ } } ); - client.setAccount( account ); + client.setAccount( access_info ); Request.Builder request_builder = new Request.Builder() .post( RequestBody.create( @@ -1223,7 +1236,7 @@ public void performBoost( final SavedAccount account, final TootStatus status, b // reblog,unreblog のレスポンスは信用ならんのでステータスを再取得する result = client.request( "/api/v1/statuses/" + status.id ); if( result.object != null ){ - new_status = TootStatus.parse( log, account, result.object ); + new_status = TootStatus.parse( log, access_info, result.object ); } } @@ -1255,7 +1268,7 @@ public void performBoost( final SavedAccount account, final TootStatus status, b } } for( Column column : pager_adapter.column_list ){ - column.findStatus( account, new_status.id, new Column.StatusEntryCallback() { + column.findStatus( access_info, new_status.id, new Column.StatusEntryCallback() { @Override public void onIterate( TootStatus status ){ status.reblogged = new_status.reblogged; status.reblogs_count = new_status.reblogs_count; @@ -1266,12 +1279,12 @@ public void performBoost( final SavedAccount account, final TootStatus status, b }else{ Utils.showToast( ActMain.this, true, result.error ); } - showColumnMatchAccount( account ); + showColumnMatchAccount( access_info ); } }.execute(); - showColumnMatchAccount( account ); + showColumnMatchAccount( access_info ); } //////////////////////////////////////// @@ -1307,8 +1320,9 @@ JSONArray encodeColumnList(){ } private void performColumnList(){ + JSONArray array = encodeColumnList(); + App1.saveColumnList(this,ActColumnList.TMP_FILE_COLUMN_LIST,array); Intent intent = new Intent( this, ActColumnList.class ); - intent.putExtra( ActColumnList.EXTRA_ORDER, encodeColumnList().toString() ); intent.putExtra( ActColumnList.EXTRA_SELECTION, pager.getCurrentItem() ); startActivityForResult( intent, REQUEST_CODE_COLUMN_LIST ); } @@ -1324,49 +1338,23 @@ private void performColumnList(){ void saveColumnList(){ JSONArray array = encodeColumnList(); - try{ - OutputStream os = openFileOutput( FILE_COLUMN_LIST, MODE_PRIVATE ); - try{ - os.write( Utils.encodeUTF8( array.toString() ) ); - }finally{ - os.close(); - } - }catch( Throwable ex ){ - ex.printStackTrace(); - Utils.showToast( this, ex, "saveColumnList failed." ); - } + App1.saveColumnList(this,FILE_COLUMN_LIST,array); + } private void loadColumnList(){ - try{ - InputStream is = openFileInput( FILE_COLUMN_LIST ); - try{ - ByteArrayOutputStream bao = new ByteArrayOutputStream( is.available() ); - byte[] tmp = new byte[ 4096 ]; - for( ; ; ){ - int r = is.read( tmp, 0, tmp.length ); - if( r <= 0 ) break; - bao.write( tmp, 0, r ); + JSONArray array = App1.loadColumnList(this,FILE_COLUMN_LIST); + if( array != null ){ + for( int i = 0, ie = array.length() ; i < ie ; ++ i ){ + try{ + JSONObject src = array.optJSONObject( i ); + Column col = new Column( ActMain.this, src ); + pager_adapter.addColumn( pager, col, pager_adapter.getCount() ); + }catch( Throwable ex ){ + ex.printStackTrace(); } - JSONArray array = new JSONArray( Utils.decodeUTF8( bao.toByteArray() ) ); - for( int i = 0, ie = array.length() ; i < ie ; ++ i ){ - try{ - JSONObject src = array.optJSONObject( i ); - Column col = new Column( ActMain.this, src ); - pager_adapter.addColumn( pager, col, pager_adapter.getCount() ); - }catch( Throwable ex ){ - ex.printStackTrace(); - } - } - }finally{ - is.close(); } - }catch( FileNotFoundException ignored ){ - }catch( Throwable ex ){ - ex.printStackTrace(); - Utils.showToast( this, ex, "loadColumnList failed." ); } - if( pager_adapter.column_list.size() > 0 ){ llEmpty.setVisibility( View.GONE ); } @@ -1400,8 +1388,84 @@ RelationResult loadRelation1( TootApiClient client, SavedAccount access_info, lo return rr; } - void callFollow( final SavedAccount access_info, final TootAccount who - , final boolean bFollow, final RelationChangedCallback callback ){ + void callFollow( + final SavedAccount access_info + , final TootAccount who + , final boolean bFollow + , boolean bConfirmed + , final RelationChangedCallback callback + ){ + if( access_info.isMe( who )){ + Utils.showToast( this,false,R.string.it_is_you ); + return; + } + + if( ! bConfirmed ){ + if( bFollow && who.locked ){ + DlgConfirm.open( this + , getString( R.string.confirm_follow_request_who_from,who.display_name ,AcctColor.getNickname( access_info.acct) ) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_follow_locked; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_follow_locked = bv; + access_info.saveSetting(); + reloadAccountSetting(access_info); + } + + @Override public void onOK(){ + //noinspection ConstantConditions + callFollow( access_info, who, bFollow, true, callback ); + } + } + ); + return; + }else if( bFollow ){ + DlgConfirm.open( this + , getString( R.string.confirm_follow_who_from,who.display_name ,AcctColor.getNickname( access_info.acct) ) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_follow; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_follow = bv; + access_info.saveSetting(); + reloadAccountSetting(access_info); + } + + @Override public void onOK(){ + //noinspection ConstantConditions + callFollow( access_info, who, bFollow, true, callback ); + } + } + ); + return; + }else{ + DlgConfirm.open( this + , getString( R.string.confirm_unfollow_who_from, who.display_name ,AcctColor.getNickname( access_info.acct)) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_unfollow; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_unfollow = bv; + access_info.saveSetting(); + reloadAccountSetting(access_info); + } + + @Override public void onOK(){ + //noinspection ConstantConditions + callFollow( access_info, who, bFollow, true, callback ); + } + } + ); + return; + } + } new AsyncTask< Void, Void, TootApiResult >() { @Override protected TootApiResult doInBackground( Void... params ){ @@ -1488,11 +1552,18 @@ protected void onPostExecute( TootApiResult result ){ if( result == null ){ // cancelled. }else if( relation != null ){ - // ローカル操作成功、もしくはリモートフォロー成功 showColumnMatchAccount( access_info ); - if( callback != null ) callback.onRelationChanged(); + if( bFollow && relation.requested ){ + // 鍵付きアカウントにフォローリクエストを申請した状態 + Utils.showToast( ActMain.this, false, R.string.follow_requested ); + }else if( !bFollow && relation.requested ){ + Utils.showToast( ActMain.this, false, R.string.follow_request_cant_remove_by_sender ); + }else{ + // ローカル操作成功、もしくはリモートフォロー成功 + if( callback != null ) callback.onRelationChanged(); + } }else if( bFollow && who.locked && result.response != null && result.response.code() == 422 ){ Utils.showToast( ActMain.this, false, R.string.cant_follow_locked_user ); @@ -1506,8 +1577,58 @@ protected void onPostExecute( TootApiResult result ){ // acct で指定したユーザをリモートフォローする void callRemoteFollow( final SavedAccount access_info - , final String acct, final boolean locked, final RelationChangedCallback callback + , final String acct, final boolean locked, boolean bConfirmed, final RelationChangedCallback callback ){ + if( access_info.isMe( acct )){ + Utils.showToast( this,false,R.string.it_is_you ); + return; + } + + if( ! bConfirmed ){ + if( locked ){ + DlgConfirm.open( this + , getString( R.string.confirm_follow_request_who_from, AcctColor.getNickname( acct ) , AcctColor.getNickname( access_info.acct ) ) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_follow_locked; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_follow_locked = bv; + access_info.saveSetting(); + reloadAccountSetting(access_info); + } + + @Override public void onOK(){ + //noinspection ConstantConditions + callRemoteFollow( access_info, acct, locked, true, callback ); + } + } + ); + return; + }else{ + DlgConfirm.open( this + , getString( R.string.confirm_follow_who_from, AcctColor.getNickname( acct ) , AcctColor.getNickname( access_info.acct ) ) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return access_info.confirm_follow; + } + + @Override public void setConfirmEnabled( boolean bv ){ + access_info.confirm_follow = bv; + access_info.saveSetting(); + reloadAccountSetting(); + } + + @Override public void onOK(){ + //noinspection ConstantConditions + callRemoteFollow( access_info, acct, locked, true, callback ); + } + } + ); + return; + } + } new AsyncTask< Void, Void, TootApiResult >() { diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActPost.java b/app/src/main/java/jp/juggler/subwaytooter/ActPost.java index 4d44cad3b..b725036e3 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActPost.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ActPost.java @@ -1,10 +1,10 @@ package jp.juggler.subwaytooter; import android.Manifest; +import android.app.Activity; import android.app.ProgressDialog; import android.content.ClipData; import android.content.ContentValues; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -61,6 +61,7 @@ import jp.juggler.subwaytooter.api.entity.TootAttachment; import jp.juggler.subwaytooter.api.entity.TootMention; import jp.juggler.subwaytooter.api.entity.TootStatus; +import jp.juggler.subwaytooter.dialog.DlgConfirm; import jp.juggler.subwaytooter.table.AcctColor; import jp.juggler.subwaytooter.table.AcctSet; import jp.juggler.subwaytooter.table.SavedAccount; @@ -90,22 +91,22 @@ public class ActPost extends AppCompatActivity implements View.OnClickListener { static final String KEY_IN_REPLY_TO_TEXT = "in_reply_to_text"; static final String KEY_IN_REPLY_TO_IMAGE = "in_reply_to_image"; - public static void open( Context context, long account_db_id, TootStatus reply_status ){ - Intent intent = new Intent( context, ActPost.class ); + public static void open( Activity activity, int request_code, long account_db_id, TootStatus reply_status ){ + Intent intent = new Intent( activity, ActPost.class ); intent.putExtra( KEY_ACCOUNT_DB_ID, account_db_id ); if( reply_status != null ){ intent.putExtra( KEY_REPLY_STATUS, reply_status.json.toString() ); } - context.startActivity( intent ); + activity.startActivityForResult( intent, request_code ); } - public static void open( Context context, long account_db_id, String initial_text ){ - Intent intent = new Intent( context, ActPost.class ); + public static void open( Activity activity, int request_code, long account_db_id, String initial_text ){ + Intent intent = new Intent( activity, ActPost.class ); intent.putExtra( KEY_ACCOUNT_DB_ID, account_db_id ); if( initial_text != null ){ intent.putExtra( KEY_INITIAL_TEXT, initial_text ); } - context.startActivity( intent ); + activity.startActivityForResult( intent, request_code ); } @Override @@ -148,7 +149,7 @@ public void onClick( View v ){ break; case R.id.btnPost: - performPost(); + performPost( false ); break; case R.id.btnRemoveReply: @@ -1205,12 +1206,13 @@ public void onClick( DialogInterface dialog, int which ){ /////////////////////////////////////////////////////////////////////////////////////// // post - private void performPost(){ + private void performPost( boolean bConfirm ){ final String content = etContent.getText().toString().trim(); if( TextUtils.isEmpty( content ) ){ Utils.showToast( this, true, R.string.post_error_contents_empty ); return; } + final String spoiler_text; if( ! cbContentWarning.isChecked() ){ spoiler_text = null; @@ -1222,6 +1224,26 @@ private void performPost(){ } } + if( ! bConfirm ){ + DlgConfirm.open( this + , getString( R.string.confirm_post_from, AcctColor.getNickname( account.acct ) ) + , new DlgConfirm.Callback() { + @Override public boolean isConfirmEnabled(){ + return account.confirm_post; + } + + @Override public void setConfirmEnabled( boolean bv ){ + account.confirm_post = bv; + account.saveSetting(); + } + + @Override public void onOK(){ + performPost( true ); + } + } ); + return; + } + final StringBuilder sb = new StringBuilder(); sb.append( "status=" ); @@ -1305,6 +1327,7 @@ protected void onPostExecute( TootApiResult result ){ }else if( status != null ){ // 連投してIdempotency が同じだった場合もエラーにはならず、ここを通る ActMain.update_at_resume = true; + setResult( RESULT_OK ); ActPost.this.finish(); }else{ Utils.showToast( ActPost.this, true, result.error ); diff --git a/app/src/main/java/jp/juggler/subwaytooter/App1.java b/app/src/main/java/jp/juggler/subwaytooter/App1.java index af1aa1223..f4f1b5778 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/App1.java +++ b/app/src/main/java/jp/juggler/subwaytooter/App1.java @@ -17,6 +17,13 @@ import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.Volley; +import org.apache.commons.io.IOUtils; +import org.json.JSONArray; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Collections; @@ -30,6 +37,7 @@ import jp.juggler.subwaytooter.table.NotificationTracking; import jp.juggler.subwaytooter.table.SavedAccount; import jp.juggler.subwaytooter.table.UserRelation; +import jp.juggler.subwaytooter.util.Utils; import okhttp3.CipherSuite; import okhttp3.ConnectionSpec; import okhttp3.OkHttpClient; @@ -42,7 +50,7 @@ public class App1 extends Application { static final String DB_NAME = "app_db"; - static final int DB_VERSION = 9; + static final int DB_VERSION = 10; // 2017/4/25 v10 1=>2 SavedAccount に通知設定を追加 // 2017/4/25 v10 1=>2 NotificationTracking テーブルを追加 // 2017/4/29 v20 2=>5 MediaShown,ContentWarningのインデクスが間違っていたので貼り直す @@ -50,6 +58,7 @@ public class App1 extends Application { // 2017/5/01 v26 6=>7 AcctSetテーブルの追加 // 2017/5/02 v32 7=>8 (この変更は取り消された) // 2017/5/02 v32 8=>9 AcctColor テーブルの追加 + // 2017/5/04 v33 9=>10 SavedAccountに項目追加 static DBOpenHelper db_open_helper; @@ -73,6 +82,7 @@ public static void setActivityTheme( Activity activity ,boolean bNoActionBar ){ } } + private static class DBOpenHelper extends SQLiteOpenHelper { private DBOpenHelper(Context context) { @@ -238,4 +248,38 @@ public void onCreate(){ public void onTerminate(){ super.onTerminate(); } + + + public static void saveColumnList( Context context, String fileName, JSONArray array ){ + + try{ + OutputStream os = context.openFileOutput( fileName, MODE_PRIVATE ); + try{ + os.write( Utils.encodeUTF8( array.toString() ) ); + }finally{ + os.close(); + } + }catch( Throwable ex ){ + ex.printStackTrace(); + Utils.showToast( context, ex, "saveColumnList failed." ); + } + } + public static JSONArray loadColumnList( Context context, String fileName ){ + try{ + InputStream is = context.openFileInput( fileName ); + try{ + ByteArrayOutputStream bao = new ByteArrayOutputStream( is.available() ); + IOUtils.copy( is,bao); + return new JSONArray( Utils.decodeUTF8( bao.toByteArray() ) ); + }finally{ + is.close(); + } + }catch( FileNotFoundException ignored ){ + }catch( Throwable ex ){ + ex.printStackTrace(); + Utils.showToast( context, ex, "loadColumnList failed." ); + } + return null; + } + } diff --git a/app/src/main/java/jp/juggler/subwaytooter/Column.java b/app/src/main/java/jp/juggler/subwaytooter/Column.java index 733d410ec..705eb4649 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Column.java +++ b/app/src/main/java/jp/juggler/subwaytooter/Column.java @@ -312,7 +312,7 @@ String getColumnName( boolean bLong ){ case TYPE_PROFILE: - return activity.getString( R.string.statuses_of + return activity.getString( R.string.profile_of , who_account != null ? AcctColor.getNickname( access_info.getFullAcct( who_account ) ) : Long.toString( profile_id ) ); diff --git a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java index b42beecc6..7563900d1 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java +++ b/app/src/main/java/jp/juggler/subwaytooter/ColumnViewHolder.java @@ -350,6 +350,7 @@ public void onClick( View v ){ Utils.hideKeyboard( activity, etSearch ); column.search_query = etSearch.getText().toString().trim(); column.search_resolve = cbResolve.isChecked(); + activity.saveColumnList(); column.startLoading(); break; @@ -379,12 +380,6 @@ private void showError( String message ){ listView.setSelectionFromTop( 0, 0 ); } } - -// final RelationshipMap.UpdateCallback callback_relation = new RelationshipMap.UpdateCallback() { -// @Override public void onRelationShipUpdate(){ -// onVisualColumn(); -// } -// }; private int acct_pad_lr; @@ -411,7 +406,7 @@ private void showError( String message ){ showColumnCloseButton(); - ivColumnIcon.setImageResource( Styler.getAttributeResourceId( activity, Column.getIconAttrId(column.type) ) ); + ivColumnIcon.setImageResource( Styler.getAttributeResourceId( activity, Column.getIconAttrId( column.type ) ) ); } @@ -537,6 +532,7 @@ private class HeaderViewHolder implements View.OnClickListener { final View btnMore; final TextView tvNote; final ImageButton btnFollow; + final ImageView ivFollowedBy; TootAccount who; SavedAccount access_info; @@ -554,6 +550,7 @@ private class HeaderViewHolder implements View.OnClickListener { this.tvNote = (TextView) viewRoot.findViewById( R.id.tvNote ); this.btnMore = viewRoot.findViewById( R.id.btnMore ); this.btnFollow = (ImageButton) viewRoot.findViewById( R.id.btnFollow ); + this.ivFollowedBy = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy ); ivBackground.setOnClickListener( this ); btnFollowing.setOnClickListener( this ); btnFollowers.setOnClickListener( this ); @@ -597,7 +594,7 @@ void bind( ActMain activity, SavedAccount access_info, TootAccount who ){ btnFollowers.setText( activity.getString( R.string.followers ) + "\n" + who.followers_count ); UserRelation relation = UserRelation.load( access_info.db_id, who.id ); - Styler.setFollowIcon( activity, btnFollow, relation ); + Styler.setFollowIcon( activity, btnFollow,ivFollowedBy, relation ,column.type); } } @@ -629,13 +626,13 @@ public void onClick( View v ){ case R.id.btnMore: if( who != null ){ - new DlgContextMenu( activity, access_info, who, null ).show(); + new DlgContextMenu( activity, access_info, who, null, column.type ).show(); } break; case R.id.btnFollow: if( who != null ){ - new DlgContextMenu( activity, access_info, who, null ).show(); + new DlgContextMenu( activity, access_info, who, null, column.type ).show(); } break; @@ -706,6 +703,7 @@ private class StatusViewHolder implements View.OnClickListener, View.OnLongClick final TextView tvFollowerName; final TextView tvFollowerAcct; final ImageButton btnFollow; + final ImageView ivFollowedBy; final View llStatus; final NetworkImageView ivThumbnail; @@ -757,7 +755,8 @@ private class StatusViewHolder implements View.OnClickListener, View.OnLongClick this.tvFollowerName = (TextView) view.findViewById( R.id.tvFollowerName ); this.tvFollowerAcct = (TextView) view.findViewById( R.id.tvFollowerAcct ); this.btnFollow = (ImageButton) view.findViewById( R.id.btnFollow ); - + this.ivFollowedBy = (ImageView) view.findViewById( R.id.ivFollowedBy ); + this.llStatus = view.findViewById( R.id.llStatus ); this.ivThumbnail = (NetworkImageView) view.findViewById( R.id.ivThumbnail ); @@ -920,7 +919,7 @@ private void showFollow( TootAccount who ){ setAcct( tvFollowerAcct, access_info.getFullAcct( who ), R.attr.colorAcctSmall ); UserRelation relation = UserRelation.load( access_info.db_id, who.id ); - Styler.setFollowIcon( activity, btnFollow, relation ); + Styler.setFollowIcon( activity, btnFollow, ivFollowedBy,relation ,column.type); } private void showStatus( ActMain activity, TootStatus status ){ @@ -1069,7 +1068,7 @@ public void onClick( View v ){ activity.performOpenUser( access_info, account_follow ); break; case R.id.btnFollow: - new DlgContextMenu( activity, access_info, account_follow, null ).show(); + new DlgContextMenu( activity, access_info, account_follow, null, column.type ).show(); break; case R.id.btnSearchTag: @@ -1090,7 +1089,7 @@ public void onClick( View v ){ @Override public boolean onLongClick( View v ){ switch( v.getId() ){ case R.id.ivThumbnail: - new DlgContextMenu( activity, access_info, account_thumbnail, null ).show(); + new DlgContextMenu( activity, access_info, account_thumbnail, null, column.type ).show(); break; } return false; @@ -1148,6 +1147,9 @@ private class ButtonsForStatus implements View.OnClickListener { final Button btnBoost; final Button btnFavourite; final ImageButton btnMore; + final ImageButton btnFollow2; + final ImageView ivFollowedBy2; + final View llFollow2; ButtonsForStatus( View viewRoot ){ btnConversation = (ImageButton) viewRoot.findViewById( R.id.btnConversation ); @@ -1155,15 +1157,21 @@ private class ButtonsForStatus implements View.OnClickListener { btnBoost = (Button) viewRoot.findViewById( R.id.btnBoost ); btnFavourite = (Button) viewRoot.findViewById( R.id.btnFavourite ); btnMore = (ImageButton) viewRoot.findViewById( R.id.btnMore ); + btnFollow2 = (ImageButton) viewRoot.findViewById( R.id.btnFollow2 ); + ivFollowedBy2 = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy2 ); + llFollow2 = viewRoot.findViewById( R.id.llFollow2 ); + btnConversation.setOnClickListener( this ); btnReply.setOnClickListener( this ); btnBoost.setOnClickListener( this ); btnFavourite.setOnClickListener( this ); btnMore.setOnClickListener( this ); + btnFollow2.setOnClickListener( this ); } TootStatus status; + UserRelation relation; void bind( TootStatus status ){ this.status = status; @@ -1189,6 +1197,16 @@ void bind( TootStatus status ){ setButton( btnFavourite, true, color, R.attr.btn_favourite, Long.toString( status.favourites_count ) ); } + if( ! activity.pref.getBoolean( Pref.KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR, false ) ){ + llFollow2.setVisibility( View.GONE ); + this.relation = null; + }else{ + llFollow2.setVisibility( View.VISIBLE ); + this.relation = UserRelation.load( access_info.db_id, status.account.id ); + Styler.setFollowIcon( activity, btnFollow2, ivFollowedBy2, relation ,column.type); + + } + } private void setButton( Button b, boolean enabled, int color, int icon_attr, String text ){ @@ -1230,7 +1248,17 @@ private void setButton( Button b, boolean enabled, int color, int icon_attr, Str } break; case R.id.btnMore: - new DlgContextMenu( activity, access_info, status.account, status ).show(); + new DlgContextMenu( activity, access_info, status.account, status, column.type ).show(); + break; + case R.id.btnFollow2: + //noinspection StatementWithEmptyBody + if( relation.blocking || relation.muting ){ + // 何もしない + }else if( relation.following || relation.requested ){ + activity.callFollow( access_info, status.account, false,false, activity.unfollow_complete_callback ); + }else{ + activity.callFollow( access_info, status.account, true, false,activity.follow_complete_callback ); + } break; } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/DlgContextMenu.java b/app/src/main/java/jp/juggler/subwaytooter/DlgContextMenu.java index 680105dbc..219e3885d 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/DlgContextMenu.java +++ b/app/src/main/java/jp/juggler/subwaytooter/DlgContextMenu.java @@ -22,6 +22,7 @@ import jp.juggler.subwaytooter.table.SavedAccount; import jp.juggler.subwaytooter.table.UserRelation; import jp.juggler.subwaytooter.util.LogCategory; +import jp.juggler.subwaytooter.util.Utils; class DlgContextMenu implements View.OnClickListener { @@ -43,6 +44,7 @@ class DlgContextMenu implements View.OnClickListener { , @NonNull SavedAccount access_info , @NonNull TootAccount who , @Nullable TootStatus status + ,int column_type ){ this.activity = activity; this.access_info = access_info; @@ -128,10 +130,19 @@ class DlgContextMenu implements View.OnClickListener { btnMute.setOnClickListener( this ); btnBlock.setOnClickListener( this ); + // 被フォロー状態 + ImageView ivFollowedBy = (ImageView) viewRoot.findViewById( R.id. ivFollowedBy); + if( !relation.followed_by){ + ivFollowedBy.setVisibility( View.GONE ); + }else{ + ivFollowedBy.setVisibility( View.VISIBLE ); + ivFollowedBy.setImageResource( Styler.getAttributeResourceId( activity,R.attr.ic_followed_by )); + } + // follow button - int icon_attr = ( relation.following ? R.attr.ic_account_remove : R.attr.ic_account_add ); + int icon_attr = ( relation.following ? R.attr.ic_follow_cross : R.attr.ic_follow_plus ); int color_attr = ( relation.requested ? R.attr.colorRegexFilterError - : relation.followed_by ? R.attr.colorImageButtonAccent + : relation.following ? R.attr.colorImageButtonAccent : R.attr.colorImageButton ); int color = Styler.getAttributeColor( activity, color_attr ); Drawable d = Styler.getAttributeDrawable( activity, icon_attr ).mutate(); @@ -165,7 +176,7 @@ class DlgContextMenu implements View.OnClickListener { btnAccountWebPage.setOnClickListener( this ); - if( relation.requested ){ + if( column_type == Column.TYPE_FOLLOW_REQUESTS ){ btnFollowRequestOK.setOnClickListener( this ); btnFollowRequestNG.setOnClickListener( this ); }else{ @@ -271,10 +282,10 @@ void show(){ break; case R.id.btnFollow: - if( relation.following ){ - activity.callFollow( access_info, who, false, activity.unfollow_complete_callback ); + if( relation.following || relation.requested ){ + activity.callFollow( access_info, who, false, false,activity.unfollow_complete_callback ); }else{ - activity.callFollow( access_info, who, true, activity.follow_complete_callback ); + activity.callFollow( access_info, who, true, false,activity.follow_complete_callback ); } break; @@ -334,7 +345,7 @@ void show(){ final String who_acct = access_info.getFullAcct( who ); AccountPicker.pick( activity, false, false, account_list_non_pseudo, new AccountPicker.AccountPickerCallback() { @Override public void onAccountPicked( SavedAccount ai ){ - activity.callRemoteFollow( ai, who_acct, who.locked, activity.follow_complete_callback ); + activity.callRemoteFollow( ai, who_acct, who.locked, false,activity.follow_complete_callback ); } } ); break; diff --git a/app/src/main/java/jp/juggler/subwaytooter/Pref.java b/app/src/main/java/jp/juggler/subwaytooter/Pref.java index 0ec30b5a4..82c86472c 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Pref.java +++ b/app/src/main/java/jp/juggler/subwaytooter/Pref.java @@ -23,6 +23,7 @@ static SharedPreferences pref( Context context ){ static final String KEY_NOTIFICATION_VIBRATION = "notification_vibration"; static final String KEY_NOTIFICATION_LED = "notification_led"; static final String KEY_EXIT_APP_WHEN_CLOSE_PROTECTED_COLUMN = "ExitAppWhenCloseProtectedColumn"; - public static final String KEY_RESIZE_IMAGE = "resize_image"; + static final String KEY_RESIZE_IMAGE = "resize_image"; + static final String KEY_SHOW_FOLLOW_BUTTON_IN_BUTTON_BAR = "ShowFollowButtonInButtonBar"; } diff --git a/app/src/main/java/jp/juggler/subwaytooter/Styler.java b/app/src/main/java/jp/juggler/subwaytooter/Styler.java index 385e8f855..9b771993f 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/Styler.java +++ b/app/src/main/java/jp/juggler/subwaytooter/Styler.java @@ -7,7 +7,9 @@ import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; +import android.view.View; import android.widget.ImageButton; +import android.widget.ImageView; import java.util.Locale; @@ -59,27 +61,63 @@ static int getAttributeResourceId(@NonNull Context context, int attr_id ){ return res_id; } - static void setFollowIcon( @NonNull Context context ,@NonNull ImageButton ib, UserRelation relation ){ - int icon_attr; - int color_attr; + static void setFollowIcon( + @NonNull Context context + , @NonNull ImageButton ib + , @NonNull ImageView iv + , @NonNull UserRelation relation + ,int column_type + + ){ + + // 被フォロー状態 + if( !relation.followed_by ){ + iv.setVisibility( View.GONE ); + }else{ + iv.setVisibility( View.VISIBLE ); + iv.setImageResource( Styler.getAttributeResourceId( context,R.attr.ic_followed_by )); +// 被フォローリクエスト状態の時に followed_by が 真と偽の両方がありえるようなので +// Relationshipだけを見ても被フォローリクエスト状態は分からないっぽい +// 仕方ないので馬鹿正直に「 followed_byが真ならバッジをつける」しかできない +// if( column_type == Column.TYPE_FOLLOW_REQUESTS ){ +// // フォローリクエストされてる状態でも followed_by はtrueになる +// int color = Styler.getAttributeColor( context,R.attr.colorRegexFilterError ); +// Drawable d = Styler.getAttributeDrawable( context,R.attr.ic_followed_by ).mutate(); +// d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP ); +// iv.setImageDrawable( d ); +// } + } + + // follow button + int color_attr ; + int icon_attr; + if( relation.blocking ){ - color_attr = ( relation.followed_by ? R.attr.colorImageButtonAccent : R.attr.colorImageButton); icon_attr = R.attr.ic_block; + color_attr = R.attr.colorImageButton; + }else if( relation.muting ){ - color_attr = ( relation.followed_by ? R.attr.colorImageButtonAccent : R.attr.colorImageButton); icon_attr = R.attr.ic_mute; + color_attr = R.attr.colorImageButton; + + }else if( relation.following ){ + icon_attr = R.attr.ic_follow_cross; + color_attr = R.attr.colorImageButtonAccent; + }else if( relation.requested ){ + icon_attr =R.attr.ic_follow_plus; color_attr = R.attr.colorRegexFilterError; - icon_attr = (relation.following ? R.attr.ic_account_remove: R.attr.ic_account_add ); }else{ - color_attr = ( relation.followed_by ? R.attr.colorImageButtonAccent : R.attr.colorImageButton ); - icon_attr = ( relation.following ? R.attr.ic_account_remove : R.attr.ic_account_add ); + icon_attr =R.attr.ic_follow_plus; + color_attr = R.attr.colorImageButton; } int color = Styler.getAttributeColor( context,color_attr ); Drawable d = Styler.getAttributeDrawable( context,icon_attr ).mutate(); d.setColorFilter( color, PorterDuff.Mode.SRC_ATOP ); ib.setImageDrawable( d ); + + } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.java b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.java new file mode 100644 index 000000000..3e2b78b91 --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.java @@ -0,0 +1,54 @@ +package jp.juggler.subwaytooter.dialog; + +import android.app.Activity; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import jp.juggler.subwaytooter.R; + +public class DlgConfirm { + + public interface Callback { + boolean isConfirmEnabled(); + + void setConfirmEnabled( boolean bv ); + + void onOK(); + } + + public static void open( + final Activity activity + , String message + , final Callback callback + ){ + + if( ! callback.isConfirmEnabled() ){ + callback.onOK(); + return; + } + + final View view = activity.getLayoutInflater().inflate( R.layout.dlg_confirm, null, false ); + final TextView tvMessage = (TextView) view.findViewById( R.id.tvMessage ); + final CheckBox cbSkipNext = (CheckBox) view.findViewById( R.id.cbSkipNext ); + tvMessage.setText( message ); + + new AlertDialog.Builder( activity ) + .setView( view ) + .setCancelable( true ) + .setNegativeButton( R.string.cancel, null ) + .setPositiveButton( R.string.ok, new DialogInterface.OnClickListener() { + @Override public void onClick( DialogInterface dialog, int which ){ + if( cbSkipNext.isChecked() ){ + callback.setConfirmEnabled( false ); + } + callback.onOK(); + } + } ) + .show(); + } + +} + diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.java b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.java index a10678030..383ab403b 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.java +++ b/app/src/main/java/jp/juggler/subwaytooter/table/SavedAccount.java @@ -34,10 +34,16 @@ public class SavedAccount extends TootAccount implements LinkClickContext { private static final String COL_VISIBILITY = "visibility"; private static final String COL_CONFIRM_BOOST = "confirm_boost"; private static final String COL_DONT_HIDE_NSFW = "dont_hide_nsfw"; + // スキーマ2から private static final String COL_NOTIFICATION_MENTION = "notification_mention"; private static final String COL_NOTIFICATION_BOOST = "notification_boost"; private static final String COL_NOTIFICATION_FAVOURITE = "notification_favourite"; private static final String COL_NOTIFICATION_FOLLOW = "notification_follow"; + // スキーマ10から + private static final String COL_CONFIRM_FOLLOW = "confirm_follow"; + private static final String COL_CONFIRM_FOLLOW_LOCKED = "confirm_follow_locked"; + private static final String COL_CONFIRM_UNFOLLOW = "confirm_unfollow"; + private static final String COL_CONFIRM_POST = "confirm_post"; public static final long INVALID_ID = - 1L; @@ -54,6 +60,11 @@ public class SavedAccount extends TootAccount implements LinkClickContext { public boolean notification_favourite; public boolean notification_follow; + public boolean confirm_follow; + public boolean confirm_follow_locked; + public boolean confirm_unfollow; + public boolean confirm_post; + public static void onDBCreate( SQLiteDatabase db ){ db.execSQL( "create table if not exists " + table @@ -65,11 +76,18 @@ public static void onDBCreate( SQLiteDatabase db ){ + ",visibility text" + ",confirm_boost integer default 1" + ",dont_hide_nsfw integer default 0" + // 以下はDBスキーマ2で追加 + ",notification_mention integer default 1" + ",notification_boost integer default 1" + ",notification_favourite integer default 1" + ",notification_follow integer default 1" + + // 以下はDBスキーマ10で更新 + + "," + COL_CONFIRM_FOLLOW + " integer default 1" + + "," + COL_CONFIRM_FOLLOW_LOCKED + " integer default 1" + + "," + COL_CONFIRM_UNFOLLOW + " integer default 1" + + "," + COL_CONFIRM_POST + " integer default 1" + ")" ); db.execSQL( "create index if not exists " + table + "_user on " + table + "(u)" ); @@ -99,6 +117,28 @@ public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersio ex.printStackTrace(); } } + if( oldVersion < 10 && newVersion >= 10 ){ + try{ + db.execSQL( "alter table " + table + " add column " + COL_CONFIRM_FOLLOW + " integer default 1" ); + }catch( Throwable ex ){ + ex.printStackTrace(); + } + try{ + db.execSQL( "alter table " + table + " add column " + COL_CONFIRM_FOLLOW_LOCKED + " integer default 1" ); + }catch( Throwable ex ){ + ex.printStackTrace(); + } + try{ + db.execSQL( "alter table " + table + " add column " + COL_CONFIRM_UNFOLLOW + " integer default 1" ); + }catch( Throwable ex ){ + ex.printStackTrace(); + } + try{ + db.execSQL( "alter table " + table + " add column " + COL_CONFIRM_POST + " integer default 1" ); + }catch( Throwable ex ){ + ex.printStackTrace(); + } + } } private SavedAccount(){ @@ -124,6 +164,11 @@ private static SavedAccount parse( Cursor cursor ) throws JSONException{ dst.notification_favourite = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_NOTIFICATION_FAVOURITE ) ) ); dst.notification_follow = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_NOTIFICATION_FOLLOW ) ) ); + dst.confirm_follow = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_CONFIRM_FOLLOW ) ) ); + dst.confirm_follow_locked = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_CONFIRM_FOLLOW_LOCKED ) ) ); + dst.confirm_unfollow = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_CONFIRM_UNFOLLOW ) ) ); + dst.confirm_post = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_CONFIRM_POST ) ) ); + dst.token_info = new JSONObject( cursor.getString( cursor.getColumnIndex( COL_TOKEN ) ) ); } return dst; @@ -177,6 +222,12 @@ public void saveSetting(){ cv.put( COL_NOTIFICATION_BOOST, notification_boost ? 1 : 0 ); cv.put( COL_NOTIFICATION_FAVOURITE, notification_favourite ? 1 : 0 ); cv.put( COL_NOTIFICATION_FOLLOW, notification_follow ? 1 : 0 ); + + cv.put( COL_CONFIRM_FOLLOW, confirm_follow ? 1 : 0 ); + cv.put( COL_CONFIRM_FOLLOW_LOCKED, confirm_follow_locked ? 1 : 0 ); + cv.put( COL_CONFIRM_UNFOLLOW, confirm_unfollow ? 1 : 0 ); + cv.put( COL_CONFIRM_POST, confirm_post ? 1 : 0 ); + App1.getDB().update( table, cv, COL_ID + "=?", new String[]{ Long.toString( db_id ) } ); } @@ -266,8 +317,8 @@ public boolean isMe( @NonNull String who_acct ){ } public String supplyBaseUrl( String url ){ - if( TextUtils.isEmpty(url)) return url; - if( url.charAt( 0 )=='/') return "https://"+host+url; + if( TextUtils.isEmpty( url ) ) return url; + if( url.charAt( 0 ) == '/' ) return "https://" + host + url; return url; } @@ -279,7 +330,7 @@ public boolean isPseudo(){ @Override public AcctColor findAcctColor( String url ){ Matcher m = reAcctUrl.matcher( url ); - if( m.find() ) return AcctColor.load( m.group(2)+"@"+m.group(1) ); + if( m.find() ) return AcctColor.load( m.group( 2 ) + "@" + m.group( 1 ) ); return null; } } diff --git a/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.java b/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.java index a6ed4361f..1a5764bdd 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.java +++ b/app/src/main/java/jp/juggler/subwaytooter/table/UserRelation.java @@ -3,6 +3,8 @@ import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.support.annotation.NonNull; +import android.support.v4.util.LruCache; import java.util.HashSet; @@ -29,136 +31,149 @@ public static void onDBCreate( SQLiteDatabase db ){ db.execSQL( "create table if not exists " + table + "(_id INTEGER PRIMARY KEY" - + ","+COL_TIME_SAVE+" integer not null" - + ","+COL_DB_ID+" integer not null" - + ","+COL_WHO_ID+" integer not null" - + ","+COL_FOLLOWING+" integer not null" - + ","+COL_FOLLOWED_BY+" integer not null" - + ","+COL_BLOCKING+" integer not null" - + ","+COL_MUTING+" integer not null" - + ","+COL_REQUESTED+" integer not null" + + "," + COL_TIME_SAVE + " integer not null" + + "," + COL_DB_ID + " integer not null" + + "," + COL_WHO_ID + " integer not null" + + "," + COL_FOLLOWING + " integer not null" + + "," + COL_FOLLOWED_BY + " integer not null" + + "," + COL_BLOCKING + " integer not null" + + "," + COL_MUTING + " integer not null" + + "," + COL_REQUESTED + " integer not null" + ")" ); db.execSQL( - "create unique index if not exists " + table + "_id on " + table + "("+COL_DB_ID+","+COL_WHO_ID+")" + "create unique index if not exists " + table + "_id on " + table + "(" + COL_DB_ID + "," + COL_WHO_ID + ")" ); db.execSQL( - "create index if not exists " + table + "_time on " + table + "("+COL_TIME_SAVE+")" + "create index if not exists " + table + "_time on " + table + "(" + COL_TIME_SAVE + ")" ); } public static void onDBUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ){ - if(oldVersion < 6 && newVersion >= 6){ + if( oldVersion < 6 && newVersion >= 6 ){ onDBCreate( db ); } } - public static void deleteOld( long now){ + public static void deleteOld( long now ){ try{ // 古いデータを掃除する long expire = now - 86400000L * 365; - App1.getDB().delete( table,COL_TIME_SAVE+" load_where_arg = new ThreadLocal() { - @Override protected String[] initialValue() { - return new String[2]; + if( bOK ){ + db.execSQL( "COMMIT TRANSACTION" ); + for( TootRelationShip src : src_list ){ + String key = String.format( "%s:%s", db_id, src.id ); + mMemoryCache.remove( key ); + } + }else{ + db.execSQL( "ROLLBACK TRANSACTION" ); } - }; + } public boolean following; public boolean followed_by; public boolean blocking; public boolean muting; public boolean requested; - + private UserRelation(){ } - - public static UserRelation load( long db_id, long who_id ){ + + private static final LruCache< String, UserRelation > mMemoryCache = new LruCache<>( 2048 ); + + static final String load_where = COL_DB_ID + "=? and " + COL_WHO_ID + "=?"; + private static final ThreadLocal< String[] > load_where_arg = new ThreadLocal< String[] >() { + @Override protected String[] initialValue(){ + return new String[ 2 ]; + } + }; + + @NonNull public static UserRelation load( long db_id, long who_id ){ + + String key = String.format( "%s:%s", db_id, who_id ); + UserRelation dst = mMemoryCache.get( key ); + + if( dst != null ) return dst; + try{ String[] where_arg = load_where_arg.get(); - where_arg[0] = Long.toString( db_id ); - where_arg[1] = Long.toString( who_id ); - Cursor cursor = App1.getDB().query( table,null,load_where,where_arg,null,null,null ); - if( cursor != null){ + where_arg[ 0 ] = Long.toString( db_id ); + where_arg[ 1 ] = Long.toString( who_id ); + Cursor cursor = App1.getDB().query( table, null, load_where, where_arg, null, null, null ); + if( cursor != null ){ try{ if( cursor.moveToNext() ){ - UserRelation dst = new UserRelation(); - dst.following = (0!=cursor.getInt( cursor.getColumnIndex( COL_FOLLOWING ) )); - dst.followed_by = (0!=cursor.getInt( cursor.getColumnIndex( COL_FOLLOWED_BY ) )); - dst.blocking = (0!=cursor.getInt( cursor.getColumnIndex( COL_BLOCKING ) )); - dst.muting = (0!=cursor.getInt( cursor.getColumnIndex( COL_MUTING ) )); - dst.requested = (0!=cursor.getInt( cursor.getColumnIndex( COL_REQUESTED ) )); + dst = new UserRelation(); + dst.following = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_FOLLOWING ) ) ); + dst.followed_by = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_FOLLOWED_BY ) ) ); + dst.blocking = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_BLOCKING ) ) ); + dst.muting = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_MUTING ) ) ); + dst.requested = ( 0 != cursor.getInt( cursor.getColumnIndex( COL_REQUESTED ) ) ); return dst; } }finally{ cursor.close(); } } - }catch(Throwable ex){ - ex.printStackTrace( ); - log.e(ex,"load failed."); + }catch( Throwable ex ){ + ex.printStackTrace(); + log.e( ex, "load failed." ); } - return new UserRelation(); + dst = new UserRelation(); + mMemoryCache.put( key, dst ); + return dst; } // public static Cursor createCursor(){ diff --git a/app/src/main/res/drawable-hdpi/ic_account_remove.png b/app/src/main/res/drawable-hdpi/ic_account_remove.png deleted file mode 100644 index 07147fbc2..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_account_remove.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_account_remove_dark.png b/app/src/main/res/drawable-hdpi/ic_account_remove_dark.png deleted file mode 100644 index 908d7b53d..000000000 Binary files a/app/src/main/res/drawable-hdpi/ic_account_remove_dark.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/ic_follow_cross.png b/app/src/main/res/drawable-hdpi/ic_follow_cross.png new file mode 100644 index 000000000..81110ae11 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_follow_cross.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_follow_cross_dark.png b/app/src/main/res/drawable-hdpi/ic_follow_cross_dark.png new file mode 100644 index 000000000..f1e25225a Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_follow_cross_dark.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_follow_plus.png b/app/src/main/res/drawable-hdpi/ic_follow_plus.png new file mode 100644 index 000000000..39cdf7914 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_follow_plus.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_follow_plus_dark.png b/app/src/main/res/drawable-hdpi/ic_follow_plus_dark.png new file mode 100644 index 000000000..6ecc368db Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_follow_plus_dark.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_followed_by.png b/app/src/main/res/drawable-hdpi/ic_followed_by.png new file mode 100644 index 000000000..b5b0e8f4c Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_followed_by.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_followed_by_dark.png b/app/src/main/res/drawable-hdpi/ic_followed_by_dark.png new file mode 100644 index 000000000..e0cee2269 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_followed_by_dark.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_account_remove.png b/app/src/main/res/drawable-mdpi/ic_account_remove.png deleted file mode 100644 index 08ffab140..000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_account_remove.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_account_remove_dark.png b/app/src/main/res/drawable-mdpi/ic_account_remove_dark.png deleted file mode 100644 index edacbbfe8..000000000 Binary files a/app/src/main/res/drawable-mdpi/ic_account_remove_dark.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_follow_cross.png b/app/src/main/res/drawable-mdpi/ic_follow_cross.png new file mode 100644 index 000000000..4c4485d2a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_follow_cross.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_follow_cross_dark.png b/app/src/main/res/drawable-mdpi/ic_follow_cross_dark.png new file mode 100644 index 000000000..bedc2ce3f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_follow_cross_dark.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_follow_plus.png b/app/src/main/res/drawable-mdpi/ic_follow_plus.png new file mode 100644 index 000000000..9d6073b52 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_follow_plus.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_follow_plus_dark.png b/app/src/main/res/drawable-mdpi/ic_follow_plus_dark.png new file mode 100644 index 000000000..98946affe Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_follow_plus_dark.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_followed_by.png b/app/src/main/res/drawable-mdpi/ic_followed_by.png new file mode 100644 index 000000000..2635f1851 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_followed_by.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_followed_by_dark.png b/app/src/main/res/drawable-mdpi/ic_followed_by_dark.png new file mode 100644 index 000000000..b95dd2fea Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_followed_by_dark.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_account_remove.png b/app/src/main/res/drawable-xhdpi/ic_account_remove.png deleted file mode 100644 index 692dbad7c..000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_account_remove.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_account_remove_dark.png b/app/src/main/res/drawable-xhdpi/ic_account_remove_dark.png deleted file mode 100644 index 252115437..000000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_account_remove_dark.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/ic_follow_cross.png b/app/src/main/res/drawable-xhdpi/ic_follow_cross.png new file mode 100644 index 000000000..7950b2239 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_follow_cross.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_follow_cross_dark.png b/app/src/main/res/drawable-xhdpi/ic_follow_cross_dark.png new file mode 100644 index 000000000..246b08434 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_follow_cross_dark.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_follow_plus.png b/app/src/main/res/drawable-xhdpi/ic_follow_plus.png new file mode 100644 index 000000000..30d0b4092 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_follow_plus.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_follow_plus_dark.png b/app/src/main/res/drawable-xhdpi/ic_follow_plus_dark.png new file mode 100644 index 000000000..2cd63847f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_follow_plus_dark.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_followed_by.png b/app/src/main/res/drawable-xhdpi/ic_followed_by.png new file mode 100644 index 000000000..a9d228a2d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_followed_by.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_followed_by_dark.png b/app/src/main/res/drawable-xhdpi/ic_followed_by_dark.png new file mode 100644 index 000000000..48db1fcb6 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_followed_by_dark.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_remove.png b/app/src/main/res/drawable-xxhdpi/ic_account_remove.png deleted file mode 100644 index d8a0a1e55..000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_account_remove.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_account_remove_dark.png b/app/src/main/res/drawable-xxhdpi/ic_account_remove_dark.png deleted file mode 100644 index 6cb6fcbe1..000000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_account_remove_dark.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_follow_cross.png b/app/src/main/res/drawable-xxhdpi/ic_follow_cross.png new file mode 100644 index 000000000..2e6b6d24a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_follow_cross.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_follow_cross_dark.png b/app/src/main/res/drawable-xxhdpi/ic_follow_cross_dark.png new file mode 100644 index 000000000..b30426f7e Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_follow_cross_dark.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_follow_plus.png b/app/src/main/res/drawable-xxhdpi/ic_follow_plus.png new file mode 100644 index 000000000..871edb5d5 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_follow_plus.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_follow_plus_dark.png b/app/src/main/res/drawable-xxhdpi/ic_follow_plus_dark.png new file mode 100644 index 000000000..f3ef2da3c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_follow_plus_dark.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_followed_by.png b/app/src/main/res/drawable-xxhdpi/ic_followed_by.png new file mode 100644 index 000000000..a1261e909 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_followed_by.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_followed_by_dark.png b/app/src/main/res/drawable-xxhdpi/ic_followed_by_dark.png new file mode 100644 index 000000000..dea47c617 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_followed_by_dark.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_remove.png b/app/src/main/res/drawable-xxxhdpi/ic_account_remove.png deleted file mode 100644 index c673ec761..000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_account_remove.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_account_remove_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_account_remove_dark.png deleted file mode 100644 index 26bea29db..000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_account_remove_dark.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_follow_cross.png b/app/src/main/res/drawable-xxxhdpi/ic_follow_cross.png new file mode 100644 index 000000000..8e78661a7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_follow_cross.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_follow_cross_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_follow_cross_dark.png new file mode 100644 index 000000000..48f86f198 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_follow_cross_dark.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_follow_plus.png b/app/src/main/res/drawable-xxxhdpi/ic_follow_plus.png new file mode 100644 index 000000000..41d3c4714 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_follow_plus.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_follow_plus_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_follow_plus_dark.png new file mode 100644 index 000000000..0fdcd6192 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_follow_plus_dark.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_followed_by.png b/app/src/main/res/drawable-xxxhdpi/ic_followed_by.png new file mode 100644 index 000000000..924504db7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_followed_by.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_followed_by_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_followed_by_dark.png new file mode 100644 index 000000000..d1b1cf684 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_followed_by_dark.png differ diff --git a/app/src/main/res/layout/act_account_setting.xml b/app/src/main/res/layout/act_account_setting.xml index 01950fd33..4e7a5dfd5 100644 --- a/app/src/main/res/layout/act_account_setting.xml +++ b/app/src/main/res/layout/act_account_setting.xml @@ -137,18 +137,17 @@ - @@ -159,28 +158,62 @@ /> - - - + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/act_app_setting.xml b/app/src/main/res/layout/act_app_setting.xml index cd318bec0..6d5db66a5 100644 --- a/app/src/main/res/layout/act_app_setting.xml +++ b/app/src/main/res/layout/act_app_setting.xml @@ -1,533 +1,552 @@ - - + - + - - - - - + - + - + - + + - + - + - + - + - - + + - + - - + - - + - + - + - + - - + - + - + - + - - + + + + + + + + + - + - + - + - - + - - + - + - + - - + - + - - + - + + + + + + - + - + - + - + - - - - + + + + + + + + - + - - - - - + + + + + - - + + - - - - - + + + + + - + - + - + - + - - - + + + - + - + - + - + - - - - - + + + + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dlg_confirm.xml b/app/src/main/res/layout/dlg_confirm.xml new file mode 100644 index 000000000..d830d0a02 --- /dev/null +++ b/app/src/main/res/layout/dlg_confirm.xml @@ -0,0 +1,31 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dlg_context_menu.xml b/app/src/main/res/layout/dlg_context_menu.xml index f1fc925de..76169c87c 100644 --- a/app/src/main/res/layout/dlg_context_menu.xml +++ b/app/src/main/res/layout/dlg_context_menu.xml @@ -11,9 +11,9 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" + android:cacheColorHint="#00000000" android:fadeScrollbars="false" android:fadingEdgeLength="20dp" - android:cacheColorHint="#00000000" > - + android:layout_height="40dp"> + + + + + + + +