- システム通知をタップしても通知が消えなかった問題の対策
- アンケート項目の文字数制限を検証
- 1.6の固定トゥート機能に対応
This commit is contained in:
tateisu 2017-09-04 01:36:15 +09:00
parent 591b2272ab
commit d18ccc1132
17 changed files with 273 additions and 31 deletions

BIN
_ArtWork/ic_pin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

BIN
_ArtWork/ic_pin.xcf Normal file

Binary file not shown.

BIN
_ArtWork/ic_pin_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

View File

@ -1765,6 +1765,7 @@ public class ActMain extends AppCompatActivity
Utils.showToast( ActMain.this, false, R.string.app_was_muted );
}
//////////////////////////////////////////////////////////////
interface FindAccountCallback {
@ -2913,6 +2914,101 @@ public class ActMain extends AppCompatActivity
task.executeOnExecutor( App1.task_executor );
}
////////////////////////////////////////
// profile pin
public void setProfilePin( @NonNull final SavedAccount access_info, final TootStatusLike status, final boolean bSet ){
if( status == null ) return;
//noinspection deprecation
final ProgressDialog progress = new ProgressDialog( this );
//
final AsyncTask< Void, Void, TootApiResult > task = new AsyncTask< Void, Void, TootApiResult >() {
TootStatus new_status;
@Override protected TootApiResult doInBackground( Void... params ){
TootApiClient client = new TootApiClient( ActMain.this, new TootApiClient.Callback() {
@Override public boolean isApiCancelled(){
return isCancelled();
}
@Override public void publishApiProgress( final String s ){
}
} );
client.setAccount( access_info );
TootApiResult result;
Request.Builder request_builder = new Request.Builder()
.post( RequestBody.create(
TootApiClient.MEDIA_TYPE_FORM_URL_ENCODED
, ""
) );
result = client.request(
( bSet
? "/api/v1/statuses/" + status.id + "/pin"
: "/api/v1/statuses/" + status.id + "/unpin"
)
, request_builder );
if( result != null && result.object != null ){
new_status = TootStatus.parse( ActMain.this, access_info, result.object );
}
return result;
}
@Override
protected void onCancelled( TootApiResult result ){
super.onPostExecute( result );
}
@Override
protected void onPostExecute( TootApiResult result ){
try{
progress.dismiss();
}catch(Throwable ignored){
}
//noinspection StatementWithEmptyBody
if( result == null ){
// cancelled.
}else if( new_status != null ){
for( Column column : app_state.column_list ){
column.findStatus( access_info.host, new_status.id, new Column.StatusEntryCallback() {
@Override public boolean onIterate( SavedAccount account, TootStatus status ){
status.pinned = bSet;
return true;
}
} );
}
}else{
Utils.showToast( ActMain.this, true, result.error );
}
// 結果に関わらず更新中状態から復帰させる
showColumnMatchAccount( access_info );
}
};
progress.setIndeterminate( true );
progress.setCancelable( true );
progress.setMessage( getString(R.string.profile_pin_progress));
progress.setOnCancelListener( new DialogInterface.OnCancelListener() {
@Override public void onCancel( DialogInterface dialog ){
task.cancel( true );
}
} );
progress.show();
task.executeOnExecutor( App1.task_executor );
}
////////////////////////////////////////
// delete notification

View File

@ -1144,6 +1144,14 @@ class Column implements StreamReader.Callback {
}
}
String parseMaxId(TootApiResult result){
if( result != null && result.link_older != null ){
Matcher m = reMaxId.matcher( result.link_older );
if( m.find() ) return m.group( 1 );
}
return null;
}
void startLoading(){
cancelLastTask();
@ -1182,6 +1190,57 @@ class Column implements StreamReader.Callback {
return result;
}
ArrayList< Object > list_pinned;
TootApiResult getStatusesPinned( TootApiClient client, String path_base ){
long time_start = SystemClock.elapsedRealtime();
TootApiResult result = client.request( path_base );
if( result != null && result.array != null ){
//
TootStatus.List src = TootStatus.parseList( context, access_info, result.array );
list_pinned = new ArrayList<>( src.size() );
addWithFilter( list_pinned, src );
// pinステータスは独自にページ管理する
String max_id = parseMaxId( result );
//
char delimiter = ( - 1 != path_base.indexOf( '?' ) ? '&' : '?' );
for( ; ; ){
if( client.isCancelled() ){
log.d( "loading-statuses-pinned: cancelled." );
break;
}
if( max_id == null ){
log.d( "loading-statuses-pinned: max_id is null." );
break;
}
if( src.isEmpty() ){
log.d( "loading-statuses-pinned: previous response is empty." );
break;
}
if( SystemClock.elapsedRealtime() - time_start > LOOP_TIMEOUT ){
log.d( "loading-statuses-pinned: timeout." );
break;
}
String path = path_base + delimiter + "max_id=" + max_id;
TootApiResult result2 = client.request( path );
if( result2 == null || result2.array == null ){
log.d( "loading-statuses-pinned: error or cancelled." );
break;
}
src = TootStatus.parseList( context, access_info, result2.array );
addWithFilter( list_pinned, src );
// pinnedステータスは独自にページ管理する
max_id = parseMaxId( result2 );
}
}
log.d("getStatusesPinned: list size=%s",list_pinned==null? -1 : list_pinned.size() );
return result;
}
ArrayList< Object > list_tmp;
@ -1381,10 +1440,12 @@ class Column implements StreamReader.Callback {
case TAB_STATUS:
if( access_info.isPseudo() ){
return client.request( PATH_INSTANCE );
}else{
String s = String.format( Locale.JAPAN, PATH_ACCOUNT_STATUSES, profile_id );
if( with_attachment ) s = s + "&only_media=1";
getStatusesPinned( client, s + "&pinned=1");
return getStatuses( client, s );
}
@ -1555,9 +1616,13 @@ class Column implements StreamReader.Callback {
if( result.error != null ){
Column.this.mInitialLoadingError = result.error;
}else{
list_data.clear();
if( list_tmp != null ){
if( list_pinned != null && ! list_pinned.isEmpty() ){
ArrayList< Object > list_new = duplicate_map.filterDuplicate( list_pinned );
list_data.addAll( list_new );
}
ArrayList< Object > list_new = duplicate_map.filterDuplicate( list_tmp );
list_data.clear();
list_data.addAll( list_new );
}
@ -2772,7 +2837,6 @@ class Column implements StreamReader.Callback {
if( access_info.isPseudo() ){
return client.request( PATH_INSTANCE );
}else{
String s = String.format( Locale.JAPAN, PATH_ACCOUNT_STATUSES, profile_id );
if( with_attachment ) s = s + "&only_media=1";

View File

@ -74,12 +74,12 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
View btnReplyAnotherAccount = viewRoot.findViewById( R.id.btnReplyAnotherAccount );
View btnDelete = viewRoot.findViewById( R.id.btnDelete );
View btnReport = viewRoot.findViewById( R.id.btnReport );
Button btnMuteApp = (Button) viewRoot.findViewById( R.id.btnMuteApp );
Button btnMuteApp = viewRoot.findViewById( R.id.btnMuteApp );
View llAccountActionBar = viewRoot.findViewById( R.id.llAccountActionBar );
ImageView btnFollow = (ImageView) viewRoot.findViewById( R.id.btnFollow );
ImageView btnFollow = viewRoot.findViewById( R.id.btnFollow );
ImageView btnMute = (ImageView) viewRoot.findViewById( R.id.btnMute );
ImageView btnBlock = (ImageView) viewRoot.findViewById( R.id.btnBlock );
ImageView btnMute = viewRoot.findViewById( R.id.btnMute );
ImageView btnBlock = viewRoot.findViewById( R.id.btnBlock );
View btnProfile = viewRoot.findViewById( R.id.btnProfile );
View btnSendMessage = viewRoot.findViewById( R.id.btnSendMessage );
View btnAccountWebPage = viewRoot.findViewById( R.id.btnAccountWebPage );
@ -88,16 +88,16 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
View btnFollowFromAnotherAccount = viewRoot.findViewById( R.id.btnFollowFromAnotherAccount );
View btnSendMessageFromAnotherAccount = viewRoot.findViewById( R.id.btnSendMessageFromAnotherAccount );
View btnOpenProfileFromAnotherAccount = viewRoot.findViewById( R.id.btnOpenProfileFromAnotherAccount );
Button btnDomainBlock = (Button) viewRoot.findViewById( R.id.btnDomainBlock );
Button btnInstanceInformation = (Button) viewRoot.findViewById( R.id.btnInstanceInformation );
ImageView ivFollowedBy = (ImageView) viewRoot.findViewById( R.id.ivFollowedBy );
Button btnOpenTimeline = (Button) viewRoot.findViewById( R.id.btnOpenTimeline );
Button btnDomainBlock = viewRoot.findViewById( R.id.btnDomainBlock );
Button btnInstanceInformation = viewRoot.findViewById( R.id.btnInstanceInformation );
ImageView ivFollowedBy = viewRoot.findViewById( R.id.ivFollowedBy );
Button btnOpenTimeline = viewRoot.findViewById( R.id.btnOpenTimeline );
View btnConversationAnotherAccount = viewRoot.findViewById( R.id.btnConversationAnotherAccount );
View btnAvatarImage = viewRoot.findViewById( R.id.btnAvatarImage );
View llNotification = viewRoot.findViewById( R.id.llNotification );
View btnNotificationDelete = viewRoot.findViewById( R.id.btnNotificationDelete );
Button btnConversationMute = (Button) viewRoot.findViewById( R.id.btnConversationMute );
Button btnConversationMute = viewRoot.findViewById( R.id.btnConversationMute );
btnStatusWebPage.setOnClickListener( this );
btnText.setOnClickListener( this );
@ -155,21 +155,23 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
}else{
btnMuteApp.setText( activity.getString( R.string.mute_app_of, status.application.name ) );
}
View btnBoostedBy = viewRoot.findViewById( R.id.btnBoostedBy );
View btnFavouritedBy= viewRoot.findViewById( R.id.btnFavouritedBy );
btnBoostedBy.setOnClickListener( this );
btnFavouritedBy.setOnClickListener( this );
boolean isNA = access_info.isNA();
btnBoostedBy.setVisibility( isNA ? View.GONE : View.VISIBLE );
btnFavouritedBy.setVisibility( isNA ? View.GONE : View.VISIBLE );
View btnProfilePin= viewRoot.findViewById( R.id.btnProfilePin );
View btnProfileUnpin = viewRoot.findViewById( R.id.btnProfileUnpin );
btnProfilePin.setOnClickListener( this );
btnProfileUnpin.setOnClickListener( this );
boolean canPin = status.canPin( access_info);
btnProfileUnpin.setVisibility(canPin && status.pinned ? View.VISIBLE : View.GONE );
btnProfilePin.setVisibility( canPin && !status.pinned ? View.VISIBLE : View.GONE );
View v;
if( access_info.isNA() ){
v = viewRoot.findViewById( R.id.btnBoostedBy );
v.setVisibility( View.GONE );
v = viewRoot.findViewById( R.id.btnFavouritedBy );
v.setVisibility( View.GONE );
}else{
v = viewRoot.findViewById( R.id.btnBoostedBy );
v.setOnClickListener( this );
v = viewRoot.findViewById( R.id.btnFavouritedBy );
v.setOnClickListener( this );
}
}
@ -568,6 +570,13 @@ class DlgContextMenu implements View.OnClickListener, View.OnLongClickListener {
activity.openInstanceInformation( pos, access_info.getAccountHost( who ).toLowerCase() );
}
break;
case R.id.btnProfilePin:
activity.setProfilePin( access_info, status, true);
break;
case R.id.btnProfileUnpin:
activity.setProfilePin( access_info, status, false);
break;
}
}

View File

@ -555,6 +555,16 @@ class ItemViewHolder implements View.OnClickListener, View.OnLongClickListener {
}
}
if( status.pinned ){
if( sb.length() > 0 ) sb.append( ' ' );
int start = sb.length();
sb.append( "pinned" );
int end = sb.length();
int icon_id = Styler.getAttributeResourceId( activity, R.attr.ic_pin );
sb.setSpan( new EmojiImageSpan( activity, icon_id ), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE );
}
if( sb.length() > 0 ) sb.append( ' ' );
sb.append( TootStatus.formatTime( activity, status.time_created_at, column.column_type != Column.TYPE_CONVERSATION ) );
tvTime.setText( sb );

View File

@ -125,6 +125,8 @@ public class TootStatus extends TootStatusLike {
status.tags = TootTag.parseList( src.optJSONArray( "tags" ) );
status.application = TootApplication.parse( src.optJSONObject( "application" ) ); // null
status.pinned = src.optBoolean( "pinned" );
status.setSpoilerText( context, Utils.optStringX( src, "spoiler_text" ) );
status.muted = src.optBoolean( "muted" );
@ -280,4 +282,11 @@ public class TootStatus extends TootStatusLike {
public boolean hasMedia(){
return media_attachments != null && media_attachments.size() > 0;
}
@Override public boolean canPin( SavedAccount access_info ){
return reblog == null
&& access_info.isMe( account )
&& ( VISIBILITY_PUBLIC.equals( visibility ) || VISIBILITY_UNLISTED.equals( visibility ) );
}
}

View File

@ -10,6 +10,7 @@ import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.regex.Pattern;
import jp.juggler.subwaytooter.table.SavedAccount;
import jp.juggler.subwaytooter.util.Emojione;
import jp.juggler.subwaytooter.util.Utils;
@ -42,6 +43,9 @@ public abstract class TootStatusLike extends TootId {
// Whether the authenticated user has muted the conversation this status from
public boolean muted;
// 固定されたトゥート
public boolean pinned;
// The detected language for the status, if detected
public String language;
@ -90,6 +94,8 @@ public abstract class TootStatusLike extends TootId {
}
}
public abstract boolean canPin( SavedAccount access_info );
public static class AutoCW {
public WeakReference< Object > refActivity;
public int cell_width;

View File

@ -159,4 +159,8 @@ public class MSPToot extends TootStatusLike {
public boolean hasMedia(){
return media_attachments != null && media_attachments.size() > 0;
}
@Override public boolean canPin( SavedAccount access_info ){
return false;
}
}

View File

@ -177,6 +177,36 @@
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnProfilePin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:text="@string/profile_pin"
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnProfileUnpin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/btn_bg_transparent"
android:gravity="start|center_vertical"
android:minHeight="32dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:text="@string/profile_unpin"
android:textAllCaps="false"
/>
<Button
android:id="@+id/btnDelete"
android:layout_width="match_parent"

View File

@ -462,8 +462,11 @@
<string name="enquete_item_is_empty">Enquete choice %1$d is empty.</string>
<string name="enquete_item_too_long">Enquete choice %1$d is too long. please decrease %2$d character(s).</string>
<string name="enquete_item_duplicate">Enquete choice %1$d is a duplicate of other choice.</string>
<string name="profile_pin">Pin on profile</string>
<string name="profile_unpin">Unpin from profile</string>
<string name="profile_pin_progress">Changing pinned status…</string>
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
<!--<string name="abc_action_bar_home_description">Revenir à l\'accueil</string>-->
<!--<string name="abc_action_bar_home_description_format">%1$s, %2$s</string>-->
<!--<string name="abc_action_bar_home_subtitle_description_format">%1$s, %2$s, %3$s</string>-->
<!--<string name="abc_action_bar_up_description">Revenir en haut de la page</string>-->

View File

@ -749,4 +749,7 @@
<string name="enquete_item_is_empty">アンケート項目%1$dがカラです</string>
<string name="enquete_item_too_long">アンケート項目%1$dが長すぎます。あと%2$d文字削ってください</string>
<string name="enquete_item_duplicate">アンケート項目%1$dは他の項目と重複してます</string>
<string name="profile_pin">プロフィールに固定表示</string>
<string name="profile_unpin">プロフィールの固定表示を解除</string>
<string name="profile_pin_progress">固定表示の変更中…</string>
</resources>

View File

@ -119,5 +119,6 @@
<attr name="ic_nicoru" format="reference" />
<attr name="ic_question" format="reference" />
<attr name="ic_eye_off" format="reference" />
<attr name="ic_pin" format="reference" />
</resources>

View File

@ -456,5 +456,8 @@
<string name="enquete_item_is_empty">Enquete choice %1$d is empty.</string>
<string name="enquete_item_too_long">Enquete choice %1$d is too long. please decrease %2$d character(s).</string>
<string name="enquete_item_duplicate">Enquete choice %1$d is a duplicate of other choice.</string>
<string name="profile_pin">Pin on profile</string>
<string name="profile_unpin">Unpin from profile</string>
<string name="profile_pin_progress">Changing pinned status…</string>
</resources>

View File

@ -89,6 +89,7 @@
<item name="ic_nicoru">@drawable/ic_nicoru</item>
<item name="ic_question">@drawable/ic_question</item>
<item name="ic_eye_off">@drawable/ic_eye_off</item>
<item name="ic_pin">@drawable/ic_pin</item>
</style>
@ -182,6 +183,7 @@
<item name="ic_nicoru">@drawable/ic_nicoru_dark</item>
<item name="ic_question">@drawable/ic_question_dark</item>
<item name="ic_eye_off">@drawable/ic_eye_off_dark</item>
<item name="ic_pin">@drawable/ic_pin_dark</item>
</style>

View File

@ -93,8 +93,10 @@ my $res_dir = "app/src/main/res";
#resize_scales( "_ArtWork/media_type_unknown.png" ,$res_dir,"drawable","media_type_unknown",-1,-1);
#resize_scales( "_ArtWork/media_type_video.png" ,$res_dir,"drawable","media_type_video",-1,-1);
resize_scales( "_ArtWork/hohoemi.png" ,$res_dir,"drawable","emoji_hohoemi",0,24);
resize_scales( "_ArtWork/nicoru.png" ,$res_dir,"drawable","emoji_nicoru",0,24);
#resize_scales( "_ArtWork/hohoemi.png" ,$res_dir,"drawable","emoji_hohoemi",0,24);
#resize_scales( "_ArtWork/nicoru.png" ,$res_dir,"drawable","emoji_nicoru",0,24);
#resize_scales( "_ArtWork/ic_nicoru.png" ,$res_dir,"drawable","ic_nicoru",0,32);
#resize_scales( "_ArtWork/ic_nicoru_dark.png" ,$res_dir,"drawable","ic_nicoru_dark",0,32);
resize_scales( "_ArtWork/ic_nicoru.png" ,$res_dir,"drawable","ic_nicoru",0,32);
resize_scales( "_ArtWork/ic_nicoru_dark.png" ,$res_dir,"drawable","ic_nicoru_dark",0,32);
resize_scales( "_ArtWork/ic_pin.png" ,$res_dir,"drawable","ic_pin",0,32);
resize_scales( "_ArtWork/ic_pin_dark.png" ,$res_dir,"drawable","ic_pin_dark",0,32);