Skip to content
Snippets Groups Projects
Commit 2e0623a1 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Added proper backlog filtering, refactored some stuff

parent bc57c06a
No related branches found
No related tags found
No related merge requests found
Showing
with 1640 additions and 524 deletions
......@@ -3,13 +3,17 @@ package de.kuschku.libquassel.syncables.types;
import android.support.annotation.NonNull;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.Syncable;
import de.kuschku.libquassel.syncables.serializers.BufferSyncerSerializer;
import de.kuschku.libquassel.syncables.serializers.IdentitySerializer;
public class Identity extends SyncableObject {
public class Identity extends SyncableObject<Identity> {
@Syncable
private String identityName;
@Syncable
......@@ -257,4 +261,14 @@ public class Identity extends SyncableObject {
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
}
@Override
public void update(Identity from) {
}
@Override
public void update(Map<String, QVariant> from) {
update(IdentitySerializer.get().fromDatastream(from));
}
}
package de.kuschku.libquassel.syncables.types;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.serializers.BufferSyncerSerializer;
import de.kuschku.libquassel.syncables.serializers.IgnoreListManagerSerializer;
import static de.kuschku.util.AndroidAssert.assertEquals;
public class IgnoreListManager extends SyncableObject<IgnoreListManager> {
List<IgnoreRule> ignoreRules = new ArrayList<>();
public IgnoreListManager(List<Integer> scope, List<Integer> ignoreType,
List<Boolean> isActive, List<String> scopeRule, List<Boolean> isRegEx,
List<Integer> strictness, List<String> ignoreRule) {
assertEquals(scope.size(),ignoreType.size(), isActive.size(),scopeRule.size(), isRegEx.size(), strictness.size(), ignoreRule.size());
for (int i = 0; i < scope.size(); i++) {
ignoreRules.add(new IgnoreRule(
scope.get(i),
ignoreType.get(i),
isActive.get(i),
scopeRule.get(i),
isRegEx.get(i),
strictness.get(i),
ignoreRule.get(i)
));
}
}
@Override
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
client.setIgnoreListManager(this);
}
@Override
public void update(IgnoreListManager from) {
}
@Override
public void update(Map<String, QVariant> from) {
update(IgnoreListManagerSerializer.get().fromDatastream(from));
}
public boolean matches(Message message) {
return false;
}
public static class IgnoreRule {
private Scope scope;
private Type ignoreType;
private boolean isActive;
private String scopeRule;
private boolean isRegEx;
private Strictness strictness;
private String ignoreRule;
public IgnoreRule(Integer scope, Integer ignoreType, boolean isActive, String scopeRule, boolean isRegEx, Integer strictness, String ignoreRule) {
this(
Scope.of(scope),
Type.of(ignoreType),
isActive,
scopeRule,
isRegEx,
Strictness.of(strictness),
ignoreRule
);
}
public IgnoreRule(Scope scope, Type ignoreType, boolean isActive, String scopeRule, boolean isRegEx, Strictness strictness, String ignoreRule) {
this.scope = scope;
this.ignoreType = ignoreType;
this.isActive = isActive;
this.scopeRule = scopeRule;
this.isRegEx = isRegEx;
this.strictness = strictness;
this.ignoreRule = ignoreRule;
}
public enum Strictness {
INVALID(-1),
UNMATCHED(0),
SOFT(1),
HARD(2);
public final int id;
Strictness(int id) {
this.id = id;
}
public static Strictness of(int id) {
switch (id) {
case 0: return UNMATCHED;
case 1: return SOFT;
case 2: return HARD;
default: return INVALID;
}
}
}
public enum Type {
INVALID(-1),
SENDER_IGNORE(0),
MESSAGE_IGNORE(1),
CTCP_IGNORE(2);
public final int id;
Type(int id) {
this.id = id;
}
public static Type of(int id) {
switch (id) {
case 0: return SENDER_IGNORE;
case 1: return MESSAGE_IGNORE;
case 2: return CTCP_IGNORE;
default: return INVALID;
}
}
}
public enum Scope {
INVALID(-1),
GLOBAL_SCOPE(0),
NETWORK_SCOPE(1),
CHANNEL_SCOPE(2);
public final int id;
Scope(int id) {
this.id = id;
}
public static Scope of(int id) {
switch (id) {
case 0: return GLOBAL_SCOPE;
case 1: return NETWORK_SCOPE;
case 2: return CHANNEL_SCOPE;
default: return INVALID;
}
}
}
}
}
package de.kuschku.libquassel.syncables.types;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.Synced;
import de.kuschku.libquassel.syncables.serializers.IrcChannelSerializer;
import de.kuschku.util.AndroidAssert;
public class IrcChannel extends SyncableObject {
public final String name;
public final String topic;
public final String password;
public final Map<String, String> UserModes;
public final Map<String, Object> ChanModes;
public final boolean encrypted;
import static de.kuschku.util.AndroidAssert.*;
public class IrcChannel extends SyncableObject<IrcChannel> {
@Synced private String name;
@Synced private String topic;
@Synced private String password;
@Synced private Map<String, String> UserModes;
@Synced private Map<String, Object> ChanModes;
@Synced private boolean encrypted;
@Nullable
private Network network;
public IrcChannel(String name, String topic, String password, Map<String, String> userModes,
Map<String, Object> chanModes, boolean encrypted) {
......@@ -27,6 +44,26 @@ public class IrcChannel extends SyncableObject {
this.encrypted = encrypted;
}
public Map<String, List<String>> getA_ChanModes() {
if (ChanModes.get("A") == null) ChanModes.put("A", new HashMap<>());
return (Map<String, List<String>>) ChanModes.get("A");
}
public Map<String, String> getB_ChanModes() {
if (ChanModes.get("B") == null) ChanModes.put("B", new HashMap<>());
return (Map<String, String>) ChanModes.get("B");
}
public Map<String, String> getC_ChanModes() {
if (ChanModes.get("C") == null) ChanModes.put("C", new HashMap<>());
return (Map<String, String>) ChanModes.get("C");
}
public Set<String> getD_ChanModes() {
if (ChanModes.get("D") == null) ChanModes.put("D", new HashSet<>());
return (Set<String>) ChanModes.get("D");
}
@NonNull
@Override
public String toString() {
......@@ -40,6 +77,15 @@ public class IrcChannel extends SyncableObject {
'}';
}
@Nullable
public Network getNetwork() {
return network;
}
public void setNetwork(@Nullable Network network) {
this.network = network;
}
public void joinIrcUsers(@NonNull List<String> users, @NonNull List<String> modes) {
for (int i = 0; i < users.size(); i++) {
joinIrcUser(users.get(i), modes.get(i));
......@@ -70,13 +116,158 @@ public class IrcChannel extends SyncableObject {
UserModes.put(nick, UserModes.get(nick).replace(mode, ""));
}
public void addChannelMode(Character mode, String params) {
addChannelMode(String.copyValueOf(new char[]{mode}), params);
}
public void addChannelMode(char mode, String params) {
addChannelMode(String.copyValueOf(new char[]{mode}), params);
}
public void addChannelMode(String mode, String params) {
assertNotNull(network);
Network.ChannelModeType type = network.channelModeType(mode);
switch (type) {
case NOT_A_CHANMODE:
return;
case A_CHANMODE:
if (!getA_ChanModes().containsKey(mode)) {
getA_ChanModes().put(mode, new ArrayList<>(Collections.singleton(params)));
} else {
getA_ChanModes().get(mode).add(params);
}
break;
case B_CHANMODE:
getB_ChanModes().put(mode, params);
break;
case C_CHANMODE:
getB_ChanModes().put(mode, params);
break;
case D_CHANMODE:
getD_ChanModes().add(mode);
break;
}
}
public void removeChannelMode(Character mode, String params) {
removeChannelMode(String.copyValueOf(new char[]{mode}), params);
}
public void removeChannelMode(char mode, String params) {
removeChannelMode(String.copyValueOf(new char[]{mode}), params);
}
public void removeChannelMode(String mode, String params) {
assertNotNull(network);
Network.ChannelModeType type = network.channelModeType(mode);
switch (type) {
case NOT_A_CHANMODE:
return;
case A_CHANMODE:
if (getA_ChanModes().containsKey(mode))
getA_ChanModes().get(mode).removeAll(Collections.singleton(params));
break;
case B_CHANMODE:
getB_ChanModes().remove(mode);
break;
case C_CHANMODE:
getB_ChanModes().remove(mode);
break;
case D_CHANMODE:
getB_ChanModes().remove(mode);
break;
}
}
public boolean hasMode(Character mode) {
return hasMode(String.copyValueOf(new char[]{mode}));
}
public boolean hasMode(char mode) {
return hasMode(String.copyValueOf(new char[]{mode}));
}
public boolean hasMode(String mode) {
assertNotNull(network);
Network.ChannelModeType type = network.channelModeType(mode);
switch (type) {
case A_CHANMODE:
return getA_ChanModes().containsKey(mode);
case B_CHANMODE:
return getA_ChanModes().containsKey(mode);
case C_CHANMODE:
return getA_ChanModes().containsKey(mode);
case D_CHANMODE:
return getA_ChanModes().containsKey(mode);
default:
return false;
}
}
public void renameUser(String oldNick, String newNick) {
UserModes.put(newNick, UserModes.get(oldNick));
UserModes.remove(oldNick);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Map<String, String> getUserModes() {
return UserModes;
}
public void setUserModes(Map<String, String> userModes) {
UserModes = userModes;
}
public boolean isEncrypted() {
return encrypted;
}
public void setEncrypted(boolean encrypted) {
this.encrypted = encrypted;
}
@Override
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
}
@Override
public void update(IrcChannel from) {
this.name = from.name;
this.topic = from.topic;
this.password = from.password;
this.UserModes = from.UserModes;
this.ChanModes = from.ChanModes;
this.encrypted = from.encrypted;
}
@Override
public void update(Map<String, QVariant> from) {
update(IrcChannelSerializer.get().fromDatastream(from));
}
public Map<String, Object> getChanModes() {
return ChanModes;
}
}
......@@ -6,31 +6,35 @@ import android.support.annotation.Nullable;
import org.joda.time.DateTime;
import java.util.List;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.serializers.BufferSyncerSerializer;
import de.kuschku.libquassel.syncables.serializers.IrcUserSerializer;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class IrcUser extends SyncableObject {
public String server;
public String ircOperator;
public boolean away;
public int lastAwayMessage;
public DateTime idleTime;
public String whoisServiceReply;
public String suserHost;
public String nick;
public String realName;
public String awayMessage;
public DateTime loginTime;
public boolean encrypted;
public class IrcUser extends SyncableObject<IrcUser> {
private String server;
private String ircOperator;
private boolean away;
private int lastAwayMessage;
private DateTime idleTime;
private String whoisServiceReply;
private String suserHost;
private String nick;
private String realName;
private String awayMessage;
private DateTime loginTime;
private boolean encrypted;
@NonNull
public List<String> channels;
public String host;
public String userModes;
public String user;
private List<String> channels;
private String host;
private String userModes;
private String user;
private Network network;
......@@ -56,6 +60,71 @@ public class IrcUser extends SyncableObject {
this.user = user;
}
public String getServer() {
return server;
}
public String getIrcOperator() {
return ircOperator;
}
public boolean isAway() {
return away;
}
public int getLastAwayMessage() {
return lastAwayMessage;
}
public DateTime getIdleTime() {
return idleTime;
}
public String getWhoisServiceReply() {
return whoisServiceReply;
}
public String getSuserHost() {
return suserHost;
}
public String getNick() {
return nick;
}
public String getRealName() {
return realName;
}
public String getAwayMessage() {
return awayMessage;
}
public DateTime getLoginTime() {
return loginTime;
}
public boolean isEncrypted() {
return encrypted;
}
@NonNull
public List<String> getChannels() {
return channels;
}
public String getHost() {
return host;
}
public String getUserModes() {
return userModes;
}
public String getUser() {
return user;
}
/* BEGIN SYNC */
public void setServer(String server) {
......@@ -155,6 +224,31 @@ public class IrcUser extends SyncableObject {
setNetwork(network);
}
@Override
public void update(IrcUser from) {
this.server = from.server;
this.ircOperator = from.ircOperator;
this.away = from.away;
this.lastAwayMessage = from.lastAwayMessage;
this.idleTime = from.idleTime;
this.whoisServiceReply = from.whoisServiceReply;
this.suserHost = from.suserHost;
this.nick = from.nick;
this.realName = from.realName;
this.awayMessage = from.awayMessage;
this.loginTime = from.loginTime;
this.encrypted = from.encrypted;
this.channels = from.channels;
this.host = from.host;
this.userModes = from.userModes;
this.user = from.user;
}
@Override
public void update(Map<String, QVariant> from) {
update(IrcUserSerializer.get().fromDatastream(from));
}
public void quit() {
network.quit(this.nick);
}
......
......@@ -14,14 +14,15 @@ import java.util.Set;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.functions.types.InitRequestFunction;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.objects.types.NetworkServer;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.serializers.NetworkSerializer;
import de.kuschku.util.observables.ContentComparable;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class Network extends SyncableObject implements ContentComparable<Network> {
public class Network extends SyncableObject<Network> implements ContentComparable<Network> {
@NonNull
private final Set<Buffer> buffers = new HashSet<>();
@NonNull
......@@ -76,6 +77,7 @@ public class Network extends SyncableObject implements ContentComparable<Network
@Nullable
private Map<String, IrcMode> supportedModes;
private int networkId;
private Client client;
public Network(@NonNull Map<String, IrcChannel> channels, @NonNull Map<String, IrcUser> users,
@NonNull List<NetworkServer> serverList, @NonNull Map<String, String> supports,
......@@ -124,7 +126,7 @@ public class Network extends SyncableObject implements ContentComparable<Network
assertNotNull(provider);
for (IrcUser user : getUsers().values()) {
provider.dispatch(new InitRequestFunction("IrcUser", getNetworkId() + "/" + user.nick));
client.sendInitRequest("IrcUser", getNetworkId() + "/" + user.getNick());
}
}
......@@ -154,7 +156,7 @@ public class Network extends SyncableObject implements ContentComparable<Network
}
public void addIrcUser(String sender) {
provider.dispatch(new InitRequestFunction("IrcUser", getObjectName() + "/" + sender));
client.sendInitRequest("IrcUser", getObjectName() + "/" + sender);
}
@Nullable
......@@ -194,6 +196,19 @@ public class Network extends SyncableObject implements ContentComparable<Network
return channels;
}
public void addIrcChannel(String channelName) {
IrcChannel ircChannel = new IrcChannel(
channelName,
null,
null,
new HashMap<>(),
new HashMap<>(),
false
);
ircChannel.setNetwork(this);
channels.put(channelName, ircChannel);
}
public void setChannels(@NonNull Map<String, IrcChannel> channels) {
this.channels = channels;
}
......@@ -476,13 +491,57 @@ public class Network extends SyncableObject implements ContentComparable<Network
@Override
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
setObjectName(function.objectName);
setBusProvider(provider);
setNetworkId(Integer.parseInt(function.objectName));
setBusProvider(provider);
setClient(client);
doInit();
}
@Override
public void doInit() {
getBuffers().addAll(client.getBuffers(getNetworkId()));
initUsers();
client.putNetwork(this);
}
@Override
public void update(Network from) {
this.channels = from.channels;
this.users = from.users;
this.ServerList = from.ServerList;
this.Supports = from.Supports;
this.autoIdentifyPassword = from.autoIdentifyPassword;
this.autoIdentifyService = from.autoIdentifyService;
this.autoReconnectInterval = from.autoReconnectInterval;
this.autoReconnectRetries = from.autoReconnectRetries;
this.codecForDecoding = from.codecForDecoding;
this.codecForEncoding = from.codecForEncoding;
this.codecForServer = from.codecForServer;
this.connectionState = from.connectionState;
this.currentServer = from.currentServer;
this.identityId = from.identityId;
this.isConnected = from.isConnected;
this.latency = from.latency;
this.myNick = from.myNick;
this.networkName = from.networkName;
this.perform = from.perform;
this.rejoinChannels = from.rejoinChannels;
this.saslAccount = from.saslAccount;
this.saslPassword = from.saslPassword;
this.unlimitedReconnectRetries = from.unlimitedReconnectRetries;
this.useAutoIdentify = from.useAutoIdentify;
this.useAutoReconnect = from.useAutoReconnect;
this.useRandomServer = from.useRandomServer;
this.useSasl = from.useSasl;
parsePrefix();
assertNotNull(supportedModes);
}
@Override
public void update(Map<String, QVariant> from) {
update(NetworkSerializer.get().fromDatastream(from));
}
@Override
public boolean equalsContent(@NonNull Network other) {
return networkId == other.networkId;
......@@ -493,6 +552,10 @@ public class Network extends SyncableObject implements ContentComparable<Network
return networkId - another.networkId;
}
public void setClient(Client client) {
this.client = client;
}
public static class IrcMode {
public final int rank;
public final String prefix;
......@@ -511,4 +574,42 @@ public class Network extends SyncableObject implements ContentComparable<Network
'}';
}
}
public ChannelModeType channelModeType(char mode) {
return channelModeType(String.copyValueOf(new char[]{mode}));
}
public ChannelModeType channelModeType(String mode) {
if (mode.isEmpty())
return ChannelModeType.NOT_A_CHANMODE;
String rawChanModes = getSupports().get("CHANMODES");
if (rawChanModes == null || rawChanModes.isEmpty())
return ChannelModeType.NOT_A_CHANMODE;
String[] chanModes = rawChanModes.split(",");
for (int i = 0; i < chanModes.length; i++) {
if (chanModes[i].contains(mode)) {
switch (i) {
case 0: return ChannelModeType.A_CHANMODE;
case 1: return ChannelModeType.B_CHANMODE;
case 2: return ChannelModeType.C_CHANMODE;
case 3: return ChannelModeType.D_CHANMODE;
default: return ChannelModeType.NOT_A_CHANMODE;
}
}
}
return ChannelModeType.NOT_A_CHANMODE;
}
// see:
// http://www.irc.org/tech_docs/005.html
// http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt
public enum ChannelModeType {
NOT_A_CHANMODE,
A_CHANMODE,
B_CHANMODE,
C_CHANMODE,
D_CHANMODE
}
}
package de.kuschku.libquassel.syncables.types;
import android.support.annotation.NonNull;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.primitives.types.QVariant;
import de.kuschku.libquassel.syncables.serializers.BufferSyncerSerializer;
import de.kuschku.libquassel.syncables.serializers.NetworkConfigSerializer;
public class NetworkConfig extends SyncableObject<NetworkConfig> {
private int autoWhoNickLimit;
private int autoWhoDelay;
private boolean autoWhoEnabled;
private boolean standardCtcp;
private int pingInterval;
private int autoWhoInterval;
private int maxPingCount;
private boolean pingTimeoutEnabled;
public NetworkConfig(int autoWhoNickLimit, int autoWhoDelay, boolean autoWhoEnabled, boolean standardCtcp, int pingInterval, int autoWhoInterval, int maxPingCount, boolean pingTimeoutEnabled) {
this.autoWhoNickLimit = autoWhoNickLimit;
this.autoWhoDelay = autoWhoDelay;
this.autoWhoEnabled = autoWhoEnabled;
this.standardCtcp = standardCtcp;
this.pingInterval = pingInterval;
this.autoWhoInterval = autoWhoInterval;
this.maxPingCount = maxPingCount;
this.pingTimeoutEnabled = pingTimeoutEnabled;
}
public int getAutoWhoNickLimit() {
return autoWhoNickLimit;
}
public void setAutoWhoNickLimit(int autoWhoNickLimit) {
this.autoWhoNickLimit = autoWhoNickLimit;
}
public int getAutoWhoDelay() {
return autoWhoDelay;
}
public void setAutoWhoDelay(int autoWhoDelay) {
this.autoWhoDelay = autoWhoDelay;
}
public boolean isAutoWhoEnabled() {
return autoWhoEnabled;
}
public void setAutoWhoEnabled(boolean autoWhoEnabled) {
this.autoWhoEnabled = autoWhoEnabled;
}
public boolean isStandardCtcp() {
return standardCtcp;
}
public void setStandardCtcp(boolean standardCtcp) {
this.standardCtcp = standardCtcp;
}
public int getPingInterval() {
return pingInterval;
}
public void setPingInterval(int pingInterval) {
this.pingInterval = pingInterval;
}
public int getAutoWhoInterval() {
return autoWhoInterval;
}
public void setAutoWhoInterval(int autoWhoInterval) {
this.autoWhoInterval = autoWhoInterval;
}
public int getMaxPingCount() {
return maxPingCount;
}
public void setMaxPingCount(int maxPingCount) {
this.maxPingCount = maxPingCount;
}
public boolean isPingTimeoutEnabled() {
return pingTimeoutEnabled;
}
public void setPingTimeoutEnabled(boolean pingTimeoutEnabled) {
this.pingTimeoutEnabled = pingTimeoutEnabled;
}
@Override
public void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client) {
}
@Override
public void update(NetworkConfig from) {
this.autoWhoNickLimit = from.autoWhoNickLimit;
this.autoWhoDelay = from.autoWhoDelay;
this.autoWhoEnabled = from.autoWhoEnabled;
this.standardCtcp = from.standardCtcp;
this.pingInterval = from.pingInterval;
this.autoWhoInterval = from.autoWhoInterval;
this.maxPingCount = from.maxPingCount;
this.pingTimeoutEnabled = from.pingTimeoutEnabled;
}
@Override
public void update(Map<String, QVariant> from) {
update(NetworkConfigSerializer.get().fromDatastream(from));
}
}
......@@ -4,15 +4,18 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Arrays;
import java.util.Map;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.functions.types.InitDataFunction;
import de.kuschku.libquassel.functions.types.SyncFunction;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.primitives.types.QVariant;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public abstract class SyncableObject {
public abstract class SyncableObject<T extends SyncableObject<T>> {
@Nullable
protected BusProvider provider;
@Nullable
......@@ -47,4 +50,9 @@ public abstract class SyncableObject {
}
public abstract void init(@NonNull InitDataFunction function, @NonNull BusProvider provider, @NonNull Client client);
public void doInit() {}
public abstract void update(T from);
public abstract void update(Map<String, QVariant> from);
}
package de.kuschku.quasseldroid_ng.ui;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.quasseldroid_ng.ui.chat.WrappedSettings;
import de.kuschku.util.ui.ThemeUtil;
public class AppContext {
private ThemeUtil themeUtil;
private WrappedSettings settings;
private Client client;
private BusProvider provider;
public ThemeUtil getThemeUtil() {
return themeUtil;
}
public void setThemeUtil(ThemeUtil themeUtil) {
this.themeUtil = themeUtil;
}
public AppContext withThemeUtil(ThemeUtil themeUtil) {
setThemeUtil(themeUtil);
return this;
}
public WrappedSettings getSettings() {
return settings;
}
public void setSettings(WrappedSettings settings) {
this.settings = settings;
}
public AppContext withSettings(WrappedSettings settings) {
setSettings(settings);
return this;
}
public Client getClient() {
return client;
}
public void setClient(Client client) {
this.client = client;
}
public AppContext withClient(Client client) {
setClient(client);
return this;
}
public BusProvider getProvider() {
return provider;
}
public void setProvider(BusProvider provider) {
this.provider = provider;
}
public AppContext withProvider(BusProvider provider) {
setProvider(provider);
return this;
}
}
......@@ -29,4 +29,11 @@ public enum AppTheme {
case "QUASSEL": return QUASSEL;
}
}
@Override
public String toString() {
return name() + "{" +
"themeId=" + themeId +
'}';
}
}
package de.kuschku.quasseldroid_ng.ui.chat;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import java.lang.reflect.Array;
import java.util.ArrayList;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.syncables.types.BufferViewConfig;
import de.kuschku.libquassel.syncables.types.Network;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.quasseldroid_ng.ui.chat.drawer.NetworkItem;
import de.kuschku.util.observables.callbacks.ElementCallback;
import de.kuschku.util.observables.lists.ObservableComparableSortedList;
import de.kuschku.util.observables.lists.ObservableSortedList;
import static de.kuschku.util.AndroidAssert.assertNotNull;
public class BufferViewConfigWrapper {
private Drawer drawer;
private BufferViewConfig config;
private ObservableSortedList<NetworkItem> networks = new ObservableSortedList<>(NetworkItem.class, new ObservableSortedList.ItemComparator<NetworkItem>() {
@Override
public int compare(NetworkItem o1, NetworkItem o2) {
return o1.getName().getText().compareTo(o2.getName().getText());
}
@Override
public boolean areContentsTheSame(NetworkItem oldItem, NetworkItem newItem) {
return oldItem.getNetwork().getNetworkId() == newItem.getNetwork().getNetworkId();
}
@Override
public boolean areItemsTheSame(NetworkItem item1, NetworkItem item2) {
return item1 == item2;
}
});
public BufferViewConfigWrapper(AppContext context, BufferViewConfig config, Drawer drawer) {
this.config = config;
this.drawer = drawer;
config.doLateInit();
networks.clear();
for (Integer networkId : config.getNetworkList()) {
Network network = context.getClient().getNetwork(networkId);
assertNotNull(network);
networks.add(new NetworkItem(context, network, config));
}
config.getNetworkList().addCallback(new ElementCallback<Integer>() {
@Override
public void notifyItemInserted(Integer element) {
networks.add(new NetworkItem(context, context.getClient().getNetwork(element), config));
}
@Override
public void notifyItemRemoved(Integer element) {
for (NetworkItem network : networks) {
if (network.getNetwork().getNetworkId() == element) {
networks.remove(network);
break;
}
}
}
@Override
public void notifyItemChanged(Integer element) {
for (NetworkItem network : networks) {
if (network.getNetwork().getNetworkId() == element) {
networks.notifyItemChanged(networks.indexOf(network));
break;
}
}
}
});
}
public void updateDrawerItems() {
drawer.removeAllItems();
for (IDrawerItem item : getItems()) {
drawer.addItem(item);
}
for (int i = 0; i < drawer.getAdapter().getItemCount(); i++) {
IDrawerItem item = drawer.getAdapter().getItem(i);
if (item instanceof NetworkItem) {
NetworkItem networkItem = (NetworkItem) item;
if (networkItem.getNetwork().isConnected())
drawer.getAdapter().expand(i);
}
}
}
public void setDrawer(Drawer drawer) {
this.drawer = drawer;
}
public ArrayList<IDrawerItem> getItems() {
ArrayList<IDrawerItem> items = new ArrayList<>();
for (IDrawerItem item : networks) {
items.add(item);
}
return items;
}
}
package de.kuschku.quasseldroid_ng.ui.chat;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
......@@ -8,66 +10,78 @@ import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.AppCompatImageButton;
import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.RelativeLayout;
import android.util.Log;
import android.view.View;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.common.base.Splitter;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.materialize.util.UIUtils;
import com.mikepenz.fastadapter.IExpandable;
import com.mikepenz.fastadapter.IItem;
import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder;
import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IProfile;
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import aspm.OnChangeListener;
import aspm.PreferenceElement;
import aspm.StringPreference;
import aspm.annotations.Preference;
import java.util.Map;
import aspm.annotations.PreferenceWrapper;
import butterknife.Bind;
import butterknife.ButterKnife;
import de.kuschku.libquassel.BusProvider;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.events.BacklogReceivedEvent;
import de.kuschku.libquassel.events.ConnectionChangeEvent;
import de.kuschku.libquassel.events.GeneralErrorEvent;
import de.kuschku.libquassel.events.LagChangedEvent;
import de.kuschku.libquassel.exceptions.UnknownTypeException;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.syncables.types.BufferViewConfig;
import de.kuschku.libquassel.syncables.types.BufferViewManager;
import de.kuschku.libquassel.syncables.types.Network;
import de.kuschku.quasseldroid_ng.BuildConfig;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.quasseldroid_ng.service.ClientBackgroundThread;
import de.kuschku.quasseldroid_ng.service.QuasselService;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.quasseldroid_ng.ui.AppTheme;
import de.kuschku.quasseldroid_ng.ui.chat.chatview.MessageAdapter;
import de.kuschku.util.DrawerUtils;
import de.kuschku.quasseldroid_ng.ui.chat.drawer.NetworkItem;
import de.kuschku.util.keyboardutils.DialogKeyboardUtil;
import de.kuschku.util.ServerAddress;
import de.kuschku.util.instancestateutil.Storable;
import de.kuschku.util.instancestateutil.Store;
import de.kuschku.util.observables.AutoScroller;
import de.kuschku.util.observables.lists.ObservableSortedList;
import de.kuschku.util.ui.SpanFormatter;
import de.kuschku.util.ui.ThemeUtil;
import static de.kuschku.util.AndroidAssert.assertNotNull;
import static de.kuschku.util.AndroidAssert.assertTrue;
@UiThread
public class ChatActivity extends AppCompatActivity {
@NonNull
private final Status status = new Status();
@Bind(R.id.drawer_left)
DrawerLayout drawerLeft;
@Bind(R.id.navigation_left)
NavigationView navigationLeft;
@Bind(R.id.toolbar)
Toolbar toolbar;
@Bind(R.id.sliding_layout)
SlidingUpPanelLayout slidingLayout;
@Bind(R.id.chatline)
AppCompatEditText chatline;
@Bind(R.id.send)
AppCompatImageButton send;
......@@ -76,40 +90,66 @@ public class ChatActivity extends AppCompatActivity {
@Bind(R.id.swipe_view)
SwipeRefreshLayout swipeView;
@Bind(R.id.messages)
RecyclerView messages;
@Bind(R.id.navigation_header_container)
RelativeLayout navigationHeaderContainer;
@Bind(R.id.buffer_view_spinner)
AppCompatSpinner bufferViewSpinner;
WrappedSettings settings;
@PreferenceWrapper(BuildConfig.APPLICATION_ID)
public static abstract class Settings {
String theme;
boolean fullHostmask;
int textSize;
boolean mircColors;
String lastHost;
int lastPort;
String lastUsername;
String lastPassword;
}
@Nullable
private QuasselService.LocalBinder binder;
private AppContext context = new AppContext();
@NonNull
private final Status status = new Status();
private static class Status extends Storable {
@Store int bufferId = -1;
@Store int bufferViewConfigId = -1;
}
private ServiceInterface serviceInterface = new ServiceInterface();
private class ServiceInterface {
private void connect(@NonNull ServerAddress address) {
assertNotNull(binder);
disconnect();
@Nullable
BusProvider provider = new BusProvider();
provider.event.register(ChatActivity.this);
binder.startBackgroundThread(provider, address);
onConnectionEstablished();
}
private void disconnect() {
if (binder != null) binder.stopBackgroundThread();
if (backgroundThread != null) backgroundThread.provider.event.unregister(this);
backgroundThread = null;
}
}
private QuasselService.LocalBinder binder;
private ClientBackgroundThread backgroundThread;
private MessageAdapter messageAdapter;
private AccountHeader accountHeader;
private Drawer drawerLeft;
private BufferViewConfigWrapper wrapper;
private CharSequence subtitle;
private ServiceConnection serviceConnection = new ServiceConnection() {
@UiThread
public void onServiceConnected(@NonNull ComponentName cn, @NonNull IBinder service) {
assertNotNull(cn);
assertNotNull(service);
if (service instanceof QuasselService.LocalBinder) {
ChatActivity.this.binder = (QuasselService.LocalBinder) service;
assertNotNull(binder);
if (binder.getBackgroundThread() != null) {
connectToThread(binder.getBackgroundThread());
}
......@@ -118,41 +158,78 @@ public class ChatActivity extends AppCompatActivity {
@UiThread
public void onServiceDisconnected(@NonNull ComponentName cn) {
assertNotNull(cn);
backgroundThread = null;
serviceInterface.disconnect();
binder = null;
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
settings = new WrappedSettings(this);
setTheme(AppTheme.resFromString(settings.theme.get()));
context.setSettings(new WrappedSettings(this));
AppTheme theme = AppTheme.QUASSEL;
setTheme(theme.themeId);
context.setThemeUtil(new ThemeUtil(this, theme));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setContentView(R.layout.activity_chat);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
DrawerUtils.initDrawer(this, drawerLeft, toolbar, R.string.open_drawer, R.string.close_drawer);
ViewGroup.LayoutParams lp = navigationHeaderContainer.getLayoutParams();
assertNotNull(lp);
lp.height = lp.height + UIUtils.getStatusBarHeight(this);
navigationHeaderContainer.setLayoutParams(lp);
connectToService();
accountHeader = new AccountHeaderBuilder()
.withActivity(this)
.withCompactStyle(true)
.withHeaderBackground(R.drawable.bg)
.withSavedInstance(savedInstanceState)
.withProfileImagesVisible(false)
.withOnAccountHeaderListener((view, profile, current) -> {
if (!current) {
selectBufferViewConfig((int) profile.getIdentifier());
}
return true;
})
.build();
drawerLeft = new DrawerBuilder()
.withActivity(this)
.withToolbar(toolbar)
.withAccountHeader(accountHeader)
.withSavedInstance(savedInstanceState)
.withTranslucentStatusBar(true)
.build();
drawerLeft.addStickyFooterItem(new PrimaryDrawerItem().withIcon(R.drawable.ic_server_light).withName("(Re-)Connect").withIdentifier(-1));
drawerLeft.setOnDrawerItemClickListener((view, position, drawerItem) -> {
long identifier = drawerItem.getIdentifier();
if (identifier == -1) {
showConnectDialog();
return false;
} else {
if (((IExpandable) drawerItem).getSubItems() != null) {
drawerLeft.getAdapter().toggleExpandable(position);
return true;
} else {
selectBuffer((int) drawerItem.getIdentifier());
return false;
}
}
});
messages.setLayoutManager(new LinearLayoutManager(this));
messages.setItemAnimator(new DefaultItemAnimator());
messages.setAdapter(new MessageAdapter(this, new AutoScroller(messages)));
messages.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true));
messageAdapter = new MessageAdapter(this, context, new AutoScroller(messages));
messages.setAdapter(messageAdapter);
msgHistory.setAdapter(new FastAdapter<>());
msgHistory.setLayoutManager(new LinearLayoutManager(this));
msgHistory.setItemAnimator(new DefaultItemAnimator());
msgHistory.setAdapter(new FastAdapter<>());
bufferViewSpinner.setAdapter(new ArrayAdapter<>(this, R.layout.md_simplelist_item, android.R.id.title, new String[]{"All Chats", "Queries", "Highlights"}));
bufferViewSpinner.setPopupBackgroundResource(R.drawable.popup_background_material);
bufferViewSpinner.setSelection(0);
swipeView.setOnRefreshListener(() -> {
assertNotNull(context.getClient());
context.getClient().getBacklogManager().requestMoreBacklog(status.bufferId, 20);
});
send.setOnClickListener(view -> sendInput());
}
@Override
......@@ -174,7 +251,7 @@ public class ChatActivity extends AppCompatActivity {
private void connectToThread(@NonNull ClientBackgroundThread backgroundThread) {
assertNotNull(backgroundThread);
if (this.backgroundThread != null) backgroundThread.provider.event.unregister(this);
serviceInterface.disconnect();
this.backgroundThread = backgroundThread;
backgroundThread.provider.event.register(this);
......@@ -183,35 +260,181 @@ public class ChatActivity extends AppCompatActivity {
}
private void selectBufferViewConfig(@IntRange(from = -1) int bufferViewConfigId) {
if (wrapper != null) wrapper.setDrawer(null);
drawerLeft.removeAllItems();
if (bufferViewConfigId == -1) {
// TODO: Implement this
drawerLeft.removeAllItems();
} else {
assertNotNull(this.backgroundThread);
assertNotNull(this.backgroundThread.handler.client.getBufferViewManager());
assertNotNull(this.backgroundThread.handler.client.getBufferViewManager().BufferViews.get(bufferViewConfigId));
// TODO: Implement this
drawerLeft.removeAllItems();
BufferViewManager bufferViewManager = context.getClient().getBufferViewManager();
assertNotNull(bufferViewManager);
BufferViewConfig viewConfig = bufferViewManager.BufferViews.get(bufferViewConfigId);
assertNotNull(viewConfig);
wrapper = new BufferViewConfigWrapper(context, viewConfig, drawerLeft);
wrapper.updateDrawerItems();
}
}
private void selectBuffer(@IntRange(from = -1) int bufferId) {
if (bufferId == -1) {
messageAdapter.setMessageList(MessageAdapter.emptyList());
toolbar.setTitle(getResources().getString(R.string.app_name));
} else {
status.bufferId = bufferId;
// Make sure we are actually connected
ObservableSortedList<Message> list = context.getClient().getBacklogManager().getFiltered(status.bufferId);
Buffer buffer = context.getClient().getBuffer(status.bufferId);
// Make sure everything is properly defined
assertNotNull("Buffer is null: " + bufferId, buffer);
assertNotNull(list);
messageAdapter.setMessageList(list);
toolbar.setTitle(buffer.getName());
}
}
private void connectToService() {
Intent intent = new Intent(this, QuasselService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void onConnectionEstablished() {
assertNotNull(binder);
this.backgroundThread = binder.getBackgroundThread();
assertNotNull(this.backgroundThread);
assertNotNull(this.backgroundThread.handler.client.getBuffer(bufferId));
context.setClient(this.backgroundThread.handler.client);
assertNotNull(context.getClient());
}
private void sendInput() {
if (context.getClient() == null) return;
Buffer buffer = context.getClient().getBuffer(status.bufferId);
assertNotNull(buffer);
CharSequence text = chatline.getText();
context.getClient().sendInput(buffer.getInfo(), text.toString());
}
assertTrue(bufferId == -1 || null != this.backgroundThread.handler.client.getBuffer(bufferId));
// TODO: Implement this
public void onEventMainThread(ConnectionChangeEvent event) {
setSubtitle(event.status.name());
switch (event.status) {
case HANDSHAKE:
break;
case CORE_SETUP_REQUIRED:
break;
case LOGIN_REQUIRED:
assertNotNull(context.getClient());
showLoginDialog();
break;
case USER_SETUP_REQUIRED:
break;
case CONNECTED:
Log.e("TIME", String.valueOf(System.currentTimeMillis()));
updateBufferViewConfigs();
break;
}
}
private static class Status extends Storable {
@Store
public int bufferId = -1;
@Store
public int bufferViewConfigId = -1;
private void updateBufferViewConfigs() {
Map<Integer, BufferViewConfig> bufferViews = context.getClient().getBufferViewManager().BufferViews;
accountHeader.clear();
for (Map.Entry<Integer, BufferViewConfig> entry : bufferViews.entrySet()) {
if (entry.getValue() != null) {
accountHeader.addProfiles(
new ProfileDrawerItem()
.withName(entry.getValue().getBufferViewName())
.withIdentifier(entry.getKey())
);
}
}
selectBufferViewConfig(status.bufferViewConfigId);
selectBuffer(status.bufferId);
}
private void showLoginDialog() {
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title("Address")
.customView(R.layout.dialog_login, false)
.onPositive((dialog1, which) -> {
View parent = dialog1.getCustomView();
AppCompatEditText usernameField = (AppCompatEditText) parent.findViewById(R.id.username);
AppCompatEditText passwordField = (AppCompatEditText) parent.findViewById(R.id.password);
String username = usernameField.getText().toString();
String password = passwordField.getText().toString();
context.getSettings().lastUsername.set(username);
context.getSettings().lastPassword.set(password);
context.getClient().login(username, password);
Log.e("TIME", String.valueOf(System.currentTimeMillis()));
})
.positiveText("Login")
.neutralText("Cancel")
.build();
dialog.setOnKeyListener(new DialogKeyboardUtil(dialog));
((AppCompatEditText) dialog.getView().findViewById(R.id.username)).setText(context.getSettings().lastUsername.or(""));
((AppCompatEditText) dialog.getView().findViewById(R.id.password)).setText(context.getSettings().lastPassword.or(""));
dialog.show();
}
public void showConnectDialog() {
MaterialDialog dialog = new MaterialDialog.Builder(this)
.title("Address")
.customView(R.layout.dialog_address, false)
.onPositive((dialog1, which) -> {
View parent = dialog1.getCustomView();
AppCompatEditText hostField = (AppCompatEditText) parent.findViewById(R.id.host);
AppCompatEditText portField = (AppCompatEditText) parent.findViewById(R.id.port);
String host = hostField.getText().toString().trim();
int port = Integer.valueOf(portField.getText().toString().trim());
context.getSettings().lastHost.set(host);
context.getSettings().lastPort.set(port);
serviceInterface.connect(new ServerAddress(host, port));
})
.positiveText("Connect")
.neutralText("Cancel")
.build();
AppCompatEditText hostField = (AppCompatEditText) dialog.getView().findViewById(R.id.host);
AppCompatEditText portField = (AppCompatEditText) dialog.getView().findViewById(R.id.port);
dialog.setOnKeyListener(new DialogKeyboardUtil(dialog));
hostField.setText(context.getSettings().lastHost.or(""));
portField.setText(String.valueOf(context.getSettings().lastPort.or(4242)));
dialog.show();
}
public void onEventMainThread(BacklogReceivedEvent event) {
if (event.bufferId == status.bufferId) {
swipeView.setRefreshing(false);
}
}
public void onEventMainThread(GeneralErrorEvent event) {
Snackbar.make(messages, event.toString(), Snackbar.LENGTH_LONG).show();
for (String line : Splitter.fixedLength(2048).split(event.toString())) {
Log.e("ChatActivity", line);
}
if (event.exception != null)
event.exception.printStackTrace();
}
public void onEventMainThread(LagChangedEvent event) {
updateSubTitle();
}
protected void setSubtitle(CharSequence subtitle) {
this.subtitle = subtitle;
updateSubTitle();
}
private void updateSubTitle() {
if (context.getClient() != null) {
toolbar.setSubtitle(SpanFormatter.format("Lag: %.2f, %s", context.getClient().getLag() / 1000.0F, subtitle));
} else {
toolbar.setSubtitle(subtitle);
}
}
}
......@@ -16,6 +16,7 @@ import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.message.Message;
import de.kuschku.quasseldroid_ng.BuildConfig;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.quasseldroid_ng.ui.AppTheme;
import de.kuschku.util.annotationbind.AutoBinder;
import de.kuschku.util.annotationbind.AutoString;
......@@ -40,26 +41,14 @@ public class ChatMessageRenderer {
private MessageStyleContainer actionStyle;
private MessageStyleContainer plainStyle;
@Nullable
private Client client;
//@NonNull
//private final SharedPreferences preferences;
public ChatMessageRenderer(@NonNull Context ctx) {
this(ctx, new ThemeUtil(ctx));
}
public ChatMessageRenderer(@NonNull Context ctx, @NonNull AppTheme theme) {
this(ctx, new ThemeUtil(ctx, theme));
}
public ChatMessageRenderer(@NonNull Context ctx, @NonNull ThemeUtil themeUtil) {
//this.preferences = ctx.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
@NonNull
private AppContext context;
public ChatMessageRenderer(@NonNull Context ctx, @NonNull AppContext context) {
this.format = DateFormatHelper.getTimeFormatter(ctx);
this.strings = new FormatStrings(ctx);
setTheme(themeUtil);
this.context = context;
setTheme(context.getThemeUtil());
}
public void setTheme(ThemeUtil themeUtil) {
......@@ -91,10 +80,6 @@ public class ChatMessageRenderer {
);
}
public void setClient(@NonNull Client client) {
this.client = client;
}
private void applyStyle(@NonNull MessageViewHolder holder, @NonNull MessageStyleContainer style, @NonNull MessageStyleContainer highlightStyle, boolean highlight) {
MessageStyleContainer container = highlight ? highlightStyle : style;
holder.content.setTextColor(container.textColor);
......@@ -115,13 +100,13 @@ public class ChatMessageRenderer {
@NonNull
private CharSequence formatNick(@NonNull String hostmask) {
return formatNick(hostmask, true);
return formatNick(hostmask, context.getSettings().fullHostmask.or(false));
}
@NonNull
private CharSequence getBufferName(Message message) {
assertNotNull(client);
Buffer buffer = client.getBuffer(message.bufferInfo.id);
assertNotNull(context.getClient());
Buffer buffer = context.getClient().getBuffer(message.bufferInfo.id);
assertNotNull(buffer);
String name = buffer.getName();
assertNotNull(name);
......
......@@ -11,6 +11,7 @@ import android.view.ViewGroup;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.message.Message;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.util.observables.AutoScroller;
import de.kuschku.util.observables.callbacks.UICallback;
import de.kuschku.util.observables.callbacks.wrappers.AdapterUICallbackWrapper;
......@@ -29,18 +30,14 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
@NonNull
private final UICallback callback;
@NonNull
private IObservableList<UICallback, Message> messageList = new ObservableComparableSortedList<>(Message.class);
private IObservableList<UICallback, Message> messageList = emptyList();
public MessageAdapter(@NonNull Context ctx, @Nullable AutoScroller scroller) {
public MessageAdapter(@NonNull Context ctx, @NonNull AppContext context, @Nullable AutoScroller scroller) {
this.inflater = LayoutInflater.from(ctx);
this.renderer = new ChatMessageRenderer(ctx);
this.renderer = new ChatMessageRenderer(ctx, context);
this.callback = new AdapterUICallbackWrapper(this, scroller);
}
public void setClient(@NonNull Client client) {
renderer.setClient(client);
}
public void setMessageList(@NonNull ObservableSortedList<Message> messageList) {
this.messageList.removeCallback(callback);
this.messageList = messageList;
......@@ -66,4 +63,9 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
public int getItemCount() {
return messageList.size();
}
private static ObservableSortedList<Message> emptyList = new ObservableComparableSortedList<Message>(Message.class);
public static ObservableSortedList<Message> emptyList() {
return emptyList;
}
}
package de.kuschku.quasseldroid_ng.ui.chat.drawer;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import com.mikepenz.materialdrawer.holder.BadgeStyle;
import com.mikepenz.materialdrawer.holder.ColorHolder;
import com.mikepenz.materialdrawer.holder.ImageHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.localtypes.ChannelBuffer;
import de.kuschku.libquassel.localtypes.QueryBuffer;
import de.kuschku.libquassel.localtypes.StatusBuffer;
import de.kuschku.libquassel.message.Message;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.util.observables.IObservable;
import de.kuschku.util.observables.callbacks.GeneralCallback;
import de.kuschku.util.observables.callbacks.wrappers.GeneralCallbackWrapper;
import de.kuschku.util.observables.callbacks.wrappers.GeneralUICallbackWrapper;
import de.kuschku.util.observables.lists.ObservableComparableSortedList;
import de.kuschku.util.ui.MessageUtil;
public class BufferItem extends SecondaryDrawerItem implements IObservable<GeneralCallback>, GeneralCallback {
private final Buffer buffer;
private final AppContext context;
private final ObservableComparableSortedList<Message> notifications;
private GeneralCallbackWrapper callback = new GeneralCallbackWrapper();
public BufferItem(Buffer buffer, AppContext context) {
this.buffer = buffer;
this.context = context;
notifications = context.getClient().getNotificationManager().getNotifications(buffer.getInfo().id);
notifications.addCallback(new GeneralUICallbackWrapper() {
@Override
public void notifyChanged() {
BufferItem.this.notifyChanged();
}
});
}
public void notifyChanged() {
callback.notifyChanged();
}
@Override
public StringHolder getBadge() {
return new StringHolder(String.valueOf(notifications.size()));
}
@Override
public BadgeStyle getBadgeStyle() {
if (notifications.isEmpty()) {
return new BadgeStyle();
} else {
return new BadgeStyle().withTextColor(Color.WHITE).withColorRes(R.color.md_red_700);
}
}
@Override
public StringHolder getDescription() {
if (buffer instanceof QueryBuffer) {
QueryBuffer queryBuffer = (QueryBuffer) buffer;
if (queryBuffer.getUser() != null)
return new StringHolder(queryBuffer.getUser().getRealName());
} else if (buffer instanceof StatusBuffer) {
} else if (buffer instanceof ChannelBuffer) {
ChannelBuffer channelBuffer = (ChannelBuffer) buffer;
if (channelBuffer.getChannel() != null)
return new StringHolder(channelBuffer.getChannel().getTopic());
}
return super.getDescription();
}
@Override
public StringHolder getName() {
return new StringHolder(buffer.getName());
}
@Override
public ImageHolder getIcon() {
if (buffer instanceof ChannelBuffer) {
if (buffer.isActive()) {
return new ImageHolder(R.drawable.ic_status_channel);
} else {
return new ImageHolder(R.drawable.ic_status_channel_offline);
}
} else if (buffer instanceof StatusBuffer) {
if (buffer.isActive()) {
return new ImageHolder(R.drawable.ic_status);
} else {
return new ImageHolder(R.drawable.ic_status_offline);
}
} else {
if (buffer.isActive()) {
return new ImageHolder(R.drawable.ic_status);
} else {
return new ImageHolder(R.drawable.ic_status_offline);
}
}
}
@Override
public ColorHolder getIconColor() {
return super.getIconColor();
}
@Override
public void addCallback(GeneralCallback callback) {
this.callback.addCallback(callback);
}
@Override
public void removeCallback(GeneralCallback callback) {
this.callback.removeCallback(callback);
}
public Buffer getBuffer() {
return buffer;
}
@Override
public long getIdentifier() {
return buffer.getInfo().id;
}
@Override
public void onPostBindView(IDrawerItem drawerItem, View view) {
super.onPostBindView(drawerItem, view);
if (getDescription() != null && getDescription().getText() != null)
((TextView) view.findViewById(R.id.material_drawer_description)).setText(MessageUtil.parseStyleCodes(
context.getThemeUtil(),
getDescription().getText(),
context.getSettings().mircColors.or(true)
));
}
}
package de.kuschku.quasseldroid_ng.ui.chat.drawer;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.bignerdranch.expandablerecyclerview.ViewHolder.ChildViewHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.interfaces.Nameable;
import butterknife.Bind;
import butterknife.ButterKnife;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.util.ui.Bindable;
@UiThread
public class BufferWrapper implements Nameable<BufferWrapper> {
@NonNull
private final Buffer buffer;
public BufferWrapper(@NonNull Buffer buffer) {
this.buffer = buffer;
}
@NonNull
@Override
public BufferWrapper withName(String name) {
return this;
}
@NonNull
@Override
public BufferWrapper withName(int nameRes) {
return this;
}
@NonNull
@Override
public BufferWrapper withName(StringHolder name) {
return this;
}
@NonNull
@Override
public StringHolder getName() {
return new StringHolder(buffer.getName());
}
@NonNull
public Buffer getBuffer() {
return buffer;
}
public static class ViewHolder extends ChildViewHolder implements Bindable<BufferWrapper> {
@Bind(R.id.material_drawer_icon)
ImageView materialDrawerIcon;
@Bind(R.id.material_drawer_name)
TextView materialDrawerName;
@Bind(R.id.material_drawer_description)
TextView materialDrawerDescription;
@Bind(R.id.material_drawer_badge_container)
View materialDrawerBadgeContainer;
@Bind(R.id.material_drawer_badge)
TextView materialDrawerBadge;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(@NonNull BufferWrapper wrapper) {
materialDrawerName.setText(wrapper.getName().getText());
}
}
}
package de.kuschku.quasseldroid_ng.ui.chat.drawer;
import android.content.Context;
import android.util.Log;
import android.util.SparseArray;
import android.view.View;
import android.widget.TextView;
import com.mikepenz.fastadapter.utils.ViewHolderFactory;
import com.mikepenz.materialdrawer.holder.ColorHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.BaseViewHolder;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
import java.util.ArrayList;
import java.util.List;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.syncables.types.BufferViewConfig;
import de.kuschku.libquassel.syncables.types.Network;
import de.kuschku.quasseldroid_ng.ui.AppContext;
import de.kuschku.util.AndroidAssert;
import de.kuschku.util.observables.IObservable;
import de.kuschku.util.observables.callbacks.ElementCallback;
import de.kuschku.util.observables.callbacks.GeneralCallback;
import de.kuschku.util.observables.callbacks.wrappers.GeneralCallbackWrapper;
import de.kuschku.util.observables.lists.ObservableSortedList;
import static de.kuschku.util.AndroidAssert.*;
public class NetworkItem extends PrimaryDrawerItem implements IObservable<GeneralCallback>, GeneralCallback {
private final AppContext context;
private final Network network;
private final BufferViewConfig config;
private final ObservableSortedList<BufferItem> buffers = new ObservableSortedList<>(BufferItem.class, new AlphabeticalComparator());
private final SparseArray<BufferItem> bufferIds = new SparseArray<>();
private final GeneralCallbackWrapper callback = new GeneralCallbackWrapper();
public NetworkItem(AppContext context, Network network, BufferViewConfig config) {
this.context = context;
this.network = network;
this.config = config;
for (Integer bufferId : this.config.getBufferList()) {
Buffer buffer = context.getClient().getBuffer(bufferId);
if (buffer != null && buffer.getInfo().networkId == network.getNetworkId()) {
this.buffers.add(new BufferItem(buffer, context));
Log.e("Drawer", "Buffer can not be null! BufferId: "+ bufferId);
}
}
this.config.getBufferList().addCallback(new ElementCallback<Integer>() {
@Override
public void notifyItemInserted(Integer element) {
if (network.getBuffers().contains(element)) {
if (bufferIds.get(element) == null) {
Buffer buffer = context.getClient().getBuffer(element);
BufferItem bufferItem = new BufferItem(buffer, context);
buffers.add(bufferItem);
bufferItem.addCallback(NetworkItem.this);
bufferIds.put(element, bufferItem);
notifyChanged();
}
}
}
@Override
public void notifyItemRemoved(Integer element) {
if (bufferIds.get(element) != null) {
bufferIds.remove(element);
notifyChanged();
}
}
@Override
public void notifyItemChanged(Integer element) {
if (bufferIds.get(element) != null) {
notifyChanged();
}
}
});
}
@Override
public boolean isIconTinted() {
return super.isIconTinted();
}
@Override
public ColorHolder getIconColor() {
return super.getIconColor();
}
@Override
public StringHolder getDescription() {
return new StringHolder(String.valueOf(network.getLatency()));
}
@Override
public StringHolder getName() {
return new StringHolder(network.getNetworkName());
}
@Override
public List<IDrawerItem> getSubItems() {
ArrayList<IDrawerItem> items = new ArrayList<>();
for (IDrawerItem item : buffers) {
items.add(item);
}
return items;
}
@Override
public void notifyChanged() {
this.callback.notifyChanged();
}
@Override
public void addCallback(GeneralCallback callback) {
this.callback.addCallback(callback);
}
@Override
public void removeCallback(GeneralCallback callback) {
this.callback.removeCallback(callback);
}
public Network getNetwork() {
return network;
}
@Override
public long getIdentifier() {
return network.getNetworkId();
}
class AlphabeticalComparator implements ObservableSortedList.ItemComparator<BufferItem> {
@Override
public int compare(BufferItem o1, BufferItem o2) {
return o1.getName().getText().compareTo(o2.getName().getText());
}
@Override
public boolean areContentsTheSame(BufferItem oldItem, BufferItem newItem) {
return oldItem.getBuffer().getInfo().id == newItem.getBuffer().getInfo().id;
}
@Override
public boolean areItemsTheSame(BufferItem item1, BufferItem item2) {
return item1 == item2;
}
}
class NoneComparator implements ObservableSortedList.ItemComparator<BufferItem> {
@Override
public int compare(BufferItem o1, BufferItem o2) {
return o1.getBuffer().getInfo().id - o2.getBuffer().getInfo().id;
}
@Override
public boolean areContentsTheSame(BufferItem oldItem, BufferItem newItem) {
return oldItem.getBuffer().getInfo().id == newItem.getBuffer().getInfo().id;
}
@Override
public boolean areItemsTheSame(BufferItem item1, BufferItem item2) {
return item1 == item2;
}
}
}
package de.kuschku.quasseldroid_ng.ui.chat.drawer;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.bignerdranch.expandablerecyclerview.Model.ParentListItem;
import com.bignerdranch.expandablerecyclerview.ViewHolder.ParentViewHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.interfaces.Nameable;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import de.kuschku.libquassel.Client;
import de.kuschku.libquassel.localtypes.Buffer;
import de.kuschku.libquassel.message.Message;
import de.kuschku.libquassel.syncables.types.BufferViewConfig;
import de.kuschku.libquassel.syncables.types.Network;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.util.observables.ContentComparable;
import de.kuschku.util.observables.callbacks.ElementCallback;
import de.kuschku.util.observables.callbacks.UIChildCallback;
import de.kuschku.util.observables.callbacks.wrappers.ChildUICallbackWrapper;
import de.kuschku.util.observables.callbacks.wrappers.MultiUIChildCallback;
import de.kuschku.util.observables.lists.ObservableSortedList;
import de.kuschku.util.ui.Bindable;
@UiThread
public class NetworkWrapper implements ParentListItem, Nameable<NetworkWrapper>, ContentComparable<NetworkWrapper> {
@NonNull
private final MultiUIChildCallback callback = MultiUIChildCallback.of();
@NonNull
private final Network network;
@NonNull
private final Client client;
@NonNull
private final ChildUICallbackWrapper wrapper = new ChildUICallbackWrapper(callback);
@NonNull
private ObservableSortedList<BufferWrapper> buffers = new ObservableSortedList<>(BufferWrapper.class, new BufferWrapperSorterWrapper(getSorter(SortMode.NONE)));
private int groupId;
public NetworkWrapper(@NonNull Network network, @NonNull Client client, @NonNull BufferViewConfig bufferViewConfig, @NonNull SortMode sortMode, int groupId) {
this.network = network;
this.client = client;
setSortMode(sortMode);
bufferViewConfig.getBufferList().addCallback(new ElementCallback<Integer>() {
@Override
public void notifyItemInserted(Integer element) {
Buffer buffer = client.getBuffer(element);
if (buffer.getInfo().networkId != network.getNetworkId()) return;
buffers.add(new BufferWrapper(buffer));
}
@Override
public void notifyItemRemoved(Integer element) {
Buffer buffer = client.getBuffer(element);
if (buffer.getInfo().networkId != network.getNetworkId()) return;
buffers.remove(new BufferWrapper(buffer));
}
@Override
public void notifyItemChanged(Integer element) {
Buffer buffer = client.getBuffer(element);
if (buffer.getInfo().networkId != network.getNetworkId()) return;
callback.notifyChildItemChanged(groupId, buffers.indexOf(new BufferWrapper(buffer)));
}
});
buffers.addCallback(wrapper);
wrapper.setGroupPosition(groupId);
}
public void addCallback(@NonNull UIChildCallback callback) {
this.callback.addCallback(callback);
}
public void removeCallback(@NonNull UIChildCallback callback) {
this.callback.removeCallback(callback);
}
public void setGroupId(int groupId) {
this.groupId = groupId;
this.wrapper.setGroupPosition(groupId);
}
public void setSortMode(@NonNull SortMode sortMode) {
ObservableSortedList.ItemComparator<BufferWrapper> sorter = new BufferWrapperSorterWrapper(getSorter(sortMode));
ObservableSortedList<BufferWrapper> newBuffers = new ObservableSortedList<>(BufferWrapper.class, sorter);
if (buffers.size() > newBuffers.size()) {
for (int i = newBuffers.size(); i < buffers.size(); i++) {
callback.notifyChildItemRemoved(groupId, i);
}
} else if (newBuffers.size() > buffers.size()) {
for (int i = buffers.size(); i < newBuffers.size(); i++) {
callback.notifyChildItemInserted(groupId, i);
}
}
int commonElementCount = Math.min(buffers.size(), newBuffers.size());
for (int i = 0; i < commonElementCount; i++) {
callback.notifyChildItemChanged(groupId, i);
}
buffers = newBuffers;
}
@NonNull
private ObservableSortedList.ItemComparator<Buffer> getSorter(@NonNull SortMode sortMode) {
switch (sortMode) {
case ALPHABETICAL:
return new AlphabeticalBufferSorter();
case RECENT_ACTIVITY:
return new RecentActivityBufferSorter();
case LAST_SEEN:
return new LastSeenBufferSorter();
default:
return new IdBufferSorter();
}
}
@NonNull
@Override
public List<?> getChildItemList() {
return buffers;
}
@Override
public boolean isInitiallyExpanded() {
return network.isConnected();
}
@NonNull
@Override
public NetworkWrapper withName(String name) {
return this;
}
@NonNull
@Override
public NetworkWrapper withName(int nameRes) {
return this;
}
@NonNull
@Override
public NetworkWrapper withName(StringHolder name) {
return this;
}
@NonNull
@Override
public StringHolder getName() {
return new StringHolder(network.getNetworkName());
}
@Override
public boolean equalsContent(@NonNull NetworkWrapper other) {
return network.equalsContent(other.network);
}
@Override
public int compareTo(@NonNull NetworkWrapper another) {
return network.compareTo(another.network);
}
public enum SortMode {
NONE,
ALPHABETICAL,
RECENT_ACTIVITY,
LAST_SEEN
}
public static class ViewHolder extends ParentViewHolder implements Bindable<NetworkWrapper> {
@Bind(R.id.material_drawer_icon)
ImageView materialDrawerIcon;
@Bind(R.id.material_drawer_name)
TextView materialDrawerName;
@Bind(R.id.material_drawer_description)
TextView materialDrawerDescription;
@Bind(R.id.material_drawer_badge_container)
View materialDrawerBadgeContainer;
@Bind(R.id.material_drawer_badge)
TextView materialDrawerBadge;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
public void bind(@NonNull NetworkWrapper wrapper) {
materialDrawerName.setText(wrapper.getName().getText());
}
}
private static class BufferWrapperSorterWrapper implements ObservableSortedList.ItemComparator<BufferWrapper> {
@NonNull
private final ObservableSortedList.ItemComparator<Buffer> wrapped;
public BufferWrapperSorterWrapper(@NonNull ObservableSortedList.ItemComparator<Buffer> wrapped) {
this.wrapped = wrapped;
}
@Override
public int compare(@NonNull BufferWrapper lhs, @NonNull BufferWrapper rhs) {
return wrapped.compare(lhs.getBuffer(), rhs.getBuffer());
}
@Override
public boolean areContentsTheSame(@NonNull BufferWrapper oldItem, @NonNull BufferWrapper newItem) {
return wrapped.areContentsTheSame(oldItem.getBuffer(), newItem.getBuffer());
}
@Override
public boolean areItemsTheSame(@NonNull BufferWrapper item1, @NonNull BufferWrapper item2) {
return areContentsTheSame(item1, item2);
}
}
private class IdBufferSorter extends BasicBufferSorter {
@Override
public int compare(@NonNull Buffer lhs, @NonNull Buffer rhs) {
return lhs.getInfo().id - rhs.getInfo().id;
}
}
private class AlphabeticalBufferSorter extends BasicBufferSorter {
@Override
public int compare(@NonNull Buffer lhs, @NonNull Buffer rhs) {
return lhs.getName().compareTo(rhs.getName());
}
}
private class RecentActivityBufferSorter extends BasicBufferSorter {
@Override
public int compare(@NonNull Buffer lhs, @NonNull Buffer rhs) {
return getLastMessageId(lhs) - getLastMessageId(rhs);
}
private int getLastMessageId(@NonNull Buffer buffer) {
int bufferId = buffer.getInfo().id;
Message message = client.getBacklogManager().get(bufferId).last();
return message == null ? -1 : message.messageId;
}
}
private class LastSeenBufferSorter extends BasicBufferSorter {
@Override
public int compare(@NonNull Buffer lhs, @NonNull Buffer rhs) {
return getLastSeenMessageId(lhs) - getLastSeenMessageId(rhs);
}
private int getLastSeenMessageId(@NonNull Buffer buffer) {
int bufferId = buffer.getInfo().id;
return client.getBufferSyncer().getLastSeenMsg(bufferId);
}
}
private abstract class BasicBufferSorter implements ObservableSortedList.ItemComparator<Buffer> {
@Override
public boolean areContentsTheSame(@NonNull Buffer oldItem, @NonNull Buffer newItem) {
return oldItem.getInfo().id == newItem.getInfo().id;
}
@Override
public boolean areItemsTheSame(@NonNull Buffer item1, @NonNull Buffer item2) {
return areContentsTheSame(item1, item2);
}
}
}
package de.kuschku.util;
import android.support.annotation.Nullable;
import android.support.design.BuildConfig;
import junit.framework.Assert;
import de.kuschku.quasseldroid_ng.BuildConfig;
/**
* Class to provide the Assert functionality of JUnit at runtime for debug builds
*/
......@@ -13,6 +14,12 @@ public class AndroidAssert extends Assert {
private AndroidAssert() {
}
public static void assertTrue(Throwable message, boolean condition) {
if (BuildConfig.DEBUG) {
if (!condition) fail(message);
}
}
public static void assertTrue(String message, boolean condition) {
if (BuildConfig.DEBUG) {
if (!condition) fail(message);
......@@ -25,13 +32,9 @@ public class AndroidAssert extends Assert {
}
}
public static void assertTrueOrNotNull(boolean condition, @Nullable Object... nonNull) {
public static void assertFalse(Throwable message, boolean condition) {
if (BuildConfig.DEBUG) {
if (condition) return;
if (nonNull == null) fail();
for (Object o : nonNull) {
if (o == null) fail();
}
if (condition) fail(message);
}
}
......@@ -47,6 +50,12 @@ public class AndroidAssert extends Assert {
}
}
public static void fail(Throwable message) {
if (BuildConfig.DEBUG) {
throw new RuntimeException(message);
}
}
public static void fail(String message) {
if (BuildConfig.DEBUG) {
throw new AssertionError(message);
......@@ -59,6 +68,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -71,6 +86,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, String expected, String actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, String expected, String actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -83,6 +104,13 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, double expected, double actual, double delta) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, double expected, double actual, double delta) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -95,6 +123,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, float expected, float actual, float delta) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, float expected, float actual, float delta) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -107,6 +141,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, long expected, long actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, long expected, long actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -119,6 +159,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, boolean expected, boolean actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, boolean expected, boolean actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -131,6 +177,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, byte expected, byte actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, byte expected, byte actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -143,6 +195,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, char expected, char actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, char expected, char actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -155,6 +213,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, short expected, short actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, short expected, short actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -167,6 +231,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertEquals(Throwable message, int expected, int actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
}
}
public static void assertEquals(String message, int expected, int actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, Objects.equals(expected, actual));
......@@ -191,6 +261,12 @@ public class AndroidAssert extends Assert {
}
}
public static void assertNotNull(Throwable message, @Nullable Object object) {
if (BuildConfig.DEBUG) {
assertTrue(message, object != null);
}
}
public static void assertNull(@Nullable Object object) {
if (BuildConfig.DEBUG) {
assertTrue(object == null);
......@@ -203,18 +279,37 @@ public class AndroidAssert extends Assert {
}
}
public static void assertNull(Throwable message, @Nullable Object object) {
if (BuildConfig.DEBUG) {
assertTrue(message, object == null);
}
}
public static void assertSame(String message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, expected == actual);
}
}
public static void assertSame(Throwable message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, expected == actual);
}
}
public static void assertSame(Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(expected == actual);
}
}
public static void assertNotSame(Throwable message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, expected != actual);
}
}
public static void assertNotSame(String message, Object expected, Object actual) {
if (BuildConfig.DEBUG) {
assertTrue(message, expected != actual);
......@@ -244,4 +339,16 @@ public class AndroidAssert extends Assert {
assertEquals(message, expected, actual);
}
}
public static void assertEquals(int... elements) {
if (BuildConfig.DEBUG) {
if (elements.length > 0) {
int first = elements[0];
for (int i = 1; i < elements.length; i++) {
if (first != elements[i])
fail();
}
}
}
}
}
package de.kuschku.util;
import android.app.Activity;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.annotation.UiThread;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import de.kuschku.quasseldroid_ng.R;
import de.kuschku.util.ui.MaterialActionBarDrawerToggle;
public class DrawerUtils {
@UiThread
public static void initDrawer(@NonNull Activity actvity, @NonNull DrawerLayout layout, Toolbar toolbar, @StringRes int open_res, @StringRes int close_res) {
ActionBarDrawerToggle actionBarDrawerToggle = new MaterialActionBarDrawerToggle(actvity, layout, toolbar, open_res, close_res);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
actvity.getWindow().setStatusBarColor(actvity.getResources().getColor(android.R.color.transparent));
layout.setStatusBarBackground(R.color.colorPrimaryDark);
}
layout.setDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
}
}
......@@ -2,6 +2,7 @@ package de.kuschku.util;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.google.common.primitives.Primitives;
......@@ -32,7 +33,8 @@ public class ReflectionUtils {
Class<?>[] classes = new Class<?>[argv.length];
for (int i = 0; i < argv.length; i++) {
classes[i] = argv[i].getClass();
if (argv[i] == null) classes[i] = null;
else classes[i] = argv[i].getClass();
}
Method m = getMethodFromSignature(name, o.getClass(), classes);
if (m == null)
......@@ -41,6 +43,7 @@ public class ReflectionUtils {
try {
m.invoke(o, argv);
} catch (Exception e) {
Log.e("DEBUG", m.toString());
throw new SyncInvocationException(e, String.format("Error invoking %s::%s with arguments %s and classes %s", o.getClass().getSimpleName(), name, Arrays.toString(argv), Arrays.toString(classes)));
}
}
......@@ -68,6 +71,10 @@ public class ReflectionUtils {
for (int i = 0; i < parameterTypes.length; i++) {
Class<?> mParam = m.getParameterTypes()[i];
Class<?> vParam = parameterTypes[i];
// Can’t check type of null values, so we’ll assume it will work
if (vParam == null) continue;
assertNotNull(vParam);
if (mParam.isPrimitive() && Primitives.isWrapperType(vParam))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment