1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-01-31 17:04:59 +01:00
moved query builder to a separate library
try implementing dm and activities
This commit is contained in:
Mariotaku Lee 2015-07-06 17:36:18 +08:00
parent 817ac8e622
commit 6fbc782ce2
84 changed files with 1512 additions and 3115 deletions

View File

@ -1,11 +1,11 @@
include ':twidere', ':twidere.extension.shortener.gist'
include ':twidere'
include ':twidere.component.common'
include ':twidere.library.extension'
include ':twidere.component.querybuilder'
include ':twidere.wear'
include ':twidere.donate.nyanwp'
include ':twidere.donate.nyanwp.wear'
include ':twidere.component.nyan'
include ':twidere.extension.twitlonger'
include ':twidere.extension.push.xiaomi'
include ':twidere.extension.launcher.compose'
include ':twidere.extension.launcher.compose'
include ':twidere.extension.shortener.gist'

View File

@ -43,8 +43,8 @@ dependencies {
compile 'com.android.support:support-v4:22.2.0'
compile 'com.bluelinelabs:logansquare:1.1.0'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.github.mariotaku:RestFu:d965fcf941'
compile 'com.github.mariotaku:RestFu:0.9'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
compile project(':twidere.component.querybuilder')
compile 'com.github.mariotaku:SQLiteQB:ef3f596199'
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -19,11 +19,15 @@
package org.mariotaku.twidere.api.twitter.api;
import org.mariotaku.restfu.annotation.method.GET;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Body;
import org.mariotaku.restfu.annotation.param.Path;
import org.mariotaku.restfu.annotation.param.Query;
import org.mariotaku.restfu.http.BodyType;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.PrivateDirectMessages;
import org.mariotaku.twidere.api.twitter.model.ResponseCode;
@SuppressWarnings("RedundantThrows")
@ -37,4 +41,9 @@ public interface PrivateDirectMessagesResources extends PrivateResources {
@Body(BodyType.FORM)
ResponseCode destroyDirectMessagesConversation(@Path("account_id") long accountId, @Path("user_id") long userId) throws TwitterException;
@GET("/dm/user_updates.json")
PrivateDirectMessages getUserUpdates(@Query Paging paging);
@GET("/dm/user_inbox.json")
PrivateDirectMessages getUserInbox(@Query Paging paging);
}

View File

@ -46,6 +46,10 @@ public class Paging extends SimpleValueMap {
put("cursor", cursor);
}
public void setCursor(String cursor) {
put("cursor", cursor);
}
public Paging sinceId(long sinceId) {
setSinceId(sinceId);
return this;

View File

@ -0,0 +1,90 @@
/*
* 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.api.twitter.model;
/**
* Created by mariotaku on 15/7/5.
*/
public interface PrivateDirectMessages {
UserEvents getUserEvents();
interface UserInbox {
User getUser(long userId);
Conversation getConversation(String conversationId);
Message[] getEntries();
}
interface UserEvents {
String getCursor();
long getLastSeenEventId();
}
UserInbox getUserInbox();
interface Message {
interface Data extends EntitySupport {
String getText();
String getConversationId();
long getId();
long getRecipientId();
long getSenderId();
long getTime();
}
}
interface Conversation {
Participant[] getParticipants();
String getConversationId();
long getLastReadEventId();
long getMaxEntryId();
long getMinEntryId();
boolean isNotificationsDisabled();
interface Participant {
long getUserId();
}
enum Type {
ONE_TO_ONE, GROUP_DM
}
}
enum Status {
HAS_MORE, AT_END
}
}

View File

@ -0,0 +1,253 @@
/*
* 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.api.twitter.model.impl;
import android.support.annotation.Nullable;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import org.mariotaku.twidere.api.twitter.model.HashtagEntity;
import org.mariotaku.twidere.api.twitter.model.MediaEntity;
import org.mariotaku.twidere.api.twitter.model.PrivateDirectMessages;
import org.mariotaku.twidere.api.twitter.model.UrlEntity;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.api.twitter.model.UserMentionEntity;
import java.util.Map;
/**
* Created by mariotaku on 15/7/5.
*/
@JsonObject
public class PrivateDirectMessagesImpl implements PrivateDirectMessages {
@JsonField(name = "user_inbox")
UserInboxImpl userInbox;
@JsonField(name = "user_events")
UserEventsImpl userEvents;
@Override
public UserInbox getUserInbox() {
return userInbox;
}
@Override
public UserEvents getUserEvents() {
return userEvents;
}
@JsonObject
public static class UserInboxImpl implements UserInbox {
@JsonField(name = "users")
Map<String, UserImpl> users;
@JsonField(name = "conversations")
Map<String, ConversationImpl> conversations;
@JsonField(name = "entries")
MessageImpl[] entries;
@Override
public User getUser(long userId) {
return users.get(String.valueOf(userId));
}
@Override
public Conversation getConversation(String conversationId) {
return conversations.get(conversationId);
}
@Override
public Message[] getEntries() {
return entries;
}
}
@JsonObject
public static class UserEventsImpl implements UserEvents {
@JsonField(name = "cursor")
String cursor;
@JsonField(name = "last_seen_event_id")
long lastSeenEventId;
@Override
public String getCursor() {
return cursor;
}
@Override
public long getLastSeenEventId() {
return lastSeenEventId;
}
}
@JsonObject
public static class MessageImpl implements Message {
@JsonObject
public static class DataImpl implements Data {
@Nullable
@JsonField(name = "entities")
EntitiesImpl entities;
@JsonField(name = "sender_id")
long senderId;
@JsonField(name = "recipient_id")
long recipientId;
@JsonField(name = "id")
long id;
@JsonField(name = "conversation_id")
String conversationId;
@JsonField(name = "text")
String text;
@JsonField(name = "time")
long time;
@Override
public String getText() {
return text;
}
@Override
public String getConversationId() {
return conversationId;
}
@Override
public long getId() {
return id;
}
@Override
public long getRecipientId() {
return recipientId;
}
@Override
public long getSenderId() {
return senderId;
}
@Override
public long getTime() {
return time;
}
@Override
public HashtagEntity[] getHashtagEntities() {
if (entities == null) return null;
return entities.getHashtags();
}
@Override
public UrlEntity[] getUrlEntities() {
if (entities == null) return null;
return entities.getUrls();
}
@Override
public MediaEntity[] getMediaEntities() {
if (entities == null) return null;
return entities.getMedia();
}
@Override
public UserMentionEntity[] getUserMentionEntities() {
if (entities == null) return null;
return entities.getUserMentions();
}
}
}
@JsonObject
public static class ConversationImpl implements Conversation {
@JsonField(name = "conversation_id")
String conversationId;
@JsonField(name = "last_read_event_id")
long lastReadEventId;
@JsonField(name = "max_entry_id")
long maxEntryId;
@JsonField(name = "min_entry_id")
long minEntryId;
@JsonField(name = "notifications_disabled")
boolean notificationsDisabled;
@JsonField(name = "participants")
ParticipantImpl[] participants;
@JsonField(name = "read_only")
boolean readOnly;
@JsonField(name = "sort_event_id")
long sortEventId;
@JsonField(name = "sort_timestamp")
long sortTimestamp;
@JsonField(name = "status")
Status status;
@JsonField(name = "type")
Type type;
@Override
public Participant[] getParticipants() {
return participants;
}
@Override
public String getConversationId() {
return conversationId;
}
@Override
public long getLastReadEventId() {
return lastReadEventId;
}
@Override
public long getMaxEntryId() {
return maxEntryId;
}
@Override
public long getMinEntryId() {
return minEntryId;
}
@Override
public boolean isNotificationsDisabled() {
return notificationsDisabled;
}
@JsonObject
public static class ParticipantImpl implements Participant {
@JsonField(name = "user_id")
long userId;
@Override
public long getUserId() {
return userId;
}
}
}
}

View File

@ -0,0 +1,85 @@
/*
* 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.model;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.util.SparseArray;
import java.util.AbstractList;
/**
* Created by mariotaku on 15/7/5.
*/
public class ObjectCursor<E> extends AbstractList<E> {
private final Cursor mCursor;
private final CursorIndices<E> mIndices;
private final SparseArray<E> mCache;
public ObjectCursor(@NonNull Cursor cursor, @NonNull CursorIndices<E> indies) {
mCursor = cursor;
mIndices = indies;
mCache = new SparseArray<>();
}
@Override
public E get(final int location) {
ensureCursor();
final int idxOfCache = mCache.indexOfKey(location);
if (idxOfCache >= 0) return mCache.valueAt(idxOfCache);
if (mCursor.moveToPosition(location)) {
final E object = get(mCursor, mIndices);
mCache.put(location, object);
return object;
}
throw new ArrayIndexOutOfBoundsException(location);
}
private void ensureCursor() {
if (mCursor.isClosed()) throw new IllegalStateException("Cursor is closed");
}
protected E get(final Cursor cursor, final CursorIndices<E> indices) {
return indices.newObject(cursor);
}
@Override
public int size() {
return mCursor.getCount();
}
public boolean isClosed() {
return mCursor.isClosed();
}
public void close() {
mCursor.close();
}
public static abstract class CursorIndices<T> {
public CursorIndices(@NonNull Cursor cursor) {
}
abstract T newObject(Cursor cursor);
}
}

View File

@ -32,9 +32,9 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.util.TwitterContentUtils;
import org.mariotaku.twidere.util.content.ContentResolverUtils;

View File

@ -58,20 +58,9 @@ import java.util.Map.Entry;
@ParcelablePlease(allFields = false)
public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus> {
public static final Parcelable.Creator<ParcelableStatus> CREATOR = new Parcelable.Creator<ParcelableStatus>() {
@Override
public ParcelableStatus createFromParcel(final Parcel in) {
ParcelableStatus status = new ParcelableStatus();
ParcelableStatusParcelablePlease.readFromParcel(status, in);
return status;
}
@Override
public ParcelableStatus[] newArray(final int size) {
return new ParcelableStatus[size];
}
};
@ParcelableThisPlease
@JsonField(name = "id")
public long id;
public static final Comparator<ParcelableStatus> REVERSE_ID_COMPARATOR = new Comparator<ParcelableStatus>() {
@Override
@ -82,7 +71,12 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
return (int) diff;
}
};
@ParcelableThisPlease
@JsonField(name = "account_id")
public long account_id;
@ParcelableThisPlease
@JsonField(name = "timestamp")
public long timestamp;
public static final Comparator<ParcelableStatus> TIMESTAMP_COMPARATOR = new Comparator<ParcelableStatus>() {
@Override
@ -93,16 +87,6 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
return (int) diff;
}
};
@ParcelableThisPlease
@JsonField(name = "id")
public long id;
@ParcelableThisPlease
@JsonField(name = "account_id")
public long account_id;
@ParcelableThisPlease
@JsonField(name = "timestamp")
public long timestamp;
@ParcelableThisPlease
@JsonField(name = "user_id")
public long user_id;
@ -259,6 +243,19 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
@ParcelableThisPlease
@JsonField(name = "card")
public ParcelableCardEntity card;
public static final Parcelable.Creator<ParcelableStatus> CREATOR = new Parcelable.Creator<ParcelableStatus>() {
@Override
public ParcelableStatus createFromParcel(final Parcel in) {
ParcelableStatus status = new ParcelableStatus();
ParcelableStatusParcelablePlease.readFromParcel(status, in);
return status;
}
@Override
public ParcelableStatus[] newArray(final int size) {
return new ParcelableStatus[size];
}
};
public ParcelableStatus(final Cursor c, final CursorIndices idx) {
id = idx.status_id != -1 ? c.getLong(idx.status_id) : -1;
@ -458,6 +455,16 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
card_name = card != null ? card.name : null;
}
@Nullable
private static String getPlaceFullName(@Nullable Place place) {
if (place == null) return null;
return place.getFullName();
}
private static long getTime(final Date date) {
return date != null ? date.getTime() : 0;
}
@Override
public int compareTo(@NonNull final ParcelableStatus another) {
final long diff = another.id - id;
@ -550,17 +557,22 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
'}';
}
@Nullable
private static String getPlaceFullName(@Nullable Place place) {
if (place == null) return null;
return place.getFullName();
@Override
public void writeToParcel(final Parcel out, final int flags) {
ParcelableStatusParcelablePlease.writeToParcel(this, out, flags);
}
private static long getTime(final Date date) {
return date != null ? date.getTime() : 0;
public static ParcelableStatus[] fromStatuses(Status[] statuses, long accountId) {
if (statuses == null) return null;
int size = statuses.length;
final ParcelableStatus[] result = new ParcelableStatus[size];
for (int i = 0; i < size; i++) {
result[i] = new ParcelableStatus(statuses[i], accountId, false);
}
return result;
}
public static final class CursorIndices {
public static final class CursorIndices extends ObjectCursor.CursorIndices<ParcelableStatus> {
public final int _id, account_id, status_id, status_timestamp, user_name, user_screen_name,
text_html, text_plain, text_unescaped, user_profile_image_url, is_favorite, is_retweet,
@ -575,6 +587,7 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
quoted_by_user_is_protected, quoted_by_user_is_verified;
public CursorIndices(final Cursor cursor) {
super(cursor);
_id = cursor.getColumnIndex(Statuses._ID);
account_id = cursor.getColumnIndex(Statuses.ACCOUNT_ID);
status_id = cursor.getColumnIndex(Statuses.STATUS_ID);
@ -633,6 +646,11 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
place_full_name = cursor.getColumnIndex(Statuses.PLACE_FULL_NAME);
}
@Override
ParcelableStatus newObject(Cursor cursor) {
return new ParcelableStatus(cursor, this);
}
@Override
public String toString() {
return "CursorIndices{" +
@ -745,6 +763,25 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
values = ParcelableBindingValue.from(card.getBindingValues());
}
public static ParcelableCardEntity fromCardEntity(CardEntity card, long account_id) {
if (card == null) return null;
return new ParcelableCardEntity(card, account_id);
}
public static ParcelableCardEntity fromJSONString(final String json) {
if (TextUtils.isEmpty(json)) return null;
try {
return LoganSquare.parse(json, ParcelableCardEntity.class);
} catch (final IOException e) {
return null;
}
}
public static ParcelableBindingValue getValue(@Nullable ParcelableCardEntity entity, @Nullable String key) {
if (entity == null || entity.values == null || key == null) return null;
return entity.values.get(key);
}
@Override
public String toString() {
return "ParcelableCardEntity{" +
@ -772,25 +809,6 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
dest.writeBundle(bundle);
}
public static ParcelableCardEntity fromCardEntity(CardEntity card, long account_id) {
if (card == null) return null;
return new ParcelableCardEntity(card, account_id);
}
public static ParcelableCardEntity fromJSONString(final String json) {
if (TextUtils.isEmpty(json)) return null;
try {
return LoganSquare.parse(json, ParcelableCardEntity.class);
} catch (final IOException e) {
return null;
}
}
public static ParcelableBindingValue getValue(@Nullable ParcelableCardEntity entity, @Nullable String key) {
if (entity == null || entity.values == null || key == null) return null;
return entity.values.get(key);
}
@JsonObject
public static final class ParcelableBindingValue implements Parcelable {
@ -835,11 +853,6 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
}
}
@Override
public int describeContents() {
return 0;
}
public static Map<String, ParcelableBindingValue> from(Map<String, BindingValue> bindingValues) {
if (bindingValues == null) return null;
final Map<String, ParcelableBindingValue> map = new HashMap<>();
@ -849,6 +862,11 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
return map;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(type);
@ -860,9 +878,4 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
}
@Override
public void writeToParcel(final Parcel out, final int flags) {
ParcelableStatusParcelablePlease.writeToParcel(this, out, flags);
}
}

View File

@ -19,7 +19,6 @@
package org.mariotaku.twidere.model;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Parcel;
import android.os.Parcelable;
@ -360,33 +359,14 @@ public class ParcelableUser implements Parcelable, Comparable<ParcelableUser> {
return new ParcelableUser(account_id, id, name, screen_name, profile_image_url);
}
public static ContentValues makeCachedUserContentValues(final ParcelableUser user) {
if (user == null) return null;
final ContentValues values = new ContentValues();
values.put(CachedUsers.USER_ID, user.id);
values.put(CachedUsers.NAME, user.name);
values.put(CachedUsers.SCREEN_NAME, user.screen_name);
values.put(CachedUsers.PROFILE_IMAGE_URL, user.profile_image_url);
values.put(CachedUsers.CREATED_AT, user.created_at);
values.put(CachedUsers.IS_PROTECTED, user.is_protected);
values.put(CachedUsers.IS_VERIFIED, user.is_verified);
values.put(CachedUsers.LISTED_COUNT, user.listed_count);
values.put(CachedUsers.FAVORITES_COUNT, user.favorites_count);
values.put(CachedUsers.FOLLOWERS_COUNT, user.followers_count);
values.put(CachedUsers.FRIENDS_COUNT, user.friends_count);
values.put(CachedUsers.STATUSES_COUNT, user.statuses_count);
values.put(CachedUsers.LOCATION, user.location);
values.put(CachedUsers.DESCRIPTION_PLAIN, user.description_plain);
values.put(CachedUsers.DESCRIPTION_HTML, user.description_html);
values.put(CachedUsers.DESCRIPTION_EXPANDED, user.description_expanded);
values.put(CachedUsers.URL, user.url);
values.put(CachedUsers.URL_EXPANDED, user.url_expanded);
values.put(CachedUsers.PROFILE_BANNER_URL, user.profile_banner_url);
values.put(CachedUsers.IS_FOLLOWING, user.is_following);
values.put(CachedUsers.BACKGROUND_COLOR, user.background_color);
values.put(CachedUsers.LINK_COLOR, user.link_color);
values.put(CachedUsers.TEXT_COLOR, user.text_color);
return values;
public static ParcelableUser[] fromUsers(final User[] users, long accountId) {
if (users == null) return null;
int size = users.length;
final ParcelableUser[] result = new ParcelableUser[size];
for (int i = 0; i < size; i++) {
result[i] = new ParcelableUser(users[i], accountId);
}
return result;
}
public static final class CachedIndices {

View File

@ -120,6 +120,16 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
subscribers_count = list.getSubscriberCount();
}
public static ParcelableUserList[] fromUserLists(UserList[] userLists, long accountId) {
if (userLists == null) return null;
int size = userLists.length;
final ParcelableUserList[] result = new ParcelableUserList[size];
for (int i = 0; i < size; i++) {
result[i] = new ParcelableUserList(userLists[i], accountId);
}
return result;
}
@Override
public int compareTo(@NonNull final ParcelableUserList another) {
final long diff = position - another.position;
@ -178,5 +188,4 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
out.writeLong(members_count);
out.writeLong(subscribers_count);
}
}

View File

@ -836,6 +836,38 @@ public interface TwidereDataStore {
}
interface Activities extends BaseColumns {
String ACCOUNT_ID = "account_id";
String TIMESTAMP = "timestamp";
String STATUS_USER_ID = "status_user_id";
String STATUS_RETWEETED_BY_USER_ID = "status_retweeted_by_user_id";
String STATUS_QUOTED_BY_USER_ID = "status_quoted_by_user_id";
String STATUS_SOURCE = "status_source";
String STATUS_QUOTE_SOURCE = "status_quote_source";
String STATUS_TEXT_PLAIN = "status_text_plain";
String STATUS_QUOTE_TEXT_PLAIN = "status_quote_text_plain";
String STATUS_TEXT_HTML = "status_text_html";
String STATUS_QUOTE_TEXT_HTML = "status_quote_text_html";
String STATUS_IS_GAP = "status_is_gap";
String MIN_POSITION = "min_position";
String MAX_POSITION = "max_position";
String SOURCES = "sources";
String TARGET_STATUSES = "target_statuses";
String TARGET_USERS = "target_users";
String TARGET_USER_LISTS = "target_user_lists";
String TARGET_OBJECT_STATUSES = "target_object_statuses";
String TARGET_OBJECT_USER_LISTS = "target_object_user_lists";
}
interface ActivitiesAboutMe extends Activities {
String CONTENT_PATH = "activities_about_me";
Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, CONTENT_PATH);
}
interface Tabs extends BaseColumns {
String TABLE_NAME = "tabs";
String CONTENT_PATH = TABLE_NAME;

View File

@ -29,6 +29,7 @@ import org.json.JSONObject;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.api.twitter.auth.OAuthAuthorization;
import org.mariotaku.twidere.api.twitter.auth.OAuthToken;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
import org.mariotaku.twidere.api.twitter.model.GeoLocation;
import org.mariotaku.twidere.api.twitter.model.Place;
@ -39,6 +40,7 @@ import org.mariotaku.twidere.api.twitter.model.Trend;
import org.mariotaku.twidere.api.twitter.model.Trends;
import org.mariotaku.twidere.api.twitter.model.UrlEntity;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.api.twitter.model.UserList;
import org.mariotaku.twidere.model.ParcelableAccount;
import org.mariotaku.twidere.model.ParcelableCredentials;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
@ -51,6 +53,7 @@ import org.mariotaku.twidere.model.ParcelableStatusUpdate;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserMention;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
@ -394,7 +397,7 @@ public final class ContentValuesCreator implements TwidereConstants {
values.put(Statuses.IS_PROTECTED, user.isProtected());
values.put(Statuses.IS_VERIFIED, user.isVerified());
values.put(Statuses.USER_PROFILE_IMAGE_URL, profileImageUrl);
values.put(CachedUsers.IS_FOLLOWING, user.isFollowing());
values.put(Statuses.IS_FOLLOWING, user.isFollowing());
final String textHtml = TwitterContentUtils.formatStatusText(status);
values.put(Statuses.TEXT_HTML, textHtml);
values.put(Statuses.TEXT_PLAIN, TwitterContentUtils.unescapeTwitterStatusText(status.getText()));
@ -442,6 +445,71 @@ public final class ContentValuesCreator implements TwidereConstants {
return createStatusDraft(status, ParcelableAccount.getAccountIds(status.accounts));
}
@NonNull
public static ContentValues createActivity(final Activity activity, final long accountId) {
final ContentValues values;
switch (activity.getAction()) {
case REPLY: {
values = createStatusActivity(activity.getTargetStatuses()[0]);
break;
}
case MENTION: {
values = createStatusActivity(activity.getTargetObjectStatuses()[0]);
break;
}
default: {
values = new ContentValues();
break;
}
}
values.put(Activities.ACCOUNT_ID, accountId);
values.put(Activities.TIMESTAMP, activity.getCreatedAt().getTime());
values.put(Activities.MIN_POSITION, activity.getMinPosition());
values.put(Activities.MAX_POSITION, activity.getMaxPosition());
values.put(Activities.SOURCES, SerializeUtils.serializeArray(User.class, activity.getSources()));
values.put(Activities.TARGET_STATUSES, SerializeUtils.serializeArray(Status.class, activity.getTargetStatuses()));
values.put(Activities.TARGET_USERS, SerializeUtils.serializeArray(User.class, activity.getTargetUsers()));
values.put(Activities.TARGET_USER_LISTS, SerializeUtils.serializeArray(UserList.class, activity.getTargetUserLists()));
values.put(Activities.TARGET_OBJECT_STATUSES, SerializeUtils.serializeArray(Status.class, activity.getTargetObjectStatuses()));
values.put(Activities.TARGET_OBJECT_USER_LISTS, SerializeUtils.serializeArray(UserList.class, activity.getTargetObjectUserLists()));
return values;
}
@NonNull
public static ContentValues createStatusActivity(final Status orig) {
if (orig == null) throw new NullPointerException();
final ContentValues values = new ContentValues();
final Status status;
if (orig.isRetweet()) {
final Status retweetedStatus = orig.getRetweetedStatus();
final User retweetUser = orig.getUser();
final long retweetedById = retweetUser.getId();
values.put(Activities.STATUS_RETWEETED_BY_USER_ID, retweetedById);
status = retweetedStatus;
} else if (orig.isQuote()) {
final Status quotedStatus = orig.getQuotedStatus();
final User quoteUser = orig.getUser();
final long quotedById = quoteUser.getId();
final String textHtml = TwitterContentUtils.formatStatusText(orig);
values.put(Activities.STATUS_QUOTE_TEXT_HTML, textHtml);
values.put(Activities.STATUS_QUOTE_TEXT_PLAIN, TwitterContentUtils.unescapeTwitterStatusText(orig.getText()));
values.put(Activities.STATUS_QUOTE_SOURCE, orig.getSource());
values.put(Activities.STATUS_QUOTED_BY_USER_ID, quotedById);
status = quotedStatus;
} else {
status = orig;
}
final User user = status.getUser();
final long userId = user.getId();
values.put(Activities.STATUS_USER_ID, userId);
final String textHtml = TwitterContentUtils.formatStatusText(status);
values.put(Activities.STATUS_TEXT_HTML, textHtml);
values.put(Activities.STATUS_TEXT_PLAIN, TwitterContentUtils.unescapeTwitterStatusText(status.getText()));
values.put(Activities.STATUS_SOURCE, status.getSource());
return values;
}
public static ContentValues createStatusDraft(final ParcelableStatusUpdate status,
final long[] accountIds) {
final ContentValues values = new ContentValues();
@ -476,4 +544,32 @@ public final class ContentValuesCreator implements TwidereConstants {
return resultList.toArray(new ContentValues[resultList.size()]);
}
public static ContentValues makeCachedUserContentValues(final ParcelableUser user) {
if (user == null) return null;
final ContentValues values = new ContentValues();
values.put(CachedUsers.USER_ID, user.id);
values.put(CachedUsers.NAME, user.name);
values.put(CachedUsers.SCREEN_NAME, user.screen_name);
values.put(CachedUsers.PROFILE_IMAGE_URL, user.profile_image_url);
values.put(CachedUsers.CREATED_AT, user.created_at);
values.put(CachedUsers.IS_PROTECTED, user.is_protected);
values.put(CachedUsers.IS_VERIFIED, user.is_verified);
values.put(CachedUsers.LISTED_COUNT, user.listed_count);
values.put(CachedUsers.FAVORITES_COUNT, user.favorites_count);
values.put(CachedUsers.FOLLOWERS_COUNT, user.followers_count);
values.put(CachedUsers.FRIENDS_COUNT, user.friends_count);
values.put(CachedUsers.STATUSES_COUNT, user.statuses_count);
values.put(CachedUsers.LOCATION, user.location);
values.put(CachedUsers.DESCRIPTION_PLAIN, user.description_plain);
values.put(CachedUsers.DESCRIPTION_HTML, user.description_html);
values.put(CachedUsers.DESCRIPTION_EXPANDED, user.description_expanded);
values.put(CachedUsers.URL, user.url);
values.put(CachedUsers.URL_EXPANDED, user.url_expanded);
values.put(CachedUsers.PROFILE_BANNER_URL, user.profile_banner_url);
values.put(CachedUsers.IS_FOLLOWING, user.is_following);
values.put(CachedUsers.BACKGROUND_COLOR, user.background_color);
values.put(CachedUsers.LINK_COLOR, user.link_color);
values.put(CachedUsers.TEXT_COLOR, user.text_color);
return values;
}
}

View File

@ -1,5 +1,5 @@
/*
* Twidere - Twitter client for Android
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
@ -17,24 +17,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.library'
apply from: rootProject.file('global.gradle')
package org.mariotaku.twidere.util;
android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
import com.bluelinelabs.logansquare.LoganSquare;
import java.io.IOException;
import java.util.Arrays;
/**
* Created by mariotaku on 15/7/6.
*/
public class SerializeUtils {
public static <T> String serializeArray(Class<T> cls, T... array) {
try {
return LoganSquare.serialize(Arrays.asList(array), cls);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}

View File

@ -1 +0,0 @@
/build

View File

@ -1,17 +0,0 @@
# 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

@ -1,32 +0,0 @@
/*
* 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

@ -1,20 +0,0 @@
<!--
~ 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

@ -1,47 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class AllColumns implements Selectable {
private final String table;
public AllColumns() {
this(null);
}
public AllColumns(final String table) {
this.table = table;
}
@Override
public String getSQL() {
return table != null ? table + ".*" : "*";
}
}

View File

@ -1,109 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Columns implements Selectable {
private final AbsColumn[] columns;
public Columns(String... columns) {
this(Columns.fromStrings(columns));
}
public Columns(final AbsColumn... columns) {
this.columns = columns;
}
private static Column[] fromStrings(String... columnsString) {
final Column[] columns = new Column[columnsString.length];
for (int i = 0, j = columnsString.length; i < j; i++) {
columns[i] = new Column(columnsString[i]);
}
return columns;
}
@Override
public String getSQL() {
return Utils.toString(columns, ',', true);
}
public abstract static class AbsColumn implements Selectable {
}
public static class AllColumn extends AbsColumn {
private final Table table;
public AllColumn() {
this(null);
}
public AllColumn(final Table table) {
this.table = table;
}
@Override
public String getSQL() {
return table != null ? table.getSQL() + ".*" : "*";
}
}
public static class Column extends AbsColumn {
private final Table table;
private final String columnName, alias;
public Column(final String columnName) {
this(null, columnName, null);
}
public Column(final String columnName, final String alias) {
this(null, columnName, alias);
}
public Column(final Table table, final String columnName) {
this(table, columnName, null);
}
public Column(final Table table, final String columnName, final String alias) {
if (columnName == null) throw new IllegalArgumentException("");
this.table = table;
this.columnName = columnName;
this.alias = alias;
}
@Override
public String getSQL() {
final String col = table != null ? table.getSQL() + "." + columnName : columnName;
return alias != null ? col + " AS " + alias : col;
}
}
}

View File

@ -1,80 +0,0 @@
/*
* 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.querybuilder;
/**
* Created by mariotaku on 15/3/30.
*/
public class Constraint implements SQLLang {
private final String name;
private final String type;
private final SQLQuery constraint;
public Constraint(String name, String type, SQLQuery constraint) {
this.name = name;
this.type = type;
this.constraint = constraint;
}
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
if (name != null) {
sb.append("CONSTRAINT ");
sb.append(name);
sb.append(" ");
}
sb.append(type);
sb.append(" ");
sb.append(constraint.getSQL());
return sb.toString();
}
public static Constraint unique(String name, Columns columns, OnConflict onConflict) {
return new Constraint(name, "UNIQUE", new ColumnConflictConstaint(columns, onConflict));
}
public static Constraint unique(Columns columns, OnConflict onConflict) {
return unique(null, columns, onConflict);
}
private static final class ColumnConflictConstaint implements SQLQuery {
private final Columns columns;
private final OnConflict onConflict;
public ColumnConflictConstaint(Columns columns, OnConflict onConflict) {
this.columns = columns;
this.onConflict = onConflict;
}
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(columns.getSQL());
sb.append(") ");
sb.append("ON CONFLICT ");
sb.append(onConflict.getAction());
return sb.toString();
}
}
}

View File

@ -1,159 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
* <p/>
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
* <p/>
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* <p/>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* <p/>
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
import org.mariotaku.querybuilder.Columns.Column;
import java.util.Locale;
public class Expression implements SQLLang {
private final String expr;
public Expression(final String expr) {
this.expr = expr;
}
public Expression(SQLLang lang) {
this(lang.getSQL());
}
public static Expression and(final Expression... expressions) {
return new Expression(toExpr(expressions, "AND"));
}
public static Expression equals(final Column l, final Column r) {
return new Expression(String.format(Locale.ROOT, "%s = %s", l.getSQL(), r.getSQL()));
}
public static Expression equals(final Column l, final Selectable r) {
return new Expression(String.format(Locale.ROOT, "%s = (%s)", l.getSQL(), r.getSQL()));
}
public static Expression equals(final String l, final Selectable r) {
return new Expression(String.format(Locale.ROOT, "%s = (%s)", l, r.getSQL()));
}
public static Expression equals(final Column l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s = %d", l.getSQL(), r));
}
public static Expression equals(final Column l, final String r) {
return new Expression(String.format(Locale.ROOT, "%s = '%s'", l.getSQL(), r));
}
public static Expression equals(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s = %d", l, r));
}
public static Expression greaterThan(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s > %d", l, r));
}
public static Expression greaterEquals(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s >= %d", l, r));
}
public static Expression lesserEquals(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s <= %d", l, r));
}
public static Expression lesserThan(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s < %d", l, r));
}
public static Expression in(final Column column, final Selectable in) {
return new Expression(String.format("%s IN(%s)", column.getSQL(), in.getSQL()));
}
public static Expression notEquals(final String l, final long r) {
return new Expression(String.format(Locale.ROOT, "%s != %d", l, r));
}
public static Expression notEquals(final String l, final String r) {
return new Expression(String.format("%s != %s", l, r));
}
public static Expression notIn(final Column column, final Selectable in) {
return new Expression(String.format("%s NOT IN(%s)", column.getSQL(), in.getSQL()));
}
public static Expression notNull(final Column column) {
return new Expression(String.format("%s NOT NULL", column.getSQL()));
}
public static Expression or(final Expression... expressions) {
return new Expression(toExpr(expressions, "OR"));
}
private static String toExpr(final Expression[] array, final String token) {
final StringBuilder builder = new StringBuilder();
builder.append('(');
final int length = array.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(String.format(" %s ", token));
}
builder.append(array[i].getSQL());
}
builder.append(')');
return builder.toString();
}
public static Expression equalsArgs(String l) {
return new Expression(String.format(Locale.ROOT, "%s = ?", l));
}
public static Expression isNull(Column column) {
return new Expression(String.format(Locale.ROOT, "%s IS NULL", column.getSQL()));
}
public static Expression greaterThan(Column column1, Column column2) {
return new Expression(String.format(Locale.ROOT, "%s > %s", column1.getSQL(), column2.getSQL()));
}
public static Expression likeRaw(final Column column, final String pattern, final String escape) {
return new Expression(String.format(Locale.ROOT, "%s LIKE %s ESCAPE '%s'", column.getSQL(), pattern, escape));
}
public static Expression like(final Column column, final SQLLang expression) {
return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), expression.getSQL()));
}
public static Expression likeRaw(final Column column, final String pattern) {
return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), pattern));
}
@Override
public String getSQL() {
return expr;
}
}

View File

@ -1,71 +0,0 @@
/*
* 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.querybuilder;
/**
* Created by mariotaku on 15/1/12.
*/
public class Join implements SQLLang {
private final boolean natural;
private final Operation operation;
private final Selectable source;
private final Expression on;
public Join(boolean natural, Operation operation, Selectable source, Expression on) {
this.natural = natural;
this.operation = operation;
this.source = source;
this.on = on;
}
@Override
public String getSQL() {
if (operation == null) throw new IllegalArgumentException("operation can't be null!");
if (source == null) throw new IllegalArgumentException("source can't be null!");
final StringBuilder builder = new StringBuilder();
if (natural) {
builder.append("NATURAL ");
}
builder.append(operation.getSQL());
builder.append(" JOIN ");
builder.append(source.getSQL());
if (on != null) {
builder.append(" ON ");
builder.append(on.getSQL());
}
return builder.toString();
}
public enum Operation implements SQLLang {
LEFT("LEFT"), LEFT_OUTER("LEFT OUTER"), INNER("INNER"), CROSS("CROSS");
private final String op;
Operation(String op) {
this.op = op;
}
@Override
public String getSQL() {
return op;
}
}
}

View File

@ -1,38 +0,0 @@
package org.mariotaku.querybuilder;
public class NewColumn implements SQLLang {
private final String name;
private final String type;
public NewColumn(final String name, final String type) {
this.name = name;
this.type = type;
}
public static NewColumn[] createNewColumns(final String[] colNames, final String[] colTypes) {
if (colNames == null || colTypes == null || colNames.length != colTypes.length)
throw new IllegalArgumentException("length of columns and types not match.");
final NewColumn[] newColumns = new NewColumn[colNames.length];
for (int i = 0, j = colNames.length; i < j; i++) {
newColumns[i] = new NewColumn(colNames[i], colTypes[i]);
}
return newColumns;
}
public String getName() {
return name;
}
@Override
public String getSQL() {
if (name == null || type == null)
throw new NullPointerException("name and type must not be null!");
return String.format("%s %s", name, type);
}
public String getType() {
return type;
}
}

View File

@ -1,17 +0,0 @@
package org.mariotaku.querybuilder;
/**
* Created by mariotaku on 14-8-7.
*/
public enum OnConflict {
ROLLBACK("ROLLBACK"), ABORT("ABORT"), REPLACE("REPLACE"), FAIL("FAIL"), IGNORE("IGNORE");
private final String action;
OnConflict(final String action) {
this.action = action;
}
public String getAction() {
return action;
}
}

View File

@ -1,65 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class OrderBy implements SQLLang {
private final String[] orderBy;
private final boolean[] ascending;
public OrderBy(final String[] orderBy, final boolean[] ascending) {
this.orderBy = orderBy;
this.ascending = ascending;
}
public OrderBy(final String... orderBy) {
this(orderBy, null);
}
public OrderBy(final String orderBy, final boolean ascending) {
this.orderBy = new String[]{orderBy};
this.ascending = new boolean[]{ascending};
}
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
for (int i = 0, j = orderBy.length; i < j; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(orderBy[i]);
if (ascending != null) {
sb.append(ascending[i] ? " ASC" : " DESC");
}
}
return sb.toString();
}
}

View File

@ -1,32 +0,0 @@
package org.mariotaku.querybuilder;
public class RawItemArray implements Selectable {
private final Object[] array;
public RawItemArray(final long[] array) {
final Long[] converted = new Long[array.length];
for (int i = 0, j = array.length; i < j; i++) {
converted[i] = array[i];
}
this.array = converted;
}
public RawItemArray(final Object[] array) {
this.array = array;
}
public RawItemArray(final int[] array) {
final Integer[] converted = new Integer[array.length];
for (int i = 0, j = array.length; i < j; i++) {
converted[i] = array[i];
}
this.array = converted;
}
@Override
public String getSQL() {
return Utils.toString(array, ',', true);
}
}

View File

@ -1,17 +0,0 @@
package org.mariotaku.querybuilder;
public class SQLFunctions {
public static String SUM(final String val) {
return String.format("SUM (%s)", val);
}
public static String COUNT() {
return COUNT("*");
}
public static String COUNT(final String val) {
return String.format("COUNT (%s)", val);
}
}

View File

@ -1,38 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public interface SQLLang extends Cloneable {
/**
* Build SQL query string
*
* @return SQL query
*/
String getSQL();
}

View File

@ -1,7 +0,0 @@
package org.mariotaku.querybuilder;
/**
* Created by mariotaku on 14-8-6.
*/
public interface SQLQuery extends SQLLang {
}

View File

@ -1,128 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
* <p/>
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
* <p/>
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* <p/>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* <p/>
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
import org.mariotaku.querybuilder.query.SQLAlterTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery;
import org.mariotaku.querybuilder.query.SQLCreateViewQuery;
import org.mariotaku.querybuilder.query.SQLDeleteQuery;
import org.mariotaku.querybuilder.query.SQLDropTableQuery;
import org.mariotaku.querybuilder.query.SQLDropTriggerQuery;
import org.mariotaku.querybuilder.query.SQLDropViewQuery;
import org.mariotaku.querybuilder.query.SQLInsertQuery;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.querybuilder.query.SQLUpdateQuery;
public class SQLQueryBuilder {
private SQLQueryBuilder() {
throw new AssertionError("You can't create instance for this class");
}
public static SQLAlterTableQuery.Builder alterTable(final String table) {
return new SQLAlterTableQuery.Builder().alterTable(table);
}
public static SQLCreateTableQuery.Builder createTable(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateTableQuery.Builder().createTable(temporary, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final boolean createIfNotExists, final String name) {
return createTable(false, createIfNotExists, name);
}
public static SQLCreateTableQuery.Builder createTable(final String name) {
return createTable(false, false, name);
}
public static SQLCreateViewQuery.Builder createView(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateViewQuery.Builder().createView(temporary, createIfNotExists, name);
}
public static SQLCreateIndexQuery.Builder createIndex(final boolean unique, final boolean createIfNotExists) {
return new SQLCreateIndexQuery.Builder().createIndex(unique, createIfNotExists);
}
public static SQLCreateTriggerQuery.Builder createTrigger(final boolean temporary, final boolean createIfNotExists,
final String name) {
return new SQLCreateTriggerQuery.Builder().createTrigger(temporary, createIfNotExists, name);
}
public static SQLCreateViewQuery.Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
public static SQLCreateViewQuery.Builder createView(final String name) {
return createView(false, false, name);
}
public static SQLDeleteQuery.Builder deleteFrom(Table table) {
return new SQLDeleteQuery.Builder().from(table);
}
public static SQLDropTableQuery dropTable(final boolean dropIfExists, final String table) {
return new SQLDropTableQuery(dropIfExists, table);
}
public static SQLDropViewQuery dropView(final boolean dropIfExists, final String table) {
return new SQLDropViewQuery(dropIfExists, table);
}
public static SQLDropTriggerQuery dropTrigger(final boolean dropIfExists, final String table) {
return new SQLDropTriggerQuery(dropIfExists, table);
}
public static SQLInsertQuery.Builder insertInto(final OnConflict onConflict, final String table) {
return new SQLInsertQuery.Builder().insertInto(onConflict, table);
}
public static SQLUpdateQuery.Builder update(final OnConflict onConflict, final Table table) {
return new SQLUpdateQuery.Builder().update(onConflict, table);
}
public static SQLUpdateQuery.Builder update(final OnConflict onConflict, final String table) {
return update(onConflict, new Table(table));
}
public static SQLInsertQuery.Builder insertInto(final String table) {
return insertInto(null, table);
}
public static SQLSelectQuery.Builder select(final boolean distinct, final Selectable select) {
return new SQLSelectQuery.Builder().select(distinct, select);
}
public static SQLSelectQuery.Builder select(final Selectable select) {
return select(false, select);
}
}

View File

@ -1,49 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class SQLQueryException extends RuntimeException {
private static final long serialVersionUID = 910158450604676104L;
public SQLQueryException() {
}
public SQLQueryException(final String detailMessage) {
super(detailMessage);
}
public SQLQueryException(final String detailMessage, final Throwable throwable) {
super(detailMessage, throwable);
}
public SQLQueryException(final Throwable throwable) {
super(throwable);
}
}

View File

@ -1,32 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public interface Selectable extends SQLLang {
}

View File

@ -1,27 +0,0 @@
package org.mariotaku.querybuilder;
import java.util.Locale;
/**
* Created by mariotaku on 14-8-7.
*/
public class SetValue implements SQLLang {
private final Columns.Column column;
private final SQLLang expression;
public SetValue(Columns.Column column, SQLLang expression) {
this.column = column;
this.expression = expression;
}
public SetValue(String column, SQLLang expression) {
this(new Columns.Column(column), expression);
}
@Override
public String getSQL() {
return String.format(Locale.ROOT, "%s = %s", column.getSQL(), expression.getSQL());
}
}

View File

@ -1,45 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Table implements Selectable {
public static final Table NEW = new Table("NEW");
private final String table;
public Table(final String table) {
this.table = table;
}
@Override
public String getSQL() {
return table;
}
}

View File

@ -1,44 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
* <p/>
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
* <p/>
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* <p/>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* <p/>
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Tables extends Table {
private final String[] tables;
public Tables(final String... tables) {
super(null);
this.tables = tables;
}
@Override
public String getSQL() {
return Utils.toString(tables, ',', true);
}
}

View File

@ -1,53 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder;
public class Utils {
public static String toString(final Object[] array, final char token, final boolean includeSpace) {
final StringBuilder builder = new StringBuilder();
final int length = array.length;
for (int i = 0; i < length; i++) {
final String string = objectToString(array[i]);
if (string != null) {
if (i > 0) {
builder.append(includeSpace ? token + " " : token);
}
builder.append(string);
}
}
return builder.toString();
}
private static String objectToString(Object o) {
if (o instanceof SQLLang)
return ((SQLLang) o).getSQL();
return o != null ? o.toString() : null;
}
}

View File

@ -1,16 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLLang;
public interface IBuilder<T extends SQLLang> {
public T build();
/**
* Equivalent to {@link #build()}.{@link SQLLang#getSQL()}
*
* @return
*/
public String buildSQL();
}

View File

@ -1,70 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLAlterTableQuery implements SQLQuery {
private String table;
private String renameTo;
private NewColumn addColumn;
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
if (renameTo == null && addColumn == null) throw new NullPointerException();
if (renameTo != null) return String.format("ALTER TABLE %s RENAME TO %s", table, renameTo);
return String.format("ALTER TABLE %s ADD COLUMN %s", table, addColumn.getSQL());
}
void setAddColumn(final NewColumn addColumn) {
this.addColumn = addColumn;
}
void setRenameTo(final String renameTo) {
this.renameTo = renameTo;
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLAlterTableQuery> {
private final SQLAlterTableQuery query = new SQLAlterTableQuery();
private boolean buildCalled;
public Builder addColumn(final NewColumn addColumn) {
checkNotBuilt();
query.setAddColumn(addColumn);
return this;
}
public Builder alterTable(final String table) {
checkNotBuilt();
query.setTable(table);
return this;
}
@Override
public SQLAlterTableQuery build() {
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder renameTo(final String renameTo) {
checkNotBuilt();
query.setRenameTo(renameTo);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,135 +0,0 @@
/*
* 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.querybuilder.query;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Table;
public class SQLCreateIndexQuery implements SQLQuery {
private boolean unique;
private boolean createIfNotExists;
private Table table;
private String indexName;
private Columns indexedColumns;
private Expression where;
SQLCreateIndexQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("Table must not be null!");
if (indexName == null)
throw new NullPointerException("SELECT statement must not be null!");
final StringBuilder sb = new StringBuilder("CREATE");
if (unique) {
sb.append(" UNIQUE");
}
sb.append(" INDEX");
if (createIfNotExists) {
sb.append(" IF NOT EXISTS");
}
if (indexedColumns == null)
throw new NullPointerException("Indexed columns must not be null !");
sb.append(String.format(" %s ON %s (%s)", indexName, table.getSQL(), indexedColumns.getSQL()));
if (where != null) {
sb.append(" WHERE");
sb.append(where.getSQL());
}
return sb.toString();
}
public void setIndexedColumns(Columns indexedColumns) {
this.indexedColumns = indexedColumns;
}
public void setWhere(Expression where) {
this.where = where;
}
void setIndexName(final String indexName) {
this.indexName = indexName;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setTable(final Table table) {
this.table = table;
}
void setUnique(final boolean unique) {
this.unique = unique;
}
public static final class Builder implements IBuilder<SQLCreateIndexQuery> {
private final SQLCreateIndexQuery query = new SQLCreateIndexQuery();
private boolean buildCalled;
public Builder on(final Table table, Columns indexedColumns) {
checkNotBuilt();
query.setTable(table);
query.setIndexedColumns(indexedColumns);
return this;
}
public Builder name(final String name) {
checkNotBuilt();
query.setIndexName(name);
return this;
}
public Builder where(final Expression expression) {
checkNotBuilt();
query.setWhere(expression);
return this;
}
@Override
public SQLCreateIndexQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder createIndex(final boolean unique, final boolean createIfNotExists) {
checkNotBuilt();
query.setUnique(unique);
query.setCreateIfNotExists(createIfNotExists);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,132 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Constraint;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Utils;
public class SQLCreateTableQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private String table;
private NewColumn[] newColumns;
private SQLSelectQuery selectStmt;
private Constraint[] constraints;
SQLCreateTableQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("NAME must not be null!");
if ((newColumns == null || newColumns.length == 0) && selectStmt == null)
throw new NullPointerException("Columns or AS must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("TABLE ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(table);
sb.append(' ');
if (newColumns != null && newColumns.length > 0) {
sb.append('(');
sb.append(Utils.toString(newColumns, ',', true));
if (constraints != null && constraints.length > 0) {
sb.append(", ");
sb.append(Utils.toString(constraints, ',', true));
sb.append(' ');
}
sb.append(')');
} else {
sb.append("AS ");
sb.append(selectStmt.getSQL());
}
return sb.toString();
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setNewColumns(final NewColumn[] newColumns) {
this.newColumns = newColumns;
}
void setTable(final String table) {
this.table = table;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static final class Builder implements IBuilder<SQLCreateTableQuery> {
private final SQLCreateTableQuery query = new SQLCreateTableQuery();
private boolean buildCalled;
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
@Override
public SQLCreateTableQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder columns(final NewColumn... newColumns) {
checkNotBuilt();
query.setNewColumns(newColumns);
return this;
}
public Builder constraint(final Constraint... constraints) {
checkNotBuilt();
query.setConstraints(constraints);
return this;
}
public Builder createTable(final boolean temporary, final boolean createIfNotExists, final String table) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setTable(table);
return this;
}
public Builder createTable(final boolean createIfNotExists, final String table) {
return createTable(false, createIfNotExists, table);
}
public Builder createTemporaryTable(final boolean createIfNotExists, final String table) {
return createTable(true, createIfNotExists, table);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
private void setConstraints(Constraint[] constraints) {
this.constraints = constraints;
}
}

View File

@ -1,202 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.Utils;
import java.util.Locale;
/**
* Created by mariotaku on 14-8-6.
*/
public class SQLCreateTriggerQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private boolean forEachRow;
private String name;
private Table on;
private Type type;
private Event event;
private Columns updateOf;
private SQLQuery[] actions;
private Expression when;
void setActions(SQLQuery[] actions) {
this.actions = actions;
}
void setForEachRow(boolean forEachRow) {
this.forEachRow = forEachRow;
}
void setOn(Table on) {
this.on = on;
}
void setUpdateOf(Columns updateOf) {
this.updateOf = updateOf;
}
void setType(Type type) {
this.type = type;
}
void setEvent(Event event) {
this.event = event;
}
void setWhen(Expression when) {
this.when = when;
}
@Override
public String getSQL() {
if (name == null) throw new NullPointerException("NAME must not be null!");
if (event == null) throw new NullPointerException("EVENT must not be null!");
if (on == null) throw new NullPointerException("ON must not be null!");
if (actions == null) throw new NullPointerException("ACTIONS must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("TRIGGER ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(name);
sb.append(' ');
if (type != null) {
sb.append(type.getSQL());
sb.append(' ');
}
sb.append(event.getSQL());
sb.append(' ');
if (event == Event.UPDATE) {
sb.append(String.format(Locale.ROOT, "%s ", updateOf.getSQL()));
}
sb.append(String.format(Locale.ROOT, "ON %s ", on.getSQL()));
if (forEachRow) {
sb.append("FOR EACH ROW ");
}
if (when != null) {
sb.append(String.format(Locale.ROOT, "WHEN %s ", when.getSQL()));
}
sb.append(String.format(Locale.ROOT, "BEGIN %s; END", Utils.toString(actions, ';', true)));
return sb.toString();
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setName(final String name) {
this.name = name;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static enum Type implements SQLLang {
BEFORE("BEFORE"), AFTER("AFTER"), INSTEAD_OF("INSTEAD OF");
private final String lang;
Type(String lang) {
this.lang = lang;
}
@Override
public String getSQL() {
return lang;
}
}
public static enum Event implements SQLLang {
INSERT("INSERT"), DELETE("DELETE"), UPDATE("UPDATE");
private final String lang;
Event(String lang) {
this.lang = lang;
}
@Override
public String getSQL() {
return lang;
}
}
public static class Builder implements IBuilder<SQLCreateTriggerQuery> {
private final SQLCreateTriggerQuery query = new SQLCreateTriggerQuery();
private boolean buildCalled;
public Builder forEachRow(final boolean forEachRow) {
checkNotBuilt();
query.setForEachRow(forEachRow);
return this;
}
public Builder on(final Table on) {
checkNotBuilt();
query.setOn(on);
return this;
}
public Builder event(Event event) {
checkNotBuilt();
query.setEvent(event);
return this;
}
public Builder type(Type type) {
checkNotBuilt();
query.setType(type);
return this;
}
public Builder updateOf(Columns updateOf) {
checkNotBuilt();
query.setUpdateOf(updateOf);
return this;
}
public Builder actions(SQLQuery... actions) {
checkNotBuilt();
query.setActions(actions);
return this;
}
public Builder when(Expression when) {
checkNotBuilt();
query.setWhen(when);
return this;
}
@Override
public SQLCreateTriggerQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
public Builder createTrigger(boolean temporary, boolean createIfNotExists, String name) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setName(name);
return this;
}
}
}

View File

@ -1,91 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLCreateViewQuery implements SQLQuery {
private boolean temporary;
private boolean createIfNotExists;
private String name;
private SQLSelectQuery selectStmt;
SQLCreateViewQuery() {
}
@Override
public String getSQL() {
if (name == null) throw new NullPointerException("NAME must not be null!");
if (selectStmt == null)
throw new NullPointerException("SELECT statement must not be null!");
final StringBuilder sb = new StringBuilder("CREATE ");
if (temporary) {
sb.append("TEMPORARY ");
}
sb.append("VIEW ");
if (createIfNotExists) {
sb.append("IF NOT EXISTS ");
}
sb.append(String.format("%s AS %s", name, selectStmt.getSQL()));
return sb.toString();
}
void setAs(final SQLSelectQuery selectStmt) {
this.selectStmt = selectStmt;
}
void setCreateIfNotExists(final boolean createIfNotExists) {
this.createIfNotExists = createIfNotExists;
}
void setName(final String name) {
this.name = name;
}
void setTemporary(final boolean temporary) {
this.temporary = temporary;
}
public static final class Builder implements IBuilder<SQLCreateViewQuery> {
private final SQLCreateViewQuery query = new SQLCreateViewQuery();
private boolean buildCalled;
public Builder as(final SQLSelectQuery selectStmt) {
checkNotBuilt();
query.setAs(selectStmt);
return this;
}
@Override
public SQLCreateViewQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder createTemporaryView(final boolean createIfNotExists, final String name) {
return createView(true, createIfNotExists, name);
}
public Builder createView(final boolean temporary, final boolean createIfNotExists, final String name) {
checkNotBuilt();
query.setTemporary(temporary);
query.setCreateIfNotExists(createIfNotExists);
query.setName(name);
return this;
}
public Builder createView(final boolean createIfNotExists, final String name) {
return createView(false, createIfNotExists, name);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,58 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Table;
public class SQLDeleteQuery implements SQLQuery {
private Table table;
private Expression where;
@Override
public String getSQL() {
if (where == null) return String.format("DELETE FROM %s", table.getSQL());
return String.format("DELETE FROM %S WHERE %s", table.getSQL(), where.getSQL());
}
void setFrom(final Table table) {
this.table = table;
}
void setWhere(final Expression where) {
this.where = where;
}
public static final class Builder implements IBuilder<SQLDeleteQuery> {
private final SQLDeleteQuery query = new SQLDeleteQuery();
private boolean buildCalled;
@Override
public SQLDeleteQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder from(final Table table) {
checkNotBuilt();
query.setFrom(table);
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,24 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.SQLQuery;
public class SQLDropQuery implements SQLQuery {
private final boolean dropIfExists;
private final String type;
private final String target;
public SQLDropQuery(final boolean dropIfExists, final String type, final String target) {
if (target == null) throw new NullPointerException();
this.dropIfExists = dropIfExists;
this.type = type;
this.target = target;
}
@Override
public final String getSQL() {
if (dropIfExists) return String.format("DROP %s IF EXISTS %s", type, target);
return String.format("DROP %s %s", type, target);
}
}

View File

@ -1,9 +0,0 @@
package org.mariotaku.querybuilder.query;
public class SQLDropTableQuery extends SQLDropQuery {
public SQLDropTableQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "TABLE", table);
}
}

View File

@ -1,9 +0,0 @@
package org.mariotaku.querybuilder.query;
public class SQLDropTriggerQuery extends SQLDropQuery {
public SQLDropTriggerQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "TRIGGER", table);
}
}

View File

@ -1,9 +0,0 @@
package org.mariotaku.querybuilder.query;
public class SQLDropViewQuery extends SQLDropQuery {
public SQLDropViewQuery(final boolean dropIfExists, final String table) {
super(dropIfExists, "VIEW", table);
}
}

View File

@ -1,115 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.Utils;
public class SQLInsertQuery implements SQLQuery {
private OnConflict onConflict;
private String table;
private String[] columns;
private String values;
SQLInsertQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
final StringBuilder sb = new StringBuilder();
sb.append("INSERT ");
if (onConflict != null) {
sb.append("OR ");
sb.append(onConflict.getAction());
sb.append(" ");
}
sb.append("INTO ");
sb.append(table);
sb.append(" (");
sb.append(Utils.toString(columns, ',', true));
sb.append(") ");
sb.append(values);
return sb.toString();
}
void setColumns(final String[] columns) {
this.columns = columns;
}
void setOnConflict(final OnConflict onConflict) {
this.onConflict = onConflict;
}
void setSelect(final SQLSelectQuery select) {
this.values = select.getSQL();
}
void setValues(final String... values) {
this.values = "VALUES (" + Utils.toString(values, ',', true) + ")";
}
void setTable(final String table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLInsertQuery> {
private final SQLInsertQuery query = new SQLInsertQuery();
private boolean buildCalled;
@Override
public SQLInsertQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder columns(final String[] columns) {
checkNotBuilt();
query.setColumns(columns);
return this;
}
public Builder values(final String[] values) {
checkNotBuilt();
query.setValues(values);
return this;
}
public Builder values(final String values) {
checkNotBuilt();
query.setValues(values);
return this;
}
public Builder insertInto(final OnConflict onConflict, final String table) {
checkNotBuilt();
query.setOnConflict(onConflict);
query.setTable(table);
return this;
}
public Builder insertInto(final String table) {
return insertInto(null, table);
}
public Builder select(final SQLSelectQuery select) {
checkNotBuilt();
query.setSelect(select);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -1,280 +0,0 @@
/**
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.Join;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.SQLLang;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SQLQueryException;
import org.mariotaku.querybuilder.Selectable;
import java.util.ArrayList;
import java.util.List;
public class SQLSelectQuery implements SQLQuery, Selectable {
private final List<InternalQuery> internalQueries = new ArrayList<>();
private InternalQuery currentInternalQuery;
private OrderBy orderBy;
private Integer limit = null, offset = null;
SQLSelectQuery() {
initCurrentQuery();
}
@Override
public String getSQL() {
final StringBuilder sb = new StringBuilder();
final int size = internalQueries.size();
for (int i = 0; i < size; i++) {
if (i != 0) {
sb.append("UNION ");
}
final InternalQuery query = internalQueries.get(i);
sb.append(query.getSQL());
}
if (orderBy != null) {
sb.append(String.format("ORDER BY %s ", orderBy.getSQL()));
}
if (limit != null) {
sb.append(String.format("LIMIT %s ", limit));
if (offset != null) {
sb.append(String.format("OFFSET %s ", offset));
}
}
return sb.toString();
}
private void initCurrentQuery() {
currentInternalQuery = new InternalQuery();
internalQueries.add(currentInternalQuery);
}
void setDistinct(final boolean distinct) {
currentInternalQuery.setDistinct(distinct);
}
void setFrom(final Selectable from) {
currentInternalQuery.setFrom(from);
}
void setGroupBy(final Selectable groupBy) {
currentInternalQuery.setGroupBy(groupBy);
}
void setHaving(final Expression having) {
currentInternalQuery.setHaving(having);
}
void setJoin(final Join join) {
currentInternalQuery.setJoin(join);
}
void setLimit(final int limit) {
this.limit = limit;
}
void setOffset(final int offset) {
this.offset = offset;
}
void setOrderBy(final OrderBy orderBy) {
this.orderBy = orderBy;
}
void setSelect(final Selectable select) {
currentInternalQuery.setSelect(select);
}
void setWhere(final Expression where) {
currentInternalQuery.setWhere(where);
}
void union() {
initCurrentQuery();
}
public static final class Builder implements IBuilder<SQLSelectQuery> {
private final SQLSelectQuery query = new SQLSelectQuery();
private boolean buildCalled;
@Override
public SQLSelectQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder from(final Selectable from) {
checkNotBuilt();
query.setFrom(from);
return this;
}
public Builder groupBy(final Selectable groupBy) {
checkNotBuilt();
query.setGroupBy(groupBy);
return this;
}
public Builder having(final Expression having) {
checkNotBuilt();
query.setHaving(having);
return this;
}
public Builder limit(final int limit) {
checkNotBuilt();
query.setLimit(limit);
return this;
}
public Builder join(final Join join) {
checkNotBuilt();
query.setJoin(join);
return this;
}
public Builder offset(final int offset) {
query.setOffset(offset);
return this;
}
public Builder orderBy(final OrderBy orderBy) {
checkNotBuilt();
query.setOrderBy(orderBy);
return this;
}
public Builder select(final boolean distinct, final Selectable select) {
checkNotBuilt();
query.setSelect(select);
query.setDistinct(distinct);
return this;
}
public Builder select(final Selectable select) {
checkNotBuilt();
select(false, select);
return this;
}
public Builder union() {
checkNotBuilt();
query.union();
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
private static class InternalQuery implements SQLLang {
private boolean distinct;
private Selectable select, from, groupBy;
private Expression where, having;
private Join join;
@Override
public String getSQL() {
if (select == null) throw new SQLQueryException("selectable is null");
final StringBuilder sb = new StringBuilder("SELECT ");
if (distinct) {
sb.append("DISTINCT ");
}
sb.append(String.format("%s ", select.getSQL()));
if (!(select instanceof SQLSelectQuery) && from == null)
throw new SQLQueryException("FROM not specified");
else if (from != null) {
if (from instanceof SQLSelectQuery) {
sb.append(String.format("FROM (%s) ", from.getSQL()));
} else {
sb.append(String.format("FROM %s ", from.getSQL()));
}
}
if (join != null) {
sb.append(String.format("%s ", join.getSQL()));
}
if (where != null) {
sb.append(String.format("WHERE %s ", where.getSQL()));
}
if (groupBy != null) {
sb.append(String.format("GROUP BY %s ", groupBy.getSQL()));
if (having != null) {
sb.append(String.format("HAVING %s ", having.getSQL()));
}
}
return sb.toString();
}
void setJoin(final Join join) {
this.join = join;
}
void setDistinct(final boolean distinct) {
this.distinct = distinct;
}
void setFrom(final Selectable from) {
this.from = from;
}
void setGroupBy(final Selectable groupBy) {
this.groupBy = groupBy;
}
void setHaving(final Expression having) {
this.having = having;
}
void setSelect(final Selectable select) {
this.select = select;
}
void setWhere(final Expression where) {
this.where = where;
}
}
}

View File

@ -1,103 +0,0 @@
package org.mariotaku.querybuilder.query;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SetValue;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.Utils;
public class SQLUpdateQuery implements SQLQuery {
private OnConflict onConflict;
private Table table;
private SetValue[] values;
private Expression where;
SQLUpdateQuery() {
}
@Override
public String getSQL() {
if (table == null) throw new NullPointerException("table must not be null!");
final StringBuilder sb = new StringBuilder();
sb.append("UPDATE ");
if (onConflict != null) {
sb.append("OR ");
sb.append(onConflict.getAction());
sb.append(" ");
}
sb.append(table.getSQL());
sb.append(" SET ");
sb.append(Utils.toString(values, ',', true));
if (where != null) {
sb.append(" WHERE ");
sb.append(where.getSQL());
}
return sb.toString();
}
void setWhere(final Expression where) {
this.where = where;
}
void setValues(final SetValue[] columns) {
this.values = columns;
}
void setOnConflict(final OnConflict onConflict) {
this.onConflict = onConflict;
}
void setTable(final Table table) {
this.table = table;
}
public static final class Builder implements IBuilder<SQLUpdateQuery> {
private final SQLUpdateQuery query = new SQLUpdateQuery();
private boolean buildCalled;
@Override
public SQLUpdateQuery build() {
buildCalled = true;
return query;
}
@Override
public String buildSQL() {
return build().getSQL();
}
public Builder set(final SetValue... values) {
checkNotBuilt();
query.setValues(values);
return this;
}
public Builder where(final Expression where) {
checkNotBuilt();
query.setWhere(where);
return this;
}
public Builder update(final OnConflict onConflict, final Table table) {
checkNotBuilt();
query.setOnConflict(onConflict);
query.setTable(table);
return this;
}
public Builder update(final Table table) {
return update(null, table);
}
private void checkNotBuilt() {
if (buildCalled) throw new IllegalStateException();
}
}
}

View File

@ -90,7 +90,7 @@ dependencies {
compile 'com.makeramen:roundedimageview:2.1.0'
compile 'com.soundcloud.android:android-crop:1.0.0@aar'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
compile 'com.github.mariotaku:PickNCrop:b8322f8e3c'
compile 'com.github.mariotaku:PickNCrop:44b09cbc69'
compile 'com.diogobernardino:williamchart:1.7.0'
googleCompile 'com.google.android.gms:play-services-maps:7.5.0'
googleCompile 'com.google.maps.android:android-maps-utils:0.3.4'

View File

@ -17,21 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.querybuilder;
package android.support.v4.content;
/**
* Created by mariotaku on 15/6/24.
* Created by mariotaku on 15/7/5.
*/
public final class RawSQLLang implements SQLLang {
private final String statement;
public RawSQLLang(String statement) {
this.statement = statement;
}
@Override
public String getSQL() {
return statement;
public class LoaderTrojan {
public static <T> boolean isContentChanged(final Loader<T> loader) {
return loader.mContentChanged;
}
}

View File

@ -53,10 +53,10 @@ import android.widget.Spinner;
import android.widget.TextView;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.QuickSearchBarActivity.SuggestionItem;
import org.mariotaku.twidere.adapter.AccountsSpinnerAdapter;

View File

@ -1,105 +0,0 @@
/*
* 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.adapter;
import android.content.Context;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatus.CursorIndices;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
/**
* Created by mariotaku on 14/11/19.
*/
public class CursorStatusesAdapter extends AbsStatusesAdapter<Cursor> {
private Cursor mCursor;
private CursorIndices mIndices;
public CursorStatusesAdapter(Context context, boolean compact) {
super(context, compact);
setHasStableIds(true);
}
@Override
public boolean isGapItem(int position) {
final Cursor c = mCursor;
if (c == null || !c.moveToPosition(position) || position == getStatusesCount() - 1)
return false;
return c.getInt(mIndices.is_gap) == 1;
}
@Override
public long getItemId(int position) {
if (position == getStatusesCount()) return Long.MAX_VALUE;
final Cursor c = mCursor;
if (c != null && c.moveToPosition(position)) {
return c.getLong(mIndices._id);
}
return RecyclerView.NO_ID;
}
@Override
protected void bindStatus(StatusViewHolder holder, int position) {
mCursor.moveToPosition(position);
holder.displayStatus(mCursor, mIndices, isShowInReplyTo());
}
@Override
public ParcelableStatus getStatus(int position) {
if (isLoadMoreIndicatorVisible() && position == getStatusesCount() - 1) return null;
final Cursor c = mCursor;
if (c != null && c.moveToPosition(position)) {
return new ParcelableStatus(c, mIndices);
}
return null;
}
@Override
public int getStatusesCount() {
if (mCursor == null) return 0;
return mCursor.getCount();
}
@Override
public long getStatusId(int position) {
if (position == getStatusesCount()) return -1;
final Cursor c = mCursor;
if (c != null && c.moveToPosition(position)) {
return c.getLong(mIndices.status_id);
}
return -1;
}
@Override
public void setData(Cursor data) {
mCursor = data;
mIndices = data != null ? new CursorIndices(data) : null;
notifyDataSetChanged();
}
@Override
public Cursor getData() {
return mCursor;
}
}

View File

@ -32,10 +32,10 @@ import android.widget.EditText;
import android.widget.FilterQueryProvider;
import android.widget.TextView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;

View File

@ -54,9 +54,9 @@ import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.UserListSelectorActivity;
import org.mariotaku.twidere.adapter.SourceAutoCompleteAdapter;

View File

@ -55,9 +55,9 @@ import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.activity.support.CustomTabEditorActivity;

View File

@ -77,7 +77,7 @@ import com.commonsware.cwac.merge.MergeAdapter;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.SettingsActivity;
import org.mariotaku.twidere.activity.iface.IThemedActivity;

View File

@ -35,7 +35,7 @@ import android.widget.TextView;
import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.activity.support.SignInActivity;

View File

@ -23,7 +23,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@ -35,14 +34,15 @@ import com.desmond.asyncmanager.AsyncManager;
import com.desmond.asyncmanager.TaskRunnable;
import com.squareup.otto.Subscribe;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter;
import org.mariotaku.twidere.adapter.CursorStatusesAdapter;
import org.mariotaku.twidere.loader.support.ExtendedCursorLoader;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.loader.support.ObjectCursorLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Filters;
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses;
@ -55,6 +55,8 @@ import org.mariotaku.twidere.util.message.StatusDestroyedEvent;
import org.mariotaku.twidere.util.message.StatusListChangedEvent;
import org.mariotaku.twidere.util.message.StatusRetweetedEvent;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.buildStatusFilterWhereClause;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getOldestStatusIdsFromDatabase;
@ -63,12 +65,12 @@ import static org.mariotaku.twidere.util.Utils.getTableNameByUri;
/**
* Created by mariotaku on 14/12/3.
*/
public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor> {
public abstract class CursorStatusesFragment extends AbsStatusesFragment<List<ParcelableStatus>> {
@Override
protected void onLoadingFinished() {
final long[] accountIds = getAccountIds();
final AbsStatusesAdapter<Cursor> adapter = getAdapter();
final AbsStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
if (adapter.getItemCount() > 0) {
showContent();
} else if (accountIds.length > 0) {
@ -84,9 +86,9 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
public abstract Uri getContentUri();
@Override
protected Loader<Cursor> onCreateStatusesLoader(final Context context,
final Bundle args,
final boolean fromUser) {
protected Loader<List<ParcelableStatus>> onCreateStatusesLoader(final Context context,
final Bundle args,
final boolean fromUser) {
final Uri uri = getContentUri();
final String table = getTableNameByUri(uri);
final String sortOrder = getSortOrder();
@ -99,10 +101,11 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
where = accountWhere;
}
final String selection = processWhere(where).getSQL();
final AbsStatusesAdapter<Cursor> adapter = getAdapter();
final AbsStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
adapter.setShowAccountsColor(accountIds.length > 1);
final String[] projection = Statuses.COLUMNS;
return new ExtendedCursorLoader(context, uri, projection, selection, null, sortOrder, fromUser);
return new ObjectCursorLoader<>(context, ParcelableStatus.CursorIndices.class, uri, projection,
selection, null, sortOrder);
}
@Override
@ -198,18 +201,18 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<Cursor>
}
@Override
protected boolean hasMoreData(final Cursor cursor) {
return cursor != null && cursor.getCount() != 0;
protected boolean hasMoreData(final List<ParcelableStatus> cursor) {
return cursor != null && cursor.size() != 0;
}
@NonNull
@Override
protected CursorStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new CursorStatusesAdapter(context, compact);
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
public void onLoaderReset(Loader<List<ParcelableStatus>> loader) {
getAdapter().setData(null);
}

View File

@ -42,9 +42,9 @@ import android.view.View;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.support.HomeActivity;

View File

@ -56,9 +56,9 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DraftsAdapter;

View File

@ -25,7 +25,7 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import org.mariotaku.twidere.adapter.CursorStatusesAdapter;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
@ -41,8 +41,8 @@ public class MentionsTimelineFragment extends CursorStatusesFragment {
@NonNull
@Override
protected CursorStatusesAdapter onCreateAdapter(Context context, boolean compact) {
final CursorStatusesAdapter adapter = super.onCreateAdapter(context, compact);
protected ParcelableStatusesAdapter onCreateAdapter(Context context, boolean compact) {
final ParcelableStatusesAdapter adapter = super.onCreateAdapter(context, compact);
adapter.setShowInReplyTo(false);
return adapter;
}

View File

@ -71,10 +71,10 @@ import com.github.johnpersano.supertoasts.SuperToast.OnDismissListener;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.BaseAppCompatActivity;
import org.mariotaku.twidere.activity.support.ThemedImagePickerActivity;
@ -113,7 +113,6 @@ import org.mariotaku.twidere.util.UserColorNameManager;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import org.mariotaku.twidere.view.ComposeEditText;
import org.mariotaku.twidere.view.ComposeMaterialEditText;
import java.util.ArrayList;
import java.util.Collections;
@ -388,6 +387,7 @@ public class MessagesConversationFragment extends BaseSupportFragment implements
public void onStop() {
mMessagesListView.removeOnScrollListener(mScrollListener);
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
assert bus != null;
bus.unregister(this);
if (mPopupMenu != null) {
mPopupMenu.dismiss();

View File

@ -83,6 +83,7 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<Lis
public void onStart() {
super.onStart();
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
assert bus != null;
bus.register(this);
}

View File

@ -23,12 +23,12 @@ import com.commonsware.cwac.merge.MergeAdapter;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
import org.mariotaku.sqliteqb.library.Table;
import org.mariotaku.sqliteqb.library.query.SQLSelectQuery;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.TrendsAdapter;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;

View File

@ -32,7 +32,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
@ -86,7 +85,7 @@ import com.meizu.flyme.reflect.StatusBarProxy;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.AccountSelectorActivity;
@ -294,7 +293,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mFollowingYouIndicator.setVisibility(relationship.isTargetFollowingSource() ? View.VISIBLE : View.GONE);
final ContentResolver resolver = getContentResolver();
final ContentValues cachedValues = ParcelableUser.makeCachedUserContentValues(user);
final ContentValues cachedValues = ContentValuesCreator.makeCachedUserContentValues(user);
resolver.insert(CachedUsers.CONTENT_URI, cachedValues);
mFollowButton.setVisibility(View.VISIBLE);
} else {

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.loader.support;
import android.content.Context;
import android.net.Uri;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.model.ObjectCursor;
/**
* Created by mariotaku on 15/1/9.
*/
public class ExtendedObjectCursorLoader<E> extends ObjectCursorLoader<E> implements IExtendedLoader {
public ExtendedObjectCursorLoader(Context context, Class<? extends ObjectCursor.CursorIndices<E>> indicesClass) {
super(context, indicesClass);
}
public ExtendedObjectCursorLoader(Context context, Class<? extends ObjectCursor.CursorIndices<E>> indicesClass,
Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder, boolean fromUser) {
super(context, indicesClass, uri, projection, selection, selectionArgs, sortOrder);
setFromUser(fromUser);
}
@Override
public boolean isFromUser() {
return true;
}
@Override
public void setFromUser(boolean fromUser) {
//No-op
}
}

View File

@ -0,0 +1,249 @@
/*
* 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.loader.support;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.LoaderTrojan;
import org.mariotaku.twidere.model.ObjectCursor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
/**
* Created by mariotaku on 15-7-5.
*/
public class ObjectCursorLoader<T> extends AsyncTaskLoader<List<T>> {
final ForceLoadContentObserver mObserver;
final Class<? extends ObjectCursor.CursorIndices<T>> mIndicesClass;
Uri mUri;
String[] mProjection;
String mSelection;
String[] mSelectionArgs;
String mSortOrder;
ObjectCursor<T> mObjects;
/* Runs on a worker thread */
@Override
public ObjectCursor<T> loadInBackground() {
Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
mSelectionArgs, mSortOrder);
if (cursor != null) {
// Ensure the cursor window is filled
cursor.getCount();
cursor.registerContentObserver(mObserver);
}
if (cursor == null) throw new NullPointerException("Cursor is null");
return new ObjectCursor<>(cursor, createIndices(cursor));
}
@SuppressWarnings("TryWithIdenticalCatches")
@NonNull
private ObjectCursor.CursorIndices<T> createIndices(final Cursor cursor) {
try {
return mIndicesClass.getConstructor(Cursor.class).newInstance(cursor);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/* Runs on the UI thread */
@Override
public void deliverResult(List<T> data) {
final ObjectCursor<T> cursor = (ObjectCursor<T>) data;
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
ObjectCursor<T> oldCursor = mObjects;
mObjects = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Creates an empty unspecified CursorLoader. You must follow this with
* calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc
* to specify the query to perform.
*/
public ObjectCursorLoader(Context context, Class<? extends ObjectCursor.CursorIndices<T>> indicesClass) {
super(context);
mIndicesClass = indicesClass;
mObserver = new ForceLoadContentObserver();
}
/**
* Creates a fully-specified CursorLoader. See
* {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
* ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
public ObjectCursorLoader(Context context, Class<? extends ObjectCursor.CursorIndices<T>> indicesClass,
Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
super(context);
mIndicesClass = indicesClass;
mObserver = new ForceLoadContentObserver();
mUri = uri;
mProjection = projection;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
* <p/>
* Must be called from the UI thread
*/
@Override
protected void onStartLoading() {
if (mObjects != null) {
deliverResult(mObjects);
}
if (takeContentChanged() || mObjects == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(List<T> data) {
final ObjectCursor<T> cursor = (ObjectCursor<T>) data;
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mObjects != null && !mObjects.isClosed()) {
mObjects.close();
}
mObjects = null;
}
public Uri getUri() {
return mUri;
}
public void setUri(Uri uri) {
mUri = uri;
}
public String[] getProjection() {
return mProjection;
}
public void setProjection(String[] projection) {
mProjection = projection;
}
public String getSelection() {
return mSelection;
}
public void setSelection(String selection) {
mSelection = selection;
}
public String[] getSelectionArgs() {
return mSelectionArgs;
}
public void setSelectionArgs(String[] selectionArgs) {
mSelectionArgs = selectionArgs;
}
public String getSortOrder() {
return mSortOrder;
}
public void setSortOrder(String sortOrder) {
mSortOrder = sortOrder;
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix);
writer.print("mUri=");
writer.println(mUri);
writer.print(prefix);
writer.print("mProjection=");
writer.println(Arrays.toString(mProjection));
writer.print(prefix);
writer.print("mSelection=");
writer.println(mSelection);
writer.print(prefix);
writer.print("mSelectionArgs=");
writer.println(Arrays.toString(mSelectionArgs));
writer.print(prefix);
writer.print("mSortOrder=");
writer.println(mSortOrder);
writer.print(prefix);
writer.print("mObjects=");
writer.println(mObjects);
writer.print(prefix);
writer.print("mContentChanged=");
writer.println(LoaderTrojan.isContentChanged(this));
}
}

View File

@ -56,7 +56,7 @@ public abstract class ParcelableActivitiesLoader extends AsyncTaskLoader<List<Pa
return false;
}
protected boolean deleteStatus(final List<ParcelableActivity> activities, final long id) {
protected boolean deleteActivity(final List<ParcelableActivity> activities, final long id) {
if (activities == null || activities.isEmpty()) return false;
boolean result = false;
for (final ParcelableActivity activity : activities.toArray(new ParcelableActivity[activities.size()])) {

View File

@ -27,13 +27,14 @@ import android.os.Bundle;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUser.CachedIndices;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.TwitterWrapper;
@ -71,7 +72,7 @@ public final class ParcelableUserLoader extends AsyncTaskLoader<SingleResponse<P
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableUser user = mExtras.getParcelable(EXTRA_USER);
if (user != null) {
final ContentValues values = ParcelableUser.makeCachedUserContentValues(user);
final ContentValues values = ContentValuesCreator.makeCachedUserContentValues(user);
resolver.insert(CachedUsers.CONTENT_URI, values);
return SingleResponse.getInstance(user);
}

View File

@ -104,27 +104,27 @@ public abstract class TwitterAPIActivitiesLoader extends ParcelableActivitiesLoa
e.printStackTrace();
return new CopyOnWriteArrayList<>(data);
}
final Pair<Long, Long> minId;
final Pair<Long, Long> position;
if (activities.isEmpty()) {
minId = new Pair<>(-1L, -1L);
position = new Pair<>(-1L, -1L);
} else {
final Activity minActivity = Collections.min(activities);
minId = new Pair<>(minActivity.getMinPosition(), minActivity.getMaxPosition());
position = new Pair<>(minActivity.getMinPosition(), minActivity.getMaxPosition());
}
final boolean insertGap = minId.first > 0 && minId.second > 0 && activities.size() > 1
final boolean insertGap = position.first > 0 && position.second > 0 && activities.size() > 1
&& !data.isEmpty() && !truncated;
// mHandler.post(CacheUsersStatusesTask.getRunnable(context, new StatusListResponse(mAccountIds, activities)));
for (final Activity activity : activities) {
final long min = activity.getMinPosition(), max = activity.getMaxPosition();
final boolean deleted = deleteStatus(data, max);
final boolean isGap = minId.first == min && minId.second == max && insertGap && !deleted;
final boolean deleted = deleteActivity(data, max);
final boolean isGap = position.first == min && position.second == max && insertGap && !deleted;
data.add(new ParcelableActivity(activity, mAccountIds, isGap));
}
// final ParcelableActivity[] array = data.toArray(new ParcelableActivity[data.size()]);
// for (int i = 0, size = array.length; i < size; i++) {
// final ParcelableActivity status = array[i];
// if (shouldFilterActivity(mDatabase, status) && !status.is_gap && i != size - 1) {
// deleteStatus(data, status.max_position);
// deleteActivity(data, status.max_position);
// }
// }
if (mComparator != null) {

View File

@ -23,9 +23,9 @@ import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.provider.TwidereDataStore.NetworkUsages;
import org.mariotaku.twidere.util.MathUtils;

View File

@ -19,20 +19,22 @@
package org.mariotaku.twidere.model;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.twidere.api.twitter.model.Activity;
import java.util.Arrays;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.Status;
import org.mariotaku.twidere.api.twitter.model.User;
import org.mariotaku.twidere.api.twitter.model.UserList;
@ParcelablePlease(allFields = false)
@JsonObject
public class ParcelableActivity implements Comparable<ParcelableActivity> {
public class ParcelableActivity implements Comparable<ParcelableActivity>, Parcelable {
public final static int ACTION_FAVORITE = Activity.Action.ACTION_FAVORITE;
public final static int ACTION_FOLLOW = Activity.Action.ACTION_FOLLOW;
@ -44,30 +46,54 @@ public class ParcelableActivity implements Comparable<ParcelableActivity> {
public final static int ACTION_FAVORITED_RETWEET = Activity.Action.ACTION_FAVORITED_RETWEET;
public final static int ACTION_RETWEETED_RETWEET = Activity.Action.ACTION_RETWEETED_RETWEET;
public static final Creator<ParcelableActivity> CREATOR = new Creator<ParcelableActivity>() {
@Override
public ParcelableActivity createFromParcel(Parcel source) {
return new ParcelableActivity(source);
}
@Override
public ParcelableActivity[] newArray(int size) {
return new ParcelableActivity[size];
}
};
@ParcelableThisPlease
@JsonField(name = "account_id")
public long account_id;
@ParcelableThisPlease
@JsonField(name = "timestamp")
public long timestamp;
@ParcelableThisPlease
@JsonField(name = "max_position")
public long max_position;
@ParcelableThisPlease
@JsonField(name = "min_position")
public long min_position;
@ParcelableThisPlease
@JsonField(name = "action")
public int action;
@ParcelableThisPlease
@JsonField(name = "sources")
public ParcelableUser[] sources;
@ParcelableThisPlease
@JsonField(name = "target_users")
public ParcelableUser[] target_users;
@ParcelableThisPlease
@JsonField(name = "target_statuses")
public ParcelableStatus[] target_statuses;
@ParcelableThisPlease
@JsonField(name = "target_user_lists")
public ParcelableUserList[] target_user_lists;
@ParcelableThisPlease
@JsonField(name = "target_object_user_lists")
public ParcelableUserList[] target_object_user_lists;
@ParcelableThisPlease
@JsonField(name = "target_object_statuses")
public ParcelableStatus[] target_object_statuses;
@ParcelableThisPlease
@JsonField(name = "is_gap")
public boolean is_gap;
@ -80,61 +106,19 @@ public class ParcelableActivity implements Comparable<ParcelableActivity> {
action = activity.getAction().getActionId();
max_position = activity.getMaxPosition();
min_position = activity.getMinPosition();
final int sources_size = activity.getSourcesSize();
sources = new ParcelableUser[sources_size];
for (int i = 0; i < sources_size; i++) {
sources[i] = new ParcelableUser(activity.getSources()[i], account_id);
}
final int targets_size = activity.getTargetsSize();
final User[] targetUsers = activity.getTargetUsers();
if (targetUsers != null) {
target_users = new ParcelableUser[targets_size];
for (int i = 0; i < targets_size; i++) {
target_users[i] = new ParcelableUser(targetUsers[i], account_id);
}
} else {
target_users = null;
}
final UserList[] targetUserLists = activity.getTargetUserLists();
if (targetUserLists != null) {
target_user_lists = new ParcelableUserList[targets_size];
for (int i = 0; i < targets_size; i++) {
target_user_lists[i] = new ParcelableUserList(targetUserLists[i], account_id);
}
} else {
target_user_lists = null;
}
final Status[] targetStatuses = activity.getTargetStatuses();
if (targetStatuses != null) {
target_statuses = new ParcelableStatus[targets_size];
for (int i = 0; i < targets_size; i++) {
target_statuses[i] = new ParcelableStatus(targetStatuses[i], account_id, false);
}
} else {
target_statuses = null;
}
final int target_objects_size = activity.getTargetObjectsSize();
final Status[] targetObjectStatuses = activity.getTargetObjectStatuses();
if (targetObjectStatuses != null) {
target_object_statuses = new ParcelableStatus[target_objects_size];
for (int i = 0; i < target_objects_size; i++) {
target_object_statuses[i] = new ParcelableStatus(targetObjectStatuses[i], account_id, false);
}
} else {
target_object_statuses = null;
}
final UserList[] targetObjectUserLists = activity.getTargetObjectUserLists();
if (targetObjectUserLists != null) {
target_object_user_lists = new ParcelableUserList[target_objects_size];
for (int i = 0; i < target_objects_size; i++) {
target_object_user_lists[i] = new ParcelableUserList(targetObjectUserLists[i], account_id);
}
} else {
target_object_user_lists = null;
}
sources = ParcelableUser.fromUsers(activity.getSources(), account_id);
target_users = ParcelableUser.fromUsers(activity.getTargetUsers(), account_id);
target_user_lists = ParcelableUserList.fromUserLists(activity.getTargetUserLists(), account_id);
target_statuses = ParcelableStatus.fromStatuses(activity.getTargetStatuses(), account_id);
target_object_statuses = ParcelableStatus.fromStatuses(activity.getTargetObjectStatuses(), account_id);
target_object_user_lists = ParcelableUserList.fromUserLists(activity.getTargetObjectUserLists(), account_id);
this.is_gap = is_gap;
}
public ParcelableActivity(Parcel src) {
ParcelableActivityParcelablePlease.readFromParcel(this, src);
}
@Override
public int compareTo(@NonNull final ParcelableActivity another) {
@ -163,4 +147,13 @@ public class ParcelableActivity implements Comparable<ParcelableActivity> {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
ParcelableActivityParcelablePlease.writeToParcel(this, dest, flags);
}
}

View File

@ -48,6 +48,7 @@ import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.InboxStyle;
import android.support.v4.util.LongSparseArray;
@ -60,16 +61,16 @@ import com.squareup.okhttp.internal.Network;
import com.squareup.otto.Bus;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.RawSQLLang;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.SetValue;
import org.mariotaku.querybuilder.query.SQLInsertQuery;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.querybuilder.query.SQLUpdateQuery;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OnConflict;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.sqliteqb.library.RawSQLLang;
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
import org.mariotaku.sqliteqb.library.SetValue;
import org.mariotaku.sqliteqb.library.query.SQLInsertQuery;
import org.mariotaku.sqliteqb.library.query.SQLSelectQuery;
import org.mariotaku.sqliteqb.library.query.SQLUpdateQuery;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
@ -136,7 +137,10 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
private ContentResolver mContentResolver;
private SQLiteDatabaseWrapper mDatabaseWrapper;
private PermissionsManager mPermissionsManager;
@Nullable
private NotificationManager mNotificationManager;
private ReadStateManager mReadStateManager;
private SharedPreferencesWrapper mPreferences;
private ImagePreloader mImagePreloader;

View File

@ -44,7 +44,7 @@ import android.widget.Toast;
import com.nostra13.universalimageloader.utils.IoUtils;
import com.twitter.Extractor;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.restfu.http.ContentType;
import org.mariotaku.restfu.http.mime.FileTypedData;
import org.mariotaku.twidere.Constants;

View File

@ -31,6 +31,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.util.LongSparseArray;
import android.util.Log;
import android.util.Pair;
import com.desmond.asyncmanager.AsyncManager;
import com.desmond.asyncmanager.BackgroundTask;
@ -38,15 +39,16 @@ import com.desmond.asyncmanager.TaskRunnable;
import com.squareup.otto.Bus;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.SQLFunctions;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.sqliteqb.library.SQLFunctions;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.http.HttpResponseCode;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
import org.mariotaku.twidere.api.twitter.model.FriendshipUpdate;
import org.mariotaku.twidere.api.twitter.model.Paging;
@ -98,6 +100,7 @@ import org.mariotaku.twidere.util.message.StatusRetweetedEvent;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@ -106,21 +109,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
import edu.tsinghua.spice.Utilies.SpiceProfilingUtil;
import edu.tsinghua.spice.Utilies.TypeMappingUtil;
import static org.mariotaku.twidere.provider.TwidereDataStore.STATUSES_URIS;
import static org.mariotaku.twidere.util.ContentValuesCreator.createDirectMessage;
import static org.mariotaku.twidere.util.ContentValuesCreator.createStatus;
import static org.mariotaku.twidere.util.ContentValuesCreator.createTrends;
import static org.mariotaku.twidere.util.Utils.getActivatedAccountIds;
import static org.mariotaku.twidere.util.Utils.getDefaultAccountId;
import static org.mariotaku.twidere.util.Utils.getNewestMessageIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getNewestStatusIdsFromDatabase;
import static org.mariotaku.twidere.util.Utils.getStatusCountInDatabase;
import static org.mariotaku.twidere.util.Utils.showErrorMessage;
import static org.mariotaku.twidere.util.Utils.showInfoMessage;
import static org.mariotaku.twidere.util.Utils.showOkMessage;
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkDelete;
import static org.mariotaku.twidere.util.content.ContentResolverUtils.bulkInsert;
public class AsyncTwitterWrapper extends TwitterWrapper {
private final Context mContext;
@ -410,7 +398,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Deprecated
public void refreshAll() {
refreshAll(getActivatedAccountIds(mContext));
refreshAll(Utils.getActivatedAccountIds(mContext));
}
public boolean refreshAll(final long[] accountIds) {
@ -420,16 +408,16 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final Object[] result = new Object[8];
result[0] = mPreferences.getBoolean(KEY_HOME_REFRESH_MENTIONS);
if (Boolean.TRUE.equals(result[0] = mPreferences.getBoolean(KEY_HOME_REFRESH_MENTIONS))) {
result[1] = getNewestStatusIdsFromDatabase(mContext, Mentions.CONTENT_URI, accountIds);
result[1] = Utils.getNewestStatusIdsFromDatabase(mContext, Mentions.CONTENT_URI, accountIds);
}
if (Boolean.TRUE.equals(result[2] = mPreferences.getBoolean(KEY_HOME_REFRESH_DIRECT_MESSAGES))) {
result[3] = getNewestMessageIdsFromDatabase(mContext, DirectMessages.Inbox.CONTENT_URI, accountIds);
result[3] = Utils.getNewestMessageIdsFromDatabase(mContext, DirectMessages.Inbox.CONTENT_URI, accountIds);
}
if (Boolean.TRUE.equals(result[4] = mPreferences.getBoolean(KEY_HOME_REFRESH_TRENDS))) {
result[5] = getDefaultAccountId(mContext);
result[5] = Utils.getDefaultAccountId(mContext);
result[6] = mPreferences.getInt(KEY_LOCAL_TRENDS_WOEID, 1);
}
result[7] = getNewestStatusIdsFromDatabase(mContext, Statuses.CONTENT_URI, accountIds);
result[7] = Utils.getNewestStatusIdsFromDatabase(mContext, Statuses.CONTENT_URI, accountIds);
return result;
}
@ -598,12 +586,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
if (result.hasData()) {
showOkMessage(mContext, R.string.profile_banner_image_updated, false);
Utils.showOkMessage(mContext, R.string.profile_banner_image_updated, false);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new ProfileUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
Utils.showErrorMessage(mContext, R.string.action_updating_profile_banner_image, result.getException(),
true);
}
}
@ -669,11 +657,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
super.onPostExecute(result);
if (result.hasData()) {
showOkMessage(mContext, R.string.profile_image_updated, false);
Utils.showOkMessage(mContext, R.string.profile_image_updated, false);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new ProfileUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_updating_profile_image, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_updating_profile_image, result.getException(), true);
}
}
@ -720,9 +709,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.accepted_users_follow_request,
manager.getDisplayName(user, nameFirst, true));
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
} else {
showErrorMessage(mContext, R.string.action_accepting_follow_request,
Utils.showErrorMessage(mContext, R.string.action_accepting_follow_request,
result.getException(), false);
}
final Intent intent = new Intent(BROADCAST_FRIENDSHIP_ACCEPTED);
@ -780,9 +769,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
message = res.getQuantityString(R.plurals.added_N_users_to_list, users.length, users.length,
result.getData().name);
}
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
} else {
showErrorMessage(mContext, R.string.action_adding_member, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_adding_member, result.getException(), true);
}
final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBERS_ADDED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
@ -840,7 +829,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
try {
final User user = twitter.createBlock(user_id);
Utils.setLastSeen(mContext, user.getId(), -1);
for (final Uri uri : STATUSES_URIS) {
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final Expression where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, account_id),
Expression.equals(Statuses.USER_ID, user_id));
mResolver.delete(uri, where.getSQL(), null);
@ -864,11 +853,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.blocked_user,
manager.getDisplayName(result.getData(), nameFirst, true));
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_blocking, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_blocking, result.getException(), true);
}
super.onPostExecute(result);
}
@ -918,6 +908,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPreExecute();
mCreatingFavoriteIds.put(account_id, status_id);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusListChangedEvent());
}
@ -940,10 +931,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
//end
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new FavoriteCreatedEvent(status));
showOkMessage(mContext, R.string.status_favorited, false);
Utils.showOkMessage(mContext, R.string.status_favorited, false);
} else {
showErrorMessage(mContext, R.string.action_favoriting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_favoriting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -998,11 +990,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
message = mContext.getString(R.string.followed_user,
manager.getDisplayName(user, nameFirst, true));
}
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_following, result.getException(), false);
Utils.showErrorMessage(mContext, R.string.action_following, result.getException(), false);
}
super.onPostExecute(result);
}
@ -1021,8 +1014,8 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
private void deleteCaches(final List<Long> list) {
for (final Uri uri : STATUSES_URIS) {
bulkDelete(mResolver, uri, Statuses.USER_ID, list, Statuses.ACCOUNT_ID + " = " + account_id, false);
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
ContentResolverUtils.bulkDelete(mResolver, uri, Statuses.USER_ID, list, Statuses.ACCOUNT_ID + " = " + account_id, false);
}
// I bet you don't want to see these users in your auto complete list.
//TODO insert to blocked users data
@ -1054,9 +1047,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected void onPostExecute(final ListResponse<Long> result) {
if (result.list != null) {
showInfoMessage(mContext, R.string.users_blocked, false);
Utils.showInfoMessage(mContext, R.string.users_blocked, false);
} else {
showErrorMessage(mContext, R.string.action_blocking, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_blocking, result.getException(), true);
}
final Intent intent = new Intent(BROADCAST_MULTI_BLOCKSTATE_CHANGED);
intent.putExtra(EXTRA_USER_ID, user_ids);
@ -1102,11 +1095,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.muted_user,
manager.getDisplayName(result.getData(), nameFirst, true));
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_muting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_muting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1139,9 +1133,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final SingleResponse<SavedSearch> result) {
if (result.hasData()) {
final String message = mContext.getString(R.string.search_name_saved, result.getData().getQuery());
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
} else {
showErrorMessage(mContext, R.string.action_saving_search, result.getException(), false);
Utils.showErrorMessage(mContext, R.string.action_saving_search, result.getException(), false);
}
super.onPostExecute(result);
}
@ -1178,12 +1172,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean succeed = result.hasData();
if (succeed) {
final String message = mContext.getString(R.string.subscribed_to_list, result.getData().name);
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_SUBSCRIBED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_subscribing_to_list, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_subscribing_to_list, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1226,12 +1220,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
if (result.hasData()) {
final UserList userList = result.getData();
final String message = mContext.getString(R.string.created_list, userList.getName());
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_CREATED);
intent.putExtra(EXTRA_USER_LIST, new ParcelableUserList(userList, account_id));
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_creating_list, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_creating_list, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1285,13 +1279,13 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
message = res.getQuantityString(R.plurals.deleted_N_users_from_list, users.length, users.length,
result.getData().name);
}
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_MEMBERS_DELETED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
intent.putExtra(EXTRA_USERS, users);
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1339,9 +1333,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.denied_users_follow_request,
manager.getDisplayName(user, nameFirst, true));
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
} else {
showErrorMessage(mContext, R.string.action_denying_follow_request, result.getException(), false);
Utils.showErrorMessage(mContext, R.string.action_denying_follow_request, result.getException(), false);
}
final Intent intent = new Intent(BROADCAST_FRIENDSHIP_DENIED);
intent.putExtra(EXTRA_USER_ID, mUserId);
@ -1384,11 +1378,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unblocked_user,
manager.getDisplayName(result.getData(), nameFirst, true));
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_unblocking, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_unblocking, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1442,9 +1437,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPostExecute(result);
if (result == null) return;
if (result.hasData() || isMessageNotFound(result.getException())) {
showInfoMessage(mContext, R.string.direct_message_deleted, false);
Utils.showInfoMessage(mContext, R.string.direct_message_deleted, false);
} else {
showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
}
@ -1500,9 +1495,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPostExecute(result);
if (result == null) return;
if (result.hasData() || isMessageNotFound(result.getException())) {
showInfoMessage(mContext, R.string.direct_message_deleted, false);
Utils.showInfoMessage(mContext, R.string.direct_message_deleted, false);
} else {
showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
}
@ -1554,6 +1549,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPreExecute();
mDestroyingFavoriteIds.put(account_id, status_id);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusListChangedEvent());
}
@ -1576,10 +1572,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
//end
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new FavoriteDestroyedEvent(status));
showInfoMessage(mContext, R.string.status_unfavorited, false);
Utils.showInfoMessage(mContext, R.string.status_unfavorited, false);
} else {
showErrorMessage(mContext, R.string.action_unfavoriting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_unfavoriting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1634,11 +1631,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unfollowed_user,
manager.getDisplayName(result.getData(), nameFirst, true));
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_unfollowing, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_unfollowing, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1678,11 +1676,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean nameFirst = mPreferences.getBoolean(KEY_NAME_FIRST);
final String message = mContext.getString(R.string.unmuted_user,
manager.getDisplayName(result.getData(), nameFirst, true));
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Bus bus = application.getMessageBus();
assert bus != null;
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_unmuting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_unmuting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1715,9 +1714,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final SingleResponse<SavedSearch> result) {
if (result.hasData()) {
final String message = mContext.getString(R.string.search_name_deleted, result.getData().getQuery());
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
} else {
showErrorMessage(mContext, R.string.action_deleting_search, result.getException(), false);
Utils.showErrorMessage(mContext, R.string.action_deleting_search, result.getException(), false);
}
super.onPostExecute(result);
}
@ -1763,6 +1762,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPreExecute();
mDestroyingStatusIds.put(account_id, status_id);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusListChangedEvent());
}
@ -1772,14 +1772,15 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
if (result.hasData()) {
final ParcelableStatus status = result.getData();
if (status.retweet_id > 0) {
showInfoMessage(mContext, R.string.retweet_cancelled, false);
Utils.showInfoMessage(mContext, R.string.retweet_cancelled, false);
} else {
showInfoMessage(mContext, R.string.status_deleted, false);
Utils.showInfoMessage(mContext, R.string.status_deleted, false);
}
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusDestroyedEvent(status));
} else {
showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1818,12 +1819,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean succeed = result.hasData();
if (succeed) {
final String message = mContext.getString(R.string.unsubscribed_from_list, result.getData().name);
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_UNSUBSCRIBED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_unsubscribing_from_list, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_unsubscribing_from_list, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1864,12 +1865,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final boolean succeed = result.hasData();
if (succeed) {
final String message = mContext.getString(R.string.deleted_list, result.getData().name);
showInfoMessage(mContext, message, false);
Utils.showInfoMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_DELETED);
intent.putExtra(EXTRA_USER_LIST, result.getData());
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_deleting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -1952,7 +1953,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
for (int i = 0, j = messages.size(); i < j; i++) {
final DirectMessage message = messages.get(i);
valuesArray[i] = createDirectMessage(message, accountId, isOutgoing);
valuesArray[i] = ContentValuesCreator.createDirectMessage(message, accountId, isOutgoing);
}
// Delete all rows conflicting before new data inserted.
@ -1964,7 +1965,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
// Insert previously fetched items.
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
bulkInsert(mResolver, insertUri, valuesArray);
ContentResolverUtils.bulkInsert(mResolver, insertUri, valuesArray);
return false;
}
@ -1973,6 +1974,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPreExecute() {
super.onPreExecute();
final Bus bus = TwidereApplication.getInstance(getContext()).getMessageBus();
assert bus != null;
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), true, null));
}
@ -1980,6 +1982,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final List<MessageListResponse> result) {
super.onPostExecute(result);
final Bus bus = TwidereApplication.getInstance(getContext()).getMessageBus();
assert bus != null;
bus.post(new GetMessagesTaskEvent(getDatabaseUri(), false, getException(result)));
}
@ -2178,14 +2181,14 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
return;
}
final Uri uri = getDatabaseUri();
final boolean noItemsBefore = getStatusCountInDatabase(mContext, uri, accountId) <= 0;
final boolean noItemsBefore = Utils.getStatusCountInDatabase(mContext, uri, accountId) <= 0;
final ContentValues[] values = new ContentValues[statuses.size()];
final long[] statusIds = new long[statuses.size()];
long minId = -1;
int minIdx = -1;
for (int i = 0, j = statuses.size(); i < j; i++) {
final org.mariotaku.twidere.api.twitter.model.Status status = statuses.get(i);
values[i] = createStatus(status, accountId);
values[i] = ContentValuesCreator.createStatus(status, accountId);
final long id = status.getId();
if (minId == -1 || id < minId) {
minId = id;
@ -2220,7 +2223,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
// Insert previously fetched items.
final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
bulkInsert(mResolver, insertUri, values);
ContentResolverUtils.bulkInsert(mResolver, insertUri, values);
}
@ -2288,6 +2291,151 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
abstract class GetActivitiesTask extends ManagedAsyncTask<Object, TwitterListResponse<Activity>, List<ActivityListResponse>> {
private final long[] mAccountIds, mMaxIds, mSinceIds;
public GetActivitiesTask(final long[] account_ids, final long[] max_ids, final long[] since_ids, final String tag) {
super(mContext, mAsyncTaskManager, tag);
mAccountIds = account_ids;
mMaxIds = max_ids;
mSinceIds = since_ids;
}
public abstract ResponseList<Activity> getActivities(Twitter twitter, Paging paging)
throws TwitterException;
@NonNull
protected abstract Uri getDatabaseUri();
final boolean isMaxIdsValid() {
return mMaxIds != null && mMaxIds.length == mAccountIds.length;
}
final boolean isSinceIdsValid() {
return mSinceIds != null && mSinceIds.length == mAccountIds.length;
}
private void storeStatus(long accountId, List<Activity> statuses, Pair<Long, Long> positions, boolean truncated, boolean notify) {
if (statuses == null || statuses.isEmpty() || accountId <= 0) {
return;
}
// final Uri uri = getDatabaseUri();
// final boolean noItemsBefore = Utils.getStatusCountInDatabase(mContext, uri, accountId) <= 0;
// final ContentValues[] values = new ContentValues[statuses.size()];
// final long[] statusIds = new long[statuses.size()];
// long minId = -1;
// int minIdx = -1;
// for (int i = 0, j = statuses.size(); i < j; i++) {
// final Activity status = statuses.get(i);
// values[i] = ContentValuesCreator.createActivity(status, accountId);
// final long id = status.getId();
// if (minId == -1 || id < minId) {
// minId = id;
// minIdx = i;
// }
// statusIds[i] = id;
// }
// // Delete all rows conflicting before new data inserted.
// final Expression accountWhere = Expression.equals(Activities.ACCOUNT_ID, accountId);
// final Expression statusWhere = Expression.in(new Column(Activities.STATUS_ID), new RawItemArray(statusIds));
// final String countWhere = Expression.and(accountWhere, statusWhere).getSQL();
// final String[] projection = {SQLFunctions.COUNT()};
// final int rowsDeleted;
// final Cursor countCur = mResolver.query(uri, projection, countWhere, null, null);
// if (countCur.moveToFirst()) {
// rowsDeleted = countCur.getInt(0);
// } else {
// rowsDeleted = 0;
// }
// countCur.close();
// //spice
// SpiceProfilingUtil.profile(mContext, accountId, accountId + ",Refresh," + TwidereArrayUtils.toString(statusIds, ',', true));
// //end
//
// // Insert a gap.
// final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, positions);
// final boolean noRowsDeleted = rowsDeleted == 0;
// final boolean insertGap = minId > 0 && (noRowsDeleted || deletedOldGap) && !truncated
// && !noItemsBefore && statuses.size() > 1;
// if (insertGap && minIdx != -1) {
// values[minIdx].put(Statuses.IS_GAP, true);
// }
// // Insert previously fetched items.
// final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
// ContentResolverUtils.bulkInsert(mResolver, insertUri, values);
}
@SafeVarargs
@Override
protected final void onProgressUpdate(TwitterListResponse<Activity>... values) {
// AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(mContext), values);
}
@Override
protected void onPostExecute(List<ActivityListResponse> result) {
super.onPostExecute(result);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new GetStatusesTaskEvent(getDatabaseUri(), false, getException(result)));
}
@Override
protected void onPreExecute() {
super.onPreExecute();
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new GetStatusesTaskEvent(getDatabaseUri(), true, null));
}
@Override
protected List<ActivityListResponse> doInBackground(final Object... params) {
final List<ActivityListResponse> result = new ArrayList<>();
if (mAccountIds == null) return result;
int idx = 0;
final int loadItemLimit = mPreferences.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
for (final long accountId : mAccountIds) {
final Twitter twitter = TwitterAPIFactory.getTwitterInstance(mContext, accountId, true);
if (twitter == null) continue;
try {
final Paging paging = new Paging();
paging.count(loadItemLimit);
final long maxId, sinceId;
if (isMaxIdsValid() && mMaxIds[idx] > 0) {
maxId = mMaxIds[idx];
paging.maxId(maxId);
} else {
maxId = -1;
}
if (isSinceIdsValid() && mSinceIds[idx] > 0) {
sinceId = mSinceIds[idx];
paging.sinceId(sinceId - 1);
} else {
sinceId = -1;
}
final List<Activity> activities = new ArrayList<>();
final boolean truncated = Utils.truncateActivities(getActivities(twitter, paging), activities, sinceId);
final Pair<Long, Long> positions;
if (activities.isEmpty()) {
positions = new Pair<>(-1L, -1L);
} else {
final Activity minActivity = Collections.min(activities);
positions = new Pair<>(minActivity.getMinPosition(), minActivity.getMaxPosition());
}
storeStatus(accountId, activities, positions, truncated, true);
publishProgress(new ActivityListResponse(accountId, activities));
} catch (final TwitterException e) {
Log.w(LOGTAG, e);
result.add(new ActivityListResponse(accountId, e));
}
idx++;
}
return result;
}
}
abstract class GetTrendsTask extends ManagedAsyncTask<Object, Object, ListResponse<Trends>> {
private final long account_id;
@ -2370,12 +2518,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final ListResponse<Long> result) {
if (result != null) {
final String user_id_where = ListUtils.toString(result.list, ',', false);
for (final Uri uri : STATUSES_URIS) {
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final Expression where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, account_id),
new Expression(String.format(Locale.ROOT, "%s IN (%s)", Statuses.USER_ID, user_id_where)));
mResolver.delete(uri, where.getSQL(), null);
}
showInfoMessage(mContext, R.string.reported_users_for_spam, false);
Utils.showInfoMessage(mContext, R.string.reported_users_for_spam, false);
final Intent intent = new Intent(BROADCAST_MULTI_BLOCKSTATE_CHANGED);
intent.putExtra(EXTRA_USER_IDS, user_ids);
intent.putExtra(EXTRA_ACCOUNT_ID, account_id);
@ -2414,16 +2562,16 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
@Override
protected void onPostExecute(final SingleResponse<ParcelableUser> result) {
if (result.hasData()) {
for (final Uri uri : STATUSES_URIS) {
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
final String where = Statuses.ACCOUNT_ID + " = " + mAccountId + " AND " + Statuses.USER_ID + " = "
+ user_id;
mResolver.delete(uri, where, null);
}
showInfoMessage(mContext, R.string.reported_user_for_spam, false);
Utils.showInfoMessage(mContext, R.string.reported_user_for_spam, false);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
bus.post(new FriendshipUserUpdatedEvent(result.getData()));
} else {
showErrorMessage(mContext, R.string.action_reporting_for_spam, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_reporting_for_spam, result.getException(), true);
}
super.onPostExecute(result);
}
@ -2463,6 +2611,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
super.onPreExecute();
mCreatingRetweetIds.put(account_id, status_id);
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusListChangedEvent());
}
@ -2477,7 +2626,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
Expression.equals(Statuses.STATUS_ID, status_id),
Expression.equals(Statuses.RETWEET_ID, status_id)
);
for (final Uri uri : STATUSES_URIS) {
for (final Uri uri : TwidereDataStore.STATUSES_URIS) {
mResolver.update(uri, values, where.getSQL(), null);
}
//spice
@ -2507,10 +2656,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
}
//end
final Bus bus = TwidereApplication.getInstance(mContext).getMessageBus();
assert bus != null;
bus.post(new StatusRetweetedEvent(status));
showOkMessage(mContext, R.string.status_retweeted, false);
Utils.showOkMessage(mContext, R.string.status_retweeted, false);
} else {
showErrorMessage(mContext, R.string.action_retweeting, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_retweeting, result.getException(), true);
}
super.onPostExecute(result);
}
@ -2544,7 +2694,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final ArrayList<String> hashtags = new ArrayList<>();
final ArrayList<ContentValues> hashtagValues = new ArrayList<>();
if (messages != null && messages.size() > 0) {
final ContentValues[] valuesArray = createTrends(messages);
final ContentValues[] valuesArray = ContentValuesCreator.createTrends(messages);
for (final ContentValues values : valuesArray) {
final String hashtag = values.getAsString(CachedTrends.NAME).replaceFirst("#", "");
if (hashtags.contains(hashtag)) {
@ -2556,9 +2706,9 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
hashtagValues.add(hashtagValue);
}
mResolver.delete(uri, null, null);
bulkInsert(mResolver, uri, valuesArray);
bulkDelete(mResolver, CachedHashtags.CONTENT_URI, CachedHashtags.NAME, hashtags, null, true);
bulkInsert(mResolver, CachedHashtags.CONTENT_URI,
ContentResolverUtils.bulkInsert(mResolver, uri, valuesArray);
ContentResolverUtils.bulkDelete(mResolver, CachedHashtags.CONTENT_URI, CachedHashtags.NAME, hashtags, null, true);
ContentResolverUtils.bulkInsert(mResolver, CachedHashtags.CONTENT_URI,
hashtagValues.toArray(new ContentValues[hashtagValues.size()]));
}
return SingleResponse.getInstance(true);
@ -2609,12 +2759,12 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
protected void onPostExecute(final SingleResponse<ParcelableUserList> result) {
if (result.hasData() && result.getData().id > 0) {
final String message = mContext.getString(R.string.updated_list_details, result.getData().name);
showOkMessage(mContext, message, false);
Utils.showOkMessage(mContext, message, false);
final Intent intent = new Intent(BROADCAST_USER_LIST_DETAILS_UPDATED);
intent.putExtra(EXTRA_LIST_ID, listId);
mContext.sendBroadcast(intent);
} else {
showErrorMessage(mContext, R.string.action_updating_details, result.getException(), true);
Utils.showErrorMessage(mContext, R.string.action_updating_details, result.getException(), true);
}
super.onPostExecute(result);
}

View File

@ -19,17 +19,17 @@
package org.mariotaku.twidere.util;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.Join;
import org.mariotaku.querybuilder.Join.Operation;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.Selectable;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.Tables;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.Join;
import org.mariotaku.sqliteqb.library.Join.Operation;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
import org.mariotaku.sqliteqb.library.Selectable;
import org.mariotaku.sqliteqb.library.Table;
import org.mariotaku.sqliteqb.library.Tables;
import org.mariotaku.sqliteqb.library.query.SQLSelectQuery;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages;

View File

@ -29,6 +29,7 @@ import org.mariotaku.restfu.http.mime.FileTypedData;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.api.twitter.Twitter;
import org.mariotaku.twidere.api.twitter.TwitterException;
import org.mariotaku.twidere.api.twitter.model.Activity;
import org.mariotaku.twidere.api.twitter.model.DirectMessage;
import org.mariotaku.twidere.api.twitter.model.Paging;
import org.mariotaku.twidere.api.twitter.model.ResponseList;
@ -260,6 +261,31 @@ public class TwitterWrapper implements Constants {
}
public static final class ActivityListResponse extends TwitterListResponse<Activity> {
public final boolean truncated;
public ActivityListResponse(final long accountId, final Exception exception) {
this(accountId, -1, -1, null, false, exception);
}
public ActivityListResponse(final long accountId, final List<Activity> list) {
this(accountId, -1, -1, list, false, null);
}
public ActivityListResponse(final long accountId, final long maxId, final long sinceId,
final List<Activity> list, final boolean truncated) {
this(accountId, maxId, sinceId, list, truncated, null);
}
ActivityListResponse(final long accountId, final long maxId, final long sinceId, final List<Activity> list,
final boolean truncated, final Exception exception) {
super(accountId, maxId, sinceId, list, exception);
this.truncated = truncated;
}
}
public static class TwitterListResponse<Data> extends ListResponse<Data> {
public final long accountId, maxId, sinceId;

View File

@ -120,18 +120,18 @@ import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.querybuilder.AllColumns;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.OrderBy;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.querybuilder.SQLFunctions;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.Selectable;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.Tables;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.sqliteqb.library.AllColumns;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.OrderBy;
import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.sqliteqb.library.SQLFunctions;
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
import org.mariotaku.sqliteqb.library.Selectable;
import org.mariotaku.sqliteqb.library.Table;
import org.mariotaku.sqliteqb.library.Tables;
import org.mariotaku.sqliteqb.library.query.SQLSelectQuery;
import org.mariotaku.restfu.RestAPIFactory;
import org.mariotaku.restfu.RestClient;
import org.mariotaku.restfu.http.Authorization;
@ -200,6 +200,7 @@ import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.provider.TwidereDataStore;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.Activities;
import org.mariotaku.twidere.provider.TwidereDataStore.CacheFiles;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedImages;
@ -589,6 +590,58 @@ public final class Utils implements Constants {
return filterExpression;
}
@NonNull
public static Expression buildActivityFilterWhereClause(@NonNull final String table, final Expression extraSelection) {
final SQLSelectQuery filteredUsersQuery = SQLQueryBuilder
.select(new Column(new Table(Filters.Users.TABLE_NAME), Filters.Users.USER_ID))
.from(new Tables(Filters.Users.TABLE_NAME))
.build();
final Expression filteredUsersWhere = Expression.or(
Expression.in(new Column(new Table(table), Activities.STATUS_USER_ID), filteredUsersQuery),
Expression.in(new Column(new Table(table), Activities.STATUS_RETWEETED_BY_USER_ID), filteredUsersQuery),
Expression.in(new Column(new Table(table), Activities.STATUS_QUOTED_BY_USER_ID), filteredUsersQuery)
);
final SQLSelectQuery.Builder filteredIdsQueryBuilder = SQLQueryBuilder
.select(true, new Column(new Table(table), Activities._ID))
.from(new Tables(table))
.where(filteredUsersWhere)
.union()
.select(true, new Columns(new Column(new Table(table), Activities._ID)))
.from(new Tables(table, Filters.Sources.TABLE_NAME))
.where(Expression.or(
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_SOURCE),
"'%>'||" + Filters.Sources.TABLE_NAME + "." + Filters.Sources.VALUE + "||'</a>%'"),
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_QUOTE_SOURCE),
"'%>'||" + Filters.Sources.TABLE_NAME + "." + Filters.Sources.VALUE + "||'</a>%'")
))
.union()
.select(true, new Columns(new Column(new Table(table), Activities._ID)))
.from(new Tables(table, Filters.Keywords.TABLE_NAME))
.where(Expression.or(
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_TEXT_PLAIN),
"'%'||" + Filters.Keywords.TABLE_NAME + "." + Filters.Keywords.VALUE + "||'%'"),
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_QUOTE_TEXT_PLAIN),
"'%'||" + Filters.Keywords.TABLE_NAME + "." + Filters.Keywords.VALUE + "||'%'")
))
.union()
.select(true, new Columns(new Column(new Table(table), Activities._ID)))
.from(new Tables(table, Filters.Links.TABLE_NAME))
.where(Expression.or(
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_TEXT_HTML),
"'%>%'||" + Filters.Links.TABLE_NAME + "." + Filters.Links.VALUE + "||'%</a>%'"),
Expression.likeRaw(new Column(new Table(table), Activities.STATUS_QUOTE_TEXT_HTML),
"'%>%'||" + Filters.Links.TABLE_NAME + "." + Filters.Links.VALUE + "||'%</a>%'")
));
final Expression filterExpression = Expression.or(
Expression.notIn(new Column(new Table(table), Activities._ID), filteredIdsQueryBuilder.build()),
Expression.equals(new Column(new Table(table), Activities.STATUS_IS_GAP), 1)
);
if (extraSelection != null) {
return Expression.and(filterExpression, extraSelection);
}
return filterExpression;
}
public static int calculateInSampleSize(final int width, final int height, final int preferredWidth,
final int preferredHeight) {
if (preferredHeight > height && preferredWidth > width) return 1;

View File

@ -24,15 +24,15 @@ import android.database.sqlite.SQLiteDatabase;
import android.text.TextUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Constraint;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.Tables;
import org.mariotaku.querybuilder.query.SQLInsertQuery;
import org.mariotaku.querybuilder.query.SQLSelectQuery;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Constraint;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.NewColumn;
import org.mariotaku.sqliteqb.library.OnConflict;
import org.mariotaku.sqliteqb.library.Tables;
import org.mariotaku.sqliteqb.library.query.SQLInsertQuery;
import org.mariotaku.sqliteqb.library.query.SQLSelectQuery;
import org.mariotaku.twidere.util.TwidereArrayUtils;
import java.util.ArrayList;
@ -42,11 +42,11 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import static org.mariotaku.querybuilder.SQLQueryBuilder.alterTable;
import static org.mariotaku.querybuilder.SQLQueryBuilder.createTable;
import static org.mariotaku.querybuilder.SQLQueryBuilder.dropTable;
import static org.mariotaku.querybuilder.SQLQueryBuilder.insertInto;
import static org.mariotaku.querybuilder.SQLQueryBuilder.select;
import static org.mariotaku.sqliteqb.library.SQLQueryBuilder.alterTable;
import static org.mariotaku.sqliteqb.library.SQLQueryBuilder.createTable;
import static org.mariotaku.sqliteqb.library.SQLQueryBuilder.dropTable;
import static org.mariotaku.sqliteqb.library.SQLQueryBuilder.insertInto;
import static org.mariotaku.sqliteqb.library.SQLQueryBuilder.select;
public final class DatabaseUpgradeHelper {

View File

@ -26,21 +26,21 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import org.mariotaku.querybuilder.Columns;
import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Constraint;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.NewColumn;
import org.mariotaku.querybuilder.OnConflict;
import org.mariotaku.querybuilder.SQLQuery;
import org.mariotaku.querybuilder.SQLQueryBuilder;
import org.mariotaku.querybuilder.SetValue;
import org.mariotaku.querybuilder.Table;
import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery.Event;
import org.mariotaku.querybuilder.query.SQLCreateTriggerQuery.Type;
import org.mariotaku.querybuilder.query.SQLDeleteQuery;
import org.mariotaku.sqliteqb.library.Columns;
import org.mariotaku.sqliteqb.library.Columns.Column;
import org.mariotaku.sqliteqb.library.Constraint;
import org.mariotaku.sqliteqb.library.Expression;
import org.mariotaku.sqliteqb.library.NewColumn;
import org.mariotaku.sqliteqb.library.OnConflict;
import org.mariotaku.sqliteqb.library.SQLQuery;
import org.mariotaku.sqliteqb.library.SQLQueryBuilder;
import org.mariotaku.sqliteqb.library.SetValue;
import org.mariotaku.sqliteqb.library.Table;
import org.mariotaku.sqliteqb.library.query.SQLCreateIndexQuery;
import org.mariotaku.sqliteqb.library.query.SQLCreateTableQuery;
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Event;
import org.mariotaku.sqliteqb.library.query.SQLCreateTriggerQuery.Type;
import org.mariotaku.sqliteqb.library.query.SQLDeleteQuery;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
import org.mariotaku.twidere.provider.TwidereDataStore.CachedHashtags;

View File

@ -1,7 +1,6 @@
package org.mariotaku.twidere.view.holder;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.CardView;
@ -24,7 +23,6 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableLocation;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatus.CursorIndices;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
@ -330,217 +328,6 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
quotedNameView.updateText();
}
public void displayStatus(@NonNull Cursor cursor, @NonNull CursorIndices indices,
final boolean displayInReplyTo) {
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final AsyncTwitterWrapper twitter = adapter.getTwitterWrapper();
final TwidereLinkify linkify = adapter.getTwidereLinkify();
final UserColorNameManager manager = adapter.getUserColorNameManager();
final Context context = adapter.getContext();
final boolean nameFirst = adapter.isNameFirst();
final boolean is_quote = cursor.getShort(indices.is_quote) == 1;
final long reply_count = cursor.getLong(is_quote ? indices.quote_reply_count : indices.reply_count);
final long retweet_count;
final long favorite_count;
final long account_id = cursor.getLong(indices.account_id);
final long user_id = cursor.getLong(indices.user_id);
final long status_id = cursor.getLong(indices.status_id);
final long retweet_id = cursor.getLong(indices.retweet_id);
final long my_retweet_id = cursor.getLong(indices.my_retweet_id);
final long in_reply_to_status_id = cursor.getLong(indices.in_reply_to_status_id);
final long in_reply_to_user_id = cursor.getLong(indices.in_reply_to_user_id);
final long retweeted_by_id = cursor.getLong(indices.retweeted_by_user_id);
final String user_name = cursor.getString(indices.user_name);
final String user_screen_name = cursor.getString(indices.user_screen_name);
final String card_name = cursor.getString(indices.card_name);
final String place_full_name = cursor.getString(indices.place_full_name);
final boolean sensitive = cursor.getShort(indices.is_possibly_sensitive) == 1;
final ParcelableMedia[] media = ParcelableMedia.fromSerializedJson(cursor.getString(indices.media));
final ParcelableLocation location = ParcelableLocation.fromString(cursor.getString(indices.location));
if (retweet_id > 0) {
final String retweeted_by_name = cursor.getString(indices.retweeted_by_user_name);
final String retweeted_by_screen_name = cursor.getString(indices.retweeted_by_user_screen_name);
final String retweetedBy = manager.getDisplayName(retweeted_by_id, retweeted_by_name,
retweeted_by_screen_name, nameFirst, false);
replyRetweetView.setText(context.getString(R.string.name_retweeted, retweetedBy));
replyRetweetIcon.setImageResource(R.drawable.ic_activity_action_retweet);
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
} else if (in_reply_to_status_id > 0 && in_reply_to_user_id > 0 && displayInReplyTo) {
final String in_reply_to_name = cursor.getString(indices.in_reply_to_user_name);
final String in_reply_to_screen_name = cursor.getString(indices.in_reply_to_user_screen_name);
final String inReplyTo = manager.getDisplayName(in_reply_to_user_id, in_reply_to_name,
in_reply_to_screen_name, nameFirst, false);
replyRetweetView.setText(context.getString(R.string.in_reply_to_name, inReplyTo));
replyRetweetIcon.setImageResource(R.drawable.ic_activity_action_reply);
replyRetweetView.setVisibility(View.VISIBLE);
replyRetweetIcon.setVisibility(View.VISIBLE);
} else {
replyRetweetView.setVisibility(View.GONE);
replyRetweetIcon.setVisibility(View.GONE);
}
final int typeIconRes;
if (is_quote) {
quotedNameView.setName(manager.getUserNickname(user_id, user_name, false));
quotedNameView.setScreenName("@" + user_screen_name);
timeView.setTime(cursor.getLong(indices.quote_timestamp));
nameView.setName(manager.getUserNickname(cursor.getLong(indices.quoted_by_user_id),
cursor.getString(indices.quoted_by_user_name), false));
nameView.setScreenName("@" + cursor.getString(indices.quoted_by_user_screen_name));
final String quote_text_unescaped = cursor.getString(indices.quote_text_unescaped);
final int idx = quote_text_unescaped.lastIndexOf(" twitter.com");
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
quoteTextView.setText(idx > 0 ? quote_text_unescaped.substring(0, idx) : quote_text_unescaped);
} else {
final Spanned text = Html.fromHtml(cursor.getString(indices.quote_text_html));
quoteTextView.setText(idx > 0 ? text.subSequence(0, idx) : text);
linkify.applyAllLinks(quoteTextView, account_id, getLayoutPosition(),
cursor.getShort(indices.is_possibly_sensitive) == 1,
adapter.getLinkHighlightingStyle());
quoteTextView.setMovementMethod(null);
}
quotedNameView.setVisibility(View.VISIBLE);
quoteTextView.setVisibility(View.VISIBLE);
quoteIndicator.setVisibility(View.VISIBLE);
quoteIndicator.setColor(manager.getUserColor(user_id, false));
if (adapter.isProfileImageEnabled()) {
profileImageView.setVisibility(View.VISIBLE);
loader.displayProfileImage(profileImageView, cursor.getString(indices.quoted_by_user_profile_image));
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.quoted_by_user_is_verified) == 1,
cursor.getShort(indices.quoted_by_user_is_protected) == 1);
} else {
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
itemContent.drawStart(manager.getUserColor(cursor.getLong(indices.quoted_by_user_id), false),
manager.getUserColor(cursor.getLong(indices.user_id), false));
} else {
nameView.setName(manager.getUserNickname(user_id, user_name, false));
nameView.setScreenName("@" + user_screen_name);
if (retweet_id > 0) {
timeView.setTime(cursor.getLong(indices.retweet_timestamp));
} else {
timeView.setTime(cursor.getLong(indices.status_timestamp));
}
quotedNameView.setVisibility(View.GONE);
quoteTextView.setVisibility(View.GONE);
quoteIndicator.setVisibility(View.GONE);
if (adapter.isProfileImageEnabled()) {
profileImageView.setVisibility(View.VISIBLE);
final String user_profile_image_url = cursor.getString(indices.user_profile_image_url);
loader.displayProfileImage(profileImageView, user_profile_image_url);
typeIconRes = getUserTypeIconRes(cursor.getShort(indices.is_verified) == 1,
cursor.getShort(indices.is_protected) == 1);
} else {
profileImageView.setVisibility(View.GONE);
loader.cancelDisplayTask(profileImageView);
typeIconRes = 0;
}
if (retweet_id > 0) {
itemContent.drawStart(manager.getUserColor(retweeted_by_id, false), manager.getUserColor(user_id, false));
} else {
itemContent.drawStart(manager.getUserColor(user_id, false));
}
}
if (typeIconRes != 0) {
profileTypeView.setImageResource(typeIconRes);
profileTypeView.setVisibility(View.VISIBLE);
} else {
profileTypeView.setImageDrawable(null);
profileTypeView.setVisibility(View.GONE);
}
if (adapter.shouldShowAccountsColor()) {
itemContent.drawEnd(Utils.getAccountColor(context, account_id));
} else {
itemContent.drawEnd();
}
if (adapter.isMediaPreviewEnabled()) {
final boolean hasMedia = media != null && media.length > 0;
if (hasMedia && (adapter.isSensitiveContentEnabled() || !sensitive)) {
mediaPreview.setVisibility(View.VISIBLE);
mediaPreview.displayMedia(media, loader, account_id, this, adapter.getMediaLoadingHandler());
} else {
mediaPreview.setVisibility(View.GONE);
}
} else {
mediaPreview.setVisibility(View.GONE);
}
if (adapter.getLinkHighlightingStyle() == VALUE_LINK_HIGHLIGHT_OPTION_CODE_NONE) {
textView.setText(cursor.getString(indices.text_unescaped));
} else {
textView.setText(Html.fromHtml(cursor.getString(indices.text_html)));
linkify.applyAllLinks(textView, account_id, getLayoutPosition(),
cursor.getShort(indices.is_possibly_sensitive) == 1,
adapter.getLinkHighlightingStyle());
textView.setMovementMethod(null);
}
if (reply_count > 0) {
replyCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), reply_count));
} else {
replyCountView.setText(null);
}
if (twitter.isDestroyingStatus(account_id, my_retweet_id)) {
retweetCountView.setActivated(false);
retweet_count = Math.max(0, cursor.getLong(is_quote ? indices.quote_retweet_count : indices.retweet_count) - 1);
} else {
final boolean creatingRetweet = twitter.isCreatingRetweet(account_id, status_id);
retweetCountView.setActivated(creatingRetweet || Utils.isMyRetweet(account_id,
retweeted_by_id, my_retweet_id));
retweet_count = cursor.getLong(is_quote ? indices.quote_retweet_count : indices.retweet_count) + (creatingRetweet ? 1 : 0);
}
if (retweet_count > 0) {
retweetCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), retweet_count));
} else {
retweetCountView.setText(null);
}
if (twitter.isDestroyingFavorite(account_id, status_id)) {
favoriteCountView.setActivated(false);
favorite_count = Math.max(0, cursor.getLong(is_quote ? indices.quote_favorite_count : indices.favorite_count) - 1);
} else {
final boolean creatingFavorite = twitter.isCreatingFavorite(account_id, status_id);
favoriteCountView.setActivated(creatingFavorite || cursor.getShort(indices.is_favorite) == 1);
favorite_count = cursor.getLong(is_quote ? indices.quote_favorite_count : indices.favorite_count) + (creatingFavorite ? 1 : 0);
}
if (favorite_count > 0) {
favoriteCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), favorite_count));
} else {
favoriteCountView.setText(null);
}
displayExtraTypeIcon(card_name, media, location, place_full_name, sensitive);
nameView.updateText();
quotedNameView.updateText();
}
public CardView getCardView() {
return (CardView) itemView.findViewById(R.id.card);
}