diff --git a/app/src/main/java/de/kuschku/libquassel/Client.java b/app/src/main/java/de/kuschku/libquassel/Client.java index 5d01acbcfe66b425263fa4d3fbf9a76c0f6e8502..70bb59b03ef6ef3dd2e09ffe2c173675e2058cf5 100644 --- a/app/src/main/java/de/kuschku/libquassel/Client.java +++ b/app/src/main/java/de/kuschku/libquassel/Client.java @@ -23,6 +23,8 @@ import de.kuschku.libquassel.syncables.types.BufferSyncer; import de.kuschku.libquassel.syncables.types.BufferViewManager; import de.kuschku.libquassel.syncables.types.Network; import de.kuschku.libquassel.syncables.types.SyncableObject; +import de.kuschku.util.backports.Optional; +import de.kuschku.util.backports.Optionals; import de.kuschku.util.backports.Stream; @@ -101,7 +103,13 @@ public class Client { } public void __objectRenamed__(String className, String newName, String oldName) { - getObjectByIdentifier(className, oldName).renameObject(newName); + safeGetObjectByIdentifier(className, oldName).renameObject(newName); + } + + private SyncableObject safeGetObjectByIdentifier(String className, String oldName) { + SyncableObject val = getObjectByIdentifier(className, oldName); + if (val == null) throw new IllegalArgumentException(String.format("Object %s::%s does not exist", className, oldName)); + else return val; } public SyncableObject getObjectByIdentifier(final String className, final String objectName) { diff --git a/app/src/main/java/de/kuschku/libquassel/CoreConnection.java b/app/src/main/java/de/kuschku/libquassel/CoreConnection.java index 0a4970bf0e0c6500b2d353083532776a3191e54e..3db6d26a0a3cf87f56c589708f3d88c6aa724760 100644 --- a/app/src/main/java/de/kuschku/libquassel/CoreConnection.java +++ b/app/src/main/java/de/kuschku/libquassel/CoreConnection.java @@ -1,6 +1,8 @@ package de.kuschku.libquassel; +import android.util.Log; + import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; @@ -15,6 +17,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import de.kuschku.libquassel.events.ConnectionChangeEvent; +import de.kuschku.libquassel.events.GeneralErrorEvent; import de.kuschku.libquassel.events.HandshakeFailedEvent; import de.kuschku.libquassel.functions.types.HandshakeFunction; import de.kuschku.libquassel.objects.types.ClientInit; @@ -175,7 +178,7 @@ public class CoreConnection { final ByteBuffer buffer = ByteBuffer.allocate(4); getChannel().read(buffer); - final Protocol protocol = new ProtocolSerializer().deserialize(buffer); + final Protocol protocol = ProtocolSerializer.get().deserialize(buffer); // Wrap socket in deflater if compression is enabled setCompression(protocol.protocolFlags.supportsCompression); @@ -210,9 +213,9 @@ public class CoreConnection { } } } catch (SocketException e) { - Logger.getLogger("libquassel").log(Level.FINEST, "Socket closed while reading"); - } catch (IOException e) { - e.printStackTrace(); + Log.e("libquassel", "Socket closed while reading"); + } catch (Exception e) { + busProvider.sendEvent(new GeneralErrorEvent(e)); } } } diff --git a/app/src/main/java/de/kuschku/libquassel/backlogmanagers/BacklogManager.java b/app/src/main/java/de/kuschku/libquassel/backlogmanagers/BacklogManager.java index 7cd7ad5b16aafb5acbc62b8fde619063b9e6deb7..17eb85768c3a71954055f471c54cb30296297876 100644 --- a/app/src/main/java/de/kuschku/libquassel/backlogmanagers/BacklogManager.java +++ b/app/src/main/java/de/kuschku/libquassel/backlogmanagers/BacklogManager.java @@ -7,7 +7,8 @@ import java.util.List; import de.kuschku.libquassel.message.Message; import de.kuschku.libquassel.syncables.types.SyncableObject; -import de.kuschku.util.ObservableList; +import de.kuschku.util.observablelists.AutoScroller; +import de.kuschku.util.observablelists.ObservableSortedList; public abstract class BacklogManager extends SyncableObject { public abstract void requestBacklog(int bufferId, int from, int to, int count, int extra); @@ -16,9 +17,9 @@ public abstract class BacklogManager extends SyncableObject { public abstract void displayMessage(int bufferId, Message message); - public abstract ObservableList<Message> get(int bufferId); + public abstract ObservableSortedList<Message> get(int bufferId); - public abstract void bind(int bufferId, @Nullable RecyclerView.Adapter adapter); + public abstract void bind(int bufferId, @Nullable RecyclerView.Adapter adapter, AutoScroller scroller); public abstract void requestMoreBacklog(int bufferId, int count); } diff --git a/app/src/main/java/de/kuschku/libquassel/backlogmanagers/SimpleBacklogManager.java b/app/src/main/java/de/kuschku/libquassel/backlogmanagers/SimpleBacklogManager.java index 1a1d85eadf83bbd19728c8ed4d5855bc3477f109..0360f62bf287d7751a73954aa5c5650936036709 100644 --- a/app/src/main/java/de/kuschku/libquassel/backlogmanagers/SimpleBacklogManager.java +++ b/app/src/main/java/de/kuschku/libquassel/backlogmanagers/SimpleBacklogManager.java @@ -15,10 +15,12 @@ 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 de.kuschku.util.ObservableList; +import de.kuschku.util.observablelists.AutoScroller; +import de.kuschku.util.observablelists.ObservableSortedList; +import de.kuschku.util.observablelists.RecyclerViewAdapterCallback; public class SimpleBacklogManager extends BacklogManager { - SparseArray<ObservableList<Message>> backlogs = new SparseArray<>(); + SparseArray<ObservableSortedList<Message>> backlogs = new SparseArray<>(); private BusProvider busProvider; public SimpleBacklogManager(BusProvider busProvider) { @@ -46,27 +48,27 @@ public class SimpleBacklogManager extends BacklogManager { get(bufferId).list.add(message); } - public void bind(int bufferId, @Nullable RecyclerView.Adapter adapter) { + public void bind(int bufferId, @Nullable RecyclerView.Adapter adapter, AutoScroller scroller) { if (adapter == null) get(bufferId).setCallback(null); else - get(bufferId).setCallback(new ObservableList.RecyclerViewAdapterCallback(adapter)); + get(bufferId).setCallback(new RecyclerViewAdapterCallback(adapter, scroller)); } @Override public void requestMoreBacklog(int bufferId, int count) { - ObservableList<Message> backlog = backlogs.get(bufferId); + ObservableSortedList<Message> backlog = backlogs.get(bufferId); int messageId = (backlog == null) ? -1 : - (backlog.first() == null) ? -1 : - backlog.first().messageId; + (backlog.last() == null) ? -1 : + backlog.last().messageId; requestBacklog(bufferId, -1, messageId, count, 0); } - public ObservableList<Message> get(int bufferId) { + public ObservableSortedList<Message> get(int bufferId) { if (backlogs.get(bufferId) == null) - backlogs.put(bufferId, new ObservableList<>(Message.class)); + backlogs.put(bufferId, new ObservableSortedList<>(Message.class, true)); return backlogs.get(bufferId); } diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitDataFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitDataFunctionSerializer.java index 8d6ec1380d0bcc777009960d178a377adadeb495..4170ce6058c635045585e8cba54bd07938bd4362 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitDataFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitDataFunctionSerializer.java @@ -7,12 +7,21 @@ import de.kuschku.libquassel.functions.types.PackedInitDataFunction; import de.kuschku.libquassel.functions.types.UnpackedInitDataFunction; public class InitDataFunctionSerializer implements FunctionSerializer<InitDataFunction> { + private static final InitDataFunctionSerializer serializer = new InitDataFunctionSerializer(); + + private InitDataFunctionSerializer() { + } + + public static InitDataFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final InitDataFunction data) { if (data instanceof UnpackedInitDataFunction) { - return new PackedInitDataFunctionSerializer().serialize((UnpackedInitDataFunction) data); + return PackedInitDataFunctionSerializer.get().serialize((UnpackedInitDataFunction) data); } else if (data instanceof PackedInitDataFunction) { - return new UnpackedInitDataFunctionSerializer().serialize((PackedInitDataFunction) data); + return UnpackedInitDataFunctionSerializer.get().serialize((PackedInitDataFunction) data); } else { throw new IllegalArgumentException("Can not be applied to these arguments"); } diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitRequestFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitRequestFunctionSerializer.java index cdf3e32b61d6d05738fd6a020bb55031d680bee2..bfde1a1f56dc0c14705dc9285fe21ab404cb3723 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitRequestFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/InitRequestFunctionSerializer.java @@ -11,6 +11,15 @@ import de.kuschku.libquassel.primitives.types.QVariant; import static de.kuschku.libquassel.primitives.QMetaType.Type.QByteArray; public class InitRequestFunctionSerializer implements FunctionSerializer<InitRequestFunction> { + private static final InitRequestFunctionSerializer serializer = new InitRequestFunctionSerializer(); + + private InitRequestFunctionSerializer() { + } + + public static InitRequestFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final InitRequestFunction data) { return Lists.newArrayList( diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedInitDataFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedInitDataFunctionSerializer.java index 540466fba4c85d5d2d9dccf430ce82d30461c8cf..3584efc5ff7a8f1d4f85d7c2157ffad6358aff02 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedInitDataFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedInitDataFunctionSerializer.java @@ -9,6 +9,15 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.protocols.DatastreamPeer; public class PackedInitDataFunctionSerializer implements FunctionSerializer<UnpackedInitDataFunction> { + private static final PackedInitDataFunctionSerializer serializer = new PackedInitDataFunctionSerializer(); + + private PackedInitDataFunctionSerializer() { + } + + public static PackedInitDataFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final UnpackedInitDataFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedRpcCallFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedRpcCallFunctionSerializer.java index 3ff34ceaadd3f5c6acf0fe5ff9c16b9d5994ef41..9bbb06d103e9f46d10bdd88e47bb164ec037fddf 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedRpcCallFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedRpcCallFunctionSerializer.java @@ -10,6 +10,15 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.protocols.DatastreamPeer; public class PackedRpcCallFunctionSerializer implements FunctionSerializer<RpcCallFunction> { + private static final PackedRpcCallFunctionSerializer serializer = new PackedRpcCallFunctionSerializer(); + + private PackedRpcCallFunctionSerializer() { + } + + public static PackedRpcCallFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final RpcCallFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedSyncFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedSyncFunctionSerializer.java index 2a5878c8d392be7a51df7026b396713250023d8f..a76a559f0b01c67bb60836ce23bbaef6ee5c7120 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedSyncFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/PackedSyncFunctionSerializer.java @@ -10,6 +10,15 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.protocols.DatastreamPeer; public class PackedSyncFunctionSerializer implements FunctionSerializer<SyncFunction> { + private static final PackedSyncFunctionSerializer serializer = new PackedSyncFunctionSerializer(); + + private PackedSyncFunctionSerializer() { + } + + public static PackedSyncFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final SyncFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedInitDataFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedInitDataFunctionSerializer.java index 5de08d549b9cbe80991d99c4583625fe39f55c0b..601dcb67ebe7c6a15718cd7bd0de5a13ad09aeb2 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedInitDataFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedInitDataFunctionSerializer.java @@ -9,6 +9,15 @@ import de.kuschku.libquassel.functions.types.PackedInitDataFunction; import de.kuschku.libquassel.primitives.types.QVariant; public class UnpackedInitDataFunctionSerializer implements FunctionSerializer<PackedInitDataFunction> { + private static final UnpackedInitDataFunctionSerializer serializer = new UnpackedInitDataFunctionSerializer(); + + private UnpackedInitDataFunctionSerializer() { + } + + public static UnpackedInitDataFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final PackedInitDataFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedRpcCallFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedRpcCallFunctionSerializer.java index 6c492926576b33c63e73eba9f444f69557af532e..ab09225054386969759fe221fe12760a2a418aac 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedRpcCallFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedRpcCallFunctionSerializer.java @@ -9,6 +9,15 @@ import de.kuschku.libquassel.primitives.QMetaType; import de.kuschku.libquassel.primitives.types.QVariant; public class UnpackedRpcCallFunctionSerializer implements FunctionSerializer<RpcCallFunction> { + private static final UnpackedRpcCallFunctionSerializer serializer = new UnpackedRpcCallFunctionSerializer(); + + private UnpackedRpcCallFunctionSerializer() { + } + + public static UnpackedRpcCallFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final RpcCallFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedSyncFunctionSerializer.java b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedSyncFunctionSerializer.java index 920cd379184e7dee32e6dbe789378819109faf9c..f77e189c9275028b0e536240222ed44edb875a34 100644 --- a/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedSyncFunctionSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/functions/serializers/UnpackedSyncFunctionSerializer.java @@ -9,6 +9,15 @@ import de.kuschku.libquassel.primitives.QMetaType; import de.kuschku.libquassel.primitives.types.QVariant; public class UnpackedSyncFunctionSerializer implements FunctionSerializer<SyncFunction> { + private static final UnpackedSyncFunctionSerializer serializer = new UnpackedSyncFunctionSerializer(); + + private UnpackedSyncFunctionSerializer() { + } + + public static UnpackedSyncFunctionSerializer get() { + return serializer; + } + @Override public List serialize(final SyncFunction data) { final List func = new ArrayList<>(); diff --git a/app/src/main/java/de/kuschku/libquassel/message/Message.java b/app/src/main/java/de/kuschku/libquassel/message/Message.java index b3a80ef6c48b7042145d3e46300167d69993ad21..e222d3b78fb13c97e8e19144345e216f1b7516ed 100644 --- a/app/src/main/java/de/kuschku/libquassel/message/Message.java +++ b/app/src/main/java/de/kuschku/libquassel/message/Message.java @@ -8,7 +8,7 @@ import java.io.Serializable; import java.util.Comparator; import de.kuschku.libquassel.primitives.types.BufferInfo; -import de.kuschku.util.ContentComparable; +import de.kuschku.util.observablelists.ContentComparable; public class Message implements ContentComparable<Message> { public final int messageId; diff --git a/app/src/main/java/de/kuschku/libquassel/objects/MessageTypeRegistry.java b/app/src/main/java/de/kuschku/libquassel/objects/MessageTypeRegistry.java index 3b7cc16dd1e229d016fc35f788c21aafcc6389a6..38e34a81708cb69f4b03291f7ef05e6bd68b4781 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/MessageTypeRegistry.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/MessageTypeRegistry.java @@ -20,16 +20,16 @@ public class MessageTypeRegistry { private static Map<String, ObjectSerializer> serializerMap = new HashMap<String, ObjectSerializer>(); static { - serializerMap.put("ClientInit", new ClientInitSerializer()); - serializerMap.put("ClientInitAck", new ClientInitAckSerializer()); - serializerMap.put("ClientInitReject", new ClientInitRejectSerializer()); - serializerMap.put("ClientLogin", new ClientLoginSerializer()); - serializerMap.put("ClientLoginAck", new ClientLoginAckSerializer()); - serializerMap.put("ClientLoginReject", new ClientLoginRejectSerializer()); - serializerMap.put("CoreSetupData", new CoreSetupDataSerializer()); - serializerMap.put("CoreSetupAck", new CoreSetupAckSerializer()); - serializerMap.put("CoreSetupReject", new CoreSetupRejectSerializer()); - serializerMap.put("SessionInit", new SessionInitSerializer()); + serializerMap.put("ClientInit", ClientInitSerializer.get()); + serializerMap.put("ClientInitAck", ClientInitAckSerializer.get()); + serializerMap.put("ClientInitReject", ClientInitRejectSerializer.get()); + serializerMap.put("ClientLogin", ClientLoginSerializer.get()); + serializerMap.put("ClientLoginAck", ClientLoginAckSerializer.get()); + serializerMap.put("ClientLoginReject", ClientLoginRejectSerializer.get()); + serializerMap.put("CoreSetupData", CoreSetupDataSerializer.get()); + serializerMap.put("CoreSetupAck", CoreSetupAckSerializer.get()); + serializerMap.put("CoreSetupReject", CoreSetupRejectSerializer.get()); + serializerMap.put("SessionInit", SessionInitSerializer.get()); } // Disable Constructor diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitAckSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitAckSerializer.java index ca0e2e7c2d1206ad2e60d82a53db20fc576a3160..dd5d31eade9a08bdf565471078251a953d8ae841 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitAckSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitAckSerializer.java @@ -15,15 +15,24 @@ import de.kuschku.libquassel.objects.types.StorageBackend; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientInitAckSerializer implements ObjectSerializer<ClientInitAck> { + private static ClientInitAckSerializer serializer = new ClientInitAckSerializer(); + + private ClientInitAckSerializer() { + } + + public static ClientInitAckSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientInitAck data) { final List<Map<String, QVariant>> storageBackends = new ArrayList<>(); - final StorageBackendSerializer storageBackendSerializer = new StorageBackendSerializer(); + final StorageBackendSerializer storageBackendSerializer = StorageBackendSerializer.get(); for (StorageBackend backend : data.StorageBackends) { storageBackends.add((Map<String, QVariant>) storageBackendSerializer.toVariantMap(backend)); } - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("Configured", new QVariant<>(data.Configured)); map.data.put("LoginEnabled", new QVariant<>(data.LoginEnabled)); map.data.put("StorageBackends", new QVariant<>(storageBackends)); @@ -40,7 +49,7 @@ public class ClientInitAckSerializer implements ObjectSerializer<ClientInitAck> public ClientInitAck fromLegacy(Map<String, QVariant> map) { final List<StorageBackend> storageBackends = new ArrayList<StorageBackend>(); if (map.containsKey("StorageBackends")) { - final StorageBackendSerializer storageBackendSerializer = new StorageBackendSerializer(); + final StorageBackendSerializer storageBackendSerializer = StorageBackendSerializer.get(); for (Map<String, QVariant> backend : (List<Map<String, QVariant>>) map.get("StorageBackends").data) { storageBackends.add(storageBackendSerializer.fromLegacy(backend)); } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitRejectSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitRejectSerializer.java index ec20c44a5faa7f9343a74938fbc994f109fd0b02..d026936649994cc34c322577b2969a4402b872b2 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitRejectSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitRejectSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.ClientInitReject; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientInitRejectSerializer implements ObjectSerializer<ClientInitReject> { + private static final ClientInitRejectSerializer serializer = new ClientInitRejectSerializer(); + + private ClientInitRejectSerializer() { + } + + public static ClientInitRejectSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientInitReject data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("Error", new QVariant<>(data.Error)); return map; } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitSerializer.java index 6f48f7e59ced601383af4c55e41c9cafbaab7d15..24dd5178251182ac2545a176d3b726d660490563 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientInitSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.ClientInit; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientInitSerializer implements ObjectSerializer<ClientInit> { + private static final ClientInitSerializer serializer = new ClientInitSerializer(); + + private ClientInitSerializer() { + } + + public static ClientInitSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientInit data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("ClientDate", new QVariant<>(data.ClientDate)); map.data.put("UseSsl", new QVariant<>(data.UseSsl)); map.data.put("ClientVersion", new QVariant<>(data.ClientVersion)); diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginAckSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginAckSerializer.java index ab877f95435f8580c98e1e3944f1de5e7a62ceac..f8bbcde710a861e6cd58d9bdef13eacd3eb5e547 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginAckSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginAckSerializer.java @@ -10,10 +10,18 @@ import de.kuschku.libquassel.objects.types.ClientLoginAck; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientLoginAckSerializer implements ObjectSerializer<ClientLoginAck> { + private static final ClientLoginAckSerializer serializer = new ClientLoginAckSerializer(); + + private ClientLoginAckSerializer() { + } + + public static ClientLoginAckSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientLoginAck data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); - return map; + return new QVariant<>(new HashMap<>()); } @Override diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginRejectSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginRejectSerializer.java index d1af697c98b43a7b6b98179c0ab67ffb244edbf7..3426462b27e33e24ab4fb37759f596919930e89a 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginRejectSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginRejectSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.ClientLoginReject; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientLoginRejectSerializer implements ObjectSerializer<ClientLoginReject> { + private static final ClientLoginRejectSerializer serializer = new ClientLoginRejectSerializer(); + + private ClientLoginRejectSerializer() { + } + + public static ClientLoginRejectSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientLoginReject data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("Error", new QVariant<>(data.Error)); return map; } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginSerializer.java index 7daf5ba6ab236afdade8f9fc4981493c5a06b195..05d347ca10118fba677d38e702d3d3cc4f74ae46 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/ClientLoginSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.ClientLogin; import de.kuschku.libquassel.primitives.types.QVariant; public class ClientLoginSerializer implements ObjectSerializer<ClientLogin> { + private static final ClientLoginSerializer serializer = new ClientLoginSerializer(); + + private ClientLoginSerializer() { + } + + public static ClientLoginSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final ClientLogin data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("User", new QVariant<>(data.User)); map.data.put("Password", new QVariant<>(data.Password)); return map; diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupAckSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupAckSerializer.java index 0c70b1e85651022afb04345654b73c208b0810d5..dce2df1dee80fac136ab8d82f677907388925b2a 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupAckSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupAckSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.CoreSetupAck; import de.kuschku.libquassel.primitives.types.QVariant; public class CoreSetupAckSerializer implements ObjectSerializer<CoreSetupAck> { + private static final CoreSetupAckSerializer serializer = new CoreSetupAckSerializer(); + + private CoreSetupAckSerializer() { + } + + public static CoreSetupAckSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final CoreSetupAck data) { - return new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + return new QVariant<>(new HashMap<>()); } @Override diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupDataSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupDataSerializer.java index 90ef2db828a0c2d5e29296a90c254c545364e6cb..ba140d3576b12d106089d995bca0e19f9d3bd16a 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupDataSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupDataSerializer.java @@ -10,10 +10,19 @@ import de.kuschku.libquassel.objects.types.CoreSetupData; import de.kuschku.libquassel.primitives.types.QVariant; public class CoreSetupDataSerializer implements ObjectSerializer<CoreSetupData> { + private static final CoreSetupDataSerializer serializer = new CoreSetupDataSerializer(); + + private CoreSetupDataSerializer() { + } + + public static CoreSetupDataSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final CoreSetupData data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); - map.data.put("SetupData", new SetupDataInitializer().toVariantMap(data.SetupData)); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); + map.data.put("SetupData", SetupDataInitializer.get().toVariantMap(data.SetupData)); return map; } @@ -25,7 +34,7 @@ public class CoreSetupDataSerializer implements ObjectSerializer<CoreSetupData> @Override public CoreSetupData fromLegacy(Map<String, QVariant> map) { return new CoreSetupData( - new SetupDataInitializer().fromLegacy((Map<String, QVariant>) map.get("SetupData").data) + SetupDataInitializer.get().fromLegacy((Map<String, QVariant>) map.get("SetupData").data) ); } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupRejectSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupRejectSerializer.java index c38d1ec84ac0db5621fd733fa4dbf15c8fc01456..864b91fefcf9bf3a3cc3b5e3e447fcec69955808 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupRejectSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/CoreSetupRejectSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.CoreSetupReject; import de.kuschku.libquassel.primitives.types.QVariant; public class CoreSetupRejectSerializer implements ObjectSerializer<CoreSetupReject> { + private static final CoreSetupRejectSerializer serializer = new CoreSetupRejectSerializer(); + + private CoreSetupRejectSerializer() { + } + + public static CoreSetupRejectSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final CoreSetupReject data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("Error", new QVariant<>(data.Error)); return map; } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/NetworkServerSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/NetworkServerSerializer.java index 79e2e1cfb8fbd67adf4f67e4fa2e17517e769efa..501499a0daac1b241600154e13135736d7dba408 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/NetworkServerSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/NetworkServerSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.NetworkServer; import de.kuschku.libquassel.primitives.types.QVariant; public class NetworkServerSerializer implements ObjectSerializer<NetworkServer> { + private static final NetworkServerSerializer serializer = new NetworkServerSerializer(); + + private NetworkServerSerializer() { + } + + public static NetworkServerSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(NetworkServer data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("UseSSL", new QVariant<>(data.UseSSL)); map.data.put("sslVersion", new QVariant<>(data.sslVersion)); map.data.put("Host", new QVariant<>(data.Host)); diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/SessionInitSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/SessionInitSerializer.java index 62819608edbf0578c1215a4347a26d80421174be..be0d63808172cdf6eca6e388aeee2e2e76735c42 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/SessionInitSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/SessionInitSerializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.SessionInit; import de.kuschku.libquassel.primitives.types.QVariant; public class SessionInitSerializer implements ObjectSerializer<SessionInit> { + private static final SessionInitSerializer serializer = new SessionInitSerializer(); + + private SessionInitSerializer() { + } + + public static SessionInitSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final SessionInit data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("SessionState", new SessionStateSerializer().toVariantMap(data.SessionState)); return map; } diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/SetupDataInitializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/SetupDataInitializer.java index 25abecbf3f6844b8fe2da9724f3e01e2d977d91c..a8b83a50591d467469a67d7cd2eaf67d434033ef 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/SetupDataInitializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/SetupDataInitializer.java @@ -10,9 +10,18 @@ import de.kuschku.libquassel.objects.types.SetupData; import de.kuschku.libquassel.primitives.types.QVariant; public class SetupDataInitializer implements ObjectSerializer<SetupData> { + private static final SetupDataInitializer serializer = new SetupDataInitializer(); + + private SetupDataInitializer() { + } + + public static SetupDataInitializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final SetupData data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("AdminPasswd", new QVariant<>(data.AdminPasswd)); map.data.put("AdminUser", new QVariant<>(data.AdminUser)); map.data.put("Backend", new QVariant<>(data.Backend)); diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/StorageBackendSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/StorageBackendSerializer.java index f1a8e169b2ca7cb2c05af6ab6fc347fd70ae62a1..98e82cf39c3c39e520d848795333aace6fd173fa 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/StorageBackendSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/StorageBackendSerializer.java @@ -11,9 +11,18 @@ import de.kuschku.libquassel.objects.types.StorageBackend; import de.kuschku.libquassel.primitives.types.QVariant; public class StorageBackendSerializer implements ObjectSerializer<StorageBackend> { + private static final StorageBackendSerializer serializer = new StorageBackendSerializer(); + + private StorageBackendSerializer() { + } + + public static StorageBackendSerializer get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(final StorageBackend data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); map.data.put("DisplayName", new QVariant<>(data.DisplayName)); map.data.put("SetupDefaults", new QVariant<>(data.SetupDefaults)); map.data.put("Description", new QVariant<>(data.Description)); diff --git a/app/src/main/java/de/kuschku/libquassel/objects/serializers/StringObjectMapSerializer.java b/app/src/main/java/de/kuschku/libquassel/objects/serializers/StringObjectMapSerializer.java index 4bb47dfbb12fa397f843027bf795119df918d766..32816648d438725dfb8c7f739f8e6e3ae371ae8d 100644 --- a/app/src/main/java/de/kuschku/libquassel/objects/serializers/StringObjectMapSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/objects/serializers/StringObjectMapSerializer.java @@ -9,9 +9,18 @@ import de.kuschku.libquassel.functions.types.UnpackedFunction; import de.kuschku.libquassel.primitives.types.QVariant; public class StringObjectMapSerializer<T> implements ObjectSerializer<Map<String, T>> { + private static final StringObjectMapSerializer serializer = new StringObjectMapSerializer(); + + private StringObjectMapSerializer() { + } + + public static <T> StringObjectMapSerializer<T> get() { + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(Map<String, T> data) { - final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); + final QVariant<Map<String, QVariant>> map = new QVariant<>(new HashMap<>()); for (Map.Entry<String, T> entry : data.entrySet()) { map.data.put(entry.getKey(), new QVariant<>(entry.getValue())); } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/QMetaTypeRegistry.java b/app/src/main/java/de/kuschku/libquassel/primitives/QMetaTypeRegistry.java index 27c87e26da259da1d049ebf9ebe36ff9824abba7..3ee192ccfcb2a17fb08272026dd12e4c378b6044 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/QMetaTypeRegistry.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/QMetaTypeRegistry.java @@ -43,35 +43,35 @@ public class QMetaTypeRegistry { private static final Map<String, QMetaType> stringSerializerMap = new HashMap<>(); static { - addType(Void.class, QMetaType.Type.Void, new VoidSerializer()); - addType(boolean.class, QMetaType.Type.Bool, new BoolSerializer()); - addType(int.class, QMetaType.Type.Int, new IntSerializer()); - addType(int.class, QMetaType.Type.UserType, "BufferId", new IntSerializer()); - addType(int.class, QMetaType.Type.UserType, "NetworkId", new IntSerializer()); - addType(int.class, QMetaType.Type.UserType, "IdentityId", new IntSerializer()); - addType(int.class, QMetaType.Type.UserType, "MsgId", new IntSerializer()); - addType(BufferInfo.class, QMetaType.Type.UserType, "BufferInfo", new BufferInfoSerializer()); - addType(Message.class, QMetaType.Type.UserType, "Message", new MessageSerializer()); - addType(Identity.class, QMetaType.Type.UserType, "Identity", new UserTypeSerializer<>(new IdentitySerializer())); - addType(NetworkServer.class, QMetaType.Type.UserType, "Network::Server", new UserTypeSerializer<>(new NetworkServerSerializer())); - addType(int.class, QMetaType.Type.UInt, new IntSerializer()); - addType(short.class, QMetaType.Type.UShort, new ShortSerializer()); + addType(Void.class, QMetaType.Type.Void, VoidSerializer.get()); + addType(boolean.class, QMetaType.Type.Bool, BoolSerializer.get()); + addType(int.class, QMetaType.Type.Int, IntSerializer.get()); + addType(int.class, QMetaType.Type.UserType, "BufferId", IntSerializer.get()); + addType(int.class, QMetaType.Type.UserType, "NetworkId", IntSerializer.get()); + addType(int.class, QMetaType.Type.UserType, "IdentityId", IntSerializer.get()); + addType(int.class, QMetaType.Type.UserType, "MsgId", IntSerializer.get()); + addType(BufferInfo.class, QMetaType.Type.UserType, "BufferInfo", BufferInfoSerializer.get()); + addType(Message.class, QMetaType.Type.UserType, "Message", MessageSerializer.get()); + addType(Identity.class, QMetaType.Type.UserType, "Identity", new UserTypeSerializer<>(IdentitySerializer.get())); + addType(NetworkServer.class, QMetaType.Type.UserType, "Network::Server", new UserTypeSerializer<>(NetworkServerSerializer.get())); + addType(int.class, QMetaType.Type.UInt, IntSerializer.get()); + addType(short.class, QMetaType.Type.UShort, ShortSerializer.get()); // TODO: Implement more custom quassel types - addType(DateTime.class, QMetaType.Type.QTime, new TimeSerializer()); + addType(DateTime.class, QMetaType.Type.QTime, TimeSerializer.get()); addType(BigDecimal.class, QMetaType.Type.LongLong); addType(BigDecimal.class, QMetaType.Type.ULongLong); addType(double.class, QMetaType.Type.Double); - addType(char.class, QMetaType.Type.QChar, new CharSerializer()); - addType(List.class, QMetaType.Type.QVariantList, new VariantListSerializer()); - addType(Map.class, QMetaType.Type.QVariantMap, new VariantMapSerializer()); - addType(List.class, QMetaType.Type.QStringList, new StringListSerializer()); - addType(String.class, QMetaType.Type.QString, new StringSerializer()); - addType(String.class, QMetaType.Type.QByteArray, new ByteArraySerializer()); + addType(char.class, QMetaType.Type.QChar, CharSerializer.get()); + addType(List.class, QMetaType.Type.QVariantList, VariantListSerializer.get()); + addType(Map.class, QMetaType.Type.QVariantMap, VariantMapSerializer.get()); + addType(List.class, QMetaType.Type.QStringList, StringListSerializer.get()); + addType(String.class, QMetaType.Type.QString, StringSerializer.get()); + addType(String.class, QMetaType.Type.QByteArray, ByteArraySerializer.get()); addType(void.class, QMetaType.Type.QBitArray); addType(void.class, QMetaType.Type.QDate); - addType(DateTime.class, QMetaType.Type.QDateTime, new DateTimeSerializer()); + addType(DateTime.class, QMetaType.Type.QDateTime, DateTimeSerializer.get()); addType(void.class, QMetaType.Type.QUrl); addType(void.class, QMetaType.Type.QLocale); addType(void.class, QMetaType.Type.QRect); @@ -113,15 +113,15 @@ public class QMetaTypeRegistry { addType(void.class, QMetaType.Type.QQuaternion); addType(void.class, QMetaType.Type.VoidStar, "void*"); - addType(long.class, QMetaType.Type.Long, new LongSerializer()); - addType(short.class, QMetaType.Type.Short, new ShortSerializer()); - addType(byte.class, QMetaType.Type.Char, new ByteSerializer()); - addType(long.class, QMetaType.Type.ULong, new LongSerializer()); - addType(byte.class, QMetaType.Type.UChar, new ByteSerializer()); + addType(long.class, QMetaType.Type.Long, LongSerializer.get()); + addType(short.class, QMetaType.Type.Short, ShortSerializer.get()); + addType(byte.class, QMetaType.Type.Char, ByteSerializer.get()); + addType(long.class, QMetaType.Type.ULong, LongSerializer.get()); + addType(byte.class, QMetaType.Type.UChar, ByteSerializer.get()); addType(void.class, QMetaType.Type.Float); addType(void.class, QMetaType.Type.QObjectStar, "QObject*"); addType(void.class, QMetaType.Type.QWidgetStar, "QWidget*"); - addType(QVariant.class, QMetaType.Type.QVariant, new VariantSerializer()); + addType(QVariant.class, QMetaType.Type.QVariant, VariantSerializer.get()); } // Disable Constructor @@ -158,11 +158,11 @@ public class QMetaTypeRegistry { } public static <T> T deserialize(final QMetaType.Type type, final ByteBuffer buffer) throws IOException { - return deserialize(((QMetaType<T>) typeSerializerMap.get(type)), buffer); + return deserialize((getMetaTypeByType(type)), buffer); } public static <T> T deserialize(final String type, final ByteBuffer buffer) throws IOException { - return deserialize(((QMetaType<T>) stringSerializerMap.get(type)), buffer); + return deserialize((getMetaTypeByString(type)), buffer); } public static <T> T deserialize(final QMetaType<T> type, final ByteBuffer buffer) throws IOException { @@ -191,42 +191,58 @@ public class QMetaTypeRegistry { } public static <T> QMetaType<T> getType(String typeName) { - return ((QMetaType<T>) stringSerializerMap.get(typeName)); + return getMetaTypeByString(typeName); + } + + private static <T> QMetaType<T> getMetaTypeByString(String typeName) { + QMetaType<T> result = stringSerializerMap.get(typeName); + if (result == null || result.serializer == null) { + throw new RuntimeException("Unknown type: " + typeName); + } + return result; } public static <T> QMetaType<T> getType(QMetaType.Type type) { - return ((QMetaType<T>) typeSerializerMap.get(type)); + return getMetaTypeByType(type); + } + + private static <T> QMetaType<T> getMetaTypeByType(QMetaType.Type type) { + QMetaType<T> result = typeSerializerMap.get(type); + if (result == null || result.serializer == null) { + throw new RuntimeException("Unknown type: " + type.toString()); + } + return result; } public static <T> QMetaType<T> getTypeByObject(T type) { - if (type instanceof Void) return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Void); + if (type instanceof Void) return getMetaTypeByType(QMetaType.Type.Void); else if (type instanceof Boolean) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Bool); + return getMetaTypeByType(QMetaType.Type.Bool); else if (type instanceof Integer) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Int); + return getMetaTypeByType(QMetaType.Type.Int); else if (type instanceof Short) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Short); + return getMetaTypeByType(QMetaType.Type.Short); else if (type instanceof DateTime) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QDateTime); + return getMetaTypeByType(QMetaType.Type.QDateTime); else if (type instanceof Character) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QChar); + return getMetaTypeByType(QMetaType.Type.QChar); else if (type instanceof List) { if (((List) type).size() > 0 && ((List) type).get(0) instanceof String) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QStringList); + return getMetaTypeByType(QMetaType.Type.QStringList); else if (((List) type).size() > 0 && ((List) type).get(0) instanceof QVariant) - return new QMetaType<>((Class) type.getClass(), QMetaType.Type.QVariantList, new VariantVariantListSerializer()); + return new QMetaType<>((Class) type.getClass(), QMetaType.Type.QVariantList, (PrimitiveSerializer<T>) VariantVariantListSerializer.get()); else - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QVariantList); + return getMetaTypeByType(QMetaType.Type.QVariantList); } else if (type instanceof Map) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QVariantMap); + return getMetaTypeByType(QMetaType.Type.QVariantMap); else if (type instanceof String) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QString); + return getMetaTypeByType(QMetaType.Type.QString); else if (type instanceof Long) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Long); + return getMetaTypeByType(QMetaType.Type.Long); else if (type instanceof Byte) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.Char); + return getMetaTypeByType(QMetaType.Type.Char); else if (type instanceof QVariant) - return (QMetaType<T>) typeSerializerMap.get(QMetaType.Type.QVariant); + return getMetaTypeByType(QMetaType.Type.QVariant); else if (type instanceof Message) return stringSerializerMap.get("Message"); else if (type instanceof BufferInfo) return stringSerializerMap.get("BufferInfo"); else diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BoolSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BoolSerializer.java index fb98e4c247a97ae109f161ac1f6163457a3dae09..6c0da695f71e5b9d367db9eab23f68268506e4a6 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BoolSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BoolSerializer.java @@ -5,6 +5,12 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class BoolSerializer implements PrimitiveSerializer<Boolean> { + private static final BoolSerializer serializer = new BoolSerializer(); + private BoolSerializer() {} + public static BoolSerializer get(){ + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Boolean data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(1); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java index 043ebec841467bad8f95c09067c4a14f9a4c633f..798d137885e569d7ff391557d96243f9fa5afe0d 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/BufferInfoSerializer.java @@ -7,23 +7,29 @@ import java.nio.channels.ByteChannel; import de.kuschku.libquassel.primitives.types.BufferInfo; public class BufferInfoSerializer implements PrimitiveSerializer<BufferInfo> { + private static final BufferInfoSerializer serializer = new BufferInfoSerializer(); + private BufferInfoSerializer() {} + public static BufferInfoSerializer get(){ + return serializer; + } + @Override public void serialize(ByteChannel channel, BufferInfo data) throws IOException { - new IntSerializer().serialize(channel, data.id); - new IntSerializer().serialize(channel, data.networkId); - new ShortSerializer().serialize(channel, data.type.id); - new IntSerializer().serialize(channel, data.groupId); - new ByteArraySerializer().serialize(channel, data.name); + IntSerializer.get().serialize(channel, data.id); + IntSerializer.get().serialize(channel, data.networkId); + ShortSerializer.get().serialize(channel, data.type.id); + IntSerializer.get().serialize(channel, data.groupId); + ByteArraySerializer.get().serialize(channel, data.name); } @Override public BufferInfo deserialize(final ByteBuffer buffer) throws IOException { return new BufferInfo( - new IntSerializer().deserialize(buffer), - new IntSerializer().deserialize(buffer), - BufferInfo.Type.fromId(new ShortSerializer().deserialize(buffer)), - new IntSerializer().deserialize(buffer), - new ByteArraySerializer().deserialize(buffer) + IntSerializer.get().deserialize(buffer), + IntSerializer.get().deserialize(buffer), + BufferInfo.Type.fromId(ShortSerializer.get().deserialize(buffer)), + IntSerializer.get().deserialize(buffer), + ByteArraySerializer.get().deserialize(buffer) ); } } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteArraySerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteArraySerializer.java index f04bd7e30a69b391881c8057c826e3aeaf6d4e4c..e953fd5ba7d71991800cbd61f978979f6c70a986 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteArraySerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteArraySerializer.java @@ -1,6 +1,7 @@ package de.kuschku.libquassel.primitives.serializers; import android.support.annotation.Nullable; +import android.util.Log; import com.google.common.base.Charsets; @@ -9,23 +10,30 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class ByteArraySerializer implements PrimitiveSerializer<String> { - public final boolean trimLastByte; + private static final ByteArraySerializer serializerFalse = new ByteArraySerializer(false); + private static final ByteArraySerializer serializerTrue = new ByteArraySerializer(true); - public ByteArraySerializer() { - this(false); + public static ByteArraySerializer get() { + return get(false); + } + public static ByteArraySerializer get(boolean trimLastByte) { + if (trimLastByte) return serializerTrue; + else return serializerFalse; } - public ByteArraySerializer(boolean trimLastByte) { + public final boolean trimLastByte; + + private ByteArraySerializer(boolean trimLastByte) { this.trimLastByte = trimLastByte; } @Override public void serialize(final ByteChannel channel, final String data) throws IOException { if (data == null) { - new IntSerializer().serialize(channel, 0xffffffff); + IntSerializer.get().serialize(channel, 0xffffffff); } else { final ByteBuffer contentBuffer = Charsets.ISO_8859_1.encode(data); - new IntSerializer().serialize(channel, contentBuffer.limit() + (trimLastByte ? 1 : 0)); + IntSerializer.get().serialize(channel, contentBuffer.limit() + (trimLastByte ? 1 : 0)); channel.write(contentBuffer); if (trimLastByte) channel.write(ByteBuffer.allocate(1)); } @@ -34,7 +42,7 @@ public class ByteArraySerializer implements PrimitiveSerializer<String> { @Nullable @Override public String deserialize(final ByteBuffer buffer) throws IOException { - final int len = new IntSerializer().deserialize(buffer); + final int len = IntSerializer.get().deserialize(buffer); if (len == 0xffffffff) return null; else if (len == 0) diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteSerializer.java index 044b5776de57c32309e7d9ebb299006534fe0b90..600f790d2000021b355fba2d81e2f5bf7e7a54b2 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ByteSerializer.java @@ -5,6 +5,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class ByteSerializer implements PrimitiveSerializer<Byte> { + private static final ByteSerializer serializer = new ByteSerializer(); + + private ByteSerializer() { + } + + public static ByteSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Byte data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(1); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/CharSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/CharSerializer.java index 6843196f8bbe982ad09b28c236387e10e5190ec7..817343e6655987e227b497f618f60afc0b9d47b3 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/CharSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/CharSerializer.java @@ -6,6 +6,15 @@ import java.nio.channels.ByteChannel; import java.nio.charset.Charset; public class CharSerializer implements PrimitiveSerializer<Character> { + private static final CharSerializer serializer = new CharSerializer(); + + private CharSerializer() { + } + + public static CharSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Character data) throws IOException { final ByteBuffer buffer = Charset.forName("UTF-16BE").encode(String.valueOf(data.charValue())); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/DateTimeSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/DateTimeSerializer.java index 78dbd4dc78da60eb6782d1cdebeb48a9a9e7b5cf..8b4217e1746c24aa58299e9a275262cbb3a37b6f 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/DateTimeSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/DateTimeSerializer.java @@ -9,6 +9,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class DateTimeSerializer implements PrimitiveSerializer<DateTime> { + private static final DateTimeSerializer serializer = new DateTimeSerializer(); + + private DateTimeSerializer() { + } + + public static DateTimeSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final DateTime data) throws IOException { final boolean isUTC; @@ -20,17 +29,17 @@ public class DateTimeSerializer implements PrimitiveSerializer<DateTime> { throw new IllegalArgumentException("Serialization of timezones except for local and UTC is not supported"); - new IntSerializer().serialize(channel, (int) DateTimeUtils.toJulianDayNumber(data.getMillis())); - new IntSerializer().serialize(channel, data.getMillisOfDay()); - new BoolSerializer().serialize(channel, isUTC); + IntSerializer.get().serialize(channel, (int) DateTimeUtils.toJulianDayNumber(data.getMillis())); + IntSerializer.get().serialize(channel, data.getMillisOfDay()); + BoolSerializer.get().serialize(channel, isUTC); } @Override public DateTime deserialize(final ByteBuffer buffer) throws IOException { - final long julianDay = new IntSerializer().deserialize(buffer); - final int millisSinceMidnight = new IntSerializer().deserialize(buffer); + final long julianDay = IntSerializer.get().deserialize(buffer); + final int millisSinceMidnight = IntSerializer.get().deserialize(buffer); - final short zone = new ByteSerializer().deserialize(buffer); + final short zone = ByteSerializer.get().deserialize(buffer); if (millisSinceMidnight == 0x73007300 && julianDay == 0x50006100 || millisSinceMidnight == -1 || julianDay == -1) return new DateTime(0); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/IntSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/IntSerializer.java index 88e60c9127a5519c7c54cd456f893711ddf97846..6499f2241d7babf8c62e152d3e87b01244118d70 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/IntSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/IntSerializer.java @@ -5,6 +5,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class IntSerializer implements PrimitiveSerializer<Integer> { + private static final IntSerializer serializer = new IntSerializer(); + + private IntSerializer() { + } + + public static IntSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Integer data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(4); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/LongSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/LongSerializer.java index ae329f8b496f0ef31e292494f2234e78b43cbfdd..2776cb185ab93000c0d7a213e68aea89243a2020 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/LongSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/LongSerializer.java @@ -5,6 +5,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class LongSerializer implements PrimitiveSerializer<Long> { + private static final LongSerializer serializer = new LongSerializer(); + + private LongSerializer() { + } + + public static LongSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Long data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(8); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java index 6dffba06775c03781cffe2da951c1dd858b6c379..1a7cf26a32c58a2d22bce9a47536736ea2dc0c52 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/MessageSerializer.java @@ -9,27 +9,36 @@ import java.nio.channels.ByteChannel; import de.kuschku.libquassel.message.Message; public class MessageSerializer implements PrimitiveSerializer<Message> { + private static final MessageSerializer serializer = new MessageSerializer(); + + private MessageSerializer() { + } + + public static MessageSerializer get() { + return serializer; + } + @Override public void serialize(ByteChannel channel, Message data) throws IOException { - new IntSerializer().serialize(channel, data.messageId); - new IntSerializer().serialize(channel, (int) (data.time.getMillis() / 1000)); - new IntSerializer().serialize(channel, data.type.value); - new ByteSerializer().serialize(channel, data.flags.flags); - new BufferInfoSerializer().serialize(channel, data.bufferInfo); - new ByteArraySerializer().serialize(channel, data.sender); - new ByteArraySerializer().serialize(channel, data.content); + IntSerializer.get().serialize(channel, data.messageId); + IntSerializer.get().serialize(channel, (int) (data.time.getMillis() / 1000)); + IntSerializer.get().serialize(channel, data.type.value); + ByteSerializer.get().serialize(channel, data.flags.flags); + BufferInfoSerializer.get().serialize(channel, data.bufferInfo); + ByteArraySerializer.get().serialize(channel, data.sender); + ByteArraySerializer.get().serialize(channel, data.content); } @Override public Message deserialize(final ByteBuffer buffer) throws IOException { return new Message( - new IntSerializer().deserialize(buffer), - new DateTime(((long) new IntSerializer().deserialize(buffer)) * 1000), - Message.Type.fromId(new IntSerializer().deserialize(buffer)), - new Message.Flags(new ByteSerializer().deserialize(buffer)), - new BufferInfoSerializer().deserialize(buffer), - new ByteArraySerializer().deserialize(buffer), - new ByteArraySerializer().deserialize(buffer) + IntSerializer.get().deserialize(buffer), + new DateTime(((long) IntSerializer.get().deserialize(buffer)) * 1000), + Message.Type.fromId(IntSerializer.get().deserialize(buffer)), + new Message.Flags(ByteSerializer.get().deserialize(buffer)), + BufferInfoSerializer.get().deserialize(buffer), + ByteArraySerializer.get().deserialize(buffer), + ByteArraySerializer.get().deserialize(buffer) ); } } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ProtocolSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ProtocolSerializer.java index c7e667ec603a5b7c6ba6bf61a23f00b524c12675..63a8adead28e075c757401bae7a7d162be8c0cb3 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ProtocolSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ProtocolSerializer.java @@ -8,19 +8,28 @@ import de.kuschku.libquassel.ClientData; import de.kuschku.libquassel.primitives.types.Protocol; public class ProtocolSerializer implements PrimitiveSerializer<Protocol> { + private static final ProtocolSerializer serializer = new ProtocolSerializer(); + + private ProtocolSerializer() { + } + + public static ProtocolSerializer get() { + return serializer; + } + @Override public void serialize(ByteChannel channel, Protocol data) throws IOException { - new ByteSerializer().serialize(channel, data.protocolFlags.flags); - new ShortSerializer().serialize(channel, data.protocolData); - new ByteSerializer().serialize(channel, data.protocolVersion); + ByteSerializer.get().serialize(channel, data.protocolFlags.flags); + ShortSerializer.get().serialize(channel, data.protocolData); + ByteSerializer.get().serialize(channel, data.protocolVersion); } @Override public Protocol deserialize(ByteBuffer buffer) throws IOException { return new Protocol( - new ClientData.FeatureFlags(new ByteSerializer().deserialize(buffer)), - new ShortSerializer().deserialize(buffer), - new ByteSerializer().deserialize(buffer) + new ClientData.FeatureFlags(ByteSerializer.get().deserialize(buffer)), + ShortSerializer.get().deserialize(buffer), + ByteSerializer.get().deserialize(buffer) ); } } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ShortSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ShortSerializer.java index c9ff182e7b968bff1e5a054d6ad5ded30ed83d22..207b82e5fc217c5e33b3f47b28383ed7f1c49673 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ShortSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/ShortSerializer.java @@ -5,6 +5,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class ShortSerializer implements PrimitiveSerializer<Short> { + private static final ShortSerializer serializer = new ShortSerializer(); + + private ShortSerializer() { + } + + public static ShortSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Short data) throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(2); diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringListSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringListSerializer.java index 271be194351b0e8abbe21caad2329f2ed9e6ce1e..6ea6cd5fa5d36069e5e11fb12e8e446e49660d2e 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringListSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringListSerializer.java @@ -7,20 +7,29 @@ import java.util.ArrayList; import java.util.List; public class StringListSerializer implements PrimitiveSerializer<List<String>> { + private static final StringListSerializer serializer = new StringListSerializer(); + + private StringListSerializer() { + } + + public static StringListSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final List<String> data) throws IOException { - new IntSerializer().serialize(channel, data.size()); + IntSerializer.get().serialize(channel, data.size()); for (String element : data) { - new StringSerializer().serialize(channel, element); + StringSerializer.get().serialize(channel, element); } } @Override public List<String> deserialize(final ByteBuffer buffer) throws IOException { - final int size = new IntSerializer().deserialize(buffer); + final int size = IntSerializer.get().deserialize(buffer); final List<String> list = new ArrayList<>(size); for (int i = 0; i < size; i++) { - list.add(new StringSerializer().deserialize(buffer)); + list.add(StringSerializer.get().deserialize(buffer)); } return list; } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringSerializer.java index 087b6eaac40f6bc54bbbb698d784f846604039b9..5c7199f622ef8fd76faf92ea54d0e25739eda243 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/StringSerializer.java @@ -3,6 +3,7 @@ package de.kuschku.libquassel.primitives.serializers; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.Log; import java.io.IOException; import java.nio.ByteBuffer; @@ -10,13 +11,22 @@ import java.nio.channels.ByteChannel; import java.nio.charset.Charset; public class StringSerializer implements PrimitiveSerializer<String> { + private static final StringSerializer serializer = new StringSerializer(); + + private StringSerializer() { + } + + public static StringSerializer get() { + return serializer; + } + @Override public void serialize(@NonNull final ByteChannel channel, @Nullable final String data) throws IOException { if (data == null) { - new IntSerializer().serialize(channel, 0xffffffff); + IntSerializer.get().serialize(channel, 0xffffffff); } else { final ByteBuffer contentBuffer = Charset.forName("UTF-16BE").encode(data); - new IntSerializer().serialize(channel, contentBuffer.limit()); + IntSerializer.get().serialize(channel, contentBuffer.limit()); channel.write(contentBuffer); } } @@ -24,7 +34,7 @@ public class StringSerializer implements PrimitiveSerializer<String> { @Nullable @Override public String deserialize(final ByteBuffer buffer) throws IOException { - final int len = new IntSerializer().deserialize(buffer); + final int len = IntSerializer.get().deserialize(buffer); if (len == 0xffffffff) return null; else { diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/TimeSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/TimeSerializer.java index 7dcb9294110d66c0d8753ec0672f6c75d9d2b8ed..20dea6276a160aba0d96ab77bbdca25daae511e2 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/TimeSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/TimeSerializer.java @@ -7,13 +7,22 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class TimeSerializer implements PrimitiveSerializer<DateTime> { + private static final TimeSerializer serializer = new TimeSerializer(); + + private TimeSerializer() { + } + + public static TimeSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final DateTime data) throws IOException { - new IntSerializer().serialize(channel, data.millisOfDay().get()); + IntSerializer.get().serialize(channel, data.millisOfDay().get()); } @Override public DateTime deserialize(final ByteBuffer buffer) throws IOException { - return DateTime.now().millisOfDay().setCopy(new IntSerializer().deserialize(buffer)); + return DateTime.now().millisOfDay().setCopy(IntSerializer.get().deserialize(buffer)); } } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/UserTypeSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/UserTypeSerializer.java index 9532e6f8fd62184aed024389c9f35c4c9c9169b6..dddf88442d5ac74dead6ef9bbf93469e7dd23321 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/UserTypeSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/UserTypeSerializer.java @@ -17,11 +17,11 @@ public class UserTypeSerializer<T> implements PrimitiveSerializer<T> { @Override public void serialize(ByteChannel channel, T data) throws IOException { - new VariantSerializer<Map<String, QVariant>>().serialize(channel, objectSerializer.toVariantMap(data)); + VariantSerializer.<Map<String, QVariant>>get().serialize(channel, objectSerializer.toVariantMap(data)); } @Override public T deserialize(ByteBuffer buffer) throws IOException { - return (T) objectSerializer.fromLegacy(new VariantMapSerializer().deserialize(buffer)); + return (T) objectSerializer.fromLegacy(((VariantMapSerializer) VariantMapSerializer.get()).deserialize(buffer)); } } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantListSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantListSerializer.java index cad66b2167bf1f52eabcd3e34f46371a3be1ca6c..25195552c7b1c02bb31738805159fc16e8737906 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantListSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantListSerializer.java @@ -9,11 +9,20 @@ import java.util.List; import de.kuschku.libquassel.primitives.types.QVariant; public class VariantListSerializer<T> implements PrimitiveSerializer<List<T>> { + private static final VariantListSerializer serializer = new VariantListSerializer(); + + private VariantListSerializer() { + } + + public static <T> VariantListSerializer<T> get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final List<T> data) throws IOException { - new IntSerializer().serialize(channel, data.size()); + IntSerializer.get().serialize(channel, data.size()); - final VariantSerializer<T> variantSerializer = new VariantSerializer<>(); + final VariantSerializer<T> variantSerializer = VariantSerializer.get(); for (T element : data) { variantSerializer.serialize(channel, new QVariant<>(element)); } @@ -21,10 +30,10 @@ public class VariantListSerializer<T> implements PrimitiveSerializer<List<T>> { @Override public List<T> deserialize(final ByteBuffer buffer) throws IOException { - final int length = new IntSerializer().deserialize(buffer); + final int length = IntSerializer.get().deserialize(buffer); final List<T> list = new ArrayList<>(length); - final VariantSerializer<T> variantSerializer = new VariantSerializer<>(); + final VariantSerializer<T> variantSerializer = VariantSerializer.get(); for (int i = 0; i < length; i++) { list.add(variantSerializer.deserialize(buffer).data); } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantMapSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantMapSerializer.java index 1a86121b5777f2dbd3f45c53b7e52b5188439dd7..cea4e0b713de237064336ffb9b6badef39dd720f 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantMapSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantMapSerializer.java @@ -9,13 +9,21 @@ import java.util.Map; import de.kuschku.libquassel.primitives.types.QVariant; public class VariantMapSerializer<T> implements PrimitiveSerializer<Map<String, QVariant<T>>> { + private static final VariantMapSerializer serializer = new VariantMapSerializer(); - private PrimitiveSerializer<String> stringSerializer = new StringSerializer(); - private VariantSerializer<T> variantSerializer = new VariantSerializer<>(); + private VariantMapSerializer() { + } + + public static <T> VariantMapSerializer<T> get() { + return serializer; + } + + private PrimitiveSerializer<String> stringSerializer = StringSerializer.get(); + private VariantSerializer<T> variantSerializer = VariantSerializer.get(); @Override public void serialize(final ByteChannel channel, final Map<String, QVariant<T>> data) throws IOException { - new IntSerializer().serialize(channel, data.size()); + IntSerializer.get().serialize(channel, data.size()); for (Map.Entry<String, QVariant<T>> element : data.entrySet()) { stringSerializer.serialize(channel, element.getKey()); @@ -25,7 +33,7 @@ public class VariantMapSerializer<T> implements PrimitiveSerializer<Map<String, @Override public Map<String, QVariant<T>> deserialize(final ByteBuffer buffer) throws IOException { - final int length = new IntSerializer().deserialize(buffer); + final int length = IntSerializer.get().deserialize(buffer); final Map<String, QVariant<T>> map = new HashMap<>(length); for (int i = 0; i < length; i++) { diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantSerializer.java index 92666dadb77b11dfcebe7b826173c1351585d417..b8ff42371ca194ffef8c067c3938da275b3b9304 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantSerializer.java @@ -9,12 +9,24 @@ import de.kuschku.libquassel.primitives.QMetaTypeRegistry; import de.kuschku.libquassel.primitives.types.QVariant; public class VariantSerializer<T> implements PrimitiveSerializer<QVariant<T>> { + private static final VariantSerializer serializer = new VariantSerializer(); + + private VariantSerializer() { + } + + public static <T> VariantSerializer<T> get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final QVariant<T> data) throws IOException { - new IntSerializer().serialize(channel, data.type.type.getValue()); - new BoolSerializer().serialize(channel, data.data == null); + IntSerializer.get().serialize(channel, data.type.type.getValue()); + BoolSerializer.get().serialize(channel, data.data == null); if (data.type.type == QMetaType.Type.UserType) { - new ByteArraySerializer(true).serialize(channel, data.type.name); + ByteArraySerializer.get(true).serialize(channel, data.type.name); + } + if (data.type.serializer == null) { + throw new IOException("Unknown type: " + data.type.name); } data.type.serializer.serialize(channel, data.data); } @@ -22,11 +34,11 @@ public class VariantSerializer<T> implements PrimitiveSerializer<QVariant<T>> { @Override public QVariant<T> deserialize(final ByteBuffer buffer) throws IOException { // Read original type - final QMetaType.Type type = QMetaType.Type.fromId(new IntSerializer().deserialize(buffer)); + final QMetaType.Type type = QMetaType.Type.fromId(IntSerializer.get().deserialize(buffer)); // Read if the data is defined or null // TODO: For some reason, this is completely ignored. Figure out why and document. - final boolean isNull = new BoolSerializer().deserialize(buffer); + final boolean isNull = BoolSerializer.get().deserialize(buffer); // Get the actual serialized type final QMetaType<T> mtype; @@ -34,7 +46,7 @@ public class VariantSerializer<T> implements PrimitiveSerializer<QVariant<T>> { // If the type is a user-defined type, read type name // WARNING: This ByteArray has a trailing null byte, which we can’t deserialize. // Therefore we have to pass a flag to make sure the serializer removes it. - final String typeName = new ByteArraySerializer(true).deserialize(buffer); + final String typeName = ByteArraySerializer.get(true).deserialize(buffer); mtype = QMetaTypeRegistry.getType(typeName); if (mtype == null || mtype.serializer == null) { diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantVariantListSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantVariantListSerializer.java index d6c68d59633567bb431f1dd62826f7c33c1b57f3..bcfeba97cfcd274be8c60fc37058fbf4670de053 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantVariantListSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VariantVariantListSerializer.java @@ -9,11 +9,20 @@ import java.util.List; import de.kuschku.libquassel.primitives.types.QVariant; public class VariantVariantListSerializer<T> implements PrimitiveSerializer<List<QVariant<T>>> { + private static final VariantVariantListSerializer serializer = new VariantVariantListSerializer(); + + private VariantVariantListSerializer() { + } + + public static <T> VariantVariantListSerializer<T> get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final List<QVariant<T>> data) throws IOException { - new IntSerializer().serialize(channel, data.size()); + IntSerializer.get().serialize(channel, data.size()); - final VariantSerializer<T> variantSerializer = new VariantSerializer<>(); + final VariantSerializer<T> variantSerializer = VariantSerializer.get(); for (QVariant<T> element : data) { variantSerializer.serialize(channel, element); } @@ -21,10 +30,10 @@ public class VariantVariantListSerializer<T> implements PrimitiveSerializer<List @Override public List<QVariant<T>> deserialize(final ByteBuffer buffer) throws IOException { - final int length = new IntSerializer().deserialize(buffer); + final int length = IntSerializer.get().deserialize(buffer); final List<QVariant<T>> list = new ArrayList<>(length); - final VariantSerializer<T> variantSerializer = new VariantSerializer<>(); + final VariantSerializer<T> variantSerializer = VariantSerializer.get(); for (int i = 0; i < length; i++) { list.add(variantSerializer.deserialize(buffer)); } diff --git a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VoidSerializer.java b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VoidSerializer.java index 18e49c17c338bbdc123435ba109090801bfaa2e4..66161a343bac1c160d7108dad5bbe9b8f4d4cff3 100644 --- a/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VoidSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/primitives/serializers/VoidSerializer.java @@ -8,6 +8,15 @@ import java.nio.ByteBuffer; import java.nio.channels.ByteChannel; public class VoidSerializer implements PrimitiveSerializer<Void> { + private static final VoidSerializer serializer = new VoidSerializer(); + + private VoidSerializer() { + } + + public static VoidSerializer get() { + return serializer; + } + @Override public void serialize(final ByteChannel channel, final Void data) throws IOException { diff --git a/app/src/main/java/de/kuschku/libquassel/protocols/DatastreamPeer.java b/app/src/main/java/de/kuschku/libquassel/protocols/DatastreamPeer.java index 77eb1cfd17a85649ee92d9f9423ea35ea103d83b..7787c038e8ba3f7b837a25de9c909819c8c134ab 100644 --- a/app/src/main/java/de/kuschku/libquassel/protocols/DatastreamPeer.java +++ b/app/src/main/java/de/kuschku/libquassel/protocols/DatastreamPeer.java @@ -1,6 +1,7 @@ package de.kuschku.libquassel.protocols; import android.support.annotation.NonNull; +import android.util.Log; import com.google.common.base.Function; import com.google.common.collect.Lists; @@ -35,6 +36,7 @@ import de.kuschku.libquassel.objects.MessageTypeRegistry; import de.kuschku.libquassel.primitives.QMetaType; import de.kuschku.libquassel.primitives.serializers.IntSerializer; import de.kuschku.libquassel.primitives.serializers.PrimitiveSerializer; +import de.kuschku.libquassel.primitives.serializers.VariantListSerializer; import de.kuschku.libquassel.primitives.serializers.VariantVariantListSerializer; import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.util.niohelpers.WrappedChannel; @@ -46,9 +48,6 @@ import de.kuschku.util.niohelpers.WrappedChannel; * @author Janne Koschinski */ public class DatastreamPeer implements RemotePeer { - private final IntSerializer intSerializer = new IntSerializer(); - private final VariantVariantListSerializer variantListSerializer = new VariantVariantListSerializer<>(); - private ByteBuffer buffer; private CoreConnection connection; private BusProvider busProvider; @@ -59,8 +58,8 @@ public class DatastreamPeer implements RemotePeer { this.busProvider.dispatch.register(this); } - public static List<QVariant> mapToList(Map<String, QVariant> data) { - final List<QVariant> list = new ArrayList<>(data.size() * 2); + public static List<QVariant<Object>> mapToList(Map<String, QVariant> data) { + final List<QVariant<Object>> list = new ArrayList<>(data.size() * 2); for (Map.Entry<String, QVariant> entry : data.entrySet()) { list.add(new QVariant<>(QMetaType.Type.QByteArray, entry.getKey())); list.add(entry.getValue()); @@ -96,40 +95,40 @@ public class DatastreamPeer implements RemotePeer { public void onEventBackgroundThread(SyncFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantVariantListSerializer(), - new UnpackedSyncFunctionSerializer().serialize(func)) - ); + VariantVariantListSerializer.<SyncFunction>get(), + UnpackedSyncFunctionSerializer.get().serialize(func) + )); } public void onEventBackgroundThread(RpcCallFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantVariantListSerializer(), - new UnpackedRpcCallFunctionSerializer().serialize(func)) - ); + VariantVariantListSerializer.<RpcCallFunction>get(), + UnpackedRpcCallFunctionSerializer.get().serialize(func) + )); } public void onEventBackgroundThread(InitRequestFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantVariantListSerializer(), - new InitRequestFunctionSerializer().serializePacked(func) + VariantVariantListSerializer.<InitRequestFunction>get(), + InitRequestFunctionSerializer.get().serializePacked(func) )); } public void onEventBackgroundThread(InitDataFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantVariantListSerializer(), - new InitDataFunctionSerializer().serialize(func)) - ); + VariantVariantListSerializer.<InitDataFunction>get(), + InitDataFunctionSerializer.get().serialize(func) + )); } public void onEventBackgroundThread(HandshakeFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantVariantListSerializer(), - DatastreamPeer.mapToList(MessageTypeRegistry.toVariantMap(func.data).data)) - ); + VariantVariantListSerializer.get(), + DatastreamPeer.mapToList(MessageTypeRegistry.toVariantMap(func.data).data) + )); } - private void handleHandshakeMessage(List<QVariant> data) { + private void handleHandshakeMessage(List data) { busProvider.handle(MessageTypeRegistry.from(DatastreamPeer.listToMap(data))); } @@ -137,16 +136,16 @@ public class DatastreamPeer implements RemotePeer { final FunctionType type = FunctionType.fromId((Integer) data.remove(0).data); switch (type) { case SYNC: - busProvider.handle(new PackedSyncFunctionSerializer().deserialize(data)); + busProvider.handle(PackedSyncFunctionSerializer.get().deserialize(data)); break; case RPCCALL: - busProvider.handle(new PackedRpcCallFunctionSerializer().deserialize(data)); + busProvider.handle(PackedRpcCallFunctionSerializer.get().deserialize(data)); break; case INITREQUEST: - busProvider.handle(new InitRequestFunctionSerializer().deserialize(data)); + busProvider.handle(InitRequestFunctionSerializer.get().deserialize(data)); break; case INITDATA: - busProvider.handle(new PackedInitDataFunctionSerializer().deserialize(data)); + busProvider.handle( PackedInitDataFunctionSerializer.get().deserialize(data)); break; case HEARTBEAT: case HEARTBEATREPLY: @@ -160,14 +159,15 @@ public class DatastreamPeer implements RemotePeer { buffer = ByteBuffer.allocate(4); connection.getChannel().read(buffer); - final int size = intSerializer.deserialize(buffer); + final int size = IntSerializer.get().deserialize(buffer); + if (size == 0) return; buffer = ByteBuffer.allocate(size); connection.getChannel().read(buffer); // TODO: Put this into a future with a time limit, and parallelize it. - final List<QVariant> data = variantListSerializer.deserialize(buffer); + final List data = VariantVariantListSerializer.get().deserialize(buffer); if (connection.getStatus() == ConnectionChangeEvent.Status.CONNECTING || connection.getStatus() == ConnectionChangeEvent.Status.HANDSHAKE || connection.getStatus() == ConnectionChangeEvent.Status.CORE_SETUP_REQUIRED @@ -211,7 +211,7 @@ public class DatastreamPeer implements RemotePeer { // Serialize the object into the buffer-channel serializer.serialize(fakeChannel, data); // Write the size of the buffer over the network - new IntSerializer().serialize(connection.getChannel(), out.size()); + IntSerializer.get().serialize(connection.getChannel(), out.size()); // Write the content of the buffer over the network connection.getChannel().write(ByteBuffer.wrap(out.toByteArray())); // Flush the deflater, if existing diff --git a/app/src/main/java/de/kuschku/libquassel/protocols/LegacyPeer.java b/app/src/main/java/de/kuschku/libquassel/protocols/LegacyPeer.java index 0a8d6f8a5880ef61aabcbee225a11fac10c0ac62..531384873c4e60fff16a243f78eb4bf785f9fcfb 100644 --- a/app/src/main/java/de/kuschku/libquassel/protocols/LegacyPeer.java +++ b/app/src/main/java/de/kuschku/libquassel/protocols/LegacyPeer.java @@ -40,9 +40,6 @@ import static de.kuschku.libquassel.primitives.QMetaType.Type.QVariantMap; * @author Janne Koschinski */ public class LegacyPeer implements RemotePeer { - private final IntSerializer intSerializer = new IntSerializer(); - private final VariantSerializer variantSerializer = new VariantSerializer(); - private ByteBuffer buffer; private CoreConnection connection; private BusProvider busProvider; @@ -54,60 +51,60 @@ public class LegacyPeer implements RemotePeer { } public final void onEventBackgroundThread(SyncFunction func) { - final List serialize = new UnpackedSyncFunctionSerializer().serialize(func); - connection.getOutputExecutor().submit(new OutputRunnable<>(new VariantSerializer<List>(), - new QVariant<>(new QMetaType<List>(List.class, QMetaType.Type.QVariantList, new VariantVariantListSerializer()), + final List serialize = UnpackedSyncFunctionSerializer.get().serialize(func); + connection.getOutputExecutor().submit(new OutputRunnable<>(VariantSerializer.get(), + new QVariant(new QMetaType(List.class, QMetaType.Type.QVariantList, VariantVariantListSerializer.get()), serialize))); } public void onEventBackgroundThread(RpcCallFunction func) { - connection.getOutputExecutor().submit(new OutputRunnable<>(new VariantSerializer<List>(), - new QVariant<>(new UnpackedRpcCallFunctionSerializer().serialize(func)))); + connection.getOutputExecutor().submit(new OutputRunnable<>(VariantSerializer.get(), + new QVariant<>(UnpackedRpcCallFunctionSerializer.get().serialize(func)))); } public void onEventBackgroundThread(InitRequestFunction func) { - connection.getOutputExecutor().submit(new OutputRunnable<>(new VariantSerializer<List>(), - new QVariant<>(new InitRequestFunctionSerializer().serialize(func)))); + connection.getOutputExecutor().submit(new OutputRunnable<>(VariantSerializer.get(), + new QVariant<>(InitRequestFunctionSerializer.get().serialize(func)))); } public void onEventBackgroundThread(InitDataFunction func) { - connection.getOutputExecutor().submit(new OutputRunnable<>(new VariantSerializer<List>(), - new QVariant<>(new InitDataFunctionSerializer().serialize(func)))); + connection.getOutputExecutor().submit(new OutputRunnable<>(VariantSerializer.get(), + new QVariant<>(InitDataFunctionSerializer.get().serialize(func)))); } public void onEventBackgroundThread(HandshakeFunction func) { connection.getOutputExecutor().submit(new OutputRunnable<>( - new VariantSerializer<>(), MessageTypeRegistry.toVariantMap(func.data))); + VariantSerializer.get(), MessageTypeRegistry.toVariantMap(func.data))); } public void processMessage() throws IOException { buffer = ByteBuffer.allocate(4); connection.getChannel().read(buffer); - final int size = intSerializer.deserialize(buffer); + final int size = IntSerializer.get().deserialize(buffer); if (size == 0) return; buffer = ByteBuffer.allocate(size); connection.getChannel().read(buffer); // TODO: Put this into a future with a time limit, and parallelize it. - final QVariant data = variantSerializer.deserialize(buffer); + final QVariant data = VariantSerializer.get().deserialize(buffer); if (data.type.type == QVariantMap) { busProvider.handle(MessageTypeRegistry.from((Map<String, QVariant>) data.data)); } else if (data.type.type == QVariantList) { final FunctionType type = FunctionType.fromId((Integer) ((List<Object>) data.data).remove(0)); switch (type) { case SYNC: - busProvider.handle(new UnpackedSyncFunctionSerializer().deserialize((List<QVariant>) data.data)); + busProvider.handle(UnpackedSyncFunctionSerializer.get().deserialize((List<QVariant>) data.data)); break; case RPCCALL: - busProvider.handle(new UnpackedRpcCallFunctionSerializer().deserialize((List<QVariant>) data.data)); + busProvider.handle(UnpackedRpcCallFunctionSerializer.get().deserialize((List<QVariant>) data.data)); break; case INITREQUEST: - busProvider.handle(new InitRequestFunctionSerializer().deserialize((List<QVariant>) data.data)); + busProvider.handle(InitRequestFunctionSerializer.get().deserialize((List<QVariant>) data.data)); break; case INITDATA: - busProvider.handle(new UnpackedInitDataFunctionSerializer().deserialize((List<QVariant>) data.data)); + busProvider.handle(UnpackedInitDataFunctionSerializer.get().deserialize((List<QVariant>) data.data)); break; case HEARTBEAT: case HEARTBEATREPLY: @@ -150,7 +147,7 @@ public class LegacyPeer implements RemotePeer { // Serialize the object into the buffer-channel serializer.serialize(fakeChannel, data); // Write the size of the buffer over the network - new IntSerializer().serialize(connection.getChannel(), out.size()); + IntSerializer.get().serialize(connection.getChannel(), out.size()); // Write the content of the buffer over the network connection.getChannel().write(ByteBuffer.wrap(out.toByteArray())); // Flush the deflater, if existing diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/SyncableRegistry.java b/app/src/main/java/de/kuschku/libquassel/syncables/SyncableRegistry.java index fb17008e7159fe69ec8eadf123913e249316963d..f2985142bbde1d1690c151a6e36e2094c7031783 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/SyncableRegistry.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/SyncableRegistry.java @@ -19,13 +19,13 @@ public class SyncableRegistry { private static final Map<String, ObjectSerializer<? extends SyncableObject>> map = new HashMap<>(); static { - map.put("BufferSyncer", new BufferSyncerSerializer()); - map.put("BufferViewConfig", new BufferViewConfigSerializer()); - map.put("BufferViewManager", new BufferViewManagerSerializer()); - map.put("Identity", new IdentitySerializer()); - map.put("IrcChannel", new IrcChannelSerializer()); - map.put("IrcUser", new IrcUserSerializer()); - map.put("Network", new NetworkSerializer()); + map.put("BufferSyncer", BufferSyncerSerializer.get()); + map.put("BufferViewConfig", BufferViewConfigSerializer.get()); + map.put("BufferViewManager", BufferViewManagerSerializer.get()); + map.put("Identity", IdentitySerializer.get()); + map.put("IrcChannel", IrcChannelSerializer.get()); + map.put("IrcUser", IrcUserSerializer.get()); + map.put("Network", NetworkSerializer.get()); } private SyncableRegistry() { diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferSyncerSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferSyncerSerializer.java index 4fa8403f86fc14a481bb99759ef7927d667dce89..5dee487e398e08e28fd29849f55feb63ff8c9a5c 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferSyncerSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferSyncerSerializer.java @@ -12,6 +12,12 @@ import de.kuschku.libquassel.protocols.DatastreamPeer; import de.kuschku.libquassel.syncables.types.BufferSyncer; public class BufferSyncerSerializer implements ObjectSerializer<BufferSyncer> { + private static final BufferSyncerSerializer serializer = new BufferSyncerSerializer(); + private BufferSyncerSerializer() {} + public static BufferSyncerSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(BufferSyncer data) { // TODO: Implement this diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewConfigSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewConfigSerializer.java index c90a5c5a90ad64d1b01e15ae36b2ab87ee97d3b2..6c6e91f8bfc57a528c5d9c98d28d1673f7e568e0 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewConfigSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewConfigSerializer.java @@ -12,6 +12,12 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.syncables.types.BufferViewConfig; public class BufferViewConfigSerializer implements ObjectSerializer<BufferViewConfig> { + private static final BufferViewConfigSerializer serializer = new BufferViewConfigSerializer(); + private BufferViewConfigSerializer() {} + public static BufferViewConfigSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(BufferViewConfig data) { final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<>()); diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewManagerSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewManagerSerializer.java index cfc32897cf400eceb7e49d3c78376c9226a3040f..54a7b217bce78691ff99963af6cef9f5b0925e0c 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewManagerSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/BufferViewManagerSerializer.java @@ -11,6 +11,12 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.syncables.types.BufferViewManager; public class BufferViewManagerSerializer implements ObjectSerializer<BufferViewManager> { + private static final BufferViewManagerSerializer serializer = new BufferViewManagerSerializer(); + private BufferViewManagerSerializer() {} + public static BufferViewManagerSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(BufferViewManager data) { return null; diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IdentitySerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IdentitySerializer.java index 8af94495610bc9c82d3ed0c46dd8764b4004b87e..9e0de026ef59ce1d075f3fd9c8a3af3890953ff3 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IdentitySerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IdentitySerializer.java @@ -12,6 +12,12 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.syncables.types.Identity; public class IdentitySerializer implements ObjectSerializer<Identity> { + private static final IdentitySerializer serializer = new IdentitySerializer(); + private IdentitySerializer() {} + public static IdentitySerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(Identity data) { final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcChannelSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcChannelSerializer.java index 489bcf9bbf8d8d1b64f599270cf73cbcc0d807b3..f582ef782c8c5b3267a0fcd1a39f21eb98eee949 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcChannelSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcChannelSerializer.java @@ -12,13 +12,19 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.syncables.types.IrcChannel; public class IrcChannelSerializer implements ObjectSerializer<IrcChannel> { + private static final IrcChannelSerializer serializer = new IrcChannelSerializer(); + private IrcChannelSerializer() {} + public static IrcChannelSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(IrcChannel data) { final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); map.data.put("name", new QVariant<>(data.name)); map.data.put("topic", new QVariant<>(data.topic)); map.data.put("password", new QVariant<>(data.password)); - map.data.put("UserModes", new StringObjectMapSerializer<String>().toVariantMap(data.UserModes)); + map.data.put("UserModes", StringObjectMapSerializer.<String>get().toVariantMap(data.UserModes)); map.data.put("ChanModes", new QVariant<>(data.ChanModes)); map.data.put("encrypted", new QVariant<>(data.encrypted)); return map; @@ -35,7 +41,7 @@ public class IrcChannelSerializer implements ObjectSerializer<IrcChannel> { (String) map.get("name").data, (String) map.get("topic").data, (String) map.get("password").data, - new StringObjectMapSerializer<String>().fromLegacy(((QVariant<Map<String, QVariant>>) map.get("UserModes")).data), + StringObjectMapSerializer.<String>get().fromLegacy(((QVariant<Map<String, QVariant>>) map.get("UserModes")).data), (Map<String, Object>) map.get("ChanModes").data, (boolean) map.get("encrypted").data ); diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java index bd32e1b35fc3a27bef94743e7374851a6424e366..bcfc2de7d218fb8ea61c6306181fe7e0b65d192b 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/IrcUserSerializer.java @@ -14,6 +14,12 @@ import de.kuschku.libquassel.primitives.types.QVariant; import de.kuschku.libquassel.syncables.types.IrcUser; public class IrcUserSerializer implements ObjectSerializer<IrcUser> { + private static final IrcUserSerializer serializer = new IrcUserSerializer(); + private IrcUserSerializer() {} + public static IrcUserSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(IrcUser data) { final QVariant<Map<String, QVariant>> map = new QVariant<Map<String, QVariant>>(new HashMap<String, QVariant>()); diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java index 22308e1a55625d4ba65b1effd48de3977c58eb57..c41bf16da42807f3d9035933f2e81b1efdc9f068 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/serializers/NetworkSerializer.java @@ -19,6 +19,12 @@ import de.kuschku.libquassel.syncables.types.IrcUser; import de.kuschku.libquassel.syncables.types.Network; public class NetworkSerializer implements ObjectSerializer<Network> { + private static final NetworkSerializer serializer = new NetworkSerializer(); + private NetworkSerializer() {} + public static NetworkSerializer get(){ + return serializer; + } + @Override public QVariant<Map<String, QVariant>> toVariantMap(Network data) { // TODO: Implement this @@ -42,7 +48,7 @@ public class NetworkSerializer implements ObjectSerializer<Network> { channelMap, userMap, (List<NetworkServer>) map.get("ServerList").data, - (Map<String, String>) new StringObjectMapSerializer().fromLegacy((Map<String, QVariant>) map.get("Supports").data), + (Map<String, String>) StringObjectMapSerializer.<String>get().fromLegacy((Map<String, QVariant>) map.get("Supports").data), (String) map.get("autoIdentifyPassword").data, (String) map.get("autoIdentifyService").data, (int) map.get("autoReconnectInterval").data, @@ -133,11 +139,11 @@ public class NetworkSerializer implements ObjectSerializer<Network> { final Map<String, QVariant<Map<String, QVariant>>> wrappedUsers = usersAndChannels.get("users").data; final Map<String, IrcChannel> channels = new HashMap<>(wrappedChannels.size()); for (Map.Entry<String, QVariant<Map<String, QVariant>>> entry : wrappedChannels.entrySet()) { - final IrcChannel ircChannel = new IrcChannelSerializer().fromLegacy(entry.getValue().data); + final IrcChannel ircChannel = IrcChannelSerializer.get().fromLegacy(entry.getValue().data); channels.put(ircChannel.name, ircChannel); } final Map<String, IrcUser> users = new HashMap<>(wrappedUsers.size()); - final Map<String, String> supports = (Map<String, String>) new StringObjectMapSerializer().fromLegacy((Map<String, QVariant>) map.get("Supports").data); + final Map<String, String> supports = (Map<String, String>) StringObjectMapSerializer.<String>get().fromLegacy((Map<String, QVariant>) map.get("Supports").data); Network network = new Network( channels, new HashMap<>(wrappedUsers.size()), @@ -168,7 +174,7 @@ public class NetworkSerializer implements ObjectSerializer<Network> { (boolean) map.get("useSasl").data ); for (Map.Entry<String, QVariant<Map<String, QVariant>>> entry : wrappedUsers.entrySet()) { - final IrcUser ircUser = new IrcUserSerializer().fromLegacy(entry.getValue().data); + final IrcUser ircUser = IrcUserSerializer.get().fromLegacy(entry.getValue().data); ircUser.setNetwork(network); } return network; diff --git a/app/src/main/java/de/kuschku/libquassel/syncables/types/BufferViewConfig.java b/app/src/main/java/de/kuschku/libquassel/syncables/types/BufferViewConfig.java index 19b1de12c2f38cb2a9c966f4ac1a8ef8c6cefb56..79f102c7d46ca983f8325ae55717a2ab27d63ff6 100644 --- a/app/src/main/java/de/kuschku/libquassel/syncables/types/BufferViewConfig.java +++ b/app/src/main/java/de/kuschku/libquassel/syncables/types/BufferViewConfig.java @@ -156,4 +156,13 @@ public class BufferViewConfig extends SyncableObject { client.getBufferViewManager().BufferViews.put(Integer.valueOf(function.objectName), this); provider.sendEvent(new BufferViewManagerChangedEvent(Integer.valueOf(function.objectName), BufferViewManagerChangedEvent.Action.ADD)); } + + public void addBuffer(int bufferId, int position) { + BufferList.add(position, bufferId); + } + + public void SYNC_addBuffer(int bufferId, int position) { + addBuffer(bufferId, position); + sync("addBuffer", new Object[] {bufferId, position}); + } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatMessageRenderer.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatMessageRenderer.java index 0551f08d6f9391cfee83d6218905bd71a7dabb36..13391ed8fe7385b522ef7318d54d161e19656085 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatMessageRenderer.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/ChatMessageRenderer.java @@ -1,6 +1,8 @@ package de.kuschku.quasseldroid_ng.ui; import android.content.Context; +import android.graphics.Typeface; +import android.support.annotation.ColorInt; import android.text.SpannableString; import android.text.TextUtils; @@ -24,7 +26,7 @@ public class ChatMessageRenderer { private final IrcFormatHelper helper; private Client client; - private boolean fullHostmask = false; + private boolean fullHostmask = true; public ChatMessageRenderer(Context ctx) { this.themeUtil = new ThemeUtil(ctx); @@ -37,18 +39,38 @@ public class ChatMessageRenderer { this.client = client; } - private void setColors(MessageViewHolder holder, boolean highlight) { + private void setColors(MessageViewHolder holder, boolean highlight, boolean isServerAction) { if (highlight) { - holder.content.setTextColor(themeUtil.colors.colorForegroundHighlight); - holder.time.setTextColor(themeUtil.colors.colorForegroundHighlight); - holder.itemView.setBackgroundColor(themeUtil.colors.colorBackgroundHighlight); + applyStyle(holder, + themeUtil.colors.colorForegroundHighlight, + Typeface.NORMAL, + themeUtil.colors.colorForegroundHighlight, + themeUtil.colors.colorBackgroundHighlight + ); + } else if (isServerAction) { + applyStyle(holder, + themeUtil.colors.colorForegroundSecondary, + Typeface.ITALIC, + themeUtil.colors.colorForegroundSecondary, + themeUtil.colors.colorBackgroundSecondary + ); } else { - holder.content.setTextColor(themeUtil.colors.colorForeground); - holder.time.setTextColor(themeUtil.colors.colorForegroundSecondary); - holder.itemView.setBackgroundColor(themeUtil.colors.transparent); + applyStyle(holder, + themeUtil.colors.colorForeground, + Typeface.NORMAL, + themeUtil.colors.colorForegroundSecondary, + themeUtil.colors.transparent + ); } } + private void applyStyle(MessageViewHolder holder, @ColorInt int textColor, int style, @ColorInt int timeColor, @ColorInt int bgColor) { + holder.content.setTextColor(textColor); + holder.content.setTypeface(null, style); + holder.time.setTextColor(timeColor); + holder.itemView.setBackgroundColor(bgColor); + } + private CharSequence formatNick(String hostmask, boolean full) { CharSequence formattedNick = helper.formatUserNick(IrcUserUtils.getNick(hostmask)); if (full) { @@ -161,61 +183,78 @@ public class ChatMessageRenderer { } public void onBind(MessageViewHolder holder, Message message) { - setColors(holder, message.flags.Highlight); holder.time.setText(format.print(message.time)); switch (message.type) { case Plain: + setColors(holder, message.flags.Highlight, false); onBindPlain(holder, message); break; case Notice: + setColors(holder, message.flags.Highlight, false); onBindNotice(holder, message); break; case Action: + setColors(holder, message.flags.Highlight, false); onBindAction(holder, message); break; case Nick: + setColors(holder, message.flags.Highlight, true); onBindNick(holder, message); break; case Mode: + setColors(holder, message.flags.Highlight, true); onBindMode(holder, message); break; case Join: + setColors(holder, message.flags.Highlight, true); onBindJoin(holder, message); break; case Part: + setColors(holder, message.flags.Highlight, true); onBindPart(holder, message); break; case Quit: + setColors(holder, message.flags.Highlight, true); onBindQuit(holder, message); break; case Kick: + setColors(holder, message.flags.Highlight, true); onBindKick(holder, message); break; case Kill: + setColors(holder, message.flags.Highlight, true); onBindKill(holder, message); break; case Server: + setColors(holder, message.flags.Highlight, false); onBindServer(holder, message); break; case Info: + setColors(holder, message.flags.Highlight, false); onBindInfo(holder, message); break; case Error: + setColors(holder, message.flags.Highlight, false); onBindError(holder, message); break; case DayChange: + setColors(holder, message.flags.Highlight, true); onBindDayChange(holder, message); break; case Topic: + setColors(holder, message.flags.Highlight, true); onBindTopic(holder, message); break; case NetsplitJoin: + setColors(holder, message.flags.Highlight, true); onBindNetsplitJoin(holder, message); break; case NetsplitQuit: + setColors(holder, message.flags.Highlight, true); onBindNetsplitQuit(holder, message); break; case Invite: + setColors(holder, message.flags.Highlight, true); onBindInvite(holder, message); break; } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.java index 446c930005fb5e3ba256fc13bafdfe4ac74f3fa5..bb9376ec38be5014687b3d7af3e0823cb73d3d41 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MainActivity.java @@ -17,11 +17,9 @@ import android.support.v7.widget.AppCompatImageButton; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; -import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.EditText; -import android.widget.ScrollView; import android.widget.Toast; import com.google.common.collect.Sets; @@ -66,6 +64,7 @@ import de.kuschku.quasseldroid_ng.QuasselService; import de.kuschku.quasseldroid_ng.R; import de.kuschku.quasseldroid_ng.util.CompatibilityUtils; import de.kuschku.quasseldroid_ng.util.ServerAddress; +import de.kuschku.util.observablelists.AutoScroller; import de.kuschku.util.backports.Stream; public class MainActivity extends AppCompatActivity { @@ -77,8 +76,6 @@ public class MainActivity extends AppCompatActivity { private static final String KEY_USER = "beta_username"; private static final String KEY_PASS = "beta_password"; - SharedPreferences pref; - @Bind(R.id.toolbar) Toolbar toolbar; @@ -104,6 +101,7 @@ public class MainActivity extends AppCompatActivity { AccountHeader header; MessageAdapter adapter; + SharedPreferences pref; QuasselService.LocalBinder binder; private ServiceConnection serviceConnection = new ServiceConnection() { @@ -112,12 +110,14 @@ public class MainActivity extends AppCompatActivity { MainActivity.this.binder = (QuasselService.LocalBinder) service; if (binder.getBackgroundThread() != null) { handler = binder.getBackgroundThread().handler; + provider = binder.getBackgroundThread().provider; + provider.event.register(MainActivity.this); toolbar.setSubtitle(binder.getBackgroundThread().connection.getStatus().name()); if (bufferId != -1) switchBuffer(bufferId); if (bufferViewId != -1) switchBufferView(bufferViewId); - // Horrible hack to load bufferviews back, should use ObservableList + // Horrible hack to load bufferviews back, should use ObservableSortedList Client client = handler == null ? null : handler.getClient(); BufferViewManager bufferViewManager = client == null ? null : client.getBufferViewManager(); Map<Integer, BufferViewConfig> bufferViews = bufferViewManager == null ? null : bufferViewManager.BufferViews; @@ -134,17 +134,20 @@ public class MainActivity extends AppCompatActivity { }; private IProtocolHandler handler; + private BusProvider provider; + private int bufferId; private int bufferViewId; - private BusProvider provider; private ItemAdapter<IDrawerItem> hackyHistoryAdapter = new ItemAdapter<>(); @Override protected void onCreate(Bundle savedInstanceState) { + pref = getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE); // TODO: ADD THEME SELECTION setTheme(R.style.Quassel); + super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); @@ -152,16 +155,27 @@ public class MainActivity extends AppCompatActivity { setSupportActionBar(toolbar); - pref = getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE); - adapter = new MessageAdapter(this); - // This fixes a horrible bug android has where opening the keyboard doesn’t resize the layout KeyboardUtil keyboardUtil = new KeyboardUtil(this, slidingLayout); keyboardUtil.enable(); + initServive(); + + initDrawer(savedInstanceState); + + initMessageList(); + + initSendCallbacks(); + + initMsgHistory(); + } + + private void initServive() { startService(new Intent(this, QuasselService.class)); bindService(new Intent(this, QuasselService.class), serviceConnection, BIND_AUTO_CREATE); + } + private void initDrawer(Bundle savedInstanceState) { header = new AccountHeaderBuilder() .withActivity(this) .withHeaderBackground(R.drawable.bg) @@ -239,14 +253,9 @@ public class MainActivity extends AppCompatActivity { } drawer.addStickyFooterItem(new PrimaryDrawerItem().withName("(Re-)Connect").withIcon(R.drawable.ic_server_light)); + } - messages.setAdapter(adapter); - messages.setLayoutManager(new LinearLayoutManager(this)); - swipeView.setOnRefreshListener(() -> { - if (handler != null) handler.getClient().getBacklogManager().requestMoreBacklog(bufferId, 20); - else swipeView.setRefreshing(false); - }); - + private void initSendCallbacks() { send.setOnClickListener(view -> { sendInput(); }); @@ -256,7 +265,9 @@ public class MainActivity extends AppCompatActivity { return false; }); + } + private void initMsgHistory() { slidingLayout.setScrollableView(msgHistory); FastAdapter<IDrawerItem> adapter = new FastAdapter<>(); hackyHistoryAdapter.wrap(adapter); @@ -264,6 +275,17 @@ public class MainActivity extends AppCompatActivity { msgHistory.setLayoutManager(new LinearLayoutManager(this)); } + private void initMessageList() { + LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true); + adapter = new MessageAdapter(this, new AutoScroller(messages, layoutManager)); + messages.setAdapter(adapter); + messages.setLayoutManager(layoutManager); + swipeView.setOnRefreshListener(() -> { + if (handler != null) handler.getClient().getBacklogManager().requestMoreBacklog(bufferId, 20); + else swipeView.setRefreshing(false); + }); + } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MessageAdapter.java b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MessageAdapter.java index c95fac8ab873026b753a5f6185747aaff3d1a8fd..d4d0369d56f634aee18295cc98fbde8d99ea021d 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MessageAdapter.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/MessageAdapter.java @@ -8,14 +8,18 @@ import android.view.ViewGroup; import de.kuschku.libquassel.Client; import de.kuschku.libquassel.message.Message; import de.kuschku.quasseldroid_ng.R; -import de.kuschku.util.ObservableList; +import de.kuschku.util.observablelists.AutoScroller; +import de.kuschku.util.observablelists.ObservableSortedList; +import de.kuschku.util.observablelists.RecyclerViewAdapterCallback; public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> { - private ObservableList<Message> messageList = new ObservableList<>(Message.class); + private final AutoScroller scroller; + private ObservableSortedList<Message> messageList = new ObservableSortedList<>(Message.class); private ChatMessageRenderer renderer; private LayoutInflater inflater; - public MessageAdapter(Context ctx) { + public MessageAdapter(Context ctx, AutoScroller scroller) { + this.scroller = scroller; this.inflater = LayoutInflater.from(ctx); this.renderer = new ChatMessageRenderer(ctx); } @@ -24,10 +28,10 @@ public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> { renderer.setClient(client); } - public void setMessageList(ObservableList<Message> messageList) { + public void setMessageList(ObservableSortedList<Message> messageList) { this.messageList.setCallback(null); this.messageList = messageList; - this.messageList.setCallback(new ObservableList.RecyclerViewAdapterCallback(this)); + this.messageList.setCallback(new RecyclerViewAdapterCallback(this, scroller)); notifyDataSetChanged(); } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/IrcFormatHelper.java b/app/src/main/java/de/kuschku/quasseldroid_ng/util/IrcFormatHelper.java index 51e506ee7145f5a46bd54a9f88c07c9125d672d0..8e272224f5c55d3b7c297e6b525fc77b0947ca55 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/IrcFormatHelper.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/IrcFormatHelper.java @@ -1,13 +1,39 @@ package de.kuschku.quasseldroid_ng.util; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; import android.graphics.Typeface; +import android.net.Uri; +import android.os.Parcel; +import android.provider.Browser; +import android.text.ParcelableSpan; import android.text.SpannableString; import android.text.Spanned; +import android.text.TextUtils; +import android.text.style.ClickableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; +import android.text.style.URLSpan; +import android.util.Log; +import android.view.View; + +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.kuschku.quasseldroid_ng.R; public class IrcFormatHelper { + private static final String scheme = "(?:(?:mailto:|(?:[+.-]?\\w)+://)|www(?=\\.\\S+\\.))"; + private static final String authority = "(?:(?:[,.;@:]?[-\\w]+)+\\.?|\\[[0-9a-f:.]+\\])(?::\\d+)?"; + private static final String urlChars = "(?:[,.;:]*[\\w~@/?&=+$()!%#*-])"; + private static final String urlEnd = "(?:>|[,.;:\"]*\\s|\\b|$)"; + private static final Pattern urlPattern = Pattern.compile(String.format("\\b(%s%s(?:/%s*)?)%s", scheme, authority, urlChars, urlEnd), Pattern.CASE_INSENSITIVE); + private static final Pattern channelPattern = Pattern.compile("((?:#|![A-Z0-9]{5})[^,:\\s]+(?::[^,:\\s]+)?)\\b", Pattern.CASE_INSENSITIVE); + private final ThemeUtil.Colors colors; public IrcFormatHelper(ThemeUtil.Colors colors) { @@ -25,7 +51,71 @@ public class IrcFormatHelper { } public CharSequence formatIrcMessage(String message) { + List<FutureClickableSpan> spans = new LinkedList<>(); + SpannableString str = new SpannableString(message); + Matcher urlMatcher = urlPattern.matcher(str); + while (urlMatcher.find()) { + spans.add(new FutureClickableSpan(new CustomURLSpan(urlMatcher.toString()), urlMatcher.start(), urlMatcher.end())); + } + for (FutureClickableSpan span : spans) { + str.setSpan(span.span, span.start, span.end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } return str; } + + private static class FutureClickableSpan { + public final ClickableSpan span; + public final int start; + public final int end; + + public FutureClickableSpan(ClickableSpan span, int start, int end) { + this.span = span; + this.start = start; + this.end = end; + } + } + + private class CustomURLSpan extends ClickableSpan implements ParcelableSpan { + private final String mURL; + + public CustomURLSpan(String url) { + mURL = url; + } + + public CustomURLSpan(Parcel src) { + mURL = src.readString(); + } + + public int getSpanTypeId() { + return R.id.custom_url_span; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mURL); + } + + public String getURL() { + return mURL; + } + + @Override + public void onClick(View widget) { + Log.e("TEST", "THIS IS A TEST"); + + Uri uri = Uri.parse(getURL()); + Context context = widget.getContext(); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString()); + } + } + } } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ThemeUtil.java b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ThemeUtil.java index 10927d4998c72fdf55ca1338ef1b70b44a764339..514fdc1954f2d18637a9383075854da741a9d394 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/ThemeUtil.java +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/ThemeUtil.java @@ -5,116 +5,71 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.support.annotation.ColorInt; +import butterknife.BindColor; +import butterknife.ButterKnife; import de.kuschku.quasseldroid_ng.R; +import de.kuschku.util.annotationbind.Binder; +import de.kuschku.util.annotationbind.Color; public class ThemeUtil { public final Colors colors = new Colors(); - private static final int[] ATTRS_SENDER = { - // sender colors - R.attr.senderColor0, - R.attr.senderColor1, - R.attr.senderColor2, - R.attr.senderColor3, - R.attr.senderColor4, - R.attr.senderColor5, - R.attr.senderColor6, - R.attr.senderColor7, - R.attr.senderColor8, - R.attr.senderColor9, - R.attr.senderColorA, - R.attr.senderColorB, - R.attr.senderColorC, - R.attr.senderColorD, - R.attr.senderColorE, - R.attr.senderColorF, - }; - - private static final int[] ATTRS_MIRC = { - // mirc colors - R.attr.mircColor0, - R.attr.mircColor1, - R.attr.mircColor2, - R.attr.mircColor3, - R.attr.mircColor4, - R.attr.mircColor5, - R.attr.mircColor6, - R.attr.mircColor7, - R.attr.mircColor8, - R.attr.mircColor9, - R.attr.mircColorA, - R.attr.mircColorB, - R.attr.mircColorC, - R.attr.mircColorD, - R.attr.mircColorE, - R.attr.mircColorF, - }; - - private static final int[] ATTRS_GENERAL = { - // General UI colors - R.attr.colorForeground, - R.attr.colorForegroundHighlight, - R.attr.colorForegroundSecondary, - - R.attr.colorBackground, - R.attr.colorBackgroundHighlight, - R.attr.colorBackgroundCard, - }; - - private static final int[] ATTRS_TINT = { - // Tint colors - R.attr.colorTintActivity, - R.attr.colorTintMessage, - R.attr.colorTintHighlight - }; - public ThemeUtil(Context ctx) { initColors(ctx.getTheme()); } public void initColors(Resources.Theme theme) { - TypedArray arr; - - arr = theme.obtainStyledAttributes(ATTRS_SENDER); - for (int i = 0; i < colors.senderColors.length;i++) { - colors.senderColors[i] = arr.getColor(i, colors.transparent); - } - arr.recycle(); - - arr = theme.obtainStyledAttributes(ATTRS_MIRC); - for (int i = 0; i < colors.senderColors.length;i++) { - colors.mircColors[i] = arr.getColor(i, colors.transparent); + try { + Binder.bind(colors, theme); + } catch (IllegalAccessException e) { + e.printStackTrace(); } - arr.recycle(); - - arr = theme.obtainStyledAttributes(ATTRS_GENERAL); - colors.colorForeground = arr.getColor(0, colors.transparent); - colors.colorForegroundHighlight = arr.getColor(1, colors.transparent); - colors.colorForegroundSecondary = arr.getColor(2, colors.transparent); - colors.colorBackground = arr.getColor(3, colors.transparent); - colors.colorBackgroundHighlight = arr.getColor(4, colors.transparent); - colors.colorBackgroundCard = arr.getColor(5, colors.transparent); - arr.recycle(); - - arr = theme.obtainStyledAttributes(ATTRS_TINT); - colors.colorTintActivity = arr.getColor(0, colors.transparent); - colors.colorTintMessage = arr.getColor(1, colors.transparent); - colors.colorTintHighlight = arr.getColor(2, colors.transparent); - arr.recycle(); } public static class Colors { - @ColorInt public int transparent = 0x00000000; - @ColorInt public int[] senderColors = new int[16]; - @ColorInt public int[] mircColors = new int[16]; - @ColorInt public int colorForeground = 0x00000000; - @ColorInt public int colorForegroundHighlight = 0x00000000; - @ColorInt public int colorForegroundSecondary = 0x00000000; - @ColorInt public int colorBackground = 0x00000000; - @ColorInt public int colorBackgroundHighlight = 0x00000000; - @ColorInt public int colorBackgroundCard = 0x00000000; - @ColorInt public int colorTintActivity = 0x00000000; - @ColorInt public int colorTintMessage = 0x00000000; - @ColorInt public int colorTintHighlight = 0x00000000; + @Color(android.R.color.transparent) + @ColorInt public int transparent; + + @Color({R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3, + R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7, + R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB, + R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF}) + @ColorInt public int[] senderColors; + + @Color({R.attr.mircColor0, R.attr.mircColor1, R.attr.mircColor2, R.attr.mircColor3, + R.attr.mircColor4, R.attr.mircColor5, R.attr.mircColor6, R.attr.mircColor7, + R.attr.mircColor8, R.attr.mircColor9, R.attr.mircColorA, R.attr.mircColorB, + R.attr.mircColorC, R.attr.mircColorD, R.attr.mircColorE, R.attr.mircColorF}) + @ColorInt public int[] mircColors; + + @Color(R.attr.colorForeground) + @ColorInt public int colorForeground; + + @Color(R.attr.colorForegroundHighlight) + @ColorInt public int colorForegroundHighlight; + + @Color(R.attr.colorForegroundSecondary) + @ColorInt public int colorForegroundSecondary; + + @Color(R.attr.colorBackground) + @ColorInt public int colorBackground; + + @Color(R.attr.colorBackgroundHighlight) + @ColorInt public int colorBackgroundHighlight; + + @Color(R.attr.colorBackgroundSecondary) + @ColorInt public int colorBackgroundSecondary; + + @Color(R.attr.colorBackgroundCard) + @ColorInt public int colorBackgroundCard; + + @Color(R.attr.colorTintActivity) + @ColorInt public int colorTintActivity; + + @Color(R.attr.colorTintMessage) + @ColorInt public int colorTintMessage; + + @Color(R.attr.colorTintHighlight) + @ColorInt public int colorTintHighlight; } } diff --git a/app/src/main/java/de/kuschku/util/ObservableList.java b/app/src/main/java/de/kuschku/util/ObservableList.java deleted file mode 100644 index b3c37813fc342d26a37d10c98ecb0c50b718be6a..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/util/ObservableList.java +++ /dev/null @@ -1,144 +0,0 @@ -package de.kuschku.util; - -import android.support.v7.util.SortedList; -import android.support.v7.widget.RecyclerView; - -public class ObservableList<T extends ContentComparable<T>> { - public final SortedList<T> list; - Callback internal = new Callback(); - UICallback callback; - RecyclerView.Adapter x; - - public ObservableList(Class<T> cl) { - list = new SortedList<>(cl, internal); - } - - public ObservableList(Class<T> cl, int initialcapacity) { - list = new SortedList<>(cl, internal, initialcapacity); - } - - public void setCallback(UICallback callback) { - this.callback = callback; - } - - public T last() { - if (list.size() == 0) return null; - - return list.get(list.size() - 1); - } - - public T first() { - if (list.size() == 0) return null; - - return list.get(0); - } - - public interface UICallback { - void notifyItemInserted(int position); - - void notifyItemChanged(int position); - - void notifyItemRemoved(int position); - - void notifyItemMoved(int from, int to); - - void notifyItemRangeInserted(int position, int count); - - void notifyItemRangeChanged(int position, int count); - - void notifyItemRangeRemoved(int position, int count); - } - - public static class RecyclerViewAdapterCallback implements UICallback { - private final RecyclerView.Adapter adapter; - - public RecyclerViewAdapterCallback(RecyclerView.Adapter adapter) { - this.adapter = adapter; - } - - @Override - public void notifyItemInserted(int position) { - adapter.notifyItemInserted(position); - } - - @Override - public void notifyItemChanged(int position) { - adapter.notifyItemChanged(position); - } - - @Override - public void notifyItemRemoved(int position) { - adapter.notifyItemRemoved(position); - } - - @Override - public void notifyItemMoved(int from, int to) { - adapter.notifyItemMoved(from, to); - } - - @Override - public void notifyItemRangeInserted(int position, int count) { - adapter.notifyItemRangeInserted(position, count); - } - - @Override - public void notifyItemRangeChanged(int position, int count) { - adapter.notifyItemRangeChanged(position, count); - } - - @Override - public void notifyItemRangeRemoved(int position, int count) { - adapter.notifyItemRangeRemoved(position, count); - } - } - - class Callback extends SortedList.Callback<T> { - @Override - public int compare(T o1, T o2) { - return o1.compareTo(o2); - } - - @Override - public void onInserted(int position, int count) { - if (callback != null) - if (count == 1) - callback.notifyItemInserted(position); - else - callback.notifyItemRangeInserted(position, count); - } - - @Override - public void onRemoved(int position, int count) { - if (callback != null) - if (count == 1) - callback.notifyItemRemoved(position); - else - callback.notifyItemRangeRemoved(position, count); - } - - @Override - public void onMoved(int fromPosition, int toPosition) { - if (callback != null) - callback.notifyItemMoved(fromPosition, toPosition); - } - - @Override - public void onChanged(int position, int count) { - if (callback != null) - if (count == 1) - callback.notifyItemChanged(position); - else - callback.notifyItemRangeChanged(position, count); - } - - @Override - public boolean areContentsTheSame(T oldItem, T newItem) { - return oldItem.equalsContent(newItem); - } - - @Override - public boolean areItemsTheSame(T item1, T item2) { - return item1.equals(item2); - } - } -} diff --git a/app/src/main/java/de/kuschku/util/SortedListWrapper.java b/app/src/main/java/de/kuschku/util/SortedListWrapper.java deleted file mode 100644 index a50824ce1e6b0847d422a6119881b361f9f8f8ac..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/util/SortedListWrapper.java +++ /dev/null @@ -1,144 +0,0 @@ -package de.kuschku.util; - -import android.support.annotation.NonNull; -import android.support.v7.util.SortedList; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -import de.kuschku.util.backports.Stream; - -public class SortedListWrapper<T> implements List<T> { - final SortedList<T> list; - - public SortedListWrapper(SortedList<T> list) { - this.list = list; - } - - - @Override - public void add(int location, T object) { - list.add(object); - } - - @Override - public boolean add(T object) { - list.add(object); - return false; - } - - @Override - public boolean addAll(int location, @NonNull Collection<? extends T> collection) { - list.addAll((Collection<T>) collection); - return false; - } - - @Override - public boolean addAll(@NonNull Collection<? extends T> collection) { - list.addAll((Collection<T>) collection); - return false; - } - - @Override - public void clear() { - list.clear(); - } - - @Override - public boolean contains(Object object) { - return indexOf(object) != SortedList.INVALID_POSITION; - } - - @Override - public boolean containsAll(@NonNull Collection<?> collection) { - return new Stream<>(collection).allMatch(this::contains); - } - - @Override - public T get(int location) { - return get(location); - } - - @Override - public int indexOf(Object object) { - return list.indexOf((T) object); - } - - @Override - public boolean isEmpty() { - return list.size() == 0; - } - - @NonNull - @Override - public Iterator<T> iterator() { - return null; - } - - @Override - public int lastIndexOf(Object object) { - return indexOf(object); - } - - @Override - public ListIterator<T> listIterator() { - return null; - } - - @Override - public ListIterator<T> listIterator(int location) { - return null; - } - - @Override - public T remove(int location) { - T val = get(location); - remove(val); - return val; - } - - @Override - public boolean remove(Object object) { - return list.remove((T) object); - } - - @Override - public boolean removeAll(Collection<?> collection) { - return new Stream<>(collection).anyMatch(this::remove); - } - - @Override - public boolean retainAll(Collection<?> collection) { - return false; - } - - @Override - public T set(int location, T object) { - return null; - } - - @Override - public int size() { - return list.size(); - } - - @NonNull - @Override - public List<T> subList(int start, int end) { - return null; - } - - @NonNull - @Override - public Object[] toArray() { - return new Object[0]; - } - - @NonNull - @Override - public <T1> T1[] toArray(T1[] array) { - return null; - } -} diff --git a/app/src/main/java/de/kuschku/util/annotationbind/Binder.java b/app/src/main/java/de/kuschku/util/annotationbind/Binder.java new file mode 100644 index 0000000000000000000000000000000000000000..067dc9ca1f9b9bad9585eaaf14c547343fff7ea5 --- /dev/null +++ b/app/src/main/java/de/kuschku/util/annotationbind/Binder.java @@ -0,0 +1,43 @@ +package de.kuschku.util.annotationbind; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.support.annotation.ColorInt; + +import java.lang.reflect.Field; + +public class Binder { + private Binder() { + + } + + public static void bind(Object o, Resources.Theme t) throws IllegalAccessException { + for (Field f : o.getClass().getFields()) { + if (f.isAnnotationPresent(Color.class)) { + int[] colors = obtainColors(f.getAnnotation(Color.class).value(), t); + if (f.getType().isArray()) + f.set(o, colors); + else if (colors.length == 1) + f.set(o, colors[0]); + else + throw new IllegalAccessException("Field length does not correspond to argument length"); + } + } + } + + public static void bind(Object o, Context t) throws IllegalAccessException { + bind(o, t.getTheme()); + } + + @ColorInt + private static int[] obtainColors(int[] res, Resources.Theme theme) { + int[] result = new int[res.length]; + TypedArray t = theme.obtainStyledAttributes(res); + for (int i = 0; i < res.length; i++) { + result[i] = t.getColor(i, 0x00000000); + } + t.recycle(); + return result; + } +} diff --git a/app/src/main/java/de/kuschku/util/annotationbind/Color.java b/app/src/main/java/de/kuschku/util/annotationbind/Color.java new file mode 100644 index 0000000000000000000000000000000000000000..833948443bb4fe8ff92899a8a4d167f42f84ac29 --- /dev/null +++ b/app/src/main/java/de/kuschku/util/annotationbind/Color.java @@ -0,0 +1,12 @@ +package de.kuschku.util.annotationbind; + +import android.support.annotation.AnyRes; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Color { + @AnyRes + int[] value() default {}; +} diff --git a/app/src/main/java/de/kuschku/util/observablelists/AutoScroller.java b/app/src/main/java/de/kuschku/util/observablelists/AutoScroller.java new file mode 100644 index 0000000000000000000000000000000000000000..2ac3aead373c38d34110243e1dcb2435ab46cd9d --- /dev/null +++ b/app/src/main/java/de/kuschku/util/observablelists/AutoScroller.java @@ -0,0 +1,19 @@ +package de.kuschku.util.observablelists; + +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; + +public class AutoScroller { + private final RecyclerView recyclerView; + private final LinearLayoutManager manager; + + public AutoScroller(RecyclerView recyclerView, LinearLayoutManager manager) { + this.recyclerView = recyclerView; + this.manager = manager; + } + + public void notifyScroll() { + if (manager.findFirstVisibleItemPosition() == 0) + manager.smoothScrollToPosition(recyclerView, null, 0); + } +} diff --git a/app/src/main/java/de/kuschku/util/ContentComparable.java b/app/src/main/java/de/kuschku/util/observablelists/ContentComparable.java similarity index 76% rename from app/src/main/java/de/kuschku/util/ContentComparable.java rename to app/src/main/java/de/kuschku/util/observablelists/ContentComparable.java index b6142b656fdc13da32b00fa2dfac914d7f136401..818c6152160a83d8457927d4101ba80496a120b8 100644 --- a/app/src/main/java/de/kuschku/util/ContentComparable.java +++ b/app/src/main/java/de/kuschku/util/observablelists/ContentComparable.java @@ -1,4 +1,4 @@ -package de.kuschku.util; +package de.kuschku.util.observablelists; public interface ContentComparable<T extends ContentComparable<T>> extends Comparable<T> { boolean equalsContent(T other); diff --git a/app/src/main/java/de/kuschku/util/observablelists/ObservableList.java b/app/src/main/java/de/kuschku/util/observablelists/ObservableList.java new file mode 100644 index 0000000000000000000000000000000000000000..f6823c0ee4c425a45c2fd0f87883cd3448e8a5b6 --- /dev/null +++ b/app/src/main/java/de/kuschku/util/observablelists/ObservableList.java @@ -0,0 +1,110 @@ +package de.kuschku.util.observablelists; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +public class ObservableList<T> extends ArrayList<T> { + UICallback callback; + + public void setCallback(UICallback callback) { + this.callback = callback; + } + + private int getPosition() { + return isEmpty() ? 0 : size() - 1; + } + + @Override + public boolean add(T object) { + add(getPosition(), object); + return true; + } + + @Override + public void add(int index, T object) { + super.add(index, object); + callback.notifyItemInserted(index); + } + + @Override + public boolean addAll(Collection<? extends T> collection) { + return addAll(getPosition(), collection); + } + + @Override + public boolean addAll(int index, Collection<? extends T> collection) { + boolean result = super.addAll(index, collection); + if (result) callback.notifyItemRangeInserted(index, collection.size()); + return result; + } + + @Override + public T remove(int index) { + T result = super.remove(index); + callback.notifyItemRemoved(index); + return result; + } + + @Override + public boolean remove(Object object) { + int position = indexOf(object); + if (position == -1) { + return false; + } else { + remove(position); + callback.notifyItemRemoved(position); + return true; + } + } + + @Override + protected void removeRange(int fromIndex, int toIndex) { + super.removeRange(fromIndex, toIndex); + callback.notifyItemRangeRemoved(fromIndex, toIndex - fromIndex); + } + + @Override + public boolean removeAll(@NonNull Collection<?> collection) { + return super.removeAll(collection); + } + + @Override + public boolean retainAll(@NonNull Collection<?> collection) { + return super.retainAll(collection); + } + + @NonNull + @Override + public Iterator<T> iterator() { + return new CallbackedArrayListIterator<>(super.iterator()); + } + + class CallbackedArrayListIterator<E> implements Iterator<E> { + final Iterator<E> iterator; + int position = 0; + + public CallbackedArrayListIterator(Iterator<E> iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public E next() { + position++; + return iterator.next(); + } + + @Override + public void remove() { + iterator.remove(); + callback.notifyItemRemoved(position); + } + } +} diff --git a/app/src/main/java/de/kuschku/util/observablelists/ObservableSortedList.java b/app/src/main/java/de/kuschku/util/observablelists/ObservableSortedList.java new file mode 100644 index 0000000000000000000000000000000000000000..fef28bb8fa87e6675779a3b83ee080f2726f99c2 --- /dev/null +++ b/app/src/main/java/de/kuschku/util/observablelists/ObservableSortedList.java @@ -0,0 +1,79 @@ +package de.kuschku.util.observablelists; + +import android.support.v7.util.SortedList; + +public class ObservableSortedList<T extends ContentComparable<T>> { + public final SortedList<T> list; + Callback internal = new Callback(); + UICallback callback; + boolean reverse; + + public ObservableSortedList(Class<T> cl) { + list = new SortedList<>(cl, internal); + } + + public ObservableSortedList(Class<T> cl, boolean reverse) { + this(cl); + this.reverse = reverse; + } + + public void setCallback(UICallback callback) { + this.callback = callback; + } + + public T last() { + if (list.size() == 0) return null; + + return list.get(list.size() - 1); + } + + class Callback extends SortedList.Callback<T> { + @Override + public int compare(T o1, T o2) { + return (reverse) ? o2.compareTo(o1): o1.compareTo(o2); + } + + @Override + public void onInserted(int position, int count) { + if (callback != null) + if (count == 1) + callback.notifyItemInserted(position); + else + callback.notifyItemRangeInserted(position, count); + } + + @Override + public void onRemoved(int position, int count) { + if (callback != null) + if (count == 1) + callback.notifyItemRemoved(position); + else + callback.notifyItemRangeRemoved(position, count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + if (callback != null) + callback.notifyItemMoved(fromPosition, toPosition); + } + + @Override + public void onChanged(int position, int count) { + if (callback != null) + if (count == 1) + callback.notifyItemChanged(position); + else + callback.notifyItemRangeChanged(position, count); + } + + @Override + public boolean areContentsTheSame(T oldItem, T newItem) { + return oldItem.equalsContent(newItem); + } + + @Override + public boolean areItemsTheSame(T item1, T item2) { + return item1.equals(item2); + } + } +} diff --git a/app/src/main/java/de/kuschku/util/observablelists/RecyclerViewAdapterCallback.java b/app/src/main/java/de/kuschku/util/observablelists/RecyclerViewAdapterCallback.java new file mode 100644 index 0000000000000000000000000000000000000000..7a59f28235010207eabd2588fa522ac8306d4e9b --- /dev/null +++ b/app/src/main/java/de/kuschku/util/observablelists/RecyclerViewAdapterCallback.java @@ -0,0 +1,50 @@ +package de.kuschku.util.observablelists; + +import android.support.v7.widget.RecyclerView; + +public class RecyclerViewAdapterCallback implements UICallback { + private final RecyclerView.Adapter adapter; + private final AutoScroller scroller; + + public RecyclerViewAdapterCallback(RecyclerView.Adapter adapter, AutoScroller scroller) { + this.adapter = adapter; + this.scroller = scroller; + } + + @Override + public void notifyItemInserted(int position) { + adapter.notifyItemInserted(position); + if (position == 0) scroller.notifyScroll(); + } + + @Override + public void notifyItemChanged(int position) { + adapter.notifyItemChanged(position); + } + + @Override + public void notifyItemRemoved(int position) { + adapter.notifyItemRemoved(position); + } + + @Override + public void notifyItemMoved(int from, int to) { + adapter.notifyItemMoved(from, to); + } + + @Override + public void notifyItemRangeInserted(int position, int count) { + adapter.notifyItemRangeInserted(position, count); + if (position == 0) scroller.notifyScroll(); + } + + @Override + public void notifyItemRangeChanged(int position, int count) { + adapter.notifyItemRangeChanged(position, count); + } + + @Override + public void notifyItemRangeRemoved(int position, int count) { + adapter.notifyItemRangeRemoved(position, count); + } +} diff --git a/app/src/main/java/de/kuschku/util/observablelists/UICallback.java b/app/src/main/java/de/kuschku/util/observablelists/UICallback.java new file mode 100644 index 0000000000000000000000000000000000000000..124f9261a360f5569e1078b09c48f4bf77373b0e --- /dev/null +++ b/app/src/main/java/de/kuschku/util/observablelists/UICallback.java @@ -0,0 +1,17 @@ +package de.kuschku.util.observablelists; + +public interface UICallback { + void notifyItemInserted(int position); + + void notifyItemChanged(int position); + + void notifyItemRemoved(int position); + + void notifyItemMoved(int from, int to); + + void notifyItemRangeInserted(int position, int count); + + void notifyItemRangeChanged(int position, int count); + + void notifyItemRangeRemoved(int position, int count); +} diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index bb2d26152e8c13ab4d1d0a16e3f8cb86de7e9fe5..dfda993f9f055c5cd41de62db1a0c6780018dd7e 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -9,6 +9,7 @@ <android.support.v7.widget.RecyclerView android:id="@+id/messages" + android:clickable="true" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/slider_main.xml b/app/src/main/res/layout/slider_main.xml index a09fc45a4b3f4f53420394837e7b042b644d0aed..0b34d0308d901000cceea50dfa745bc32a1e47a2 100644 --- a/app/src/main/res/layout/slider_main.xml +++ b/app/src/main/res/layout/slider_main.xml @@ -1,6 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout - android:clickable="true" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" diff --git a/app/src/main/res/layout/widget_chatmessage.xml b/app/src/main/res/layout/widget_chatmessage.xml index 877bceca382d9a5f15f5c37fd37ef40f3df0e75d..f58de9f1e73b40374ca6883733b4923fd834299c 100644 --- a/app/src/main/res/layout/widget_chatmessage.xml +++ b/app/src/main/res/layout/widget_chatmessage.xml @@ -6,21 +6,25 @@ android:layout_height="match_parent" android:textAppearance="?android:attr/textAppearanceListItemSmall" android:gravity="top" - android:paddingStart="?android:attr/listPreferredItemPaddingStart" - android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingRight="?android:attr/listPreferredItemPaddingRight" - android:paddingTop="4dp" - android:paddingBottom="4dp" > - <TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:clickable="true" + android:paddingStart="@dimen/message_horizontal" + android:paddingLeft="@dimen/message_horizontal" + android:paddingEnd="@dimen/message_horizontal" + android:paddingRight="@dimen/message_horizontal" + android:paddingTop="@dimen/message_vertical" + android:paddingBottom="@dimen/message_vertical" > + <TextView android:id="@+id/time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:typeface="monospace" - android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" - android:paddingRight="?android:attr/listPreferredItemPaddingRight" /> - <TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:text="10:08" + android:layout_marginEnd="@dimen/message_horizontal" + android:layout_marginRight="@dimen/message_horizontal" /> + <TextView android:id="@+id/content" + android:clickable="true" + android:text="NK33 well, the issue is I need the main engines to tilt 90 degrees for vertical takeoff and landing" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" /> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 2e9ab05cbd7148030dd57c6efb9eeb9d4408234b..7a2bf40c8086a6b7f417fd852af7467a826e3ed5 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -50,6 +50,7 @@ <attr name="colorBackground" format="color" /> <attr name="colorBackgroundHighlight" format="color" /> + <attr name="colorBackgroundSecondary" format="color" /> <attr name="colorBackgroundCard" format="color" /> <!-- Tint colors for drawer --> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 812cb7be0a1565a849a29c08fa07fb9901ccb347..0222438f9a46ef8e9a898f4ce3e1d2ca95a93342 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -3,4 +3,7 @@ <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="fab_margin">16dp</dimen> + + <dimen name="message_horizontal">8dp</dimen> + <dimen name="message_vertical">4dp</dimen> </resources> diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml new file mode 100644 index 0000000000000000000000000000000000000000..1194555c60b5e25bd88dcc85705c3316b32bd690 --- /dev/null +++ b/app/src/main/res/values/ids.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <item name="custom_url_span" type="id" /> + <item name="custom_channel_span" type="id" /> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index af5d1ca069b7d6d07cbb660ee4f58799ba308e40..35f6fbc2ff72e5c4fc9ec0af0162e2bff7f12f84 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -24,6 +24,7 @@ <item name="colorBackground">@color/md_dark_background</item> <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@android:color/transparent</item> <item name="colorBackgroundCard">@color/md_dark_cards</item> <item name="colorTintActivity">#88cc33</item> @@ -55,6 +56,7 @@ <item name="colorBackground">@color/md_light_background</item> <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@android:color/transparent</item> <item name="colorBackgroundCard">@color/md_light_cards</item> <item name="colorTintActivity">#88cc33</item> @@ -86,6 +88,7 @@ <item name="colorBackground">@color/md_light_background</item> <item name="colorBackgroundHighlight">#ff8811</item> + <item name="colorBackgroundSecondary">@android:color/transparent</item> <item name="colorBackgroundCard">@color/md_light_cards</item> <item name="colorTintActivity">#88cc33</item>