diff --git a/CHANGELOG.md b/CHANGELOG.md index 870ba79..a74d0d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 12.0.0 + +* Add array-based enum parameters (e.g., `permissions: List`). + ## 11.4.0 * Add `getScreenshot` method to `Avatars` service diff --git a/LICENSE.md b/LICENSE.md index c1602fc..6f8702b 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2025 Appwrite (https://appwrite.io) and individual contributors. +Copyright (c) 2026 Appwrite (https://appwrite.io) and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index f058b47..f1d6b76 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ ![Maven Central](https://img.shields.io/maven-central/v/io.appwrite/sdk-for-android.svg?color=green&style=flat-square) ![License](https://img.shields.io/github/license/appwrite/sdk-for-android.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-1.8.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.8.1-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) **This SDK is compatible with Appwrite server version 1.8.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-android/releases).** -Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) +Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) ![Appwrite](https://github.com/appwrite/appwrite/raw/main/public/images/github.png) @@ -38,7 +38,7 @@ repositories { Next, add the dependency to your project's `build.gradle(.kts)` file: ```groovy -implementation("io.appwrite:sdk-for-android:11.4.0") +implementation("io.appwrite:sdk-for-android:12.0.0") ``` ### Maven @@ -49,7 +49,7 @@ Add this to your project's `pom.xml` file: io.appwrite sdk-for-android - 11.4.0 + 12.0.0 ``` diff --git a/build.gradle b/build.gradle index 0b0c86c..a1957d4 100644 --- a/build.gradle +++ b/build.gradle @@ -29,6 +29,5 @@ task clean(type: Delete) { delete rootProject.buildDir } - apply from: "${rootDir}/scripts/publish-config.gradle" diff --git a/docs/examples/java/account/create-jwt.md b/docs/examples/java/account/create-jwt.md index 9e3bd28..56c31ee 100644 --- a/docs/examples/java/account/create-jwt.md +++ b/docs/examples/java/account/create-jwt.md @@ -8,11 +8,15 @@ Client client = new Client(context) Account account = new Account(client); -account.createJWT(new CoroutineCallback<>((result, error) -> { - if (error != null) { - error.printStackTrace(); - return; - } +account.createJWT( + 0, // duration (optional) + new CoroutineCallback<>((result, error) -> { + if (error != null) { + error.printStackTrace(); + return; + } + + Log.d("Appwrite", result.toString()); + }) +); - Log.d("Appwrite", result.toString()); -})); diff --git a/docs/examples/java/avatars/get-screenshot.md b/docs/examples/java/avatars/get-screenshot.md index ce8372d..24c4998 100644 --- a/docs/examples/java/avatars/get-screenshot.md +++ b/docs/examples/java/avatars/get-screenshot.md @@ -3,7 +3,8 @@ import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Avatars; import io.appwrite.enums.Theme; import io.appwrite.enums.Timezone; -import io.appwrite.enums.Output; +import io.appwrite.enums.BrowserPermission; +import io.appwrite.enums.ImageFormat; Client client = new Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -29,12 +30,12 @@ avatars.getScreenshot( -122.4194, // longitude (optional) 100, // accuracy (optional) true, // touch (optional) - List.of("geolocation", "notifications"), // permissions (optional) + BrowserPermission.GEOLOCATION, // permissions (optional) 3, // sleep (optional) 800, // width (optional) 600, // height (optional) 85, // quality (optional) - Output.JPG, // output (optional) + ImageFormat.JPG, // output (optional) new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/java/databases/update-document.md b/docs/examples/java/databases/update-document.md index 0f13f74..74e4244 100644 --- a/docs/examples/java/databases/update-document.md +++ b/docs/examples/java/databases/update-document.md @@ -14,7 +14,13 @@ databases.updateDocument( "", // databaseId "", // collectionId "", // documentId - Map.of("a", "b"), // data (optional) + Map.of( + "username", "walter.obrien", + "email", "walter.obrien@example.com", + "fullName", "Walter O'Brien", + "age", 33, + "isAdmin", false + ), // data (optional) List.of(Permission.read(Role.any())), // permissions (optional) "", // transactionId (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/java/databases/upsert-document.md b/docs/examples/java/databases/upsert-document.md index 8c72734..9e04ef5 100644 --- a/docs/examples/java/databases/upsert-document.md +++ b/docs/examples/java/databases/upsert-document.md @@ -14,7 +14,13 @@ databases.upsertDocument( "", // databaseId "", // collectionId "", // documentId - Map.of("a", "b"), // data + Map.of( + "username", "walter.obrien", + "email", "walter.obrien@example.com", + "fullName", "Walter O'Brien", + "age", 30, + "isAdmin", false + ), // data (optional) List.of(Permission.read(Role.any())), // permissions (optional) "", // transactionId (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/java/tablesdb/update-row.md b/docs/examples/java/tablesdb/update-row.md index 89f2646..c41cc09 100644 --- a/docs/examples/java/tablesdb/update-row.md +++ b/docs/examples/java/tablesdb/update-row.md @@ -14,7 +14,13 @@ tablesDB.updateRow( "", // databaseId "", // tableId "", // rowId - Map.of("a", "b"), // data (optional) + Map.of( + "username", "walter.obrien", + "email", "walter.obrien@example.com", + "fullName", "Walter O'Brien", + "age", 33, + "isAdmin", false + ), // data (optional) List.of(Permission.read(Role.any())), // permissions (optional) "", // transactionId (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/java/tablesdb/upsert-row.md b/docs/examples/java/tablesdb/upsert-row.md index c6cfe6d..0b40f6b 100644 --- a/docs/examples/java/tablesdb/upsert-row.md +++ b/docs/examples/java/tablesdb/upsert-row.md @@ -14,7 +14,13 @@ tablesDB.upsertRow( "", // databaseId "", // tableId "", // rowId - Map.of("a", "b"), // data (optional) + Map.of( + "username", "walter.obrien", + "email", "walter.obrien@example.com", + "fullName", "Walter O'Brien", + "age", 33, + "isAdmin", false + ), // data (optional) List.of(Permission.read(Role.any())), // permissions (optional) "", // transactionId (optional) new CoroutineCallback<>((result, error) -> { diff --git a/docs/examples/java/teams/create-membership.md b/docs/examples/java/teams/create-membership.md index e5eee20..161e65e 100644 --- a/docs/examples/java/teams/create-membership.md +++ b/docs/examples/java/teams/create-membership.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Teams; +import io.appwrite.enums.Roles; Client client = new Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -10,7 +11,7 @@ Teams teams = new Teams(client); teams.createMembership( "", // teamId - List.of(), // roles + Roles.ADMIN, // roles "email@example.com", // email (optional) "", // userId (optional) "+12065550100", // phone (optional) diff --git a/docs/examples/java/teams/update-membership.md b/docs/examples/java/teams/update-membership.md index f8adcf1..83675d7 100644 --- a/docs/examples/java/teams/update-membership.md +++ b/docs/examples/java/teams/update-membership.md @@ -1,6 +1,7 @@ import io.appwrite.Client; import io.appwrite.coroutines.CoroutineCallback; import io.appwrite.services.Teams; +import io.appwrite.enums.Roles; Client client = new Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -11,7 +12,7 @@ Teams teams = new Teams(client); teams.updateMembership( "", // teamId "", // membershipId - List.of(), // roles + Roles.ADMIN, // roles new CoroutineCallback<>((result, error) -> { if (error != null) { error.printStackTrace(); diff --git a/docs/examples/kotlin/account/create-jwt.md b/docs/examples/kotlin/account/create-jwt.md index c87eaf3..1c72fa8 100644 --- a/docs/examples/kotlin/account/create-jwt.md +++ b/docs/examples/kotlin/account/create-jwt.md @@ -8,4 +8,6 @@ val client = Client(context) val account = Account(client) -val result = account.createJWT() +val result = account.createJWT( + duration = 0, // (optional) +) \ No newline at end of file diff --git a/docs/examples/kotlin/avatars/get-screenshot.md b/docs/examples/kotlin/avatars/get-screenshot.md index d7cd6cd..4ac6717 100644 --- a/docs/examples/kotlin/avatars/get-screenshot.md +++ b/docs/examples/kotlin/avatars/get-screenshot.md @@ -3,7 +3,8 @@ import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Avatars import io.appwrite.enums.Theme import io.appwrite.enums.Timezone -import io.appwrite.enums.Output +import io.appwrite.enums.BrowserPermission +import io.appwrite.enums.ImageFormat val client = Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -29,10 +30,10 @@ val result = avatars.getScreenshot( longitude = -122.4194, // (optional) accuracy = 100, // (optional) touch = true, // (optional) - permissions = listOf("geolocation", "notifications"), // (optional) + permissions = BrowserPermission.GEOLOCATION, // (optional) sleep = 3, // (optional) width = 800, // (optional) height = 600, // (optional) quality = 85, // (optional) - output = output.JPG, // (optional) + output = ImageFormat.JPG, // (optional) ) \ No newline at end of file diff --git a/docs/examples/kotlin/databases/update-document.md b/docs/examples/kotlin/databases/update-document.md index ba6d4d1..49f0dbc 100644 --- a/docs/examples/kotlin/databases/update-document.md +++ b/docs/examples/kotlin/databases/update-document.md @@ -14,7 +14,13 @@ val result = databases.updateDocument( databaseId = "", collectionId = "", documentId = "", - data = mapOf( "a" to "b" ), // (optional) + data = mapOf( + "username" to "walter.obrien", + "email" to "walter.obrien@example.com", + "fullName" to "Walter O'Brien", + "age" to 33, + "isAdmin" to false + ), // (optional) permissions = listOf(Permission.read(Role.any())), // (optional) transactionId = "", // (optional) ) \ No newline at end of file diff --git a/docs/examples/kotlin/databases/upsert-document.md b/docs/examples/kotlin/databases/upsert-document.md index 4d95c9d..42aff0e 100644 --- a/docs/examples/kotlin/databases/upsert-document.md +++ b/docs/examples/kotlin/databases/upsert-document.md @@ -14,7 +14,13 @@ val result = databases.upsertDocument( databaseId = "", collectionId = "", documentId = "", - data = mapOf( "a" to "b" ), + data = mapOf( + "username" to "walter.obrien", + "email" to "walter.obrien@example.com", + "fullName" to "Walter O'Brien", + "age" to 30, + "isAdmin" to false + ), // (optional) permissions = listOf(Permission.read(Role.any())), // (optional) transactionId = "", // (optional) ) \ No newline at end of file diff --git a/docs/examples/kotlin/tablesdb/update-row.md b/docs/examples/kotlin/tablesdb/update-row.md index 91b2709..20319e3 100644 --- a/docs/examples/kotlin/tablesdb/update-row.md +++ b/docs/examples/kotlin/tablesdb/update-row.md @@ -14,7 +14,13 @@ val result = tablesDB.updateRow( databaseId = "", tableId = "", rowId = "", - data = mapOf( "a" to "b" ), // (optional) + data = mapOf( + "username" to "walter.obrien", + "email" to "walter.obrien@example.com", + "fullName" to "Walter O'Brien", + "age" to 33, + "isAdmin" to false + ), // (optional) permissions = listOf(Permission.read(Role.any())), // (optional) transactionId = "", // (optional) ) \ No newline at end of file diff --git a/docs/examples/kotlin/tablesdb/upsert-row.md b/docs/examples/kotlin/tablesdb/upsert-row.md index 6b1a45e..3af7902 100644 --- a/docs/examples/kotlin/tablesdb/upsert-row.md +++ b/docs/examples/kotlin/tablesdb/upsert-row.md @@ -14,7 +14,13 @@ val result = tablesDB.upsertRow( databaseId = "", tableId = "", rowId = "", - data = mapOf( "a" to "b" ), // (optional) + data = mapOf( + "username" to "walter.obrien", + "email" to "walter.obrien@example.com", + "fullName" to "Walter O'Brien", + "age" to 33, + "isAdmin" to false + ), // (optional) permissions = listOf(Permission.read(Role.any())), // (optional) transactionId = "", // (optional) ) \ No newline at end of file diff --git a/docs/examples/kotlin/teams/create-membership.md b/docs/examples/kotlin/teams/create-membership.md index 70eb7dd..f850028 100644 --- a/docs/examples/kotlin/teams/create-membership.md +++ b/docs/examples/kotlin/teams/create-membership.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Teams +import io.appwrite.enums.Roles val client = Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -10,7 +11,7 @@ val teams = Teams(client) val result = teams.createMembership( teamId = "", - roles = listOf(), + roles = roles.ADMIN, email = "email@example.com", // (optional) userId = "", // (optional) phone = "+12065550100", // (optional) diff --git a/docs/examples/kotlin/teams/update-membership.md b/docs/examples/kotlin/teams/update-membership.md index 86216a8..8375c77 100644 --- a/docs/examples/kotlin/teams/update-membership.md +++ b/docs/examples/kotlin/teams/update-membership.md @@ -1,6 +1,7 @@ import io.appwrite.Client import io.appwrite.coroutines.CoroutineCallback import io.appwrite.services.Teams +import io.appwrite.enums.Roles val client = Client(context) .setEndpoint("https://.cloud.appwrite.io/v1") // Your API Endpoint @@ -11,5 +12,5 @@ val teams = Teams(client) val result = teams.updateMembership( teamId = "", membershipId = "", - roles = listOf(), + roles = roles.ADMIN, ) \ No newline at end of file diff --git a/example/src/main/java/io/appwrite/android/ui/accounts/AccountsFragment.kt b/example/src/main/java/io/appwrite/android/ui/accounts/AccountsFragment.kt index 40c40b5..4e60808 100644 --- a/example/src/main/java/io/appwrite/android/ui/accounts/AccountsFragment.kt +++ b/example/src/main/java/io/appwrite/android/ui/accounts/AccountsFragment.kt @@ -13,7 +13,6 @@ import androidx.fragment.app.viewModels import io.appwrite.android.R import io.appwrite.android.databinding.FragmentAccountBinding - class AccountsFragment : Fragment() { private lateinit var binding: FragmentAccountBinding diff --git a/library/build.gradle b/library/build.gradle index 998da2b..cc21f31 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -10,7 +10,7 @@ ext { POM_URL = 'https://github.com/appwrite/sdk-for-android' POM_SCM_URL = 'https://github.com/appwrite/sdk-for-android' POM_ISSUE_URL = 'https://github.com/appwrite/sdk-for-android/issues' - POM_DESCRIPTION = 'Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)' + POM_DESCRIPTION = 'Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)' POM_LICENSE_URL = 'https://opensource.org/licenses/GPL-3.0' POM_LICENSE_NAME = "GPL-3.0" POM_DEVELOPER_ID = 'appwrite' diff --git a/library/src/main/java/io/appwrite/Channel.kt b/library/src/main/java/io/appwrite/Channel.kt new file mode 100644 index 0000000..f358c72 --- /dev/null +++ b/library/src/main/java/io/appwrite/Channel.kt @@ -0,0 +1,262 @@ +package io.appwrite + +// Marker interfaces for type safety +public interface _Root +public interface _Database +public interface _Collection +public interface _Document +public interface _TablesDB +public interface _Table +public interface _Row +public interface _Bucket +public interface _File +public interface _Func +public interface _Execution +public interface _Team +public interface _Membership +public interface _Resolved + +// Union type for actionable channels +typealias Actionable = _Document + +/** + * Helper for normalizing IDs + */ +private fun normalize(id: String): String { + val trimmed = id.trim() + return if (trimmed.isEmpty()) "*" else trimmed +} + +/** + * Channel class with generic type parameter for type-safe method chaining + */ +class Channel private constructor( + private val segments: List +) { + /** + * Internal helper to transition to next state with segment and ID + * Public for extension function access + */ + fun next(segment: String, id: String = "*"): Channel { + return Channel(segments + listOf(segment, normalize(id))) + } + + /** + * Internal helper for terminal actions (no ID segment) + * Public for extension function access + */ + fun resolve(action: String): Channel<_Resolved> { + return Channel(segments + listOf(action)) + } + + /** + * Convert channel to string representation + */ + override fun toString(): String = segments.joinToString(".") + + companion object { + fun database(id: String = "*"): Channel<_Database> = + Channel(listOf("databases", normalize(id))) + + fun tablesdb(id: String = "*"): Channel<_TablesDB> = + Channel(listOf("tablesdb", normalize(id))) + + fun bucket(id: String = "*"): Channel<_Bucket> = + Channel(listOf("buckets", normalize(id))) + + fun function(id: String = "*"): Channel<_Func> = + Channel(listOf("functions", normalize(id))) + + fun team(id: String = "*"): Channel<_Team> = + Channel(listOf("teams", normalize(id))) + + fun membership(id: String = "*"): Channel<_Membership> = + Channel(listOf("memberships", normalize(id))) + + fun account(userId: String = ""): String { + val id = normalize(userId) + return if (id == "*") "account" else "account.$id" + } + + // Global events + fun documents(): String = "documents" + fun rows(): String = "rows" + fun files(): String = "files" + fun executions(): String = "executions" + fun teams(): String = "teams" + } +} + +// --- DATABASE ROUTE --- +// Extension functions restricted by receiver type + +/** + * Only available on Channel<_Database> + */ +fun Channel<_Database>.collection(id: String = "*"): Channel<_Collection> = + this.next("collections", id) + +/** + * Only available on Channel<_Collection> + */ +fun Channel<_Collection>.document(id: String = "*"): Channel<_Document> = + this.next("documents", id) + +// --- TABLESDB ROUTE --- + +/** + * Only available on Channel<_TablesDB> + */ +fun Channel<_TablesDB>.table(id: String = "*"): Channel<_Table> = + this.next("tables", id) + +/** + * Only available on Channel<_Table> + */ +fun Channel<_Table>.row(id: String = "*"): Channel<_Row> = + this.next("rows", id) + +// --- BUCKET ROUTE --- + +/** + * Only available on Channel<_Bucket> + */ +fun Channel<_Bucket>.file(id: String = "*"): Channel<_File> = + this.next("files", id) + +// --- FUNCTION ROUTE --- + +/** + * Only available on Channel<_Func> + */ +fun Channel<_Func>.execution(id: String = "*"): Channel<_Execution> = + this.next("executions", id) + +// --- TERMINAL ACTIONS --- +// Restricted to Actionable types (_Document, _Row, _File, _Execution, _Team, _Membership) + +/** + * Only available on Channel<_Document> + */ +@JvmName("createDocument") +fun Channel<_Document>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_Document> + */ +@JvmName("updateDocument") +fun Channel<_Document>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_Document> + */ +@JvmName("deleteDocument") +fun Channel<_Document>.delete(): Channel<_Resolved> = + this.resolve("delete") + +/** + * Only available on Channel<_Row> + */ +@JvmName("createRow") +fun Channel<_Row>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_Row> + */ +@JvmName("updateRow") +fun Channel<_Row>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_Row> + */ +@JvmName("deleteRow") +fun Channel<_Row>.delete(): Channel<_Resolved> = + this.resolve("delete") + +/** + * Only available on Channel<_File> + */ +@JvmName("createFile") +fun Channel<_File>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_File> + */ +@JvmName("updateFile") +fun Channel<_File>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_File> + */ +@JvmName("deleteFile") +fun Channel<_File>.delete(): Channel<_Resolved> = + this.resolve("delete") + +/** + * Only available on Channel<_Execution> + */ +@JvmName("createExecution") +fun Channel<_Execution>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_Execution> + */ +@JvmName("updateExecution") +fun Channel<_Execution>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_Execution> + */ +@JvmName("deleteExecution") +fun Channel<_Execution>.delete(): Channel<_Resolved> = + this.resolve("delete") + +/** + * Only available on Channel<_Team> + */ +@JvmName("createTeam") +fun Channel<_Team>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_Team> + */ +@JvmName("updateTeam") +fun Channel<_Team>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_Team> + */ +@JvmName("deleteTeam") +fun Channel<_Team>.delete(): Channel<_Resolved> = + this.resolve("delete") + +/** + * Only available on Channel<_Membership> + */ +@JvmName("createMembership") +fun Channel<_Membership>.create(): Channel<_Resolved> = + this.resolve("create") + +/** + * Only available on Channel<_Membership> + */ +@JvmName("updateMembership") +fun Channel<_Membership>.update(): Channel<_Resolved> = + this.resolve("update") + +/** + * Only available on Channel<_Membership> + */ +@JvmName("deleteMembership") +fun Channel<_Membership>.delete(): Channel<_Resolved> = + this.resolve("delete") diff --git a/library/src/main/java/io/appwrite/Client.kt b/library/src/main/java/io/appwrite/Client.kt index 9ba0816..5b94669 100644 --- a/library/src/main/java/io/appwrite/Client.kt +++ b/library/src/main/java/io/appwrite/Client.kt @@ -87,7 +87,7 @@ class Client @JvmOverloads constructor( "x-sdk-name" to "Android", "x-sdk-platform" to "client", "x-sdk-language" to "android", - "x-sdk-version" to "11.4.0", + "x-sdk-version" to "12.0.0", "x-appwrite-response-format" to "1.8.0" ) config = mutableMapOf() diff --git a/library/src/main/java/io/appwrite/Query.kt b/library/src/main/java/io/appwrite/Query.kt index c088a79..e602f18 100644 --- a/library/src/main/java/io/appwrite/Query.kt +++ b/library/src/main/java/io/appwrite/Query.kt @@ -38,6 +38,15 @@ class Query( */ fun notEqual(attribute: String, value: Any) = Query("notEqual", attribute, parseValue(value)).toJson() + /** + * Filter resources where attribute matches a regular expression pattern. + * + * @param attribute The attribute to filter on. + * @param pattern The regular expression pattern to match. + * @returns The query string. + */ + fun regex(attribute: String, pattern: String) = Query("regex", attribute, parseValue(pattern)).toJson() + /** * Filter resources where attribute is less than value. * @@ -99,6 +108,22 @@ class Query( */ fun isNotNull(attribute: String) = Query("isNotNull", attribute).toJson() + /** + * Filter resources where the specified attributes exist. + * + * @param attributes The list of attributes that must exist. + * @returns The query string. + */ + fun exists(attributes: List) = Query("exists", null, attributes).toJson() + + /** + * Filter resources where the specified attributes do not exist. + * + * @param attributes The list of attributes that must not exist. + * @returns The query string. + */ + fun notExists(attributes: List) = Query("notExists", null, attributes).toJson() + /** * Filter resources where attribute is between start and end (inclusive). * @@ -311,6 +336,15 @@ class Query( */ fun and(queries: List) = Query("and", null, queries.map { it.fromJson() }).toJson() + /** + * Filter array elements where at least one element matches all the specified queries. + * + * @param attribute The attribute containing the array to filter on. + * @param queries The list of query strings to match against array elements. + * @returns The query string. + */ + fun elemMatch(attribute: String, queries: List) = Query("elemMatch", attribute, queries.map { it.fromJson() }).toJson() + /** * Filter resources where attribute is at a specific distance from the given coordinates. * diff --git a/library/src/main/java/io/appwrite/enums/BrowserPermission.kt b/library/src/main/java/io/appwrite/enums/BrowserPermission.kt new file mode 100644 index 0000000..339166a --- /dev/null +++ b/library/src/main/java/io/appwrite/enums/BrowserPermission.kt @@ -0,0 +1,48 @@ +package io.appwrite.enums + +import com.google.gson.annotations.SerializedName + +enum class BrowserPermission(val value: String) { + @SerializedName("geolocation") + GEOLOCATION("geolocation"), + @SerializedName("camera") + CAMERA("camera"), + @SerializedName("microphone") + MICROPHONE("microphone"), + @SerializedName("notifications") + NOTIFICATIONS("notifications"), + @SerializedName("midi") + MIDI("midi"), + @SerializedName("push") + PUSH("push"), + @SerializedName("clipboard-read") + CLIPBOARD_READ("clipboard-read"), + @SerializedName("clipboard-write") + CLIPBOARD_WRITE("clipboard-write"), + @SerializedName("payment-handler") + PAYMENT_HANDLER("payment-handler"), + @SerializedName("usb") + USB("usb"), + @SerializedName("bluetooth") + BLUETOOTH("bluetooth"), + @SerializedName("accelerometer") + ACCELEROMETER("accelerometer"), + @SerializedName("gyroscope") + GYROSCOPE("gyroscope"), + @SerializedName("magnetometer") + MAGNETOMETER("magnetometer"), + @SerializedName("ambient-light-sensor") + AMBIENT_LIGHT_SENSOR("ambient-light-sensor"), + @SerializedName("background-sync") + BACKGROUND_SYNC("background-sync"), + @SerializedName("persistent-storage") + PERSISTENT_STORAGE("persistent-storage"), + @SerializedName("screen-wake-lock") + SCREEN_WAKE_LOCK("screen-wake-lock"), + @SerializedName("web-share") + WEB_SHARE("web-share"), + @SerializedName("xr-spatial-tracking") + XR_SPATIAL_TRACKING("xr-spatial-tracking"); + + override fun toString() = value +} \ No newline at end of file diff --git a/library/src/main/java/io/appwrite/enums/OAuthProvider.kt b/library/src/main/java/io/appwrite/enums/OAuthProvider.kt index b0cff85..955df30 100644 --- a/library/src/main/java/io/appwrite/enums/OAuthProvider.kt +++ b/library/src/main/java/io/appwrite/enums/OAuthProvider.kt @@ -80,9 +80,7 @@ enum class OAuthProvider(val value: String) { @SerializedName("zoho") ZOHO("zoho"), @SerializedName("zoom") - ZOOM("zoom"), - @SerializedName("mock") - MOCK("mock"); + ZOOM("zoom"); override fun toString() = value } \ No newline at end of file diff --git a/library/src/main/java/io/appwrite/enums/Output.kt b/library/src/main/java/io/appwrite/enums/Output.kt deleted file mode 100644 index 819b29b..0000000 --- a/library/src/main/java/io/appwrite/enums/Output.kt +++ /dev/null @@ -1,22 +0,0 @@ -package io.appwrite.enums - -import com.google.gson.annotations.SerializedName - -enum class Output(val value: String) { - @SerializedName("jpg") - JPG("jpg"), - @SerializedName("jpeg") - JPEG("jpeg"), - @SerializedName("png") - PNG("png"), - @SerializedName("webp") - WEBP("webp"), - @SerializedName("heic") - HEIC("heic"), - @SerializedName("avif") - AVIF("avif"), - @SerializedName("gif") - GIF("gif"); - - override fun toString() = value -} \ No newline at end of file diff --git a/library/src/main/java/io/appwrite/enums/Roles.kt b/library/src/main/java/io/appwrite/enums/Roles.kt new file mode 100644 index 0000000..94c6b7a --- /dev/null +++ b/library/src/main/java/io/appwrite/enums/Roles.kt @@ -0,0 +1,14 @@ +package io.appwrite.enums + +import com.google.gson.annotations.SerializedName + +enum class Roles(val value: String) { + @SerializedName("admin") + ADMIN("admin"), + @SerializedName("developer") + DEVELOPER("developer"), + @SerializedName("owner") + OWNER("owner"); + + override fun toString() = value +} \ No newline at end of file diff --git a/library/src/main/java/io/appwrite/models/File.kt b/library/src/main/java/io/appwrite/models/File.kt index 897fc4a..0671cc8 100644 --- a/library/src/main/java/io/appwrite/models/File.kt +++ b/library/src/main/java/io/appwrite/models/File.kt @@ -73,6 +73,18 @@ data class File( @SerializedName("chunksUploaded") val chunksUploaded: Long, + /** + * Whether file contents are encrypted at rest. + */ + @SerializedName("encryption") + val encryption: Boolean, + + /** + * Compression algorithm used for the file. Will be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd). + */ + @SerializedName("compression") + val compression: String, + ) { fun toMap(): Map = mapOf( "\$id" to id as Any, @@ -86,6 +98,8 @@ data class File( "sizeOriginal" to sizeOriginal as Any, "chunksTotal" to chunksTotal as Any, "chunksUploaded" to chunksUploaded as Any, + "encryption" to encryption as Any, + "compression" to compression as Any, ) companion object { @@ -105,6 +119,8 @@ data class File( sizeOriginal = (map["sizeOriginal"] as Number).toLong(), chunksTotal = (map["chunksTotal"] as Number).toLong(), chunksUploaded = (map["chunksUploaded"] as Number).toLong(), + encryption = map["encryption"] as Boolean, + compression = map["compression"] as String, ) } } \ No newline at end of file diff --git a/library/src/main/java/io/appwrite/services/Account.kt b/library/src/main/java/io/appwrite/services/Account.kt index 3f90e6d..8591423 100644 --- a/library/src/main/java/io/appwrite/services/Account.kt +++ b/library/src/main/java/io/appwrite/services/Account.kt @@ -244,13 +244,17 @@ class Account(client: Client) : Service(client) { /** * Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame. * + * @param duration Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds. * @return [io.appwrite.models.Jwt] */ + @JvmOverloads suspend fun createJWT( + duration: Long? = null, ): io.appwrite.models.Jwt { val apiPath = "/account/jwts" val apiParams = mutableMapOf( + "duration" to duration, ) val apiHeaders = mutableMapOf( "content-type" to "application/json", diff --git a/library/src/main/java/io/appwrite/services/Avatars.kt b/library/src/main/java/io/appwrite/services/Avatars.kt index fc14866..7694c0d 100644 --- a/library/src/main/java/io/appwrite/services/Avatars.kt +++ b/library/src/main/java/io/appwrite/services/Avatars.kt @@ -306,12 +306,12 @@ class Avatars(client: Client) : Service(client) { longitude: Double? = null, accuracy: Double? = null, touch: Boolean? = null, - permissions: List? = null, + permissions: List? = null, sleep: Long? = null, width: Long? = null, height: Long? = null, quality: Long? = null, - output: io.appwrite.enums.Output? = null, + output: io.appwrite.enums.ImageFormat? = null, ): ByteArray { val apiPath = "/avatars/screenshots" diff --git a/library/src/main/java/io/appwrite/services/Databases.kt b/library/src/main/java/io/appwrite/services/Databases.kt index ce73151..57f2274 100644 --- a/library/src/main/java/io/appwrite/services/Databases.kt +++ b/library/src/main/java/io/appwrite/services/Databases.kt @@ -476,7 +476,7 @@ class Databases(client: Client) : Service(client) { databaseId: String, collectionId: String, documentId: String, - data: Any, + data: Any? = null, permissions: List? = null, transactionId: String? = null, nestedType: Class, @@ -529,7 +529,7 @@ class Databases(client: Client) : Service(client) { databaseId: String, collectionId: String, documentId: String, - data: Any, + data: Any? = null, permissions: List? = null, transactionId: String? = null, ): io.appwrite.models.Document> = upsertDocument( diff --git a/library/src/main/java/io/appwrite/services/Realtime.kt b/library/src/main/java/io/appwrite/services/Realtime.kt index b06eacf..ee77357 100644 --- a/library/src/main/java/io/appwrite/services/Realtime.kt +++ b/library/src/main/java/io/appwrite/services/Realtime.kt @@ -2,6 +2,7 @@ package io.appwrite.services import io.appwrite.Service import io.appwrite.Client +import io.appwrite.Channel import io.appwrite.exceptions.AppwriteException import io.appwrite.extensions.forEachAsync import io.appwrite.extensions.fromJson @@ -109,6 +110,27 @@ class Realtime(client: Client) : Service(client), CoroutineScope { else -> 60000L } + /** + * Convert channel value to string + * All Channel instances have toString() method + */ + private fun channelToString(channel: Any): String { + return when { + channel is String -> channel + channel is Channel<*> -> channel.toString() + else -> channel.toString() + } + } + + fun subscribe( + vararg channels: Channel<*>, + callback: (RealtimeResponseEvent) -> Unit, + ) = subscribe( + channels = channels.map { channelToString(it) }.toTypedArray(), + Any::class.java, + callback + ) + fun subscribe( vararg channels: String, callback: (RealtimeResponseEvent) -> Unit, @@ -118,6 +140,18 @@ class Realtime(client: Client) : Service(client), CoroutineScope { callback ) + fun subscribe( + vararg channels: Channel<*>, + payloadType: Class, + callback: (RealtimeResponseEvent) -> Unit, + ): RealtimeSubscription { + return subscribe( + channels = channels.map { channelToString(it) }.toTypedArray(), + payloadType = payloadType, + callback = callback + ) + } + fun subscribe( vararg channels: String, payloadType: Class, diff --git a/library/src/main/java/io/appwrite/services/Storage.kt b/library/src/main/java/io/appwrite/services/Storage.kt index 063290f..6a8e973 100644 --- a/library/src/main/java/io/appwrite/services/Storage.kt +++ b/library/src/main/java/io/appwrite/services/Storage.kt @@ -148,10 +148,10 @@ class Storage(client: Client) : Service(client) { /** * Update a file by its unique ID. Only users with write permissions have access to update this resource. * - * @param bucketId Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket). - * @param fileId File unique ID. - * @param name Name of the file - * @param permissions An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param bucketId Bucket unique ID. + * @param fileId File ID. + * @param name File name. + * @param permissions An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @return [io.appwrite.models.File] */ @JvmOverloads diff --git a/library/src/main/java/io/appwrite/services/Teams.kt b/library/src/main/java/io/appwrite/services/Teams.kt index 5d48f28..d3b6156 100644 --- a/library/src/main/java/io/appwrite/services/Teams.kt +++ b/library/src/main/java/io/appwrite/services/Teams.kt @@ -320,7 +320,7 @@ class Teams(client: Client) : Service(client) { @JvmOverloads suspend fun createMembership( teamId: String, - roles: List, + roles: List, email: String? = null, userId: String? = null, phone: String? = null, @@ -402,7 +402,7 @@ class Teams(client: Client) : Service(client) { suspend fun updateMembership( teamId: String, membershipId: String, - roles: List, + roles: List, ): io.appwrite.models.Membership { val apiPath = "/teams/{teamId}/memberships/{membershipId}" .replace("{teamId}", teamId)