├── .github └── ISSUE_TEMPLATE │ ├── bug.yaml │ ├── documentation.yaml │ └── feature.yaml ├── .gitignore ├── .gitpod.yml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── io │ │ └── appwrite │ │ └── playgroundforandroid │ │ ├── Extensions.kt │ │ ├── MainActivity.kt │ │ └── PlaygroundViewModel.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values-night │ └── themes.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro └── settings.gradle /.github/ISSUE_TEMPLATE/bug.yaml: -------------------------------------------------------------------------------- 1 | name: "🐛 Bug Report" 2 | description: "Submit a bug report to help us improve" 3 | title: "🐛 Bug Report: " 4 | labels: [bug] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out our bug report form 🙏 10 | - type: textarea 11 | id: steps-to-reproduce 12 | validations: 13 | required: true 14 | attributes: 15 | label: "👟 Reproduction steps" 16 | description: "How do you trigger this bug? Please walk us through it step by step." 17 | placeholder: "When I ..." 18 | - type: textarea 19 | id: expected-behavior 20 | validations: 21 | required: true 22 | attributes: 23 | label: "👍 Expected behavior" 24 | description: "What did you think would happen?" 25 | placeholder: "It should ..." 26 | - type: textarea 27 | id: actual-behavior 28 | validations: 29 | required: true 30 | attributes: 31 | label: "👎 Actual Behavior" 32 | description: "What did actually happen? Add screenshots, if applicable." 33 | placeholder: "It actually ..." 34 | - type: dropdown 35 | id: appwrite-version 36 | attributes: 37 | label: "🎲 Appwrite version" 38 | description: "What version of Appwrite are you running?" 39 | options: 40 | - Version 0.10.x 41 | - Version 0.9.x 42 | - Version 0.8.x 43 | - Version 0.7.x 44 | - Version 0.6.x 45 | - Different version (specify in environment) 46 | validations: 47 | required: true 48 | - type: dropdown 49 | id: operating-system 50 | attributes: 51 | label: "💻 Operating system" 52 | description: "What OS is your server / device running on?" 53 | options: 54 | - Linux 55 | - MacOS 56 | - Windows 57 | - Something else 58 | validations: 59 | required: true 60 | - type: textarea 61 | id: enviromnemt 62 | validations: 63 | required: false 64 | attributes: 65 | label: "🧱 Your Environment" 66 | description: "Is your environment customized in any way?" 67 | placeholder: "I use Cloudflare for ..." 68 | - type: checkboxes 69 | id: no-duplicate-issues 70 | attributes: 71 | label: "👀 Have you spent some time to check if this issue has been raised before?" 72 | description: "Have you Googled for a similar issue or checked our older issues for a similar bug?" 73 | options: 74 | - label: "I checked and didn't find similar issue" 75 | required: true 76 | - type: checkboxes 77 | id: read-code-of-conduct 78 | attributes: 79 | label: "🏢 Have you read the Code of Conduct?" 80 | options: 81 | - label: "I have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/HEAD/CODE_OF_CONDUCT.md)" 82 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.yaml: -------------------------------------------------------------------------------- 1 | name: "📚 Documentation" 2 | description: "Report an issue related to documentation" 3 | title: "📚 Documentation: " 4 | labels: [documentation] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to make our documentation better 🙏 10 | - type: textarea 11 | id: issue-description 12 | validations: 13 | required: true 14 | attributes: 15 | label: "💭 Description" 16 | description: "A clear and concise description of what the issue is." 17 | placeholder: "Documentation should not ..." 18 | - type: checkboxes 19 | id: no-duplicate-issues 20 | attributes: 21 | label: "👀 Have you spent some time to check if this issue has been raised before?" 22 | description: "Have you Googled for a similar issue or checked our older issues for a similar bug?" 23 | options: 24 | - label: "I checked and didn't find similar issue" 25 | required: true 26 | - type: checkboxes 27 | id: read-code-of-conduct 28 | attributes: 29 | label: "🏢 Have you read the Code of Conduct?" 30 | options: 31 | - label: "I have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/HEAD/CODE_OF_CONDUCT.md)" 32 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yaml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature 2 | description: "Submit a proposal for a new feature" 3 | title: "🚀 Feature: " 4 | labels: [feature] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out our feature request form 🙏 10 | - type: textarea 11 | id: feature-description 12 | validations: 13 | required: true 14 | attributes: 15 | label: "🔖 Feature description" 16 | description: "A clear and concise description of what the feature is." 17 | placeholder: "You should add ..." 18 | - type: textarea 19 | id: pitch 20 | validations: 21 | required: true 22 | attributes: 23 | label: "🎤 Pitch" 24 | description: "Please explain why this feature should be implemented and how it would be used. Add examples, if applicable." 25 | placeholder: "In my use-case, ..." 26 | - type: checkboxes 27 | id: no-duplicate-issues 28 | attributes: 29 | label: "👀 Have you spent some time to check if this issue has been raised before?" 30 | description: "Have you Googled for a similar issue or checked our older issues for a similar bug?" 31 | options: 32 | - label: "I checked and didn't find similar issue" 33 | required: true 34 | - type: checkboxes 35 | id: read-code-of-conduct 36 | attributes: 37 | label: "🏢 Have you read the Code of Conduct?" 38 | options: 39 | - label: "I have read the [Code of Conduct](https://github.com/appwrite/appwrite/blob/HEAD/CODE_OF_CONDUCT.md)" 40 | required: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | kotlin-android/build 17 | /.idea -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | 7 | tasks: 8 | - init: ./gradlew build 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Appwrite's Android Playground 🎮 2 | 3 | Appwrite playground for Android is a simple way to explore the Appwrite API & Appwrite Android SDK. Use the source code of this page to learn how to use the different Appwrite Android SDK features. 4 | 5 | ## Get Started 6 | 7 | The **app/src/main/java/com/example/playgroundforandroid/PlaygroundViewModel.kt** file contains all the playground examples and source code. 8 | 9 | You can learn how to integrate your Appwrite Android SDK in your project and see different features of the SDK that can be used. 10 | 11 | This playground doesn't include any Appwrite best practices but rather intended to show the most simple examples and use cases of using Appwrite API in your android app. 12 | 13 | ## Contributing 14 | 15 | All code contributions - including those of people having commit access - must go through a pull request and approved by a core developer before being merged. This is to ensure proper review of all the code. 16 | 17 | We truly ❤️ pull requests! If you wish to help, you can learn more about how you can contribute to this project in the [contribution guide](https://github.com/appwrite/appwrite/blob/master/CONTRIBUTING.md). 18 | 19 | ## Security 20 | 21 | For security issues, kindly email us [security@appwrite.io](mailto:security@appwrite.io) instead of posting a public issue in GitHub. 22 | 23 | ## Follow Us 24 | 25 | Join our growing community around the world! Follow us on [Twitter](https://twitter.com/appwrite), [Facebook Page](https://www.facebook.com/appwrite.io), [Facebook Group](https://www.facebook.com/groups/appwrite.developers/) or join our [Discord Server](https://appwrite.io/discord) for more help, ideas and discussions. 26 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | } 6 | 7 | android { 8 | namespace "io.appwrite.playgroundforandroid" 9 | compileSdk 34 10 | defaultConfig { 11 | applicationId "io.appwrite.playgroundforandroid" 12 | minSdk 21 13 | targetSdk 34 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_11 28 | targetCompatibility JavaVersion.VERSION_11 29 | } 30 | kotlinOptions { 31 | jvmTarget = '11' 32 | } 33 | buildFeatures { 34 | viewBinding true 35 | } 36 | } 37 | 38 | dependencies { 39 | implementation 'io.appwrite:sdk-for-android:5.1.0' 40 | 41 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 42 | implementation 'androidx.core:core-ktx:1.8.0' 43 | implementation 'androidx.appcompat:appcompat:1.5.0' 44 | implementation 'com.google.android.material:material:1.6.1' 45 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4' 46 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' 47 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/io/appwrite/playgroundforandroid/Extensions.kt: -------------------------------------------------------------------------------- 1 | package io.appwrite.playgroundforandroid 2 | 3 | import android.content.ContentResolver 4 | import android.net.Uri 5 | import android.provider.OpenableColumns 6 | 7 | fun ContentResolver.getFileName(fileUri: Uri): String { 8 | var name = "" 9 | val returnCursor = this.query(fileUri, null, null, null, null) 10 | if (returnCursor != null) { 11 | val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) 12 | returnCursor.moveToFirst() 13 | name = returnCursor.getString(nameIndex) 14 | returnCursor.close() 15 | } 16 | return name 17 | } -------------------------------------------------------------------------------- /app/src/main/java/io/appwrite/playgroundforandroid/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package io.appwrite.playgroundforandroid 2 | 3 | import android.Manifest 4 | import android.content.pm.PackageManager 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import android.widget.TextView 8 | import android.widget.Toast 9 | import androidx.activity.result.contract.ActivityResultContracts 10 | import androidx.appcompat.app.AlertDialog 11 | import androidx.appcompat.app.AppCompatActivity 12 | import androidx.core.content.ContextCompat 13 | import androidx.lifecycle.ViewModelProvider 14 | import io.appwrite.playgroundforandroid.databinding.ActivityMainBinding 15 | import io.appwrite.enums.OAuthProvider 16 | import java.io.File 17 | 18 | class MainActivity : AppCompatActivity() { 19 | 20 | private lateinit var binding: ActivityMainBinding 21 | private lateinit var viewModel: PlaygroundViewModel 22 | 23 | private val output: TextView by lazy { 24 | binding.textView 25 | } 26 | 27 | private val getContent = 28 | registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> 29 | uri ?: return@registerForActivityResult 30 | val descriptor = contentResolver.openFileDescriptor(uri, "r", null) 31 | val copyDest = File(cacheDir, contentResolver.getFileName(uri)) 32 | viewModel.uploadFile(descriptor!!.fileDescriptor, copyDest) 33 | } 34 | 35 | private val requestPermissions = 36 | registerForActivityResult(ActivityResultContracts.RequestPermission()) { 37 | if (it) { 38 | getContent.launch("image/*") 39 | } 40 | } 41 | 42 | override fun onCreate(savedInstanceState: Bundle?) { 43 | super.onCreate(savedInstanceState) 44 | binding = ActivityMainBinding.inflate(layoutInflater) 45 | setContentView(binding.root) 46 | 47 | viewModel = ViewModelProvider(this).get(PlaygroundViewModel::class.java) 48 | viewModel.createClient(this) 49 | 50 | setClickListeners() 51 | setObservers() 52 | } 53 | 54 | private fun setClickListeners() { 55 | binding.createAccount.setOnClickListener { 56 | viewModel.createAccount() 57 | } 58 | binding.loginWithEmail.setOnClickListener { 59 | viewModel.createSession() 60 | } 61 | binding.createDoc.setOnClickListener { 62 | viewModel.createDocument() 63 | } 64 | binding.listDoc.setOnClickListener { 65 | viewModel.listDocuments() 66 | } 67 | binding.deleteDoc.setOnClickListener { 68 | viewModel.deleteDocument() 69 | } 70 | binding.createExecution.setOnClickListener { 71 | viewModel.createExecution() 72 | } 73 | binding.listExecutions.setOnClickListener { 74 | viewModel.listExecutions() 75 | } 76 | binding.getExecution.setOnClickListener { 77 | viewModel.getExecution() 78 | } 79 | binding.loginWithFacebook.setOnClickListener { 80 | viewModel.createOAuth2Session(this, OAuthProvider.FACEBOOK) 81 | } 82 | binding.loginWithGithub.setOnClickListener { 83 | viewModel.createOAuth2Session(this, OAuthProvider.GITHUB) 84 | } 85 | binding.loginWithGoogle.setOnClickListener { 86 | viewModel.createOAuth2Session(this, OAuthProvider.GOOGLE) 87 | } 88 | binding.updateEmail.setOnClickListener { 89 | viewModel.updateAccountEmail() 90 | } 91 | binding.updatePrefs.setOnClickListener { 92 | viewModel.updateAccountPrefs() 93 | } 94 | binding.updateStatus.setOnClickListener { 95 | viewModel.updateStatus() 96 | } 97 | binding.subscribeButton.setOnClickListener { 98 | viewModel.subscribeToRealtime() 99 | Toast.makeText(this, R.string.subscribed, Toast.LENGTH_SHORT).show() 100 | } 101 | binding.logoutButton.setOnClickListener { 102 | viewModel.deleteSession() 103 | } 104 | 105 | binding.uploadFile.setOnClickListener { 106 | when (PackageManager.PERMISSION_GRANTED) { 107 | ContextCompat.checkSelfPermission( 108 | this, 109 | Manifest.permission.READ_MEDIA_IMAGES, 110 | 111 | ) -> { 112 | getContent.launch("image/*") 113 | } 114 | else -> { 115 | requestPermissions.launch(Manifest.permission.READ_MEDIA_IMAGES) 116 | } 117 | } 118 | } 119 | binding.listFiles.setOnClickListener { 120 | viewModel.listFiles() 121 | } 122 | binding.deleteFile.setOnClickListener { 123 | viewModel.deleteFile() 124 | } 125 | } 126 | 127 | private fun setObservers() { 128 | viewModel.user.observe(this) { 129 | if (it != null) { 130 | output.text = "${it.name} ${it.email}" 131 | } else { 132 | output.text = getString(R.string.anonymous) 133 | } 134 | } 135 | viewModel.items.observe(this) { 136 | Toast.makeText( 137 | binding.root.context, 138 | "REALTIME EVENT: $it", 139 | Toast.LENGTH_LONG 140 | ).show() 141 | } 142 | viewModel.dialogText.observe(this) { 143 | if (it == null) { 144 | return@observe 145 | } 146 | AlertDialog.Builder(this) 147 | .setTitle("Info") 148 | .setMessage(it) 149 | .setNeutralButton("OK") { d, _ -> d.dismiss() } 150 | .create() 151 | .show() 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /app/src/main/java/io/appwrite/playgroundforandroid/PlaygroundViewModel.kt: -------------------------------------------------------------------------------- 1 | package io.appwrite.playgroundforandroid 2 | 3 | import android.content.Context 4 | import androidx.activity.ComponentActivity 5 | import androidx.lifecycle.LiveData 6 | import androidx.lifecycle.MutableLiveData 7 | import androidx.lifecycle.ViewModel 8 | import androidx.lifecycle.viewModelScope 9 | import io.appwrite.* 10 | import io.appwrite.exceptions.AppwriteException 11 | import io.appwrite.extensions.toJson 12 | import io.appwrite.models.* 13 | import io.appwrite.models.User 14 | import io.appwrite.services.* 15 | import io.appwrite.services.Locale 16 | import kotlinx.coroutines.launch 17 | import java.io.File 18 | import java.io.FileDescriptor 19 | import java.io.FileInputStream 20 | import java.io.FileOutputStream 21 | import java.lang.System.currentTimeMillis 22 | import io.appwrite.models.User as AppwriteAccount 23 | import io.appwrite.models.File as AppwriteFile 24 | 25 | class PlaygroundViewModel : ViewModel() { 26 | 27 | private val endpoint = "YOUR_ENDPOINT" 28 | private val projectId = "YOUR_PROJECT_ID" 29 | private val collectionId = "YOUR_COLLECTION_ID" // Single required 'username' string attribute 30 | private val functionId = "YOUR_FUNCTION_ID" 31 | private val bucketId = "YOUR_BUCKET_ID" 32 | private var databaseId = "YOUR_DATABASE_ID" 33 | 34 | private var documentId = "" 35 | private var executionId = "" 36 | private var fileId = "" 37 | 38 | private lateinit var client: Client 39 | 40 | private lateinit var account: Account 41 | private lateinit var avatars: Avatars 42 | private lateinit var databases: Databases 43 | private lateinit var storage: Storage 44 | private lateinit var functions: Functions 45 | private lateinit var locale: Locale 46 | private lateinit var teams: Teams 47 | private lateinit var realtime: Realtime 48 | 49 | private val _items = MutableLiveData() 50 | val items: LiveData = _items 51 | 52 | fun createClient(context: Context) { 53 | client = Client(context) 54 | .setEndpoint(endpoint) 55 | .setProject(projectId) 56 | .setSelfSigned(true) 57 | 58 | account = Account(client) 59 | avatars = Avatars(client) 60 | databases = Databases(client) 61 | storage = Storage(client) 62 | functions = Functions(client) 63 | locale = Locale(client) 64 | teams = Teams(client) 65 | realtime = Realtime(client) 66 | } 67 | 68 | private val _user = MutableLiveData>?>(null) 69 | val user: LiveData>?> = _user 70 | 71 | private val _dialogText = MutableLiveData(null) 72 | val dialogText: LiveData = _dialogText 73 | 74 | var emailId = currentTimeMillis() 75 | 76 | fun createAccount() { 77 | viewModelScope.launch { 78 | try { 79 | val user: User> = account.create( 80 | userId = ID.unique(), 81 | email = "$emailId@appwrite.io", 82 | password = "password" 83 | ) 84 | val json = user.toJson() 85 | _dialogText.postValue(json) 86 | _user.postValue(user) 87 | } catch (e: AppwriteException) { 88 | _dialogText.postValue(e.message) 89 | } 90 | } 91 | } 92 | 93 | fun createSession() { 94 | viewModelScope.launch { 95 | try { 96 | val session: Session = account.createEmailPasswordSession( 97 | email = "$emailId@appwrite.io", 98 | password = "password" 99 | ) 100 | val json = session.toJson() 101 | _dialogText.postValue(json) 102 | getAccount() 103 | } catch (e: AppwriteException) { 104 | _dialogText.postValue(e.message) 105 | } 106 | } 107 | } 108 | 109 | fun getSession() { 110 | viewModelScope.launch { 111 | try { 112 | val session: Session = account.getSession("current") 113 | val json = session.toJson() 114 | _dialogText.postValue(json) 115 | } catch (e: AppwriteException) { 116 | _dialogText.postValue(e.message) 117 | } 118 | } 119 | } 120 | 121 | fun getAccount() { 122 | viewModelScope.launch { 123 | try { 124 | val user: User> = account.get() 125 | val json = user.toJson() 126 | _dialogText.postValue(json) 127 | _user.postValue(user) 128 | } catch (e: AppwriteException) { 129 | _dialogText.postValue(e.message) 130 | } 131 | } 132 | } 133 | 134 | fun createOAuth2Session( 135 | activity: ComponentActivity, 136 | provider: io.appwrite.enums.OAuthProvider 137 | ) { 138 | viewModelScope.launch { 139 | try { 140 | account.createOAuth2Session(activity, provider) 141 | } catch (e: AppwriteException) { 142 | _dialogText.postValue(e.message) 143 | } 144 | } 145 | } 146 | 147 | fun updateAccountEmail() { 148 | viewModelScope.launch { 149 | try { 150 | emailId = currentTimeMillis() 151 | val user: User> = account.updateEmail( 152 | email = "$emailId@email.com", 153 | password = "password" 154 | ) 155 | val json = user.toJson() 156 | _user.postValue(user) 157 | _dialogText.postValue(json) 158 | } catch (e: AppwriteException) { 159 | _dialogText.postValue(e.message) 160 | } 161 | } 162 | } 163 | 164 | fun updateAccountPrefs() { 165 | viewModelScope.launch { 166 | try { 167 | val user: User> = account.updatePrefs( 168 | mapOf( 169 | "key" to "value" 170 | ) 171 | ) 172 | val json = user.toJson() 173 | _user.postValue(user) 174 | _dialogText.postValue(json) 175 | } catch (e: AppwriteException) { 176 | _dialogText.postValue(e.message) 177 | } 178 | } 179 | } 180 | 181 | fun updateStatus() { 182 | viewModelScope.launch { 183 | try { 184 | val user: User> = account.updateStatus() 185 | val json = user.toJson() 186 | _user.postValue(user) 187 | _dialogText.postValue(json) 188 | } catch (e: AppwriteException) { 189 | _dialogText.postValue(e.message) 190 | } 191 | } 192 | } 193 | 194 | fun deleteSession() { 195 | viewModelScope.launch { 196 | try { 197 | account.deleteSession("current") 198 | _user.postValue(null) 199 | _dialogText.postValue("Logged out!") 200 | } catch (e: AppwriteException) { 201 | _dialogText.postValue(e.message) 202 | } 203 | } 204 | } 205 | 206 | fun createDocument() { 207 | viewModelScope.launch { 208 | try { 209 | val document: Document> = databases.createDocument( 210 | databaseId, 211 | collectionId, 212 | documentId = ID.unique(), 213 | data = mapOf( 214 | "username" to "Android" 215 | ), 216 | permissions = listOf( 217 | Permission.read(Role.users()), 218 | Permission.update(Role.users()), 219 | Permission.delete(Role.users()), 220 | ), 221 | ) 222 | val json = document.toJson() 223 | documentId = document.id 224 | _dialogText.postValue(json) 225 | } catch (e: AppwriteException) { 226 | _dialogText.postValue(e.message) 227 | } 228 | } 229 | } 230 | 231 | fun listDocuments() { 232 | viewModelScope.launch { 233 | try { 234 | val documentList: DocumentList> = databases.listDocuments( 235 | databaseId, 236 | collectionId, 237 | queries = listOf( 238 | Query.equal("username", "Android") 239 | ) 240 | ) 241 | val json = documentList.toJson() 242 | _dialogText.postValue(json) 243 | } catch (e: AppwriteException) { 244 | _dialogText.postValue(e.message) 245 | } 246 | } 247 | } 248 | 249 | fun deleteDocument() { 250 | viewModelScope.launch { 251 | try { 252 | databases.deleteDocument( 253 | databaseId, 254 | collectionId, 255 | documentId 256 | ) 257 | _dialogText.postValue("Deleted document!") 258 | } catch (e: AppwriteException) { 259 | _dialogText.postValue(e.message) 260 | } 261 | } 262 | } 263 | 264 | fun createExecution() { 265 | viewModelScope.launch { 266 | try { 267 | val execution: Execution = functions.createExecution( 268 | functionId, 269 | "{}" 270 | ) 271 | val json = execution.toJson() 272 | executionId = execution.id 273 | _dialogText.postValue(json) 274 | } catch (e: AppwriteException) { 275 | _dialogText.postValue(e.message) 276 | } 277 | } 278 | } 279 | 280 | fun listExecutions() { 281 | viewModelScope.launch { 282 | try { 283 | val executionList: ExecutionList = functions.listExecutions(functionId) 284 | val json = executionList.toJson() 285 | _dialogText.postValue(json) 286 | } catch (e: AppwriteException) { 287 | _dialogText.postValue(e.message) 288 | } 289 | } 290 | } 291 | 292 | fun getExecution() { 293 | viewModelScope.launch { 294 | try { 295 | val execution: Execution = functions.getExecution( 296 | functionId, 297 | executionId 298 | ) 299 | val json = execution.toJson() 300 | _dialogText.postValue(json) 301 | } catch (e: AppwriteException) { 302 | _dialogText.postValue(e.message) 303 | } 304 | } 305 | } 306 | 307 | fun uploadFile(input: FileDescriptor, file: File) { 308 | viewModelScope.launch { 309 | try { 310 | val inputStream = FileInputStream(input) 311 | val outputStream = FileOutputStream(file) 312 | inputStream.copyTo(outputStream) 313 | 314 | val storageFile: AppwriteFile = storage.createFile( 315 | bucketId, 316 | fileId = ID.unique(), 317 | file = InputFile.fromFile(file), 318 | permissions = listOf( 319 | Permission.read(Role.users()), 320 | Permission.update(Role.users()), 321 | Permission.delete(Role.users()), 322 | ), 323 | ) 324 | fileId = storageFile.id 325 | val json = storageFile.toJson() 326 | _dialogText.postValue(json) 327 | } catch (e: AppwriteException) { 328 | _dialogText.postValue(e.message) 329 | } 330 | } 331 | } 332 | 333 | fun listFiles() { 334 | viewModelScope.launch { 335 | try { 336 | val fileList: FileList = storage.listFiles(bucketId) 337 | val json = fileList.toJson() 338 | _dialogText.postValue(json) 339 | } catch (e: AppwriteException) { 340 | _dialogText.postValue(e.message) 341 | } 342 | } 343 | } 344 | 345 | fun deleteFile() { 346 | viewModelScope.launch { 347 | try { 348 | storage.deleteFile( 349 | bucketId = bucketId, 350 | fileId = fileId 351 | ) 352 | _dialogText.postValue("File deleted!") 353 | } catch (e: AppwriteException) { 354 | _dialogText.postValue(e.message) 355 | } 356 | } 357 | } 358 | 359 | fun subscribeToRealtime() { 360 | val channel = "databases.${databaseId}.collections.${collectionId}.documents" 361 | 362 | realtime.subscribe(channel) { 363 | _items.postValue(it.toJson()) 364 | } 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 27 | 28 | 35 | 36 |