@ -60,13 +60,32 @@ import android.widget.PopupMenu;
import android.widget.TextView ;
import android.widget.TextView ;
import android.widget.Toast ;
import android.widget.Toast ;
import androidx.annotation.ColorInt ;
import androidx.annotation.NonNull ;
import androidx.annotation.Nullable ;
import androidx.annotation.Px ;
import androidx.annotation.StringRes ;
import androidx.appcompat.app.ActionBar ;
import androidx.appcompat.app.AlertDialog ;
import androidx.appcompat.content.res.AppCompatResources ;
import androidx.appcompat.widget.Toolbar ;
import androidx.core.app.ActivityCompat ;
import androidx.core.content.ContextCompat ;
import androidx.core.content.FileProvider ;
import androidx.core.view.inputmethod.InputConnectionCompat ;
import androidx.core.view.inputmethod.InputContentInfoCompat ;
import androidx.lifecycle.Lifecycle ;
import androidx.recyclerview.widget.GridLayoutManager ;
import androidx.recyclerview.widget.RecyclerView ;
import androidx.transition.TransitionManager ;
import com.bumptech.glide.Glide ;
import com.bumptech.glide.Glide ;
import com.google.android.material.bottomsheet.BottomSheetBehavior ;
import com.google.android.material.bottomsheet.BottomSheetBehavior ;
import com.google.android.material.snackbar.Snackbar ;
import com.google.android.material.snackbar.Snackbar ;
import com.google.gson.Gson ;
import com.google.gson.Gson ;
import com.google.gson.reflect.TypeToken ;
import com.google.gson.reflect.TypeToken ;
import com.keylesspalace.tusky.adapter.EmojiAdapter ;
import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter ;
import com.keylesspalace.tusky.adapter.ComposeAutoCompleteAdapter ;
import com.keylesspalace.tusky.adapter.EmojiAdapter ;
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener ;
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener ;
import com.keylesspalace.tusky.db.AccountEntity ;
import com.keylesspalace.tusky.db.AccountEntity ;
import com.keylesspalace.tusky.db.AppDatabase ;
import com.keylesspalace.tusky.db.AppDatabase ;
@ -81,10 +100,10 @@ import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.network.MastodonApi ;
import com.keylesspalace.tusky.network.MastodonApi ;
import com.keylesspalace.tusky.network.ProgressRequestBody ;
import com.keylesspalace.tusky.network.ProgressRequestBody ;
import com.keylesspalace.tusky.service.SendTootService ;
import com.keylesspalace.tusky.service.SendTootService ;
import com.keylesspalace.tusky.util.ComposeTokenizer ;
import com.keylesspalace.tusky.util.CountUpDownLatch ;
import com.keylesspalace.tusky.util.CountUpDownLatch ;
import com.keylesspalace.tusky.util.DownsizeImageTask ;
import com.keylesspalace.tusky.util.DownsizeImageTask ;
import com.keylesspalace.tusky.util.ListUtils ;
import com.keylesspalace.tusky.util.ListUtils ;
import com.keylesspalace.tusky.util.ComposeTokenizer ;
import com.keylesspalace.tusky.util.SaveTootHelper ;
import com.keylesspalace.tusky.util.SaveTootHelper ;
import com.keylesspalace.tusky.util.SpanUtilsKt ;
import com.keylesspalace.tusky.util.SpanUtilsKt ;
import com.keylesspalace.tusky.util.StringUtils ;
import com.keylesspalace.tusky.util.StringUtils ;
@ -114,24 +133,6 @@ import java.util.concurrent.CountDownLatch;
import javax.inject.Inject ;
import javax.inject.Inject ;
import androidx.annotation.ColorInt ;
import androidx.annotation.NonNull ;
import androidx.annotation.Nullable ;
import androidx.annotation.Px ;
import androidx.annotation.StringRes ;
import androidx.appcompat.app.ActionBar ;
import androidx.appcompat.app.AlertDialog ;
import androidx.appcompat.content.res.AppCompatResources ;
import androidx.appcompat.widget.Toolbar ;
import androidx.core.app.ActivityCompat ;
import androidx.core.content.ContextCompat ;
import androidx.core.content.FileProvider ;
import androidx.core.view.inputmethod.InputConnectionCompat ;
import androidx.core.view.inputmethod.InputContentInfoCompat ;
import androidx.lifecycle.Lifecycle ;
import androidx.recyclerview.widget.GridLayoutManager ;
import androidx.recyclerview.widget.RecyclerView ;
import androidx.transition.TransitionManager ;
import at.connyduck.sparkbutton.helpers.Utils ;
import at.connyduck.sparkbutton.helpers.Utils ;
import io.reactivex.Single ;
import io.reactivex.Single ;
import io.reactivex.SingleObserver ;
import io.reactivex.SingleObserver ;
@ -171,16 +172,18 @@ public final class ComposeActivity
private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1 ;
private static final int PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1 ;
private static final String SAVED_TOOT_UID_EXTRA = "saved_toot_uid" ;
private static final String SAVED_TOOT_UID_EXTRA = "saved_toot_uid" ;
private static final String SAVED_ TOOT_TEXT_EXTRA = "saved_ toot_text" ;
private static final String TOOT_TEXT_EXTRA = "toot_text" ;
private static final String SAVED_JSON_URLS_EXTRA = "saved_json_urls" ;
private static final String SAVED_JSON_URLS_EXTRA = "saved_json_urls" ;
private static final String SAVED_JSON_DESCRIPTIONS_EXTRA = "saved_json_descriptions" ;
private static final String SAVED_JSON_DESCRIPTIONS_EXTRA = "saved_json_descriptions" ;
private static final String SAVED_ TOOT_VISIBILITY_EXTRA = "saved_ toot_visibility" ;
private static final String TOOT_VISIBILITY_EXTRA = "toot_visibility" ;
private static final String IN_REPLY_TO_ID_EXTRA = "in_reply_to_id" ;
private static final String IN_REPLY_TO_ID_EXTRA = "in_reply_to_id" ;
private static final String REPLY_VISIBILITY_EXTRA = "reply_visibilty" ;
private static final String REPLY_VISIBILITY_EXTRA = "reply_visibili ty" ;
private static final String CONTENT_WARNING_EXTRA = "content_warning" ;
private static final String CONTENT_WARNING_EXTRA = "content_warning" ;
private static final String MENTIONED_USERNAMES_EXTRA = "netn ioned_usernames" ;
private static final String MENTIONED_USERNAMES_EXTRA = "ment ioned_usernames" ;
private static final String REPLYING_STATUS_AUTHOR_USERNAME_EXTRA = "replying_author_nickname_extra" ;
private static final String REPLYING_STATUS_AUTHOR_USERNAME_EXTRA = "replying_author_nickname_extra" ;
private static final String REPLYING_STATUS_CONTENT_EXTRA = "replying_status_content" ;
private static final String REPLYING_STATUS_CONTENT_EXTRA = "replying_status_content" ;
private static final String MEDIA_ATTACHMENTS_EXTRA = "media_attachments" ;
private static final String SENSITIVE_EXTRA = "sensitive" ;
// Mastodon only counts URLs as this long in terms of status character limits
// Mastodon only counts URLs as this long in terms of status character limits
static final int MAXIMUM_URL_LENGTH = 23 ;
static final int MAXIMUM_URL_LENGTH = 23 ;
// https://github.com/tootsuite/mastodon/blob/1656663/app/models/media_attachment.rb#L94
// https://github.com/tootsuite/mastodon/blob/1656663/app/models/media_attachment.rb#L94
@ -409,6 +412,7 @@ public final class ComposeActivity
String [ ] mentionedUsernames = null ;
String [ ] mentionedUsernames = null ;
ArrayList < String > loadedDraftMediaUris = null ;
ArrayList < String > loadedDraftMediaUris = null ;
ArrayList < String > loadedDraftMediaDescriptions = null ;
ArrayList < String > loadedDraftMediaDescriptions = null ;
ArrayList < Attachment > mediaAttachments = null ;
inReplyToId = null ;
inReplyToId = null ;
if ( intent ! = null ) {
if ( intent ! = null ) {
@ -432,14 +436,13 @@ public final class ComposeActivity
}
}
}
}
// If come from SavedTootActivity
String tootText = intent . getStringExtra ( TOOT_TEXT_EXTRA ) ;
String savedTootText = intent . getStringExtra ( SAVED_TOOT_TEXT_EXTRA ) ;
if ( ! TextUtils . isEmpty ( tootText ) ) {
if ( ! TextUtils . isEmpty ( savedTootText ) ) {
textEditor . setText ( tootText ) ;
startingText = savedTootText ;
textEditor . setText ( savedTootText ) ;
}
}
// try to redo a list of media
// try to redo a list of media
// If come from SavedTootActivity
String savedJsonUrls = intent . getStringExtra ( SAVED_JSON_URLS_EXTRA ) ;
String savedJsonUrls = intent . getStringExtra ( SAVED_JSON_URLS_EXTRA ) ;
String savedJsonDescriptions = intent . getStringExtra ( SAVED_JSON_DESCRIPTIONS_EXTRA ) ;
String savedJsonDescriptions = intent . getStringExtra ( SAVED_JSON_DESCRIPTIONS_EXTRA ) ;
if ( ! TextUtils . isEmpty ( savedJsonUrls ) ) {
if ( ! TextUtils . isEmpty ( savedJsonUrls ) ) {
@ -452,15 +455,20 @@ public final class ComposeActivity
new TypeToken < ArrayList < String > > ( ) {
new TypeToken < ArrayList < String > > ( ) {
} . getType ( ) ) ;
} . getType ( ) ) ;
}
}
// If come from redraft
mediaAttachments = intent . getParcelableArrayListExtra ( MEDIA_ATTACHMENTS_EXTRA ) ;
int savedTootUid = intent . getIntExtra ( SAVED_TOOT_UID_EXTRA , 0 ) ;
int savedTootUid = intent . getIntExtra ( SAVED_TOOT_UID_EXTRA , 0 ) ;
if ( savedTootUid ! = 0 ) {
if ( savedTootUid ! = 0 ) {
this . savedTootUid = savedTootUid ;
this . savedTootUid = savedTootUid ;
// If come from SavedTootActivity
startingText = tootText ;
}
}
int savedTootVisibility = intent . getIntExtra ( SAVED_TOOT_VISIBILITY_EXTRA , Status . Visibility . UNKNOWN . getNum ( ) ) ;
int t ootVisibility = intent . getIntExtra ( TOOT_VISIBILITY_EXTRA , Status . Visibility . UNKNOWN . getNum ( ) ) ;
if ( savedT ootVisibility ! = Status . Visibility . UNKNOWN . getNum ( ) ) {
if ( t ootVisibility ! = Status . Visibility . UNKNOWN . getNum ( ) ) {
startingVisibility = Status . Visibility . byNum ( savedT ootVisibility) ;
startingVisibility = Status . Visibility . byNum ( t ootVisibility) ;
}
}
if ( intent . hasExtra ( REPLYING_STATUS_AUTHOR_USERNAME_EXTRA ) ) {
if ( intent . hasExtra ( REPLYING_STATUS_AUTHOR_USERNAME_EXTRA ) ) {
@ -491,6 +499,8 @@ public final class ComposeActivity
if ( intent . hasExtra ( REPLYING_STATUS_CONTENT_EXTRA ) ) {
if ( intent . hasExtra ( REPLYING_STATUS_CONTENT_EXTRA ) ) {
replyContentTextView . setText ( intent . getStringExtra ( REPLYING_STATUS_CONTENT_EXTRA ) ) ;
replyContentTextView . setText ( intent . getStringExtra ( REPLYING_STATUS_CONTENT_EXTRA ) ) ;
}
}
statusMarkSensitive = intent . getBooleanExtra ( SENSITIVE_EXTRA , false ) ;
}
}
// After the starting state is finalised, the interface can be set to reflect this state.
// After the starting state is finalised, the interface can be set to reflect this state.
@ -575,6 +585,25 @@ public final class ComposeActivity
}
}
pickMedia ( uri , mediaSize , description ) ;
pickMedia ( uri , mediaSize , description ) ;
}
}
} else if ( ! ListUtils . isEmpty ( mediaAttachments ) ) {
for ( int mediaIndex = 0 ; mediaIndex < mediaAttachments . size ( ) ; + + mediaIndex ) {
Attachment media = mediaAttachments . get ( mediaIndex ) ;
QueuedMedia . Type type ;
switch ( media . getType ( ) ) {
case UNKNOWN :
case IMAGE :
default : {
type = QueuedMedia . Type . IMAGE ;
break ;
}
case VIDEO :
case GIFV : {
type = QueuedMedia . Type . VIDEO ;
break ;
}
}
addMediaToQueue ( media . getId ( ) , type , media . getPreviewUrl ( ) , media . getDescription ( ) ) ;
}
} else if ( savedMediaQueued ! = null ) {
} else if ( savedMediaQueued ! = null ) {
for ( SavedQueuedMedia item : savedMediaQueued ) {
for ( SavedQueuedMedia item : savedMediaQueued ) {
Bitmap preview = getImageThumbnail ( getContentResolver ( ) , item . uri , thumbnailViewSize ) ;
Bitmap preview = getImageThumbnail ( getContentResolver ( ) , item . uri , thumbnailViewSize ) ;
@ -1111,6 +1140,11 @@ public final class ComposeActivity
addMediaToQueue ( null , type , preview , uri , mediaSize , null , description ) ;
addMediaToQueue ( null , type , preview , uri , mediaSize , null , description ) ;
}
}
private void addMediaToQueue ( String id , QueuedMedia . Type type , String previewUrl , @Nullable String description ) {
addMediaToQueue ( id , type , null , Uri . parse ( previewUrl ) , 0 ,
QueuedMedia . ReadyStage . UPLOADED , description ) ;
}
private void addMediaToQueue ( @Nullable String id , QueuedMedia . Type type , Bitmap preview , Uri uri ,
private void addMediaToQueue ( @Nullable String id , QueuedMedia . Type type , Bitmap preview , Uri uri ,
long mediaSize , QueuedMedia . ReadyStage readyStage , @Nullable String description ) {
long mediaSize , QueuedMedia . ReadyStage readyStage , @Nullable String description ) {
final QueuedMedia item = new QueuedMedia ( type , uri , new ProgressImageView ( this ) ,
final QueuedMedia item = new QueuedMedia ( type , uri , new ProgressImageView ( this ) ,
@ -1126,7 +1160,14 @@ public final class ComposeActivity
layoutParams . setMargins ( margin , 0 , margin , marginBottom ) ;
layoutParams . setMargins ( margin , 0 , margin , marginBottom ) ;
view . setLayoutParams ( layoutParams ) ;
view . setLayoutParams ( layoutParams ) ;
view . setScaleType ( ImageView . ScaleType . CENTER_CROP ) ;
view . setScaleType ( ImageView . ScaleType . CENTER_CROP ) ;
view . setImageBitmap ( preview ) ;
if ( preview ! = null ) {
view . setImageBitmap ( preview ) ;
} else {
Glide . with ( this )
. load ( uri )
. placeholder ( null )
. into ( view ) ;
}
view . setOnClickListener ( v - > onMediaClick ( item , v ) ) ;
view . setOnClickListener ( v - > onMediaClick ( item , v ) ) ;
view . setContentDescription ( getString ( R . string . action_delete ) ) ;
view . setContentDescription ( getString ( R . string . action_delete ) ) ;
mediaPreviewBar . addView ( view ) ;
mediaPreviewBar . addView ( view ) ;
@ -1782,7 +1823,7 @@ public final class ComposeActivity
@Nullable
@Nullable
private Integer savedTootUid ;
private Integer savedTootUid ;
@Nullable
@Nullable
private String savedT ootText;
private String t ootText;
@Nullable
@Nullable
private String savedJsonUrls ;
private String savedJsonUrls ;
@Nullable
@Nullable
@ -1794,21 +1835,25 @@ public final class ComposeActivity
@Nullable
@Nullable
private Status . Visibility replyVisibility ;
private Status . Visibility replyVisibility ;
@Nullable
@Nullable
private Status . Visibility sa vedV isibility;
private Status . Visibility visibility ;
@Nullable
@Nullable
private String contentWarning ;
private String contentWarning ;
@Nullable
@Nullable
private String replyingStatusAuthor ;
private String replyingStatusAuthor ;
@Nullable
@Nullable
private String replyingStatusContent ;
private String replyingStatusContent ;
@Nullable
private ArrayList < Attachment > mediaAttachments ;
private boolean sensitive = false ;
public IntentBuilder savedTootUid ( int uid ) {
public IntentBuilder savedTootUid ( int uid ) {
this . savedTootUid = uid ;
this . savedTootUid = uid ;
return this ;
return this ;
}
}
public IntentBuilder savedTootText ( String savedT ootText) {
public IntentBuilder tootText ( String t ootText) {
this . savedTootText = savedT ootText;
this . tootText = t ootText;
return this ;
return this ;
}
}
@ -1822,8 +1867,8 @@ public final class ComposeActivity
return this ;
return this ;
}
}
public IntentBuilder sa vedV isibility( Status . Visibility sa vedV isibility) {
public IntentBuilder visibility ( Status . Visibility visibility ) {
this . sa vedV isibility = sa vedV isibility;
this . visibility = visibility ;
return this ;
return this ;
}
}
@ -1857,14 +1902,24 @@ public final class ComposeActivity
return this ;
return this ;
}
}
public IntentBuilder mediaAttachments ( ArrayList < Attachment > mediaAttachments ) {
this . mediaAttachments = mediaAttachments ;
return this ;
}
public IntentBuilder sensitive ( boolean sensitive ) {
this . sensitive = sensitive ;
return this ;
}
public Intent build ( Context context ) {
public Intent build ( Context context ) {
Intent intent = new Intent ( context , ComposeActivity . class ) ;
Intent intent = new Intent ( context , ComposeActivity . class ) ;
if ( savedTootUid ! = null ) {
if ( savedTootUid ! = null ) {
intent . putExtra ( SAVED_TOOT_UID_EXTRA , ( int ) savedTootUid ) ;
intent . putExtra ( SAVED_TOOT_UID_EXTRA , ( int ) savedTootUid ) ;
}
}
if ( savedTootText ! = null ) {
if ( t ootText ! = null ) {
intent . putExtra ( SAVED_TOOT_TEXT_EXTRA , savedTootText ) ;
intent . putExtra ( TOOT_TEXT_EXTRA , t ootText) ;
}
}
if ( savedJsonUrls ! = null ) {
if ( savedJsonUrls ! = null ) {
intent . putExtra ( SAVED_JSON_URLS_EXTRA , savedJsonUrls ) ;
intent . putExtra ( SAVED_JSON_URLS_EXTRA , savedJsonUrls ) ;
@ -1882,8 +1937,8 @@ public final class ComposeActivity
if ( replyVisibility ! = null ) {
if ( replyVisibility ! = null ) {
intent . putExtra ( REPLY_VISIBILITY_EXTRA , replyVisibility . getNum ( ) ) ;
intent . putExtra ( REPLY_VISIBILITY_EXTRA , replyVisibility . getNum ( ) ) ;
}
}
if ( sa vedV isibility ! = null ) {
if ( visibility ! = null ) {
intent . putExtra ( SAVED_ TOOT_VISIBILITY_EXTRA, sa vedV isibility. getNum ( ) ) ;
intent . putExtra ( TOOT_VISIBILITY_EXTRA , visibility . getNum ( ) ) ;
}
}
if ( contentWarning ! = null ) {
if ( contentWarning ! = null ) {
intent . putExtra ( CONTENT_WARNING_EXTRA , contentWarning ) ;
intent . putExtra ( CONTENT_WARNING_EXTRA , contentWarning ) ;
@ -1894,6 +1949,10 @@ public final class ComposeActivity
if ( replyingStatusAuthor ! = null ) {
if ( replyingStatusAuthor ! = null ) {
intent . putExtra ( REPLYING_STATUS_AUTHOR_USERNAME_EXTRA , replyingStatusAuthor ) ;
intent . putExtra ( REPLYING_STATUS_AUTHOR_USERNAME_EXTRA , replyingStatusAuthor ) ;
}
}
if ( mediaAttachments ! = null ) {
intent . putParcelableArrayListExtra ( MEDIA_ATTACHMENTS_EXTRA , mediaAttachments ) ;
}
intent . putExtra ( SENSITIVE_EXTRA , sensitive ) ;
return intent ;
return intent ;
}
}
}
}