removed global proxy class, added dialog warning for video viewer, bug fix, code cleanup

This commit is contained in:
nuclearfog 2022-05-23 19:08:54 +02:00
parent ac5dfdb194
commit 688aaf066d
No known key found for this signature in database
GPG Key ID: AA0271FBE406DB98
21 changed files with 193 additions and 145 deletions

View File

@ -5,13 +5,7 @@ import android.os.Build;
import androidx.appcompat.app.AppCompatDelegate;
import org.nuclearfog.twidda.backend.proxy.GlobalProxySelector;
import org.nuclearfog.twidda.backend.proxy.ProxyAuthenticator;
import org.nuclearfog.twidda.backend.utils.TLSSocketFactory;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.net.Authenticator;
import java.net.ProxySelector;
/**
* custom application class to initialize support for old android versions and proxy settings
@ -31,17 +25,5 @@ public class CompatApplication extends Application {
// check and enable TLS 1.2 support
TLSSocketFactory.setSupportTLS();
// setup global proxy
// Twitter API and picasso use their own proxy implementation
GlobalSettings settings = GlobalSettings.getInstance(this);
GlobalProxySelector proxyConnection = new GlobalProxySelector(settings);
ProxyAuthenticator proxyLogin = new ProxyAuthenticator(settings);
try {
ProxySelector.setDefault(proxyConnection);
Authenticator.setDefault(proxyLogin);
} catch (SecurityException e) {
e.printStackTrace();
}
}
}

View File

@ -1,40 +0,0 @@
package org.nuclearfog.twidda.backend.proxy;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.LinkedList;
import java.util.List;
/**
* This class hosts {@link UserProxy} and provides the proxy settings on demand
* Some classes like MediaPlayer doesn't support proxy settings.
*
* @author nuclearfog
*/
public class GlobalProxySelector extends ProxySelector {
private GlobalSettings settings;
public GlobalProxySelector(GlobalSettings settings) {
this.settings = settings;
}
@Override
public List<Proxy> select(URI uri) {
// create proxy list from the settings
List<Proxy> proxyList = new LinkedList<>();
proxyList.add(UserProxy.get(settings));
return proxyList;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
// ignore
}
}

View File

@ -1,5 +1,7 @@
package org.nuclearfog.twidda.backend.proxy;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.net.Authenticator;
@ -12,14 +14,16 @@ import okhttp3.Route;
/**
* this class provides proxy authentication
* when proxy settings changes, the new setup will be applied immediately
* when proxy settings changes, the new setup will be applied immediately to all okhttp instances
*
* @author nuclearfog
*/
public class ProxyAuthenticator extends Authenticator implements okhttp3.Authenticator {
private GlobalSettings settings;
/**
* @param settings global app settings instance
*/
public ProxyAuthenticator(GlobalSettings settings) {
this.settings = settings;
}
@ -35,8 +39,9 @@ public class ProxyAuthenticator extends Authenticator implements okhttp3.Authent
return new PasswordAuthentication("", new char[0]);
}
@Override
public Request authenticate(Route route, Response response) {
public Request authenticate(Route route, @NonNull Response response) {
if (settings.isProxyAuthSet()) {
String credential = Credentials.basic(settings.getProxyUser(), settings.getProxyPass());
return response.request().newBuilder().header("Proxy-Authorization", credential).build();

View File

@ -104,6 +104,7 @@ public class GlobalSettings {
private static final String PROXY_PORT = "proxy_port";
private static final String PROXY_USER = "proxy_user";
private static final String PROXY_PASS = "proxy_pass";
private static final String PROXY_IGNORE = "ignore_proxy_set";
private static final String TREND_LOC = "location";
private static final String TREND_ID = "world_id";
private static final String LINK_PREVIEW = "link_preview";
@ -153,6 +154,7 @@ public class GlobalSettings {
private boolean loggedIn;
private boolean isProxyEnabled;
private boolean isProxyAuthSet;
private boolean ignoreProxyWarning;
private boolean customAPIKey;
private boolean toolbarOverlap;
private boolean linkPreview;
@ -882,7 +884,7 @@ public class GlobalSettings {
}
/**
* check kif proxy authentication is set
* check if proxy authentication is set
*
* @return true if user auth is set
*/
@ -890,6 +892,27 @@ public class GlobalSettings {
return isProxyAuthSet;
}
/**
* check if proxy warning should be ignored
*
* @return true if proxy warning should be ignored
*/
public boolean ignoreProxyWarning() {
return ignoreProxyWarning;
}
/**
* enable/ignore proxy warning
*
* @param ignore true to ignore proxy warning
*/
public void setIgnoreProxyWarning(boolean ignore) {
ignoreProxyWarning = ignore;
Editor e = settings.edit();
e.putBoolean(PROXY_IGNORE, ignore);
e.apply();
}
/**
* Check if current user is logged in
*
@ -1093,6 +1116,7 @@ public class GlobalSettings {
listSize = settings.getInt(LIST_SIZE, DEFAULT_LIST_SIZE);
isProxyEnabled = settings.getBoolean(PROXY_SET, false);
isProxyAuthSet = settings.getBoolean(AUTH_SET, false);
ignoreProxyWarning = settings.getBoolean(PROXY_IGNORE, false);
loggedIn = settings.getBoolean(LOGGED_IN, false);
loadImage = settings.getBoolean(IMAGE_LOAD, true);
loadAnswer = settings.getBoolean(ANSWER_LOAD, false);

View File

@ -316,7 +316,7 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// confirm log out
if (type == DialogType.APP_LOG_OUT) {
settings.logout();
@ -713,6 +713,7 @@ public class AppSettings extends AppCompatActivity implements OnClickListener, O
}
} else {
settings.clearProxyServer();
settings.setIgnoreProxyWarning(false);
}
// check if API-keys are correctly set
if (enableAPI.isChecked()) {

View File

@ -166,7 +166,7 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// retry sending message
if (type == DialogType.MESSAGE_EDITOR_ERROR) {
sendMessage();

View File

@ -239,7 +239,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, OnP
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// leave without settings
if (type == DialogType.PROFILE_EDITOR_LEAVE) {
finish();

View File

@ -124,7 +124,7 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
private Picasso picasso;
private LinkDialog linkPreview;
private ConfirmDialog deleteDialog;
private ConfirmDialog confirmDialog;
private TextView tweet_api, tweetDate, tweetText, scrName, usrName, tweetLocName, sensitive_media;
private Button ansButton, rtwButton, favButton, replyName, tweetLocGPS, retweeter;
@ -215,9 +215,9 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
picasso = PicassoBuilder.get(this);
linkPreview = new LinkDialog(this);
deleteDialog = new ConfirmDialog(this);
confirmDialog = new ConfirmDialog(this);
deleteDialog.setConfirmListener(this);
confirmDialog.setConfirmListener(this);
retweeter.setOnClickListener(this);
replyName.setOnClickListener(this);
ansButton.setOnClickListener(this);
@ -327,7 +327,7 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
User author = clickedTweet.getAuthor();
// Delete tweet option
if (item.getItemId() == R.id.menu_tweet_delete) {
deleteDialog.show(DialogType.TWEET_DELETE);
confirmDialog.show(DialogType.TWEET_DELETE);
}
// hide tweet
else if (item.getItemId() == R.id.menu_tweet_hide) {
@ -449,11 +449,15 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
}
// open embedded video link
else if (clickedTweet.getMediaType().equals(Tweet.MEDIA_VIDEO)) {
if (!settings.isProxyEnabled() || (settings.isProxyEnabled() && settings.ignoreProxyWarning())) {
Uri link = clickedTweet.getMediaUris()[0];
Intent mediaIntent = new Intent(this, VideoViewer.class);
mediaIntent.putExtra(VideoViewer.VIDEO_URI, link);
mediaIntent.putExtra(VideoViewer.ENABLE_VIDEO_CONTROLS, true);
startActivity(mediaIntent);
} else {
confirmDialog.show(DialogType.PROXY_CONFIRM);
}
}
// open embedded gif link
else if (clickedTweet.getMediaType().equals(Tweet.MEDIA_GIF)) {
@ -505,14 +509,23 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
@Override
public void onConfirm(DialogType type) {
if (type == DialogType.TWEET_DELETE) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (tweet != null) {
long tweetId = tweet.getId();
if (tweet.getEmbeddedTweet() != null)
tweetId = tweet.getEmbeddedTweet().getId();
statusAsync = new TweetAction(this, Action.DELETE, tweetId, tweet.getRetweetId());
Tweet clickedTweet = tweet;
if (tweet.getEmbeddedTweet() != null) {
clickedTweet = tweet.getEmbeddedTweet();
}
if (type == DialogType.TWEET_DELETE) {
statusAsync = new TweetAction(this, Action.DELETE, clickedTweet.getId(), tweet.getRetweetId());
statusAsync.execute();
} else if (type == DialogType.PROXY_CONFIRM) {
settings.setIgnoreProxyWarning(rememberChoice);
Uri link = clickedTweet.getMediaUris()[0];
Intent mediaIntent = new Intent(this, VideoViewer.class);
mediaIntent.putExtra(VideoViewer.VIDEO_URI, link);
mediaIntent.putExtra(VideoViewer.ENABLE_VIDEO_CONTROLS, true);
startActivity(mediaIntent);
}
}
}

View File

@ -308,7 +308,7 @@ public class TweetEditor extends MediaActivity implements OnClickListener, OnPro
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// retry uploading tweet
if (type == DialogType.TWEET_EDITOR_ERROR) {
updateTweet();

View File

@ -536,7 +536,7 @@ public class UserProfile extends AppCompatActivity implements OnClickListener, O
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (user != null) {
profileAsync = new UserAction(this, user.getId());
// confirmed unfollowing user

View File

@ -273,7 +273,7 @@ public class UserlistActivity extends AppCompatActivity implements OnTabSelected
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// delete user list
if (type == DialogType.LIST_DELETE) {
if (userList != null) {

View File

@ -148,7 +148,7 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
// retry updating list
if (type == DialogType.LIST_EDITOR_ERROR) {
updateList();

View File

@ -374,7 +374,7 @@ public class VideoViewer extends MediaActivity implements OnSeekBarChangeListene
@Override
public void onConfirm(ConfirmDialog.DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (type == DialogType.VIDEO_ERROR) {
Uri link = getIntent().getParcelableExtra(VIDEO_URI);
if (link != null) {

View File

@ -6,6 +6,7 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import androidx.annotation.Nullable;
@ -29,6 +30,7 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
DELETE_APP_DATA,
APP_LOG_OUT,
REMOVE_ACCOUNT,
PROXY_CONFIRM,
VIDEO_ERROR,
TWEET_DELETE,
TWEET_EDITOR_LEAVE,
@ -48,7 +50,8 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
LIST_EDITOR_ERROR
}
private TextView txtTitle, txtMessage;
private TextView title, message, confirmDescr;
private CompoundButton confirmCheck;
private Button confirm, cancel;
@Nullable
@ -63,8 +66,10 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
ViewGroup root = findViewById(R.id.confirm_rootview);
confirm = findViewById(R.id.confirm_yes);
cancel = findViewById(R.id.confirm_no);
txtTitle = findViewById(R.id.confirm_title);
txtMessage = findViewById(R.id.confirm_message);
title = findViewById(R.id.confirm_title);
message = findViewById(R.id.confirm_message);
confirmDescr = findViewById(R.id.confirm_remember_descr);
confirmCheck = findViewById(R.id.confirm_remember);
GlobalSettings settings = GlobalSettings.getInstance(context);
AppStyles.setTheme(root, settings.getBackgroundColor());
@ -85,97 +90,118 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
// attach type to the view
confirm.setTag(type);
// set default values
confirm.setCompoundDrawablesWithIntrinsicBounds(R.drawable.check, 0, 0, 0);
cancel.setCompoundDrawablesWithIntrinsicBounds(R.drawable.cross, 0, 0, 0);
confirm.setText(android.R.string.ok);
cancel.setText(android.R.string.cancel);
cancel.setVisibility(View.VISIBLE);
txtTitle.setVisibility(View.GONE);
// default values
int titleVis = View.GONE;
int titleTxt = R.string.info_error;
int messageTxt = R.string.confirm_unknown_error;
int confirmTxt = android.R.string.ok;
int confirmIcon = R.drawable.check;
int confirmVis = View.INVISIBLE;
int cancelTxt = android.R.string.cancel;
int cancelIcon = R.drawable.cross;
int cancelVis = View.VISIBLE;
switch (type) {
case MESSAGE_DELETE:
txtMessage.setText(R.string.confirm_delete_message);
messageTxt = R.string.confirm_delete_message;
break;
case WRONG_PROXY:
txtTitle.setVisibility(View.VISIBLE);
txtTitle.setText(R.string.info_error);
txtMessage.setText(R.string.error_wrong_connection_settings);
titleVis = View.VISIBLE;
messageTxt = R.string.error_wrong_connection_settings;
break;
case DELETE_APP_DATA:
txtMessage.setText(R.string.confirm_delete_database);
messageTxt = R.string.confirm_delete_database;
break;
case APP_LOG_OUT:
txtMessage.setText(R.string.confirm_log_lout);
messageTxt = R.string.confirm_log_lout;
break;
case VIDEO_ERROR:
txtTitle.setVisibility(View.VISIBLE);
txtTitle.setText(R.string.info_error);
txtMessage.setText(R.string.error_cant_load_video);
confirm.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
confirm.setText(R.string.confirm_open_link);
cancel.setVisibility(View.GONE);
titleVis = View.VISIBLE;
messageTxt = R.string.error_cant_load_video;
confirmIcon = 0;
confirmTxt = R.string.confirm_open_link;
cancelVis = View.GONE;
break;
case LIST_EDITOR_LEAVE:
case PROFILE_EDITOR_LEAVE:
txtMessage.setText(R.string.confirm_discard);
messageTxt = R.string.confirm_discard;
break;
case TWEET_EDITOR_LEAVE:
txtMessage.setText(R.string.confirm_cancel_tweet);
messageTxt = R.string.confirm_cancel_tweet;
break;
case MESSAGE_EDITOR_LEAVE:
txtMessage.setText(R.string.confirm_cancel_message);
messageTxt = R.string.confirm_cancel_message;
break;
case LIST_EDITOR_ERROR:
case MESSAGE_EDITOR_ERROR:
case TWEET_EDITOR_ERROR:
case PROFILE_EDITOR_ERROR:
txtTitle.setVisibility(View.VISIBLE);
txtTitle.setText(R.string.info_error);
txtMessage.setText(R.string.error_connection_failed);
confirm.setText(R.string.confirm_retry_button);
titleVis = View.VISIBLE;
messageTxt = R.string.error_connection_failed;
confirmTxt = R.string.confirm_retry_button;
break;
case TWEET_DELETE:
txtMessage.setText(R.string.confirm_delete_tweet);
messageTxt = R.string.confirm_delete_tweet;
break;
case PROFILE_UNFOLLOW:
txtMessage.setText(R.string.confirm_unfollow);
messageTxt = R.string.confirm_unfollow;
break;
case PROFILE_BLOCK:
txtMessage.setText(R.string.confirm_block);
messageTxt = R.string.confirm_block;
break;
case PROFILE_MUTE:
txtMessage.setText(R.string.confirm_mute);
messageTxt = R.string.confirm_mute;
break;
case LIST_REMOVE_USER:
txtMessage.setText(R.string.confirm_remove_user_from_list);
messageTxt = R.string.confirm_remove_user_from_list;
break;
case LIST_UNFOLLOW:
txtMessage.setText(R.string.confirm_unfollow_list);
messageTxt = R.string.confirm_unfollow_list;
break;
case LIST_DELETE:
txtMessage.setText(R.string.confirm_delete_list);
messageTxt = R.string.confirm_delete_list;
break;
case REMOVE_ACCOUNT:
txtMessage.setText(R.string.confirm_remove_account);
messageTxt = R.string.confirm_remove_account;
break;
case PROXY_CONFIRM:
confirmVis = View.VISIBLE;
titleVis = View.VISIBLE;
titleTxt = R.string.dialog_confirm_warning;
messageTxt = R.string.dialog_warning_videoview;
break;
}
title.setVisibility(titleVis);
title.setText(titleTxt);
message.setText(messageTxt);
cancel.setVisibility(cancelVis);
cancel.setText(cancelTxt);
cancel.setCompoundDrawablesWithIntrinsicBounds(cancelIcon, 0, 0, 0);
confirmCheck.setVisibility(confirmVis);
confirmDescr.setVisibility(confirmVis);
confirm.setText(confirmTxt);
confirm.setCompoundDrawablesWithIntrinsicBounds(confirmIcon, 0, 0, 0);
super.show();
}
@ -186,7 +212,8 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
Object tag = v.getTag();
if (listener != null && tag instanceof DialogType) {
DialogType type = (DialogType) tag;
listener.onConfirm(type);
boolean remember = confirmCheck.getVisibility() == View.VISIBLE && confirmCheck.isChecked();
listener.onConfirm(type, remember);
}
dismiss();
} else if (v.getId() == R.id.confirm_no) {
@ -207,7 +234,7 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
* @param message message text
*/
public void setMessage(String message) {
txtMessage.setText(message);
this.message.setText(message);
}
/**
@ -219,7 +246,8 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
* called when the positive button was clicked
*
* @param type type of dialog
* @param rememberChoice true if choice should be remembered
*/
void onConfirm(DialogType type);
void onConfirm(DialogType type, boolean rememberChoice);
}
}

View File

@ -108,7 +108,7 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (type == DialogType.REMOVE_ACCOUNT) {
loginTask = new AccountLoader(this);
loginTask.execute(selection);

View File

@ -176,7 +176,7 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (type == DialogType.MESSAGE_DELETE) {
if (messageTask != null && messageTask.getStatus() != RUNNING) {
messageTask = new MessageLoader(this, MessageLoader.Action.DEL, null, deleteId);

View File

@ -214,7 +214,7 @@ public class UserFragment extends ListFragment implements UserClickListener,
@Override
public void onConfirm(DialogType type) {
public void onConfirm(DialogType type, boolean rememberChoice) {
if (type == DialogType.LIST_REMOVE_USER) {
if (listTask == null || listTask.getStatus() != RUNNING) {
listTask = new ListManager(requireContext(), id, DEL_USER, deleteUserName, this);

View File

@ -11,17 +11,17 @@
android:id="@+id/confirm_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/confirm_text_margin"
android:layout_marginStart="@dimen/confirm_text_margin"
android:layout_marginLeft="@dimen/confirm_text_margin"
android:layout_marginTop="@dimen/confirm_text_margin"
android:layout_marginRight="@dimen/confirm_text_margin"
android:layout_marginEnd="@dimen/confirm_text_margin"
android:layout_marginRight="@dimen/confirm_text_margin"
android:singleLine="true"
android:textSize="@dimen/confirm_title_fontsize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/confirm_message"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/confirm_message"
@ -31,42 +31,66 @@
android:maxLines="@integer/confirm_message_max_ines"
android:scrollbars="vertical"
android:textSize="@dimen/confirm_message_fontsize"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/confirm_title"
app:layout_constraintBottom_toTopOf="@id/confirm_barrier"
app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/confirm_title" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/confirm_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="top"
app:constraint_referenced_ids="confirm_no,confirm_yes" />
app:constraint_referenced_ids="confirm_no,confirm_yes,confirm_remember,confirm_remember_descr" />
<CheckBox
android:id="@+id/confirm_remember"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/confirm_button_margin"
android:singleLine="true"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/confirm_remember_descr"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/confirm_remember_descr"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/confirm_checkbox_text_margin"
android:layout_marginRight="@dimen/confirm_checkbox_text_margin"
android:text="@string/dialog_confirm_remember"
android:textSize="@dimen/confirm_checkbox_text_size"
app:layout_constraintBottom_toBottomOf="@id/confirm_remember"
app:layout_constraintEnd_toStartOf="@id/confirm_no"
app:layout_constraintStart_toEndOf="@id/confirm_remember"
app:layout_constraintTop_toTopOf="@id/confirm_remember" />
<Button
android:id="@+id/confirm_no"
style="@style/FeedbackButton"
android:layout_width="0dp"
android:layout_height="@dimen/confirm_button_height"
android:padding="@dimen/confirm_button_padding"
android:layout_margin="@dimen/confirm_button_margin"
android:padding="@dimen/confirm_button_padding"
android:singleLine="true"
android:text="@android:string/cancel"
android:textSize="@dimen/confirm_button_fontsize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/confirm_yes"
style="@style/FeedbackButton" />
app:layout_constraintEnd_toStartOf="@id/confirm_yes" />
<Button
android:id="@+id/confirm_yes"
style="@style/FeedbackButton"
android:layout_width="0dp"
android:layout_height="@dimen/confirm_button_height"
android:padding="@dimen/confirm_button_padding"
android:layout_margin="@dimen/confirm_button_margin"
android:padding="@dimen/confirm_button_padding"
android:singleLine="true"
android:text="@android:string/ok"
android:textSize="@dimen/confirm_button_fontsize"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="@style/FeedbackButton" />
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -235,4 +235,9 @@
<string name="info_reply_hidden">Antwort wurde ausgeblendet</string>
<string name="info_reply_unhidden">Antwort wurde eingeblendet</string>
<string name="settings_description_enable_twitter_alt">nitter.net für Links benutzen</string>
<string name="dialog_confirm_warning">Warnung</string>
<string name="dialog_warning_videoview">Videoplayer unterstützt keine Proxy Verbindung! Fortsetzen ohne Proxy?</string>
<string name="confirm_unknown_error">Unbekannter Fehler!</string>
<string name="dialog_confirm_remember">merken</string>
<string name="directmessage_media_button">Medienanhang</string>
</resources>

View File

@ -196,6 +196,8 @@
<dimen name="confirm_message_fontsize">18sp</dimen>
<dimen name="confirm_title_fontsize">22sp</dimen>
<dimen name="confirm_button_height">30sp</dimen>
<dimen name="confirm_checkbox_text_margin">5dp</dimen>
<dimen name="confirm_checkbox_text_size">10sp</dimen>
<integer name="confirm_message_max_ines">8</integer>
<!--dimens of dialog_userlist.xml-->

View File

@ -243,6 +243,8 @@
<string name="update_list">update list</string>
<string name="confirm_remove_user_from_list">remove user from list?</string>
<string name="descr_remove_user">remove user from list</string>
<string name="dialog_confirm_remember">remember</string>
<string name="confirm_unknown_error">unknown error!</string>
<string name="list_following_indicator">following list</string>
<string name="descr_add_profile_image">change profile image</string>
<string name="app_info_twitter_rules">The Twitter rules:</string>
@ -255,6 +257,8 @@
<string name="settings_follow_color">Following icon</string>
<string name="account_page" translatable="false">Accounts</string>
<string name="confirm_remove_account">remove account from list?</string>
<string name="dialog_confirm_warning">Warning</string>
<string name="dialog_warning_videoview">videoplayer does not support proxy! Continue without proxy connection?</string>
<string name="account_user_id_prefix" translatable="false">User ID:</string>
<string name="account_user_unnamed">\'unnamed\'</string>
<string name="toolbar_tweet_favoriter">User favoriting this tweet</string>