├── .editorconfig
├── .github
├── CODEOWNERS
├── pull_request_template.md
└── workflows
│ ├── android.yml
│ ├── publish-snapshot.yml
│ └── publish.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── io
│ │ └── getstream
│ │ └── avatarviewdemo
│ │ ├── MainActivity.kt
│ │ └── Samples.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── stream.png
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── values-night
│ └── themes.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
├── avatarview-coil
├── .gitignore
├── api
│ └── avatarview-coil.api
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── avatarview
│ └── coil
│ ├── Avatar.kt
│ ├── AvatarBitmapFactory.kt
│ ├── AvatarCoil.kt
│ ├── AvatarFetcher.kt
│ ├── AvatarImageLoaderFactory.kt
│ ├── AvatarImageLoaderInternal.kt
│ ├── AvatarViewExtension.kt
│ └── ImageHeadersProvider.kt
├── avatarview-glide
├── .gitignore
├── README.md
├── api
│ └── avatarview-glide.api
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── io
│ └── getstream
│ └── avatarview
│ └── glide
│ ├── AvatarBitmapLoader.kt
│ ├── AvatarResult.kt
│ └── AvatarViewExtension.kt
├── avatarview-stream-integration
├── .gitignore
├── api
│ └── avatarview-stream-integration.api
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── io
│ │ └── getstream
│ │ └── avatarview
│ │ └── stream
│ │ └── integration
│ │ ├── AvatarViewStreamIntegration.kt
│ │ └── StreamAvatarBitmapFactory.kt
│ └── res
│ └── values
│ └── colors.xml
├── avatarview
├── .gitignore
├── api
│ └── avatarview.api
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── kotlin
│ └── io
│ │ └── getstream
│ │ └── avatarview
│ │ ├── AvatarBitmapCombiner.kt
│ │ ├── AvatarShape.kt
│ │ ├── AvatarView.kt
│ │ ├── IndicatorPosition.kt
│ │ └── internal
│ │ ├── Extensions.kt
│ │ ├── InternalAvatarViewApi.kt
│ │ ├── Properties.kt
│ │ └── ViewProperty.kt
│ └── res
│ └── values
│ └── attrs_avatar_view.xml
├── build.gradle
├── buildSrc
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── io
│ └── getstream
│ └── avatarview
│ ├── Configuration.kt
│ └── Dependencies.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── preview
├── dokka-avatarview.svg
├── preview0.png
├── preview1.png
├── preview10.png
├── preview2.png
├── preview3.png
├── preview4.png
├── preview5.png
├── preview6.png
├── preview7.gif
├── preview8.png
└── preview9.png
├── scripts
├── publish-module.gradle
└── publish-root.gradle
├── settings.gradle
└── spotless
├── copyright.kt
├── copyright.xml
└── spotless.gradle
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 | [*]
3 | # Most of the standard properties are supported
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | max_line_length = 100
9 | insert_final_newline = true
10 | trim_trailing_whitespace = true
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # More details are here: https://help.github.com/articles/about-codeowners/
5 |
6 | # The '*' pattern is global owners.
7 | # Not adding in this PR, but I'd like to try adding a global owner set with the entire team.
8 | # One interpretation of their docs is that global owners are added only if not removed
9 | # by a more local rule.
10 |
11 | # Order is important. The last matching pattern has the most precedence.
12 | # The folders are ordered as follows:
13 |
14 | # In each subsection folders are ordered first by depth, then alphabetically.
15 | # This should make it easy to add new rules without breaking existing ones.
16 | * @skydoves
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### 🎯 Goal
2 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue.
3 |
4 | ### 🛠 Implementation details
5 | Describe the implementation details for this Pull Request.
6 |
7 | ### ✍️ Explain examples
8 | Explain examples with code for this updates.
9 |
10 | ### Preparing a pull request for review
11 | Ensure your change is properly formatted by running:
12 |
13 | ```gradle
14 | $ ./gradlew spotlessApply
15 | ```
16 |
17 | Please correct any failures before requesting a review.
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android CI
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 |
15 | - name: set up JDK
16 | uses: actions/setup-java@v1
17 | with:
18 | java-version: 11
19 |
20 | - name: Cache Gradle and wrapper
21 | uses: actions/cache@v2
22 | with:
23 | path: |
24 | ~/.gradle/caches
25 | ~/.gradle/wrapper
26 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
27 | restore-keys: |
28 | ${{ runner.os }}-gradle-
29 | - name: Make Gradle executable
30 | run: chmod +x ./gradlew
31 |
32 | - name: Build with Gradle
33 | run: ./gradlew build
--------------------------------------------------------------------------------
/.github/workflows/publish-snapshot.yml:
--------------------------------------------------------------------------------
1 | name: Publish Snapshot builds
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | publish:
10 | name: Snapshot build and publish
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Check out code
14 | uses: actions/checkout@v2
15 | - name: Set up JDK 11
16 | uses: actions/setup-java@v2
17 | with:
18 | distribution: adopt
19 | java-version: 11
20 | - name: Release build
21 | run: ./gradlew assemble --scan
22 | - name: Source jar and dokka
23 | run: ./gradlew androidSourcesJar javadocJar --scan
24 | - name: Publish to MavenCentral
25 | run: ./gradlew publishReleasePublicationToSonatypeRepository --scan
26 | env:
27 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
28 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
29 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
30 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
31 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
32 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
33 | SNAPSHOT: true
34 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | types: [released]
6 |
7 | jobs:
8 | publish:
9 | name: Release build and publish
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Check out code
13 | uses: actions/checkout@v2
14 | - name: Set up JDK 11
15 | uses: actions/setup-java@v2
16 | with:
17 | distribution: adopt
18 | java-version: 11
19 | - name: Release build
20 | run: ./gradlew assemble --scan
21 | - name: Source jar and dokka
22 | run: ./gradlew androidSourcesJar javadocJar --scan
23 | - name: Publish to MavenCentral
24 | run: ./gradlew publishReleasePublicationToSonatypeRepository --max-workers 1 closeAndReleaseSonatypeStagingRepository --scan
25 | env:
26 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
27 | OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
28 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }}
29 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
30 | SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
31 | SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | /.idea
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # Intellij
37 | *.iml
38 | .idea/workspace.xml
39 | .idea/tasks.xml
40 | .idea/gradle.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | app/.idea/
44 |
45 | # Mac
46 | *.DS_Store
47 |
48 | # Keystore files
49 | *.jks
50 |
51 | # External native build folder generated in Android Studio 2.2 and later
52 | .externalNativeBuild
53 |
54 | # Google Services (e.g. APIs or Firebase)
55 | google-services.json
56 |
57 | # Temporary API docs
58 | docs/api
59 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | GetStream.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## How to contribute
2 | We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow.
3 |
4 | ## Preparing a pull request for review
5 | Ensure your change is properly formatted by running:
6 |
7 | ```gradle
8 | ./gradlew spotlessApply
9 | ```
10 |
11 | Then dump binary API of this library that is public in sense of Kotlin visibilities and ensures that the public binary API wasn't changed in a way that make this change binary incompatible.
12 |
13 | ```gradle
14 | ./gradlew apiDump
15 | ```
16 |
17 | Please correct any failures before requesting a review.
18 |
19 | ## Code reviews
20 | All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) for more information on using pull requests.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | import io.getstream.avatarview.Configuration
2 | import io.getstream.avatarview.Dependencies
3 |
4 | plugins {
5 | id 'com.android.application'
6 | id 'org.jetbrains.kotlin.android'
7 | }
8 |
9 | android {
10 | compileSdkVersion Configuration.compileSdk
11 | defaultConfig {
12 | applicationId "io.getstream.avatarviewdemo"
13 | minSdkVersion Configuration.minSdk
14 | targetSdkVersion Configuration.targetSdk
15 | versionCode Configuration.versionCode
16 | versionName Configuration.versionName
17 | }
18 |
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_11
21 | targetCompatibility JavaVersion.VERSION_11
22 | }
23 |
24 | kotlinOptions {
25 | jvmTarget = "11"
26 | }
27 |
28 | buildFeatures {
29 | viewBinding true
30 | dataBinding true
31 | }
32 |
33 | lintOptions {
34 | abortOnError false
35 | }
36 | }
37 |
38 | dependencies {
39 | implementation Dependencies.material
40 | implementation project(":avatarview-coil")
41 | implementation project(":avatarview-glide")
42 | implementation project(":avatarview-stream-integration")
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
19 |
20 |
21 |
22 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/avatarviewdemo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarviewdemo
18 |
19 | import android.os.Bundle
20 | import androidx.appcompat.app.AppCompatActivity
21 | import coil.transform.RoundedCornersTransformation
22 | import io.getstream.avatarview.coil.loadImage
23 | import io.getstream.avatarviewdemo.Samples.cats
24 | import io.getstream.avatarviewdemo.databinding.ActivityMainBinding
25 |
26 | class MainActivity : AppCompatActivity() {
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 |
31 | val binding = ActivityMainBinding.inflate(layoutInflater)
32 | setContentView(binding.root)
33 |
34 | with(binding) {
35 | avatarView1.loadImage(cats.take(1))
36 |
37 | avatarView2.loadImage(
38 | cats.take(2)
39 | ) {
40 | crossfade(true)
41 | crossfade(300)
42 | lifecycle(this@MainActivity)
43 | }
44 |
45 | avatarView3.loadImage(
46 | cats.take(3)
47 | ) {
48 | crossfade(true)
49 | crossfade(400)
50 | lifecycle(this@MainActivity)
51 | }
52 |
53 | avatarView4.loadImage(
54 | cats.take(4)
55 | ) {
56 | crossfade(true)
57 | crossfade(400)
58 | lifecycle(this@MainActivity)
59 | }
60 |
61 | avatarView5.loadImage(
62 | cats.take(1)
63 | ) {
64 | crossfade(true)
65 | crossfade(400)
66 | lifecycle(this@MainActivity)
67 | }
68 |
69 | avatarView6.loadImage(
70 | cats.take(2)
71 | ) {
72 | crossfade(true)
73 | crossfade(400)
74 | lifecycle(this@MainActivity)
75 | }
76 |
77 | avatarView7.loadImage(
78 | cats.take(3)
79 | ) {
80 | crossfade(true)
81 | crossfade(400)
82 | lifecycle(this@MainActivity)
83 | transformations(
84 | RoundedCornersTransformation(36f)
85 | )
86 | }
87 |
88 | avatarView8.loadImage(
89 | cats.take(4)
90 | ) {
91 | crossfade(true)
92 | crossfade(400)
93 | lifecycle(this@MainActivity)
94 | }
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/io/getstream/avatarviewdemo/Samples.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarviewdemo
18 |
19 | object Samples {
20 |
21 | val cats: List
22 | get() = listOf(
23 | "https://swiftype-ss.imgix.net/https%3A%2F%2Fcdn.petcarerx.com%2FLPPE%2Fimages%2Farticlethumbs%2FFluffy-Cats-Small.jpg?ixlib=rb-1.1.0&h=320&fit=clip&dpr=2.0&s=c81a75f749ea4ed736b7607100cb52cc.png",
24 | "https://images.ctfassets.net/cnu0m8re1exe/1GxSYi0mQSp9xJ5svaWkVO/d151a93af61918c234c3049e0d6393e1/93347270_cat-1151519_1280.jpg?fm=jpg&fl=progressive&w=660&h=433&fit=fill",
25 | "https://img.webmd.com/dtmcms/live/webmd/consumer_assets/site_images/article_thumbnails/other/cat_relaxing_on_patio_other/1800x1200_cat_relaxing_on_patio_other.jpg",
26 | "https://post.healthline.com/wp-content/uploads/2020/08/cat-thumb2-732x415.jpg",
27 | ).shuffled()
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
23 |
24 |
25 |
31 |
34 |
37 |
38 |
39 |
40 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
22 |
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 |
175 |
180 |
185 |
186 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/stream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/drawable/stream.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
52 |
53 |
76 |
77 |
100 |
101 |
119 |
120 |
144 |
145 |
165 |
166 |
187 |
188 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GetStream/avatarview-android/d0bb30467a12c1efae00e41eb260bc2f1f3b4f38/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | #212121
19 | #005FFF
20 | #005FFF
21 | #005FFF
22 | #FF03DAC5
23 | #FF018786
24 | #FFFFFFFF
25 | #57A8D8
26 | #FBC02D
27 | #FFD600
28 | #FBC02D
29 | #FFA000
30 | #FFA726
31 | #FF6D00
32 | #81C784
33 | #388E3C
34 | #81D4fA
35 | #0091EA
36 | #FF000000
37 | #FF0000
38 | #FF7F00
39 | #7FFF00
40 | #00FF00
41 | #00FF7F
42 | #00FFFF
43 | #007FFF
44 | #0000FF
45 | #7F00FF
46 | #FF00FF
47 |
48 |
49 | @color/md_yellow_100
50 | @color/md_orange_100
51 | @color/md_green_100
52 | @color/md_blue_100
53 |
54 |
55 |
56 | @color/red
57 | @color/orange
58 | @color/yellow
59 | @color/chartreuse
60 | @color/green
61 | @color/spring_green
62 | @color/cyan
63 | @color/azure
64 | @color/blue
65 | @color/violet
66 | @color/magenta
67 |
68 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | AvatarView
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
32 |
--------------------------------------------------------------------------------
/avatarview-coil/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/avatarview-coil/api/avatarview-coil.api:
--------------------------------------------------------------------------------
1 | public final class io/getstream/avatarview/coil/Avatar {
2 | public fun (Ljava/util/List;IILandroid/graphics/drawable/Drawable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)V
3 | public final fun component1 ()Ljava/util/List;
4 | public final fun component2 ()I
5 | public final fun component3 ()I
6 | public final fun component4 ()Landroid/graphics/drawable/Drawable;
7 | public final fun component5 ()Lkotlin/jvm/functions/Function2;
8 | public final fun component6 ()Lkotlin/jvm/functions/Function2;
9 | public final fun copy (Ljava/util/List;IILandroid/graphics/drawable/Drawable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lio/getstream/avatarview/coil/Avatar;
10 | public static synthetic fun copy$default (Lio/getstream/avatarview/coil/Avatar;Ljava/util/List;IILandroid/graphics/drawable/Drawable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/getstream/avatarview/coil/Avatar;
11 | public fun equals (Ljava/lang/Object;)Z
12 | public final fun getAvatarBorderWidth ()I
13 | public final fun getData ()Ljava/util/List;
14 | public final fun getErrorPlaceholder ()Landroid/graphics/drawable/Drawable;
15 | public final fun getMaxSectionSize ()I
16 | public final fun getOnError ()Lkotlin/jvm/functions/Function2;
17 | public final fun getOnSuccess ()Lkotlin/jvm/functions/Function2;
18 | public final fun getTag (Ljava/lang/String;)Ljava/lang/Object;
19 | public fun hashCode ()I
20 | public final fun setTagIfAbsent (Ljava/lang/String;Ljava/lang/Object;)V
21 | public fun toString ()Ljava/lang/String;
22 | }
23 |
24 | public class io/getstream/avatarview/coil/AvatarBitmapFactory {
25 | public fun (Landroid/content/Context;)V
26 | public fun avatarBitmapKey (Lio/getstream/avatarview/coil/Avatar;)Ljava/lang/String;
27 | public fun createAvatarBitmaps (Lio/getstream/avatarview/coil/Avatar;ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
28 | public fun loadAvatarBitmap (Ljava/lang/Object;Lio/getstream/avatarview/coil/Avatar;ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
29 | public fun loadAvatarBitmapBlocking (Ljava/lang/Object;Lio/getstream/avatarview/coil/Avatar;I)Landroid/graphics/Bitmap;
30 | public fun loadAvatarPlaceholderBitmap (Ljava/lang/Object;Lio/getstream/avatarview/coil/Avatar;ILkotlin/coroutines/Continuation;)Ljava/lang/Object;
31 | public fun loadAvatarPlaceholderBitmapBlocking (Ljava/lang/Object;Lio/getstream/avatarview/coil/Avatar;I)Landroid/graphics/Bitmap;
32 | }
33 |
34 | public final class io/getstream/avatarview/coil/AvatarCoil {
35 | public static final field INSTANCE Lio/getstream/avatarview/coil/AvatarCoil;
36 | public final fun getAvatarBitmapFactory (Landroid/content/Context;)Lio/getstream/avatarview/coil/AvatarBitmapFactory;
37 | public final fun getImageHeadersProvider ()Lio/getstream/avatarview/coil/ImageHeadersProvider;
38 | public final fun setAvatarBitmapFactory (Lio/getstream/avatarview/coil/AvatarBitmapFactory;)V
39 | public final fun setImageHeadersProvider (Lio/getstream/avatarview/coil/ImageHeadersProvider;)V
40 | public final fun setImageLoader (Lcoil/ImageLoaderFactory;)V
41 | }
42 |
43 | public final class io/getstream/avatarview/coil/AvatarImageLoaderFactory : coil/ImageLoaderFactory {
44 | public fun (Landroid/content/Context;Lkotlin/jvm/functions/Function1;)V
45 | public synthetic fun (Landroid/content/Context;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
46 | public fun newImageLoader ()Lcoil/ImageLoader;
47 | }
48 |
49 | public final class io/getstream/avatarview/coil/AvatarImageLoaderInternal {
50 | public static final field INSTANCE Lio/getstream/avatarview/coil/AvatarImageLoaderInternal;
51 | public final synthetic fun loadAsBitmap (Landroid/content/Context;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
52 | public static synthetic fun loadAsBitmap$default (Lio/getstream/avatarview/coil/AvatarImageLoaderInternal;Landroid/content/Context;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
53 | }
54 |
55 | public final class io/getstream/avatarview/coil/AvatarViewExtension {
56 | public static final synthetic fun loadImage (Lio/getstream/avatarview/AvatarView;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
57 | public static final synthetic fun loadImage (Lio/getstream/avatarview/AvatarView;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
58 | public static final synthetic fun loadImage (Lio/getstream/avatarview/AvatarView;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V
59 | public static synthetic fun loadImage$default (Lio/getstream/avatarview/AvatarView;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
60 | public static synthetic fun loadImage$default (Lio/getstream/avatarview/AvatarView;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
61 | public static synthetic fun loadImage$default (Lio/getstream/avatarview/AvatarView;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
62 | }
63 |
64 | public abstract interface class io/getstream/avatarview/coil/ImageHeadersProvider {
65 | public abstract fun getImageRequestHeaders ()Ljava/util/Map;
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/avatarview-coil/build.gradle:
--------------------------------------------------------------------------------
1 | import io.getstream.avatarview.Configuration
2 | import io.getstream.avatarview.Dependencies
3 |
4 | plugins {
5 | id 'com.android.library'
6 | id 'org.jetbrains.kotlin.android'
7 | id 'org.jetbrains.dokka'
8 | id 'binary-compatibility-validator'
9 | }
10 |
11 | ext {
12 | PUBLISH_GROUP_ID = Configuration.artifactGroup
13 | if (snapshot) {
14 | PUBLISH_VERSION = Configuration.snapshotVersionName
15 | } else {
16 | PUBLISH_VERSION = Configuration.versionName
17 | }
18 | PUBLISH_ARTIFACT_ID = 'avatarview-coil'
19 | }
20 |
21 | apply from: "${rootDir}/scripts/publish-module.gradle"
22 |
23 | android {
24 | compileSdkVersion Configuration.compileSdk
25 | defaultConfig {
26 | minSdkVersion Configuration.minSdk
27 | targetSdkVersion Configuration.targetSdk
28 | }
29 |
30 | buildFeatures {
31 | buildConfig false
32 | }
33 |
34 | compileOptions {
35 | sourceCompatibility JavaVersion.VERSION_1_8
36 | targetCompatibility JavaVersion.VERSION_1_8
37 | }
38 |
39 | kotlinOptions {
40 | jvmTarget = '1.8'
41 | }
42 |
43 | lintOptions {
44 | abortOnError false
45 | }
46 | }
47 |
48 | tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
49 | kotlinOptions.freeCompilerArgs += [
50 | "-Xexplicit-api=strict",
51 | "-Xopt-in=io.getstream.avatarview.internal.InternalAvatarViewApi",
52 | ]
53 | }
54 |
55 | apiValidation {
56 | nonPublicMarkers += ["kotlin.PublishedApi"]
57 | }
58 |
59 | dependencies {
60 | api project(":avatarview")
61 | api Dependencies.coil
62 | api Dependencies.coilGif
63 |
64 | implementation Dependencies.androidxAppcompat
65 | implementation Dependencies.coroutines
66 | implementation Dependencies.okhttp
67 | }
68 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/Avatar.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.graphics.Bitmap
20 | import android.graphics.drawable.Drawable
21 | import android.net.Uri
22 | import androidx.annotation.DrawableRes
23 | import coil.request.ErrorResult
24 | import coil.request.ImageRequest
25 | import coil.request.SuccessResult
26 | import okhttp3.HttpUrl
27 | import java.io.File
28 |
29 | /**
30 | * A data transfer model for transferring image data to [AvatarFetcher].
31 | * This model will be fetched by [AvatarFetcher] when we request image loading by using this type to Coil.
32 | *
33 | * The default supported data types are:
34 | * - [String] (mapped to a [Uri])
35 | * - [Uri] ("android.resource", "content", "file", "http", and "https" schemes only)
36 | * - [HttpUrl]
37 | * - [File]
38 | * - [DrawableRes]
39 | * - [Drawable]
40 | * - [Bitmap]
41 | *
42 | * @param data A list of image data.
43 | * @param maxSectionSize The maximum section size of the avatar when loading multiple images.
44 | * @param avatarBorderWidth The border width of AvatarView.
45 | * @param errorPlaceholder An error placeholder that should be shown when request failed.
46 | */
47 | public data class Avatar(
48 |
49 | /** A list of data to be requested. */
50 | val data: List,
51 |
52 | /** The maximum size of the sections. */
53 | val maxSectionSize: Int,
54 |
55 | /** The border width of AvatarView. */
56 | val avatarBorderWidth: Int,
57 |
58 | /** An error placeholder that should be shown when request failed. */
59 | val errorPlaceholder: Drawable?,
60 |
61 | /** A lambda function will be executed when loading succeeds. */
62 | val onSuccess: (request: ImageRequest, result: SuccessResult) -> Unit,
63 |
64 | /** A lambda function will be executed when loading failed. */
65 | val onError: (request: ImageRequest, result: ErrorResult) -> Unit,
66 | ) {
67 | private val bagOfTags: MutableMap = mutableMapOf()
68 |
69 | /**
70 | * Sets a tag associated with this avatar and a key.
71 | * If the given [newValue] was already set for the given key, this calls do nothing,
72 | * the given [newValue] would be ignored.
73 | *
74 | * @param key A new key to set a tag associated with this avatar.
75 | * @param newValue A new value to be set on the bag.
76 | */
77 | @Suppress("UNCHECKED_CAST")
78 | public fun setTagIfAbsent(key: String, newValue: T) {
79 | synchronized(bagOfTags) {
80 | val previous = bagOfTags[key] as? T
81 | if (previous == null) {
82 | bagOfTags[key] = newValue
83 | }
84 | }
85 | }
86 |
87 | /**
88 | * Returns the tag associated with this avatar using the given [key].
89 | *
90 | * @param key A new key to get a tag associated with this avatar.
91 | *
92 | * @return A tag in the bag.
93 | */
94 | @Suppress("UNCHECKED_CAST")
95 | public fun getTag(key: String): T? {
96 | synchronized(bagOfTags) {
97 | return bagOfTags[key] as? T
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarBitmapFactory.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.content.Context
20 | import android.graphics.Bitmap
21 | import androidx.annotation.Px
22 | import coil.ImageLoader
23 | import io.getstream.avatarview.AvatarBitmapCombiner
24 | import kotlinx.coroutines.Dispatchers
25 | import kotlinx.coroutines.withContext
26 |
27 | /**
28 | * A Bitmap factory to create avatar bitmaps.
29 | */
30 | public open class AvatarBitmapFactory(private val context: Context) {
31 |
32 | /**
33 | * Creates a Bitmap with the image request [data] to represent the avatar in a suspending operation.
34 | *
35 | * @param data An image request model.
36 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
37 | * @param avatarSize A specified avatar size.
38 | *
39 | * @return The loaded bitmap or null if the loading failed (e.g. network issues).
40 | */
41 | @JvmSynthetic
42 | internal suspend fun createAvatarBitmapInternal(
43 | data: Any?,
44 | avatar: Avatar,
45 | @Px avatarSize: Int
46 | ): Bitmap? {
47 | val customBitmap = withContext(Dispatchers.IO) {
48 | loadAvatarBitmapBlocking(data, avatar, avatarSize)
49 | }
50 |
51 | val bitmap = customBitmap ?: loadAvatarBitmap(data, avatar, avatarSize)
52 | if (bitmap != null) {
53 | return bitmap
54 | }
55 |
56 | val customPlaceholderBitmap = withContext(Dispatchers.IO) {
57 | loadAvatarPlaceholderBitmapBlocking(data, avatar, avatarSize)
58 | }
59 |
60 | return customPlaceholderBitmap ?: loadAvatarPlaceholderBitmap(data, avatar, avatarSize)
61 | }
62 |
63 | /**
64 | * Creates a Bitmap to represent an avatar image.
65 | *
66 | * This method takes precedence over [loadAvatarBitmap] if both are implemented.
67 | *
68 | * Override this method only if you can't provide a suspending implementation, otherwise
69 | * override [loadAvatarBitmap] instead.
70 | *
71 | * @param data An image request model.
72 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
73 | * @param avatarSize A specified avatar size.
74 | *
75 | * @return The loaded bitmap or null if the loading failed (e.g. network issues).
76 | */
77 | public open fun loadAvatarBitmapBlocking(
78 | data: Any?,
79 | avatar: Avatar,
80 | @Px avatarSize: Int
81 | ): Bitmap? {
82 | return null
83 | }
84 |
85 | /**
86 | * Loads a Bitmap with the image request [data] to represent the avatar in a suspending operation.
87 | *
88 | * This method requests images by using the [ImageLoader] on an IO coroutines scope.
89 | * The [loadAvatarBitmapBlocking] method takes precedence over this one if both are implemented.
90 | * Prefer implementing this method if possible.
91 | *
92 | * @param data An image request model.
93 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
94 | * @param avatarSize A specified avatar size.
95 | *
96 | * @return The loaded bitmap or null if the loading failed (e.g. network issues).
97 | */
98 | public open suspend fun loadAvatarBitmap(
99 | data: Any?,
100 | avatar: Avatar,
101 | @Px avatarSize: Int
102 | ): Bitmap? {
103 | return AvatarImageLoaderInternal.loadAsBitmap(
104 | context = context,
105 | data = data,
106 | onSuccess = avatar.onSuccess,
107 | onError = avatar.onError
108 | )
109 | }
110 |
111 | /**
112 | * Loads a Bitmap with the [avatar] to represent the placeholder of the avatar
113 | * in a suspending operation. This method will be executed if the previous image request failed.
114 | *
115 | * This method takes precedence over [loadAvatarPlaceholderBitmap] if both are implemented.
116 | *
117 | * Override this method only if you can't provide a suspending implementation, otherwise
118 | * override [loadAvatarPlaceholderBitmap] instead.
119 | *
120 | * @param data An image request model.
121 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
122 | * @param avatarSize A specified avatar size.
123 | */
124 | public open fun loadAvatarPlaceholderBitmapBlocking(
125 | data: Any?,
126 | avatar: Avatar,
127 | @Px avatarSize: Int
128 | ): Bitmap? {
129 | return null
130 | }
131 |
132 | /**
133 | * Loads a Bitmap with the [avatar] to represent the placeholder of the avatar
134 | * in a suspending operation. This method will be executed if the previous image request failed.
135 | *
136 | * The [loadAvatarPlaceholderBitmapBlocking] method takes precedence over this one if both are implemented.
137 | * Prefer implementing this method if possible.
138 | *
139 | * @param data An image request model.
140 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
141 | * @param avatarSize A specified avatar size.
142 | */
143 | public open suspend fun loadAvatarPlaceholderBitmap(
144 | data: Any?,
145 | avatar: Avatar,
146 | @Px avatarSize: Int
147 | ): Bitmap? {
148 | return null
149 | }
150 |
151 | /**
152 | * Creates a combined avatar Bitmap with the data model [avatar] and the specified [avatarSize]
153 | * to represent the avatar image, in a suspending operation.
154 | *
155 | * @param avatar An [Avatar] data model which includes request model and avatar styles.
156 | * @param avatarSize A specified avatar size.
157 | *
158 | * @return The combined bitmap or null if the loading failed (e.g. network issues).
159 | */
160 | public open suspend fun createAvatarBitmaps(
161 | avatar: Avatar,
162 | @Px avatarSize: Int,
163 | ): Bitmap? {
164 | return avatar.data.take(avatar.maxSectionSize)
165 | .map { createAvatarBitmapInternal(it, avatar, avatarSize) }
166 | .takeIf { it.isNotEmpty() }
167 | ?.let {
168 | AvatarBitmapCombiner.combine(
169 | bitmaps = it,
170 | size = avatarSize,
171 | maxSectionSize = avatar.maxSectionSize,
172 | errorPlaceholder = avatar.errorPlaceholder
173 | )
174 | }
175 | }
176 |
177 | /** Returns cache key for caching the avatar Bitmap image on memory. */
178 | public open fun avatarBitmapKey(avatar: Avatar): String? = "${avatar.data}"
179 | }
180 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarCoil.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.annotation.SuppressLint
20 | import android.content.Context
21 | import android.graphics.drawable.BitmapDrawable
22 | import coil.ImageLoader
23 | import coil.ImageLoaderFactory
24 | import io.getstream.avatarview.coil.AvatarCoil.imageLoader
25 | import io.getstream.avatarview.coil.AvatarCoil.setImageLoader
26 |
27 | /**
28 | * AvatarCoil provides a [ImageLoader], [AvatarBitmapFactory], and [ImageHeadersProvider] that can be
29 | * fully customized for loading avatar image:
30 | *
31 | * - [imageLoader] be used to load [Avatar] payload internally. You can customize with your
32 | * own [ImageLoaderFactory] or [AvatarImageLoaderFactory] by using [setImageLoader] function.
33 | *
34 | * - [AvatarBitmapFactory] will creates avatar bitmaps when [AvatarFetcher] fetches
35 | * the [Avatar] payload successfully. The loaded bitmaps will be operated by the factory and they will be
36 | * loaded as [BitmapDrawable] to the [io.getstream.avatarview.AvatarView].
37 | *
38 | * - [ImageHeadersProvider] be used to provide image header. If you're using your own CDN,
39 | * you can set the [AvatarCoil.imageHeadersProvider] to load image data with your own header.
40 | */
41 | public object AvatarCoil {
42 |
43 | private var imageLoader: ImageLoader? = null
44 | private var imageLoaderFactory: ImageLoaderFactory? = null
45 |
46 | /**
47 | * Sets a [ImageLoaderFactory] to provide your own [ImageLoader].
48 | *
49 | * @param factory An [ImageLoader] factory.
50 | */
51 | @Synchronized
52 | public fun setImageLoader(factory: ImageLoaderFactory) {
53 | imageLoaderFactory = factory
54 | imageLoader = null
55 | }
56 |
57 | /** Returns an [imageLoader] or [newImageLoader]. */
58 | @PublishedApi
59 | internal fun imageLoader(context: Context): ImageLoader = imageLoader ?: newImageLoader(context)
60 |
61 | /** Returns an [imageLoader] or a new [imageLoader] from the [imageLoaderFactory]. */
62 | @Synchronized
63 | private fun newImageLoader(context: Context): ImageLoader {
64 | imageLoader?.let { return it }
65 |
66 | val imageLoaderFactory = imageLoaderFactory ?: newImageLoaderFactory(context)
67 | return imageLoaderFactory.newImageLoader().apply {
68 | imageLoader = this
69 | }
70 | }
71 |
72 | /** Creates a new default instance of the [ImageLoaderFactory]. */
73 | private fun newImageLoaderFactory(context: Context): ImageLoaderFactory {
74 | return AvatarImageLoaderFactory(context).apply {
75 | imageLoaderFactory = this
76 | }
77 | }
78 |
79 | /** Returns an [imageLoader] to load avatar images. */
80 | @PublishedApi
81 | internal inline val Context.avatarImageLoader: ImageLoader
82 | get() = imageLoader(this)
83 |
84 | /** An avatar bitmap factory to create custom avatar bitmaps. */
85 | @SuppressLint("StaticFieldLeak")
86 | private var avatarBitmapFactory: AvatarBitmapFactory? = null
87 |
88 | /** Returns an [AvatarBitmapFactory]. */
89 | public fun getAvatarBitmapFactory(context: Context): AvatarBitmapFactory {
90 | return avatarBitmapFactory ?: synchronized(this) {
91 | avatarBitmapFactory ?: AvatarBitmapFactory(context.applicationContext).also {
92 | avatarBitmapFactory = it
93 | }
94 | }
95 | }
96 |
97 | /** Sets a custom [AvatarBitmapFactory]. */
98 | @Synchronized
99 | public fun setAvatarBitmapFactory(avatarBitmapFactory: AvatarBitmapFactory?) {
100 | this.avatarBitmapFactory = avatarBitmapFactory
101 | }
102 |
103 | /** Provides a custom image header. */
104 | public var imageHeadersProvider: ImageHeadersProvider = DefaultImageHeadersProvider
105 | }
106 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarFetcher.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.content.Context
20 | import android.graphics.drawable.BitmapDrawable
21 | import coil.ImageLoader
22 | import coil.decode.DataSource
23 | import coil.fetch.DrawableResult
24 | import coil.fetch.Fetcher
25 | import coil.request.Options
26 | import coil.size.pxOrElse
27 |
28 | /**
29 | * An image request fetcher of [Avatar] data type.
30 | *
31 | * This fetcher will create a Bitmap using the [Avatar] data in the coroutines scope.
32 | */
33 | internal class AvatarFetcher constructor(
34 | private val context: Context
35 | ) : Fetcher.Factory {
36 |
37 | override fun create(data: Avatar, options: Options, imageLoader: ImageLoader): Fetcher {
38 | val targetSize = options.size.width.pxOrElse { 0 }
39 | val resources = options.context.resources
40 | return Fetcher {
41 | DrawableResult(
42 | BitmapDrawable(
43 | resources,
44 | AvatarCoil.getAvatarBitmapFactory(context).createAvatarBitmaps(
45 | data,
46 | targetSize - data.avatarBorderWidth * 2
47 | )
48 | ),
49 | false,
50 | DataSource.MEMORY
51 | )
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarImageLoaderFactory.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.content.Context
20 | import android.os.Build
21 | import coil.ImageLoader
22 | import coil.ImageLoaderFactory
23 | import coil.decode.GifDecoder
24 | import coil.decode.ImageDecoderDecoder
25 |
26 | /**
27 | * An [ImageLoader] factory to provide an instance of the [ImageLoader].
28 | *
29 | * AvatarImageLoaderFactory creates a default [ImageLoader] that has
30 | * caching strategy with OkHttp, image decoder (supports GIFs), and [AvatarFetcher].
31 | */
32 | public class AvatarImageLoaderFactory(
33 | private val context: Context,
34 | private val builder: ImageLoader.Builder.() -> Unit = {}
35 | ) : ImageLoaderFactory {
36 |
37 | /** Creates a new [ImageLoader] to load [Avatar] image data. */
38 | override fun newImageLoader(): ImageLoader {
39 | return ImageLoader.Builder(context)
40 | .allowHardware(false)
41 | .crossfade(true)
42 | .components {
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
44 | add(ImageDecoderDecoder.Factory())
45 | } else {
46 | add(GifDecoder.Factory())
47 | }
48 | add(AvatarFetcher(context))
49 | }
50 | .apply(builder)
51 | .build()
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarImageLoaderInternal.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | import android.content.Context
20 | import android.graphics.Bitmap
21 | import android.graphics.drawable.BitmapDrawable
22 | import coil.load
23 | import coil.request.ErrorResult
24 | import coil.request.ImageRequest
25 | import coil.request.SuccessResult
26 | import coil.transform.CircleCropTransformation
27 | import coil.transform.Transformation
28 | import io.getstream.avatarview.AvatarView
29 | import io.getstream.avatarview.coil.AvatarCoil.avatarImageLoader
30 | import io.getstream.avatarview.internal.InternalAvatarViewApi
31 | import kotlinx.coroutines.Dispatchers
32 | import kotlinx.coroutines.withContext
33 | import okhttp3.Headers.Companion.toHeaders
34 |
35 | /** An internal image loader to request image data with Coil. */
36 | @InternalAvatarViewApi
37 | public object AvatarImageLoaderInternal {
38 |
39 | /**
40 | * Request an image [data] and loads it as a Bitmap in a suspending operation.
41 | *
42 | * If you're using your own CDN, you can set the [AvatarCoil.imageHeadersProvider] to load
43 | * image data.
44 | *
45 | * @param context A context to build [ImageRequest].
46 | * @param data An image [data].
47 | * @param onSuccess A lambda function will be executed when loading succeeds.
48 | * @param onError A lambda function will be executed when loading failed.
49 | *
50 | * @return The loaded bitmap or null if the loading failed (e.g. network issues).
51 | */
52 | @JvmSynthetic
53 | public suspend fun loadAsBitmap(
54 | context: Context,
55 | data: Any?,
56 | onSuccess: (request: ImageRequest, result: SuccessResult) -> Unit = { _, _ -> },
57 | onError: (request: ImageRequest, result: ErrorResult) -> Unit = { _, _ -> },
58 | ): Bitmap? = withContext(Dispatchers.IO) {
59 | val imageResult = context.avatarImageLoader.execute(
60 | ImageRequest.Builder(context)
61 | .headers(AvatarCoil.imageHeadersProvider.getImageRequestHeaders().toHeaders())
62 | .listener(onSuccess = onSuccess, onError = onError)
63 | .data(data)
64 | .build()
65 | )
66 | (imageResult.drawable as? BitmapDrawable)?.bitmap
67 | }
68 |
69 | /**
70 | * Loads an image [data] to the [target] AvatarView with [transformation].
71 | *
72 | * @param target A target [AvatarView] to load image data.
73 | * @param data An image data to be loaded.
74 | * @param transformation A [Transformation] to transform loaded images.
75 | * @param onStart A lambda function will be executed when start requesting.
76 | * @param onComplete A lambda function will be executed when finish loading.
77 | * @param builder A receiver to be applied with the [ImageRequest.Builder].
78 | */
79 | @JvmSynthetic
80 | @PublishedApi
81 | internal fun load(
82 | target: AvatarView,
83 | data: Any?,
84 | transformation: Transformation = CircleCropTransformation(),
85 | onStart: () -> Unit,
86 | onComplete: () -> Unit,
87 | builder: ImageRequest.Builder.() -> Unit
88 | ) {
89 | val context = target.context
90 | target.load(data, context.avatarImageLoader) {
91 | headers(AvatarCoil.imageHeadersProvider.getImageRequestHeaders().toHeaders())
92 | transformations(transformation)
93 | listener(
94 | onStart = { onStart() },
95 | onCancel = { onComplete() },
96 | onError = { _, _ -> onComplete() },
97 | onSuccess = { _, _ -> onComplete() },
98 | )
99 | apply(builder)
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/AvatarViewExtension.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | @file:JvmName("AvatarViewExtension")
18 | @file:JvmMultifileClass
19 |
20 | package io.getstream.avatarview.coil
21 |
22 | import coil.request.ErrorResult
23 | import coil.request.ImageRequest
24 | import coil.request.SuccessResult
25 | import coil.transform.CircleCropTransformation
26 | import coil.transform.RoundedCornersTransformation
27 | import coil.transform.Transformation
28 | import io.getstream.avatarview.AvatarShape
29 | import io.getstream.avatarview.AvatarView
30 |
31 | /**
32 | * Loads an image request [data] to the [AvatarView].
33 | *
34 | * @param data An image data to be loaded.
35 | * @param onStart A lambda function will be executed when start requesting.
36 | * @param onComplete A lambda function will be executed when loading finished.
37 | * @param onSuccess A lambda function will be executed when loading succeeds.
38 | * @param onError A lambda function will be executed when loading failed.
39 | * @param builder A receiver to be applied with the [ImageRequest.Builder].
40 | */
41 | @JvmSynthetic
42 | public fun AvatarView.loadImage(
43 | data: Any?,
44 | onStart: () -> Unit = {},
45 | onComplete: () -> Unit = {},
46 | onSuccess: (request: ImageRequest, result: SuccessResult) -> Unit = { _, _ -> },
47 | onError: (request: ImageRequest, result: ErrorResult) -> Unit = { _, _ -> },
48 | builder: ImageRequest.Builder.() -> Unit = {}
49 | ) {
50 | loadPlaceholder()
51 | AvatarImageLoaderInternal.load(
52 | target = this,
53 | data = Avatar(
54 | data = listOf(data),
55 | maxSectionSize = maxSectionSize,
56 | avatarBorderWidth = avatarBorderWidth,
57 | errorPlaceholder = errorPlaceholder,
58 | onSuccess = onSuccess,
59 | onError = onError
60 | ),
61 | transformation = transformation,
62 | onStart = onStart,
63 | onComplete = onComplete,
64 | builder = builder,
65 | )
66 | }
67 |
68 | /**
69 | * Loads a list of image request [data] to the [AvatarView].
70 | * Up to 4 images will be combined and loaded.
71 | *
72 | * @param data A list of image data to be loaded.
73 | * @param onStart A lambda function will be executed when start requesting.
74 | * @param onComplete A lambda function will be executed when finish loading.
75 | * @param onSuccess A lambda function will be executed when loading succeeds.
76 | * @param onError A lambda function will be executed when loading failed.
77 | * @param builder A receiver to be applied with the [ImageRequest.Builder].
78 | */
79 | @JvmSynthetic
80 | public fun AvatarView.loadImage(
81 | data: List,
82 | onStart: () -> Unit = {},
83 | onComplete: () -> Unit = {},
84 | onSuccess: (request: ImageRequest, result: SuccessResult) -> Unit = { _, _ -> },
85 | onError: (request: ImageRequest, result: ErrorResult) -> Unit = { _, _ -> },
86 | builder: ImageRequest.Builder.() -> Unit = {}
87 | ) {
88 | loadPlaceholder()
89 | AvatarImageLoaderInternal.load(
90 | target = this,
91 | data = Avatar(
92 | data = data,
93 | maxSectionSize = maxSectionSize,
94 | avatarBorderWidth = avatarBorderWidth,
95 | errorPlaceholder = errorPlaceholder,
96 | onSuccess = onSuccess,
97 | onError = onError
98 | ),
99 | transformation = transformation,
100 | onStart = onStart,
101 | onComplete = onComplete,
102 | builder = builder,
103 | )
104 | }
105 |
106 | /**
107 | * Loads a vararg of image request [data] to the [AvatarView].
108 | * Up to 4 images will be combined and loaded.
109 | *
110 | * @param data A vararg of image data to be loaded.
111 | * @param onStart A lambda function will be executed when start requesting.
112 | * @param onComplete A lambda function will be executed when finish loading.
113 | * @param onSuccess A lambda function will be executed when loading succeeds.
114 | * @param onError A lambda function will be executed when loading failed.
115 | * @param builder A receiver to be applied with the [ImageRequest.Builder].
116 | */
117 | @JvmSynthetic
118 | public fun AvatarView.loadImage(
119 | vararg data: Any?,
120 | onStart: () -> Unit = {},
121 | onComplete: () -> Unit = {},
122 | onSuccess: (request: ImageRequest, result: SuccessResult) -> Unit = { _, _ -> },
123 | onError: (request: ImageRequest, result: ErrorResult) -> Unit = { _, _ -> },
124 | builder: ImageRequest.Builder.() -> Unit = {}
125 | ) {
126 | loadPlaceholder()
127 | loadImage(
128 | data = data.toList(),
129 | onStart = onStart,
130 | onComplete = onComplete,
131 | onSuccess = onSuccess,
132 | onError = onError,
133 | builder = builder
134 | )
135 | }
136 |
137 | /** Loads a placeholder with the [AvatarView.placeholder] property. */
138 | @PublishedApi
139 | internal fun AvatarView.loadPlaceholder() {
140 | placeholder?.let {
141 | AvatarImageLoaderInternal.load(
142 | target = this,
143 | data = it,
144 | transformation = transformation,
145 | onStart = {},
146 | onComplete = {},
147 | builder = {}
148 | )
149 | }
150 | }
151 |
152 | /** Returns a [Transformation] from a [AvatarView]. */
153 | @PublishedApi
154 | internal val AvatarView.transformation: Transformation
155 | @JvmSynthetic inline get() = when (avatarShape) {
156 | AvatarShape.CIRCLE -> CircleCropTransformation()
157 | AvatarShape.ROUNDED_RECT -> RoundedCornersTransformation(avatarBorderRadius)
158 | }
159 |
--------------------------------------------------------------------------------
/avatarview-coil/src/main/kotlin/io/getstream/avatarview/coil/ImageHeadersProvider.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 Stream.IO, Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package io.getstream.avatarview.coil
18 |
19 | /** Provides HTTP headers for image loading requests. */
20 | public interface ImageHeadersProvider {
21 | public fun getImageRequestHeaders(): Map
22 | }
23 |
24 | /** Provides a default HTTP headers for image loading requests. */
25 | internal object DefaultImageHeadersProvider : ImageHeadersProvider {
26 | override fun getImageRequestHeaders(): Map = emptyMap()
27 | }
28 |
--------------------------------------------------------------------------------
/avatarview-glide/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/avatarview-glide/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
AvatarView-Glide
4 |
5 |
6 | AvatarView supports loading profile images with fractional style, borders, indicators, and initials for Android.
7 |