improve default post privacy to work like web mastodon, add default post privacy option

This commit is contained in:
Conny Duck 2017-11-27 20:11:31 +01:00
parent 1351c8b885
commit 1c2a647569
5 changed files with 94 additions and 168 deletions

View file

@ -35,6 +35,7 @@ import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.support.annotation.AttrRes; import android.support.annotation.AttrRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
@ -134,7 +135,6 @@ public final class ComposeActivity extends BaseActivity
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 REMEMBERED_VISIBILITY_PREF = "rememberedVisibilityNum";
private static TootDao tootDao = TuskyApplication.getDB().tootDao(); private static TootDao tootDao = TuskyApplication.getDB().tootDao();
private TextView replyTextView; private TextView replyTextView;
@ -198,42 +198,12 @@ public final class ComposeActivity extends BaseActivity
} }
// Setup the interface buttons. // Setup the interface buttons.
floatingBtn.setOnClickListener(new View.OnClickListener() { floatingBtn.setOnClickListener(v -> onSendClicked());
@Override floatingBtn.setOnLongClickListener(v -> saveDraft());
public void onClick(View v) { pickButton.setOnClickListener(v -> openPickDialog());
onSendClicked(); visibilityBtn.setOnClickListener(v -> showComposeOptions());
} saveButton.setOnClickListener(v -> saveDraft());
}); hideMediaToggle.setOnClickListener(v -> toggleHideMedia());
floatingBtn.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return saveDraft();
}
});
pickButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openPickDialog();
}
});
visibilityBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showComposeOptions();
}
});
saveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveDraft();
}
});
hideMediaToggle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleHideMedia();
}
});
//fix a bug with autocomplete and some keyboards //fix a bug with autocomplete and some keyboards
int newInputType = textEditor.getInputType() & (textEditor.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); int newInputType = textEditor.getInputType() & (textEditor.getInputType() ^ InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
@ -241,9 +211,7 @@ public final class ComposeActivity extends BaseActivity
/* Initialise all the state, or restore it from a previous run, to determine a "starting" /* Initialise all the state, or restore it from a previous run, to determine a "starting"
* state. */ * state. */
SharedPreferences preferences = getPrivatePreferences(); Status.Visibility startingVisibility = Status.Visibility.UNKNOWN;
Status.Visibility startingVisibility;
boolean startingHideText; boolean startingHideText;
String startingContentWarning = null; String startingContentWarning = null;
ArrayList<SavedQueuedMedia> savedMediaQueued = null; ArrayList<SavedQueuedMedia> savedMediaQueued = null;
@ -267,10 +235,6 @@ public final class ComposeActivity extends BaseActivity
photoUploadUri = savedInstanceState.getParcelable("photoUploadUri"); photoUploadUri = savedInstanceState.getParcelable("photoUploadUri");
} else { } else {
showMarkSensitive = false; showMarkSensitive = false;
startingVisibility = Status.Visibility.byNum(
preferences.getInt(REMEMBERED_VISIBILITY_PREF,
Status.Visibility.UNKNOWN.getNum())
);
statusMarkSensitive = false; statusMarkSensitive = false;
startingHideText = false; startingHideText = false;
photoUploadUri = null; photoUploadUri = null;
@ -283,12 +247,23 @@ public final class ComposeActivity extends BaseActivity
String[] mentionedUsernames = null; String[] mentionedUsernames = null;
ArrayList<String> loadedDraftMediaUris = null; ArrayList<String> loadedDraftMediaUris = null;
inReplyToId = null; inReplyToId = null;
Status.Visibility replyVisibility = Status.Visibility.UNKNOWN;
if (intent != null) { if (intent != null) {
if(startingVisibility == Status.Visibility.UNKNOWN) {
Status.Visibility replyVisibility = Status.Visibility.byNum(
intent.getIntExtra(REPLY_VISIBILITY_EXTRA, Status.Visibility.UNKNOWN.getNum()));
if(replyVisibility != Status.Visibility.UNKNOWN) {
startingVisibility = replyVisibility;
} else {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
startingVisibility = Status.Visibility.byString(
preferences.getString("defaultPostPrivacy",
Status.Visibility.PUBLIC.serverString()));
}
}
inReplyToId = intent.getStringExtra(IN_REPLY_TO_ID_EXTRA); inReplyToId = intent.getStringExtra(IN_REPLY_TO_ID_EXTRA);
replyVisibility = Status.Visibility.byNum(
intent.getIntExtra(REPLY_VISIBILITY_EXTRA, Status.Visibility.UNKNOWN.getNum())
);
mentionedUsernames = intent.getStringArrayExtra(MENTIONED_USERNAMES_EXTRA); mentionedUsernames = intent.getStringArrayExtra(MENTIONED_USERNAMES_EXTRA);
@ -323,14 +298,11 @@ public final class ComposeActivity extends BaseActivity
replyTextView.setVisibility(View.VISIBLE); replyTextView.setVisibility(View.VISIBLE);
String username = intent.getStringExtra(REPLYING_STATUS_AUTHOR_USERNAME_EXTRA); String username = intent.getStringExtra(REPLYING_STATUS_AUTHOR_USERNAME_EXTRA);
replyTextView.setText(getString(R.string.replying_to, username)); replyTextView.setText(getString(R.string.replying_to, username));
replyTextView.setOnClickListener(new View.OnClickListener() { replyTextView.setOnClickListener(v -> {
@Override if (replyContentTextView.getVisibility() != View.VISIBLE) {
public void onClick(View v) { replyContentTextView.setVisibility(View.VISIBLE);
if (replyContentTextView.getVisibility() != View.VISIBLE) { } else {
replyContentTextView.setVisibility(View.VISIBLE); replyContentTextView.setVisibility(View.GONE);
} else {
replyContentTextView.setVisibility(View.GONE);
}
} }
}); });
} }
@ -340,11 +312,8 @@ public final class ComposeActivity extends BaseActivity
} }
} }
Status.Visibility pickedVisibility = pickVisibility(startingVisibility, replyVisibility,
preferences.getBoolean("loggedInAccountLocked", 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.
setStatusVisibility(pickedVisibility); setStatusVisibility(startingVisibility);
postProgress.setVisibility(View.INVISIBLE); postProgress.setVisibility(View.INVISIBLE);
updateHideMediaToggleColor(); updateHideMediaToggleColor();
@ -496,6 +465,7 @@ public final class ComposeActivity extends BaseActivity
currentInputContentInfo = null; currentInputContentInfo = null;
currentFlags = 0; currentFlags = 0;
outState.putParcelable("photoUploadUri", photoUploadUri); outState.putParcelable("photoUploadUri", photoUploadUri);
outState.putInt("statusVisibility", statusVisibility.getNum());
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
@ -822,28 +792,12 @@ public final class ComposeActivity extends BaseActivity
readyStatus(statusVisibility, statusMarkSensitive); readyStatus(statusVisibility, statusMarkSensitive);
} }
@Override
protected void onStop() {
super.onStop();
// Don't save the visibility setting for replies because they adopt the visibility of
// the status they reply to and that behaviour needs to be kept separate.
if (inReplyToId == null) {
getPrivatePreferences().edit()
.putInt(REMEMBERED_VISIBILITY_PREF, statusVisibility.getNum())
.apply();
}
}
private void setEditTextMimeTypes() { private void setEditTextMimeTypes() {
final String[] mimeTypes = new String[]{"image/*"}; final String[] mimeTypes = new String[]{"image/*"};
textEditor.setMimeTypes(mimeTypes, new InputConnectionCompat.OnCommitContentListener() { textEditor.setMimeTypes(mimeTypes,
@Override (inputContentInfo, flags, opts) ->
public boolean onCommitContent(InputContentInfoCompat inputContentInfo, ComposeActivity.this.onCommitContent(inputContentInfo, flags,
int flags, Bundle opts) { mimeTypes));
return ComposeActivity.this.onCommitContent(inputContentInfo, flags,
mimeTypes);
}
});
} }
private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, private boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
@ -963,13 +917,10 @@ public final class ComposeActivity extends BaseActivity
if (response != null && inReplyToId != null && response.code() == 404) { if (response != null && inReplyToId != null && response.code() == 404) {
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setMessage(R.string.dialog_reply_not_found) .setMessage(R.string.dialog_reply_not_found)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, (dialog, which) -> {
@Override inReplyToId = null;
public void onClick(DialogInterface dialog, int which) { replyContentTextView.setVisibility(View.GONE);
inReplyToId = null; replyTextView.setVisibility(View.GONE);
replyContentTextView.setVisibility(View.GONE);
replyTextView.setVisibility(View.GONE);
}
}) })
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.show(); .show();
@ -1013,14 +964,11 @@ public final class ComposeActivity extends BaseActivity
super.onCancelled(); super.onCancelled();
} }
}; };
finishingUploadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { finishingUploadDialog.setOnCancelListener(dialog -> {
@Override /* Generating an interrupt by passing true here is important because an interrupt
public void onCancel(DialogInterface dialog) { * exception is the only thing that will kick the latch out of its waiting loop
/* Generating an interrupt by passing true here is important because an interrupt * early. */
* exception is the only thing that will kick the latch out of its waiting loop waitForMediaTask.cancel(true);
* early. */
waitForMediaTask.cancel(true);
}
}); });
waitForMediaTask.execute(); waitForMediaTask.execute();
} }
@ -1048,12 +996,7 @@ public final class ComposeActivity extends BaseActivity
private void onReadyFailure(final Status.Visibility visibility, final boolean sensitive) { private void onReadyFailure(final Status.Visibility visibility, final boolean sensitive) {
doErrorDialog(R.string.error_media_upload_sending, R.string.action_retry, doErrorDialog(R.string.error_media_upload_sending, R.string.action_retry,
new View.OnClickListener() { v -> readyStatus(visibility, sensitive));
@Override
public void onClick(View v) {
readyStatus(visibility, sensitive);
}
});
setStateToNotReadying(); setStateToNotReadying();
} }
@ -1063,18 +1006,15 @@ public final class ComposeActivity extends BaseActivity
CharSequence[] choices = new CharSequence[2]; CharSequence[] choices = new CharSequence[2];
choices[CHOICE_TAKE] = getString(R.string.action_photo_take); choices[CHOICE_TAKE] = getString(R.string.action_photo_take);
choices[CHOICE_PICK] = getString(R.string.action_photo_pick); choices[CHOICE_PICK] = getString(R.string.action_photo_pick);
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener listener = (dialog, which) -> {
@Override switch (which) {
public void onClick(DialogInterface dialog, int which) { case CHOICE_TAKE: {
switch (which) { initiateCameraApp();
case CHOICE_TAKE: { break;
initiateCameraApp(); }
break; case CHOICE_PICK: {
} onMediaPick();
case CHOICE_PICK: { break;
onMediaPick();
break;
}
} }
} }
}; };
@ -1106,12 +1046,7 @@ public final class ComposeActivity extends BaseActivity
initiateMediaPicking(); initiateMediaPicking();
} else { } else {
doErrorDialog(R.string.error_media_upload_permission, R.string.action_retry, doErrorDialog(R.string.error_media_upload_permission, R.string.action_retry,
new View.OnClickListener() { v -> onMediaPick());
@Override
public void onClick(View v) {
onMediaPick();
}
});
} }
break; break;
} }
@ -1193,12 +1128,7 @@ public final class ComposeActivity extends BaseActivity
view.setLayoutParams(layoutParams); view.setLayoutParams(layoutParams);
view.setScaleType(ImageView.ScaleType.CENTER_CROP); view.setScaleType(ImageView.ScaleType.CENTER_CROP);
view.setImageBitmap(preview); view.setImageBitmap(preview);
view.setOnClickListener(new View.OnClickListener() { view.setOnClickListener(v -> removeMediaFromQueue(item));
@Override
public void onClick(View v) {
removeMediaFromQueue(item);
}
});
view.setContentDescription(getString(R.string.action_delete)); view.setContentDescription(getString(R.string.action_delete));
mediaPreviewBar.addView(view); mediaPreviewBar.addView(view);
mediaQueued.add(item); mediaQueued.add(item);
@ -1334,12 +1264,7 @@ public final class ComposeActivity extends BaseActivity
@Override @Override
public void onProgressUpdate(final int percentage) { public void onProgressUpdate(final int percentage) {
if (percentage != lastProgress) { if (percentage != lastProgress) {
runOnUiThread(new Runnable() { runOnUiThread(() -> item.preview.setProgress(percentage));
@Override
public void run() {
item.preview.setProgress(percentage);
}
});
} }
lastProgress = percentage; lastProgress = percentage;
} }
@ -1607,41 +1532,6 @@ public final class ComposeActivity extends BaseActivity
} }
} }
/**
* Function to decide which visibility should be used for posting a status
*
* @return {@code PRIVATE} if account is locked, {@code PUBLIC} if both start and reply
* visibilities are unknown or minimal known visibility of two of them.
*/
private static Status.Visibility pickVisibility(final Status.Visibility startVisibility,
final Status.Visibility replyVisibility,
boolean isAccountLocked) {
// If the currently logged in account is locked, its posts should default to private.
// This should override even the reply settings.
if (isAccountLocked) {
return Status.Visibility.PRIVATE;
}
if (startVisibility == Status.Visibility.UNKNOWN &&
replyVisibility == Status.Visibility.UNKNOWN) {
return Status.Visibility.PUBLIC;
}
if (replyVisibility == Status.Visibility.UNKNOWN) {
return startVisibility;
}
if (startVisibility == Status.Visibility.UNKNOWN) {
return replyVisibility;
}
if (startVisibility.getNum() > replyVisibility.getNum()) {
return startVisibility;
} else {
return replyVisibility;
}
}
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static final class IntentBuilder { public static final class IntentBuilder {
@Nullable @Nullable

View file

@ -80,6 +80,16 @@ public class Status {
} }
} }
public static Visibility byString(String s) {
switch (s) {
case "public": return PUBLIC;
case "unlisted": return UNLISTED;
case "private": return PRIVATE;
case "direct": return DIRECT;
case "unknown": default: return UNKNOWN;
}
}
public String serverString() { public String serverString() {
switch (this) { switch (this) {
case PUBLIC: return "public"; case PUBLIC: return "public";

View file

@ -16,4 +16,10 @@
<item>60</item> <item>60</item>
<item>120</item> <item>120</item>
</string-array> </string-array>
<string-array name="post_privacy_values" inputType="integer">
<item>public</item>
<item>unlisted</item>
<item>private</item>
</string-array>
</resources> </resources>

View file

@ -107,7 +107,7 @@
<string name="download_image">Downloading %1$s</string> <string name="download_image">Downloading %1$s</string>
<string name="action_copy_link">Copy the link</string> <string name="action_copy_link">Copy the link</string>
<string name="send_status_link_to">Share toot URL to…</string> <string name="send_status_link_to">Share toot URL to…</string>
<string name="send_status_content_to">Share toot to…</string> <string name="send_status_content_to">Share toot to…</string>
@ -146,7 +146,6 @@
<string name="dialog_download_image">Download</string> <string name="dialog_download_image">Download</string>
<string name="dialog_message_follow_request">Follow request pending: awaiting their response</string> <string name="dialog_message_follow_request">Follow request pending: awaiting their response</string>
<string name="dialog_unfollow_warning">Unfollow this account?</string> <string name="dialog_unfollow_warning">Unfollow this account?</string>
<string name="dialog_reply_not_found">Couldn\'t post this status. The status you\'re replying to might not be available. Remove reply info?</string>
<string name="visibility_public">Public: Post to public timelines</string> <string name="visibility_public">Public: Post to public timelines</string>
<string name="visibility_unlisted">Unlisted: Do not show in public timelines</string> <string name="visibility_unlisted">Unlisted: Do not show in public timelines</string>
@ -187,6 +186,15 @@
<item>2 hours</item> <item>2 hours</item>
</string-array> </string-array>
<string name="pref_default_post_privacy">Default post privacy</string>
<string name="pref_publishing">Publishing</string>
<string-array name="post_privacy_names" inputType="integer">
<item>Public</item>
<item>Unlisted</item>
<item>Followers-only</item>
</string-array>
<string name="notification_channel_mention_name">New Mentions</string> <string name="notification_channel_mention_name">New Mentions</string>
<string name="notification_channel_mention_descriptions">Notifications about new mentions</string> <string name="notification_channel_mention_descriptions">Notifications about new mentions</string>
<string name="notification_channel_follow_name">New Followers</string> <string name="notification_channel_follow_name">New Followers</string>
@ -250,4 +258,5 @@
<string name="replying_to">Replying to @%s</string> <string name="replying_to">Replying to @%s</string>
<string name="load_more_placeholder_text">load more</string> <string name="load_more_placeholder_text">load more</string>
</resources> </resources>

View file

@ -25,6 +25,17 @@
android:title="@string/pref_title_alway_show_sensitive_media" /> android:title="@string/pref_title_alway_show_sensitive_media" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/pref_publishing">
<ListPreference
android:defaultValue="public"
android:entries="@array/post_privacy_names"
android:entryValues="@array/post_privacy_values"
android:key="defaultPostPrivacy"
android:summary="%s"
android:title="@string/pref_default_post_privacy" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_title_browser_settings"> <PreferenceCategory android:title="@string/pref_title_browser_settings">
<CheckBoxPreference <CheckBoxPreference
android:defaultValue="false" android:defaultValue="false"