1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-13 18:20:37 +01:00

refactoring

make streaming extension work again
This commit is contained in:
Mariotaku Lee 2015-01-11 17:28:45 +08:00
parent 4b93497c5d
commit ff13288b65
432 changed files with 10304 additions and 8065 deletions

View File

@ -1,10 +1,16 @@
include ':twidere'
include ':twidere.component.twitter4j'
include ':twidere.component.twitter4j.streaming'
include ':twidere.component.common'
include ':twidere.library.extension'
include ':twidere.component.jsonserializer'
include ':twidere.component.querybuilder'
include ':twidere.wear'
include ':twidere.donate.nyanwp'
include ':twidere.donate.nyanwp.wear'
include ':twidere.component.nyan'
include ':twidere.component.viewer.media'
//include ':twidere.extension.streaming'
include ':twidere.extension.streaming'
include ':SlidingMenu', ':DragSortListView', ':MenuComponent', ':RefreshNow', ':PullToRefresh', ':MessageBubbleView'
project(':SlidingMenu').projectDir = file('libraries/SlidingMenu/library')

62
signing.gradle Normal file
View File

@ -0,0 +1,62 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
android {
signingConfigs {
debug {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
Properties signingProp = new Properties()
signingProp.load(signingPropFile.newDataInputStream())
storeFile file(signingProp.get("twidere.debug.storeFile"))
storePassword signingProp.get("twidere.debug.storePassword")
keyAlias signingProp.get("twidere.debug.keyAlias")
keyPassword signingProp.get("twidere.debug.keyPassword")
}
}
release {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
Properties signingProp = new Properties()
signingProp.load(signingPropFile.newDataInputStream())
storeFile file(signingProp.get("twidere.release.storeFile"))
storePassword signingProp.get("twidere.release.storePassword")
keyAlias signingProp.get("twidere.release.keyAlias")
keyPassword signingProp.get("twidere.release.keyPassword")
}
}
}
buildTypes {
debug {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
signingConfig signingConfigs.debug
}
}
release {
File signingPropFile = rootProject.file('signing.properties')
if (signingPropFile.exists()) {
signingConfig signingConfigs.release
}
}
}
}

1
twidere.component.common/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,47 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:support-annotations:21.0.3'
compile 'org.apache.commons:commons-lang3:3.3.2'
compile project(':twidere.component.jsonserializer')
compile project(':twidere.component.querybuilder')
compile project(':twidere.component.twitter4j')
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,32 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.common;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,20 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="org.mariotaku.twidere.common"/>

View File

@ -19,10 +19,9 @@
package org.mariotaku.twidere.constant;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.annotation.Preference;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import static org.mariotaku.twidere.annotation.Preference.Type.BOOLEAN;
import static org.mariotaku.twidere.annotation.Preference.Type.INT;
@ -134,7 +133,7 @@ public interface SharedPreferenceConstants {
public static final String KEY_DATABASE_ITEM_LIMIT = "database_item_limit";
@Preference(type = INT, hasDefault = true, defaultInt = DEFAULT_LOAD_ITEM_LIMIT)
public static final String KEY_LOAD_ITEM_LIMIT = "load_item_limit";
@Preference(type = INT, hasDefault = true, defaultResource = R.integer.default_text_size)
@Preference(type = INT, hasDefault = true, defaultInt = 15)
public static final String KEY_TEXT_SIZE = "text_size_int";
@Preference(type = STRING, hasDefault = true, defaultString = DEFAULT_THEME)
public static final String KEY_THEME = "theme";

View File

@ -26,8 +26,8 @@ import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.twidere.provider.TweetStore.Drafts;
import org.mariotaku.twidere.util.ArrayUtils;
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.util.TwidereArrayUtils;
public class DraftItem implements Parcelable {
@ -56,7 +56,7 @@ public class DraftItem implements Parcelable {
_id = cursor.getLong(indices._id);
text = cursor.getString(indices.text);
media = ParcelableMediaUpdate.fromJSONString(cursor.getString(indices.media));
account_ids = ArrayUtils.parseLongArray(cursor.getString(indices.account_ids), ',');
account_ids = TwidereArrayUtils.parseLongArray(cursor.getString(indices.account_ids), ',');
in_reply_to_status_id = cursor.getLong(indices.in_reply_to_status_id);
is_possibly_sensitive = cursor.getShort(indices.is_possibly_sensitive) == 1;
location = new ParcelableLocation(cursor.getString(indices.location));

View File

@ -29,16 +29,14 @@ import android.support.annotation.NonNull;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.content.ContentResolverUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.isOfficialConsumerKeySecret;
import static org.mariotaku.twidere.util.Utils.shouldForceUsingPrivateAPIs;
public class ParcelableAccount implements Parcelable {
public static final Parcelable.Creator<ParcelableAccount> CREATOR = new Parcelable.Creator<ParcelableAccount>() {
@ -187,8 +185,7 @@ public class ParcelableAccount implements Parcelable {
} else {
final String consumerKey = cur.getString(indices.consumer_key);
final String consumerSecret = cur.getString(indices.consumer_secret);
if (shouldForceUsingPrivateAPIs(context)
|| isOfficialConsumerKeySecret(context, consumerKey, consumerSecret)) {
if (TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret)) {
accounts.add(new ParcelableAccount(cur, indices));
}
}
@ -294,8 +291,7 @@ public class ParcelableAccount implements Parcelable {
} else {
final String consumerKey = cur.getString(indices.consumer_key);
final String consumerSecret = cur.getString(indices.consumer_secret);
if (shouldForceUsingPrivateAPIs(context)
|| isOfficialConsumerKeySecret(context, consumerKey, consumerSecret)) {
if (TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret)) {
accounts.add(new ParcelableCredentials(cur, indices));
}
}
@ -305,14 +301,6 @@ public class ParcelableAccount implements Parcelable {
return accounts;
}
public static boolean isOfficialCredentials(final Context context, final ParcelableCredentials account) {
if (account == null) return false;
final boolean isOAuth = account.auth_type == Accounts.AUTH_TYPE_OAUTH
|| account.auth_type == Accounts.AUTH_TYPE_XAUTH;
final String consumerKey = account.consumer_key, consumerSecret = account.consumer_secret;
return isOAuth && isOfficialConsumerKeySecret(context, consumerKey, consumerSecret);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);

View File

@ -0,0 +1,262 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.model;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;
import android.os.Parcelable;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.ParseUtils;
import java.util.Comparator;
import java.util.Date;
import twitter4j.DirectMessage;
import twitter4j.User;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
import static org.mariotaku.twidere.util.content.ContentValuesUtils.getAsBoolean;
import static org.mariotaku.twidere.util.content.ContentValuesUtils.getAsLong;
public class ParcelableDirectMessage implements Parcelable, Comparable<ParcelableDirectMessage> {
public static final Parcelable.Creator<ParcelableDirectMessage> CREATOR = new Parcelable.Creator<ParcelableDirectMessage>() {
@Override
public ParcelableDirectMessage createFromParcel(final Parcel in) {
return new ParcelableDirectMessage(in);
}
@Override
public ParcelableDirectMessage[] newArray(final int size) {
return new ParcelableDirectMessage[size];
}
};
public static final Comparator<ParcelableDirectMessage> MESSAGE_ID_COMPARATOR = new Comparator<ParcelableDirectMessage>() {
@Override
public int compare(final ParcelableDirectMessage object1, final ParcelableDirectMessage object2) {
final long diff = object2.id - object1.id;
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int) diff;
}
};
public final long account_id, id, timestamp;
public final long sender_id, recipient_id;
public final boolean is_outgoing;
public final String text_html, text_plain, text_unescaped;
public final String sender_name, recipient_name, sender_screen_name, recipient_screen_name;
public final String sender_profile_image_url, recipient_profile_image_url;
public final String first_media;
public final ParcelableMedia[] media;
public ParcelableDirectMessage(final ContentValues values) {
text_plain = values.getAsString(DirectMessages.TEXT_PLAIN);
text_html = values.getAsString(DirectMessages.TEXT_HTML);
text_unescaped = toPlainText(text_html);
sender_screen_name = values.getAsString(DirectMessages.SENDER_SCREEN_NAME);
sender_profile_image_url = values.getAsString(DirectMessages.SENDER_PROFILE_IMAGE_URL);
sender_name = values.getAsString(DirectMessages.SENDER_NAME);
sender_id = getAsLong(values, DirectMessages.SENDER_ID, -1);
recipient_screen_name = values.getAsString(DirectMessages.RECIPIENT_SCREEN_NAME);
recipient_profile_image_url = values.getAsString(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL);
recipient_name = values.getAsString(DirectMessages.RECIPIENT_NAME);
recipient_id = getAsLong(values, DirectMessages.RECIPIENT_ID, -1);
timestamp = getAsLong(values, DirectMessages.MESSAGE_TIMESTAMP, -1);
id = getAsLong(values, DirectMessages.MESSAGE_ID, -1);
is_outgoing = getAsBoolean(values, DirectMessages.IS_OUTGOING, false);
account_id = getAsLong(values, DirectMessages.ACCOUNT_ID, -1);
media = ParcelableMedia.fromJSONString(values.getAsString(DirectMessages.MEDIA));
first_media = values.getAsString(DirectMessages.FIRST_MEDIA);
}
public ParcelableDirectMessage(final Cursor c, final CursorIndices idx) {
account_id = idx.account_id != -1 ? c.getLong(idx.account_id) : -1;
is_outgoing = idx.is_outgoing != -1 ? c.getShort(idx.is_outgoing) == 1 : null;
id = idx.message_id != -1 ? c.getLong(idx.message_id) : -1;
timestamp = idx.message_timestamp != -1 ? c.getLong(idx.message_timestamp) : -1;
sender_id = idx.sender_id != -1 ? c.getLong(idx.sender_id) : -1;
recipient_id = idx.recipient_id != -1 ? c.getLong(idx.recipient_id) : -1;
text_html = idx.text != -1 ? c.getString(idx.text) : null;
text_plain = idx.text_plain != -1 ? c.getString(idx.text_plain) : null;
text_unescaped = toPlainText(text_html);
sender_name = idx.sender_name != -1 ? c.getString(idx.sender_name) : null;
recipient_name = idx.recipient_name != -1 ? c.getString(idx.recipient_name) : null;
sender_screen_name = idx.sender_screen_name != -1 ? c.getString(idx.sender_screen_name) : null;
recipient_screen_name = idx.recipient_screen_name != -1 ? c.getString(idx.recipient_screen_name) : null;
sender_profile_image_url = idx.sender_profile_image_url != -1 ? c.getString(idx.sender_profile_image_url)
: null;
recipient_profile_image_url = idx.recipient_profile_image_url != -1 ? c
.getString(idx.recipient_profile_image_url) : null;
media = ParcelableMedia.fromJSONString(idx.media != -1 ? c.getString(idx.media) : null);
first_media = idx.first_media != -1 ? c.getString(idx.first_media) : null;
}
public ParcelableDirectMessage(final DirectMessage message, final long account_id, final boolean is_outgoing) {
this.account_id = account_id;
this.is_outgoing = is_outgoing;
final User sender = message.getSender(), recipient = message.getRecipient();
final String sender_profile_image_url_string = sender != null ? ParseUtils.parseString(sender
.getProfileImageUrlHttps()) : null;
final String recipient_profile_image_url_string = recipient != null ? ParseUtils.parseString(recipient
.getProfileImageUrlHttps()) : null;
id = message.getId();
timestamp = getTime(message.getCreatedAt());
sender_id = sender != null ? sender.getId() : -1;
recipient_id = recipient != null ? recipient.getId() : -1;
text_html = TwitterContentUtils.formatDirectMessageText(message);
text_plain = message.getText();
sender_name = sender != null ? sender.getName() : null;
recipient_name = recipient != null ? recipient.getName() : null;
sender_screen_name = sender != null ? sender.getScreenName() : null;
recipient_screen_name = recipient != null ? recipient.getScreenName() : null;
sender_profile_image_url = sender_profile_image_url_string;
recipient_profile_image_url = recipient_profile_image_url_string;
text_unescaped = toPlainText(text_html);
media = ParcelableMedia.fromEntities(message);
first_media = media != null && media.length > 0 ? media[0].url : null;
}
public ParcelableDirectMessage(final Parcel in) {
account_id = in.readLong();
id = in.readLong();
timestamp = in.readLong();
sender_id = in.readLong();
recipient_id = in.readLong();
is_outgoing = in.readInt() == 1;
text_html = in.readString();
text_plain = in.readString();
sender_name = in.readString();
recipient_name = in.readString();
sender_screen_name = in.readString();
recipient_screen_name = in.readString();
sender_profile_image_url = in.readString();
recipient_profile_image_url = in.readString();
text_unescaped = in.readString();
media = in.createTypedArray(ParcelableMedia.CREATOR);
first_media = media != null && media.length > 0 ? media[0].url : null;
}
@Override
public int compareTo(final ParcelableDirectMessage another) {
if (another == null) return 0;
final long diff = another.id - id;
if (diff > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (diff < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int) diff;
}
@Override
public int describeContents() {
return hashCode();
}
@Override
public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof ParcelableDirectMessage)) return false;
final ParcelableDirectMessage other = (ParcelableDirectMessage) obj;
if (account_id != other.account_id) return false;
if (id != other.id) return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (account_id ^ account_id >>> 32);
result = prime * result + (int) (id ^ id >>> 32);
return result;
}
@Override
public String toString() {
return "ParcelableDirectMessage{account_id=" + account_id + ", id=" + id + ", timestamp=" + timestamp
+ ", sender_id=" + sender_id + ", recipient_id=" + recipient_id + ", is_outgoing=" + is_outgoing
+ ", text_html=" + text_html + ", text_plain=" + text_plain + ", text_unescaped=" + text_unescaped
+ ", sender_name=" + sender_name + ", recipient_name=" + recipient_name + ", sender_screen_name="
+ sender_screen_name + ", recipient_screen_name=" + recipient_screen_name
+ ", sender_profile_image_url=" + sender_profile_image_url + ", recipient_profile_image_url="
+ recipient_profile_image_url + "}";
}
@Override
public void writeToParcel(final Parcel out, final int flags) {
out.writeLong(account_id);
out.writeLong(id);
out.writeLong(timestamp);
out.writeLong(sender_id);
out.writeLong(recipient_id);
out.writeInt(is_outgoing ? 1 : 0);
out.writeString(text_html);
out.writeString(text_plain);
out.writeString(sender_name);
out.writeString(recipient_name);
out.writeString(sender_screen_name);
out.writeString(recipient_screen_name);
out.writeString(sender_profile_image_url);
out.writeString(recipient_profile_image_url);
out.writeString(text_unescaped);
out.writeTypedArray(media, flags);
}
private static long getTime(final Date date) {
return date != null ? date.getTime() : 0;
}
public static class CursorIndices {
public final int account_id, message_id, message_timestamp, sender_name, sender_screen_name, text, text_plain,
recipient_name, recipient_screen_name, sender_profile_image_url, is_outgoing,
recipient_profile_image_url, sender_id, recipient_id, media, first_media;
public CursorIndices(final Cursor cursor) {
account_id = cursor.getColumnIndex(DirectMessages.ACCOUNT_ID);
message_id = cursor.getColumnIndex(DirectMessages.MESSAGE_ID);
message_timestamp = cursor.getColumnIndex(DirectMessages.MESSAGE_TIMESTAMP);
sender_id = cursor.getColumnIndex(DirectMessages.SENDER_ID);
recipient_id = cursor.getColumnIndex(DirectMessages.RECIPIENT_ID);
is_outgoing = cursor.getColumnIndex(DirectMessages.IS_OUTGOING);
text = cursor.getColumnIndex(DirectMessages.TEXT_HTML);
text_plain = cursor.getColumnIndex(DirectMessages.TEXT_PLAIN);
sender_name = cursor.getColumnIndex(DirectMessages.SENDER_NAME);
recipient_name = cursor.getColumnIndex(DirectMessages.RECIPIENT_NAME);
sender_screen_name = cursor.getColumnIndex(DirectMessages.SENDER_SCREEN_NAME);
recipient_screen_name = cursor.getColumnIndex(DirectMessages.RECIPIENT_SCREEN_NAME);
sender_profile_image_url = cursor.getColumnIndex(DirectMessages.SENDER_PROFILE_IMAGE_URL);
recipient_profile_image_url = cursor.getColumnIndex(DirectMessages.RECIPIENT_PROFILE_IMAGE_URL);
media = cursor.getColumnIndex(DirectMessages.MEDIA);
first_media = cursor.getColumnIndex(DirectMessages.FIRST_MEDIA);
}
}
}

View File

@ -22,6 +22,7 @@ import twitter4j.MediaEntity;
import twitter4j.MediaEntity.Size;
import twitter4j.URLEntity;
@SuppressWarnings("unused")
public class ParcelableMedia implements Parcelable, JSONParcelable {
public static final int TYPE_IMAGE = 1;

View File

@ -31,8 +31,11 @@ import org.json.JSONObject;
import org.mariotaku.jsonserializer.JSONParcel;
import org.mariotaku.jsonserializer.JSONParcelable;
import org.mariotaku.jsonserializer.JSONSerializer;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.content.ContentValuesUtils;
import java.util.Arrays;
import java.util.Comparator;
@ -46,13 +49,7 @@ import twitter4j.CardEntity.UserValue;
import twitter4j.Status;
import twitter4j.User;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
import static org.mariotaku.twidere.util.Utils.formatStatusText;
import static org.mariotaku.twidere.util.Utils.getInReplyToName;
import static org.mariotaku.twidere.util.content.ContentValuesUtils.getAsBoolean;
import static org.mariotaku.twidere.util.content.ContentValuesUtils.getAsInteger;
import static org.mariotaku.twidere.util.content.ContentValuesUtils.getAsLong;
@SuppressWarnings("unused")
public class ParcelableStatus implements TwidereParcelable, Comparable<ParcelableStatus> {
public static final Parcelable.Creator<ParcelableStatus> CREATOR = new Parcelable.Creator<ParcelableStatus>() {
@ -121,41 +118,41 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
public final ParcelableCardEntity card;
public ParcelableStatus(final ContentValues values) {
id = getAsLong(values, Statuses.STATUS_ID, -1);
account_id = getAsLong(values, Statuses.ACCOUNT_ID, -1);
timestamp = getAsLong(values, Statuses.STATUS_TIMESTAMP, -1);
user_id = getAsLong(values, Statuses.USER_ID, -1);
retweet_id = getAsLong(values, Statuses.RETWEET_ID, -1);
retweet_timestamp = getAsLong(values, Statuses.RETWEET_TIMESTAMP, -1);
retweeted_by_id = getAsLong(values, Statuses.RETWEETED_BY_USER_ID, -1);
id = ContentValuesUtils.getAsLong(values, Statuses.STATUS_ID, -1);
account_id = ContentValuesUtils.getAsLong(values, Statuses.ACCOUNT_ID, -1);
timestamp = ContentValuesUtils.getAsLong(values, Statuses.STATUS_TIMESTAMP, -1);
user_id = ContentValuesUtils.getAsLong(values, Statuses.USER_ID, -1);
retweet_id = ContentValuesUtils.getAsLong(values, Statuses.RETWEET_ID, -1);
retweet_timestamp = ContentValuesUtils.getAsLong(values, Statuses.RETWEET_TIMESTAMP, -1);
retweeted_by_id = ContentValuesUtils.getAsLong(values, Statuses.RETWEETED_BY_USER_ID, -1);
user_name = values.getAsString(Statuses.USER_NAME);
user_screen_name = values.getAsString(Statuses.USER_SCREEN_NAME);
text_html = values.getAsString(Statuses.TEXT_HTML);
text_plain = values.getAsString(Statuses.TEXT_PLAIN);
user_profile_image_url = values.getAsString(Statuses.USER_PROFILE_IMAGE_URL);
is_favorite = getAsBoolean(values, Statuses.IS_FAVORITE, false);
is_retweet = getAsBoolean(values, Statuses.IS_RETWEET, false);
is_gap = getAsBoolean(values, Statuses.IS_GAP, false);
is_favorite = ContentValuesUtils.getAsBoolean(values, Statuses.IS_FAVORITE, false);
is_retweet = ContentValuesUtils.getAsBoolean(values, Statuses.IS_RETWEET, false);
is_gap = ContentValuesUtils.getAsBoolean(values, Statuses.IS_GAP, false);
location = ParcelableLocation.fromString(values.getAsString(Statuses.LOCATION));
user_is_protected = getAsBoolean(values, Statuses.IS_PROTECTED, false);
user_is_verified = getAsBoolean(values, Statuses.IS_VERIFIED, false);
in_reply_to_status_id = getAsLong(values, Statuses.IN_REPLY_TO_STATUS_ID, -1);
in_reply_to_user_id = getAsLong(values, Statuses.IN_REPLY_TO_USER_ID, -1);
user_is_protected = ContentValuesUtils.getAsBoolean(values, Statuses.IS_PROTECTED, false);
user_is_verified = ContentValuesUtils.getAsBoolean(values, Statuses.IS_VERIFIED, false);
in_reply_to_status_id = ContentValuesUtils.getAsLong(values, Statuses.IN_REPLY_TO_STATUS_ID, -1);
in_reply_to_user_id = ContentValuesUtils.getAsLong(values, Statuses.IN_REPLY_TO_USER_ID, -1);
in_reply_to_name = values.getAsString(Statuses.IN_REPLY_TO_USER_NAME);
in_reply_to_screen_name = values.getAsString(Statuses.IN_REPLY_TO_USER_SCREEN_NAME);
my_retweet_id = getAsLong(values, Statuses.MY_RETWEET_ID, -1);
my_retweet_id = ContentValuesUtils.getAsLong(values, Statuses.MY_RETWEET_ID, -1);
retweeted_by_name = values.getAsString(Statuses.RETWEETED_BY_USER_NAME);
retweeted_by_screen_name = values.getAsString(Statuses.RETWEETED_BY_USER_SCREEN_NAME);
retweeted_by_profile_image = values.getAsString(Statuses.RETWEETED_BY_USER_PROFILE_IMAGE);
source = values.getAsString(Statuses.SOURCE);
retweet_count = getAsInteger(values, Statuses.RETWEET_COUNT, 0);
favorite_count = getAsInteger(values, Statuses.FAVORITE_COUNT, 0);
reply_count = getAsInteger(values, Statuses.REPLY_COUNT, 0);
descendent_reply_count = getAsInteger(values, Statuses.DESCENDENT_REPLY_COUNT, 0);
retweet_count = ContentValuesUtils.getAsInteger(values, Statuses.RETWEET_COUNT, 0);
favorite_count = ContentValuesUtils.getAsInteger(values, Statuses.FAVORITE_COUNT, 0);
reply_count = ContentValuesUtils.getAsInteger(values, Statuses.REPLY_COUNT, 0);
descendent_reply_count = ContentValuesUtils.getAsInteger(values, Statuses.DESCENDENT_REPLY_COUNT, 0);
text_unescaped = values.getAsString(Statuses.TEXT_UNESCAPED);
media = ParcelableMedia.fromJSONString(values.getAsString(Statuses.MEDIA));
is_possibly_sensitive = getAsBoolean(values, Statuses.IS_POSSIBLY_SENSITIVE, false);
user_is_following = getAsBoolean(values, Statuses.IS_FOLLOWING, false);
is_possibly_sensitive = ContentValuesUtils.getAsBoolean(values, Statuses.IS_POSSIBLY_SENSITIVE, false);
user_is_following = ContentValuesUtils.getAsBoolean(values, Statuses.IS_FOLLOWING, false);
mentions = ParcelableUserMention.fromJSONString(values.getAsString(Statuses.MENTIONS));
first_media = values.getAsString(Statuses.FIRST_MEDIA);
card = ParcelableCardEntity.fromJSONString(values.getAsString(Statuses.CARD));
@ -353,21 +350,21 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
user_is_protected = user.isProtected();
user_is_verified = user.isVerified();
user_is_following = user.isFollowing();
text_html = formatStatusText(status);
text_html = TwitterContentUtils.formatStatusText(status);
media = ParcelableMedia.fromEntities(status);
text_plain = status.getText();
retweet_count = status.getRetweetCount();
favorite_count = status.getFavoriteCount();
reply_count = status.getReplyCount();
descendent_reply_count = status.getDescendentReplyCount();
in_reply_to_name = getInReplyToName(status);
in_reply_to_name = TwitterContentUtils.getInReplyToName(status);
in_reply_to_screen_name = status.getInReplyToScreenName();
in_reply_to_status_id = status.getInReplyToStatusId();
in_reply_to_user_id = status.getInReplyToUserId();
source = status.getSource();
location = new ParcelableLocation(status.getGeoLocation());
is_favorite = status.isFavorited();
text_unescaped = toPlainText(text_html);
text_unescaped = HtmlEscapeHelper.toPlainText(text_html);
my_retweet_id = retweeted_by_id == account_id ? id : status.getCurrentUserRetweet();
is_possibly_sensitive = status.isPossiblySensitive();
mentions = ParcelableUserMention.fromUserMentionEntities(status.getUserMentionEntities());
@ -762,23 +759,21 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
public ParcelableValueItem(JSONParcel in) {
this.name = in.readString("name");
this.type = in.readString("type");
if ("STRING".equals(type)) {
value = in.readString("value");
} else if ("IMAGE".equals(type)) {
value = in.readParcelable("value", ParcelableImageValue.JSON_CREATOR);
} else if ("USER".equals(type)) {
value = in.readParcelable("value", ParcelableUserValue.JSON_CREATOR);
} else {
throw new UnsupportedOperationException();
switch (type) {
case "STRING":
value = in.readString("value");
break;
case "IMAGE":
value = in.readParcelable("value", ParcelableImageValue.JSON_CREATOR);
break;
case "USER":
value = in.readParcelable("value", ParcelableUserValue.JSON_CREATOR);
break;
default:
throw new UnsupportedOperationException();
}
}
public ParcelableValueItem(String name, String type, Object value) {
this.name = name;
this.type = type;
this.value = value;
}
public ParcelableValueItem(Parcel in) {
this.name = in.readString();
this.type = in.readString();
@ -788,14 +783,19 @@ public class ParcelableStatus implements TwidereParcelable, Comparable<Parcelabl
public ParcelableValueItem(BindingValue bindingValue) {
name = bindingValue.getName();
type = bindingValue.getType();
if ("STRING".equals(type)) {
value = ((StringValue) bindingValue).getValue();
} else if ("IMAGE".equals(type)) {
value = new ParcelableImageValue((ImageValue) bindingValue);
} else if ("USER".equals(type)) {
value = new ParcelableUserValue((UserValue) bindingValue);
} else {
value = null;
switch (type) {
case "STRING":
value = ((StringValue) bindingValue).getValue();
break;
case "IMAGE":
value = new ParcelableImageValue((ImageValue) bindingValue);
break;
case "USER":
value = new ParcelableUserValue((UserValue) bindingValue);
break;
default:
value = null;
break;
}
}

View File

@ -28,17 +28,15 @@ import android.support.annotation.Nullable;
import org.mariotaku.jsonserializer.JSONParcel;
import org.mariotaku.jsonserializer.JSONParcelable;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.util.HtmlEscapeHelper;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.ParseUtils;
import twitter4j.URLEntity;
import twitter4j.User;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
import static org.mariotaku.twidere.util.Utils.formatExpandedUserDescription;
import static org.mariotaku.twidere.util.Utils.formatUserDescription;
public class ParcelableUser implements TwidereParcelable, Comparable<ParcelableUser> {
public static final Parcelable.Creator<ParcelableUser> CREATOR = new Parcelable.Creator<ParcelableUser>() {
@ -139,7 +137,7 @@ public class ParcelableUser implements TwidereParcelable, Comparable<ParcelableU
url_expanded = indices.url_expanded != -1 ? cursor.getString(indices.url_expanded) : null;
profile_banner_url = indices.profile_banner_url != -1 ? cursor.getString(indices.profile_banner_url) : null;
is_cache = true;
description_unescaped = toPlainText(description_html);
description_unescaped = HtmlEscapeHelper.toPlainText(description_html);
is_following = indices.is_following != -1 && cursor.getInt(indices.is_following) == 1;
background_color = indices.background_color != -1 ? cursor.getInt(indices.background_color) : 0;
link_color = indices.link_color != -1 ? cursor.getInt(indices.link_color) : 0;
@ -223,9 +221,9 @@ public class ParcelableUser implements TwidereParcelable, Comparable<ParcelableU
name = user.getName();
screen_name = user.getScreenName();
description_plain = user.getDescription();
description_html = formatUserDescription(user);
description_expanded = formatExpandedUserDescription(user);
description_unescaped = toPlainText(description_html);
description_html = TwitterContentUtils.formatUserDescription(user);
description_expanded = TwitterContentUtils.formatExpandedUserDescription(user);
description_unescaped = HtmlEscapeHelper.toPlainText(description_html);
location = user.getLocation();
profile_image_url = ParseUtils.parseString(user.getProfileImageUrlHttps());
profile_banner_url = user.getProfileBannerImageUrl();

View File

@ -23,7 +23,8 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.provider.BaseColumns;
public interface TweetStore {
@SuppressWarnings("unused")
public interface TwidereDataStore {
public static final String AUTHORITY = "twidere";

View File

@ -34,15 +34,15 @@ import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserMention;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.CachedRelationships;
import org.mariotaku.twidere.provider.TweetStore.CachedTrends;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
import org.mariotaku.twidere.provider.TweetStore.Drafts;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.provider.TweetStore.SavedSearches;
import org.mariotaku.twidere.provider.TweetStore.Statuses;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts;
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.provider.TwidereDataStore.SavedSearches;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
import java.util.ArrayList;
import java.util.List;
@ -162,8 +162,8 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(CachedUsers.LISTED_COUNT, user.getListedCount());
values.put(CachedUsers.LOCATION, user.getLocation());
values.put(CachedUsers.DESCRIPTION_PLAIN, user.getDescription());
values.put(CachedUsers.DESCRIPTION_HTML, Utils.formatUserDescription(user));
values.put(CachedUsers.DESCRIPTION_EXPANDED, Utils.formatExpandedUserDescription(user));
values.put(CachedUsers.DESCRIPTION_HTML, TwitterContentUtils.formatUserDescription(user));
values.put(CachedUsers.DESCRIPTION_EXPANDED, TwitterContentUtils.formatExpandedUserDescription(user));
values.put(CachedUsers.URL, url);
if (url != null && urls != null && urls.length > 0) {
values.put(CachedUsers.URL_EXPANDED, ParseUtils.parseString(urls[0].getExpandedURL()));
@ -187,7 +187,7 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(DirectMessages.MESSAGE_TIMESTAMP, message.getCreatedAt().getTime());
values.put(DirectMessages.SENDER_ID, sender.getId());
values.put(DirectMessages.RECIPIENT_ID, recipient.getId());
final String text_html = Utils.formatDirectMessageText(message);
final String text_html = TwitterContentUtils.formatDirectMessageText(message);
values.put(DirectMessages.TEXT_HTML, text_html);
values.put(DirectMessages.TEXT_PLAIN, message.getText());
values.put(DirectMessages.TEXT_UNESCAPED, toPlainText(text_html));
@ -262,7 +262,7 @@ public final class ContentValuesCreator implements TwidereConstants {
final ContentValues values = new ContentValues();
values.put(Drafts.ACTION_TYPE, Drafts.ACTION_SEND_DIRECT_MESSAGE);
values.put(Drafts.TEXT, text);
values.put(Drafts.ACCOUNT_IDS, ArrayUtils.toString(new long[]{accountId}, ',', false));
values.put(Drafts.ACCOUNT_IDS, TwidereArrayUtils.toString(new long[]{accountId}, ',', false));
values.put(Drafts.TIMESTAMP, System.currentTimeMillis());
if (imageUri != null) {
final ParcelableMediaUpdate[] mediaArray = {new ParcelableMediaUpdate(imageUri, 0)};
@ -335,7 +335,7 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.IS_VERIFIED, user.isVerified());
values.put(Statuses.USER_PROFILE_IMAGE_URL, profileImageUrl);
values.put(CachedUsers.IS_FOLLOWING, user.isFollowing());
final String text_html = Utils.formatStatusText(status);
final String text_html = TwitterContentUtils.formatStatusText(status);
values.put(Statuses.TEXT_HTML, text_html);
values.put(Statuses.TEXT_PLAIN, status.getText());
values.put(Statuses.TEXT_UNESCAPED, toPlainText(text_html));
@ -344,7 +344,7 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.DESCENDENT_REPLY_COUNT, status.getDescendentReplyCount());
values.put(Statuses.IN_REPLY_TO_STATUS_ID, status.getInReplyToStatusId());
values.put(Statuses.IN_REPLY_TO_USER_ID, status.getInReplyToUserId());
values.put(Statuses.IN_REPLY_TO_USER_NAME, Utils.getInReplyToName(status));
values.put(Statuses.IN_REPLY_TO_USER_NAME, TwitterContentUtils.getInReplyToName(status));
values.put(Statuses.IN_REPLY_TO_USER_SCREEN_NAME, status.getInReplyToScreenName());
values.put(Statuses.SOURCE, status.getSource());
values.put(Statuses.IS_POSSIBLY_SENSITIVE, status.isPossiblySensitive());
@ -375,7 +375,7 @@ public final class ContentValuesCreator implements TwidereConstants {
final ContentValues values = new ContentValues();
values.put(Drafts.ACTION_TYPE, Drafts.ACTION_UPDATE_STATUS);
values.put(Drafts.TEXT, status.text);
values.put(Drafts.ACCOUNT_IDS, ArrayUtils.toString(accountIds, ',', false));
values.put(Drafts.ACCOUNT_IDS, TwidereArrayUtils.toString(accountIds, ',', false));
values.put(Drafts.IN_REPLY_TO_STATUS_ID, status.in_reply_to_status_id);
values.put(Drafts.LOCATION, ParcelableLocation.toString(status.location));
values.put(Drafts.IS_POSSIBLY_SENSITIVE, status.is_possibly_sensitive);

View File

@ -0,0 +1,217 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.escape;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toHtml;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.unescape;
public class HtmlBuilder {
private final String source;
private final int[] codePoints;
private final int codePointsLength;
private final boolean throwExceptions, sourceIsEscaped, shouldReEscape;
private final ArrayList<LinkSpec> links = new ArrayList<>();
public HtmlBuilder(final String source, final boolean strict, final boolean sourceIsEscaped,
final boolean shouldReEscape) {
if (source == null) throw new NullPointerException();
this.source = source;
final int length = source.length();
final int[] codepointsTemp = new int[length];
int codePointsLength = 0;
for (int offset = 0; offset < length; ) {
final int codepoint = source.codePointAt(offset);
codepointsTemp[codePointsLength++] = codepoint;
offset += Character.charCount(codepoint);
}
codePoints = new int[codePointsLength];
System.arraycopy(codepointsTemp, 0, codePoints, 0, codePointsLength);
throwExceptions = strict;
this.sourceIsEscaped = sourceIsEscaped;
this.shouldReEscape = shouldReEscape;
this.codePointsLength = codePointsLength;
}
public boolean addLink(final String link, final String display, final int start, final int end) {
return addLink(link, display, start, end, false);
}
public boolean addLink(final String link, final String display, final int start, final int end,
final boolean display_is_html) {
if (start < 0 || end < 0 || start > end || end > codePointsLength) {
final String message = String.format(Locale.US, "text:%s, length:%d, start:%d, end:%d", source,
codePointsLength, start, end);
if (throwExceptions) throw new StringIndexOutOfBoundsException(message);
return false;
}
if (hasLink(start, end)) {
final String message = String.format(Locale.US,
"link already added in this range! text:%s, link:%s, display:%s, start:%d, end:%d", source, link,
display, start, end);
if (throwExceptions) throw new IllegalArgumentException(message);
return false;
}
return links.add(new LinkSpec(link, display, start, end, display_is_html));
}
public String build() {
if (links.isEmpty()) return escapeSource(source);
Collections.sort(links);
final StringBuilder builder = new StringBuilder();
final int linksSize = links.size();
for (int i = 0; i < linksSize; i++) {
final LinkSpec spec = links.get(i);
if (spec == null) {
continue;
}
final int start = spec.start, end = spec.end;
if (i == 0) {
if (start >= 0 && start <= codePointsLength) {
appendSource(builder, 0, start);
}
} else if (i > 0) {
final int lastEnd = links.get(i - 1).end;
if (lastEnd >= 0 && lastEnd <= start && start <= codePointsLength) {
appendSource(builder, lastEnd, start);
}
}
builder.append("<a href=\"");
builder.append(spec.link);
builder.append("\">");
if (start >= 0 && start <= end && end <= codePointsLength) {
builder.append(!isEmpty(spec.display) ? spec.display_is_html ? spec.display : toHtml(spec.display)
: spec.link);
}
builder.append("</a>");
if (i == linksSize - 1 && end >= 0 && end <= codePointsLength) {
appendSource(builder, end, codePointsLength);
}
}
return builder.toString();
}
public boolean hasLink(final int start, final int end) {
for (final LinkSpec spec : links) {
if (start >= spec.start && start <= spec.end || end >= spec.start && end <= spec.end)
return true;
}
return false;
}
@Override
public String toString() {
return "HtmlBuilder{orig=" + source + ", codePoints=" + Arrays.toString(codePoints) + ", string_length="
+ codePointsLength + ", throw_exceptions=" + throwExceptions + ", source_is_escaped=" + sourceIsEscaped
+ ", should_re_escape=" + shouldReEscape + ", links=" + links + "}";
}
private void appendSource(final StringBuilder builder, final int start, final int end) {
if (sourceIsEscaped == shouldReEscape) {
for (int i = start; i < end; i++) {
builder.appendCodePoint(codePoints[i]);
}
} else if (shouldReEscape) {
builder.append(escape(subString(start, end)));
} else {
builder.append(unescape(subString(start, end)));
}
}
private String escapeSource(final String source) {
if (sourceIsEscaped == shouldReEscape) return source;
return shouldReEscape ? escape(source) : unescape(source);
}
private String subString(final int start, final int end) {
final StringBuilder sb = new StringBuilder();
for (int i = start; i < end; i++) {
sb.appendCodePoint(codePoints[i]);
}
return sb.toString();
}
static final class LinkSpec implements Comparable<LinkSpec> {
final String link, display;
final int start, end;
final boolean display_is_html;
LinkSpec(final String link, final String display, final int start, final int end, final boolean display_is_html) {
this.link = link;
this.display = display;
this.start = start;
this.end = end;
this.display_is_html = display_is_html;
}
@Override
public int compareTo(@NonNull final LinkSpec that) {
return start - that.start;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof LinkSpec)) return false;
final LinkSpec other = (LinkSpec) obj;
if (display == null) {
if (other.display != null) return false;
} else if (!display.equals(other.display)) return false;
if (display_is_html != other.display_is_html) return false;
if (end != other.end) return false;
if (link == null) {
if (other.link != null) return false;
} else if (!link.equals(other.link)) return false;
if (start != other.start) return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (display == null ? 0 : display.hashCode());
result = prime * result + (display_is_html ? 1231 : 1237);
result = prime * result + end;
result = prime * result + (link == null ? 0 : link.hashCode());
result = prime * result + start;
return result;
}
@Override
public String toString() {
return "LinkSpec{link=" + link + ", display=" + display + ", start=" + start + ", end=" + end
+ ", display_is_html=" + display_is_html + "}";
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlLinkExtractor {
private final Pattern patternTag, patternLink;
private static final String HTML_A_TAG_PATTERN = "(?i)<a([^>]+)>(.+?)</a>";
private static final String HTML_A_HREF_TAG_PATTERN = "\\s*(?i)href\\s*=\\s*(\"([^\"]*\")|'[^']*'|([^'\">\\s]+))";
public HtmlLinkExtractor() {
patternTag = Pattern.compile(HTML_A_TAG_PATTERN);
patternLink = Pattern.compile(HTML_A_HREF_TAG_PATTERN);
}
/**
* Validate html with regular expression
*
* @param html html content for validation
* @return Vector links and link text
*/
public Vector<HtmlLink> grabLinks(final String html) {
final Vector<HtmlLink> result = new Vector<HtmlLink>();
final Matcher matcherTag = patternTag.matcher(html);
while (matcherTag.find()) {
final String href = matcherTag.group(1); // href
final String linkText = matcherTag.group(2); // link text
final Matcher matcherLink = patternLink.matcher(href);
while (matcherLink.find()) {
final String link = matcherLink.group(1); // link
final HtmlLink obj = new HtmlLink(link, linkText);
result.add(obj);
}
}
return result;
}
public static class HtmlLink {
private final String link;
private final String text;
private HtmlLink(final String link, final String text) {
this.link = replaceInvalidChar(link);
this.text = text;
}
public String getLink() {
return link;
}
public String getLinkText() {
return text;
}
private static String replaceInvalidChar(String link) {
link = link.replaceAll("'", "");
link = link.replaceAll("\"", "");
return link;
}
}
}

View File

@ -19,24 +19,15 @@
package org.mariotaku.twidere.util;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.util.HtmlLinkExtractor.HtmlLink;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -50,7 +41,6 @@ import twitter4j.http.HttpParameter;
import twitter4j.http.HttpResponse;
import static android.text.TextUtils.isEmpty;
import static org.mariotaku.twidere.util.Utils.matcherGroup;
public class MediaPreviewUtils {
@ -193,52 +183,6 @@ public class MediaPreviewUtils {
private static final String URL_PHOTOZOU_PHOTO_INFO = "https://api.photozou.jp/rest/photo_info.json";
public static void addToLinearLayout(final LinearLayout container, final ImageLoaderWrapper loader,
final List<ParcelableMedia> mediaList, final long accountId,
final int maxColumnCount, final OnMediaClickListener mediaClickListener) {
if (container.getOrientation() != LinearLayout.VERTICAL)
throw new IllegalArgumentException();
final Context context = container.getContext();
final ImageLoadingHandler loadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
final LayoutInflater inflater = LayoutInflater.from(context);
final ListIterator<ParcelableMedia> iterator = mediaList.listIterator();
final int imageCount = mediaList.size();
final double imageCountSqrt = Math.sqrt(imageCount);
final int bestColumnCount = imageCountSqrt % 1 == 0 ? (int) imageCountSqrt : maxColumnCount;
final int firstColumn = imageCount % bestColumnCount, fullRowCount = imageCount / bestColumnCount;
final int rowCount = fullRowCount + (firstColumn > 0 ? 1 : 0);
final View.OnClickListener clickListener = new ImageGridClickListener(mediaClickListener, accountId);
container.setMotionEventSplittingEnabled(false);
for (int currentRow = 0; currentRow < rowCount; currentRow++) {
final LinearLayout rowContainer = new LinearLayout(context);
rowContainer.setOrientation(LinearLayout.HORIZONTAL);
rowContainer.setMotionEventSplittingEnabled(false);
container.addView(rowContainer, LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
final int columnCount = currentRow == 0 && firstColumn > 0 ? firstColumn : bestColumnCount;
for (int currentColumn = 0; currentColumn < columnCount; currentColumn++) {
final ParcelableMedia media = iterator.next();
final View item = inflater.inflate(R.layout.grid_item_media_preview, rowContainer, false);
item.setTag(media);
if (mediaClickListener != null) {
item.setOnClickListener(clickListener);
}
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) item.getLayoutParams();
lp.weight = 1.0f;
rowContainer.addView(item, lp);
final ImageView imageView = (ImageView) item.findViewById(R.id.media_preview_item);
loader.displayPreviewImage(imageView, media.url, loadingHandler);
}
}
}
public static void addToLinearLayout(final LinearLayout container, final ImageLoaderWrapper loader,
final ParcelableMedia[] mediaArray, final long accountId,
final int maxColumnCount, final OnMediaClickListener listener) {
addToLinearLayout(container, loader, Arrays.asList(mediaArray), accountId, maxColumnCount,
listener);
}
public static ParcelableMedia getAllAvailableImage(final String link, final boolean fullImage) {
try {
return getAllAvailableImage(link, fullImage, null);
@ -250,43 +194,47 @@ public class MediaPreviewUtils {
public static ParcelableMedia getAllAvailableImage(final String link, final boolean fullImage,
final HttpClientWrapper client) throws IOException {
if (link == null) return null;
StrictModeUtils.checkLengthyOperation();
Matcher m;
m = PATTERN_TWITTER_IMAGES.matcher(link);
if (m.matches()) return getTwitterImage(link, fullImage);
m = PATTERN_INSTAGRAM.matcher(link);
if (m.matches())
return getInstagramImage(matcherGroup(m, INSTAGRAM_GROUP_ID), link, fullImage);
return getInstagramImage(RegexUtils.matcherGroup(m, INSTAGRAM_GROUP_ID), link, fullImage);
m = PATTERN_GOOGLE_IMAGES.matcher(link);
if (m.matches())
return getGoogleImage(matcherGroup(m, GOOGLE_IMAGES_GROUP_SERVER), matcherGroup(m, GOOGLE_IMAGES_GROUP_ID),
return getGoogleImage(RegexUtils.matcherGroup(m, GOOGLE_IMAGES_GROUP_SERVER), RegexUtils.matcherGroup(m, GOOGLE_IMAGES_GROUP_ID),
fullImage);
m = PATTERN_GOOGLE_PROXY_IMAGES.matcher(link);
if (m.matches())
return getGoogleProxyImage(matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_SERVER),
matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_ID), fullImage);
return getGoogleProxyImage(RegexUtils.matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_SERVER),
RegexUtils.matcherGroup(m, GOOGLE_PROXY_IMAGES_GROUP_ID), fullImage);
m = PATTERN_SINA_WEIBO_IMAGES.matcher(link);
if (m.matches()) return getSinaWeiboImage(link, fullImage);
m = PATTERN_TWITPIC.matcher(link);
if (m.matches()) return getTwitpicImage(matcherGroup(m, TWITPIC_GROUP_ID), link, fullImage);
if (m.matches())
return getTwitpicImage(RegexUtils.matcherGroup(m, TWITPIC_GROUP_ID), link, fullImage);
m = PATTERN_IMGUR.matcher(link);
if (m.matches()) return getImgurImage(matcherGroup(m, IMGUR_GROUP_ID), link, fullImage);
if (m.matches())
return getImgurImage(RegexUtils.matcherGroup(m, IMGUR_GROUP_ID), link, fullImage);
m = PATTERN_IMGLY.matcher(link);
if (m.matches()) return getImglyImage(matcherGroup(m, IMGLY_GROUP_ID), link, fullImage);
if (m.matches())
return getImglyImage(RegexUtils.matcherGroup(m, IMGLY_GROUP_ID), link, fullImage);
m = PATTERN_YFROG.matcher(link);
if (m.matches()) return getYfrogImage(matcherGroup(m, YFROG_GROUP_ID), link, fullImage);
if (m.matches())
return getYfrogImage(RegexUtils.matcherGroup(m, YFROG_GROUP_ID), link, fullImage);
m = PATTERN_LOCKERZ.matcher(link);
if (m.matches()) return getLockerzAndPlixiImage(link, fullImage);
m = PATTERN_PLIXI.matcher(link);
if (m.matches()) return getLockerzAndPlixiImage(link, fullImage);
m = PATTERN_TWITGOO.matcher(link);
if (m.matches()) return getTwitgooImage(matcherGroup(m, TWITGOO_GROUP_ID), link, fullImage);
if (m.matches())
return getTwitgooImage(RegexUtils.matcherGroup(m, TWITGOO_GROUP_ID), link, fullImage);
m = PATTERN_MOBYPICTURE.matcher(link);
if (m.matches())
return getMobyPictureImage(matcherGroup(m, MOBYPICTURE_GROUP_ID), link, fullImage);
return getMobyPictureImage(RegexUtils.matcherGroup(m, MOBYPICTURE_GROUP_ID), link, fullImage);
m = PATTERN_PHOTOZOU.matcher(link);
if (m.matches())
return getPhotozouImage(client, matcherGroup(m, PHOTOZOU_GROUP_ID), link, fullImage);
return getPhotozouImage(client, RegexUtils.matcherGroup(m, PHOTOZOU_GROUP_ID), link, fullImage);
return null;
}
@ -461,24 +409,4 @@ public class MediaPreviewUtils {
}
public interface OnMediaClickListener {
void onMediaClick(View view, ParcelableMedia media, long accountId);
}
private static class ImageGridClickListener implements View.OnClickListener {
private final OnMediaClickListener mListener;
private final long mAccountId;
ImageGridClickListener(final OnMediaClickListener listener, final long accountId) {
mListener = listener;
mAccountId = accountId;
}
@Override
public void onClick(final View v) {
if (mListener == null) return;
mListener.onMediaClick(v, (ParcelableMedia) v.getTag(), mAccountId);
}
}
}

View File

@ -0,0 +1,205 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.constant.IntentConstants;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import static android.text.TextUtils.isEmpty;
public final class ParseUtils {
public static String bundleToJSON(final Bundle args) {
final Set<String> keys = args.keySet();
final JSONObject json = new JSONObject();
for (final String key : keys) {
final Object value = args.get(key);
if (value == null) {
continue;
}
try {
if (value instanceof Boolean) {
json.put(key, args.getBoolean(key));
} else if (value instanceof Integer) {
json.put(key, args.getInt(key));
} else if (value instanceof Long) {
json.put(key, args.getLong(key));
} else if (value instanceof String) {
json.put(key, args.getString(key));
} else {
Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
}
} catch (final JSONException e) {
e.printStackTrace();
}
}
return json.toString();
}
public static Bundle jsonToBundle(final String string) {
final Bundle bundle = new Bundle();
if (string == null) return bundle;
try {
final JSONObject json = new JSONObject(string);
final Iterator<?> it = json.keys();
while (it.hasNext()) {
final Object key_obj = it.next();
if (key_obj == null) {
continue;
}
final String key = key_obj.toString();
final Object value = json.get(key);
if (value instanceof Boolean) {
bundle.putBoolean(key, json.optBoolean(key));
} else if (value instanceof Integer) {
// Simple workaround for account_id
if (shouldPutLong(key)) {
bundle.putLong(key, json.optLong(key));
} else {
bundle.putInt(key, json.optInt(key));
}
} else if (value instanceof Long) {
bundle.putLong(key, json.optLong(key));
} else if (value instanceof String) {
bundle.putString(key, json.optString(key));
} else {
Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
}
}
} catch (final JSONException e) {
e.printStackTrace();
} catch (final ClassCastException e) {
e.printStackTrace();
}
return bundle;
}
public static double parseDouble(final String source) {
return parseDouble(source, -1);
}
public static double parseDouble(final String source, final double def) {
if (source == null) return def;
try {
return Double.parseDouble(source);
} catch (final NumberFormatException e) {
// Wrong number format? Ignore them.
}
return def;
}
public static float parseFloat(final String source) {
return parseFloat(source, -1);
}
public static float parseFloat(final String source, final float def) {
if (source == null) return def;
try {
return Float.parseFloat(source);
} catch (final NumberFormatException e) {
// Wrong number format? Ignore them.
}
return def;
}
public static int parseInt(final String source) {
return parseInt(source, -1);
}
public static int parseInt(final String source, final int def) {
if (source == null) return def;
try {
return Integer.valueOf(source);
} catch (final NumberFormatException e) {
// Wrong number format? Ignore them.
}
return def;
}
public static long parseLong(final String source) {
return parseLong(source, -1);
}
public static long parseLong(final String source, final long def) {
if (source == null) return def;
try {
return Long.parseLong(source);
} catch (final NumberFormatException e) {
// Wrong number format? Ignore them.
}
return def;
}
public static String parseString(final Object object) {
return parseString(object, null);
}
public static String parseString(final Object object, final String def) {
if (object == null) return def;
return String.valueOf(object);
}
public static URI parseURI(final String uriString) {
if (uriString == null) return null;
try {
return new URI(uriString);
} catch (final URISyntaxException e) {
// This should not happen.
}
return null;
}
public static URL parseURL(final String urlString) {
if (urlString == null) return null;
try {
return new URL(urlString);
} catch (final MalformedURLException e) {
// This should not happen.
}
return null;
}
private static boolean shouldPutLong(final String key) {
return IntentConstants.EXTRA_ACCOUNT_ID.equals(key) || IntentConstants.EXTRA_USER_ID.equals(key) || IntentConstants.EXTRA_STATUS_ID.equals(key)
|| IntentConstants.EXTRA_LIST_ID.equals(key);
}
public static int parseColor(String str, int def) {
if (isEmpty(str)) return def;
try {
return Color.parseColor(str);
} catch (IllegalArgumentException e) {
return def;
}
}
}

View File

@ -0,0 +1,54 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import java.util.regex.Matcher;
/**
* Created by mariotaku on 15/1/11.
*/
public class RegexUtils {
public static int matcherEnd(final Matcher matcher, final int group) {
try {
return matcher.end(group);
} catch (final IllegalStateException e) {
// Ignore.
}
return -1;
}
public static String matcherGroup(final Matcher matcher, final int group) {
try {
return matcher.group(group);
} catch (final IllegalStateException e) {
// Ignore.
}
return null;
}
public static int matcherStart(final Matcher matcher, final int group) {
try {
return matcher.start(group);
} catch (final IllegalStateException e) {
// Ignore.
}
return -1;
}
}

View File

@ -21,48 +21,33 @@ package org.mariotaku.twidere.util;
import android.support.annotation.NonNull;
import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
public final class ArrayUtils {
public final class TwidereArrayUtils {
private ArrayUtils() {
private TwidereArrayUtils() {
throw new AssertionError("You are trying to create an instance for this utility class!");
}
public static boolean contains(final int[] array, final int value) {
if (array == null) return false;
for (final int item : array) {
if (item == value) return true;
}
return false;
}
public static boolean contains(final long[] array, final long value) {
if (array == null) return false;
for (final long item : array) {
if (item == value) return true;
}
return false;
}
public static boolean contains(final Object[] array, final Object value) {
if (array == null || value == null) return false;
return contains(array, new Object[]{value});
}
public static boolean contains(final Object[] array, final Object[] values) {
if (array == null || values == null) return false;
for (final Object item : array) {
for (final Object value : values) {
if (item == null || value == null) {
if (item == value) return true;
continue;
}
if (item.equals(value)) return true;
}
for (final Object value : values) {
if (!ArrayUtils.contains(array, value)) return false;
}
return false;
return true;
}
public static boolean contentMatch(final long[] array1, final long[] array2) {
if (array1 == null || array2 == null) return array1 == array2;
if (array1.length != array2.length) return false;
final int length = array1.length;
for (int i = 0; i < length; i++) {
if (!ArrayUtils.contains(array2, array1[i])) return false;
}
return true;
}
public static boolean contentMatch(final Object[] array1, final Object[] array2) {
@ -70,7 +55,7 @@ public final class ArrayUtils {
if (array1.length != array2.length) return false;
final int length = array1.length;
for (int i = 0; i < length; i++) {
if (!contains(array2, array1[i])) return false;
if (!ArrayUtils.contains(array2, array1[i])) return false;
}
return true;
}
@ -85,29 +70,6 @@ public final class ArrayUtils {
return array;
}
public static int indexOf(final int[] array, final int value) {
final int length = array.length;
for (int i = 0; i < length; i++) {
if (array[i] == value) return i;
}
return -1;
}
public static int indexOf(final long[] array, final long value) {
final int length = array.length;
for (int i = 0; i < length; i++) {
if (array[i] == value) return i;
}
return -1;
}
public static int indexOf(final Object[] array, final Object value) {
final int length = array.length;
for (int i = 0; i < length; i++) {
if (array[i].equals(value)) return i;
}
return -1;
}
public static long[] intersection(final long[] array1, final long[] array2) {
if (array1 == null || array2 == null) return new long[0];
@ -220,13 +182,11 @@ public final class ArrayUtils {
final StringBuilder builder = new StringBuilder();
final int length = array.length;
for (int i = 0; i < length; i++) {
final String id_string = String.valueOf(array[i]);
if (id_string != null) {
if (i > 0) {
builder.append(include_space ? token + " " : token);
}
builder.append(id_string);
final String idString = String.valueOf(array[i]);
if (i > 0) {
builder.append(include_space ? token + " " : token);
}
builder.append(idString);
}
return builder.toString();
}

View File

@ -0,0 +1,150 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util;
import android.content.Context;
import android.support.annotation.NonNull;
import org.mariotaku.twidere.common.R;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.zip.CRC32;
import twitter4j.DirectMessage;
import twitter4j.EntitySupport;
import twitter4j.MediaEntity;
import twitter4j.Status;
import twitter4j.URLEntity;
import twitter4j.User;
import twitter4j.UserMentionEntity;
import static org.mariotaku.twidere.util.HtmlEscapeHelper.toPlainText;
/**
* Created by mariotaku on 15/1/11.
*/
public class TwitterContentUtils {
public static String formatDirectMessageText(final DirectMessage message) {
if (message == null) return null;
final String text = message.getRawText();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
TwitterContentUtils.parseEntities(builder, message);
return builder.build().replace("\n", "<br/>");
}
public static String formatExpandedUserDescription(final User user) {
if (user == null) return null;
final String text = user.getDescription();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
final URLEntity[] urls = user.getDescriptionEntities();
if (urls != null) {
for (final URLEntity url : urls) {
final String expanded_url = ParseUtils.parseString(url.getExpandedURL());
if (expanded_url != null) {
builder.addLink(expanded_url, expanded_url, url.getStart(), url.getEnd());
}
}
}
return toPlainText(builder.build().replace("\n", "<br/>"));
}
public static String formatStatusText(final Status status) {
if (status == null) return null;
final String text = status.getRawText();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
TwitterContentUtils.parseEntities(builder, status);
return builder.build().replace("\n", "<br/>");
}
public static String formatUserDescription(final User user) {
if (user == null) return null;
final String text = user.getDescription();
if (text == null) return null;
final HtmlBuilder builder = new HtmlBuilder(text, false, true, true);
final URLEntity[] urls = user.getDescriptionEntities();
if (urls != null) {
for (final URLEntity url : urls) {
final URL expanded_url = url.getExpandedURL();
if (expanded_url != null) {
builder.addLink(ParseUtils.parseString(expanded_url), url.getDisplayURL(), url.getStart(),
url.getEnd());
}
}
}
return builder.build().replace("\n", "<br/>");
}
@NonNull
public static String getInReplyToName(@NonNull final Status status) {
final Status orig = status.isRetweet() ? status.getRetweetedStatus() : status;
final long inReplyToUserId = status.getInReplyToUserId();
final UserMentionEntity[] entities = status.getUserMentionEntities();
if (entities == null) return orig.getInReplyToScreenName();
for (final UserMentionEntity entity : entities) {
if (inReplyToUserId == entity.getId()) return entity.getName();
}
return orig.getInReplyToScreenName();
}
public static boolean isOfficialKey(final Context context, final String consumerKey,
final String consumerSecret) {
if (context == null || consumerKey == null || consumerSecret == null) return false;
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32);
final CRC32 crc32 = new CRC32();
final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8"));
crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length);
final long value = crc32.getValue();
crc32.reset();
for (final String keySecret : keySecrets) {
if (Long.parseLong(keySecret, 16) == value) return true;
}
return false;
}
private static void parseEntities(final HtmlBuilder builder, final EntitySupport entities) {
// Format media.
final MediaEntity[] mediaEntities = entities.getMediaEntities();
if (mediaEntities != null) {
for (final MediaEntity mediaEntity : mediaEntities) {
final int start = mediaEntity.getStart(), end = mediaEntity.getEnd();
final URL mediaUrl = mediaEntity.getMediaURL();
if (mediaUrl != null && start >= 0 && end >= 0) {
builder.addLink(ParseUtils.parseString(mediaUrl), mediaEntity.getDisplayURL(),
start, end);
}
}
}
final URLEntity[] urlEntities = entities.getURLEntities();
if (urlEntities != null) {
for (final URLEntity urlEntity : urlEntities) {
final int start = urlEntity.getStart(), end = urlEntity.getEnd();
final URL expandedUrl = urlEntity.getExpandedURL();
if (expandedUrl != null && start >= 0 && end >= 0) {
builder.addLink(ParseUtils.parseString(expandedUrl), urlEntity.getDisplayURL(),
start, end);
}
}
}
}
}

View File

@ -0,0 +1,104 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util.content;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.CancellationSignal;
import org.mariotaku.twidere.util.TwidereArrayUtils;
import java.util.Collection;
import static android.text.TextUtils.isEmpty;
public class ContentResolverUtils {
private static final int MAX_DELETE_COUNT = 128;
public static <T> int bulkDelete(final ContentResolver resolver, final Uri uri, final String inColumn,
final Collection<T> colValues, final String extraWhere, final boolean valuesIsString) {
if (colValues == null) return 0;
return bulkDelete(resolver, uri, inColumn, colValues.toArray(), extraWhere, valuesIsString);
}
public static <T> int bulkDelete(final ContentResolver resolver, final Uri uri, final String inColumn,
final T[] colValues, final String extraWhere, final boolean valuesIsString) {
if (resolver == null || uri == null || isEmpty(inColumn) || colValues == null || colValues.length == 0)
return 0;
final int col_values_length = colValues.length, blocks_count = col_values_length / MAX_DELETE_COUNT + 1;
int rows_deleted = 0;
for (int i = 0; i < blocks_count; i++) {
final int start = i * MAX_DELETE_COUNT, end = Math.min(start + MAX_DELETE_COUNT, col_values_length);
final String[] block = TwidereArrayUtils.toStringArray(TwidereArrayUtils.subArray(colValues, start, end));
if (valuesIsString) {
final StringBuilder where = new StringBuilder(inColumn + " IN(" + TwidereArrayUtils.toStringForSQL(block)
+ ")");
if (!isEmpty(extraWhere)) {
where.append("AND ").append(extraWhere);
}
rows_deleted += resolver.delete(uri, where.toString(), block);
} else {
final StringBuilder where = new StringBuilder(inColumn + " IN("
+ TwidereArrayUtils.toString(block, ',', true) + ")");
if (!isEmpty(extraWhere)) {
where.append("AND ").append(extraWhere);
}
rows_deleted += resolver.delete(uri, where.toString(), null);
}
}
return rows_deleted;
}
public static int bulkInsert(final ContentResolver resolver, final Uri uri, final Collection<ContentValues> values) {
if (values == null) return 0;
return bulkInsert(resolver, uri, values.toArray(new ContentValues[values.size()]));
}
public static int bulkInsert(final ContentResolver resolver, final Uri uri, final ContentValues[] values) {
if (resolver == null || uri == null || values == null || values.length == 0) return 0;
final int colValuesLength = values.length, blocksCount = colValuesLength / MAX_DELETE_COUNT + 1;
int rowsInserted = 0;
for (int i = 0; i < blocksCount; i++) {
final int start = i * MAX_DELETE_COUNT, end = Math.min(start + MAX_DELETE_COUNT, colValuesLength);
final ContentValues[] block = new ContentValues[end - start];
System.arraycopy(values, start, block, 0, end - start);
rowsInserted += resolver.bulkInsert(uri, block);
}
return rowsInserted;
}
public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection,
final String selection, final String[] selectionArgs, final String sortOrder) {
return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection,
final String selection, final String[] selectionArgs, final String sortOrder,
final CancellationSignal cancellationSignal) {
return resolver.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
}
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<!-- CRC32 checksum of consumer secret of official clients to check whether user is using official keys -->
<string-array name="values_official_consumer_secret_crc32">
<!--Twitter for Android-->
<item>6ce85096</item>
<!--Twitter for iPhone-->
<item>deffe9c7</item>
<!--Twitter for iPad-->
<item>9f00e0cb</item>
<!--Twitter for Mac-->
<item>df27640e</item>
<!--Twitter for Windows Phone-->
<item>62bd0d33</item>
<!--Twitter for Google TV-->
<item>56d8f9ff</item>
</string-array>
</resources>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<integer name="default_text_size">15</integer>
</resources>

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,42 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,32 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.jsonserializer;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,20 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="org.mariotaku.jsonserializer"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,22 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">twidere.component.jsonserializer</string>
</resources>

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,42 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,32 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twiderecomponentsqlquerybuilder;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,20 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest package="org.mariotaku.querybuilder"/>

View File

@ -28,8 +28,6 @@
package org.mariotaku.querybuilder;
import org.mariotaku.twidere.util.ArrayUtils;
public class OrderBy implements SQLLang {
private final String[] orderBy;
@ -40,7 +38,7 @@ public class OrderBy implements SQLLang {
@Override
public String getSQL() {
return ArrayUtils.toString(orderBy, ',', false);
return Utils.toString(orderBy, ',', false);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,22 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<resources>
<string name="app_name">twidere.component.sqlquerybuilder</string>
</resources>

View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,43 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile project(':twidere.component.twitter4j')
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/mariotaku/Tools/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,32 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.library.twitter4j.streaming;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,27 @@
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mariotaku.twidere.library.twitter4j.streaming">
<uses-permission android:name="android.permission.INTERNET"/>
<application/>
</manifest>

View File

@ -16,21 +16,23 @@
package twitter4j;
import java.io.Serializable;
/**
* @author Mariotaku Lee
* @since Twitter4J 2.2.5
* @author Yusuke Yamamoto - yusuke at mac.com
* @since Twitter4J 2.1.7
*/
public interface ExtendedEntitySupport extends EntitySupport {
public interface ConnectionLifeCycleListener {
/**
* called before thread gets cleaned up
*/
void onCleanUp();
/**
* Returns an array of MediaEntities if media are available in the tweet,
* or null if no media is included in the tweet.
*
* @return an array of MediaEntities.
* @since Twitter4J 2.2.3
* called after connection was established
*/
MediaEntity[] getExtendedMediaEntities();
void onConnect();
/**
* called after connection was disconnected
*/
void onDisconnect();
}

View File

@ -0,0 +1,115 @@
/*
* Copyright 2007 Yusuke Yamamoto
* Copyright (C) 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package twitter4j;
import static twitter4j.internal.util.InternalParseUtil.getBoolean;
import static twitter4j.internal.util.InternalParseUtil.getRawString;
import java.io.Serializable;
import java.util.Arrays;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @author Yusuke Yamamoto - yusuke at twitter.com
* @since Twitter4J 2.2.6
*/
public final class ControlStreamInfo implements Serializable {
private static final long serialVersionUID = -6761659771734942177L;
private final StreamController.User[] users;
private final boolean includeFollowingsActivity;
private final boolean includeUserChanges;
private final String replies;
private final String with;
private transient final StreamController controller;
/* package */ControlStreamInfo(final StreamController controller, final JSONObject json) throws TwitterException {
this.controller = controller;
try {
final JSONObject info = json.getJSONObject("info");
includeFollowingsActivity = getBoolean("include_followings_activity", info);
includeUserChanges = getBoolean("include_user_changes", info);
replies = getRawString("replies", info);
with = getRawString("with", info);
final JSONArray usersJSON = info.getJSONArray("users");
users = new StreamController.User[usersJSON.length()];
for (int i = 0; i < usersJSON.length(); i++) {
users[i] = this.controller.createUser(usersJSON.getJSONObject(i));
}
} catch (final JSONException e) {
throw new TwitterException(e);
}
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ControlStreamInfo that = (ControlStreamInfo) o;
if (includeFollowingsActivity != that.includeFollowingsActivity) return false;
if (includeUserChanges != that.includeUserChanges) return false;
if (replies != null ? !replies.equals(that.replies) : that.replies != null) return false;
if (!Arrays.equals(users, that.users)) return false;
if (with != null ? !with.equals(that.with) : that.with != null) return false;
return true;
}
public StreamController.User[] getUsers() {
return users;
}
@Override
public int hashCode() {
int result = users != null ? Arrays.hashCode(users) : 0;
result = 31 * result + (includeFollowingsActivity ? 1 : 0);
result = 31 * result + (includeUserChanges ? 1 : 0);
result = 31 * result + (replies != null ? replies.hashCode() : 0);
result = 31 * result + (with != null ? with.hashCode() : 0);
return result;
}
public boolean isIncludeFollowingsActivity() {
return includeFollowingsActivity;
}
public boolean isIncludeUserChanges() {
return includeUserChanges;
}
public String isReplies() {
return replies;
}
public String isWith() {
return with;
}
@Override
public String toString() {
return "ControlStreamInfo{" + "users=" + (users == null ? null : Arrays.asList(users))
+ ", includeFollowingsActivity=" + includeFollowingsActivity + ", includeUserChanges="
+ includeUserChanges + ", replies='" + replies + '\'' + ", with='" + with + '\'' + '}';
}
}

View File

@ -0,0 +1,205 @@
/*
* Copyright 2007 Yusuke Yamamoto
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package twitter4j;
import java.util.ArrayList;
import java.util.Arrays;
import twitter4j.http.HttpParameter;
import twitter4j.internal.util.InternalStringUtil;
/**
* @author Yusuke Yamamoto - yusuke at mac.com
* @since Twitter4J 2.1.2
*/
public final class FilterQuery implements java.io.Serializable {
private static final long serialVersionUID = 430966623248982833L;
private int count;
private long[] follow;
private String[] track;
private double[][] locations;
/**
* Creates a new FilterQuery
*/
public FilterQuery() {
count = 0;
follow = null;
track = null;
locations = null;
}
/**
* Creates a new FilterQuery
*
* @param count Indicates the number of previous statuses to stream before
* transitioning to the live stream.
* @param follow Specifies the users, by ID, to receive public tweets from.
*/
public FilterQuery(final int count, final long[] follow) {
this();
this.count = count;
this.follow = follow;
}
/**
* Creates a new FilterQuery
*
* @param count Indicates the number of previous statuses to stream before
* transitioning to the live stream.
* @param follow Specifies the users, by ID, to receive public tweets from.
* @param track Specifies keywords to track.
*/
public FilterQuery(final int count, final long[] follow, final String[] track) {
this();
this.count = count;
this.follow = follow;
this.track = track;
}
/**
* Creates a new FilterQuery
*
* @param count Indicates the number of previous statuses to stream before
* transitioning to the live stream.
* @param follow Specifies the users, by ID, to receive public tweets from.
* @param track Specifies keywords to track.
* @param locations Specifies the locations to track. 2D array
*/
public FilterQuery(final int count, final long[] follow, final String[] track, final double[][] locations) {
this.count = count;
this.follow = follow;
this.track = track;
this.locations = locations;
}
/**
* Creates a new FilterQuery
*
* @param follow Specifies the users, by ID, to receive public tweets from.
*/
public FilterQuery(final long[] follow) {
this();
count = 0;
this.follow = follow;
}
/**
* Sets count
*
* @param count Indicates the number of previous statuses to stream before
* transitioning to the live stream.
* @return this instance
*/
public FilterQuery count(final int count) {
this.count = count;
return this;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final FilterQuery that = (FilterQuery) o;
if (count != that.count) return false;
if (!Arrays.equals(follow, that.follow)) return false;
if (!Arrays.equals(track, that.track)) return false;
return true;
}
/**
* Sets follow
*
* @param follow Specifies the users, by ID, to receive public tweets from.
* @return this instance
*/
public FilterQuery follow(final long[] follow) {
this.follow = follow;
return this;
}
@Override
public int hashCode() {
int result = count;
result = 31 * result + (follow != null ? Arrays.hashCode(follow) : 0);
result = 31 * result + (track != null ? Arrays.hashCode(track) : 0);
return result;
}
/**
* Sets locations
*
* @param locations Specifies the locations to track. 2D array
* @return this instance
*/
public FilterQuery locations(final double[][] locations) {
this.locations = locations;
return this;
}
@Override
public String toString() {
return "FilterQuery{" + "count=" + count + ", follow=" + Arrays.toString(follow) + ", track="
+ (track == null ? null : Arrays.asList(track)) + ", locations="
+ (locations == null ? null : Arrays.asList(locations)) + '}';
}
/**
* Sets track
*
* @param track Specifies keywords to track.
* @return this instance
*/
public FilterQuery track(final String[] track) {
this.track = track;
return this;
}
private String toLocationsString(final double[][] keywords) {
final StringBuilder buf = new StringBuilder(20 * keywords.length * 2);
for (final double[] keyword : keywords) {
if (0 != buf.length()) {
buf.append(",");
}
buf.append(keyword[0]);
buf.append(",");
buf.append(keyword[1]);
}
return buf.toString();
}
/* package */HttpParameter[] asHttpParameterArray(final HttpParameter stallWarningsParam) {
final ArrayList<HttpParameter> params = new ArrayList<HttpParameter>();
params.add(new HttpParameter("count", count));
if (follow != null && follow.length > 0) {
params.add(new HttpParameter("follow", InternalStringUtil.join(follow)));
}
if (track != null && track.length > 0) {
params.add(new HttpParameter("track", InternalStringUtil.join(track)));
}
if (locations != null && locations.length > 0) {
params.add(new HttpParameter("locations", toLocationsString(locations)));
}
params.add(stallWarningsParam);
final HttpParameter[] paramArray = new HttpParameter[params.size()];
return params.toArray(paramArray);
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2007 Yusuke Yamamoto
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package twitter4j;
/**
* @author Yusuke Yamamoto - yusuke at mac.com
* @since Twitter4J 3.0.2
*/
public interface RawStreamListener extends StreamListener {
void onMessage(String rawString);
}

Some files were not shown because too many files have changed in this diff Show More