removed unnecessary code, bug fix, layout fix

This commit is contained in:
nuclearfog 2020-05-26 16:24:51 +02:00
parent 5229d05ef1
commit 6ff138e971
No known key found for this signature in database
GPG Key ID: ED35E22099354A64
25 changed files with 369 additions and 380 deletions

View File

@ -19,8 +19,8 @@
<option name="values">
<map>
<entry key="assetSourceType" value="FILE" />
<entry key="outputName" value="list" />
<entry key="sourceFile" value="$USER_HOME$/Dokumente/Rest/Entypo SVG/list.svg" />
<entry key="outputName" value="images" />
<entry key="sourceFile" value="$USER_HOME$/Dokumente/Rest/Entypo SVG/images.svg" />
</map>
</option>
</PersistentState>

View File

@ -8,7 +8,7 @@ android {
applicationId 'org.nuclearfog.twidda'
minSdkVersion 16
targetSdkVersion 29
versionCode 14
versionCode 15
versionName '1.7.7'
vectorDrawables.useSupportLibrary true
}

View File

@ -37,7 +37,6 @@ import org.nuclearfog.twidda.backend.TweetLoader.Action;
import org.nuclearfog.twidda.backend.engine.EngineException;
import org.nuclearfog.twidda.backend.helper.ErrorHandler;
import org.nuclearfog.twidda.backend.helper.FontTool;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.items.Tweet;
import org.nuclearfog.twidda.backend.items.TwitterUser;
import org.nuclearfog.twidda.database.GlobalSettings;
@ -48,6 +47,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_SHORT;
import static org.nuclearfog.twidda.activity.MediaViewer.KEY_MEDIA_LINK;
@ -61,6 +61,8 @@ import static org.nuclearfog.twidda.activity.TweetPopup.KEY_TWEETPOPUP_REPLYID;
import static org.nuclearfog.twidda.activity.UserDetail.KEY_USERDETAIL_ID;
import static org.nuclearfog.twidda.activity.UserDetail.KEY_USERDETAIL_MODE;
import static org.nuclearfog.twidda.activity.UserDetail.USERLIST_RETWEETS;
import static org.nuclearfog.twidda.backend.engine.EngineException.ErrorType.NOT_AUTHORIZED;
import static org.nuclearfog.twidda.backend.engine.EngineException.ErrorType.RESOURCE_NOT_FOUND;
import static org.nuclearfog.twidda.fragment.TweetFragment.RETURN_TWEET_CHANGED;
@ -74,10 +76,10 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
private TweetLoader statusAsync;
private GlobalSettings settings;
private View header, footer, videoButton, imageButton;
private View header, footer;
private TextView tweet_api, tweetDate, tweetText, scrName, usrName, tweetLocName;
private Button rtwButton, favButton, replyName, tweetLocGPS;
private ImageView profile_img;
private ImageView profile_img, mediaButton;
@Nullable
private Tweet tweet;
@ -105,8 +107,7 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
tweet_api = findViewById(R.id.used_api);
tweetLocName = findViewById(R.id.tweet_location_name);
tweetLocGPS = findViewById(R.id.tweet_location_coordinate);
imageButton = findViewById(R.id.image_attach);
videoButton = findViewById(R.id.video_attach);
mediaButton = findViewById(R.id.tweet_media_attach);
Bundle param = getIntent().getExtras();
Uri link = getIntent().getData();
@ -137,8 +138,7 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
favButton.setOnLongClickListener(this);
profile_img.setOnClickListener(this);
tweetLocGPS.setOnClickListener(this);
videoButton.setOnClickListener(this);
imageButton.setOnClickListener(this);
mediaButton.setOnClickListener(this);
}
@ -265,25 +265,23 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
break;
}
case R.id.image_attach:
case R.id.tweet_media_attach:
if (tweet != null) {
Intent mediaIntent = new Intent(getApplicationContext(), MediaViewer.class);
Intent mediaIntent = new Intent(this, MediaViewer.class);
mediaIntent.putExtra(KEY_MEDIA_LINK, tweet.getMediaLinks());
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_IMAGE);
startActivity(mediaIntent);
}
break;
switch (tweet.getMediaType()) {
case IMAGE:
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_IMAGE);
break;
case R.id.video_attach:
if (tweet != null) {
String[] links = tweet.getMediaLinks();
StringTools.FileType ext = StringTools.getFileType(links[0]);
Intent mediaIntent = new Intent(getApplicationContext(), MediaViewer.class);
if (ext == StringTools.FileType.VIDEO)
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_ANGIF);
else
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_VIDEO);
mediaIntent.putExtra(KEY_MEDIA_LINK, links);
case VIDEO:
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_VIDEO);
break;
case GIF:
mediaIntent.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_ANGIF);
break;
}
startActivity(mediaIntent);
}
break;
@ -371,13 +369,25 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
replyName.append(tweet.getReplyName());
replyName.setVisibility(VISIBLE);
}
if (tweet.hasMedia()) {
String[] links = tweet.getMediaLinks();
StringTools.FileType ext = StringTools.getFileType(links[0]);
if (ext == StringTools.FileType.IMAGE)
imageButton.setVisibility(VISIBLE);
else
videoButton.setVisibility(VISIBLE);
switch (tweet.getMediaType()) {
case IMAGE:
mediaButton.setVisibility(VISIBLE);
mediaButton.setImageResource(R.drawable.image);
break;
case VIDEO:
mediaButton.setVisibility(VISIBLE);
mediaButton.setImageResource(R.drawable.video);
break;
case GIF:
mediaButton.setVisibility(VISIBLE);
mediaButton.setImageResource(R.drawable.images);
break;
default:
mediaButton.setVisibility(GONE);
break;
}
if (settings.getImageLoad()) {
String pbLink = author.getImageLink();
@ -433,8 +443,12 @@ public class TweetDetail extends AppCompatActivity implements OnClickListener,
* @param error Engine Exception
*/
public void onError(EngineException error) {
boolean hardFailure = ErrorHandler.handleFailure(this, error);
if (tweet == null || hardFailure) {
ErrorHandler.handleFailure(this, error);
EngineException.ErrorType errorType = error.getErrorType();
if (errorType == RESOURCE_NOT_FOUND || errorType == NOT_AUTHORIZED) {
setResult(RETURN_TWEET_CHANGED);
finish();
} else if (tweet == null) {
finish();
}
}

View File

@ -29,8 +29,6 @@ import org.nuclearfog.twidda.backend.TweetUploader;
import org.nuclearfog.twidda.backend.engine.EngineException;
import org.nuclearfog.twidda.backend.helper.ErrorHandler;
import org.nuclearfog.twidda.backend.helper.FontTool;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.helper.StringTools.FileType;
import org.nuclearfog.twidda.backend.items.TweetHolder;
import org.nuclearfog.twidda.database.GlobalSettings;
@ -60,18 +58,20 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
public static final String KEY_TWEETPOPUP_REPLYID = "tweet_replyID";
public static final String KEY_TWEETPOPUP_PREFIX = "tweet_prefix";
private static final int NONE = 0;
private static final int IMAGE = 1;
private static final int VIDEO = 2;
private static final int GIF = 3;
private enum MediaType {
NONE,
GIF,
IMAGE,
VIDEO,
}
private static final String[] PERM_STORAGE = {READ_EXTERNAL_STORAGE};
private static final String[] PERM_LOCATION = {ACCESS_FINE_LOCATION};
private static final String[] GET_MEDIA = {MediaStore.Images.Media.DATA};
private static final String TYPE_IMAGE = "image/*";
private static final String TYPE_VIDEO = "video/*";
private static final int PICK_MEDIA = 3;
private static final int CHECK_PERM = 4;
private static final int REQ_PICK_MEDIA = 3;
private static final int REQ_CHECK_PERM = 4;
private static final int MAX_IMAGES = 4;
@Nullable
@ -85,7 +85,8 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
private EditText tweetText;
private String addition = "";
private long inReplyId = 0;
private int mode = NONE;
private MediaType selectedFormat = MediaType.NONE;
@Override
protected void onCreate(Bundle b) {
@ -150,42 +151,46 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
@Override
protected void onActivityResult(int reqCode, int returnCode, Intent intent) {
super.onActivityResult(reqCode, returnCode, intent);
if (reqCode == PICK_MEDIA && returnCode == RESULT_OK) {
if (reqCode == REQ_PICK_MEDIA && returnCode == RESULT_OK) {
if (intent != null && intent.getData() != null) {
Cursor cursor = getContentResolver().query(intent.getData(), GET_MEDIA, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
int index = cursor.getColumnIndex(GET_MEDIA[0]);
String path = cursor.getString(index);
FileType type = StringTools.getFileType(path);
switch (type) {
case IMAGE:
if (mode == NONE)
mode = IMAGE;
if (mediaPath.size() < MAX_IMAGES && mode == IMAGE) {
mediaPath.add(path);
previewBtn.setVisibility(VISIBLE);
String count = Integer.toString(mediaPath.size());
imgCount.setText(count);
if (mediaPath.size() == MAX_IMAGES)
mediaBtn.setVisibility(INVISIBLE);
String extension = path.substring(path.lastIndexOf('.') + 1).toLowerCase();
switch (extension) {
case "jpg":
case "jpeg":
case "png":
if (selectedFormat == MediaType.NONE)
selectedFormat = MediaType.IMAGE;
if (selectedFormat == MediaType.IMAGE) {
if (mediaPath.size() < MAX_IMAGES) {
mediaPath.add(path);
previewBtn.setVisibility(VISIBLE);
String count = Integer.toString(mediaPath.size());
imgCount.setText(count);
if (mediaPath.size() == MAX_IMAGES)
mediaBtn.setVisibility(INVISIBLE);
}
} else {
Toast.makeText(this, R.string.info_cant_add_video, LENGTH_SHORT).show();
}
break;
case ANGIF:
if (mode == NONE)
mode = GIF;
if (mode == GIF) {
case "gif":
if (selectedFormat == MediaType.NONE) {
selectedFormat = MediaType.GIF;
mediaPath.add(path);
previewBtn.setVisibility(VISIBLE);
mediaBtn.setVisibility(INVISIBLE);
}
break;
case VIDEO:
if (mode == NONE)
mode = VIDEO;
if (mode == VIDEO) {
case "mp4":
case "3gp":
if (selectedFormat == MediaType.NONE) {
selectedFormat = MediaType.VIDEO;
mediaPath.add(path);
previewBtn.setVisibility(VISIBLE);
mediaBtn.setVisibility(INVISIBLE);
@ -205,7 +210,7 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == CHECK_PERM && permissions.length > 0 && grantResults.length > 0) {
if (requestCode == REQ_CHECK_PERM && permissions.length > 0 && grantResults.length > 0) {
switch (permissions[0]) {
case READ_EXTERNAL_STORAGE:
if (grantResults[0] == PERMISSION_GRANTED)
@ -230,8 +235,10 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
Toast.makeText(this, R.string.error_empty_tweet, LENGTH_SHORT).show();
} else if (locationProg.getVisibility() == INVISIBLE) {
TweetHolder tweet = new TweetHolder(tweetStr, inReplyId);
if (!mediaPath.isEmpty())
tweet.addMedia(mediaPath.toArray(new String[0]));
if (selectedFormat == MediaType.IMAGE || selectedFormat == MediaType.GIF)
tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.IMAGE);
else if (selectedFormat == MediaType.VIDEO)
tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.VIDEO);
if (location != null)
tweet.addLocation(location);
uploaderAsync = new TweetUploader(this, tweet);
@ -251,7 +258,7 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
Intent image = new Intent(this, MediaViewer.class);
image.putExtra(KEY_MEDIA_LINK, mediaPath.toArray(new String[0]));
switch (mode) {
switch (selectedFormat) {
case IMAGE:
image.putExtra(KEY_MEDIA_TYPE, MEDIAVIEWER_IMG_STORAGE);
startActivity(image);
@ -288,17 +295,6 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
locationBtn.setVisibility(VISIBLE);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
if (location == null)
@ -307,6 +303,15 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
locationBtn.setVisibility(VISIBLE);
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onDismiss(DialogInterface dialog) {
if (uploaderAsync != null && uploaderAsync.getStatus() == RUNNING) {
@ -382,26 +387,20 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
boolean accessGranted = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(PERM_STORAGE[0]) != PERMISSION_GRANTED) {
requestPermissions(PERM_STORAGE, CHECK_PERM);
requestPermissions(PERM_STORAGE, REQ_CHECK_PERM);
accessGranted = false;
}
}
if (accessGranted) {
if (mode == NONE) {
Intent mediaIntent = new Intent(ACTION_PICK);
mediaIntent.setDataAndType(EXTERNAL_CONTENT_URI, TYPE_IMAGE + TYPE_VIDEO);
if (mediaIntent.resolveActivity(getPackageManager()) != null)
startActivityForResult(mediaIntent, PICK_MEDIA);
else
Toast.makeText(getApplicationContext(), R.string.error_no_media_app, LENGTH_SHORT).show();
} else if (mode == IMAGE) {
Intent imageIntent = new Intent(ACTION_PICK);
imageIntent.setDataAndType(EXTERNAL_CONTENT_URI, TYPE_IMAGE);
if (imageIntent.resolveActivity(getPackageManager()) != null)
startActivityForResult(imageIntent, PICK_MEDIA);
else
Toast.makeText(getApplicationContext(), R.string.error_no_media_app, LENGTH_SHORT).show();
}
Intent mediaSelect = new Intent(ACTION_PICK);
if (selectedFormat == MediaType.IMAGE)
mediaSelect.setDataAndType(EXTERNAL_CONTENT_URI, TYPE_IMAGE);
else
mediaSelect.setDataAndType(EXTERNAL_CONTENT_URI, TYPE_IMAGE + TYPE_VIDEO);
if (mediaSelect.resolveActivity(getPackageManager()) != null)
startActivityForResult(mediaSelect, REQ_PICK_MEDIA);
else
Toast.makeText(getApplicationContext(), R.string.error_no_media_app, LENGTH_SHORT).show();
}
}
@ -413,14 +412,14 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
boolean accessGranted = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(PERM_LOCATION[0]) != PERMISSION_GRANTED) {
requestPermissions(PERM_LOCATION, CHECK_PERM);
requestPermissions(PERM_LOCATION, REQ_CHECK_PERM);
accessGranted = false;
}
}
if (accessGranted) {
if (mLocation != null && mLocation.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, R.string.info_get_location, LENGTH_SHORT).show();
mLocation.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, null);
Toast.makeText(this, R.string.info_get_location, LENGTH_SHORT).show();
locationProg.setVisibility(VISIBLE);
locationBtn.setVisibility(INVISIBLE);
} else {

View File

@ -17,14 +17,15 @@ import com.squareup.picasso.Picasso;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.helper.FontTool;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.items.TwitterList;
import org.nuclearfog.twidda.backend.items.TwitterUser;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.lang.ref.WeakReference;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static android.view.View.GONE;
@ -158,7 +159,7 @@ public class ListAdapter extends Adapter<ListAdapter.ListHolder> {
vh.title.setText(item.getTitle());
vh.ownername.setText(owner.getScreenname());
vh.description.setText(item.getDescription());
vh.createdAt.setText(StringTools.getTimeString(item.getCreatedAt()));
vh.createdAt.setText(getTimeString(item.getCreatedAt()));
vh.memberCount.setText(formatter.format(item.getMemberCount()));
vh.subscriberCount.setText(formatter.format(item.getSubscriberCount()));
if (settings.getImageLoad()) {
@ -185,6 +186,29 @@ public class ListAdapter extends Adapter<ListAdapter.ListHolder> {
}
private String getTimeString(long time) {
long diff = new Date().getTime() - time;
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
if (weeks > 4) {
Date tweetDate = new Date(time);
return SimpleDateFormat.getDateInstance().format(tweetDate);
}
if (weeks > 0)
return weeks + " w";
if (days > 0)
return days + " d";
if (hours > 0)
return hours + " h";
if (minutes > 0)
return minutes + " m";
return seconds + " s";
}
static class ListHolder extends ViewHolder {
final ImageView pb_image;
final Button followList, deleteList;

View File

@ -20,13 +20,14 @@ import org.nuclearfog.tag.Tagger;
import org.nuclearfog.tag.Tagger.OnTagClickListener;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.helper.FontTool;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.items.Message;
import org.nuclearfog.twidda.backend.items.TwitterUser;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
@ -134,7 +135,7 @@ public class MessageAdapter extends Adapter<MessageAdapter.MessageHolder> {
vh.message.setText(text);
vh.username.setText(sender.getUsername());
vh.screenname.setText(sender.getScreenname());
vh.createdAt.setText(StringTools.getTimeString(message.getTime()));
vh.createdAt.setText(getTimeString(message.getTime()));
vh.receivername.setText(message.getReceiver().getScreenname());
if (sender.isVerified())
@ -154,6 +155,29 @@ public class MessageAdapter extends Adapter<MessageAdapter.MessageHolder> {
}
private String getTimeString(long time) {
long diff = new Date().getTime() - time;
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
if (weeks > 4) {
Date tweetDate = new Date(time);
return SimpleDateFormat.getDateInstance().format(tweetDate);
}
if (weeks > 0)
return weeks + " w";
if (days > 0)
return days + " d";
if (hours > 0)
return hours + " h";
if (minutes > 0)
return minutes + " m";
return seconds + " s";
}
static class MessageHolder extends ViewHolder {
final ImageView profile_img;
final TextView username;

View File

@ -18,14 +18,15 @@ import com.squareup.picasso.Picasso;
import org.nuclearfog.tag.Tagger;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.helper.FontTool;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.items.Tweet;
import org.nuclearfog.twidda.backend.items.TwitterUser;
import org.nuclearfog.twidda.database.GlobalSettings;
import java.lang.ref.WeakReference;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
@ -131,7 +132,7 @@ public class TweetAdapter extends Adapter<TweetAdapter.ItemHolder> {
vh.screenname.setText(user.getScreenname());
vh.retweet.setText(formatter.format(tweet.getRetweetCount()));
vh.favorite.setText(formatter.format(tweet.getFavorCount()));
vh.time.setText(StringTools.getTimeString(tweet.getTime()));
vh.time.setText(getTimeString(tweet.getTime()));
if (tweet.retweeted())
vh.retweet.setCompoundDrawablesWithIntrinsicBounds(R.drawable.retweet_enabled, 0, 0, 0);
else
@ -158,6 +159,28 @@ public class TweetAdapter extends Adapter<TweetAdapter.ItemHolder> {
vh.profile.setImageResource(0);
}
private String getTimeString(long time) {
long diff = new Date().getTime() - time;
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
if (weeks > 4) {
Date tweetDate = new Date(time);
return SimpleDateFormat.getDateInstance().format(tweetDate);
}
if (weeks > 0)
return weeks + " w";
if (days > 0)
return days + " d";
if (hours > 0)
return hours + " h";
if (minutes > 0)
return minutes + " m";
return seconds + " s";
}
static class ItemHolder extends ViewHolder {
final TextView username, screenname, tweet, retweet;
final TextView favorite, retweeter, time;

View File

@ -76,13 +76,13 @@ public class MessageListLoader extends AsyncTask<Long, Void, List<Message>> {
messageId = param[0];
id = messageId;
mTwitter.deleteMessage(messageId);
db.deleteDm(messageId);
db.deleteMessage(messageId);
break;
}
} catch (EngineException twException) {
this.twException = twException;
if (twException.getErrorType() == RESOURCE_NOT_FOUND)
db.deleteDm(messageId);
db.deleteMessage(messageId);
} catch (Exception exception) {
exception.printStackTrace();
}

View File

@ -114,7 +114,8 @@ public class TweetLoader extends AsyncTask<Long, Tweet, Tweet> {
if (ui.get() != null) {
if (tweet != null) {
ui.get().onAction(tweet, action);
} else if (twException != null) {
}
if (twException != null) {
ui.get().onError(twException);
}
}

View File

@ -26,7 +26,7 @@ public class EngineException extends Exception {
ERROR_NOT_DEFINED
}
private final ErrorType messageResource;
private final ErrorType errorType;
private int retryAfter;
@ -40,61 +40,61 @@ public class EngineException extends Exception {
case 88:
case 420: //
case 429: // Rate limit exceeded!
messageResource = ErrorType.RATE_LIMIT_EX;
errorType = ErrorType.RATE_LIMIT_EX;
retryAfter = error.getRetryAfter();
break;
case 17:
case 50: // USER not found
case 63: // USER suspended
messageResource = ErrorType.USER_NOT_FOUND;
errorType = ErrorType.USER_NOT_FOUND;
break;
case 32:
messageResource = ErrorType.REQ_TOKEN_EXPIRED;
errorType = ErrorType.REQ_TOKEN_EXPIRED;
break;
case 34: //
case 144: // TWEET not found
messageResource = ErrorType.RESOURCE_NOT_FOUND;
errorType = ErrorType.RESOURCE_NOT_FOUND;
break;
case 150:
messageResource = ErrorType.CANT_SEND_DM;
errorType = ErrorType.CANT_SEND_DM;
break;
case 136:
case 179:
messageResource = ErrorType.NOT_AUTHORIZED;
errorType = ErrorType.NOT_AUTHORIZED;
break;
case 186:
messageResource = ErrorType.TWEET_TOO_LONG;
errorType = ErrorType.TWEET_TOO_LONG;
break;
case 187:
messageResource = ErrorType.DUPLICATE_TWEET;
errorType = ErrorType.DUPLICATE_TWEET;
break;
case 349:
messageResource = ErrorType.NO_DM_TO_USER;
errorType = ErrorType.NO_DM_TO_USER;
break;
case 354:
messageResource = ErrorType.DM_TOO_LONG;
errorType = ErrorType.DM_TOO_LONG;
break;
case 89:
messageResource = ErrorType.TOKEN_EXPIRED;
errorType = ErrorType.TOKEN_EXPIRED;
break;
default:
if (error.getStatusCode() == 401) {
messageResource = ErrorType.NOT_AUTHORIZED;
errorType = ErrorType.NOT_AUTHORIZED;
} else if (error.isCausedByNetworkIssue()) {
messageResource = ErrorType.NO_CONNECTION;
errorType = ErrorType.NO_CONNECTION;
} else {
messageResource = ErrorType.ERROR_NOT_DEFINED;
errorType = ErrorType.ERROR_NOT_DEFINED;
}
break;
}
@ -107,15 +107,15 @@ public class EngineException extends Exception {
EngineException(int errorCode) {
switch (errorCode) {
case FILENOTFOUND:
messageResource = ErrorType.NO_MEDIA_FOUND;
errorType = ErrorType.NO_MEDIA_FOUND;
break;
case TOKENNOTSET:
messageResource = ErrorType.NO_LINK_DEFINED;
errorType = ErrorType.NO_LINK_DEFINED;
break;
default:
messageResource = ErrorType.ERROR_NOT_DEFINED;
errorType = ErrorType.ERROR_NOT_DEFINED;
break;
}
}
@ -125,7 +125,7 @@ public class EngineException extends Exception {
* @return type of error {@link ErrorType}
*/
public ErrorType getErrorType() {
return messageResource;
return errorType;
}

View File

@ -547,11 +547,11 @@ public class TwitterEngine {
mStatus.setInReplyToStatusId(tweet.getReplyId());
if (tweet.hasLocation())
mStatus.setLocation(new GeoLocation(tweet.getLatitude(), tweet.getLongitude()));
if (tweet.hasImages()) {
long[] ids = uploadImages(tweet.getImageLink());
if (tweet.getMediaType() == TweetHolder.MediaType.IMAGE) {
long[] ids = uploadImages(tweet.getMediaLinks());
mStatus.setMediaIds(ids);
} else if (tweet.hasVideo()) {
long id = uploadVideo(tweet.getVideoLink());
} else if (tweet.getMediaType() == TweetHolder.MediaType.VIDEO) {
long id = uploadVideo(tweet.getMediaLink());
mStatus.setMediaIds(id);
}
twitter.updateStatus(mStatus);

View File

@ -19,9 +19,8 @@ public abstract class ErrorHandler {
*
* @param context current activity context
* @param error Error exception throwed by TwitterEngine
* @return true if its a hard failure
*/
public static boolean handleFailure(@NonNull Context context, @NonNull EngineException error) {
public static void handleFailure(@NonNull Context context, @NonNull EngineException error) {
switch (error.getErrorType()) {
case RATE_LIMIT_EX:
int timeToWait = error.getTimeToWait();
@ -38,7 +37,7 @@ public abstract class ErrorHandler {
case USER_NOT_FOUND:
Toast.makeText(context, R.string.error_user_not_found, Toast.LENGTH_SHORT).show();
return true;
break;
case REQ_TOKEN_EXPIRED:
Toast.makeText(context, R.string.error_request_token, Toast.LENGTH_SHORT).show();
@ -46,7 +45,7 @@ public abstract class ErrorHandler {
case RESOURCE_NOT_FOUND:
Toast.makeText(context, R.string.error_not_found, Toast.LENGTH_SHORT).show();
return true;
break;
case CANT_SEND_DM:
Toast.makeText(context, R.string.error_send_dm_to_user, Toast.LENGTH_SHORT).show();
@ -54,7 +53,7 @@ public abstract class ErrorHandler {
case NOT_AUTHORIZED:
Toast.makeText(context, R.string.error_not_authorized, Toast.LENGTH_SHORT).show();
return true;
break;
case TWEET_TOO_LONG:
Toast.makeText(context, R.string.error_status_length, Toast.LENGTH_SHORT).show();
@ -93,6 +92,5 @@ public abstract class ErrorHandler {
Toast.makeText(context, error.getMessage(), Toast.LENGTH_SHORT).show();
break;
}
return false;
}
}

View File

@ -1,105 +0,0 @@
package org.nuclearfog.twidda.backend.helper;
import androidx.annotation.NonNull;
import java.text.SimpleDateFormat;
import java.util.Date;
public abstract class StringTools {
public enum FileType {
IMAGE,
VIDEO,
STREAM,
ANGIF,
NONE
}
public static String getTimeString(long time) {
long diff = new Date().getTime() - time;
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
if (weeks > 4) {
Date tweetDate = new Date(time);
return SimpleDateFormat.getDateInstance().format(tweetDate);
}
if (weeks > 0)
return weeks + " w";
if (days > 0)
return days + " d";
if (hours > 0)
return hours + " h";
if (minutes > 0)
return minutes + " m";
return seconds + " s";
}
public static FileType getFileType(String path) {
String ext = getExtension(path);
switch (ext) {
case "png":
case "jpg":
case "jpeg":
return FileType.IMAGE;
case "mp4":
case "3gp":
return FileType.VIDEO;
case "m3u8":
return FileType.STREAM;
case "gif":
return FileType.ANGIF;
default:
return FileType.NONE;
}
}
private static String getExtension(@NonNull String path) {
String filename = getFilename(path);
String ext = "";
int start = lastIndexOf(filename, '.') + 1;
if (start > 0 && start < filename.length()) {
int end = lastIndexOf(filename, '?');
if (end > 0)
ext = filename.substring(start, end);
else
ext = filename.substring(start);
ext = asciiLowerCase(ext);
}
return ext;
}
private static String getFilename(@NonNull String path) {
String filename = "";
int end = lastIndexOf(path, '/') + 1;
if (end > 0 && end < path.length())
filename = path.substring(end);
return filename;
}
private static String asciiLowerCase(String ext) {
StringBuilder result = new StringBuilder();
for (int index = 0; index < ext.length(); index++) {
char current = ext.charAt(index);
if (current >= 'A' && current <= 'Z')
current += 0x20;
result.append(current);
}
return result.toString();
}
private static int lastIndexOf(String text, char symbol) {
int position = 0;
for (int index = 0; index < text.length(); index++) {
if (text.charAt(index) == symbol)
position = index;
}
return position;
}
}

View File

@ -11,6 +11,13 @@ import twitter4j.URLEntity;
public class Tweet {
public enum MediaType {
IMAGE,
VIDEO,
GIF,
NONE
}
private static final String PHOTO = "photo";
private static final String VIDEO = "video";
private static final String ANGIF = "animated_gif";
@ -38,6 +45,8 @@ public class Tweet {
private final String locationName;
private final String locationCoordinates;
private final MediaType mediaType;
/**
* Tweet Constructor
@ -66,7 +75,6 @@ public class Tweet {
tweet = getText(status);
time = status.getCreatedAt().getTime();
replyID = status.getInReplyToStatusId();
medias = getMediaLinks(status);
myRetweetId = status.getCurrentUserRetweetId();
replyUserId = status.getInReplyToUserId();
@ -74,7 +82,7 @@ public class Tweet {
String api = "" + status.getSource();
int start = api.indexOf('>') + 1;
int end = api.lastIndexOf('<');
if (start > 0 && end > 0)
if (start > 0 && end > start)
api = api.substring(start, end);
source = api;
@ -96,6 +104,37 @@ public class Tweet {
embedded = new Tweet(status.getRetweetedStatus());
else
embedded = null;
MediaEntity[] mediaEntities = status.getMediaEntities();
medias = new String[mediaEntities.length];
if (medias.length == 0) {
mediaType = MediaType.NONE;
} else {
switch (mediaEntities[0].getType()) {
case PHOTO:
mediaType = MediaType.IMAGE;
for (int i = 0; i < mediaEntities.length; i++)
medias[i] = mediaEntities[i].getMediaURLHttps();
break;
case VIDEO:
mediaType = MediaType.VIDEO;
for (MediaEntity.Variant type : mediaEntities[0].getVideoVariants()) {
if (type.getContentType().equals(MEDIA_VIDEO))
medias[0] = type.getUrl();
}
break;
case ANGIF:
mediaType = MediaType.GIF;
medias[0] = mediaEntities[0].getVideoVariants()[0].getUrl();
break;
default:
mediaType = MediaType.NONE;
break;
}
}
}
/**
@ -119,7 +158,7 @@ public class Tweet {
* @param place location full place name
*/
public Tweet(long tweetID, int retweetCount, int favoriteCount, TwitterUser user, String tweet, long time,
String replyName, long replyUserId, String[] medias, String source, long replyID,
String replyName, long replyUserId, String[] medias, MediaType mediaType, String source, long replyID,
Tweet embedded, long myRetweetId, boolean retweeted, boolean favored, String place, String geo) {
this.tweetID = tweetID;
@ -130,6 +169,7 @@ public class Tweet {
this.replyID = replyID;
this.embedded = embedded;
this.medias = medias;
this.mediaType = mediaType;
this.retweeted = retweeted;
this.favored = favored;
this.myRetweetId = myRetweetId;
@ -260,12 +300,12 @@ public class Tweet {
}
/**
* check if tweet contains media
* check tweet media type
*
* @return true if tweet contains media
* @return media type or NONE if there isnt any media
*/
public boolean hasMedia() {
return medias != null && medias.length > 0;
public MediaType getMediaType() {
return mediaType;
}
/**
@ -304,35 +344,6 @@ public class Tweet {
return locationCoordinates;
}
/**
* @param status Twitter4J status
* @return Array of Medialinks
*/
private String[] getMediaLinks(Status status) {
MediaEntity[] mediaEntities = status.getMediaEntities();
String[] medias = new String[mediaEntities.length];
for (int i = 0; i < medias.length; i++) {
MediaEntity mediaEntity = mediaEntities[i];
switch (mediaEntity.getType()) {
case PHOTO:
medias[i] = mediaEntity.getMediaURLHttps();
break;
case VIDEO:
for (MediaEntity.Variant type : mediaEntity.getVideoVariants()) {
if (type.getContentType().equals(MEDIA_VIDEO))
medias[i] = type.getUrl();
}
break;
case ANGIF:
medias[i] = mediaEntity.getVideoVariants()[0].getUrl();
break;
}
}
return medias;
}
/**
* Resolve shortened tweet links
*

View File

@ -4,18 +4,21 @@ import android.location.Location;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.backend.helper.StringTools;
import org.nuclearfog.twidda.backend.helper.StringTools.FileType;
public class TweetHolder {
public enum MediaType {
IMAGE,
VIDEO,
NONE
}
private final String text;
private final long replyId;
private String[] imageLink;
private String videoLink;
private String[] mediaLinks;
private double longitude, latitude;
private boolean hasImage = false;
private boolean hasVideo = false;
private MediaType mType = MediaType.NONE;
private boolean hasLocation = false;
@ -25,23 +28,9 @@ public class TweetHolder {
}
public void addMedia(String[] mediaLinks) {
FileType type = StringTools.getFileType(mediaLinks[0]);
switch (type) {
case VIDEO:
imageLink = new String[0];
videoLink = mediaLinks[0];
hasVideo = true;
break;
case ANGIF:
case IMAGE:
videoLink = "";
imageLink = mediaLinks;
hasImage = true;
break;
}
public void addMedia(String[] mediaLinks, MediaType mType) {
this.mediaLinks = mediaLinks;
this.mType = mType;
}
public void addLocation(Location location) {
@ -58,12 +47,16 @@ public class TweetHolder {
return replyId;
}
public String getVideoLink() {
return videoLink;
public MediaType getMediaType() {
return mType;
}
public String[] getImageLink() {
return imageLink;
public String[] getMediaLinks() {
return mediaLinks;
}
public String getMediaLink() {
return mediaLinks[0];
}
public double getLongitude() {
@ -74,14 +67,6 @@ public class TweetHolder {
return latitude;
}
public boolean hasImages() {
return hasImage;
}
public boolean hasVideo() {
return hasVideo;
}
public boolean hasLocation() {
return hasLocation;
}
@ -93,8 +78,6 @@ public class TweetHolder {
@NonNull
@Override
public String toString() {
return "to=" + replyId + ", location added=" + hasLocation + ", image added=" + hasImage + ", video added=" + hasVideo
+ "\n" + text;
return "to=" + replyId + "\nTweet=" + text;
}
}

View File

@ -20,18 +20,22 @@ import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE;
public class AppDatabase {
private static final int FAV_MASK = 1; // FAVORITE MASK
private static final int RTW_MASK = 1 << 1; // RETWEET MASK
private static final int HOM_MASK = 1 << 2; // HOME TWEET MASK
private static final int MEN_MASK = 1 << 3; // MENTION MASK
private static final int UTW_MASK = 1 << 4; // USER TWEETS
private static final int RPL_MASK = 1 << 5; // TWEET ANSWERS
private static final int FAV_MASK = 1; // tweet is favored by user
private static final int RTW_MASK = 1 << 1; // tweet is retweeted by user
private static final int HOM_MASK = 1 << 2; // tweet is from home timeline
private static final int MEN_MASK = 1 << 3; // tweet is from mention timeline
private static final int UTW_MASK = 1 << 4; // tweet is from an users timeline
private static final int RPL_MASK = 1 << 5; // tweet is from a reply timeline
private static final int VER_MASK = 1; // USER VERIFIED MASK
private static final int LCK_MASK = 1 << 1; // USER LOCKED MASK
private static final int FRQ_MASK = 1 << 2; // USER REQUEST FOLLOW
private static final int EXCL_USR = 1 << 3; // EXCLUDE USERS TWEETS
private static final int DEF_IMG = 1 << 4; // DEFAULT PROFILE IMAGE
private static final int MEDIA_IMAGE_MASK = 1 << 6; // tweet contains images
private static final int MEDIA_VIDEO_MASK = 1 << 7; // tweet contains a video
private static final int MEDIA_ANGIF_MASK = 1 << 8; // tweet contains an animation
private static final int VER_MASK = 1; // user is verified
private static final int LCK_MASK = 1 << 1; // user is private
private static final int FRQ_MASK = 1 << 2; // a follow request is pending
private static final int EXCL_USR = 1 << 3; // user excluded from mention timeline
private static final int DEF_IMG = 1 << 4; // user has a default profile image
private final int limit; // DATABASE ENTRY limit
private final long homeId;
@ -165,18 +169,6 @@ public class AppDatabase {
commit(db);
}
/**
* get user information
*
* @param userId ID of user
* @return user information or null if not found
*/
@Nullable
public TwitterUser getUser(long userId) {
SQLiteDatabase db = getDbRead();
return getUser(userId, db);
}
/**
* load home timeline
*
@ -275,6 +267,18 @@ public class AppDatabase {
return tweetList;
}
/**
* get user information
*
* @param userId ID of user
* @return user information or null if not found
*/
@Nullable
public TwitterUser getUser(long userId) {
SQLiteDatabase db = getDbRead();
return getUser(userId, db);
}
/**
* load status
*
@ -421,7 +425,7 @@ public class AppDatabase {
*
* @param id Direct Message ID
*/
public void deleteDm(long id) {
public void deleteMessage(long id) {
final String[] messageId = {Long.toString(id)};
SQLiteDatabase db = getDbWrite();
@ -543,15 +547,22 @@ public class AppDatabase {
String geo = cursor.getString(cursor.getColumnIndex("geo"));
long replyUserId = cursor.getLong(cursor.getColumnIndex("replyUserID"));
int statusregister = cursor.getInt(cursor.getColumnIndex("statusregister"));
boolean favorited = (statusregister & FAV_MASK) > 0;
boolean retweeted = (statusregister & RTW_MASK) > 0;
boolean favorited = (statusregister & FAV_MASK) != 0;
boolean retweeted = (statusregister & RTW_MASK) != 0;
String[] medias = parseMedia(medialinks);
Tweet.MediaType mediaType = Tweet.MediaType.NONE;
if ((statusregister & MEDIA_IMAGE_MASK) != 0)
mediaType = Tweet.MediaType.IMAGE;
else if ((statusregister & MEDIA_VIDEO_MASK) != 0)
mediaType = Tweet.MediaType.VIDEO;
else if ((statusregister & MEDIA_ANGIF_MASK) != 0)
mediaType = Tweet.MediaType.GIF;
TwitterUser user = getUser(cursor);
Tweet embeddedTweet = null;
if (retweetId > 1)
embeddedTweet = getStatus(retweetId);
return new Tweet(tweetId, retweet, favorit, user, tweettext, time, replyname, replyUserId, medias,
source, replyStatusId, embeddedTweet, retweeterId, retweeted, favorited, place, geo);
mediaType, source, replyStatusId, embeddedTweet, retweeterId, retweeted, favorited, place, geo);
}
@ -654,6 +665,19 @@ public class AppDatabase {
} else {
statusRegister &= ~RTW_MASK;
}
switch (tweet.getMediaType()) {
case IMAGE:
statusRegister |= MEDIA_IMAGE_MASK;
break;
case VIDEO:
statusRegister |= MEDIA_VIDEO_MASK;
break;
case GIF:
statusRegister |= MEDIA_ANGIF_MASK;
break;
}
status.put("media", getMediaLinks(tweet));
status.put("statusregister", statusRegister);

View File

@ -9,7 +9,7 @@ import org.nuclearfog.twidda.backend.items.TrendLocation;
import static android.content.Context.MODE_PRIVATE;
public final class GlobalSettings {
public class GlobalSettings {
public static final Typeface[] fonts = {Typeface.DEFAULT, Typeface.MONOSPACE,
Typeface.SERIF, Typeface.create("sans-serif-thin", Typeface.NORMAL)};

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M17.125,6.17l-2.046,-5.635c-0.151,-0.416 -0.595,-0.637 -0.989,-0.492L0.492,5.006C0.098,5.15 -0.101,5.603 0.051,6.019l2.156,5.941V8.777c0,-1.438 1.148,-2.607 2.56,-2.607H8.36l4.285,-3.008l2.479,3.008H17.125zM19.238,8H4.767c-0.42,0 -0.762,0.334 -0.762,0.777v9.42C4.006,18.641 4.348,19 4.767,19h14.471C19.658,19 20,18.641 20,18.197v-9.42C20,8.334 19.658,8 19.238,8zM18,17H6v-2l1.984,-4.018l2.768,3.436l2.598,-2.662l3.338,-1.205L18,14V17z"
android:fillColor="#FFFFFF" />
</vector>

View File

@ -23,7 +23,7 @@
android:textSize="@dimen/textsize_trendname" />
<LinearLayout
android:layout_weight="8"
android:layout_weight="7"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical">

View File

@ -153,7 +153,7 @@
android:id="@+id/load_dialog"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/button_settings"
android:layout_height="@dimen/button_settings_height"
android:layout_marginStart="@dimen/button_margin"
android:layout_marginLeft="@dimen/button_margin"
android:layout_marginEnd="@dimen/button_margin"
@ -229,7 +229,7 @@
android:id="@+id/delete_db"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/button_settings"
android:layout_height="@dimen/button_settings_height"
android:layout_margin="@dimen/button_margin"
android:layout_weight="1"
android:background="@drawable/button"
@ -240,7 +240,7 @@
android:id="@+id/logout"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="0dp"
android:layout_height="@dimen/button_settings"
android:layout_height="@dimen/button_settings_height"
android:layout_margin="@dimen/button_margin"
android:layout_weight="1"
android:background="@drawable/button"

View File

@ -112,26 +112,14 @@
android:visibility="gone" />
<ImageButton
android:id="@+id/image_attach"
android:id="@+id/tweet_media_attach"
android:layout_width="@dimen/button_media_width"
android:layout_height="@dimen/button_media_height"
android:layout_gravity="center"
android:layout_margin="@dimen/tweet_media_button_margin"
android:background="@drawable/button"
android:contentDescription="@string/image_preview_button"
android:visibility="gone"
app:srcCompat="@drawable/image" />
<ImageButton
android:id="@+id/video_attach"
android:layout_width="@dimen/button_media_width"
android:layout_height="@dimen/button_media_height"
android:layout_gravity="center"
android:layout_margin="@dimen/tweet_media_button_margin"
android:background="@drawable/button"
android:contentDescription="@string/video_preview_button"
android:visibility="gone"
app:srcCompat="@drawable/video" />
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -15,10 +15,10 @@
android:textSize="@dimen/settings_info_appname_font" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srcCompat="@drawable/twitter4j_badge" />
app:srcCompat="@drawable/twitter4j_badge"
android:contentDescription="@string/badge_twitter4j" />
<TextView
android:layout_width="match_parent"

View File

@ -109,7 +109,6 @@
<string name="proxy_authentication">Proxy Login</string>
<string name="error_empty_port">Proxy port muss gesetzt werden!</string>
<string name="error_empty_pass">Proxy Passort darf nicht leer sein!</string>
<string name="video_preview_button">Videovorschau Button</string>
<string name="error_open_link">Fehler beim Öffnen des links!</string>
<string name="error_image_download">Bild konnte nicht geladen werden!</string>
<string name="error_dm_send">Direktnachricht konnte nicht an diesen Nutzer gesendet werden!</string>
@ -146,4 +145,5 @@
<string name="settings_3rd_party_license">App und Drittanbieter Lizenz:</string>
<string name="settings_info_github">Github Seite:</string>
<string name="error_rate_limit">Zu viele Anfragen! Bitte 15 Minuten warten!</string>
<string name="info_cant_add_video">Video konnte nicht hinzugefügt werden!</string>
</resources>

View File

@ -2,22 +2,18 @@
<resources>
<dimen name="toolbar_height">45dp</dimen>
<dimen name="divider">2dp</dimen>
<dimen name="profile_image">80dp</dimen>
<dimen name="profile_middle">40dp</dimen>
<dimen name="profile_small">36dp</dimen>
<dimen name="tweet_profile">56dp</dimen>
<dimen name="profile_middle">40sp</dimen>
<dimen name="profile_small">36sp</dimen>
<dimen name="tweet_profile">56sp</dimen>
<dimen name="margin_dm_icon">5dp</dimen>
<dimen name="margin_tweet_icon">16dp</dimen>
<dimen name="margin_layout">5dp</dimen>
<dimen name="margin_layout_tweet">2dp</dimen>
<dimen name="margin_side">10dp</dimen>
<dimen name="padding_editprofile">20dp</dimen>
<dimen name="padding_drawable">5dp</dimen>
<dimen name="padding_side">10dp</dimen>
<dimen name="text_bio_height">150dp</dimen>
<dimen name="text_settings">5dp</dimen>
<dimen name="text_input_width">300dp</dimen>
@ -39,23 +35,22 @@
<dimen name="textsize_settings_small">11sp</dimen>
<integer name="text_tweet_lines">9</integer>
<integer name="text_bio_lines">3</integer>
<dimen name="button_dm">40dp</dimen>
<dimen name="button_settings_color">40dp</dimen>
<dimen name="button_settings">30dp</dimen>
<dimen name="button_load">36dp</dimen>
<dimen name="button_settings_color">40sp</dimen>
<dimen name="button_settings_height">30sp</dimen>
<dimen name="button_load">36sp</dimen>
<dimen name="button_margin">5dp</dimen>
<dimen name="button_padding">5dp</dimen>
<dimen name="button_height">20dp</dimen>
<dimen name="button_height">20sp</dimen>
<dimen name="button_size">40dp</dimen>
<dimen name="button_tweet_size">40dp</dimen>
<dimen name="button_media_height">36dp</dimen>
<dimen name="button_media_width">64dp</dimen>
<dimen name="preview_margin">10dp</dimen>
<dimen name="dm_item_button_height">20dp</dimen>
<dimen name="dm_item_button_height">20sp</dimen>
<dimen name="tweet_media_button_margin">5dp</dimen>
<dimen name="tweet_location_progress_size">30dp</dimen>
<dimen name="list_button_height">20dp</dimen>
<dimen name="list_button_height">20sp</dimen>
<dimen name="listitem_margin">4dp</dimen>
<dimen name="list_padding">5dp</dimen>
<dimen name="list_bar_padding">10dp</dimen>

View File

@ -73,7 +73,6 @@
<string name="info_clipboard">Link copied to clipboard!</string>
<string name="profile_link">link</string>
<string name="image_preview_button">image preview button</string>
<string name="video_preview_button">video preview button</string>
<string name="close_dm">close direct message</string>
<string name="error_user_not_found">user not found!</string>
<string name="error_send_dm_to_user">cannot send dm to user!</string>
@ -148,4 +147,6 @@
<string name="settings_info_license_link" translatable="false">http://www.apache.org/licenses/LICENSE-2.0</string>
<string name="settings_info_github">App on GitHub:</string>
<string name="error_rate_limit">Too many requests! Please wait 15 minutes.</string>
<string name="info_cant_add_video">Can\'t add video!</string>
<string name="badge_twitter4j" translatable="false">Twitter4J Badge</string>
</resources>