From 54ecb93f3c0e6f56a20d761a89b47422bf26819d Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 9 Sep 2024 10:28:29 +0100 Subject: [PATCH 1/2] feat: use Cancellation object instead of unsubscribe methods It's proven to be easier to manage to implement when subscription return object that you can use to unsubscribe --- .gitignore | 1 + .../main/java/com/ably/chat/Cancellation.kt | 12 ++++++++ .../java/com/ably/chat/ConnectionStatus.kt | 8 +---- .../com/ably/chat/EmitsDiscontinuities.kt | 8 +---- .../src/main/java/com/ably/chat/Messages.kt | 29 +++++-------------- .../src/main/java/com/ably/chat/Occupancy.kt | 21 ++------------ .../src/main/java/com/ably/chat/Presence.kt | 20 ++----------- .../main/java/com/ably/chat/RoomReactions.kt | 19 ++---------- .../src/main/java/com/ably/chat/RoomStatus.kt | 7 +---- .../src/main/java/com/ably/chat/Typing.kt | 19 ++---------- 10 files changed, 36 insertions(+), 108 deletions(-) create mode 100644 chat-android/src/main/java/com/ably/chat/Cancellation.kt diff --git a/.gitignore b/.gitignore index 4544f87..92c9f86 100644 --- a/.gitignore +++ b/.gitignore @@ -95,6 +95,7 @@ publish.properties /.idea/compiler.xml /.idea/jarRepositories.xml /.idea/misc.xml +/.idea/shelf # general **/.DS_Store diff --git a/chat-android/src/main/java/com/ably/chat/Cancellation.kt b/chat-android/src/main/java/com/ably/chat/Cancellation.kt new file mode 100644 index 0000000..2357a1a --- /dev/null +++ b/chat-android/src/main/java/com/ably/chat/Cancellation.kt @@ -0,0 +1,12 @@ +package com.ably.chat + +/** + * A cancellation handle, returned by various functions (mostly subscriptions) + * where cancellation is required. + */ +fun interface Cancellation { + /** + * Handle cancellation (unsubscribe listeners, clean up) + */ + fun cancel() +} diff --git a/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt b/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt index 6858f50..c9cc806 100644 --- a/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt +++ b/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt @@ -25,13 +25,7 @@ interface ConnectionStatus { * Registers a listener that will be called whenever the connection status changes. * @param listener The function to call when the status changes. */ - fun on(listener: Listener) - - /** - * Unregisters a listener - * @param listener The function to call when the status changes. - */ - fun off(listener: Listener) + fun on(listener: Listener): Cancellation /** * An interface for listening to changes for the connection status diff --git a/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt b/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt index 10ffac6..6606bc2 100644 --- a/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt +++ b/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt @@ -10,13 +10,7 @@ interface EmitsDiscontinuities { * Register a listener to be called when a discontinuity is detected. * @param listener The listener to be called when a discontinuity is detected. */ - fun onDiscontinuity(listener: Listener) - - /** - * Unregister a listener to be called when a discontinuity is detected. - * @param listener The listener - */ - fun offDiscontinuity(listener: Listener) + fun onDiscontinuity(listener: Listener): Cancellation /** * An interface for listening when discontinuity happens diff --git a/chat-android/src/main/java/com/ably/chat/Messages.kt b/chat-android/src/main/java/com/ably/chat/Messages.kt index 854b147..dc47679 100644 --- a/chat-android/src/main/java/com/ably/chat/Messages.kt +++ b/chat-android/src/main/java/com/ably/chat/Messages.kt @@ -3,7 +3,6 @@ package com.ably.chat import io.ably.lib.realtime.Channel -import io.ably.lib.types.PaginatedResult /** * This interface is used to interact with messages in a chat room: subscribing @@ -24,13 +23,7 @@ interface Messages : EmitsDiscontinuities { * @param listener callback that will be called * @returns A response object that allows you to control the subscription. */ - fun subscribe(listener: Listener) - - /** - * Unsubscribe listener - * @param listener callback that will be unsubscribed - */ - fun unsubscribe(listener: Listener) + fun subscribe(listener: Listener): MessagesSubscription /** * Get messages that have been previously sent to the chat room, based on the provided options. @@ -176,6 +169,10 @@ data class SendMessageParams( val headers: MessageHeaders? = null, ) +interface MessagesSubscription : Cancellation { + suspend fun getPreviousMessages(queryOptions: QueryOptions): PaginatedResult +} + class DefaultMessages( private val roomId: String, private val realtimeClient: RealtimeClient, @@ -190,25 +187,15 @@ class DefaultMessages( override val channel: Channel get() = realtimeClient.channels.get(messagesChannelName, ChatChannelOptions()) - override fun subscribe(listener: Messages.Listener) { + override fun subscribe(listener: Messages.Listener): MessagesSubscription { TODO("Not yet implemented") } - override fun unsubscribe(listener: Messages.Listener) { - TODO("Not yet implemented") - } - - override suspend fun get(options: QueryOptions): PaginatedResult { - TODO("Not yet implemented") - } + override suspend fun get(options: QueryOptions): PaginatedResult = chatApi.getMessages(roomId, options) override suspend fun send(params: SendMessageParams): Message = chatApi.sendMessage(roomId, params) - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) { - TODO("Not yet implemented") - } - - override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/Occupancy.kt b/chat-android/src/main/java/com/ably/chat/Occupancy.kt index 62a6bb0..95be9c4 100644 --- a/chat-android/src/main/java/com/ably/chat/Occupancy.kt +++ b/chat-android/src/main/java/com/ably/chat/Occupancy.kt @@ -23,14 +23,7 @@ interface Occupancy : EmitsDiscontinuities { * * @param listener A listener to be called when the occupancy of the room changes. */ - fun subscribe(listener: Listener) - - /** - * Unsubscribe a given listener to occupancy updates of the chat room. - * - * @param listener A listener to be unsubscribed. - */ - fun unsubscribe(listener: Listener) + fun subscribe(listener: Listener): Cancellation /** * Get the current occupancy of the chat room. @@ -72,11 +65,7 @@ internal class DefaultOccupancy( override val channel: Channel get() = messages.channel - override fun subscribe(listener: Occupancy.Listener) { - TODO("Not yet implemented") - } - - override fun unsubscribe(listener: Occupancy.Listener) { + override fun subscribe(listener: Occupancy.Listener): Cancellation { TODO("Not yet implemented") } @@ -84,11 +73,7 @@ internal class DefaultOccupancy( TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) { - TODO("Not yet implemented") - } - - override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/Presence.kt b/chat-android/src/main/java/com/ably/chat/Presence.kt index ba49296..5987102 100644 --- a/chat-android/src/main/java/com/ably/chat/Presence.kt +++ b/chat-android/src/main/java/com/ably/chat/Presence.kt @@ -60,13 +60,7 @@ interface Presence : EmitsDiscontinuities { * Subscribe the given listener to all presence events. * @param listener listener to subscribe */ - fun subscribe(listener: Listener) - - /** - * Unsubscribe the given listener to all presence events. - * @param listener listener to unsubscribe - */ - fun unsubscribe(listener: Listener) + fun subscribe(listener: Listener): Cancellation /** * An interface for listening to new presence event @@ -162,19 +156,11 @@ internal class DefaultPresence( TODO("Not yet implemented") } - override fun subscribe(listener: Presence.Listener) { - TODO("Not yet implemented") - } - - override fun unsubscribe(listener: Presence.Listener) { - TODO("Not yet implemented") - } - - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun subscribe(listener: Presence.Listener): Cancellation { TODO("Not yet implemented") } - override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/RoomReactions.kt b/chat-android/src/main/java/com/ably/chat/RoomReactions.kt index f3a2d58..2c79339 100644 --- a/chat-android/src/main/java/com/ably/chat/RoomReactions.kt +++ b/chat-android/src/main/java/com/ably/chat/RoomReactions.kt @@ -38,12 +38,7 @@ interface RoomReactions : EmitsDiscontinuities { * @param listener The listener function to be called when a reaction is received. * @returns A response object that allows you to control the subscription. */ - fun subscribe(listener: Listener) - - /** - * Unsubscribe all listeners from receiving room-level reaction events. - */ - fun unsubscribe(listener: Listener) + fun subscribe(listener: Listener): Cancellation /** * An interface for listening to new reaction events @@ -116,19 +111,11 @@ internal class DefaultRoomReactions( TODO("Not yet implemented") } - override fun subscribe(listener: RoomReactions.Listener) { - TODO("Not yet implemented") - } - - override fun unsubscribe(listener: RoomReactions.Listener) { - TODO("Not yet implemented") - } - - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun subscribe(listener: RoomReactions.Listener): Cancellation { TODO("Not yet implemented") } - override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/RoomStatus.kt b/chat-android/src/main/java/com/ably/chat/RoomStatus.kt index 09f5b7a..82620b7 100644 --- a/chat-android/src/main/java/com/ably/chat/RoomStatus.kt +++ b/chat-android/src/main/java/com/ably/chat/RoomStatus.kt @@ -21,12 +21,7 @@ interface RoomStatus { * @param listener The function to call when the status changes. * @returns An object that can be used to unregister the listener. */ - fun on(listener: Listener) - - /** - * Removes all listeners that were added by the `onChange` method. - */ - fun off(listener: Listener) + fun on(listener: Listener): Cancellation /** * An interface for listening to changes for the room status diff --git a/chat-android/src/main/java/com/ably/chat/Typing.kt b/chat-android/src/main/java/com/ably/chat/Typing.kt index fa75bc2..5de49f6 100644 --- a/chat-android/src/main/java/com/ably/chat/Typing.kt +++ b/chat-android/src/main/java/com/ably/chat/Typing.kt @@ -37,12 +37,7 @@ interface Typing : EmitsDiscontinuities { * * @param listener A listener to be called when the typing state of a user in the room changes. */ - fun subscribe(listener: Listener) - - /** - * Unsubscribe listeners from receiving typing events. - */ - fun unsubscribe(listener: Listener) + fun subscribe(listener: Listener): Cancellation /** * Get the current typers, a set of clientIds. @@ -89,11 +84,7 @@ internal class DefaultTyping( override val channel: Channel get() = realtimeClient.channels.get(typingIndicatorsChannelName, ChatChannelOptions()) - override fun subscribe(listener: Typing.Listener) { - TODO("Not yet implemented") - } - - override fun unsubscribe(listener: Typing.Listener) { + override fun subscribe(listener: Typing.Listener): Cancellation { TODO("Not yet implemented") } @@ -109,11 +100,7 @@ internal class DefaultTyping( TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener) { - TODO("Not yet implemented") - } - - override fun offDiscontinuity(listener: EmitsDiscontinuities.Listener) { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { TODO("Not yet implemented") } } From f5b2078981fc66e2ced91ac0e21f52dd10aed0c0 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 17 Sep 2024 12:45:15 +0100 Subject: [PATCH 2/2] chore: rename `Cancellation` to `Subscription` to avoid confusions with coroutine cancellation --- .../src/main/java/com/ably/chat/Cancellation.kt | 12 ------------ .../src/main/java/com/ably/chat/ConnectionStatus.kt | 2 +- .../main/java/com/ably/chat/EmitsDiscontinuities.kt | 2 +- chat-android/src/main/java/com/ably/chat/Messages.kt | 4 ++-- .../src/main/java/com/ably/chat/Occupancy.kt | 6 +++--- chat-android/src/main/java/com/ably/chat/Presence.kt | 6 +++--- .../src/main/java/com/ably/chat/RoomReactions.kt | 6 +++--- .../src/main/java/com/ably/chat/RoomStatus.kt | 2 +- .../src/main/java/com/ably/chat/Subscription.kt | 12 ++++++++++++ chat-android/src/main/java/com/ably/chat/Typing.kt | 6 +++--- 10 files changed, 29 insertions(+), 29 deletions(-) delete mode 100644 chat-android/src/main/java/com/ably/chat/Cancellation.kt create mode 100644 chat-android/src/main/java/com/ably/chat/Subscription.kt diff --git a/chat-android/src/main/java/com/ably/chat/Cancellation.kt b/chat-android/src/main/java/com/ably/chat/Cancellation.kt deleted file mode 100644 index 2357a1a..0000000 --- a/chat-android/src/main/java/com/ably/chat/Cancellation.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.ably.chat - -/** - * A cancellation handle, returned by various functions (mostly subscriptions) - * where cancellation is required. - */ -fun interface Cancellation { - /** - * Handle cancellation (unsubscribe listeners, clean up) - */ - fun cancel() -} diff --git a/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt b/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt index c9cc806..2822f10 100644 --- a/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt +++ b/chat-android/src/main/java/com/ably/chat/ConnectionStatus.kt @@ -25,7 +25,7 @@ interface ConnectionStatus { * Registers a listener that will be called whenever the connection status changes. * @param listener The function to call when the status changes. */ - fun on(listener: Listener): Cancellation + fun on(listener: Listener): Subscription /** * An interface for listening to changes for the connection status diff --git a/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt b/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt index 6606bc2..07412f4 100644 --- a/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt +++ b/chat-android/src/main/java/com/ably/chat/EmitsDiscontinuities.kt @@ -10,7 +10,7 @@ interface EmitsDiscontinuities { * Register a listener to be called when a discontinuity is detected. * @param listener The listener to be called when a discontinuity is detected. */ - fun onDiscontinuity(listener: Listener): Cancellation + fun onDiscontinuity(listener: Listener): Subscription /** * An interface for listening when discontinuity happens diff --git a/chat-android/src/main/java/com/ably/chat/Messages.kt b/chat-android/src/main/java/com/ably/chat/Messages.kt index dc47679..eb9600f 100644 --- a/chat-android/src/main/java/com/ably/chat/Messages.kt +++ b/chat-android/src/main/java/com/ably/chat/Messages.kt @@ -169,7 +169,7 @@ data class SendMessageParams( val headers: MessageHeaders? = null, ) -interface MessagesSubscription : Cancellation { +interface MessagesSubscription : Subscription { suspend fun getPreviousMessages(queryOptions: QueryOptions): PaginatedResult } @@ -195,7 +195,7 @@ class DefaultMessages( override suspend fun send(params: SendMessageParams): Message = chatApi.sendMessage(roomId, params) - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Subscription { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/Occupancy.kt b/chat-android/src/main/java/com/ably/chat/Occupancy.kt index 95be9c4..a9e18ed 100644 --- a/chat-android/src/main/java/com/ably/chat/Occupancy.kt +++ b/chat-android/src/main/java/com/ably/chat/Occupancy.kt @@ -23,7 +23,7 @@ interface Occupancy : EmitsDiscontinuities { * * @param listener A listener to be called when the occupancy of the room changes. */ - fun subscribe(listener: Listener): Cancellation + fun subscribe(listener: Listener): Subscription /** * Get the current occupancy of the chat room. @@ -65,7 +65,7 @@ internal class DefaultOccupancy( override val channel: Channel get() = messages.channel - override fun subscribe(listener: Occupancy.Listener): Cancellation { + override fun subscribe(listener: Occupancy.Listener): Subscription { TODO("Not yet implemented") } @@ -73,7 +73,7 @@ internal class DefaultOccupancy( TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Subscription { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/Presence.kt b/chat-android/src/main/java/com/ably/chat/Presence.kt index 5987102..2973e48 100644 --- a/chat-android/src/main/java/com/ably/chat/Presence.kt +++ b/chat-android/src/main/java/com/ably/chat/Presence.kt @@ -60,7 +60,7 @@ interface Presence : EmitsDiscontinuities { * Subscribe the given listener to all presence events. * @param listener listener to subscribe */ - fun subscribe(listener: Listener): Cancellation + fun subscribe(listener: Listener): Subscription /** * An interface for listening to new presence event @@ -156,11 +156,11 @@ internal class DefaultPresence( TODO("Not yet implemented") } - override fun subscribe(listener: Presence.Listener): Cancellation { + override fun subscribe(listener: Presence.Listener): Subscription { TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Subscription { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/RoomReactions.kt b/chat-android/src/main/java/com/ably/chat/RoomReactions.kt index 2c79339..06b214c 100644 --- a/chat-android/src/main/java/com/ably/chat/RoomReactions.kt +++ b/chat-android/src/main/java/com/ably/chat/RoomReactions.kt @@ -38,7 +38,7 @@ interface RoomReactions : EmitsDiscontinuities { * @param listener The listener function to be called when a reaction is received. * @returns A response object that allows you to control the subscription. */ - fun subscribe(listener: Listener): Cancellation + fun subscribe(listener: Listener): Subscription /** * An interface for listening to new reaction events @@ -111,11 +111,11 @@ internal class DefaultRoomReactions( TODO("Not yet implemented") } - override fun subscribe(listener: RoomReactions.Listener): Cancellation { + override fun subscribe(listener: RoomReactions.Listener): Subscription { TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Subscription { TODO("Not yet implemented") } } diff --git a/chat-android/src/main/java/com/ably/chat/RoomStatus.kt b/chat-android/src/main/java/com/ably/chat/RoomStatus.kt index 82620b7..05e54e4 100644 --- a/chat-android/src/main/java/com/ably/chat/RoomStatus.kt +++ b/chat-android/src/main/java/com/ably/chat/RoomStatus.kt @@ -21,7 +21,7 @@ interface RoomStatus { * @param listener The function to call when the status changes. * @returns An object that can be used to unregister the listener. */ - fun on(listener: Listener): Cancellation + fun on(listener: Listener): Subscription /** * An interface for listening to changes for the room status diff --git a/chat-android/src/main/java/com/ably/chat/Subscription.kt b/chat-android/src/main/java/com/ably/chat/Subscription.kt new file mode 100644 index 0000000..e2990a8 --- /dev/null +++ b/chat-android/src/main/java/com/ably/chat/Subscription.kt @@ -0,0 +1,12 @@ +package com.ably.chat + +/** + * An unsubscription handle, returned by various functions (mostly subscriptions) + * where unsubscription is required. + */ +fun interface Subscription { + /** + * Handle unsubscription (unsubscribe listeners, clean up) + */ + fun unsubscribe() +} diff --git a/chat-android/src/main/java/com/ably/chat/Typing.kt b/chat-android/src/main/java/com/ably/chat/Typing.kt index 5de49f6..6add59f 100644 --- a/chat-android/src/main/java/com/ably/chat/Typing.kt +++ b/chat-android/src/main/java/com/ably/chat/Typing.kt @@ -37,7 +37,7 @@ interface Typing : EmitsDiscontinuities { * * @param listener A listener to be called when the typing state of a user in the room changes. */ - fun subscribe(listener: Listener): Cancellation + fun subscribe(listener: Listener): Subscription /** * Get the current typers, a set of clientIds. @@ -84,7 +84,7 @@ internal class DefaultTyping( override val channel: Channel get() = realtimeClient.channels.get(typingIndicatorsChannelName, ChatChannelOptions()) - override fun subscribe(listener: Typing.Listener): Cancellation { + override fun subscribe(listener: Typing.Listener): Subscription { TODO("Not yet implemented") } @@ -100,7 +100,7 @@ internal class DefaultTyping( TODO("Not yet implemented") } - override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Cancellation { + override fun onDiscontinuity(listener: EmitsDiscontinuities.Listener): Subscription { TODO("Not yet implemented") } }