mirror of
https://github.com/nuclearfog/Shitter.git
synced 2025-01-30 19:05:02 +01:00
bug fix
This commit is contained in:
parent
31456a9331
commit
0282ed2376
@ -2,6 +2,7 @@ package org.nuclearfog.twidda.backend.api;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.nuclearfog.twidda.model.Relation;
|
||||
|
||||
@ -20,13 +21,19 @@ class RelationV1 implements Relation {
|
||||
private boolean canDm;
|
||||
|
||||
|
||||
RelationV1(JSONObject json, long currentId) {
|
||||
isHome = json.optLong("target_id") == currentId;
|
||||
isFollowing = json.optBoolean("following");
|
||||
isFollower = json.optBoolean("followed_by");
|
||||
isBlocked = json.optBoolean("blocking");
|
||||
isMuted = json.optBoolean("muting");
|
||||
canDm = json.optBoolean("can_dm");
|
||||
RelationV1(JSONObject json) throws JSONException {
|
||||
JSONObject relationship = json.getJSONObject("relationship");
|
||||
JSONObject source = relationship.getJSONObject("source");
|
||||
JSONObject target = relationship.getJSONObject("target");
|
||||
|
||||
long sourceId = Long.parseLong(source.getString("id_str"));
|
||||
long targetId = Long.parseLong(target.getString("id_str"));
|
||||
isHome = sourceId == targetId;
|
||||
isFollowing = source.optBoolean("following");
|
||||
isFollower = source.optBoolean("followed_by");
|
||||
isBlocked = source.optBoolean("blocking");
|
||||
isMuted = source.optBoolean("muting");
|
||||
canDm = source.optBoolean("can_dm");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,8 +64,8 @@ class TweetV1 implements Tweet {
|
||||
|
||||
|
||||
TweetV1(JSONObject json, long twitterId) throws JSONException {
|
||||
id = json.optLong("id");
|
||||
text = json.optString("full_text");
|
||||
author = new UserV1(json.getJSONObject("user"), twitterId);
|
||||
id = Long.parseLong(json.optString("id_str", "-1"));
|
||||
replyId = json.optLong("in_reply_to_status_id", -1);
|
||||
replyUserId = json.optLong("in_reply_to_status_id", -1);
|
||||
retweetCount = json.optInt("retweet_count");
|
||||
@ -73,23 +73,19 @@ class TweetV1 implements Tweet {
|
||||
isFavorited = json.optBoolean("favorited");
|
||||
isRetweeted = json.optBoolean("retweeted");
|
||||
isSensitive = json.optBoolean("possibly_sensitive");
|
||||
timestamp = StringTools.getTime(json.optString("created_at"));
|
||||
timestamp = StringTools.getTime1(json.optString("created_at"));
|
||||
source = StringTools.getSource(json.optString("source"));
|
||||
text = createText(json);
|
||||
|
||||
String replyName = json.optString("in_reply_to_screen_name");
|
||||
String userMentions = StringTools.getUserMentions(text);
|
||||
|
||||
JSONObject locationJson = json.optJSONObject("place");
|
||||
JSONObject coordinateJson = json.optJSONObject("coordinates");
|
||||
JSONObject user = json.getJSONObject("user");
|
||||
JSONObject quoted_tweet = json.optJSONObject("retweeted_status");
|
||||
JSONObject user_retweet = json.optJSONObject("current_user_retweet");
|
||||
JSONObject entities = json.optJSONObject("entities");
|
||||
JSONObject extEntities = json.optJSONObject("extended_entities");
|
||||
|
||||
author = new UserV1(user, twitterId);
|
||||
if (locationJson != null) {
|
||||
location = locationJson.optString("full_name");
|
||||
}
|
||||
if (coordinateJson != null) {
|
||||
if (coordinateJson.optString("type").equals("Point")) {
|
||||
JSONArray coordinateArray = coordinateJson.optJSONArray("coordinates");
|
||||
@ -100,6 +96,9 @@ class TweetV1 implements Tweet {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (locationJson != null) {
|
||||
location = locationJson.optString("full_name");
|
||||
}
|
||||
if (!replyName.equals("null")) {
|
||||
this.replyName = '@' + replyName;
|
||||
}
|
||||
@ -115,8 +114,6 @@ class TweetV1 implements Tweet {
|
||||
isRetweeted = embeddedTweet.isRetweeted();
|
||||
isFavorited = embeddedTweet.isFavorited();
|
||||
}
|
||||
if (entities != null)
|
||||
addURLs(entities);
|
||||
if (extEntities != null) {
|
||||
addMedia(extEntities);
|
||||
}
|
||||
@ -338,15 +335,16 @@ class TweetV1 implements Tweet {
|
||||
}
|
||||
|
||||
/**
|
||||
* expand URLs int the tweet text
|
||||
*
|
||||
* @param entities json object with tweet entities
|
||||
* read tweet and expand urls
|
||||
*/
|
||||
private void addURLs(@NonNull JSONObject entities) {
|
||||
private String createText(@NonNull JSONObject json) {
|
||||
String text = json.optString("full_text");
|
||||
StringBuilder builder = new StringBuilder(text);
|
||||
|
||||
// check for shortened urls and replace them with full urls
|
||||
try {
|
||||
JSONObject entities = json.getJSONObject("entities");
|
||||
JSONArray urls = entities.getJSONArray("urls");
|
||||
// replace new line symbol with new line character
|
||||
StringBuilder builder = new StringBuilder(text);
|
||||
for (int i = urls.length() - 1; i >= 0; i--) {
|
||||
JSONObject entry = urls.getJSONObject(i);
|
||||
String link = entry.getString("expanded_url");
|
||||
@ -356,9 +354,17 @@ class TweetV1 implements Tweet {
|
||||
int offset = StringTools.calculateIndexOffset(text, start);
|
||||
builder.replace(start + offset, end + offset, link);
|
||||
}
|
||||
this.text = builder.toString();
|
||||
} catch (JSONException e) {
|
||||
// use default description
|
||||
// use default tweet text
|
||||
builder = new StringBuilder(text);
|
||||
}
|
||||
|
||||
// replace "&" string
|
||||
int index = builder.lastIndexOf("&");
|
||||
while (index >= 0) {
|
||||
builder.replace(index, index + 5, "&");
|
||||
index = builder.lastIndexOf("&");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@ -338,9 +338,7 @@ public class Twitter {
|
||||
if (response.body() != null) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if (response.code() == 200) {
|
||||
JSONObject source = json.getJSONObject("relationship").getJSONObject("source");
|
||||
long currentId = settings.getCurrentUserId();
|
||||
return new RelationV1(source, currentId);
|
||||
return new RelationV1(json);
|
||||
}
|
||||
throw new TwitterException(json);
|
||||
}
|
||||
|
@ -31,14 +31,14 @@ class UserListV1 implements UserList {
|
||||
|
||||
|
||||
UserListV1(JSONObject json, long currentId) throws JSONException {
|
||||
id = json.optLong("id");
|
||||
id = Long.parseLong(json.optString("id_str", "-1"));
|
||||
title = json.optString("name");
|
||||
description = json.optString("description");
|
||||
memberCount = json.optInt("member_count");
|
||||
subscriberCount = json.optInt("subscriber_count");
|
||||
isPrivate = json.optString("mode").equals("private");
|
||||
following = json.optBoolean("following");
|
||||
time = StringTools.getTime(json.optString("created_at"));
|
||||
time = StringTools.getTime1(json.optString("created_at"));
|
||||
owner = new UserV1(json.getJSONObject("user"));
|
||||
isOwner = currentId == owner.getId();
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ class UserV1 implements User {
|
||||
private String screenName;
|
||||
private String description;
|
||||
private String location;
|
||||
private String profileUrl;
|
||||
private String url;
|
||||
private String profileImageUrl;
|
||||
private String profileBannerUrl;
|
||||
private int following;
|
||||
@ -45,50 +45,23 @@ class UserV1 implements User {
|
||||
|
||||
|
||||
UserV1(JSONObject json) {
|
||||
String profileImage = json.optString("profile_image_url_https");
|
||||
profileBannerUrl = json.optString("profile_banner_url");
|
||||
description = json.optString("description");
|
||||
id = Long.parseLong(json.optString("id_str", "-1"));
|
||||
username = json.optString("name");
|
||||
screenName = '@' + json.optString("screen_name");
|
||||
location = json.optString("location");
|
||||
id = json.optLong("id");
|
||||
isVerified = json.optBoolean("verified");
|
||||
isLocked = json.optBoolean("protected");
|
||||
profileImageUrl = getProfileImage(json);
|
||||
profileBannerUrl = json.optString("profile_banner_url");
|
||||
description = getDescription(json);
|
||||
location = json.optString("location");
|
||||
following = json.optInt("friends_count");
|
||||
follower = json.optInt("followers_count");
|
||||
tweetCount = json.optInt("statuses_count");
|
||||
favorCount = json.optInt("favourites_count");
|
||||
followReqSent = json.optBoolean("follow_request_sent");
|
||||
defaultImage = json.optBoolean("default_profile_image");
|
||||
profileUrl = json.optString("profile_image_url_https");
|
||||
created = StringTools.getTime(json.optString("created_at"));
|
||||
|
||||
// expand URLs
|
||||
JSONObject entities = json.optJSONObject("entities");
|
||||
if (entities != null) {
|
||||
JSONObject url = entities.optJSONObject("url");
|
||||
if (url != null) {
|
||||
JSONArray urls = url.optJSONArray("urls");
|
||||
if (urls != null && urls.length() > 0) {
|
||||
profileUrl = urls.optJSONObject(0).optString("display_url");
|
||||
}
|
||||
}
|
||||
JSONObject descrEntities = entities.optJSONObject("description");
|
||||
if (descrEntities != null) {
|
||||
JSONArray urls = descrEntities.optJSONArray("urls");
|
||||
if (urls != null) {
|
||||
expandDescriptionUrls(urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
// set profile image url
|
||||
int start = profileImage.lastIndexOf('_');
|
||||
int end = profileImage.lastIndexOf('.');
|
||||
if (!defaultImage && start > 0 && end > 0) {
|
||||
profileImageUrl = profileImage.substring(0, start) + profileImage.substring(end);
|
||||
} else {
|
||||
profileImageUrl = profileImage;
|
||||
}
|
||||
created = StringTools.getTime1(json.optString("created_at"));
|
||||
url = getUrl(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -133,7 +106,7 @@ class UserV1 implements User {
|
||||
|
||||
@Override
|
||||
public String getProfileUrl() {
|
||||
return profileUrl;
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -195,13 +168,19 @@ class UserV1 implements User {
|
||||
}
|
||||
|
||||
/**
|
||||
* expand URLs in the user description
|
||||
* expand URLs of the user description
|
||||
*
|
||||
* @param urls json object with url information
|
||||
* @param json root json object of user v1
|
||||
* @return user description
|
||||
*/
|
||||
private void expandDescriptionUrls(@NonNull JSONArray urls) {
|
||||
private String getDescription(JSONObject json) {
|
||||
try {
|
||||
// replace new line symbol with new line character
|
||||
JSONObject entities = json.getJSONObject("entities");
|
||||
String description = json.getString("description");
|
||||
JSONObject descrEntities = entities.getJSONObject("description");
|
||||
JSONArray urls = descrEntities.getJSONArray("urls");
|
||||
|
||||
// expand shortened urls
|
||||
StringBuilder builder = new StringBuilder(description);
|
||||
for (int i = urls.length() - 1; i >= 0; i--) {
|
||||
JSONObject entry = urls.getJSONObject(i);
|
||||
@ -212,9 +191,45 @@ class UserV1 implements User {
|
||||
int offset = StringTools.calculateIndexOffset(description, start);
|
||||
builder.replace(start + offset, end + offset, link);
|
||||
}
|
||||
this.description = builder.toString();
|
||||
return builder.toString();
|
||||
} catch (JSONException e) {
|
||||
// use default description
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get expanded profile url
|
||||
*
|
||||
* @param json root json object of user v1
|
||||
* @return expanded url
|
||||
*/
|
||||
private String getUrl(JSONObject json) {
|
||||
try {
|
||||
JSONObject entities = json.getJSONObject("entities");
|
||||
JSONObject urlJson = entities.getJSONObject("url");
|
||||
JSONArray urls = urlJson.getJSONArray("urls");
|
||||
if ( urls.length() > 0) {
|
||||
return urls.getJSONObject(0).getString("display_url");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* get original sized profile image url
|
||||
*
|
||||
* @param json root json object of user v1
|
||||
* @return profile image url
|
||||
*/
|
||||
private String getProfileImage(JSONObject json) {
|
||||
String profileImage = json.optString("profile_image_url_https");
|
||||
// set profile image url
|
||||
int start = profileImage.lastIndexOf('_');
|
||||
int end = profileImage.lastIndexOf('.');
|
||||
if (!defaultImage && start > 0 && end > 0)
|
||||
return profileImage.substring(0, start) + profileImage.substring(end);
|
||||
return profileImage;
|
||||
}
|
||||
}
|
@ -3,13 +3,12 @@ package org.nuclearfog.twidda.backend.api;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.nuclearfog.twidda.backend.utils.StringTools;
|
||||
import org.nuclearfog.twidda.model.User;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* implementation of User accessed by API 2.0
|
||||
*
|
||||
@ -22,13 +21,8 @@ class UserV2 implements User {
|
||||
/**
|
||||
* extra parameters required to fetch additional data
|
||||
*/
|
||||
public static final String PARAMS = "user.fields=profile_image_url%2Cpublic_metrics%2Cverified%2Cprotected";
|
||||
|
||||
/**
|
||||
* date time formatter for ISO 8601
|
||||
*/
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
|
||||
|
||||
public static final String PARAMS = "user.fields=profile_image_url%2Cpublic_metrics%2Cverified" +
|
||||
"%2Cprotected%2Cdescription%2Ccreated_at%2Curl%2Centities";
|
||||
|
||||
private long id;
|
||||
private long created;
|
||||
@ -36,7 +30,7 @@ class UserV2 implements User {
|
||||
private String screenName;
|
||||
private String description;
|
||||
private String location;
|
||||
private String profileUrl;
|
||||
private String url;
|
||||
private String profileImageUrl;
|
||||
private String profileBannerUrl;
|
||||
private int following;
|
||||
@ -51,16 +45,18 @@ class UserV2 implements User {
|
||||
|
||||
|
||||
UserV2(JSONObject json, long twitterId) {
|
||||
id = json.optLong("id");
|
||||
id = Long.parseLong(json.optString("id", "-1"));
|
||||
username = json.optString("name");
|
||||
screenName = '@' + json.optString("username"); // username -> screenname
|
||||
screenName = '@' + json.optString("username");
|
||||
isProtected = json.optBoolean("protected");
|
||||
location = json.optString("location");
|
||||
profileUrl = json.optString("url");
|
||||
description = json.optString("description");
|
||||
isVerified = json.optBoolean("verified");
|
||||
profileImageUrl = json.optString("profile_image_url");
|
||||
profileBannerUrl = json.optString("profile_banner_url");
|
||||
created = StringTools.getTime2(json.optString("created_at"));
|
||||
description = getDescription(json);
|
||||
url = getUrl(json);
|
||||
isCurrentUser = id == twitterId;
|
||||
|
||||
JSONObject metrics = json.optJSONObject("public_metrics");
|
||||
if (metrics != null) {
|
||||
@ -68,9 +64,8 @@ class UserV2 implements User {
|
||||
follower = metrics.optInt("followers_count");
|
||||
tweetCount = metrics.optInt("tweet_count");
|
||||
}
|
||||
isCurrentUser = id == twitterId;
|
||||
setDate(json.optString("created_at"));
|
||||
|
||||
// not yet implemented in API 2.0
|
||||
favorCount = 0;
|
||||
followReqSent = false;
|
||||
defaultImage = false;
|
||||
@ -118,7 +113,7 @@ class UserV2 implements User {
|
||||
|
||||
@Override
|
||||
public String getProfileUrl() {
|
||||
return profileUrl;
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -180,17 +175,57 @@ class UserV2 implements User {
|
||||
}
|
||||
|
||||
/**
|
||||
* set time of account creation
|
||||
* expand URLs of the user description
|
||||
*
|
||||
* @param dateStr date string from twitter
|
||||
* @param json root json object of user v1
|
||||
* @return user description
|
||||
*/
|
||||
private void setDate(String dateStr) {
|
||||
try {
|
||||
Date date = sdf.parse(dateStr);
|
||||
if (date != null)
|
||||
created = date.getTime();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
private String getDescription(JSONObject json) {
|
||||
String description = json.optString("description");
|
||||
JSONObject entities = json.optJSONObject("entities");
|
||||
if (entities != null) {
|
||||
try {
|
||||
JSONObject descrEntities = entities.getJSONObject("description");
|
||||
JSONArray urls = descrEntities.getJSONArray("urls");
|
||||
// expand shortened urls
|
||||
StringBuilder builder = new StringBuilder(description);
|
||||
for (int i = urls.length() - 1; i >= 0; i--) {
|
||||
JSONObject entry = urls.getJSONObject(i);
|
||||
String link = entry.getString("expanded_url");
|
||||
int start = entry.getInt("start");
|
||||
int end = entry.getInt("end");
|
||||
int offset = StringTools.calculateIndexOffset(description, start);
|
||||
builder.replace(start + offset, end + offset, link);
|
||||
}
|
||||
return builder.toString();
|
||||
} catch (JSONException e) {
|
||||
// ignore, use default description
|
||||
}
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* get expanded profile url
|
||||
*
|
||||
* @param json root json object of user v1
|
||||
* @return expanded url
|
||||
*/
|
||||
private String getUrl(JSONObject json) {
|
||||
JSONObject entities = json.optJSONObject("entities");
|
||||
if (entities != null) {
|
||||
JSONObject urlJson = entities.optJSONObject("url");
|
||||
if (urlJson != null) {
|
||||
try {
|
||||
JSONArray urls = urlJson.getJSONArray("urls");
|
||||
if (urls.length() > 0) {
|
||||
return urls.getJSONObject(0).getString("display_url");
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ public class UserLists extends LinkedList<UserList> {
|
||||
* @return true if list is linked
|
||||
*/
|
||||
public boolean hasPrevious() {
|
||||
return prevCursor > 0;
|
||||
return prevCursor != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +57,7 @@ public class UserLists extends LinkedList<UserList> {
|
||||
* @return true if list has a successor
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return nextCursor > 0;
|
||||
return nextCursor != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ public class Users extends LinkedList<User> {
|
||||
* @return true if list is linked
|
||||
*/
|
||||
public boolean hasPrevious() {
|
||||
return prevCursor > 0;
|
||||
return prevCursor != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +73,7 @@ public class Users extends LinkedList<User> {
|
||||
* @return true if list has a successor
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return nextCursor > 0;
|
||||
return nextCursor != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,10 +25,31 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
*/
|
||||
public final class StringTools {
|
||||
|
||||
/**
|
||||
* regex pattern used to get user mentions
|
||||
*/
|
||||
private static final Pattern MENTION = Pattern.compile("[@][\\w_]+");
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.US);
|
||||
|
||||
/**
|
||||
* date format used by API 1.1
|
||||
* e.g. "Mon Jan 17 13:00:12 +0000 2022"
|
||||
*/
|
||||
private static final SimpleDateFormat dateFormat1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.US);
|
||||
|
||||
/**
|
||||
* date format used by API 2.0
|
||||
* e.g. "2008-08-15T13:51:34.000Z"
|
||||
*/
|
||||
private static final SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
|
||||
|
||||
/**
|
||||
* fallback date if parsing failed
|
||||
*/
|
||||
private static final long DEFAULT_TIME = 0x61D99F64;
|
||||
|
||||
/**
|
||||
* random generator used to generate random strings
|
||||
*/
|
||||
private static Random rand = new Random();
|
||||
|
||||
private StringTools() {
|
||||
@ -116,26 +137,40 @@ public final class StringTools {
|
||||
*/
|
||||
public static int countMentions(String text) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < text.length() - 1; i++) {
|
||||
if (text.charAt(i) == '@') {
|
||||
char next = text.charAt(i + 1);
|
||||
if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') || (next >= '0' && next <= '9') || next == '_') {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
Matcher m = MENTION.matcher(text);
|
||||
while (m.find()) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert Twitter ISO 8601 date time to long format
|
||||
* convert Twitter API 1.1 date time to long format
|
||||
*
|
||||
* @param timeStr Twitter time string
|
||||
* @return date time
|
||||
*/
|
||||
public static long getTime(String timeStr) {
|
||||
public static long getTime1(String timeStr) {
|
||||
try {
|
||||
Date date = sdf.parse(timeStr);
|
||||
Date date = dateFormat1.parse(timeStr);
|
||||
if (date != null)
|
||||
return date.getTime();
|
||||
} catch (Exception e) {
|
||||
// make date invalid so it will be not shown
|
||||
e.printStackTrace();
|
||||
}
|
||||
return DEFAULT_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert Twitter API 2 date time to long format
|
||||
*
|
||||
* @param timeStr Twitter time string
|
||||
* @return date time
|
||||
*/
|
||||
public static long getTime2(String timeStr) {
|
||||
try {
|
||||
Date date = dateFormat2.parse(timeStr);
|
||||
if (date != null)
|
||||
return date.getTime();
|
||||
} catch (Exception e) {
|
||||
@ -168,7 +203,7 @@ public final class StringTools {
|
||||
*/
|
||||
public static int calculateIndexOffset(String text, int limit) {
|
||||
int offset = 0;
|
||||
for (int c = 0; c < limit - 1 && c < text.length(); c++) {
|
||||
for (int c = 0; c < limit - 1 && c < text.length() - 1; c++) {
|
||||
// determine if a pair of chars represent an emoji
|
||||
if (Character.isSurrogatePair(text.charAt(c), text.charAt(c + 1))) {
|
||||
offset++;
|
||||
|
Loading…
x
Reference in New Issue
Block a user