added nfc share (user/tweet), and twidere is not required, if you don't have twidere installed, a browser(or other client can handle twitter link) will be opened
This commit is contained in:
parent
b88ffa055a
commit
6ccb61e183
|
@ -47,19 +47,27 @@ public class Expression implements SQLLang {
|
|||
}
|
||||
|
||||
public static Expression equals(final Column l, final Column r) {
|
||||
return new Expression(String.format(Locale.US, "%s = %s", l.getSQL(), r.getSQL()));
|
||||
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.US, "%s = %d", l.getSQL(), 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.US, "%s = '%s'", l.getSQL(), 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.US, "%s = %d", l, r));
|
||||
return new Expression(String.format(Locale.ROOT, "%s = %d", l, r));
|
||||
}
|
||||
|
||||
public static Expression in(final Column column, final Selectable in) {
|
||||
|
@ -67,7 +75,7 @@ public class Expression implements SQLLang {
|
|||
}
|
||||
|
||||
public static Expression notEquals(final String l, final long r) {
|
||||
return new Expression(String.format(Locale.US, "%s != %d", l, r));
|
||||
return new Expression(String.format(Locale.ROOT, "%s != %d", l, r));
|
||||
}
|
||||
|
||||
public static Expression notEquals(final String l, final String r) {
|
||||
|
@ -101,7 +109,7 @@ public class Expression implements SQLLang {
|
|||
}
|
||||
|
||||
public static Expression equalsArgs(String l) {
|
||||
return new Expression(String.format(Locale.US, "%s = ?", l));
|
||||
return new Expression(String.format(Locale.ROOT, "%s = ?", l));
|
||||
}
|
||||
|
||||
public static Expression isNull(Column column) {
|
||||
|
@ -113,12 +121,12 @@ public class Expression implements SQLLang {
|
|||
}
|
||||
|
||||
public static Expression likeRaw(final Column column, final String pattern, final String escape) {
|
||||
return new Expression(String.format(Locale.US, "%s LIKE %s ESCAPE '%s'", column.getSQL(), pattern, escape));
|
||||
return new Expression(String.format(Locale.ROOT, "%s LIKE %s ESCAPE '%s'", column.getSQL(), pattern, escape));
|
||||
}
|
||||
|
||||
|
||||
public static Expression likeRaw(final Column column, final String pattern) {
|
||||
return new Expression(String.format(Locale.US, "%s LIKE %s", column.getSQL(), pattern));
|
||||
return new Expression(String.format(Locale.ROOT, "%s LIKE %s", column.getSQL(), pattern));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,14 +31,35 @@ 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 = 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() {
|
||||
return Utils.toString(orderBy, ',', false);
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
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;
|
||||
|
@ -65,6 +66,10 @@ public class SQLQueryBuilder {
|
|||
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) {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -178,6 +178,7 @@ public class SQLCreateTriggerQuery implements SQLQuery {
|
|||
|
||||
@Override
|
||||
public SQLCreateTriggerQuery build() {
|
||||
buildCalled = true;
|
||||
return query;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ public class SQLCreateViewQuery implements SQLQuery {
|
|||
|
||||
@Override
|
||||
public SQLCreateViewQuery build() {
|
||||
buildCalled = true;
|
||||
return query;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package twitter4j.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public interface HostAddressResolver {
|
||||
|
||||
public String resolve(String host) throws IOException;
|
||||
public InetAddress[] resolve(String host) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.io.IOException;
|
|||
import java.io.OutputStream;
|
||||
import java.net.Authenticator;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.Proxy;
|
||||
|
@ -261,12 +262,12 @@ public class HttpClientImpl extends HttpClientBase implements HttpClient, HttpRe
|
|||
throw new IOException("Invalid URI " + url_string);
|
||||
}
|
||||
final String host = url_orig.getHost(), authority = url_orig.getAuthority();
|
||||
final String resolved_host = resolver != null ? resolver.resolve(host) : null;
|
||||
con = (HttpURLConnection) new URL(resolved_host != null ? url_string.replace("://" + host, "://"
|
||||
+ resolved_host) : url_string).openConnection(proxy);
|
||||
if (resolved_host != null && !host.equals(resolved_host)) {
|
||||
con.setRequestProperty("Host", authority);
|
||||
}
|
||||
final InetAddress[] resolved_host = resolver != null ? resolver.resolve(host) : InetAddress.getAllByName(host);
|
||||
con = (HttpURLConnection) new URL(resolved_host.length > 0 ? url_string.replace("://" + host, "://"
|
||||
+ resolved_host[0].getHostAddress()) : url_string).openConnection(proxy);
|
||||
// if (resolved_host != null && !host.equals(resolved_host)) {
|
||||
// con.setRequestProperty("Host", authority);
|
||||
// }
|
||||
if (CONF.getHttpConnectionTimeout() > 0) {
|
||||
con.setConnectTimeout(CONF.getHttpConnectionTimeout());
|
||||
}
|
||||
|
|
|
@ -19,67 +19,58 @@
|
|||
|
||||
package org.mariotaku.twidere.extension.streaming.util;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mariotaku.twidere.Twidere;
|
||||
import org.mariotaku.twidere.extension.streaming.BuildConfig;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import twitter4j.http.HostAddressResolver;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public class TwidereHostAddressResolver implements HostAddressResolver {
|
||||
|
||||
private static final String RESOLVER_LOGTAG = "Twidere.Streaming.HostAddressResolver";
|
||||
private static final String RESOLVER_LOGTAG = "Twidere.Streaming.Host";
|
||||
|
||||
private final HostCache mHostCache = new HostCache(512);
|
||||
private final Context mContext;
|
||||
private final HostCache mHostCache = new HostCache(512);
|
||||
private final Context mContext;
|
||||
|
||||
public TwidereHostAddressResolver(final Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
public TwidereHostAddressResolver(final Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String resolve(final String host) {
|
||||
if (host == null) return null;
|
||||
// First, I'll try to load address cached.
|
||||
if (mHostCache.containsKey(host)) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got cached address " + mHostCache.get(host) + " for host " + host);
|
||||
}
|
||||
return mHostCache.get(host);
|
||||
}
|
||||
final String address = Twidere.resolveHost(mContext, host);
|
||||
if (isValidIpAddress(address)) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(RESOLVER_LOGTAG, "Resolved address " + address + " for host " + host);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.w(RESOLVER_LOGTAG, "Resolve address " + host + " failed, using original host");
|
||||
}
|
||||
return host;
|
||||
}
|
||||
@Override
|
||||
public InetAddress[] resolve(final String host) throws UnknownHostException {
|
||||
if (host == null) return null;
|
||||
// First, I'll try to load address cached.
|
||||
final InetAddress[] cached = mHostCache.get(host);
|
||||
if (cached != null) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got cached " + Arrays.toString(cached));
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
final InetAddress[] resolved = Twidere.resolveHost(mContext, host);
|
||||
mHostCache.put(host, resolved);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
static boolean isValidIpAddress(final String address) {
|
||||
return !isEmpty(address);
|
||||
}
|
||||
private static class HostCache extends LinkedHashMap<String, InetAddress[]> {
|
||||
|
||||
private static class HostCache extends LinkedHashMap<String, String> {
|
||||
private static final long serialVersionUID = -9216545511009449147L;
|
||||
|
||||
private static final long serialVersionUID = -9216545511009449147L;
|
||||
HostCache(final int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
HostCache(final int initialCapacity) {
|
||||
super(initialCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String put(final String key, final String value) {
|
||||
if (value == null) return value;
|
||||
return super.put(key, value);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public InetAddress[] put(final String key, final InetAddress[] value) {
|
||||
if (value == null) return null;
|
||||
return super.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,16 +29,25 @@ import android.database.Cursor;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.mariotaku.twidere.model.ComposingStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableStatus;
|
||||
import org.mariotaku.twidere.model.ParcelableUser;
|
||||
import org.mariotaku.twidere.model.ParcelableUserList;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.DNS;
|
||||
import org.mariotaku.twidere.util.TwidereArrayUtils;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static android.text.TextUtils.isEmpty;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class Twidere implements TwidereConstants {
|
||||
|
||||
public static void appendComposeActivityText(final Activity activity, final String text) {
|
||||
|
@ -142,7 +151,8 @@ public final class Twidere implements TwidereConstants {
|
|||
}
|
||||
c.moveToNext();
|
||||
}
|
||||
} catch (final SecurityException e) {
|
||||
} catch (final SecurityException ignore) {
|
||||
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
@ -162,17 +172,35 @@ public final class Twidere implements TwidereConstants {
|
|||
activity.finish();
|
||||
}
|
||||
|
||||
public static String resolveHost(final Context context, final String host) {
|
||||
if (context == null || host == null) return null;
|
||||
private static InetAddress fromAddressString(String host, String address) throws UnknownHostException {
|
||||
InetAddress inetAddress = InetAddress.getByName(address);
|
||||
if (inetAddress instanceof Inet4Address) {
|
||||
return Inet4Address.getByAddress(host, inetAddress.getAddress());
|
||||
} else if (inetAddress instanceof Inet6Address) {
|
||||
return Inet6Address.getByAddress(host, inetAddress.getAddress());
|
||||
}
|
||||
throw new UnknownHostException("Bad address " + host + " = " + address);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static InetAddress[] resolveHost(final Context context, final String host) throws UnknownHostException {
|
||||
if (context == null || host == null) return InetAddress.getAllByName(host);
|
||||
final ContentResolver resolver = context.getContentResolver();
|
||||
final Uri uri = Uri.withAppendedPath(TwidereDataStore.DNS.CONTENT_URI, host);
|
||||
final Cursor cur = resolver.query(uri, TwidereDataStore.DNS.MATRIX_COLUMNS, null, null, null);
|
||||
if (cur == null) return null;
|
||||
final Uri uri = Uri.withAppendedPath(DNS.CONTENT_URI, host);
|
||||
final Cursor cur = resolver.query(uri, DNS.MATRIX_COLUMNS, null, null, null);
|
||||
if (cur == null) return InetAddress.getAllByName(host);
|
||||
try {
|
||||
if (cur.getCount() == 0) return null;
|
||||
final int addr_idx = cur.getColumnIndex(TwidereDataStore.DNS.ADDRESS);
|
||||
cur.moveToFirst();
|
||||
return cur.getString(addr_idx);
|
||||
final ArrayList<InetAddress> addresses = new ArrayList<>();
|
||||
final int idxHost = cur.getColumnIndex(DNS.HOST), idxAddr = cur.getColumnIndex(DNS.ADDRESS);
|
||||
while (!cur.isAfterLast()) {
|
||||
addresses.add(fromAddressString(cur.getString(idxHost), cur.getString(idxAddr)));
|
||||
cur.moveToNext();
|
||||
}
|
||||
if (addresses.isEmpty()) {
|
||||
throw new UnknownHostException("Unknown host " + host);
|
||||
}
|
||||
return addresses.toArray(new InetAddress[addresses.size()]);
|
||||
} finally {
|
||||
cur.close();
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.nfc"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true"/>
|
||||
|
@ -32,6 +35,7 @@
|
|||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.NFC"/>
|
||||
<uses-permission android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS"/>
|
||||
<uses-permission android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA"/>
|
||||
<uses-permission android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE"/>
|
||||
|
@ -548,6 +552,7 @@
|
|||
android:scheme="https"/>
|
||||
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* 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 com.squareup.okhttp.internal;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.okhttp.Protocol;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/3/13.
|
||||
*/
|
||||
public class TwidereOkHttpPlatform extends Platform implements Constants {
|
||||
|
||||
// setUseSessionTickets(boolean)
|
||||
private static final OptionalMethod<Socket> SET_USE_SESSION_TICKETS =
|
||||
new OptionalMethod<>(null, "setUseSessionTickets", Boolean.TYPE);
|
||||
// setHostname(String)
|
||||
private static final OptionalMethod<Socket> SET_HOSTNAME =
|
||||
new OptionalMethod<>(null, "setHostname", String.class);
|
||||
// byte[] getAlpnSelectedProtocol()
|
||||
private static final OptionalMethod<Socket> GET_ALPN_SELECTED_PROTOCOL =
|
||||
new OptionalMethod<>(byte[].class, "getAlpnSelectedProtocol");
|
||||
// setAlpnSelectedProtocol(byte[])
|
||||
private static final OptionalMethod<Socket> SET_ALPN_PROTOCOLS =
|
||||
new OptionalMethod<>(null, "setAlpnProtocols", byte[].class);
|
||||
|
||||
private final TwidereApplication application;
|
||||
|
||||
// Non-null on Android 4.0+.
|
||||
private final Method trafficStatsTagSocket;
|
||||
private final Method trafficStatsUntagSocket;
|
||||
|
||||
private TwidereOkHttpPlatform(TwidereApplication application, Method trafficStatsTagSocket, Method trafficStatsUntagSocket) {
|
||||
this.application = application;
|
||||
this.trafficStatsTagSocket = trafficStatsTagSocket;
|
||||
this.trafficStatsUntagSocket = trafficStatsUntagSocket;
|
||||
}
|
||||
|
||||
public static void applyHack(TwidereApplication application) {
|
||||
final TwidereOkHttpPlatform platform = get(application);
|
||||
try {
|
||||
final Field field = Platform.class.getDeclaredField("PLATFORM");
|
||||
field.setAccessible(true);
|
||||
field.set(null, platform);
|
||||
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||
//Unable to change default platform
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static TwidereOkHttpPlatform get(TwidereApplication application) {
|
||||
// Attempt to find Android 4.0+ APIs.
|
||||
Method trafficStatsTagSocket = null;
|
||||
Method trafficStatsUntagSocket = null;
|
||||
try {
|
||||
Class<?> trafficStats = Class.forName("android.net.TrafficStats");
|
||||
trafficStatsTagSocket = trafficStats.getMethod("tagSocket", Socket.class);
|
||||
trafficStatsUntagSocket = trafficStats.getMethod("untagSocket", Socket.class);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException ignored) {
|
||||
}
|
||||
return new TwidereOkHttpPlatform(application, trafficStatsTagSocket, trafficStatsUntagSocket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectSocket(Socket socket, InetSocketAddress address,
|
||||
int connectTimeout) throws IOException {
|
||||
try {
|
||||
// final HostAddressResolver resolver = application.getHostAddressResolver();
|
||||
socket.connect(address, connectTimeout);
|
||||
} catch (SecurityException se) {
|
||||
// Before android 4.3, socket.connect could throw a SecurityException
|
||||
// if opening a socket resulted in an EACCES error.
|
||||
IOException ioException = new IOException("Exception in connect");
|
||||
ioException.initCause(se);
|
||||
throw ioException;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureTlsExtensions(
|
||||
SSLSocket sslSocket, String hostname, List<Protocol> protocols) {
|
||||
// Enable SNI and session tickets.
|
||||
if (hostname != null) {
|
||||
SET_USE_SESSION_TICKETS.invokeOptionalWithoutCheckedException(sslSocket, true);
|
||||
SET_HOSTNAME.invokeOptionalWithoutCheckedException(sslSocket, hostname);
|
||||
}
|
||||
|
||||
// Enable ALPN.
|
||||
boolean alpnSupported = SET_ALPN_PROTOCOLS.isSupported(sslSocket);
|
||||
if (!alpnSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object[] parameters = {concatLengthPrefixed(protocols)};
|
||||
SET_ALPN_PROTOCOLS.invokeWithoutCheckedException(sslSocket, parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectedProtocol(SSLSocket socket) {
|
||||
boolean alpnSupported = GET_ALPN_SELECTED_PROTOCOL.isSupported(socket);
|
||||
if (!alpnSupported) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] alpnResult =
|
||||
(byte[]) GET_ALPN_SELECTED_PROTOCOL.invokeWithoutCheckedException(socket);
|
||||
if (alpnResult != null) {
|
||||
return new String(alpnResult, Util.UTF_8);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tagSocket(Socket socket) throws SocketException {
|
||||
if (trafficStatsTagSocket == null) return;
|
||||
|
||||
try {
|
||||
trafficStatsTagSocket.invoke(null, socket);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void untagSocket(Socket socket) throws SocketException {
|
||||
if (trafficStatsUntagSocket == null) return;
|
||||
|
||||
try {
|
||||
trafficStatsUntagSocket.invoke(null, socket);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ package org.mariotaku.twidere;
|
|||
public interface Constants extends TwidereConstants {
|
||||
|
||||
public static final String DATABASES_NAME = "twidere.sqlite";
|
||||
public static final int DATABASES_VERSION = 85;
|
||||
public static final int DATABASES_VERSION = 86;
|
||||
|
||||
public static final int MENU_GROUP_STATUS_EXTENSION = 10;
|
||||
public static final int MENU_GROUP_COMPOSE_EXTENSION = 11;
|
||||
|
|
|
@ -573,8 +573,9 @@ public class QuickSearchBarActivity extends ThemedFragmentActivity implements On
|
|||
Expression.likeRaw(new Column(CachedUsers.NAME), "?||'%'", "^"),
|
||||
Expression.in(new Column(CachedUsers.USER_ID), new RawItemArray(nicknameIds)));
|
||||
final String[] selectionArgs = new String[]{queryEscaped, queryEscaped};
|
||||
final OrderBy orderBy = new OrderBy(CachedUsers.LAST_SEEN + " DESC", "score DESC",
|
||||
CachedUsers.SCREEN_NAME, CachedUsers.NAME);
|
||||
final String[] order = {CachedUsers.LAST_SEEN, "score", CachedUsers.SCREEN_NAME, CachedUsers.NAME};
|
||||
final boolean[] ascending = {false, false, true, true};
|
||||
final OrderBy orderBy = new OrderBy(order, ascending);
|
||||
final Uri uri = Uri.withAppendedPath(CachedUsers.CONTENT_URI_WITH_SCORE, String.valueOf(mAccountId));
|
||||
final Cursor usersCursor = context.getContentResolver().query(uri,
|
||||
CachedUsers.COLUMNS, selection != null ? selection.getSQL() : null,
|
||||
|
|
|
@ -38,6 +38,7 @@ import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
|
|||
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
|
||||
import com.nostra13.universalimageloader.core.download.ImageDownloader;
|
||||
import com.nostra13.universalimageloader.utils.L;
|
||||
import com.squareup.okhttp.internal.TwidereOkHttpPlatform;
|
||||
import com.squareup.otto.Bus;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
|
@ -186,6 +187,7 @@ public class TwidereApplication extends MultiDexApplication implements Constants
|
|||
}
|
||||
setTheme(ThemeUtils.getThemeResource(this));
|
||||
super.onCreate();
|
||||
// TwidereOkHttpPlatform.applyHack(this);
|
||||
mHandler = new Handler();
|
||||
mMessageBus = new Bus();
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
|
||||
|
|
|
@ -156,6 +156,7 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
|
|||
|
||||
public void setRefreshing(boolean refreshing) {
|
||||
if (refreshing == mSwipeRefreshLayout.isRefreshing()) return;
|
||||
if (!refreshing)
|
||||
updateRefreshProgressOffset();
|
||||
mSwipeRefreshLayout.setRefreshing(refreshing);
|
||||
}
|
||||
|
@ -249,7 +250,6 @@ public abstract class AbsStatusesFragment<Data> extends BaseSupportFragment impl
|
|||
super.fitSystemWindows(insets);
|
||||
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
mSystemWindowsInsets.set(insets);
|
||||
|
||||
updateRefreshProgressOffset();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,16 @@ import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
|||
import android.support.v4.content.CursorLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v4.util.Pair;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.internal.view.SupportMenuInflater;
|
||||
import android.support.v7.widget.ActionMenuView;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.Adapter;
|
||||
import android.support.v7.widget.RecyclerView.ViewHolder;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -70,6 +74,7 @@ import org.mariotaku.twidere.activity.support.QuickSearchBarActivity;
|
|||
import org.mariotaku.twidere.activity.support.UserProfileEditorActivity;
|
||||
import org.mariotaku.twidere.adapter.ArrayAdapter;
|
||||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.menu.SupportAccountActionProvider;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount.Indices;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
|
@ -89,6 +94,7 @@ import static org.mariotaku.twidere.util.Utils.openUserProfile;
|
|||
public class AccountsDashboardFragment extends BaseSupportListFragment implements LoaderCallbacks<Cursor>,
|
||||
OnSharedPreferenceChangeListener, OnCheckedChangeListener, ImageLoadingListener, OnClickListener {
|
||||
|
||||
private static final int MENU_GROUP_ACCOUNT_TOGGLE = 101;
|
||||
private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver(
|
||||
this, 0, this);
|
||||
|
||||
|
@ -106,7 +112,7 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
private ImageView mAccountProfileBannerView;
|
||||
private ShapedImageView mAccountProfileImageView;
|
||||
private TextView mAccountProfileNameView, mAccountProfileScreenNameView;
|
||||
private Switch mAccountsToggle;
|
||||
private ActionMenuView mAccountsToggleMenu;
|
||||
private View mAccountProfileContainer;
|
||||
|
||||
private Context mThemedContext;
|
||||
|
@ -166,10 +172,26 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) {
|
||||
if (data != null && data.getCount() > 0 && mAccountsAdapter.getSelectedAccountId() <= 0) {
|
||||
final Menu menu = mAccountsToggleMenu.getMenu();
|
||||
final SupportAccountActionProvider provider = (SupportAccountActionProvider) MenuItemCompat.getActionProvider(menu.findItem(MENU_SELECT_ACCOUNT));
|
||||
final ArrayList<ParcelableAccount> accounts = new ArrayList<>();
|
||||
if (data != null) {
|
||||
data.moveToFirst();
|
||||
mAccountsAdapter.setSelectedAccountId(mPreferences.getLong(KEY_DEFAULT_ACCOUNT_ID, -1));
|
||||
final Indices indices = new Indices(data);
|
||||
long defaultId = -1;
|
||||
while (!data.isAfterLast()) {
|
||||
final ParcelableAccount account = new ParcelableAccount(data, indices);
|
||||
accounts.add(account);
|
||||
if (defaultId < 0 && account.is_activated) {
|
||||
defaultId = account.account_id;
|
||||
}
|
||||
data.moveToNext();
|
||||
}
|
||||
if (mAccountsAdapter.getSelectedAccountId() <= 0) {
|
||||
mAccountsAdapter.setSelectedAccountId(mPreferences.getLong(KEY_DEFAULT_ACCOUNT_ID, defaultId));
|
||||
}
|
||||
}
|
||||
provider.setAccounts(accounts.toArray(new ParcelableAccount[accounts.size()]));
|
||||
mAccountsAdapter.changeCursor(data);
|
||||
updateAccountOptionsSeparatorLabel();
|
||||
updateDefaultAccountState();
|
||||
|
@ -310,7 +332,7 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
mAccountsAdapter = new AccountSelectorAdapter(context, this);
|
||||
mAccountOptionsAdapter = new AccountOptionsAdapter(context);
|
||||
mAppMenuAdapter = new AppMenuAdapter(context);
|
||||
mAppMenuSectionView = newSectionView(context, R.string.more);
|
||||
mAppMenuSectionView = Utils.newSectionView(context, R.string.more);
|
||||
mAccountSelectorView = inflater.inflate(R.layout.header_drawer_account_selector, listView, false);
|
||||
mAccountsSelector = (RecyclerView) mAccountSelectorView.findViewById(R.id.other_accounts_list);
|
||||
final LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||
|
@ -322,11 +344,12 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
mAccountProfileBannerView = (ImageView) mAccountSelectorView.findViewById(R.id.account_profile_banner);
|
||||
mAccountProfileNameView = (TextView) mAccountSelectorView.findViewById(R.id.name);
|
||||
mAccountProfileScreenNameView = (TextView) mAccountSelectorView.findViewById(R.id.screen_name);
|
||||
mAccountsToggle = (Switch) mAccountSelectorView.findViewById(R.id.toggle);
|
||||
mAccountsToggleMenu = (ActionMenuView) mAccountSelectorView.findViewById(R.id.toggle_menu);
|
||||
final SupportMenuInflater menuInflater = new SupportMenuInflater(context);
|
||||
menuInflater.inflate(R.menu.action_dashboard_timeline_toggle, mAccountsToggleMenu.getMenu());
|
||||
|
||||
mAccountProfileContainer.setOnClickListener(this);
|
||||
|
||||
mAccountsToggle.setOnCheckedChangeListener(this);
|
||||
mAdapter.addView(mAccountSelectorView, false);
|
||||
mAdapter.addAdapter(mAccountOptionsAdapter);
|
||||
mAdapter.addView(mAppMenuSectionView, false);
|
||||
|
@ -370,14 +393,6 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
return mThemedContext = new ContextThemeWrapper(context, themeResource);
|
||||
}
|
||||
|
||||
private static TextView newSectionView(final Context context, final int titleRes) {
|
||||
final TextView textView = new TextView(context, null, android.R.attr.listSeparatorTextViewStyle);
|
||||
if (titleRes != 0) {
|
||||
textView.setText(titleRes);
|
||||
}
|
||||
return textView;
|
||||
}
|
||||
|
||||
private void onAccountSelected(ParcelableAccount account) {
|
||||
mAccountsAdapter.setSelectedAccountId(account.account_id);
|
||||
updateAccountOptionsSeparatorLabel();
|
||||
|
@ -390,7 +405,6 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
}
|
||||
mAccountProfileNameView.setText(account.name);
|
||||
mAccountProfileScreenNameView.setText("@" + account.screen_name);
|
||||
mAccountsToggle.setChecked(account.is_activated);
|
||||
mImageLoader.displayProfileImage(mAccountProfileImageView, account.profile_image_url);
|
||||
mAccountProfileImageView.setBorderColors(account.color);
|
||||
final int bannerWidth = mAccountProfileBannerView.getWidth();
|
||||
|
|
|
@ -746,8 +746,9 @@ public class DirectMessagesConversationFragment extends BaseSupportFragment impl
|
|||
selection = null;
|
||||
selectionArgs = null;
|
||||
}
|
||||
final OrderBy orderBy = new OrderBy(CachedUsers.LAST_SEEN + " DESC",
|
||||
CachedUsers.SCREEN_NAME, CachedUsers.NAME);
|
||||
final String[] order = {CachedUsers.LAST_SEEN, CachedUsers.SCREEN_NAME, CachedUsers.NAME};
|
||||
final boolean[] ascending = {false, true, true};
|
||||
final OrderBy orderBy = new OrderBy(order, ascending);
|
||||
final Cursor c = context.getContentResolver().query(CachedUsers.CONTENT_URI,
|
||||
CachedUsers.BASIC_COLUMNS, selection != null ? selection.getSQL() : null,
|
||||
selectionArgs, orderBy.getSQL());
|
||||
|
|
|
@ -95,9 +95,10 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
|
||||
@Subscribe
|
||||
public void notifyTaskStateChanged(TaskStateChangedEvent event) {
|
||||
// updateRefreshState();
|
||||
updateRefreshState();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEntryClick(int position, DirectMessageEntry entry) {
|
||||
Utils.openMessageConversation(getActivity(), entry.account_id, entry.conversation_id);
|
||||
|
@ -105,7 +106,6 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
if (isRefreshing()) return;
|
||||
new TwidereAsyncTask<Void, Void, long[][]>() {
|
||||
|
||||
@Override
|
||||
|
@ -291,7 +291,7 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
public void setUserVisibleHint(final boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
if (isVisibleToUser) {
|
||||
// updateRefreshState();
|
||||
updateRefreshState();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,11 +319,15 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
// loadMoreMessages();
|
||||
// }
|
||||
|
||||
// protected void updateRefreshState() {
|
||||
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
// if (twitter == null || !getUserVisibleHint()) return;
|
||||
// setRefreshing(twitter.isReceivedDirectMessagesRefreshing() || twitter.isSentDirectMessagesRefreshing());
|
||||
// }
|
||||
protected void updateRefreshState() {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (twitter == null || !getUserVisibleHint()) return;
|
||||
setRefreshing(twitter.isReceivedDirectMessagesRefreshing() || twitter.isSentDirectMessagesRefreshing());
|
||||
}
|
||||
|
||||
public void setRefreshing(boolean refreshing) {
|
||||
mSwipeRefreshLayout.setRefreshing(refreshing);
|
||||
}
|
||||
|
||||
public boolean isRefreshing() {
|
||||
return mSwipeRefreshLayout.isRefreshing();
|
||||
|
@ -346,30 +350,31 @@ public class DirectMessagesFragment extends BaseSupportFragment implements Loade
|
|||
counts.add(id);
|
||||
}
|
||||
}
|
||||
//
|
||||
// private void loadMoreMessages() {
|
||||
// if (isRefreshing()) return;
|
||||
// new TwidereAsyncTask<Void, Void, long[][]>() {
|
||||
//
|
||||
// @Override
|
||||
// protected long[][] doInBackground(final Void... params) {
|
||||
// final long[][] result = new long[3][];
|
||||
// result[0] = getActivatedAccountIds(getActivity());
|
||||
// result[1] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
// result[2] = getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Outbox.CONTENT_URI);
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// protected void onPostExecute(final long[][] result) {
|
||||
// final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
// if (twitter == null) return;
|
||||
// twitter.getReceivedDirectMessagesAsync(result[0], result[1], null);
|
||||
// twitter.getSentDirectMessagesAsync(result[0], result[2], null);
|
||||
// }
|
||||
//
|
||||
// }.executeTask();
|
||||
// }
|
||||
|
||||
//
|
||||
private void loadMoreMessages() {
|
||||
if (isRefreshing()) return;
|
||||
new TwidereAsyncTask<Void, Void, long[][]>() {
|
||||
|
||||
@Override
|
||||
protected long[][] doInBackground(final Void... params) {
|
||||
final long[][] result = new long[3][];
|
||||
result[0] = Utils.getActivatedAccountIds(getActivity());
|
||||
result[1] = Utils.getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Inbox.CONTENT_URI);
|
||||
result[2] = Utils.getOldestMessageIdsFromDatabase(getActivity(), DirectMessages.Outbox.CONTENT_URI);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final long[][] result) {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
if (twitter == null) return;
|
||||
twitter.getReceivedDirectMessagesAsync(result[0], result[1], null);
|
||||
twitter.getSentDirectMessagesAsync(result[0], result[2], null);
|
||||
}
|
||||
|
||||
}.executeTask();
|
||||
}
|
||||
|
||||
private MessageEntriesAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.mariotaku.twidere.fragment.support;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.LoaderManager.LoaderCallbacks;
|
||||
|
@ -12,23 +13,37 @@ import android.view.ContextThemeWrapper;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
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.twidere.R;
|
||||
import org.mariotaku.twidere.fragment.support.TrendsSuggectionsFragment.TrendsAdapter;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.CachedTrends;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.accessor.ViewAccessor;
|
||||
import org.mariotaku.twidere.view.ExtendedFrameLayout;
|
||||
import org.mariotaku.twidere.view.iface.IExtendedView.OnFitSystemWindowsListener;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.getTableNameByUri;
|
||||
import static org.mariotaku.twidere.util.Utils.openTweetSearch;
|
||||
|
||||
public class QuickMenuFragment extends BaseSupportFragment {
|
||||
public class QuickMenuFragment extends BaseSupportFragment implements OnFitSystemWindowsListener, OnItemClickListener {
|
||||
|
||||
private ExtendedFrameLayout mQuickMenuContainer;
|
||||
private SharedPreferences mPreferences;
|
||||
private Context mThemedContext;
|
||||
private ListView mListView;
|
||||
|
@ -46,9 +61,13 @@ public class QuickMenuFragment extends BaseSupportFragment {
|
|||
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
|
||||
final Uri uri = CachedTrends.Local.CONTENT_URI;
|
||||
final String table = getTableNameByUri(uri);
|
||||
final String where = table != null ? CachedTrends.TIMESTAMP + " = " + "(SELECT " + CachedTrends.TIMESTAMP
|
||||
+ " FROM " + table + " ORDER BY " + CachedTrends.TIMESTAMP + " DESC LIMIT 1)" : null;
|
||||
return new CursorLoader(getActivity(), uri, CachedTrends.COLUMNS, where, null, null);
|
||||
final SQLSelectQuery selectQuery = SQLQueryBuilder.select(new Columns(CachedTrends.TIMESTAMP))
|
||||
.from(new Table(table))
|
||||
.orderBy(new OrderBy(CachedTrends.TIMESTAMP, false))
|
||||
.limit(1)
|
||||
.build();
|
||||
final Expression where = Expression.equals(CachedTrends.TIMESTAMP, selectQuery);
|
||||
return new CursorLoader(getActivity(), uri, CachedTrends.COLUMNS, where.getSQL(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,20 +85,30 @@ public class QuickMenuFragment extends BaseSupportFragment {
|
|||
@Override
|
||||
public void onActivityCreated(final Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
mQuickMenuContainer.setOnFitSystemWindowsListener(this);
|
||||
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
if (mPreferences.getBoolean(KEY_QUICK_MENU_EXPANDED, false)) {
|
||||
} else {
|
||||
}
|
||||
final Context context = getThemedContext();
|
||||
mAdapter = new MergeAdapter();
|
||||
mTrendsAdapter = new TrendsAdapter(getThemedContext());
|
||||
mTrendsAdapter = new TrendsAdapter(context);
|
||||
|
||||
mAdapter.addView(Utils.newSectionView(context, R.string.trends), false);
|
||||
mAdapter.addAdapter(mTrendsAdapter);
|
||||
mListView.setAdapter(mAdapter);
|
||||
mListView.setOnItemClickListener(this);
|
||||
getLoaderManager().initLoader(LOADER_ID_TRENDS, null, mTrendsCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
|
||||
return LayoutInflater.from(getThemedContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
|
||||
return LayoutInflater.from(getThemedContext()).inflate(R.layout.fragment_quick_menu, container, false);
|
||||
return inflater.inflate(R.layout.fragment_quick_menu, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,6 +122,7 @@ public class QuickMenuFragment extends BaseSupportFragment {
|
|||
@Override
|
||||
public void onBaseViewCreated(final View view, final Bundle savedInstanceState) {
|
||||
super.onBaseViewCreated(view, savedInstanceState);
|
||||
mQuickMenuContainer = (ExtendedFrameLayout) view.findViewById(R.id.quick_menu_fragment);
|
||||
mListView = (ListView) view.findViewById(android.R.id.list);
|
||||
mSlidingUpPanel = (SlidingUpPanelLayout) view.findViewById(R.id.activities_drawer);
|
||||
mActivitiesConfigButton = (ImageButton) view.findViewById(R.id.activities_config_button);
|
||||
|
@ -100,6 +130,23 @@ public class QuickMenuFragment extends BaseSupportFragment {
|
|||
ViewAccessor.setBackground(activitiesContainer, ThemeUtils.getWindowBackground(getThemedContext()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFitSystemWindows(Rect insets) {
|
||||
mQuickMenuContainer.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ListAdapter adapter = mAdapter.getAdapter(position);
|
||||
if (adapter instanceof TrendsAdapter) {
|
||||
openTweetSearch(getActivity(), getAccountId(), (String) adapter.getItem(position));
|
||||
}
|
||||
}
|
||||
|
||||
private long getAccountId() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Context getThemedContext() {
|
||||
if (mThemedContext != null) return mThemedContext;
|
||||
final Context context = getActivity();
|
||||
|
|
|
@ -29,6 +29,11 @@ import android.graphics.Color;
|
|||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
|
||||
import android.nfc.NfcEvent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
|
@ -85,6 +90,7 @@ import org.mariotaku.twidere.util.ClipboardUtils;
|
|||
import org.mariotaku.twidere.util.CompareUtils;
|
||||
import org.mariotaku.twidere.util.ImageLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.ImageLoadingHandler;
|
||||
import org.mariotaku.twidere.util.LinkCreator;
|
||||
import org.mariotaku.twidere.util.StatusLinkClickHandler;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.TwidereLinkify;
|
||||
|
@ -129,7 +135,8 @@ import static org.mariotaku.twidere.util.Utils.showOkMessage;
|
|||
* Created by mariotaku on 14/12/5.
|
||||
*/
|
||||
public class StatusFragment extends BaseSupportFragment
|
||||
implements LoaderCallbacks<SingleResponse<ParcelableStatus>>, OnMediaClickListener, StatusAdapterListener {
|
||||
implements LoaderCallbacks<SingleResponse<ParcelableStatus>>, OnMediaClickListener,
|
||||
StatusAdapterListener, CreateNdefMessageCallback {
|
||||
|
||||
private static final int LOADER_ID_DETAIL_STATUS = 1;
|
||||
private static final int LOADER_ID_STATUS_REPLIES = 2;
|
||||
|
@ -173,6 +180,19 @@ public class StatusFragment extends BaseSupportFragment
|
|||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public NdefMessage createNdefMessage(NfcEvent event) {
|
||||
final ParcelableStatus status = getStatus();
|
||||
if (status == null) return null;
|
||||
return new NdefMessage(new NdefRecord[]{
|
||||
NdefRecord.createUri(LinkCreator.getStatusTwitterLink(status.user_screen_name, status.id)),
|
||||
});
|
||||
}
|
||||
|
||||
private ParcelableStatus getStatus() {
|
||||
return mStatusAdapter.getStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
switch (requestCode) {
|
||||
|
@ -214,6 +234,7 @@ public class StatusFragment extends BaseSupportFragment
|
|||
if (view == null) throw new AssertionError();
|
||||
final Context context = view.getContext();
|
||||
final boolean compact = Utils.isCompactCards(context);
|
||||
initNdefCallback();
|
||||
mLayoutManager = new StatusListLinearLayoutManager(context, mRecyclerView);
|
||||
mItemDecoration = new DividerItemDecoration(context, mLayoutManager.getOrientation());
|
||||
if (compact) {
|
||||
|
@ -364,12 +385,12 @@ public class StatusFragment extends BaseSupportFragment
|
|||
if (status.media == null) {
|
||||
SpiceProfilingUtil.profile(getActivity(), status.account_id,
|
||||
status.id + ",Words," + status.account_id + "," + status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + status.text_plain.length() + "," + status.timestamp);
|
||||
+ "," + status.text_plain.length() + "," + status.timestamp);
|
||||
SpiceProfilingUtil.log(getActivity(), status.id + ",Words," + status.account_id + "," + status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + status.text_plain.length() + "," + status.timestamp);
|
||||
} else {
|
||||
for (final ParcelableMedia spiceMedia : status.media) {
|
||||
if(TypeMapingUtil.getMediaType(spiceMedia.type).equals("image")) {
|
||||
if (TypeMapingUtil.getMediaType(spiceMedia.type).equals("image")) {
|
||||
SpiceProfilingUtil.profile(getActivity(), status.account_id,
|
||||
status.id + ",PreviewM," + status.account_id + "," + status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + status.text_plain.length() + "," + TypeMapingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height + ","
|
||||
|
@ -1210,6 +1231,18 @@ public class StatusFragment extends BaseSupportFragment
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void initNdefCallback() {
|
||||
try {
|
||||
final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(getActivity());
|
||||
if (adapter == null) return;
|
||||
adapter.setNdefPushMessageCallback(this, getActivity());
|
||||
} catch (SecurityException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class StatusListLinearLayoutManager extends LinearLayoutManager {
|
||||
|
||||
private final RecyclerView recyclerView;
|
||||
|
|
|
@ -76,9 +76,9 @@ public class TrendsSuggectionsFragment extends BasePullToRefreshListFragment imp
|
|||
@Override
|
||||
public void onListItemClick(final ListView l, final View v, final int position, final long id) {
|
||||
if (mMultiSelectManager.isActive()) return;
|
||||
final Cursor cur = (Cursor) mTrendsAdapter.getItem(position - l.getHeaderViewsCount());
|
||||
if (cur == null) return;
|
||||
openTweetSearch(getActivity(), mAccountId, cur.getString(cur.getColumnIndex(CachedTrends.NAME)));
|
||||
final String trend = mTrendsAdapter.getItem(position - l.getHeaderViewsCount());
|
||||
if (trend == null) return;
|
||||
openTweetSearch(getActivity(), mAccountId, trend);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,6 +126,23 @@ public class TrendsSuggectionsFragment extends BasePullToRefreshListFragment imp
|
|||
}
|
||||
|
||||
static class TrendsAdapter extends SimpleCursorAdapter {
|
||||
private int mNameIdx;
|
||||
|
||||
@Override
|
||||
public String getItem(int position) {
|
||||
final Cursor c = getCursor();
|
||||
if (c != null && !c.isClosed() && c.moveToPosition(position))
|
||||
return c.getString(mNameIdx);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor swapCursor(Cursor c) {
|
||||
if (c != null) {
|
||||
mNameIdx = c.getColumnIndex(CachedTrends.NAME);
|
||||
}
|
||||
return super.swapCursor(c);
|
||||
}
|
||||
|
||||
public TrendsAdapter(final Context context) {
|
||||
super(context, android.R.layout.simple_list_item_1, null, new String[]{CachedTrends.NAME},
|
||||
|
|
|
@ -42,6 +42,12 @@ import android.graphics.drawable.ColorDrawable;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
|
||||
import android.nfc.NfcEvent;
|
||||
import android.nfc.tech.Ndef;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
|
@ -104,6 +110,7 @@ import org.mariotaku.twidere.text.TextAlphaSpan;
|
|||
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
|
||||
import org.mariotaku.twidere.util.ContentValuesCreator;
|
||||
import org.mariotaku.twidere.util.ImageLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.LinkCreator;
|
||||
import org.mariotaku.twidere.util.MathUtils;
|
||||
import org.mariotaku.twidere.util.ParseUtils;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
|
@ -160,7 +167,8 @@ import static org.mariotaku.twidere.util.Utils.showInfoMessage;
|
|||
|
||||
public class UserFragment extends BaseSupportFragment implements OnClickListener,
|
||||
OnLinkClickListener, OnSizeChangedListener, OnSharedPreferenceChangeListener,
|
||||
OnTouchListener, DrawerCallback, SupportFragmentCallback, SystemWindowsInsetsCallback {
|
||||
OnTouchListener, DrawerCallback, SupportFragmentCallback, SystemWindowsInsetsCallback,
|
||||
CreateNdefMessageCallback {
|
||||
|
||||
public static final String TRANSITION_NAME_PROFILE_IMAGE = "profile_image";
|
||||
public static final String TRANSITION_NAME_PROFILE_TYPE = "profile_type";
|
||||
|
@ -220,7 +228,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
}
|
||||
|
||||
private void updateRefreshState() {
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
if (user == null) return;
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
final boolean is_creating_friendship = twitter != null
|
||||
|
@ -317,7 +325,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
public void onLoadFinished(final Loader<SingleResponse<Relationship>> loader,
|
||||
final SingleResponse<Relationship> data) {
|
||||
mFollowProgress.setVisibility(View.GONE);
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
final Relationship relationship = data.getData();
|
||||
mRelationship = relationship;
|
||||
if (user == null) return;
|
||||
|
@ -566,7 +574,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
switch (requestCode) {
|
||||
case REQUEST_SET_COLOR: {
|
||||
if (user == null) return;
|
||||
|
@ -644,6 +652,8 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
mProfileImageLoader = getApplication().getImageLoaderWrapper();
|
||||
final FragmentActivity activity = getActivity();
|
||||
|
||||
initNdefCallback();
|
||||
|
||||
activity.setEnterSharedElementCallback(new SharedElementCallback() {
|
||||
|
||||
@Override
|
||||
|
@ -715,6 +725,25 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
setupUserPages();
|
||||
}
|
||||
|
||||
private void initNdefCallback() {
|
||||
try {
|
||||
final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(getActivity());
|
||||
if (adapter == null) return;
|
||||
adapter.setNdefPushMessageCallback(this, getActivity());
|
||||
} catch (SecurityException e) {
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NdefMessage createNdefMessage(NfcEvent event) {
|
||||
final ParcelableUser user = getUser();
|
||||
if (user == null) return null;
|
||||
return new NdefMessage(new NdefRecord[]{
|
||||
NdefRecord.createUri(LinkCreator.getUserTwitterLink(user.screen_name)),
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
@ -725,11 +754,15 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
|
||||
@Subscribe
|
||||
public void notifyProfileUpdated(ProfileUpdatedEvent event) {
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
if (user == null || !user.equals(event.user)) return;
|
||||
displayUser(event.user);
|
||||
}
|
||||
|
||||
public ParcelableUser getUser() {
|
||||
return mUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
final Bus bus = TwidereApplication.getInstance(getActivity()).getMessageBus();
|
||||
|
@ -739,7 +772,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
|
||||
@Override
|
||||
public void onSaveInstanceState(final Bundle outState) {
|
||||
outState.putParcelable(EXTRA_USER, mUser);
|
||||
outState.putParcelable(EXTRA_USER, getUser());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
@ -763,7 +796,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
public void onPrepareOptionsMenu(final Menu menu) {
|
||||
if (!shouldUseNativeMenu() || !menu.hasVisibleItems()) return;
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
final Relationship relationship = mRelationship;
|
||||
if (twitter == null || user == null) return;
|
||||
final boolean isMyself = user.account_id == user.id;
|
||||
|
@ -827,7 +860,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
final Relationship relationship = mRelationship;
|
||||
if (user == null || twitter == null) return false;
|
||||
switch (item.getItemId()) {
|
||||
|
@ -964,7 +997,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
@Override
|
||||
public void onClick(final View view) {
|
||||
final FragmentActivity activity = getActivity();
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
if (activity == null || user == null) return;
|
||||
switch (view.getId()) {
|
||||
case R.id.retry: {
|
||||
|
@ -1030,7 +1063,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
@Override
|
||||
public void onLinkClick(final String link, final String orig, final long account_id, final int type,
|
||||
final boolean sensitive, int start, int end) {
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
if (user == null) return;
|
||||
switch (type) {
|
||||
case TwidereLinkify.LINK_TYPE_MENTION: {
|
||||
|
@ -1156,7 +1189,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
|
||||
private void getFriendship() {
|
||||
mRelationship = null;
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
final LoaderManager lm = getLoaderManager();
|
||||
lm.destroyLoader(LOADER_ID_FRIENDSHIP);
|
||||
final Bundle args = new Bundle();
|
||||
|
@ -1187,7 +1220,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
|
|||
|
||||
private void updateFollowProgressState() {
|
||||
final AsyncTwitterWrapper twitter = getTwitterWrapper();
|
||||
final ParcelableUser user = mUser;
|
||||
final ParcelableUser user = getUser();
|
||||
if (twitter == null || user == null) {
|
||||
mFollowButton.setVisibility(View.GONE);
|
||||
mFollowProgress.setVisibility(View.GONE);
|
||||
|
|
|
@ -13,49 +13,59 @@ import org.mariotaku.twidere.model.ParcelableAccount;
|
|||
|
||||
public class AccountActionProvider extends ActionProvider implements TwidereConstants {
|
||||
|
||||
public static final int MENU_GROUP = 201;
|
||||
public static final int MENU_GROUP = 201;
|
||||
|
||||
private final ParcelableAccount[] mAccounts;
|
||||
private ParcelableAccount[] mAccounts;
|
||||
|
||||
private long mAccountId;
|
||||
private long mAccountId;
|
||||
|
||||
public AccountActionProvider(final Context context) {
|
||||
super(context);
|
||||
mAccounts = ParcelableAccount.getAccounts(context, false, false);
|
||||
}
|
||||
public AccountActionProvider(final Context context, final ParcelableAccount[] accounts) {
|
||||
super(context);
|
||||
setAccounts(accounts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return true;
|
||||
}
|
||||
public AccountActionProvider(final Context context) {
|
||||
this(context, ParcelableAccount.getAccounts(context, false, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(final SubMenu subMenu) {
|
||||
subMenu.removeGroup(MENU_GROUP);
|
||||
for (final ParcelableAccount account : mAccounts) {
|
||||
final MenuItem item = subMenu.add(MENU_GROUP, Menu.NONE, 0, account.name);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, account);
|
||||
item.setIntent(intent);
|
||||
}
|
||||
subMenu.setGroupCheckable(MENU_GROUP, true, true);
|
||||
for (int i = 0, j = subMenu.size(); i < j; i++) {
|
||||
final MenuItem item = subMenu.getItem(i);
|
||||
final Intent intent = item.getIntent();
|
||||
final ParcelableAccount account = intent.getParcelableExtra(EXTRA_ACCOUNT);
|
||||
if (account.account_id == mAccountId) {
|
||||
item.setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setAccountId(final long accountId) {
|
||||
mAccountId = accountId;
|
||||
}
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setAccounts(ParcelableAccount[] accounts) {
|
||||
mAccounts = accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(final SubMenu subMenu) {
|
||||
if (mAccounts == null) return;
|
||||
subMenu.removeGroup(MENU_GROUP);
|
||||
for (final ParcelableAccount account : mAccounts) {
|
||||
final MenuItem item = subMenu.add(MENU_GROUP, Menu.NONE, 0, account.name);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, account);
|
||||
item.setIntent(intent);
|
||||
}
|
||||
subMenu.setGroupCheckable(MENU_GROUP, true, true);
|
||||
for (int i = 0, j = subMenu.size(); i < j; i++) {
|
||||
final MenuItem item = subMenu.getItem(i);
|
||||
final Intent intent = item.getIntent();
|
||||
final ParcelableAccount account = intent.getParcelableExtra(EXTRA_ACCOUNT);
|
||||
if (account.account_id == mAccountId) {
|
||||
item.setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAccountId(final long accountId) {
|
||||
mAccountId = accountId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.view.ActionProvider;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
|
||||
import org.mariotaku.twidere.TwidereConstants;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
|
||||
public class SupportAccountActionProvider extends ActionProvider implements TwidereConstants {
|
||||
|
||||
public static final int MENU_GROUP = 201;
|
||||
|
||||
private ParcelableAccount[] mAccounts;
|
||||
|
||||
private long mAccountId;
|
||||
private boolean mExclusive;
|
||||
|
||||
public SupportAccountActionProvider(final Context context, final ParcelableAccount[] accounts) {
|
||||
super(context);
|
||||
mAccounts = accounts;
|
||||
}
|
||||
|
||||
public SupportAccountActionProvider(final Context context) {
|
||||
this(context, ParcelableAccount.getAccounts(context, false, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setAccounts(ParcelableAccount[] accounts) {
|
||||
mAccounts = accounts;
|
||||
}
|
||||
|
||||
public void setExclusive(boolean exclusive) {
|
||||
mExclusive = exclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(final SubMenu subMenu) {
|
||||
if (mAccounts == null) return;
|
||||
subMenu.removeGroup(MENU_GROUP);
|
||||
for (final ParcelableAccount account : mAccounts) {
|
||||
final MenuItem item = subMenu.add(MENU_GROUP, Menu.NONE, 0, account.name);
|
||||
final Intent intent = new Intent();
|
||||
intent.putExtra(EXTRA_ACCOUNT, account);
|
||||
item.setIntent(intent);
|
||||
}
|
||||
subMenu.setGroupCheckable(MENU_GROUP, true, mExclusive);
|
||||
for (int i = 0, j = subMenu.size(); i < j; i++) {
|
||||
final MenuItem item = subMenu.getItem(i);
|
||||
final Intent intent = item.getIntent();
|
||||
final ParcelableAccount account = intent.getParcelableExtra(EXTRA_ACCOUNT);
|
||||
if (account.account_id == mAccountId) {
|
||||
item.setChecked(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setAccountId(final long accountId) {
|
||||
mAccountId = accountId;
|
||||
}
|
||||
|
||||
}
|
|
@ -35,12 +35,12 @@ import static org.mariotaku.twidere.util.Utils.createStatusShareIntent;
|
|||
/**
|
||||
* Created by mariotaku on 14/12/7.
|
||||
*/
|
||||
public class StatusShareProvider extends ActionProvider implements Constants {
|
||||
public class SupportStatusShareProvider extends ActionProvider implements Constants {
|
||||
|
||||
private final Context mContext;
|
||||
private ParcelableStatus mStatus;
|
||||
|
||||
public StatusShareProvider(Context context) {
|
||||
public SupportStatusShareProvider(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
|
@ -97,6 +97,7 @@ import org.mariotaku.twidere.util.message.UnreadCountUpdatedEvent;
|
|||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -975,12 +976,14 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
|
|||
private Cursor getDNSCursor(final String host) {
|
||||
final MatrixCursor c = new MatrixCursor(TwidereDataStore.DNS.MATRIX_COLUMNS);
|
||||
try {
|
||||
final String address = mHostAddressResolver.resolve(host);
|
||||
if (host != null && address != null) {
|
||||
c.addRow(new String[]{host, address});
|
||||
final InetAddress[] addresses = mHostAddressResolver.resolve(host);
|
||||
for (InetAddress address : addresses) {
|
||||
c.addRow(new String[]{host, address.getHostAddress()});
|
||||
}
|
||||
} catch (final IOException ignore) {
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.w(LOGTAG, ignore);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
|
|
@ -534,7 +534,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
cr.delete(SavedSearches.CONTENT_URI, where.getSQL(), null);
|
||||
ContentResolverUtils.bulkInsert(cr, SavedSearches.CONTENT_URI, values);
|
||||
} catch (TwitterException e) {
|
||||
e.printStackTrace();
|
||||
Log.w(LOGTAG, e);
|
||||
}
|
||||
}
|
||||
return SingleResponse.getInstance();
|
||||
|
@ -2332,21 +2332,21 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
|||
bus.post(new StatusRetweetedEvent(status));
|
||||
//spice
|
||||
if (status.media == null) {
|
||||
SpiceProfilingUtil.log(getContext(),status.id + ",Retweet," + account_id + ","
|
||||
SpiceProfilingUtil.log(getContext(), status.id + ",Retweet," + account_id + ","
|
||||
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count);
|
||||
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",Retweet," + account_id + ","
|
||||
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count);
|
||||
} else {
|
||||
for (final ParcelableMedia spiceMedia : status.media) {
|
||||
if(TypeMapingUtil.getMediaType(spiceMedia.type).equals("image")) {
|
||||
SpiceProfilingUtil.log(getContext(),status.id + ",RetweetM," + account_id + ","
|
||||
if (TypeMapingUtil.getMediaType(spiceMedia.type).equals("image")) {
|
||||
SpiceProfilingUtil.log(getContext(), status.id + ",RetweetM," + account_id + ","
|
||||
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + spiceMedia.media_url + "," + TypeMapingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height);
|
||||
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",RetweetM," + account_id + ","
|
||||
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + spiceMedia.media_url + "," + TypeMapingUtil.getMediaType(spiceMedia.type) + "," + spiceMedia.width + "x" + spiceMedia.height);
|
||||
} else {
|
||||
SpiceProfilingUtil.log(getContext(),status.id + ",RetweetO," + account_id + ","
|
||||
SpiceProfilingUtil.log(getContext(), status.id + ",RetweetO," + account_id + ","
|
||||
+ status.user_id + "," + status.reply_count + "," + status.retweet_count + "," + status.favorite_count
|
||||
+ "," + spiceMedia.media_url + "," + TypeMapingUtil.getMediaType(spiceMedia.type));
|
||||
SpiceProfilingUtil.profile(getContext(), account_id, status.id + ",RetweetO," + account_id + ","
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.mariotaku.twidere.Constants;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/3/14.
|
||||
*/
|
||||
public class LinkCreator implements Constants {
|
||||
|
||||
private static final String AUTHORITY_TWITTER = "twitter.com";
|
||||
|
||||
public static Uri getStatusTwitterLink(String screenName, long statusId) {
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_HTTPS);
|
||||
builder.authority(AUTHORITY_TWITTER);
|
||||
builder.appendPath(screenName);
|
||||
builder.appendPath("status");
|
||||
builder.appendPath(String.valueOf(statusId));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Uri getTwidereStatusLink(long accountId, long statusId) {
|
||||
final Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_TWIDERE);
|
||||
builder.authority(AUTHORITY_STATUS);
|
||||
if (accountId > 0) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
|
||||
}
|
||||
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, String.valueOf(statusId));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Uri getTwidereUserLink(long accountId, long userId, String screenName) {
|
||||
final Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_TWIDERE);
|
||||
builder.authority(AUTHORITY_USER);
|
||||
if (accountId > 0) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
|
||||
}
|
||||
if (userId > 0) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(userId));
|
||||
}
|
||||
if (screenName != null) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Uri getUserTwitterLink(String screenName) {
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_HTTPS);
|
||||
builder.authority(AUTHORITY_TWITTER);
|
||||
builder.appendPath(screenName);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
|
@ -231,7 +231,7 @@ public class TwidereQueryBuilder {
|
|||
}
|
||||
qb.where(where);
|
||||
qb.groupBy(Utils.getColumnsFromProjection(ConversationEntries.CONVERSATION_ID, DirectMessages.ACCOUNT_ID));
|
||||
qb.orderBy(new OrderBy(ConversationEntries.MESSAGE_TIMESTAMP + " DESC"));
|
||||
qb.orderBy(new OrderBy(ConversationEntries.MESSAGE_TIMESTAMP ,false));
|
||||
return qb.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ import org.mariotaku.twidere.fragment.support.UserTimelineFragment;
|
|||
import org.mariotaku.twidere.fragment.support.UsersListFragment;
|
||||
import org.mariotaku.twidere.graphic.ActionIconDrawable;
|
||||
import org.mariotaku.twidere.graphic.PaddingDrawable;
|
||||
import org.mariotaku.twidere.menu.StatusShareProvider;
|
||||
import org.mariotaku.twidere.menu.SupportStatusShareProvider;
|
||||
import org.mariotaku.twidere.model.AccountPreferences;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount.ParcelableCredentials;
|
||||
|
@ -648,8 +648,8 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final Expression account_where = new Expression(Statuses.ACCOUNT_ID + " = " + account_id);
|
||||
final SQLSelectQuery.Builder qb = new SQLSelectQuery.Builder();
|
||||
qb.select(new Column(Statuses._ID)).from(new Tables(table));
|
||||
qb.where(new Expression(Statuses.ACCOUNT_ID + " = " + account_id));
|
||||
qb.orderBy(new OrderBy(Statuses.STATUS_ID + " DESC"));
|
||||
qb.where(Expression.equals(Statuses.ACCOUNT_ID, account_id));
|
||||
qb.orderBy(new OrderBy(Statuses.STATUS_ID, false));
|
||||
qb.limit(itemLimit);
|
||||
final Expression where = Expression.and(Expression.notIn(new Column(Statuses._ID), qb.build()), account_where);
|
||||
resolver.delete(uri, where.getSQL(), null);
|
||||
|
@ -659,8 +659,8 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final Expression account_where = new Expression(DirectMessages.ACCOUNT_ID + " = " + account_id);
|
||||
final SQLSelectQuery.Builder qb = new SQLSelectQuery.Builder();
|
||||
qb.select(new Column(DirectMessages._ID)).from(new Tables(table));
|
||||
qb.where(new Expression(DirectMessages.ACCOUNT_ID + " = " + account_id));
|
||||
qb.orderBy(new OrderBy(DirectMessages.MESSAGE_ID + " DESC"));
|
||||
qb.where(Expression.equals(DirectMessages.ACCOUNT_ID, account_id));
|
||||
qb.orderBy(new OrderBy(DirectMessages.MESSAGE_ID, false));
|
||||
qb.limit(itemLimit);
|
||||
final Expression where = Expression.and(Expression.notIn(new Column(DirectMessages._ID), qb.build()), account_where);
|
||||
resolver.delete(uri, where.getSQL(), null);
|
||||
|
@ -673,7 +673,7 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
final SQLSelectQuery.Builder qb = new SQLSelectQuery.Builder();
|
||||
qb.select(new Column(BaseColumns._ID));
|
||||
qb.from(new Tables(table));
|
||||
qb.orderBy(new OrderBy(BaseColumns._ID + " DESC"));
|
||||
qb.orderBy(new OrderBy(BaseColumns._ID, false));
|
||||
qb.limit(itemLimit * 20);
|
||||
final Expression where = Expression.notIn(new Column(BaseColumns._ID), qb.build());
|
||||
resolver.delete(uri, where.getSQL(), null);
|
||||
|
@ -1101,10 +1101,9 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
}
|
||||
|
||||
public static String getStatusShareText(final Context context, final ParcelableStatus status) {
|
||||
final String link = String.format(Locale.ROOT, "https://twitter.com/%s/status/%d",
|
||||
status.user_screen_name, status.id);
|
||||
final Uri link = LinkCreator.getStatusTwitterLink(status.user_screen_name, status.id);
|
||||
return context.getString(R.string.status_share_text_format_with_link,
|
||||
status.text_plain, link);
|
||||
status.text_plain, link.toString());
|
||||
}
|
||||
|
||||
public static String getStatusShareSubject(final Context context, ParcelableStatus status) {
|
||||
|
@ -1558,6 +1557,16 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
return isOAuth && TwitterContentUtils.isOfficialKey(context, consumerKey, consumerSecret);
|
||||
}
|
||||
|
||||
public static TextView newSectionView(final Context context, final int titleRes) {
|
||||
return newSectionView(context, titleRes != 0 ? context.getString(titleRes) : null);
|
||||
}
|
||||
|
||||
public static TextView newSectionView(final Context context, final CharSequence title) {
|
||||
final TextView textView = new TextView(context, null, android.R.attr.listSeparatorTextViewStyle);
|
||||
textView.setText(title);
|
||||
return textView;
|
||||
}
|
||||
|
||||
public static boolean setLastSeen(Context context, UserMentionEntity[] entities, long time) {
|
||||
if (entities == null) return false;
|
||||
boolean result = false;
|
||||
|
@ -3053,18 +3062,15 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
builder.authority(AUTHORITY_SEARCH);
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
|
||||
builder.appendQueryParameter(QUERY_PARAM_QUERY, query);
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
|
||||
final Uri uri = builder.build();
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void openStatus(final Context context, final long accountId, final long statusId) {
|
||||
if (context == null || accountId <= 0 || statusId <= 0) return;
|
||||
final Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_TWIDERE);
|
||||
builder.authority(AUTHORITY_STATUS);
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
|
||||
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, String.valueOf(statusId));
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
|
||||
final Uri uri = LinkCreator.getTwidereStatusLink(accountId, statusId);
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
|
@ -3387,17 +3393,8 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
public static void openUserProfile(final Context context, final long accountId, final long userId,
|
||||
final String screenName, final Bundle activityOptions) {
|
||||
if (context == null || accountId <= 0 || userId <= 0 && isEmpty(screenName)) return;
|
||||
final Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(SCHEME_TWIDERE);
|
||||
builder.authority(AUTHORITY_USER);
|
||||
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
|
||||
if (userId > 0) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(userId));
|
||||
}
|
||||
if (screenName != null) {
|
||||
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
|
||||
}
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
|
||||
final Uri uri = LinkCreator.getTwidereUserLink(accountId, userId, screenName);
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
if (context instanceof Activity) {
|
||||
ActivityCompat.startActivity((Activity) context, intent, activityOptions);
|
||||
} else {
|
||||
|
@ -3613,8 +3610,8 @@ public final class Utils implements Constants, TwitterConstants {
|
|||
EXTRA_STATUS, EXTRA_STATUS_JSON, status);
|
||||
final MenuItem shareItem = menu.findItem(R.id.share);
|
||||
final ActionProvider shareProvider = MenuItemCompat.getActionProvider(shareItem);
|
||||
if (shareProvider instanceof StatusShareProvider) {
|
||||
((StatusShareProvider) shareProvider).setStatus(status);
|
||||
if (shareProvider instanceof SupportStatusShareProvider) {
|
||||
((SupportStatusShareProvider) shareProvider).setStatus(status);
|
||||
} else if (shareProvider instanceof ShareActionProvider) {
|
||||
final Intent shareIntent = createStatusShareIntent(context, status);
|
||||
((ShareActionProvider) shareProvider).setShareIntent(shareIntent);
|
||||
|
|
|
@ -24,9 +24,13 @@ import android.content.Context;
|
|||
import android.content.SharedPreferences;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
|
||||
import org.mariotaku.querybuilder.Columns;
|
||||
import org.mariotaku.querybuilder.NewColumn;
|
||||
import org.mariotaku.querybuilder.SQLQueryBuilder;
|
||||
import org.mariotaku.querybuilder.Table;
|
||||
import org.mariotaku.querybuilder.query.SQLCreateIndexQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLCreateTableQuery;
|
||||
import org.mariotaku.querybuilder.query.SQLCreateViewQuery;
|
||||
import org.mariotaku.twidere.Constants;
|
||||
|
@ -85,12 +89,27 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
db.execSQL(createTable(Tabs.TABLE_NAME, Tabs.COLUMNS, Tabs.TYPES, true));
|
||||
db.execSQL(createTable(SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true));
|
||||
db.execSQL(createTable(SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true));
|
||||
db.execSQL(createDirectMessagesView().getSQL());
|
||||
db.execSQL(createDirectMessageConversationEntriesView().getSQL());
|
||||
|
||||
createViews(db);
|
||||
|
||||
createIndices(db);
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
private void createIndices(SQLiteDatabase db) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
|
||||
db.execSQL(createIndex("statuses_index", Statuses.TABLE_NAME, new String[]{Statuses.ACCOUNT_ID}, true));
|
||||
db.execSQL(createIndex("mentions_index", Mentions.TABLE_NAME, new String[]{Statuses.ACCOUNT_ID}, true));
|
||||
}
|
||||
|
||||
private void createViews(SQLiteDatabase db) {
|
||||
db.execSQL(createDirectMessagesView().getSQL());
|
||||
db.execSQL(createDirectMessageConversationEntriesView().getSQL());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDowngrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
handleVersionChange(db, oldVersion, newVersion);
|
||||
|
@ -166,8 +185,8 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
safeUpgrade(db, SavedSearches.TABLE_NAME, SavedSearches.COLUMNS, SavedSearches.TYPES, true, null);
|
||||
safeUpgrade(db, SearchHistory.TABLE_NAME, SearchHistory.COLUMNS, SearchHistory.TYPES, true, null);
|
||||
db.beginTransaction();
|
||||
db.execSQL(createDirectMessagesView().getSQL());
|
||||
db.execSQL(createDirectMessageConversationEntriesView().getSQL());
|
||||
createViews(db);
|
||||
createIndices(db);
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
}
|
||||
|
@ -179,4 +198,12 @@ public final class TwidereSQLiteOpenHelper extends SQLiteOpenHelper implements C
|
|||
return qb.buildSQL();
|
||||
}
|
||||
|
||||
private static String createIndex(final String indexName, final String tableName, final String[] columns,
|
||||
final boolean createIfNotExists) {
|
||||
final SQLCreateIndexQuery.Builder qb = SQLQueryBuilder.createIndex(false, createIfNotExists);
|
||||
qb.name(indexName);
|
||||
qb.on(new Table(tableName), new Columns(columns));
|
||||
return qb.buildSQL();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,94 +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.twidere.util.net;
|
||||
|
||||
import android.net.SSLCertificateSocketFactory;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import twitter4j.http.HostAddressResolver;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/1/31.
|
||||
*/
|
||||
public class HostResolvedSSLSocketFactory extends SSLSocketFactory {
|
||||
|
||||
private final SSLSocketFactory defaultFactory;
|
||||
private final HostAddressResolver resolver;
|
||||
|
||||
public HostResolvedSSLSocketFactory(HostAddressResolver resolver, boolean ignoreError) {
|
||||
if (ignoreError) {
|
||||
defaultFactory = SSLCertificateSocketFactory.getInsecure(0, null);
|
||||
} else {
|
||||
defaultFactory = SSLCertificateSocketFactory.getDefault(0, null);
|
||||
}
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
return defaultFactory.createSocket(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return defaultFactory.createSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||
return defaultFactory.createSocket(host, port, localHost, localPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
return defaultFactory.createSocket(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
return defaultFactory.createSocket(address, port, localAddress, localPort);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return defaultFactory.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return defaultFactory.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
return defaultFactory.createSocket(s, host, port, autoClose);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,118 +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.twidere.util.net;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
|
||||
import twitter4j.http.HostAddressResolver;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 15/1/31.
|
||||
*/
|
||||
public class HostResolvedSocketFactory extends SocketFactory {
|
||||
|
||||
private final SocketFactory defaultFactory;
|
||||
private final HostAddressResolver resolver;
|
||||
|
||||
public HostResolvedSocketFactory(HostAddressResolver resolver) {
|
||||
defaultFactory = SocketFactory.getDefault();
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
final String resolvedHost = resolver.resolve(host);
|
||||
if (resolvedHost != null && !resolvedHost.equals(host)) {
|
||||
if (InetAddressUtils.isIPv6Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(host, resolvedAddress), port);
|
||||
} else if (InetAddressUtils.isIPv4Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(host, resolvedAddress), port);
|
||||
}
|
||||
}
|
||||
return defaultFactory.createSocket(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return new Socket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||
final String resolvedHost = resolver.resolve(host);
|
||||
if (resolvedHost != null && !resolvedHost.equals(host)) {
|
||||
if (InetAddressUtils.isIPv6Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(host, resolvedAddress), port);
|
||||
} else if (InetAddressUtils.isIPv4Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(host, resolvedAddress), port);
|
||||
}
|
||||
}
|
||||
return defaultFactory.createSocket(host, port, localHost, localPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
final String hostName = host.getHostName();
|
||||
final String resolvedHost = resolver.resolve(hostName);
|
||||
if (resolvedHost != null && !resolvedHost.equals(hostName)) {
|
||||
if (InetAddressUtils.isIPv6Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port);
|
||||
} else if (InetAddressUtils.isIPv4Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port);
|
||||
}
|
||||
}
|
||||
return defaultFactory.createSocket(host, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
final String hostName = address.getHostName();
|
||||
final String resolvedHost = resolver.resolve(hostName);
|
||||
if (resolvedHost != null && !resolvedHost.equals(hostName)) {
|
||||
if (InetAddressUtils.isIPv6Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port, localAddress, localPort);
|
||||
} else if (InetAddressUtils.isIPv4Address(resolvedHost)) {
|
||||
final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress();
|
||||
return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port, localAddress, localPort);
|
||||
}
|
||||
}
|
||||
return defaultFactory.createSocket(address, port, localAddress, localPort);
|
||||
}
|
||||
|
||||
protected HostAddressResolver getResolver() {
|
||||
return resolver;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
package org.mariotaku.twidere.util.net;
|
||||
|
||||
import android.net.SSLCertificateSocketFactory;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.squareup.okhttp.Headers;
|
||||
|
@ -28,15 +29,19 @@ import com.squareup.okhttp.OkHttpClient;
|
|||
import com.squareup.okhttp.Request.Builder;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.internal.Internal;
|
||||
import com.squareup.okhttp.internal.Network;
|
||||
|
||||
import org.mariotaku.twidere.TwidereConstants;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.Proxy.Type;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -44,6 +49,8 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
import twitter4j.TwitterException;
|
||||
import twitter4j.auth.Authorization;
|
||||
import twitter4j.http.HostAddressResolver;
|
||||
|
@ -101,12 +108,28 @@ public class OkHttpClientImpl implements HttpClient, TwidereConstants {
|
|||
final OkHttpClient client = new OkHttpClient();
|
||||
final boolean ignoreSSLError = conf.isSSLErrorIgnored();
|
||||
client.setHostnameVerifier(new HostResolvedHostnameVerifier(ignoreSSLError));
|
||||
client.setSslSocketFactory(new HostResolvedSSLSocketFactory(resolver, ignoreSSLError));
|
||||
client.setSocketFactory(new HostResolvedSocketFactory(resolver));
|
||||
if (ignoreSSLError) {
|
||||
client.setSslSocketFactory(SSLCertificateSocketFactory.getInsecure(0, null));
|
||||
} else {
|
||||
client.setSslSocketFactory(SSLCertificateSocketFactory.getDefault(0, null));
|
||||
}
|
||||
client.setSocketFactory(SocketFactory.getDefault());
|
||||
|
||||
if (conf.isProxyConfigured()) {
|
||||
client.setProxy(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved(conf.getHttpProxyHost(),
|
||||
conf.getHttpProxyPort())));
|
||||
}
|
||||
Internal.instance.setNetwork(client, new Network() {
|
||||
@Override
|
||||
public InetAddress[] resolveInetAddresses(String host) throws UnknownHostException {
|
||||
try {
|
||||
return resolver.resolve(host);
|
||||
} catch (IOException e) {
|
||||
if (e instanceof UnknownHostException) throw (UnknownHostException) e;
|
||||
throw new UnknownHostException("Unable to resolve address " + e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
return client;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.mariotaku.twidere.util.net;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
|
@ -39,8 +40,14 @@ import org.xbill.DNS.SimpleResolver;
|
|||
import org.xbill.DNS.Type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import twitter4j.http.HostAddressResolver;
|
||||
|
||||
|
@ -48,7 +55,7 @@ import static android.text.TextUtils.isEmpty;
|
|||
|
||||
public class TwidereHostAddressResolver implements Constants, HostAddressResolver {
|
||||
|
||||
private static final String RESOLVER_LOGTAG = "TwidereHostAddressResolver";
|
||||
private static final String RESOLVER_LOGTAG = "Twidere.Host";
|
||||
|
||||
private static final String DEFAULT_DNS_SERVER_ADDRESS = "8.8.8.8";
|
||||
|
||||
|
@ -76,111 +83,125 @@ public class TwidereHostAddressResolver implements Constants, HostAddressResolve
|
|||
mHostCache.remove(host);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String resolve(final String host) throws IOException {
|
||||
if (host == null) return null;
|
||||
if (isValidIpAddress(host)) return null;
|
||||
public InetAddress[] resolve(@NonNull final String host) throws IOException {
|
||||
return resolveInternal(host, host);
|
||||
}
|
||||
|
||||
private InetAddress[] resolveInternal(String originalHost, String host) throws IOException {
|
||||
if (isValidIpAddress(host)) return fromAddressString(originalHost, host);
|
||||
// First, I'll try to load address cached.
|
||||
if (mHostCache.containsKey(host)) {
|
||||
final InetAddress[] hostAddr = mHostCache.get(host);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got cached address " + mHostCache.get(host) + " for host " + host);
|
||||
Log.d(RESOLVER_LOGTAG, "Got cached " + Arrays.toString(hostAddr));
|
||||
}
|
||||
return mHostCache.get(host);
|
||||
return hostAddr;
|
||||
}
|
||||
// Then I'll try to load from custom host mapping.
|
||||
// Stupid way to find top domain, but really fast.
|
||||
if (mHostMapping.contains(host)) {
|
||||
final String mappedAddr = mHostMapping.getString(host, null);
|
||||
mHostCache.put(host, mappedAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got mapped address " + mappedAddr + " for host " + host);
|
||||
if (mappedAddr != null) {
|
||||
final InetAddress[] hostAddr = fromAddressString(originalHost, mappedAddr);
|
||||
mHostCache.put(originalHost, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got mapped " + Arrays.toString(hostAddr));
|
||||
}
|
||||
return hostAddr;
|
||||
}
|
||||
return mappedAddr;
|
||||
}
|
||||
mSystemHosts.reloadIfNeeded();
|
||||
if (mSystemHosts.contains(host)) {
|
||||
final String hostAddr = mSystemHosts.getAddress(host);
|
||||
mHostCache.put(host, hostAddr);
|
||||
final InetAddress[] hostAddr = fromAddressString(originalHost, mSystemHosts.getAddress(host));
|
||||
mHostCache.put(originalHost, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got mapped address " + hostAddr + " for host " + host);
|
||||
Log.d(RESOLVER_LOGTAG, "Got hosts " + Arrays.toString(hostAddr));
|
||||
}
|
||||
return hostAddr;
|
||||
}
|
||||
final String customMappedHost = findHost(host);
|
||||
if (customMappedHost != null) {
|
||||
mHostCache.put(host, customMappedHost);
|
||||
final InetAddress[] hostAddr = fromAddressString(originalHost, customMappedHost);
|
||||
mHostCache.put(originalHost, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Got mapped address " + customMappedHost + " for host " + host);
|
||||
}
|
||||
return customMappedHost;
|
||||
return hostAddr;
|
||||
}
|
||||
initDns();
|
||||
// Use TCP DNS Query if enabled.
|
||||
if (mDns != null && mPreferences.getBoolean(KEY_TCP_DNS_QUERY, false)) {
|
||||
final Resolver dns = getResolver();
|
||||
if (dns != null && mPreferences.getBoolean(KEY_TCP_DNS_QUERY, false)) {
|
||||
final Lookup lookup = new Lookup(new Name(host), Type.A, DClass.IN);
|
||||
final Record[] records;
|
||||
lookup.setResolver(mDns);
|
||||
lookup.setResolver(dns);
|
||||
lookup.run();
|
||||
final int result = lookup.getResult();
|
||||
if (result != Lookup.SUCCESSFUL) {
|
||||
throw new IOException("Could not find " + host);
|
||||
}
|
||||
records = lookup.getAnswers();
|
||||
String hostAddr = null;
|
||||
final ArrayList<InetAddress> resolvedAddresses = new ArrayList<>();
|
||||
// Test each IP address resolved.
|
||||
for (final Record record : records) {
|
||||
if (record instanceof ARecord) {
|
||||
final InetAddress ipv4Addr = ((ARecord) record).getAddress();
|
||||
if (ipv4Addr.isReachable(300)) {
|
||||
hostAddr = ipv4Addr.getHostAddress();
|
||||
}
|
||||
resolvedAddresses.add(InetAddress.getByAddress(originalHost, ipv4Addr.getAddress()));
|
||||
// if (ipv4Addr.isReachable(300)) {
|
||||
// hostAddr = ipv4Addr.getHostAddress();
|
||||
// }
|
||||
} else if (record instanceof AAAARecord) {
|
||||
final InetAddress ipv6Addr = ((AAAARecord) record).getAddress();
|
||||
if (ipv6Addr.isReachable(300)) {
|
||||
hostAddr = ipv6Addr.getHostAddress();
|
||||
}
|
||||
resolvedAddresses.add(InetAddress.getByAddress(originalHost, ipv6Addr.getAddress()));
|
||||
// if (ipv6Addr.isReachable(300)) {
|
||||
// hostAddr = ipv6Addr.getHostAddress();
|
||||
// }
|
||||
}
|
||||
if (hostAddr != null) {
|
||||
mHostCache.put(host, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Resolved address " + hostAddr + " for host " + host);
|
||||
}
|
||||
return hostAddr;
|
||||
}
|
||||
if (!resolvedAddresses.isEmpty()) {
|
||||
final InetAddress[] hostAddr = resolvedAddresses.toArray(new InetAddress[resolvedAddresses.size()]);
|
||||
mHostCache.put(originalHost, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Resolved " + Arrays.toString(hostAddr));
|
||||
}
|
||||
return hostAddr;
|
||||
}
|
||||
// No address is reachable, but I believe the IP is correct.
|
||||
final Record record = records[0];
|
||||
if (record instanceof ARecord) {
|
||||
final InetAddress ipv4Addr = ((ARecord) record).getAddress();
|
||||
hostAddr = ipv4Addr.getHostAddress();
|
||||
} else if (record instanceof AAAARecord) {
|
||||
final InetAddress ipv6Addr = ((AAAARecord) record).getAddress();
|
||||
hostAddr = ipv6Addr.getHostAddress();
|
||||
} else if (record instanceof CNAMERecord)
|
||||
return resolve(((CNAMERecord) record).getTarget().toString());
|
||||
mHostCache.put(host, hostAddr);
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.d(RESOLVER_LOGTAG, "Resolved address " + hostAddr + " for host " + host);
|
||||
|
||||
for (final Record record : records) {
|
||||
if (record instanceof CNAMERecord)
|
||||
return resolveInternal(originalHost, ((CNAMERecord) record).getTarget().toString());
|
||||
}
|
||||
return hostAddr;
|
||||
}
|
||||
if (Utils.isDebugBuild()) {
|
||||
Log.w(RESOLVER_LOGTAG, "Resolve address " + host + " failed, using original host");
|
||||
}
|
||||
return host;
|
||||
return InetAddress.getAllByName(host);
|
||||
}
|
||||
|
||||
private InetAddress[] fromAddressString(String host, String address) throws UnknownHostException {
|
||||
InetAddress inetAddress = InetAddress.getByName(address);
|
||||
if (inetAddress instanceof Inet4Address) {
|
||||
return new InetAddress[]{Inet4Address.getByAddress(host, inetAddress.getAddress())};
|
||||
} else if (inetAddress instanceof Inet6Address) {
|
||||
return new InetAddress[]{Inet6Address.getByAddress(host, inetAddress.getAddress())};
|
||||
}
|
||||
throw new UnknownHostException("Bad address " + host + " = " + address);
|
||||
}
|
||||
|
||||
private String findHost(final String host) {
|
||||
for (final String rule : mHostMapping.getAll().keySet()) {
|
||||
if (hostMatches(host, rule)) return mHostMapping.getString(rule, null);
|
||||
for (final Entry<String, ?> entry : mHostMapping.getAll().entrySet()) {
|
||||
if (hostMatches(host, entry.getKey())) return (String) entry.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void initDns() throws IOException {
|
||||
if (mDns != null) return;
|
||||
private Resolver getResolver() throws IOException {
|
||||
if (mDns != null) return mDns;
|
||||
mDns = new SimpleResolver(mDnsAddress);
|
||||
mDns.setTCP(true);
|
||||
return mDns;
|
||||
}
|
||||
|
||||
private static boolean hostMatches(final String host, final String rule) {
|
||||
|
@ -194,7 +215,7 @@ public class TwidereHostAddressResolver implements Constants, HostAddressResolve
|
|||
return InetAddressUtils.isIPv4Address(address) || InetAddressUtils.isIPv6Address(address);
|
||||
}
|
||||
|
||||
private static class HostCache extends LinkedHashMap<String, String> {
|
||||
private static class HostCache extends LinkedHashMap<String, InetAddress[]> {
|
||||
|
||||
private static final long serialVersionUID = -9216545511009449147L;
|
||||
|
||||
|
@ -203,7 +224,7 @@ public class TwidereHostAddressResolver implements Constants, HostAddressResolve
|
|||
}
|
||||
|
||||
@Override
|
||||
public String put(final String key, final String value) {
|
||||
public InetAddress[] put(final String key, final InetAddress... value) {
|
||||
if (value == null) return null;
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import android.widget.TextView;
|
|||
import org.mariotaku.twidere.R;
|
||||
import org.mariotaku.twidere.adapter.iface.ContentCardClickListener;
|
||||
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
|
||||
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;
|
||||
|
@ -37,9 +38,8 @@ import twitter4j.TranslationResult;
|
|||
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
|
||||
|
||||
/**
|
||||
*
|
||||
* IDE gives me warning if I don't change default comment, so I write this XD
|
||||
*
|
||||
* <p/>
|
||||
* Created by mariotaku on 14/11/19.
|
||||
*/
|
||||
public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
|
||||
|
@ -217,7 +217,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
|
|||
} else {
|
||||
favoriteCountView.setText(null);
|
||||
}
|
||||
displayExtraTypeIcon(status.card_name, status.media != null ? status.media.length : 0);
|
||||
displayExtraTypeIcon(status.card_name, status.media, status.location);
|
||||
}
|
||||
|
||||
public void displayStatus(@NonNull Cursor cursor, @NonNull CursorIndices indices,
|
||||
|
@ -253,7 +253,10 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
|
|||
final String in_reply_to_screen_name = cursor.getString(indices.in_reply_to_user_screen_name);
|
||||
final String card_name = cursor.getString(indices.card_name);
|
||||
|
||||
final ParcelableMedia[] media = SimpleValueSerializer.fromSerializedString(cursor.getString(indices.media), ParcelableMedia.SIMPLE_CREATOR);
|
||||
final ParcelableMedia[] media = SimpleValueSerializer.fromSerializedString(
|
||||
cursor.getString(indices.media), ParcelableMedia.SIMPLE_CREATOR);
|
||||
final ParcelableLocation location = ParcelableLocation.fromString(
|
||||
cursor.getString(indices.location));
|
||||
|
||||
if (retweet_id > 0) {
|
||||
final String retweetedBy = UserColorNameUtils.getDisplayName(context, retweeted_by_id,
|
||||
|
@ -348,7 +351,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
|
|||
} else {
|
||||
favoriteCountView.setText(null);
|
||||
}
|
||||
displayExtraTypeIcon(card_name, media != null ? media.length : 0);
|
||||
displayExtraTypeIcon(card_name, media, location);
|
||||
}
|
||||
|
||||
public CardView getCardView() {
|
||||
|
@ -421,7 +424,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
|
|||
setTextSize(adapter.getTextSize());
|
||||
}
|
||||
|
||||
private void displayExtraTypeIcon(String cardName, int mediaLength) {
|
||||
private void displayExtraTypeIcon(String cardName, ParcelableMedia[] media, ParcelableLocation location) {
|
||||
if (TwitterCardUtils.CARD_NAME_AUDIO.equals(cardName)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_music);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
|
@ -431,9 +434,12 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
|
|||
} else if (TwitterCardUtils.CARD_NAME_PLAYER.equals(cardName)) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_play_circle);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (mediaLength > 0) {
|
||||
} else if (media != null && media.length > 0) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_gallery);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else if (location != null && location.isValid()) {
|
||||
extraTypeView.setImageResource(R.drawable.ic_action_location);
|
||||
extraTypeView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
extraTypeView.setVisibility(View.GONE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="#808080"/>
|
||||
<item android:state_window_focused="false" android:color="#808080"/>
|
||||
<item android:state_pressed="true" android:color="#808080"/>
|
||||
<item android:state_selected="true" android:color="#323232"/>
|
||||
<item android:color="#808080"/>
|
||||
<!-- not selected -->
|
||||
</selector>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false" android:color="#b0b0b0"/>
|
||||
<item android:state_window_focused="false" android:color="#808080"/>
|
||||
<item android:state_pressed="true" android:color="#808080"/>
|
||||
<item android:state_selected="true" android:color="#808080"/>
|
||||
<item android:color="#969696"/> <!-- not selected -->
|
||||
</selector>
|
||||
|
|
@ -46,6 +46,7 @@
|
|||
<android.support.v7.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="?cardItemBackgroundColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardPreventCornerOverlap="false"
|
||||
|
@ -200,6 +201,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/element_spacing_normal"
|
||||
app:cardBackgroundColor="?cardItemBackgroundColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardPreventCornerOverlap="false"
|
||||
|
@ -300,6 +302,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/element_spacing_normal"
|
||||
app:cardBackgroundColor="?cardItemBackgroundColor"
|
||||
app:cardCornerRadius="0dp"
|
||||
app:cardElevation="0dp"
|
||||
app:cardPreventCornerOverlap="false"
|
||||
|
|
|
@ -217,7 +217,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_reply"/>
|
||||
app:iabActivatedColor="@color/highlight_reply"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconThemedTextView
|
||||
android:id="@+id/retweet_count"
|
||||
|
@ -229,7 +230,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_retweet"/>
|
||||
app:iabActivatedColor="@color/highlight_retweet"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconThemedTextView
|
||||
android:id="@+id/favorite_count"
|
||||
|
@ -241,7 +243,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_favorite"/>
|
||||
app:iabActivatedColor="@color/highlight_favorite"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -196,7 +196,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_reply"/>
|
||||
app:iabActivatedColor="@color/highlight_reply"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconThemedTextView
|
||||
android:id="@+id/retweet_count"
|
||||
|
@ -209,7 +210,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_retweet"/>
|
||||
app:iabActivatedColor="@color/highlight_retweet"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
<org.mariotaku.twidere.view.ActionIconThemedTextView
|
||||
android:id="@+id/favorite_count"
|
||||
|
@ -222,7 +224,8 @@
|
|||
android:paddingLeft="@dimen/element_spacing_normal"
|
||||
android:paddingRight="@dimen/element_spacing_normal"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
app:iabActivatedColor="@color/highlight_favorite"/>
|
||||
app:iabActivatedColor="@color/highlight_favorite"
|
||||
app:iabColor="?android:textColorTertiary"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -25,41 +25,10 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
<fragment
|
||||
android:id="@+id/right_drawer"
|
||||
class="org.mariotaku.twidere.fragment.support.QuickMenuFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/right_drawer"
|
||||
class="org.mariotaku.twidere.fragment.support.QuickMenuFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout="@layout/fragment_quick_menu"/>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/element_spacing_normal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:rotation="95.0"
|
||||
android:text=": )"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="48sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.5"
|
||||
android:gravity="center"
|
||||
android:text="Something awesome will appear soon"
|
||||
android:textColor="@android:color/white"/>
|
||||
</LinearLayout>
|
||||
tools:layout="@layout/fragment_quick_menu"/>
|
||||
</org.mariotaku.twidere.view.RightDrawerFrameLayout>
|
|
@ -17,68 +17,73 @@
|
|||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<com.sothree.slidinguppanel.SlidingUpPanelLayout
|
||||
android:id="@+id/activities_drawer"
|
||||
<org.mariotaku.twidere.view.ExtendedFrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="bottom"
|
||||
app:umanoDragView="@+id/activities_header_title"
|
||||
app:umanoPanelHeight="@dimen/header_height_quick_menu">
|
||||
android:id="@+id/quick_menu_fragment"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/quick_menu_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/activities_container"
|
||||
<com.sothree.slidinguppanel.SlidingUpPanelLayout
|
||||
android:id="@+id/activities_drawer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/activities_header"
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/header_height_quick_menu"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activities_header_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/notifications"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activities_config_button"
|
||||
android:layout_width="@dimen/element_size_normal"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:contentDescription="@string/customize"
|
||||
android:src="@drawable/ic_action_settings"
|
||||
android:text="@string/notifications"/>
|
||||
</LinearLayout>
|
||||
android:gravity="bottom"
|
||||
app:umanoDragView="@+id/activities_header_title"
|
||||
app:umanoPanelHeight="@dimen/header_height_quick_menu">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/activities_content"
|
||||
android:id="@+id/quick_menu_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/activities_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/activities_header"
|
||||
style="?android:listSeparatorTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/header_height_quick_menu"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activities_header_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/notifications"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/activities_config_button"
|
||||
android:layout_width="@dimen/element_size_normal"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:contentDescription="@string/customize"
|
||||
android:src="@drawable/ic_action_settings"
|
||||
android:text="@string/notifications"/>
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/activities_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
|
||||
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
|
||||
</org.mariotaku.twidere.view.ExtendedFrameLayout>
|
|
@ -21,6 +21,7 @@
|
|||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
@ -56,7 +57,8 @@
|
|||
android:layout_marginBottom="@dimen/element_spacing_mlarge"
|
||||
android:layout_marginTop="@dimen/element_spacing_mlarge"
|
||||
app:sivBorder="true"
|
||||
app:sivBorderWidth="2dp"/>
|
||||
app:sivBorderWidth="2dp"
|
||||
tools:src="@drawable/profile_image_nyan_sakamoto"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/other_accounts_list"
|
||||
|
@ -86,23 +88,33 @@
|
|||
android:id="@+id/name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="bold"/>
|
||||
android:textStyle="bold"
|
||||
tools:text="Name"/>
|
||||
|
||||
<org.mariotaku.twidere.view.themed.ThemedTextView
|
||||
android:id="@+id/screen_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:textAppearanceSmall"/>
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:textAppearanceSmall"
|
||||
tools:text="\@username"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<org.mariotaku.twidere.view.themed.ThemedSwitch
|
||||
android:id="@+id/toggle"
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"/>
|
||||
android:layout_height="@dimen/element_size_normal">
|
||||
|
||||
<org.mariotaku.twidere.view.TwidereActionMenuView
|
||||
android:id="@+id/toggle_menu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
|
|
@ -34,10 +34,11 @@
|
|||
android:clickable="true"
|
||||
android:paddingLeft="@dimen/element_spacing_small"
|
||||
android:paddingRight="@dimen/element_spacing_small"
|
||||
android:layout_marginBottom="@dimen/element_spacing_minus_normal"
|
||||
tools:visiblity="visible">
|
||||
|
||||
<Space
|
||||
android:layout_width="@dimen/icon_size_card_list_item"
|
||||
android:layout_width="@dimen/element_spacing_large"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/padding_profile_image_detail_page"/>
|
||||
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Twidere - Twitter client for Android
|
||||
~
|
||||
~ Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@id/select_account"
|
||||
android:icon="@drawable/ic_action_user"
|
||||
android:title="@string/select_account"
|
||||
app:actionProviderClass="org.mariotaku.twidere.menu.SupportAccountActionProvider"
|
||||
app:showAsAction="always"/>
|
||||
|
||||
|
||||
</menu>
|
|
@ -32,7 +32,7 @@
|
|||
android:id="@id/share"
|
||||
android:icon="@drawable/ic_action_share"
|
||||
android:title="@string/share"
|
||||
app:actionProviderClass="org.mariotaku.twidere.menu.StatusShareProvider"
|
||||
app:actionProviderClass="org.mariotaku.twidere.menu.SupportStatusShareProvider"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@id/copy"
|
||||
|
|
|
@ -727,5 +727,7 @@
|
|||
<string name="research_tsinghua_spice">Tsinghua Spice</string>
|
||||
<string name="unknown_location">Unknown location</string>
|
||||
<string name="ellipsis">…</string>
|
||||
<string name="designed_by">Designed by</string>
|
||||
<string name="designer_name">Uucky Lee</string>
|
||||
|
||||
</resources>
|
|
@ -25,6 +25,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#ccc</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_dark</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.NoActionBar" parent="Theme.AppCompat.NoActionBar">
|
||||
|
@ -32,6 +34,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#ccc</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_dark</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.Dialog" parent="Theme.AppCompat.Dialog">
|
||||
|
@ -39,6 +43,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#ccc</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_dark</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.Light" parent="Theme.AppCompat.Light">
|
||||
|
@ -46,6 +52,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#aaa</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_light</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.Light.DarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
|
@ -53,6 +61,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#aaa</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_light</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.Light.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
|
@ -60,6 +70,8 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#aaa</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_light</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Compat.Base.Light.Dialog" parent="Theme.AppCompat.Light.Dialog">
|
||||
|
@ -67,5 +79,7 @@
|
|||
<!--<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>-->
|
||||
<!--<item name="android:colorAccent">@color/material_light_blue_a200</item>-->
|
||||
<!--<item name="android:colorAccent">#aaa</item>-->
|
||||
<item name="android:textColorTertiary">@color/tertiary_text_mtrl_light</item>
|
||||
<item name="android:textColorTertiaryInverse">@color/tertiary_text_mtrl_dark</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -20,6 +20,13 @@
|
|||
android:action="android.intent.action.VIEW"
|
||||
android:data="twidere://user?user_id=57610574&finish_only=true"/>
|
||||
</Preference>
|
||||
<Preference
|
||||
android:summary="@string/designer_name"
|
||||
android:title="@string/designed_by">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="twidere://user?user_id=1062473329&finish_only=true"/>
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:key="cat_donate"
|
||||
|
|
Loading…
Reference in New Issue