├── .github
└── ISSUE_TEMPLATE
│ ├── bug.yaml
│ ├── documentation.yaml
│ └── feature.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── appwritedemoapplication
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── appwritedemoapplication
│ │ │ ├── Config.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── ui
│ │ │ ├── Accounts
│ │ │ │ ├── AccountsFragment.kt
│ │ │ │ └── AccountsViewModel.kt
│ │ │ ├── Avatars
│ │ │ │ ├── AvatarsFragment.kt
│ │ │ │ └── AvatarsViewModel.kt
│ │ │ ├── Database
│ │ │ │ ├── DatabaseFragment.kt
│ │ │ │ └── DatabaseViewModel.kt
│ │ │ ├── Functions
│ │ │ │ ├── FunctionsFragment.kt
│ │ │ │ └── FunctionsViewModel.kt
│ │ │ ├── Localization
│ │ │ │ ├── LocalizationFragment.kt
│ │ │ │ └── LocalizationViewModel.kt
│ │ │ ├── Storage
│ │ │ │ ├── StorageFragment.kt
│ │ │ │ └── StorageViewModel.kt
│ │ │ └── Teams
│ │ │ │ ├── TeamsFragment.kt
│ │ │ │ └── TeamsViewModel.kt
│ │ │ └── utils
│ │ │ ├── Client.kt
│ │ │ └── Event.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_menu_camera.xml
│ │ ├── ic_menu_gallery.xml
│ │ ├── ic_menu_slideshow.xml
│ │ └── side_nav_bar.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── app_bar_main.xml
│ │ ├── content_main.xml
│ │ ├── fragment_account.xml
│ │ ├── fragment_avatars.xml
│ │ ├── fragment_database.xml
│ │ ├── fragment_functions.xml
│ │ ├── fragment_localization.xml
│ │ ├── fragment_storage.xml
│ │ ├── fragment_teams.xml
│ │ └── nav_header_main.xml
│ │ ├── menu
│ │ └── activity_main_drawer.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
│ │ ├── navigation
│ │ └── mobile_navigation.xml
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── appwritedemoapplication
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── 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 documentation request?"
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 feature request?"
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/
5 | /.idea/caches
6 | /.idea/libraries
7 | /.idea/modules.xml
8 | /.idea/workspace.xml
9 | /.idea/navEditor.xml
10 | /.idea/assetWizardSettings.xml
11 | .DS_Store
12 | /build
13 | /captures
14 | .externalNativeBuild
15 | .cxx
16 | local.properties
17 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to make participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity, expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at team@appwrite.io. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We would ❤️ for you to contribute to Appwrite and help make it better! We want contributing to Appwrite to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more.
4 |
5 | ## How to Start?
6 |
7 | If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or [@appwrite_io](https://twitter.com/appwrite_io) on Twitter, and anyone from the [Appwrite team on Discord](https://discord.gg/GSeTUeA). You can also submit an issue, and a maintainer can guide you!
8 |
9 | ## Code of Conduct
10 |
11 | Help us keep Appwrite open and inclusive. Please read and follow our [Code of Conduct](/CODE_OF_CONDUCT.md).
12 |
13 | ## Submit a Pull Request 🚀
14 |
15 | Branch naming convention is as following
16 |
17 | `TYPE-ISSUE_ID-DESCRIPTION`
18 |
19 | example:
20 |
21 | ```
22 | doc-548-submit-a-pull-request-section-to-contribution-guide
23 | ```
24 |
25 | When `TYPE` can be:
26 |
27 | - **feat** - is a new feature
28 | - **doc** - documentation only changes
29 | - **cicd** - changes related to CI/CD system
30 | - **fix** - a bug fix
31 | - **refactor** - code change that neither fixes a bug nor adds a feature
32 |
33 | **All PRs must include a commit message with the changes description!**
34 |
35 | For the initial start, fork the project and use git clone command to download the repository to your computer. A standard procedure for working on an issue would be to:
36 |
37 | 1. `git pull`, before creating a new branch, pull the changes from upstream. Your master needs to be up to date.
38 |
39 | ```
40 | $ git pull
41 | ```
42 |
43 | 2. Create new branch from `master` like: `doc-548-submit-a-pull-request-section-to-contribution-guide`
44 |
45 | ```
46 | $ git checkout -b [name_of_your_new_branch]
47 | ```
48 |
49 | 3. Work - commit - repeat ( be sure to be in your branch )
50 |
51 | 4. Push changes to GitHub
52 |
53 | ```
54 | $ git push origin [name_of_your_new_branch]
55 | ```
56 |
57 | 5. Submit your changes for review
58 | If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button.
59 | 6. Start a Pull Request
60 | Now submit the pull request and click on `Create pull request`.
61 | 7. Get a code review approval/reject
62 | 8. After approval, merge your PR
63 | 9. GitHub will automatically delete the branch after the merge is done. (they can still be restored).
64 |
65 | ## Introducing New Features
66 |
67 | We would 💖 you to contribute to Appwrite, but we would also like to make sure Appwrite is as great as possible and loyal to its vision and mission statement 🙏.
68 |
69 | For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request.
70 |
71 | This will allow the Appwrite community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision.
72 |
73 | This is also important for the Appwrite lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc).
74 |
75 | ## Other Ways to Help
76 |
77 | Pull requests are great, but there are many other areas where you can help Appwrite.
78 |
79 | ### Blogging & Speaking
80 |
81 | Blogging, speaking about, or creating tutorials about one of Appwrite’s many features. Mention [@appwrite_io](https://twitter.com/appwrite_io) on Twitter and/or email team [at] appwrite [dot] io so we can give pointers and tips and help you spread the word by promoting your content on the different Appwrite communication channels. Please add your blog posts and videos of talks to our [Awesome Appwrite](https://github.com/appwrite/awesome-appwrite) repo on GitHub.
82 |
83 | ### Presenting at Meetups
84 |
85 | Presenting at meetups and conferences about your Appwrite projects. Your unique challenges and successes in building things with Appwrite can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help!
86 |
87 | ### Sending Feedbacks & Reporting Bugs
88 |
89 | Sending feedback is a great way for us to understand your different use cases of Appwrite better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA).
90 |
91 | ### Submitting New Ideas
92 |
93 | If you think Appwrite could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature.
94 |
95 | ### Improving Documentation
96 |
97 | Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated.
98 |
99 | ### Helping Someone
100 |
101 | Searching for Appwrite on Discord, GitHub, or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Appwrite's repo!
102 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Christy Jacob
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🤖 Get Started With Android
2 |
3 | A Simple Android App to get started with Appwrite's Android SDK
4 |
5 | ## 🚀 Usage
6 |
7 | - Clone the repository
8 |
9 | ```sh
10 | git clone https://github.com/appwrite/demo-getstarted-with-android
11 | ```
12 |
13 | - Import into Android Studio and run!
14 |
15 | ## 📁 Folder Structure
16 |
17 | Each folder under the `ui` directory has interactions with one particular API of Appwrite.
18 |
19 | The `Accounts` directory contains interactions with Appwrite's Account's API and so on.
20 |
21 | `Client.kt` contains a singleton object that initializes the Appwrite client.
22 |
23 | `Config.kt` contains a singleton object that contains the Appwrite project's configuration.
24 |
25 | ```sh
26 | ➜ appwrite-android-demo git:(main) ✗ tree app/src/main/java/com/example/appwritedemoapplication/
27 | app/src/main/java/com/example/appwritedemoapplication/
28 | ├── MainActivity.kt
29 | ├── Config.kt
30 | ├── ui
31 | │ ├── Accounts
32 | │ │ ├── AccountsFragment.kt
33 | │ │ └── AccountsViewModel.kt
34 | │ ├── Avatars
35 | │ │ ├── AvatarsFragment.kt
36 | │ │ └── AvatarsViewModel.kt
37 | │ ├── Database
38 | │ │ ├── DatabaseFragment.kt
39 | │ │ └── DatabaseViewModel.kt
40 | │ ├── Functions
41 | │ │ ├── FunctionsFragment.kt
42 | │ │ └── FunctionsViewModel.kt
43 | │ ├── Localization
44 | │ │ ├── LocalizationFragment.kt
45 | │ │ └── LocalizationViewModel.kt
46 | │ ├── Storage
47 | │ │ ├── StorageFragment.kt
48 | │ │ └── StorageViewModel.kt
49 | │ └── Teams
50 | │ ├── TeamsFragment.kt
51 | │ └── TeamsViewModel.kt
52 | └── utils
53 | ├── Client.kt
54 | └── Event.kt
55 |
56 | ```
57 |
58 | ## ✨ Screenshots
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | ## 🍻 Contributing
68 |
69 | Contributions, issues and feature requests are welcome.
70 | Feel free to check [issues page](https://github.com/appwrite/demo-getstarted-with-android/issues) if you want to contribute.
71 |
72 |
73 | ## 🤕 Support
74 | If you get stuck anywhere, hop onto one of our [support channels in discord](https://appwrite.io/discord) and we'd be delighted to help you out 🤝
75 |
--------------------------------------------------------------------------------
/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 | compileSdkVersion 33
9 |
10 | defaultConfig {
11 | applicationId "com.example.appwritedemoapplication"
12 | minSdkVersion 23
13 | targetSdkVersion 33
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 | packagingOptions {
20 | resources {
21 | excludes += ['META-INF/LICENSE-notice.md', 'META-INF/LICENSE.md']
22 | }
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | buildFeatures {
32 | dataBinding true
33 | }
34 | compileOptions {
35 | sourceCompatibility JavaVersion.VERSION_1_8
36 | targetCompatibility JavaVersion.VERSION_1_8
37 | }
38 | kotlinOptions {
39 | jvmTarget = '1.8'
40 | }
41 | namespace 'com.example.appwritedemoapplication'
42 | }
43 |
44 | dependencies {
45 |
46 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
47 | implementation 'androidx.core:core-ktx:1.9.0'
48 | implementation 'androidx.appcompat:appcompat:1.5.1'
49 | implementation 'com.google.android.material:material:1.6.1'
50 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
51 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.2'
52 | implementation "androidx.fragment:fragment-ktx:1.5.3"
53 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.2'
54 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
55 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
56 | implementation 'androidx.navigation:navigation-fragment-ktx:2.5.2'
57 | implementation 'androidx.navigation:navigation-ui-ktx:2.5.2'
58 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
59 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
60 | implementation "androidx.documentfile:documentfile:1.0.1"
61 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
62 | implementation 'io.appwrite:sdk-for-android:1.1.0'
63 | testImplementation 'junit:junit:4.13.2'
64 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
65 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
66 | }
--------------------------------------------------------------------------------
/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/androidTest/java/com/example/appwritedemoapplication/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.example.appwritedemoapplication" , appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/Config.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication
2 |
3 | /**
4 | * Config file for the Appwrite demo application
5 | */
6 | object Config {
7 |
8 | // Change below values to match your Appwrite project
9 | const val HOST = "[HOST]"
10 | const val PROJECT = "[PROJECT]"
11 | const val DATABASE = "[DATABASE]"
12 | const val COLLECTION = "[COLLECTION]"
13 | const val STORAGE = "[BUCKET]"
14 |
15 | // DO NOT mutate below values
16 | const val ENDPOINT = "https://$HOST/v1"
17 | const val CALLBACK = "appwrite-callback-$PROJECT"
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import androidx.appcompat.widget.Toolbar
6 | import androidx.drawerlayout.widget.DrawerLayout
7 | import androidx.navigation.findNavController
8 | import androidx.navigation.ui.AppBarConfiguration
9 | import androidx.navigation.ui.navigateUp
10 | import androidx.navigation.ui.setupActionBarWithNavController
11 | import androidx.navigation.ui.setupWithNavController
12 | import com.example.appwritedemoapplication.utils.Client
13 | import com.google.android.material.navigation.NavigationView
14 |
15 | class MainActivity : AppCompatActivity() {
16 |
17 | private lateinit var appBarConfiguration: AppBarConfiguration
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | setContentView(R.layout.activity_main)
22 | val toolbar: Toolbar = findViewById(R.id.toolbar)
23 | setSupportActionBar(toolbar)
24 |
25 | val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
26 | val navView: NavigationView = findViewById(R.id.nav_view)
27 | val navController = findNavController(R.id.nav_host_fragment)
28 | // Passing each menu ID as a set of Ids because each
29 | // menu should be considered as top level destinations.
30 | appBarConfiguration = AppBarConfiguration(setOf(
31 | R.id.nav_account , R.id.nav_teams , R.id.nav_database) , drawerLayout)
32 | setupActionBarWithNavController(navController , appBarConfiguration)
33 | navView.setupWithNavController(navController)
34 |
35 | Client.create(applicationContext)
36 | }
37 |
38 | override fun onSupportNavigateUp(): Boolean {
39 | val navController = findNavController(R.id.nav_host_fragment)
40 | return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Accounts/AccountsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Accounts
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.Toast
8 | import androidx.activity.ComponentActivity
9 | import androidx.databinding.DataBindingUtil
10 | import androidx.fragment.app.Fragment
11 | import androidx.lifecycle.Observer
12 | import androidx.lifecycle.ViewModelProvider
13 | import com.example.appwritedemoapplication.R
14 | import com.example.appwritedemoapplication.databinding.FragmentAccountBinding
15 |
16 |
17 | class AccountsFragment : Fragment() {
18 |
19 | private lateinit var binding: FragmentAccountBinding
20 | private lateinit var viewModel: AccountsViewModel
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater ,
24 | container: ViewGroup? ,
25 | savedInstanceState: Bundle?
26 | ): View? {
27 | viewModel = ViewModelProvider(this).get(AccountsViewModel::class.java)
28 | binding = DataBindingUtil.inflate(
29 | inflater,
30 | R.layout.fragment_account,
31 | container,
32 | false
33 | )
34 | binding.lifecycleOwner = viewLifecycleOwner
35 | binding.login.setOnClickListener{
36 | viewModel.onLogin(binding.email.text, binding.password.text)
37 | }
38 |
39 | binding.signup.setOnClickListener{
40 | viewModel.onSignup(binding.email.text, binding.password.text, binding.name.text)
41 | }
42 |
43 | binding.getUser.setOnClickListener{
44 | viewModel.getUser()
45 | }
46 |
47 | binding.oAuth.setOnClickListener{
48 | viewModel.oAuthLogin(activity as ComponentActivity)
49 | }
50 |
51 | binding.logout.setOnClickListener{
52 | viewModel.logout()
53 | }
54 |
55 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
56 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
57 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
58 | }
59 | })
60 |
61 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
62 | event?.getContentIfNotHandled()?.let {
63 | binding.responseTV.setText(it)
64 | }
65 | })
66 |
67 | return binding.root
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Accounts/AccountsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Accounts
2 |
3 | import android.text.Editable
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 com.example.appwritedemoapplication.Config
10 | import com.example.appwritedemoapplication.utils.Client.client
11 | import com.example.appwritedemoapplication.utils.Event
12 | import io.appwrite.ID
13 | import io.appwrite.exceptions.AppwriteException
14 | import io.appwrite.extensions.toJson
15 | import io.appwrite.services.Account
16 | import kotlinx.coroutines.launch
17 |
18 |
19 | class AccountsViewModel : ViewModel() {
20 |
21 | private val _error = MutableLiveData>().apply {
22 | value = null
23 | }
24 | val error: LiveData> = _error
25 |
26 | private val _response = MutableLiveData>().apply {
27 | value = null
28 | }
29 | val response: LiveData> = _response
30 |
31 | private val accountService by lazy {
32 | Account(client)
33 | }
34 |
35 | fun onLogin(email: Editable , password : Editable) {
36 | viewModelScope.launch {
37 | try {
38 | val response = accountService.createEmailSession(email.toString(), password.toString())
39 | val json = response.toJson()
40 | _response.postValue(Event(json))
41 | } catch (e: AppwriteException) {
42 | _error.postValue(Event(e))
43 | }
44 | }
45 |
46 | }
47 |
48 | fun onSignup(email: Editable , password : Editable, name: Editable) {
49 | viewModelScope.launch {
50 | try {
51 | val response = accountService.create(ID.unique(), email.toString(), password.toString(), name.toString())
52 | val json = response.toJson()
53 | _response.postValue(Event(json))
54 | } catch (e: AppwriteException) {
55 | _error.postValue(Event(e))
56 | }
57 | }
58 |
59 | }
60 |
61 | fun oAuthLogin(activity: ComponentActivity) {
62 | viewModelScope.launch {
63 | try {
64 | accountService.createOAuth2Session(activity, "facebook", "${Config.CALLBACK}://${Config.HOST}/auth/oauth2/success", "${Config.CALLBACK}://${Config.HOST}/auth/oauth2/failure")
65 | } catch (e: Exception) {
66 | _error.postValue(Event(e))
67 | } catch (e: AppwriteException) {
68 | _error.postValue(Event(e))
69 | }
70 | }
71 | }
72 |
73 | fun getUser() {
74 | viewModelScope.launch {
75 | try {
76 | val response = accountService.get()
77 | val json = response.toJson()
78 | _response.postValue(Event(json))
79 | } catch (e: AppwriteException) {
80 | _error.postValue(Event(e))
81 | }
82 | }
83 | }
84 |
85 | fun logout() {
86 | viewModelScope.launch {
87 | try {
88 | val response = accountService.deleteSession("current")
89 | val json = response.toJson().ifEmpty { "{}" }
90 | _response.postValue(Event(json))
91 | } catch (e: AppwriteException) {
92 | _error.postValue(Event(e))
93 | }
94 | }
95 | }
96 |
97 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Avatars/AvatarsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Avatars
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.TextView
8 | import android.widget.Toast
9 | import androidx.databinding.DataBindingUtil
10 | import androidx.fragment.app.Fragment
11 | import androidx.lifecycle.Observer
12 | import androidx.lifecycle.ViewModelProvider
13 | import com.example.appwritedemoapplication.R
14 | import com.example.appwritedemoapplication.databinding.FragmentAvatarsBinding
15 | import com.example.appwritedemoapplication.databinding.FragmentDatabaseBinding
16 | import com.example.appwritedemoapplication.ui.Database.DatabaseViewModel
17 |
18 | class AvatarsFragment : Fragment() {
19 |
20 | private lateinit var binding: FragmentAvatarsBinding
21 | private lateinit var viewModel: AvatarsViewModel
22 |
23 | override fun onCreateView(
24 | inflater: LayoutInflater ,
25 | container: ViewGroup? ,
26 | savedInstanceState: Bundle?
27 | ): View? {
28 | // Inflate view and obtain an instance of the binding class
29 | binding = DataBindingUtil.inflate(
30 | inflater,
31 | R.layout.fragment_avatars,
32 | container,
33 | false
34 | )
35 |
36 | binding.getBrowser.setOnClickListener{
37 | viewModel.getBrowser(binding.code.text)
38 | }
39 |
40 | binding.getCountryCode.setOnClickListener{
41 | viewModel.getCountryCode(binding.code.text)
42 | }
43 |
44 | binding.getCreditCard.setOnClickListener{
45 | viewModel.getCreditCard(binding.code.text)
46 | }
47 |
48 | binding.getQrCode.setOnClickListener{
49 | viewModel.getQrCode(binding.code.text)
50 | }
51 |
52 | viewModel = ViewModelProvider(this).get(AvatarsViewModel::class.java)
53 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
54 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
55 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
56 | }
57 | })
58 |
59 | viewModel.image.observe(viewLifecycleOwner, Observer { event ->
60 | event?.getContentIfNotHandled()?.let {
61 | binding.imageView.setImageBitmap(it)
62 | }
63 | })
64 |
65 | return binding.root
66 | }
67 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Avatars/AvatarsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Avatars
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.BitmapFactory
5 | import android.text.Editable
6 | import androidx.lifecycle.LiveData
7 | import androidx.lifecycle.MutableLiveData
8 | import androidx.lifecycle.ViewModel
9 | import androidx.lifecycle.viewModelScope
10 | import com.example.appwritedemoapplication.utils.Client
11 | import com.example.appwritedemoapplication.utils.Event
12 | import io.appwrite.exceptions.AppwriteException
13 | import io.appwrite.services.Avatars
14 | import kotlinx.coroutines.launch
15 |
16 | class AvatarsViewModel : ViewModel() {
17 | private val _error = MutableLiveData>().apply {
18 | value = null
19 | }
20 | val error: LiveData> = _error
21 |
22 | private val _image = MutableLiveData>().apply {
23 | value = null
24 | }
25 | val image: LiveData> = _image
26 |
27 | private val avatarsService by lazy {
28 | Avatars(Client.client)
29 | }
30 |
31 | fun getBrowser(code: Editable?) {
32 | viewModelScope.launch {
33 | try{
34 | val response = avatarsService.getBrowser(code.toString())
35 | val image = BitmapFactory.decodeByteArray(response, 0, response.size)
36 | _image.postValue(Event(image))
37 | } catch (e: AppwriteException) {
38 | _error.postValue(Event(e))
39 | }
40 | }
41 | }
42 |
43 | fun getCountryCode(code: Editable?) {
44 | viewModelScope.launch {
45 | try{
46 | val response = avatarsService.getFlag(code.toString())
47 | val image = BitmapFactory.decodeByteArray(response, 0, response.size)
48 | _image.postValue(Event(image))
49 | } catch (e: AppwriteException) {
50 | _error.postValue(Event(e))
51 | }
52 | }
53 | }
54 |
55 | fun getCreditCard(code: Editable?) {
56 | viewModelScope.launch {
57 | try{
58 | val response = avatarsService.getCreditCard(code.toString())
59 | val image = BitmapFactory.decodeByteArray(response, 0, response.size)
60 | _image.postValue(Event(image))
61 | } catch (e: AppwriteException) {
62 | _error.postValue(Event(e))
63 | }
64 | }
65 | }
66 |
67 | fun getQrCode(name: Editable?) {
68 | viewModelScope.launch {
69 | try{
70 | val response = avatarsService.getQR(name.toString())
71 | val image = BitmapFactory.decodeByteArray(response, 0, response.size)
72 | _image.postValue(Event(image))
73 | } catch (e: AppwriteException) {
74 | _error.postValue(Event(e))
75 | }
76 | }
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Database/DatabaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Database
2 |
3 | import android.os.Bundle
4 | import android.text.method.ScrollingMovementMethod
5 | import android.util.Log
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.Toast
10 | import androidx.databinding.DataBindingUtil
11 | import androidx.fragment.app.Fragment
12 | import androidx.lifecycle.Observer
13 | import androidx.lifecycle.ViewModelProvider
14 | import com.example.appwritedemoapplication.R
15 | import com.example.appwritedemoapplication.databinding.FragmentDatabaseBinding
16 | import com.google.android.material.snackbar.Snackbar
17 |
18 |
19 | class DatabaseFragment : Fragment() {
20 |
21 | private lateinit var binding: FragmentDatabaseBinding
22 | private lateinit var viewModel: DatabaseViewModel
23 |
24 | override fun onCreateView(
25 | inflater: LayoutInflater ,
26 | container: ViewGroup? ,
27 | savedInstanceState: Bundle?
28 | ): View? {
29 | // Inflate view and obtain an instance of the binding class
30 | binding = DataBindingUtil.inflate(
31 | inflater,
32 | R.layout.fragment_database,
33 | container,
34 | false
35 | )
36 |
37 | binding.createDocument.setOnClickListener{
38 | viewModel.createDocument(binding.content.text, binding.isComplete.isSelected)
39 | }
40 |
41 | binding.getDocument.setOnClickListener{
42 | viewModel.getDocument(binding.documentId.text)
43 | }
44 |
45 | binding.getDocuments.setOnClickListener{
46 | viewModel.getDocuments()
47 | }
48 |
49 | binding.deleteDocument.setOnClickListener{
50 | viewModel.deleteDocument(binding.documentId.text)
51 | }
52 |
53 | viewModel = ViewModelProvider(this).get(DatabaseViewModel::class.java)
54 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
55 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
56 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
57 | }
58 | })
59 |
60 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
61 | event?.getContentIfNotHandled()?.let {
62 | binding.responseTV.setText(it)
63 | }
64 | })
65 |
66 | return binding.root
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Database/DatabaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Database
2 |
3 | import android.text.Editable
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import androidx.lifecycle.viewModelScope
8 | import com.example.appwritedemoapplication.Config
9 | import com.example.appwritedemoapplication.utils.Client.client
10 | import com.example.appwritedemoapplication.utils.Event
11 | import io.appwrite.ID
12 | import io.appwrite.Permission
13 | import io.appwrite.Role
14 | import io.appwrite.exceptions.AppwriteException
15 | import io.appwrite.extensions.toJson
16 | import io.appwrite.services.Databases
17 | import kotlinx.coroutines.launch
18 |
19 | class DatabaseViewModel : ViewModel() {
20 |
21 | private val _error = MutableLiveData>().apply {
22 | value = null
23 | }
24 | val error: LiveData> = _error
25 |
26 | private val _response = MutableLiveData>().apply {
27 | value = null
28 | }
29 | val response: LiveData> = _response
30 |
31 | private val databaseService by lazy {
32 | Databases(client)
33 | }
34 |
35 |
36 | fun createDocument(content: Editable? , isComplete: Boolean) {
37 | val data = mapOf(
38 | "content" to content.toString(),
39 | "isComplete" to isComplete
40 | )
41 | val permissions = listOf(Permission.read(Role.any()))
42 | viewModelScope.launch {
43 | try {
44 | val response = databaseService.createDocument(Config.DATABASE, Config.COLLECTION, ID.unique(), data, permissions)
45 | val json = response.toJson()
46 | _response.postValue(Event(json))
47 | } catch (e: AppwriteException) {
48 | _error.postValue(Event(e))
49 | }
50 | }
51 | }
52 |
53 | fun getDocuments() {
54 | viewModelScope.launch {
55 | try {
56 | val response = databaseService.listDocuments(Config.DATABASE, Config.COLLECTION)
57 | val json = response.toJson()
58 | _response.postValue(Event(json))
59 | } catch (e: AppwriteException) {
60 | _error.postValue(Event(e))
61 | }
62 | }
63 | }
64 |
65 | fun getDocument(id: Editable?) {
66 | viewModelScope.launch {
67 | try {
68 | val response = databaseService.getDocument(Config.DATABASE, Config.COLLECTION, id.toString())
69 | val json = response.toJson()
70 | _response.postValue(Event(json))
71 | } catch (e: AppwriteException) {
72 | _error.postValue(Event(e))
73 | }
74 | }
75 | }
76 |
77 | fun deleteDocument(id: Editable?) {
78 | viewModelScope.launch {
79 | try {
80 | val response = databaseService.deleteDocument(Config.DATABASE, Config.COLLECTION, id.toString())
81 | val json = response.toJson().ifEmpty { "{}" }
82 | _response.postValue(Event(json))
83 | } catch (e: AppwriteException) {
84 | _error.postValue(Event(e))
85 | }
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Functions/FunctionsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Functions
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import android.text.Editable
6 | import android.text.method.ScrollingMovementMethod
7 | import androidx.fragment.app.Fragment
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import android.widget.Toast
12 | import androidx.databinding.DataBindingUtil
13 | import androidx.lifecycle.Observer
14 | import com.example.appwritedemoapplication.R
15 | import com.example.appwritedemoapplication.databinding.FragmentDatabaseBinding
16 | import com.example.appwritedemoapplication.databinding.FragmentFunctionsBinding
17 | import com.example.appwritedemoapplication.ui.Database.DatabaseViewModel
18 |
19 | class FunctionsFragment : Fragment() {
20 |
21 | private lateinit var binding: FragmentFunctionsBinding
22 | private lateinit var viewModel: FunctionsViewModel
23 |
24 | override fun onCreateView(
25 | inflater: LayoutInflater ,
26 | container: ViewGroup? ,
27 | savedInstanceState: Bundle?
28 | ): View? {
29 | // Inflate view and obtain an instance of the binding class
30 | binding = DataBindingUtil.inflate(
31 | inflater,
32 | R.layout.fragment_functions,
33 | container,
34 | false
35 | )
36 |
37 | binding.createExecution.setOnClickListener{
38 | viewModel.createExecution(binding.functionId.text)
39 | }
40 |
41 | binding.listExecutions.setOnClickListener{
42 | viewModel.listExecutions(binding.functionId.text)
43 | }
44 |
45 | binding.getExecution.setOnClickListener{
46 | viewModel.getExecution(binding.functionId.text, binding.executionId.text)
47 | }
48 |
49 |
50 | viewModel = ViewModelProvider(this).get(FunctionsViewModel::class.java)
51 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
52 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
53 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
54 | }
55 | })
56 |
57 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
58 | event?.getContentIfNotHandled()?.let {
59 | binding.responseTV.setText(it)
60 | }
61 | })
62 |
63 | return binding.root
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Functions/FunctionsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Functions
2 |
3 | import android.text.Editable
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import androidx.lifecycle.viewModelScope
8 | import com.example.appwritedemoapplication.utils.Client
9 | import com.example.appwritedemoapplication.utils.Event
10 | import io.appwrite.exceptions.AppwriteException
11 | import io.appwrite.extensions.toJson
12 | import io.appwrite.services.Functions
13 | import kotlinx.coroutines.launch
14 |
15 | class FunctionsViewModel : ViewModel() {
16 |
17 | private val _error = MutableLiveData>().apply {
18 | value = null
19 | }
20 | val error: LiveData> = _error
21 |
22 | private val _response = MutableLiveData>().apply {
23 | value = null
24 | }
25 | val response: LiveData> = _response
26 |
27 | private val functionsService by lazy {
28 | Functions(Client.client)
29 | }
30 |
31 |
32 | fun createExecution(id: Editable?) {
33 | viewModelScope.launch {
34 | try {
35 | val response = functionsService.createExecution(id.toString())
36 | val json = response.toJson()
37 | _response.postValue(Event(json))
38 | } catch (e: AppwriteException) {
39 | _error.postValue(Event(e))
40 | }
41 | }
42 | }
43 |
44 | fun listExecutions(id: Editable?) {
45 | viewModelScope.launch {
46 | try {
47 | val response = functionsService.listExecutions(id.toString())
48 | val json = response.toJson()
49 | _response.postValue(Event(json))
50 | } catch (e: AppwriteException) {
51 | _error.postValue(Event(e))
52 | }
53 | }
54 | }
55 |
56 | fun getExecution(functionId: Editable? , executionId: Editable?) {
57 | viewModelScope.launch {
58 | try {
59 | val response = functionsService.getExecution(functionId.toString(), executionId.toString())
60 | val json = response.toJson()
61 | _response.postValue(Event(json))
62 | } catch (e: AppwriteException) {
63 | _error.postValue(Event(e))
64 | }
65 | }
66 | }
67 |
68 |
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Localization/LocalizationFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Localization
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.Toast
10 | import androidx.databinding.DataBindingUtil
11 | import androidx.lifecycle.Observer
12 | import com.example.appwritedemoapplication.R
13 | import com.example.appwritedemoapplication.databinding.FragmentDatabaseBinding
14 | import com.example.appwritedemoapplication.databinding.FragmentLocalizationBinding
15 | import com.example.appwritedemoapplication.ui.Database.DatabaseViewModel
16 |
17 | class LocalizationFragment : Fragment() {
18 |
19 | private lateinit var binding: FragmentLocalizationBinding
20 | private lateinit var viewModel: LocalizationViewModel
21 |
22 | override fun onCreateView(
23 | inflater: LayoutInflater ,
24 | container: ViewGroup? ,
25 | savedInstanceState: Bundle?
26 | ): View? {
27 | // Inflate view and obtain an instance of the binding class
28 | binding = DataBindingUtil.inflate(
29 | inflater,
30 | R.layout.fragment_localization,
31 | container,
32 | false
33 | )
34 |
35 | binding.getLocale.setOnClickListener{
36 | viewModel.getLocale()
37 | }
38 |
39 | viewModel = ViewModelProvider(this).get(LocalizationViewModel::class.java)
40 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
41 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
42 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
43 | }
44 | })
45 |
46 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
47 | event?.getContentIfNotHandled()?.let {
48 | binding.responseTV.setText(it)
49 | }
50 | })
51 |
52 | return binding.root
53 | }
54 |
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Localization/LocalizationViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Localization
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.example.appwritedemoapplication.utils.Client
8 | import com.example.appwritedemoapplication.utils.Event
9 | import io.appwrite.exceptions.AppwriteException
10 | import io.appwrite.extensions.toJson
11 | import io.appwrite.services.Locale
12 | import kotlinx.coroutines.launch
13 |
14 | class LocalizationViewModel : ViewModel() {
15 |
16 | private val _error = MutableLiveData>().apply {
17 | value = null
18 | }
19 | val error: LiveData> = _error
20 |
21 | private val _response = MutableLiveData>().apply {
22 | value = null
23 | }
24 | val response: LiveData> = _response
25 |
26 | private val localizationService by lazy {
27 | Locale(Client.client)
28 | }
29 |
30 | fun getLocale() {
31 | viewModelScope.launch {
32 | try {
33 | val response = localizationService.get()
34 | val json = response.toJson()
35 | _response.postValue(Event(json))
36 | } catch (e: AppwriteException) {
37 | _error.postValue(Event(e))
38 | }
39 | }
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Storage/StorageFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Storage
2 |
3 | import android.Manifest
4 | import android.content.pm.PackageManager
5 | import android.net.Uri
6 | import androidx.lifecycle.ViewModelProvider
7 | import android.os.Bundle
8 | import android.util.Log
9 | import androidx.fragment.app.Fragment
10 | import android.view.LayoutInflater
11 | import android.view.View
12 | import android.view.ViewGroup
13 | import android.widget.Toast
14 | import androidx.activity.result.contract.ActivityResultContracts
15 | import androidx.core.content.ContextCompat
16 | import androidx.databinding.DataBindingUtil
17 | import androidx.lifecycle.Observer
18 | import com.example.appwritedemoapplication.R
19 | import com.example.appwritedemoapplication.databinding.FragmentStorageBinding
20 |
21 | class StorageFragment : Fragment() {
22 |
23 | private lateinit var viewModel: StorageViewModel
24 | private lateinit var binding: FragmentStorageBinding
25 |
26 | private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
27 | viewModel.uploadFile(uri, requireContext())
28 | }
29 |
30 | private val requestPermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
31 | permissions.entries.forEach {
32 | Log.d("DEBUG", "${it.key} = ${it.value}")
33 | }
34 | }
35 |
36 | override fun onCreateView(
37 | inflater: LayoutInflater, container: ViewGroup?,
38 | savedInstanceState: Bundle?
39 | ): View? {
40 | viewModel = ViewModelProvider(this).get(StorageViewModel::class.java)
41 | // Inflate view and obtain an instance of the binding class
42 | binding = DataBindingUtil.inflate(
43 | inflater,
44 | R.layout.fragment_storage,
45 | container,
46 | false
47 | )
48 | binding.lifecycleOwner = viewLifecycleOwner
49 |
50 | binding.deleteFile.setOnClickListener{
51 | viewModel.deleteFile(binding.fileId.text)
52 | }
53 |
54 | binding.getFiles.setOnClickListener{
55 | viewModel.getFiles()
56 | }
57 |
58 | binding.getFile.setOnClickListener{
59 | viewModel.getFile(binding.fileId.text)
60 | }
61 |
62 | binding.downloadFile.setOnClickListener{
63 | viewModel.downloadFile(binding.fileId.text)
64 | }
65 |
66 | binding.uploadFile.setOnClickListener {
67 | // Pass in the mime type you'd like to allow the user to select
68 | // as the input
69 | when {
70 | ContextCompat.checkSelfPermission(
71 | requireContext(),
72 | Manifest.permission.READ_EXTERNAL_STORAGE
73 | ) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
74 | requireContext(),
75 | Manifest.permission.WRITE_EXTERNAL_STORAGE
76 | ) == PackageManager.PERMISSION_GRANTED -> {
77 | getContent.launch("image/*")
78 | }
79 | else -> {
80 | requestPermissions.launch(
81 | arrayOf(
82 | Manifest.permission.READ_EXTERNAL_STORAGE,
83 | Manifest.permission.WRITE_EXTERNAL_STORAGE
84 | )
85 | )
86 | }
87 | }
88 |
89 | }
90 |
91 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
92 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
93 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
94 | }
95 | })
96 |
97 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
98 | event?.getContentIfNotHandled()?.let {
99 | binding.responseTV.setText(it)
100 | }
101 | })
102 |
103 | viewModel.image.observe(viewLifecycleOwner, Observer { event ->
104 | event?.getContentIfNotHandled()?.let {
105 | binding.imageView.setImageBitmap(it)
106 | }
107 | })
108 |
109 | return binding.root
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Storage/StorageViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Storage
2 |
3 | import android.content.ContentResolver
4 | import android.content.Context
5 | import android.graphics.Bitmap
6 | import android.graphics.BitmapFactory
7 | import android.net.Uri
8 | import android.provider.OpenableColumns
9 | import android.text.Editable
10 | import androidx.lifecycle.LiveData
11 | import androidx.lifecycle.MutableLiveData
12 | import androidx.lifecycle.ViewModel
13 | import androidx.lifecycle.viewModelScope
14 | import com.example.appwritedemoapplication.Config
15 | import com.example.appwritedemoapplication.utils.Client
16 | import com.example.appwritedemoapplication.utils.Event
17 | import io.appwrite.ID
18 | import io.appwrite.Permission
19 | import io.appwrite.Role
20 | import io.appwrite.exceptions.AppwriteException
21 | import io.appwrite.extensions.toJson
22 | import io.appwrite.models.InputFile
23 | import io.appwrite.services.Storage
24 | import kotlinx.coroutines.Dispatchers
25 | import kotlinx.coroutines.launch
26 | import kotlinx.coroutines.withContext
27 | import java.io.File
28 | import java.io.FileOutputStream
29 |
30 |
31 | class StorageViewModel : ViewModel() {
32 |
33 | private val _error = MutableLiveData>().apply {
34 | value = null
35 | }
36 | val error: LiveData> = _error
37 |
38 | private val _response = MutableLiveData>().apply {
39 | value = null
40 | }
41 | val response: LiveData> = _response
42 |
43 | private val _image = MutableLiveData>().apply {
44 | value = null
45 | }
46 | val image: LiveData> = _image
47 |
48 | private val storageService by lazy {
49 | Storage(Client.client)
50 | }
51 |
52 |
53 | fun getFile(id: Editable) {
54 | viewModelScope.launch {
55 | try {
56 | val response = storageService.getFile(Config.STORAGE, id.toString())
57 | val json = response.toJson()
58 | _response.postValue(Event(json))
59 | } catch (e: AppwriteException) {
60 | _error.postValue(Event(e))
61 | }
62 | }
63 | }
64 |
65 |
66 | fun deleteFile(id: Editable?) {
67 | viewModelScope.launch {
68 | try {
69 | val response = storageService.deleteFile(Config.STORAGE, id.toString())
70 | val json = response.toJson().ifEmpty { "{}" }
71 | _response.postValue(Event(json))
72 | } catch (e: AppwriteException) {
73 | _error.postValue(Event(e))
74 | }
75 | }
76 | }
77 |
78 | fun getFiles() {
79 | viewModelScope.launch {
80 | try {
81 | val response = storageService.listFiles(Config.STORAGE)
82 | val json = response.toJson()
83 | _response.postValue(Event(json))
84 | } catch (e: AppwriteException) {
85 | _error.postValue(Event(e))
86 | }
87 | }
88 | }
89 |
90 |
91 | fun uploadFile(uri: Uri?, context: Context) {
92 | if (uri == null) return
93 | viewModelScope.launch {
94 | context.contentResolver.openInputStream(uri).use {
95 | if (it == null) return@use
96 | withContext(Dispatchers.IO) {
97 | try {
98 | val file = File(context.cacheDir, context.contentResolver.getFileName(uri))
99 | it.copyTo(FileOutputStream(file))
100 | val response = storageService.createFile(
101 | Config.STORAGE,
102 | ID.unique(),
103 | InputFile.fromFile(file),
104 | listOf(Permission.read(Role.any())))
105 | val json = response.toJson()
106 | _response.postValue(Event(json))
107 | } catch (e: AppwriteException) {
108 | e.printStackTrace()
109 | _error.postValue(Event(e))
110 | }
111 |
112 | }
113 | }
114 | }
115 |
116 |
117 | }
118 |
119 | private fun ContentResolver.getFileName(fileUri: Uri): String {
120 | var name = ""
121 | val returnCursor = this.query(fileUri, null, null, null, null)
122 | if (returnCursor != null) {
123 | val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
124 | returnCursor.moveToFirst()
125 | name = returnCursor.getString(nameIndex)
126 | returnCursor.close()
127 | }
128 | return name
129 | }
130 |
131 | fun downloadFile(fileId: Editable?) {
132 | viewModelScope.launch {
133 | try {
134 | val response = storageService.getFileDownload(Config.STORAGE, fileId.toString())
135 | val image = BitmapFactory.decodeByteArray(response, 0, response.size)
136 | _image.postValue(Event(image))
137 | } catch (e: AppwriteException) {
138 | _error.postValue(Event(e))
139 | }
140 | }
141 | }
142 |
143 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Teams/TeamsFragment.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Teams
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import android.text.method.ScrollingMovementMethod
6 | import androidx.fragment.app.Fragment
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.Toast
11 | import androidx.databinding.DataBindingUtil
12 | import androidx.lifecycle.Observer
13 | import com.example.appwritedemoapplication.R
14 | import com.example.appwritedemoapplication.databinding.FragmentDatabaseBinding
15 | import com.example.appwritedemoapplication.databinding.FragmentTeamsBinding
16 | import com.example.appwritedemoapplication.ui.Database.DatabaseViewModel
17 |
18 | class TeamsFragment : Fragment() {
19 |
20 | private lateinit var binding: FragmentTeamsBinding
21 | private lateinit var viewModel: TeamsViewModel
22 |
23 | override fun onCreateView(
24 | inflater: LayoutInflater ,
25 | container: ViewGroup? ,
26 | savedInstanceState: Bundle?
27 | ): View? {
28 | // Inflate view and obtain an instance of the binding class
29 | binding = DataBindingUtil.inflate(
30 | inflater,
31 | R.layout.fragment_teams,
32 | container,
33 | false
34 | )
35 |
36 | binding.createTeam.setOnClickListener{
37 | viewModel.createTeam(binding.content.text)
38 | }
39 |
40 | binding.getTeams.setOnClickListener{
41 | viewModel.getTeams()
42 | }
43 |
44 | binding.getTeam.setOnClickListener{
45 | viewModel.getTeam(binding.teamId.text)
46 | }
47 |
48 | binding.deleteTeam.setOnClickListener{
49 | viewModel.deleteTeam(binding.teamId.text)
50 | }
51 |
52 | viewModel = ViewModelProvider(this).get(TeamsViewModel::class.java)
53 | viewModel.error.observe(viewLifecycleOwner, Observer { event ->
54 | event?.getContentIfNotHandled()?.let { // Only proceed if the event has never been handled
55 | Toast.makeText(requireContext(), it.message , Toast.LENGTH_SHORT).show()
56 | }
57 | })
58 |
59 | viewModel.response.observe(viewLifecycleOwner, Observer { event ->
60 | event?.getContentIfNotHandled()?.let {
61 | binding.responseTV.setText(it)
62 | }
63 | })
64 |
65 | return binding.root
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/ui/Teams/TeamsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.ui.Teams
2 |
3 | import android.text.Editable
4 | import androidx.lifecycle.LiveData
5 | import androidx.lifecycle.MutableLiveData
6 | import androidx.lifecycle.ViewModel
7 | import androidx.lifecycle.viewModelScope
8 | import com.example.appwritedemoapplication.utils.Client
9 | import com.example.appwritedemoapplication.utils.Event
10 | import io.appwrite.ID
11 | import io.appwrite.exceptions.AppwriteException
12 | import io.appwrite.extensions.toJson
13 | import io.appwrite.services.Teams
14 | import kotlinx.coroutines.launch
15 |
16 | class TeamsViewModel : ViewModel() {
17 |
18 | private val _error = MutableLiveData>().apply {
19 | value = null
20 | }
21 | val error: LiveData> = _error
22 |
23 | private val _response = MutableLiveData>().apply {
24 | value = null
25 | }
26 | val response: LiveData> = _response
27 |
28 | private val teamsService by lazy {
29 | Teams(Client.client)
30 | }
31 |
32 |
33 | fun createTeam(name: Editable?) {
34 | viewModelScope.launch {
35 | try {
36 | val response = teamsService.create(ID.unique(), name.toString())
37 | val json = response.toJson()
38 | _response.postValue(Event(json))
39 | } catch (e: AppwriteException) {
40 | _error.postValue(Event(e))
41 | }
42 | }
43 | }
44 |
45 | fun getTeams() {
46 | viewModelScope.launch {
47 | try {
48 | val response = teamsService.list()
49 | val json = response.toJson()
50 | _response.postValue(Event(json))
51 | } catch (e: AppwriteException) {
52 | _error.postValue(Event(e))
53 | }
54 | }
55 | }
56 |
57 | fun getTeam(id: Editable?) {
58 | viewModelScope.launch {
59 | try {
60 | val response = teamsService.get(id.toString())
61 | val json = response.toJson()
62 | _response.postValue(Event(json))
63 | } catch (e: AppwriteException) {
64 | _error.postValue(Event(e))
65 | }
66 | }
67 | }
68 |
69 | fun deleteTeam(id: Editable?) {
70 | viewModelScope.launch {
71 | try {
72 | val response = teamsService.delete(id.toString())
73 | val json = response.toJson().ifEmpty { "{}" }
74 | _response.postValue(Event(json))
75 | } catch (e: AppwriteException) {
76 | _error.postValue(Event(e))
77 | }
78 | }
79 | }
80 |
81 |
82 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/utils/Client.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.utils
2 |
3 | import android.content.Context
4 | import com.example.appwritedemoapplication.Config
5 | import com.example.appwritedemoapplication.R
6 | import io.appwrite.Client
7 |
8 | object Client {
9 | lateinit var client : Client
10 |
11 | fun create(context: Context) {
12 | client = Client(context)
13 | .setEndpoint(Config.ENDPOINT)
14 | .setProject(Config.PROJECT)
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/appwritedemoapplication/utils/Event.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication.utils
2 |
3 | /**
4 | * Used as a wrapper for data that is exposed via a LiveData that represents an event.
5 | */
6 | open class Event(private val content: T) {
7 |
8 | var hasBeenHandled = false
9 | private set // Allow external read but not write
10 |
11 | /**
12 | * Returns the content and prevents its use again.
13 | */
14 | fun getContentIfNotHandled(): T? {
15 | return if (hasBeenHandled) {
16 | null
17 | } else {
18 | hasBeenHandled = true
19 | content
20 | }
21 | }
22 |
23 | /**
24 | * Returns the content, even if it's already been handled.
25 | */
26 | fun peekContent(): T = content
27 | }
28 |
--------------------------------------------------------------------------------
/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/drawable/ic_menu_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_gallery.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_slideshow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_account.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
41 |
42 |
43 |
53 |
54 |
63 |
64 |
75 |
76 |
86 |
87 |
97 |
98 |
110 |
111 |
120 |
121 |
122 |
123 |
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_avatars.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
23 |
24 |
33 |
34 |
45 |
46 |
55 |
56 |
67 |
68 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_database.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
42 |
43 |
52 |
53 |
64 |
65 |
74 |
75 |
82 |
83 |
94 |
95 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_functions.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
40 |
41 |
49 |
50 |
57 |
58 |
69 |
70 |
71 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_localization.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_storage.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
42 |
43 |
52 |
53 |
60 |
61 |
71 |
72 |
80 |
81 |
91 |
92 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_teams.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
15 |
16 |
30 |
31 |
40 |
41 |
52 |
53 |
62 |
63 |
70 |
71 |
82 |
83 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
29 |
30 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
11 |
15 |
19 |
23 |
27 |
31 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
31 |
32 |
37 |
38 |
43 |
44 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 176dp
7 | 16dp
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Appwrite Demo Application
3 | Open navigation drawer
4 | Close navigation drawer
5 | Android Studio
6 | android.studio@android.com
7 | Navigation header
8 | Settings
9 |
10 | Accounts
11 | Teams
12 | Database
13 | Storage
14 | Functions
15 | Localization
16 | Avatars
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/appwritedemoapplication/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.appwritedemoapplication
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4 , 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.7.10'
4 | repositories {
5 | mavenCentral()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.3.0'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | maven {
22 | url "https://s01.oss.sonatype.org/content/repositories/snapshots/"
23 | }
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/appwrite/demo-getstarted-with-android/681ca3f393248eeec4ae332a91b50112ca83d64e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 09 21:12:30 IST 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "Appwrite Demo Application"
--------------------------------------------------------------------------------