bug fix, created report dialog, version upgrade

This commit is contained in:
nuclearfog 2023-07-02 16:14:36 +02:00
parent 3572ec6d68
commit 1849a03c08
No known key found for this signature in database
GPG Key ID: 03488A185C476379
38 changed files with 951 additions and 382 deletions

View File

@ -11,8 +11,8 @@ android {
applicationId 'org.nuclearfog.twidda'
minSdkVersion 21
targetSdkVersion 33
versionCode 89
versionName '3.2.2'
versionCode 90
versionName '3.2.3'
resConfigs 'en', 'es', 'de-rDE', 'zh-rCN'
}

View File

@ -1,10 +1,12 @@
package org.nuclearfog.twidda.backend.api;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.update.FilterUpdate;
import org.nuclearfog.twidda.backend.helper.update.ProfileUpdate;
import org.nuclearfog.twidda.backend.helper.update.PushUpdate;
import org.nuclearfog.twidda.backend.helper.update.ReportUpdate;
import org.nuclearfog.twidda.backend.helper.update.StatusUpdate;
import org.nuclearfog.twidda.backend.helper.update.UserListUpdate;
import org.nuclearfog.twidda.model.Account;
@ -45,7 +47,7 @@ public interface Connection {
* @param connection connection configuration
* @return authorisation link to open in a browser
*/
String getAuthorisationLink(ConnectionConfig connection) throws ConnectionException;
ConnectionResult getAuthorisationLink(ConnectionUpdate connection) throws ConnectionException;
/**
* login app and get login credentials
@ -54,7 +56,7 @@ public interface Connection {
* @param code verification code to login
* @return account information of the created login
*/
Account loginApp(ConnectionConfig connection, String code) throws ConnectionException;
Account loginApp(ConnectionUpdate connection, String code) throws ConnectionException;
/**
* get information about the host server
@ -705,4 +707,11 @@ public interface Connection {
* @return translation of the status
*/
Translation getStatusTranslation(long id) throws ConnectionException;
/**
* report status/user
*
* @param update report contianing information about status/user
*/
void createReport(ReportUpdate update) throws ConnectionException;
}

View File

@ -26,12 +26,14 @@ import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonStatus;
import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonTranslation;
import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonTrend;
import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonUser;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.update.FilterUpdate;
import org.nuclearfog.twidda.backend.helper.update.PollUpdate;
import org.nuclearfog.twidda.backend.helper.update.ProfileUpdate;
import org.nuclearfog.twidda.backend.helper.update.PushUpdate;
import org.nuclearfog.twidda.backend.helper.update.ReportUpdate;
import org.nuclearfog.twidda.backend.helper.update.StatusUpdate;
import org.nuclearfog.twidda.backend.helper.update.UserListUpdate;
import org.nuclearfog.twidda.backend.utils.ConnectionBuilder;
@ -145,6 +147,7 @@ public class Mastodon implements Connection {
private static final String ENDPOINT_DOMAIN_BLOCK = "/api/v1/domain_blocks";
private static final String ENDPOINT_PUSH_UPDATE = "/api/v1/push/subscription";
private static final String ENDPOINT_FILTER = "/api/v2/filters";
private static final String ENDPOINT_REPORT = "/api/v1/reports";
private static final MediaType TYPE_TEXT = MediaType.parse("text/plain");
private static final MediaType TYPE_STREAM = MediaType.parse("application/octet-stream");
@ -170,7 +173,7 @@ public class Mastodon implements Connection {
@Override
public String getAuthorisationLink(ConnectionConfig connection) throws MastodonException {
public ConnectionResult getAuthorisationLink(ConnectionUpdate connection) throws MastodonException {
List<String> params = new ArrayList<>();
params.add("scopes=" + AUTH_SCOPES);
params.add("redirect_uris=" + REDIRECT_URI);
@ -184,8 +187,8 @@ public class Mastodon implements Connection {
JSONObject json = new JSONObject(body.string());
String client_id = json.getString("client_id");
String client_secret = json.getString("client_secret");
connection.setOauthTokens(client_id, client_secret);
return hostname + ENDPOINT_AUTHORIZE_APP + "?scope=" + AUTH_SCOPES + "&response_type=code&redirect_uri=" + REDIRECT_URI + "&client_id=" + client_id;
String authLink = hostname + ENDPOINT_AUTHORIZE_APP + "?scope=" + AUTH_SCOPES + "&response_type=code&redirect_uri=" + REDIRECT_URI + "&client_id=" + client_id;
return new ConnectionResult(authLink, client_id, client_secret);
}
throw new MastodonException(response);
} catch (IOException | JSONException e) {
@ -195,7 +198,7 @@ public class Mastodon implements Connection {
@Override
public Account loginApp(ConnectionConfig connection, String pin) throws MastodonException {
public Account loginApp(ConnectionUpdate connection, String pin) throws MastodonException {
List<String> params = new ArrayList<>();
params.add("client_id=" + connection.getOauthConsumerToken());
params.add("client_secret=" + connection.getOauthTokenSecret());
@ -1228,9 +1231,9 @@ public class Mastodon implements Connection {
@Override
public Translation getStatusTranslation(long id) throws ConnectionException {
try {
List<String> param = new ArrayList<>();
param.add("lang=" + Locale.getDefault().getLanguage()); // set system language as destiny for translation
Response response = post(ENDPOINT_STATUS + id + "/translate", param);
List<String> params = new ArrayList<>();
params.add("lang=" + Locale.getDefault().getLanguage()); // set system language as destiny for translation
Response response = post(ENDPOINT_STATUS + id + "/translate", params);
ResponseBody body = response.body();
if (response.code() == 200 && body != null) {
JSONObject json = new JSONObject(body.string());
@ -1242,6 +1245,35 @@ public class Mastodon implements Connection {
}
}
@Override
public void createReport(ReportUpdate update) throws ConnectionException {
try {
List<String> params = new ArrayList<>();
params.add("account_id=" + update.getUserId());
for (long statusId : update.getStatusIds())
params.add("status_ids[]=" + statusId);
for (int ruleId : update.getRuleIds())
params.add("rule_ids[]=" + ruleId);
if (!update.getComment().trim().isEmpty())
params.add("comment=" + StringUtils.encode(update.getComment()));
if (update.getCategory() == ReportUpdate.CATEGORY_OTHER)
params.add("category=other");
else if (update.getCategory() == ReportUpdate.CATEGORY_SPAM)
params.add("category=spam");
else if (update.getCategory() == ReportUpdate.CATEGORY_VIOLATION)
params.add("category=violation");
if (update.getForward())
params.add("forward=true");
Response response = post(ENDPOINT_REPORT, params);
if (response.code() != 200) {
throw new MastodonException(response);
}
} catch (IOException e) {
throw new MastodonException(e);
}
}
/**
* get information about the current user
*

View File

@ -22,11 +22,13 @@ import org.nuclearfog.twidda.backend.api.twitter.v1.impl.TweetV1;
import org.nuclearfog.twidda.backend.api.twitter.v1.impl.TwitterV1Instance;
import org.nuclearfog.twidda.backend.api.twitter.v1.impl.UserListV1;
import org.nuclearfog.twidda.backend.api.twitter.v1.impl.UserV1;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.update.FilterUpdate;
import org.nuclearfog.twidda.backend.helper.update.ProfileUpdate;
import org.nuclearfog.twidda.backend.helper.update.PushUpdate;
import org.nuclearfog.twidda.backend.helper.update.ReportUpdate;
import org.nuclearfog.twidda.backend.helper.update.StatusUpdate;
import org.nuclearfog.twidda.backend.helper.update.UserListUpdate;
import org.nuclearfog.twidda.backend.utils.ConnectionBuilder;
@ -199,7 +201,7 @@ public class TwitterV1 implements Connection {
@Override
public String getAuthorisationLink(ConnectionConfig connection) throws TwitterException {
public ConnectionResult getAuthorisationLink(ConnectionUpdate connection) throws TwitterException {
try {
Response response;
if (connection.useTokens())
@ -212,8 +214,8 @@ public class TwitterV1 implements Connection {
// extract oauth_token from url
Uri uri = Uri.parse(AUTHENTICATE + "?" + res);
String tempOauthToken = uri.getQueryParameter("oauth_token");
connection.setTempOauthToken(tempOauthToken);
return TwitterV1.AUTHENTICATE + "?oauth_token=" + tempOauthToken;
String authLink = TwitterV1.AUTHENTICATE + "?oauth_token=" + tempOauthToken;
return new ConnectionResult(authLink, tempOauthToken);
}
throw new TwitterException(response);
} catch (IOException e) {
@ -223,7 +225,7 @@ public class TwitterV1 implements Connection {
@Override
public Account loginApp(ConnectionConfig connection, String pin) throws TwitterException {
public Account loginApp(ConnectionUpdate connection, String pin) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("oauth_verifier=" + pin);
params.add("oauth_token=" + connection.getTempOauthToken());
@ -1239,6 +1241,12 @@ public class TwitterV1 implements Connection {
throw new TwitterException("not supported");
}
@Override
public void createReport(ReportUpdate update) throws ConnectionException {
throw new TwitterException("not implemented");
}
/**
* get tweets using an endpoint
*

View File

@ -19,7 +19,7 @@ import org.nuclearfog.twidda.backend.api.twitter.v2.maps.LocationV2Map;
import org.nuclearfog.twidda.backend.api.twitter.v2.maps.MediaV2Map;
import org.nuclearfog.twidda.backend.api.twitter.v2.maps.PollV2Map;
import org.nuclearfog.twidda.backend.api.twitter.v2.maps.UserV2Map;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.utils.StringUtils;
import org.nuclearfog.twidda.model.Account;
import org.nuclearfog.twidda.model.Instance;
@ -58,7 +58,7 @@ public class TwitterV2 extends TwitterV1 {
@Override
public Account loginApp(ConnectionConfig connection, String pin) throws TwitterException {
public Account loginApp(ConnectionUpdate connection, String pin) throws TwitterException {
Account account = super.loginApp(connection, pin);
return new AccountV2(account);
}

View File

@ -9,7 +9,8 @@ import org.nuclearfog.twidda.BuildConfig;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.helper.update.PushUpdate;
import org.nuclearfog.twidda.config.Configuration;
import org.nuclearfog.twidda.config.GlobalSettings;
@ -53,8 +54,8 @@ public class LoginAction extends AsyncExecutor<LoginAction.LoginParam, LoginActi
database.saveLogin(login);
}
}
String redirectUrl = connection.getAuthorisationLink(param.connection);
return new LoginResult(LoginResult.MODE_REQUEST, redirectUrl, null);
ConnectionResult result = connection.getAuthorisationLink(param.connection);
return new LoginResult(LoginResult.MODE_REQUEST, result, null);
case LoginParam.MODE_LOGIN:
// login with pin and access token
@ -98,12 +99,12 @@ public class LoginAction extends AsyncExecutor<LoginAction.LoginParam, LoginActi
public static final int MODE_REQUEST = 1;
public static final int MODE_LOGIN = 2;
final ConnectionConfig connection;
final ConnectionUpdate connection;
final Configuration configuration;
final String code;
final int mode;
public LoginParam(int mode, Configuration configuration, ConnectionConfig connection, String code) {
public LoginParam(int mode, Configuration configuration, ConnectionUpdate connection, String code) {
this.connection = connection;
this.configuration = configuration;
this.mode = mode;
@ -124,10 +125,10 @@ public class LoginAction extends AsyncExecutor<LoginAction.LoginParam, LoginActi
@Nullable
public final ConnectionException exception;
@Nullable
public final String redirectUrl;
public final ConnectionResult connection;
LoginResult(int mode, @Nullable String redirectUrl, @Nullable ConnectionException exception) {
this.redirectUrl = redirectUrl;
LoginResult(int mode, @Nullable ConnectionResult connection, @Nullable ConnectionException exception) {
this.connection = connection;
this.exception = exception;
this.mode = mode;
}

View File

@ -0,0 +1,65 @@
package org.nuclearfog.twidda.backend.helper;
/**
* This class contains temporary access tokens and authorization url used to login app
*
* @author nuclearfog
*/
public class ConnectionResult {
private String consumerKey;
private String consumerSecret;
private String tempOauth;
private String authorizationUrl;
/**
* @param authorizationUrl authorization url used to redirect to login page
* @param consumerKey temporary generated app consumer token
* @param consumerSecret temporary generated app consumer secret
*/
public ConnectionResult(String authorizationUrl, String consumerKey, String consumerSecret) {
this.consumerKey = consumerKey;
this.consumerSecret = consumerSecret;
this.authorizationUrl = authorizationUrl;
tempOauth = "";
}
/**
* @param authorizationUrl authorization url used to redirect to login page
* @param tempOauth temporary generated oauth 1.0 access token
*/
public ConnectionResult(String authorizationUrl, String tempOauth) {
this.tempOauth = tempOauth;
this.authorizationUrl = authorizationUrl;
consumerKey = "";
consumerSecret = "";
}
/**
*
*/
public String getConsumerKey() {
return consumerKey;
}
/**
*
*/
public String getConsumerSecret() {
return consumerSecret;
}
/**
*
*/
public String getOauthToken() {
return tempOauth;
}
/**
*
*/
public String getAuthorizationUrl() {
return authorizationUrl;
}
}

View File

@ -1,7 +1,9 @@
package org.nuclearfog.twidda.backend.helper;
package org.nuclearfog.twidda.backend.helper.update;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.config.Configuration;
import java.io.Serializable;
@ -11,16 +13,15 @@ import java.io.Serializable;
*
* @author nuclearfog
*/
public class ConnectionConfig implements Serializable {
public class ConnectionUpdate implements Serializable {
private static final long serialVersionUID = 2238181470544567706L;
private Configuration apiConfig;
private String hostname = "";
// these attributes below may be changed by another (background) thread
private volatile String consumerKey = "";
private volatile String consumerSecret = "";
private volatile String tempOauth = "";
private String consumerKey = "";
private String consumerSecret = "";
private String tempOauth = "";
/**
* get host url used by the API
@ -102,10 +103,10 @@ public class ConnectionConfig implements Serializable {
}
/**
* set oauth token key pair
* set custom oauth tokens
*
* @param consumerKey oauth token
* @param consumerSecret oauth token secret
* @param consumerKey custom oauth consumer key
* @param consumerSecret custom oauth consumer secret
*/
public void setOauthTokens(String consumerKey, String consumerSecret) {
if (consumerKey != null) {
@ -117,12 +118,20 @@ public class ConnectionConfig implements Serializable {
}
/**
* set temporary oauth token
* set temporary access tokens
*
* @param tempOauth oauth token
* @param connectionResult connection containing temporary access tokens
*/
public void setTempOauthToken(String tempOauth) {
this.tempOauth = tempOauth;
public void setConnection(@Nullable ConnectionResult connectionResult) {
if (connectionResult != null) {
tempOauth = connectionResult.getOauthToken();
consumerKey = connectionResult.getConsumerKey();
consumerSecret = connectionResult.getConsumerSecret();
} else {
tempOauth = "";
consumerKey = "";
consumerSecret = "";
}
}

View File

@ -47,7 +47,11 @@ public class FilterUpdate implements Serializable {
keywordIds = new long[keywords.length];
for (int i = 0 ; i < keywords.length ; i++) {
keywordIds[i] = keywords[i].getId();
keyWordStr[i] = keywords[i].getKeyword();
if (keywords[i].isOneWord()) {
keyWordStr[i] = '\"' + keywords[i].getKeyword() + '\"';
} else {
keyWordStr[i] = keywords[i].getKeyword();
}
}
if (expires_at > 0) {
this.expires_at = expires_at;

View File

@ -0,0 +1,140 @@
package org.nuclearfog.twidda.backend.helper.update;
import androidx.annotation.NonNull;
import java.io.Serializable;
import java.util.Arrays;
/**
* Updater class to create report of status/user
*
* @author nuclearfog
*/
public class ReportUpdate implements Serializable {
private static final long serialVersionUID = 7643792374030657129L;
public static final int CATEGORY_OTHER = 10;
public static final int CATEGORY_SPAM = 11;
public static final int CATEGORY_VIOLATION = 12;
private long userId;
private long[] statusIds = {};
private int[] ruleIds = {};
private String comment = "";
private int category = CATEGORY_OTHER;
private boolean forward = false;
/**
* @param userId user ID to report
*/
public ReportUpdate(long userId) {
this.userId = userId;
}
/**
* get user ID to report
*
* @return user ID
*/
public long getUserId() {
return userId;
}
/**
* set status ID's related to user ID
*
* @param statusIds array of status IDs
*/
public void setStatusIds(long[] statusIds) {
this.statusIds = Arrays.copyOf(statusIds, statusIds.length);
}
/**
* get status ID's related to user ID
*
* @return array of status IDs
*/
public long[] getStatusIds() {
return Arrays.copyOf(statusIds, statusIds.length);
}
/**
* set rule IDs violated by user
*
* @param ruleIds array of rule IDs
*/
public void setRuleIds(int[] ruleIds) {
this.ruleIds = Arrays.copyOf(ruleIds, ruleIds.length);
}
/**
* get rule IDs violated by user
*
* @return array of rule IDs
*/
public int[] getRuleIds() {
return Arrays.copyOf(ruleIds, ruleIds.length);
}
/**
* add additional comment to violation
*
* @param comment comment attached to the report
*/
public void setComment(String comment) {
this.comment = comment;
}
/**
* get additional comment to violation
*
* @return comment attached to the report
*/
public String getComment() {
return comment;
}
/**
* set category of violation
*
* @param category violation category {@link #CATEGORY_VIOLATION ,#CATEGORY_SPAM,#CATEGORY_OTHER}
*/
public void setCategory(int category) {
this.category = category;
}
/**
* get category of violation
*
* @return violation category {@link #CATEGORY_VIOLATION ,#CATEGORY_SPAM,#CATEGORY_OTHER}
*/
public int getCategory() {
return category;
}
/**
* set report forwarding to source instance
*
* @return true to forward report to source instance
*/
public void setForward(boolean forward) {
this.forward = forward;
}
/**
* should report be forwarded to source instance
*
* @return true to forward report to source instance
*/
public boolean getForward() {
return forward;
}
@NonNull
@Override
public String toString() {
return "userID=" + userId;
}
}

View File

@ -33,7 +33,8 @@ import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.async.LoginAction;
import org.nuclearfog.twidda.backend.async.LoginAction.LoginParam;
import org.nuclearfog.twidda.backend.async.LoginAction.LoginResult;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.ConnectionResult;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorUtils;
import org.nuclearfog.twidda.config.Configuration;
@ -97,8 +98,8 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
private ViewGroup root;
@Nullable
private String loginLink;
private ConnectionConfig connection = new ConnectionConfig();
private ConnectionResult connectionResult;
private ConnectionUpdate connection = new ConnectionUpdate();
@Override
@ -132,8 +133,8 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
hostSelector.setAdapter(adapter);
if (savedInstanceState != null) {
Serializable data = savedInstanceState.getSerializable(KEY_SAVE);
if (data instanceof ConnectionConfig) {
connection = (ConnectionConfig) data;
if (data instanceof ConnectionUpdate) {
connection = (ConnectionUpdate) data;
}
}
@ -251,7 +252,7 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
else if (v.getId() == R.id.login_verifier) {
String code = pinInput.getText().toString();
// check if user clicked on PIN button
if (loginLink == null) {
if (connectionResult == null) {
Toast.makeText(getApplicationContext(), R.string.info_get_link, Toast.LENGTH_LONG).show();
} else if (code.isEmpty()) {
pinInput.setError(getString(R.string.error_enter_code));
@ -275,12 +276,14 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
}
// open API settings dialog
else if (v.getId() == R.id.login_network_settings) {
if (hostSelector.getSelectedItemPosition() == IDX_TWITTER) {
connectionDialog.show(connection);
} else if (hostSelector.getSelectedItemPosition() == IDX_MASTODON) {
connectionDialog.show(connection);
if (!connectionDialog.isShowing()) {
if (hostSelector.getSelectedItemPosition() == IDX_TWITTER) {
connectionDialog.show(connection);
} else if (hostSelector.getSelectedItemPosition() == IDX_MASTODON) {
connectionDialog.show(connection);
}
reset();
}
loginLink = null;
}
}
@ -299,7 +302,7 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
connection.setApiType(Configuration.TWITTER2);
}
}
loginLink = null;
reset();
}
@ -317,8 +320,11 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
break;
case LoginResult.MODE_REQUEST:
loginLink = result.redirectUrl;
connect();
connectionResult = result.connection;
if (connectionResult != null) {
connection.setConnection(connectionResult);
connect(connectionResult.getAuthorizationUrl());
}
break;
case LoginResult.MODE_ERROR:
@ -330,7 +336,7 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
/**
* open login page
*/
private void connect() {
private void connect(String loginLink) {
Intent loginIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(loginLink));
try {
startActivity(loginIntent);
@ -338,4 +344,12 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
Toast.makeText(getApplicationContext(), R.string.error_open_link, Toast.LENGTH_SHORT).show();
}
}
/**
* reset connection information
*/
private void reset() {
connection.setConnection(null);
connectionResult = null;
}
}

View File

@ -68,7 +68,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
viewPager = findViewById(R.id.home_pager);
tabSelector = findViewById(R.id.home_tab);
root = findViewById(R.id.main_layout);
loadingCircle = new ProgressDialog(this);
loadingCircle = new ProgressDialog(this, null);
settings = GlobalSettings.get(this);
tabSelector.addViewPager(viewPager);

View File

@ -87,7 +87,7 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
messageUpdater = new MessageUpdater(this);
instanceLoader = new InstanceLoader(this);
loadingCircle = new ProgressDialog(this);
loadingCircle = new ProgressDialog(this, this);
confirmDialog = new ConfirmDialog(this, this);
String prefix = getIntent().getStringExtra(KEY_MESSAGE_PREFIX);
@ -97,7 +97,6 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
send.setOnClickListener(this);
media.setOnClickListener(this);
preview.setOnClickListener(this);
loadingCircle.addOnProgressStopListener(this);
}

View File

@ -736,8 +736,7 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
if (result.mode == DomainResult.MODE_BLOCK) {
Toast.makeText(getApplicationContext(), R.string.info_domain_blocked, Toast.LENGTH_SHORT).show();
} else if (result.mode == DomainResult.ERROR) {
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
}
}

View File

@ -102,7 +102,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
profileLocation = findViewById(R.id.profile_edit_change_location);
userDescription = findViewById(R.id.profile_edit_change_description);
loadingCircle = new ProgressDialog(this);
loadingCircle = new ProgressDialog(this, null);
confirmDialog = new ConfirmDialog(this, this);
editorAsync = new UserUpdater(this);
settings = GlobalSettings.get(this);

View File

@ -256,8 +256,7 @@ public class SearchActivity extends AppCompatActivity implements OnTabSelectedLi
break;
case HashtagResult.ERROR:
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
break;
}
}

View File

@ -266,6 +266,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
hideSensitive.setOnCheckedChangeListener(this);
enable_proxy.setOnCheckedChangeListener(this);
enable_auth.setOnCheckedChangeListener(this);
push_label.setOnClickListener(this);
toolbarOverlap.setOnCheckedChangeListener(this);
fontSelector.setOnItemSelectedListener(this);
scaleSelector.setOnItemSelectedListener(this);
@ -328,6 +329,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
if (requestCode == REQUEST_PERMISSION_NOTIFICATION) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
PushSubscription.subscripe(getApplicationContext());
pushDialog.show();
} else {
enablePush.setChecked(false);
}
@ -423,6 +425,10 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
color = settings.getFollowIconColor();
showColorPicker(color, false);
}
// show push configuration dialog
else if (v.getId() == R.id.settings_enable_push_descr) {
pushDialog.show();
}
}
@ -677,8 +683,7 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
// set listener after modifying content to prevent listener call
location_dropdown.setOnItemSelectedListener(this);
} else {
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
}
}

View File

@ -1019,8 +1019,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
break;
case StatusResult.ERROR:
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
if (status == null) {
finish();
} else if (result.exception != null && result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
@ -1066,8 +1065,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
break;
case NotificationActionResult.ERROR:
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
if (notification == null) {
finish();
} else if (result.exception != null && result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
@ -1101,8 +1099,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
break;
case PollActionResult.ERROR:
String message = ErrorUtils.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
ErrorUtils.showErrorMessage(this, result.exception);
break;
}
}

View File

@ -135,7 +135,7 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
instanceLoader = new InstanceLoader(this);
statusUpdater = new StatusUpdater(this);
settings = GlobalSettings.get(this);
loadingCircle = new ProgressDialog(this);
loadingCircle = new ProgressDialog(this, this);
confirmDialog = new ConfirmDialog(this, this);
preferenceDialog = new StatusPreferenceDialog(this, statusUpdate);
pollDialog = new PollDialog(this, this);
@ -190,7 +190,6 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
pollBtn.setOnClickListener(this);
mediaBtn.setOnClickListener(this);
locationBtn.setOnClickListener(this);
loadingCircle.addOnProgressStopListener(this);
}
@ -212,6 +211,13 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
}
@Override
protected void onStop() {
audioDialog.dismiss();
super.onStop();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putSerializable(KEY_SAVE, statusUpdate);

View File

@ -90,7 +90,7 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
titleText = findViewById(R.id.list_edit_title);
descriptionText = findViewById(R.id.list_edit_descr);
loadingCircle = new ProgressDialog(this);
loadingCircle = new ProgressDialog(this, this);
confirmDialog = new ConfirmDialog(this, this);
listUpdater = new UserlistUpdater(this);
@ -115,7 +115,6 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
visibilityLabel.setVisibility(View.INVISIBLE);
}
updateButton.setOnClickListener(this);
loadingCircle.addOnProgressStopListener(this);
visibilitySwitch.setOnCheckedChangeListener(this);
}

View File

@ -4,12 +4,14 @@ import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
@ -49,20 +51,27 @@ public class AudioPlayerDialog extends Dialog implements OnClickListener, Closea
private ExoPlayer player;
@Nullable
private Uri data;
/**
* @inheritDoc
*
*/
public AudioPlayerDialog(Activity activity) {
super(activity, R.style.AudioDialog);
player = new ExoPlayer.Builder(activity.getApplicationContext(), createRenderer(activity.getApplicationContext())).build();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_audio_player);
controls = findViewById(R.id.dialog_audio_player_controls);
mediaLink = findViewById(R.id.dialog_audio_player_share);
controls = findViewById(R.id.dialog_audio_player_controls);
controls.setShowNextButton(false);
controls.setShowPreviousButton(false);
player = new ExoPlayer.Builder(activity.getApplicationContext(), createRenderer(activity.getApplicationContext())).build();
controls.setPlayer(player);
controls.setShowTimeoutMs(-1);
@ -70,6 +79,47 @@ public class AudioPlayerDialog extends Dialog implements OnClickListener, Closea
}
@Override
protected void onStart() {
super.onStart();
// prevent re-initializing after resuming
if (data != null) {
DataSource.Factory dataSourceFactory;
MediaItem mediaItem = MediaItem.fromUri(data);
// initialize online source
if (data.getScheme().startsWith("http")) {
// configure with okhttp connection of the app
dataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) ConnectionBuilder.create(getContext()));
mediaLink.setVisibility(View.VISIBLE);
}
// initialize local source
else {
mediaLink.setVisibility(View.GONE);
dataSourceFactory = new DataSource.Factory() {
@NonNull
@Override
public DataSource createDataSource() {
return new ContentDataSource(getContext());
}
};
}
MediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory, new DefaultExtractorsFactory()).createMediaSource(mediaItem);
player.setMediaSource(mediaSource);
player.prepare();
player.setPlayWhenReady(true);
// reset data source
data = null;
}
}
@Override
protected void onStop() {
super.onStop();
player.pause();
}
@Override
public void show() {
// use show(Uri) instead
@ -90,16 +140,16 @@ public class AudioPlayerDialog extends Dialog implements OnClickListener, Closea
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_audio_player_share) {
if (data != null) {
LinkUtils.openMediaLink(getContext(), data);
}
LinkUtils.openMediaLink(getContext(), data);
}
}
@Override
public void close() {
// remove player to prevent memory leak
controls.setPlayer(null);
if (controls != null) {
controls.setPlayer(null);
}
}
/**
@ -108,35 +158,10 @@ public class AudioPlayerDialog extends Dialog implements OnClickListener, Closea
* @param data uri to the audio file
*/
public void show(Uri data) {
if (isShowing())
return;
super.show();
this.data = data;
DataSource.Factory dataSourceFactory;
MediaItem mediaItem = MediaItem.fromUri(data);
// initialize online source
if (data.getScheme().startsWith("http")) {
// configure with okhttp connection of the app
dataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) ConnectionBuilder.create(getContext()));
mediaLink.setVisibility(View.VISIBLE);
if (!isShowing()) {
this.data = data;
super.show();
}
// initialize local source
else {
mediaLink.setVisibility(View.GONE);
dataSourceFactory = new DataSource.Factory() {
@NonNull
@Override
public DataSource createDataSource() {
return new ContentDataSource(getContext());
}
};
}
MediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory, new DefaultExtractorsFactory()).createMediaSource(mediaItem);
player.setMediaSource(mediaSource);
player.prepare();
player.setPlayWhenReady(true);
}
/**

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -126,70 +127,59 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
*/
public static final int NOTIFICATION_DISMISS = 623;
/**
* show notification when adding domain hostname to blocklist
*/
public static final int DOMAIN_BLOCK_ADD = 624;
/**
* show notification when removing domain hostname to blocklist
*/
public static final int DOMAIN_BLOCK_REMOVE = 625;
/**
* show notification when removing a filter from filterlist
*/
public static final int FILTER_REMOVE = 626;
private TextView title, message;
private Button confirm, cancel;
private ViewGroup root;
private OnConfirmListener listener;
private int type = 0;
private String messageStr = "";
/**
*
*/
public ConfirmDialog(Activity activity, OnConfirmListener listener) {
super(activity, R.style.ConfirmDialog);
this.listener = listener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_confirm);
root = findViewById(R.id.confirm_rootview);
ViewGroup root = findViewById(R.id.confirm_rootview);
confirm = findViewById(R.id.confirm_yes);
cancel = findViewById(R.id.confirm_no);
title = findViewById(R.id.confirm_title);
message = findViewById(R.id.confirm_message);
AppStyles.setTheme(root);
confirm.setOnClickListener(this);
cancel.setOnClickListener(this);
}
@Override
public void dismiss() {
if (isShowing()) {
super.dismiss();
}
}
@Override
public void show() {
}
/**
* creates an alert dialog
*
* @param type Type of dialog to show
*/
public void show(int type) {
show(type, null);
}
/**
* creates an alert dialog
*
* @param type Type of dialog to show
* @param messageTxt override default message text
*/
public void show(int type, @Nullable String messageTxt) {
if (isShowing()) {
return;
}
// attach type to the view
protected void onStart() {
super.onStart();
confirm.setTag(type);
// default visibility values
int titleVis = View.GONE;
@ -301,13 +291,48 @@ public class ConfirmDialog extends Dialog implements OnClickListener {
confirm.setText(confirmRes);
confirm.setCompoundDrawablesWithIntrinsicBounds(confirmIconRes, 0, 0, 0);
// setup message
if (messageTxt != null && !messageTxt.isEmpty()) {
message.setText(messageTxt);
if (messageStr != null && !messageStr.isEmpty()) {
message.setText(messageStr);
} else {
message.setText(messageRes);
}
AppStyles.setTheme(root);
super.show();
}
@Override
public void show() {
// using show(int) and show(int, String) instead
}
@Override
public void dismiss() {
if (isShowing()) {
super.dismiss();
}
}
/**
* creates an alert dialog
*
* @param type Type of dialog to show
*/
public void show(int type) {
show(type, null);
}
/**
* creates an alert dialog
*
* @param type Type of dialog to show
* @param messageStr override default message text
*/
public void show(int type, @Nullable String messageStr) {
if (!isShowing()) {
this.type = type;
this.messageStr = messageStr;
super.show();
}
}

View File

@ -2,11 +2,11 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Patterns;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
@ -17,7 +17,7 @@ import com.kyleduo.switchbutton.SwitchButton;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.api.twitter.v1.Tokens;
import org.nuclearfog.twidda.backend.helper.ConnectionConfig;
import org.nuclearfog.twidda.backend.helper.update.ConnectionUpdate;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.config.Configuration;
@ -32,13 +32,19 @@ public class ConnectionDialog extends Dialog implements OnCheckedChangeListener,
private TextView apiLabel, v2Label, hostLabel;
private EditText host, api1, api2;
private ConnectionConfig connection;
private ConnectionUpdate connection;
/**
*
*/
public ConnectionDialog(Activity activity) {
super(activity, R.style.ConfirmDialog);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setCanceledOnTouchOutside(false);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_connection);
ViewGroup root = findViewById(R.id.dialog_connection_root);
Button confirm = findViewById(R.id.dialog_connection_confirm);
@ -53,9 +59,8 @@ public class ConnectionDialog extends Dialog implements OnCheckedChangeListener,
api1 = findViewById(R.id.dialog_connection_api1);
api2 = findViewById(R.id.dialog_connection_api2);
int width = (int) (activity.getResources().getDisplayMetrics().widthPixels * 0.9f);
getWindow().setLayout(width, ViewGroup.LayoutParams.WRAP_CONTENT);
AppStyles.setTheme(root);
enableApi.setOnCheckedChangeListener(this);
enableHost.setOnCheckedChangeListener(this);
confirm.setOnClickListener(this);
@ -63,6 +68,67 @@ public class ConnectionDialog extends Dialog implements OnCheckedChangeListener,
}
@Override
protected void onStart() {
super.onStart();
if (connection != null) {
switch (connection.getApiType()) {
case TWITTER2:
enableV2.setCheckedImmediately(true);
// fall through
case TWITTER1:
if (connection.useTokens()) {
enableApi.setCheckedImmediately(true);
api1.setVisibility(View.VISIBLE);
api2.setVisibility(View.VISIBLE);
api1.setText(connection.getOauthConsumerToken());
api2.setText(connection.getOauthTokenSecret());
} else {
enableApi.setCheckedImmediately(false);
api1.setVisibility(View.INVISIBLE);
api2.setVisibility(View.INVISIBLE);
}
enableApi.setVisibility(View.VISIBLE);
apiLabel.setVisibility(View.VISIBLE);
hostLabel.setVisibility(View.GONE);
enableHost.setVisibility(View.GONE);
host.setVisibility(View.GONE);
break;
case MASTODON:
if (connection.useHost()) {
enableHost.setCheckedImmediately(true);
host.setVisibility(View.VISIBLE);
host.setText(connection.getHostname());
} else {
enableHost.setCheckedImmediately(false);
host.setVisibility(View.INVISIBLE);
}
hostLabel.setVisibility(View.VISIBLE);
enableHost.setVisibility(View.VISIBLE);
enableApi.setVisibility(View.GONE);
apiLabel.setVisibility(View.GONE);
enableV2.setVisibility(View.GONE);
v2Label.setVisibility(View.GONE);
api1.setVisibility(View.GONE);
api2.setVisibility(View.GONE);
break;
}
}
// reset all error messages
if (api1.getError() != null) {
api1.setError(null);
}
if (api2.getError() != null) {
api2.setError(null);
}
if (host.getError() != null) {
host.setError(null);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_connection_confirm) {
@ -142,7 +208,7 @@ public class ConnectionDialog extends Dialog implements OnCheckedChangeListener,
@Override
public void show() {
// ignore method call, call instead show(int)
// using show(ConnectionConfig) instead
}
@ -153,60 +219,13 @@ public class ConnectionDialog extends Dialog implements OnCheckedChangeListener,
}
}
public void show(ConnectionConfig connection) {
switch (connection.getApiType()) {
case TWITTER2:
enableV2.setCheckedImmediately(true);
case TWITTER1:
if (connection.useTokens()) {
enableApi.setCheckedImmediately(true);
api1.setVisibility(View.VISIBLE);
api2.setVisibility(View.VISIBLE);
api1.setText(connection.getOauthConsumerToken());
api2.setText(connection.getOauthTokenSecret());
} else {
enableApi.setCheckedImmediately(false);
api1.setVisibility(View.INVISIBLE);
api2.setVisibility(View.INVISIBLE);
}
enableApi.setVisibility(View.VISIBLE);
apiLabel.setVisibility(View.VISIBLE);
hostLabel.setVisibility(View.GONE);
enableHost.setVisibility(View.GONE);
host.setVisibility(View.GONE);
break;
case MASTODON:
if (connection.useHost()) {
enableHost.setCheckedImmediately(true);
host.setVisibility(View.VISIBLE);
host.setText(connection.getHostname());
} else {
enableHost.setCheckedImmediately(false);
host.setVisibility(View.INVISIBLE);
}
hostLabel.setVisibility(View.VISIBLE);
enableHost.setVisibility(View.VISIBLE);
enableApi.setVisibility(View.GONE);
apiLabel.setVisibility(View.GONE);
enableV2.setVisibility(View.GONE);
v2Label.setVisibility(View.GONE);
api1.setVisibility(View.GONE);
api2.setVisibility(View.GONE);
break;
default:
return;
/**
*
*/
public void show(ConnectionUpdate connection) {
if (!isShowing()) {
this.connection = connection;
super.show();
}
// erase all error messages
if (api1.getError() != null)
api1.setError(null);
if (api2.getError() != null)
api2.setError(null);
if (host.getError() != null)
host.setError(null);
this.connection = connection;
super.show();
}
}

View File

@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@ -34,18 +35,24 @@ public class EmojiPicker extends BottomSheetDialog implements AsyncCallback<List
private OnEmojiSelectListener listener;
private EmojiAdapter adapter;
private EmojiLoader emojiLoader;
/**
* @param activity activity used to show emoji picker
* @param listener emoji add listener
*/
@SuppressWarnings("ConstantConditions")
public EmojiPicker(Activity activity, OnEmojiSelectListener listener) {
super(activity, R.style.EmojiPickerDialog);
GlobalSettings settings = GlobalSettings.get(activity);
emojiLoader = new EmojiLoader(activity.getApplicationContext());
adapter = new EmojiAdapter(this);
this.listener = listener;
}
@Override
@SuppressWarnings("ConstantConditions")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_emoji_picker);
ViewGroup root = findViewById(R.id.dialog_emoji_root);
RecyclerView listView = findViewById(R.id.dialog_emoji_list);
@ -53,16 +60,16 @@ public class EmojiPicker extends BottomSheetDialog implements AsyncCallback<List
// set round corner background annd color
getWindow().setBackgroundDrawable(new ColorDrawable(0));
GlobalSettings settings = GlobalSettings.get(getContext());
background.getBackground().setColorFilter(settings.getBackgroundColor(), PorterDuff.Mode.SRC_IN);
// set height
int height = Resources.getSystem().getDisplayMetrics().heightPixels / 4;
BottomSheetBehavior<View> mBehavior = BottomSheetBehavior.from((View) root.getParent());
mBehavior.setPeekHeight(height);
listView.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext(), LinearLayoutManager.VERTICAL, false));
listView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
listView.setAdapter(adapter);
EmojiLoader emojiLoader = new EmojiLoader(activity.getApplicationContext());
emojiLoader.execute(null, this);
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -39,9 +40,8 @@ public class FilterDialog extends Dialog implements OnClickListener, OnCheckedCh
private TextView title;
private StatusFilterAction filterAction;
private FilterDialogCallback callback;
private FilterUpdate update = new FilterUpdate();
private FilterUpdate update;
/**
*
@ -49,8 +49,15 @@ public class FilterDialog extends Dialog implements OnClickListener, OnCheckedCh
public FilterDialog(Activity activity, FilterDialogCallback callback) {
super(activity, R.style.FilterDialog);
this.callback = callback;
setContentView(R.layout.dialog_filter);
update = new FilterUpdate();
filterAction = new StatusFilterAction(activity);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_filter);
ViewGroup root = findViewById(R.id.dialog_filter_root);
Button btn_create = findViewById(R.id.dialog_filter_create);
sw_hide = findViewById(R.id.dialog_filter_switch_hide);
@ -63,7 +70,6 @@ public class FilterDialog extends Dialog implements OnClickListener, OnCheckedCh
txt_title = findViewById(R.id.dialog_filter_name);
txt_keywords = findViewById(R.id.dialog_filter_keywords);
filterAction = new StatusFilterAction(activity);
AppStyles.setTheme(root);
btn_create.setOnClickListener(this);
@ -76,15 +82,53 @@ public class FilterDialog extends Dialog implements OnClickListener, OnCheckedCh
}
@Override
protected void onStart() {
super.onStart();
if (update != null) {
// update an existing filter
if (update.getId() != 0L) {
title.setText(R.string.dialog_filter_update);
if (update.getKeywords().length > 0) {
StringBuilder keywordsStr = new StringBuilder();
for (String keyword : update.getKeywords()) {
keywordsStr.append(keyword).append('\n');
}
// delete last newline symbol
keywordsStr.deleteCharAt(keywordsStr.length() - 1);
txt_keywords.setText(keywordsStr);
} else {
txt_keywords.setText("");
}
}
// create new filter
else {
title.setText(R.string.dialog_filter_create);
txt_keywords.setText("");
}
sw_home.setCheckedImmediately(update.filterHomeSet());
sw_notification.setCheckedImmediately(update.filterNotificationSet());
sw_public.setCheckedImmediately(update.filterPublicSet());
sw_user.setCheckedImmediately(update.filterUserSet());
sw_thread.setCheckedImmediately(update.filterThreadSet());
sw_hide.setCheckedImmediately(update.getFilterAction() == Filter.ACTION_HIDE);
txt_title.setText(update.getTitle());
}
}
@Override
public void show() {
// using show(filter) instead
}
@Override
public void dismiss() {
filterAction.cancel();
super.dismiss();
if (isShowing()) {
filterAction.cancel();
super.dismiss();
}
}
@ -150,41 +194,12 @@ public class FilterDialog extends Dialog implements OnClickListener, OnCheckedCh
*/
public void show(@Nullable Filter filter) {
if (!isShowing()) {
super.show();
// update an existing filter
if (filter != null) {
update = new FilterUpdate(filter);
title.setText(R.string.dialog_filter_update);
if (filter.getKeywords().length > 0) {
StringBuilder keywordsStr = new StringBuilder();
for (Filter.Keyword keyword : filter.getKeywords()) {
if (keyword.isOneWord()) {
keywordsStr.append("\"").append(keyword.getKeyword()).append("\"\n");
} else {
keywordsStr.append(keyword.getKeyword()).append('\n');
}
}
// delete last newline symbol
keywordsStr.deleteCharAt(keywordsStr.length() - 1);
txt_keywords.setText(keywordsStr);
} else {
txt_keywords.setText("");
}
}
// create new filter
else {
} else {
update = new FilterUpdate();
title.setText(R.string.dialog_filter_create);
txt_keywords.setText("");
}
sw_home.setCheckedImmediately(update.filterHomeSet());
sw_notification.setCheckedImmediately(update.filterNotificationSet());
sw_public.setCheckedImmediately(update.filterPublicSet());
sw_user.setCheckedImmediately(update.filterUserSet());
sw_thread.setCheckedImmediately(update.filterThreadSet());
sw_hide.setCheckedImmediately(update.getFilterAction() == Filter.ACTION_HIDE);
txt_title.setText(update.getTitle());
super.show();
}
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.widget.TextView;
import org.nuclearfog.twidda.BuildConfig;
@ -19,6 +20,12 @@ public class InfoDialog extends Dialog {
*/
public InfoDialog(Activity activity) {
super(activity, R.style.AppInfoDialog);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_app_info);
TextView appInfo = findViewById(R.id.settings_app_info);

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.webkit.WebView;
import org.nuclearfog.twidda.R;
@ -13,13 +14,20 @@ import org.nuclearfog.twidda.R;
*/
public class LicenseDialog extends Dialog {
/**
*
*/
public LicenseDialog(Activity activity) {
super(activity, R.style.LicenseDialog);
WebView htmlViewer = new WebView(activity.getApplicationContext());
setContentView(htmlViewer);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView htmlViewer = new WebView(getContext());
htmlViewer.loadUrl("file:///android_asset/licenses.html");
setContentView(htmlViewer);
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@ -21,9 +22,19 @@ public class MetricsDialog extends Dialog {
private TextView views, profileClicks, linkClicks, quotes, videoViews;
private View linkIcon, quoteIcon, videoIcon;
private Metrics metrics;
/**
*
*/
public MetricsDialog(Activity activity) {
super(activity, R.style.MetricsDialog);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_metrics);
ViewGroup root = findViewById(R.id.dialog_metrics_root);
views = findViewById(R.id.dialog_metrics_views);
@ -39,24 +50,9 @@ public class MetricsDialog extends Dialog {
@Override
public void show() {
}
@Override
public void dismiss() {
if (isShowing()) {
super.dismiss();
}
}
/**
* show dialog window
*
* @param metrics status metrics to show
*/
public void show(Metrics metrics) {
if (!isShowing()) {
protected void onStart() {
super.onStart();
if (metrics != null) {
views.setText(StringUtils.NUMBER_FORMAT.format(metrics.getViews()));
profileClicks.setText(StringUtils.NUMBER_FORMAT.format(metrics.getProfileClicks()));
if (metrics.getLinkClicks() > 0) {
@ -83,6 +79,31 @@ public class MetricsDialog extends Dialog {
videoViews.setVisibility(View.GONE);
videoIcon.setVisibility(View.GONE);
}
}
}
@Override
public void show() {
// using show(Metrics) instead
}
@Override
public void dismiss() {
if (isShowing()) {
super.dismiss();
}
}
/**
* show dialog window
*
* @param metrics status metrics to show
*/
public void show(Metrics metrics) {
if (!isShowing()) {
this.metrics = metrics;
super.show();
}
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -32,14 +33,16 @@ import java.util.List;
public class PollDialog extends Dialog implements OnClickListener {
private EditOptionsAdapter optionAdapter;
private DropdownAdapter timeUnitAdapter;
private PollUpdateCallback callback;
private SwitchButton multiple_choice, hide_votes;
private Spinner timeUnitSelector;
private EditText durationInput;
private PollUpdateCallback callback;
private PollUpdate poll;
@Nullable
private Instance instance;
private PollUpdate poll;
/**
*
@ -47,6 +50,15 @@ public class PollDialog extends Dialog implements OnClickListener {
public PollDialog(Activity activity, PollUpdateCallback callback) {
super(activity, R.style.PollDialog);
this.callback = callback;
optionAdapter = new EditOptionsAdapter();
timeUnitAdapter = new DropdownAdapter(activity.getApplicationContext());
timeUnitAdapter.setItems(R.array.timeunits);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_poll);
ViewGroup root = findViewById(R.id.dialog_poll_root);
RecyclerView optionsList = findViewById(R.id.dialog_poll_option_list);
@ -57,13 +69,9 @@ public class PollDialog extends Dialog implements OnClickListener {
multiple_choice = findViewById(R.id.dialog_poll_mul_choice);
hide_votes = findViewById(R.id.dialog_poll_hide_total);
DropdownAdapter adapter = new DropdownAdapter(activity.getApplicationContext());
adapter.setItems(R.array.timeunits);
timeUnitSelector.setAdapter(adapter);
timeUnitSelector.setSelection(2);
optionAdapter = new EditOptionsAdapter();
optionsList.setAdapter(optionAdapter);
timeUnitSelector.setAdapter(timeUnitAdapter);
timeUnitSelector.setSelection(2);
AppStyles.setTheme(root);
confirm.setOnClickListener(this);
@ -71,6 +79,25 @@ public class PollDialog extends Dialog implements OnClickListener {
}
@Override
protected void onStart() {
super.onStart();
optionAdapter.replaceItems(poll.getOptions());
multiple_choice.setCheckedImmediately(poll.multipleChoiceEnabled());
hide_votes.setCheckedImmediately(poll.hideTotalVotes());
if (poll.getDuration() > 86400000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 86400000d)));
timeUnitSelector.setSelection(2);
} else if (poll.getDuration() > 3600000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 3600000d)));
timeUnitSelector.setSelection(1);
} else if (poll.getDuration() > 60000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 60000d)));
timeUnitSelector.setSelection(0);
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_poll_create) {
@ -91,7 +118,7 @@ public class PollDialog extends Dialog implements OnClickListener {
Toast.makeText(getContext(), R.string.error_duration_time_low, Toast.LENGTH_SHORT).show();
} else if (instance != null && duration > instance.getMaxPollDuration()) {
Toast.makeText(getContext(), R.string.error_duration_time_high, Toast.LENGTH_SHORT).show();
} else {
} else if (poll != null) {
List<String> options = optionAdapter.getItems();
for (String option : options) {
if (option.trim().isEmpty()) {
@ -114,6 +141,7 @@ public class PollDialog extends Dialog implements OnClickListener {
@Override
public void show() {
// using show(PollUpdate) instead
}
@ -132,19 +160,6 @@ public class PollDialog extends Dialog implements OnClickListener {
public void show(@Nullable PollUpdate poll) {
if (!isShowing()) {
if (poll != null) {
optionAdapter.replaceItems(poll.getOptions());
multiple_choice.setCheckedImmediately(poll.multipleChoiceEnabled());
hide_votes.setCheckedImmediately(poll.hideTotalVotes());
if (poll.getDuration() > 86400000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 86400000d)));
timeUnitSelector.setSelection(2);
} else if (poll.getDuration() > 3600000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 3600000d)));
timeUnitSelector.setSelection(1);
} else if (poll.getDuration() > 60000L) {
durationInput.setText(Long.toString(Math.round(poll.getDuration() / 60000d)));
timeUnitSelector.setSelection(0);
}
this.poll = poll;
} else {
this.poll = new PollUpdate();

View File

@ -2,9 +2,9 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageView;
import android.widget.ProgressBar;
@ -24,26 +24,30 @@ public class ProgressDialog extends Dialog implements OnClickListener {
@Nullable
private OnProgressStopListener listener;
private ImageView cancel;
/**
*
*/
public ProgressDialog(Activity activity) {
public ProgressDialog(Activity activity, @Nullable OnProgressStopListener listener) {
super(activity, R.style.LoadingDialog);
// setup dialog
requestWindowFeature(Window.FEATURE_NO_TITLE);
setCanceledOnTouchOutside(false);
setCancelable(false);
this.listener = listener;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.item_load);
cancel = findViewById(R.id.kill_button);
ProgressBar circle = findViewById(R.id.progress_item);
ImageView cancel = findViewById(R.id.kill_button);
GlobalSettings settings = GlobalSettings.get(activity);
GlobalSettings settings = GlobalSettings.get(getContext());
AppStyles.setProgressColor(circle, settings.getHighlightColor());
AppStyles.setDrawableColor(cancel, settings.getIconColor());
if (listener != null) {
cancel.setVisibility(View.VISIBLE);
} else {
cancel.setVisibility(View.GONE);
}
cancel.setOnClickListener(this);
}
@ -72,14 +76,6 @@ public class ProgressDialog extends Dialog implements OnClickListener {
}
}
/**
* enables cancel button and adds a listener
*/
public void addOnProgressStopListener(OnProgressStopListener listener) {
cancel.setVisibility(View.VISIBLE);
this.listener = listener;
}
/**
* listener for progress
*/

View File

@ -0,0 +1,43 @@
package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import com.kyleduo.switchbutton.SwitchButton;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AppStyles;
public class ReportDialog extends Dialog {
private TextView textTitle;
private SwitchButton switchForward;
private EditText editDescription;
/**
*
*/
public ReportDialog(Activity activity) {
super(activity, R.style.ReportDialog);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_report);
ViewGroup root = findViewById(R.id.dialog_report_root);
textTitle = findViewById(R.id.dialog_report_title);
switchForward = findViewById(R.id.dialog_report_switch_forward);
editDescription = findViewById(R.id.dialog_report_description);
AppStyles.setTheme(root);
}
@Override
public void show() {
}
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@ -32,8 +33,8 @@ public class StatusPreferenceDialog extends Dialog implements OnCheckedChangeLis
private Spinner visibilitySelector;
private DropdownAdapter visibility_adapter, language_adapter;
private StatusUpdate statusUpdate;
private String[] languageCodes;
/**
@ -42,24 +43,8 @@ public class StatusPreferenceDialog extends Dialog implements OnCheckedChangeLis
public StatusPreferenceDialog(Activity activity, StatusUpdate statusUpdate) {
super(activity, R.style.StatusDialog);
this.statusUpdate = statusUpdate;
setContentView(R.layout.dialog_status);
ViewGroup rootView = findViewById(R.id.dialog_status_root);
SwitchButton sensitiveCheck = findViewById(R.id.dialog_status_sensitive);
SwitchButton spoilerCheck = findViewById(R.id.dialog_status_spoiler);
View statusVisibility = findViewById(R.id.dialog_status_visibility_container);
View statusSpoiler = findViewById(R.id.dialog_status_spoiler_container);
Spinner languageSelector = findViewById(R.id.dialog_status_language);
visibilitySelector = findViewById(R.id.dialog_status_visibility);
GlobalSettings settings = GlobalSettings.get(activity.getApplicationContext());
AppStyles.setTheme(rootView);
DropdownAdapter visibility_adapter = new DropdownAdapter(activity.getApplicationContext());
DropdownAdapter language_adapter = new DropdownAdapter(activity.getApplicationContext());
languageSelector.setAdapter(language_adapter);
languageSelector.setSelected(false);
visibilitySelector.setAdapter(visibility_adapter);
visibilitySelector.setSelection(0, false);
visibilitySelector.setSelected(false);
visibility_adapter = new DropdownAdapter(activity.getApplicationContext());
language_adapter = new DropdownAdapter(activity.getApplicationContext());
// initialize language selector
Map<String, String> languages = new TreeMap<>();
@ -69,8 +54,29 @@ public class StatusPreferenceDialog extends Dialog implements OnCheckedChangeLis
languages.put(locale.getDisplayLanguage(), locale.getLanguage());
}
languageCodes = languages.values().toArray(new String[0]);
String[] languageNames = languages.keySet().toArray(new String[0]);
language_adapter.setItems(languageNames);
language_adapter.setItems(languages.keySet().toArray(new String[0]));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_status);
ViewGroup rootView = findViewById(R.id.dialog_status_root);
SwitchButton sensitiveCheck = findViewById(R.id.dialog_status_sensitive);
SwitchButton spoilerCheck = findViewById(R.id.dialog_status_spoiler);
View statusVisibility = findViewById(R.id.dialog_status_visibility_container);
View statusSpoiler = findViewById(R.id.dialog_status_spoiler_container);
Spinner languageSelector = findViewById(R.id.dialog_status_language);
visibilitySelector = findViewById(R.id.dialog_status_visibility);
GlobalSettings settings = GlobalSettings.get(getContext());
AppStyles.setTheme(rootView);
languageSelector.setAdapter(language_adapter);
languageSelector.setSelected(false);
visibilitySelector.setAdapter(visibility_adapter);
visibilitySelector.setSelection(0, false);
visibilitySelector.setSelected(false);
// enable/disable functions
if (!settings.getLogin().getConfiguration().statusVisibilitySupported()) {
@ -88,25 +94,25 @@ public class StatusPreferenceDialog extends Dialog implements OnCheckedChangeLis
@Override
public void show() {
switch (statusUpdate.getVisibility()) {
case Status.VISIBLE_PUBLIC:
visibilitySelector.setSelection(0, false);
break;
case Status.VISIBLE_PRIVATE:
visibilitySelector.setSelection(1, false);
break;
case Status.VISIBLE_DIRECT:
visibilitySelector.setSelection(2, false);
break;
case Status.VISIBLE_UNLISTED:
visibilitySelector.setSelection(3, false);
break;
protected void onStart() {
super.onStart();
if (statusUpdate.getVisibility() == Status.VISIBLE_PUBLIC) {
visibilitySelector.setSelection(0, false);
} else if (statusUpdate.getVisibility() == Status.VISIBLE_PRIVATE) {
visibilitySelector.setSelection(1, false);
} else if (statusUpdate.getVisibility() == Status.VISIBLE_DIRECT) {
visibilitySelector.setSelection(2, false);
} else if (statusUpdate.getVisibility() == Status.VISIBLE_UNLISTED) {
visibilitySelector.setSelection(3, false);
}
}
@Override
public void show() {
if (!isShowing()) {
super.show();
}
super.show();
}

View File

@ -2,6 +2,7 @@ package org.nuclearfog.twidda.ui.dialogs;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@ -39,7 +40,8 @@ public class WebPushDialog extends Dialog implements OnCheckedChangeListener, On
private Spinner policySelector;
private GlobalSettings settings;
private PushUpdater updater;
private PushUpdater pushUpdater;
private DropdownAdapter adapter;
private PushUpdate update;
@ -48,6 +50,16 @@ public class WebPushDialog extends Dialog implements OnCheckedChangeListener, On
*/
public WebPushDialog(Activity activity) {
super(activity, R.style.WebPushDialog);
adapter = new DropdownAdapter(activity.getApplicationContext());
settings = GlobalSettings.get(getContext());
pushUpdater = new PushUpdater(getContext());
update = new PushUpdate(settings.getWebPush());
adapter.setItems(R.array.push_policy);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.dialog_push);
ViewGroup root = findViewById(R.id.dialog_push_root);
Button apply_changes = findViewById(R.id.dialog_push_apply);
@ -60,14 +72,10 @@ public class WebPushDialog extends Dialog implements OnCheckedChangeListener, On
status_new = findViewById(R.id.dialog_push_new_status);
status_edit = findViewById(R.id.dialog_push_edit_status);
policySelector = findViewById(R.id.dialog_push_policy);
settings = GlobalSettings.get(activity.getApplicationContext());
updater = new PushUpdater(activity.getApplicationContext());
DropdownAdapter adapter = new DropdownAdapter(activity.getApplicationContext());
adapter.setItems(R.array.push_policy);
policySelector.setAdapter(adapter);
AppStyles.setTheme(root);
policySelector.setAdapter(adapter);
mention.setOnCheckedChangeListener(this);
repost.setOnCheckedChangeListener(this);
favorite.setOnCheckedChangeListener(this);
@ -81,25 +89,30 @@ public class WebPushDialog extends Dialog implements OnCheckedChangeListener, On
}
@Override
protected void onStart() {
super.onStart();
mention.setCheckedImmediately(update.mentionsEnabled());
repost.setCheckedImmediately(update.repostEnabled());
favorite.setCheckedImmediately(update.favoriteEnabled());
poll.setCheckedImmediately(update.pollEnabled());
follow.setCheckedImmediately(update.followEnabled());
request.setCheckedImmediately(update.followRequestEnabled());
status_new.setCheckedImmediately(update.statusPostEnabled());
status_edit.setCheckedImmediately(update.statusEditEnabled());
if (update.getPolicy() == WebPush.POLICY_ALL) {
policySelector.setSelection(0);
} else if (update.getPolicy() == WebPush.POLICY_FOLLOWING) {
policySelector.setSelection(1);
} else if (update.getPolicy() == WebPush.POLICY_FOLLOWER) {
policySelector.setSelection(2);
}
}
@Override
public void show() {
if (!isShowing()) {
update = new PushUpdate(settings.getWebPush());
mention.setCheckedImmediately(update.mentionsEnabled());
repost.setCheckedImmediately(update.repostEnabled());
favorite.setCheckedImmediately(update.favoriteEnabled());
poll.setCheckedImmediately(update.pollEnabled());
follow.setCheckedImmediately(update.followEnabled());
request.setCheckedImmediately(update.followRequestEnabled());
status_new.setCheckedImmediately(update.statusPostEnabled());
status_edit.setCheckedImmediately(update.statusEditEnabled());
if (update.getPolicy() == WebPush.POLICY_ALL) {
policySelector.setSelection(0);
} else if (update.getPolicy() == WebPush.POLICY_FOLLOWING) {
policySelector.setSelection(1);
} else if (update.getPolicy() == WebPush.POLICY_FOLLOWER) {
policySelector.setSelection(2);
}
super.show();
}
}
@ -116,12 +129,13 @@ public class WebPushDialog extends Dialog implements OnCheckedChangeListener, On
@Override
public void onClick(View v) {
if (v.getId() == R.id.dialog_push_apply) {
if (updater.isIdle()) {
if (pushUpdater.isIdle()) {
// fix: setting host url if empty
if (update.getHost().isEmpty()) {
update.setHost(settings.getWebPush().getHost());
}
updater.execute(update, this);
pushUpdater.execute(update, this);
Toast.makeText(getContext(), R.string.info_webpush_update_progress, Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -198,6 +198,7 @@
android:layout_margin="@dimen/dialog_filter_margin_items_layout"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dialog_filter_keywords"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/dialog_filter_switch_thread_label" />
<TextView

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_report_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/dialog_report_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:lines="1"
android:textSize="@dimen/dialog_report_textsize_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<Spinner
android:id="@+id/dialog_report_category"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dialog_report_title"
app:layout_constraintEnd_toEndOf="parent" />
<EditText
android:id="@+id/dialog_report_description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:lines="5"
android:inputType="textMultiLine"
android:fadeScrollbars="false"
android:scrollbars="vertical"
android:scrollbarStyle="outsideInset"
android:hint="@string/dialog_report_hint_description"
android:background="@android:color/transparent"
android:gravity="top"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dialog_report_category"
app:layout_constraintEnd_toEndOf="parent" />
<com.kyleduo.switchbutton.SwitchButton
android:id="@+id/dialog_report_switch_forward"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/dialog_report_description"/>
<TextView
android:id="@+id/dialog_report_switch_forward_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/dialog_report_description_forward"
android:textSize="@dimen/dialog_report_textsize_label"
android:lines="1"
app:layout_constraintStart_toEndOf="@id/dialog_report_switch_forward"
app:layout_constraintTop_toTopOf="@id/dialog_report_switch_forward"
app:layout_constraintBottom_toBottomOf="@id/dialog_report_switch_forward"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -347,4 +347,8 @@
<dimen name="dialog_filter_textsize_label">11sp</dimen>
<dimen name="dialog_filter_margin_items_layout">4dp</dimen>
<!--dimens of dialog_report.xml-->
<dimen name="dialog_report_textsize_title">22sp</dimen>
<dimen name="dialog_report_textsize_label">12sp</dimen>
</resources>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<!--app/repository dependent strings-->
<string name="app_name" translatable="false">Shitter</string>
<string name="app_name_api" translatable="false">SH1TT3R</string>
@ -79,6 +79,7 @@
<string name="info_domain_removed">domain removed from the list</string>
<string name="info_hashtag_followed">hashtag followed</string>
<string name="info_domain_blocked">domain blocked!</string>
<string name="info_webpush_update_progress">updating push configuration</string>
<string name="info_webpush_update">Push configuration updated</string>
<string name="info_filter_created">Filter created</string>
<string name="info_filter_updated">Filter updated</string>
@ -264,6 +265,10 @@
<string name="settings_key2_hint">Consumer secret</string>
<string name="dialog_connection_custom_host">use custom hostname</string>
<string name="dialog_connection_apply">apply changes</string>
<string name="dialog_report_status_title">Report post</string>
<string name="dialog_report_user_title">Report 1$s</string>
<string name="dialog_report_hint_description">additional description</string>
<string name="dialog_report_description_forward">forward report to source instance</string>
<string name="confirm_mute">mute user?</string>
<string name="item_list_pb_desc">Profile of the list owner</string>
<string name="list_appbar">Lists</string>
@ -363,9 +368,9 @@
<string name="description_filter_public_timeline">Public timeline filter enabled</string>
<string name="description_filter_thread">Thread filter enabled</string>
<string name="description_filter_user_timeline">User timeline filter enabled</string>
<string name="dialog_filter_create">create a filter</string>
<string name="dialog_filter_create">create filter</string>
<string name="dialog_filter_name_hint">enter filter name</string>
<string name="dialog_filter_update">update a filter</string>
<string name="dialog_filter_update">update filter</string>
<string name="dialog_filter_button_apply">apply</string>
<string name="dialog_filter_apply">apply filter for</string>
<string name="dialog_filter_home">Home timeline</string>

View File

@ -27,6 +27,7 @@
</style>
<style name="LicenseDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowMinWidthMinor">80%</item>
<item name="android:background">@android:color/white</item>
<item name="android:textColor">@android:color/black</item>
<item name="android:textSize">@dimen/license_textsize</item>
@ -36,11 +37,16 @@
<style name="LoadingDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="ConfirmDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowMinWidthMinor">80%</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:textSize">@dimen/dialog_connection_textsizte_normal</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
@ -74,6 +80,11 @@
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
<style name="ReportDialog" parent="Theme.AppCompat.Dialog">
<item name="android:windowMinWidthMinor">90%</item>
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
<style name="EmojiPickerDialog" parent="Theme.Design.Light.BottomSheetDialog">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>