├── .allstar
└── binary_artifacts.yaml
├── .github
├── ISSUE_TEMPLATE
│ ├── adaptive-bug-report.md
│ ├── bug_report.md
│ ├── config.yml
│ ├── general-bug-report.md
│ ├── general-other-bug-report.md
│ ├── navigation-material-bug-report.md
│ ├── permissions-bug-report.md
│ └── testharness-bug-report.md
├── auto-merge.yml
├── ci-gradle.properties
├── pull_request_template.md
├── release-drafter.yml
└── workflows
│ ├── automerger.yml
│ ├── build-snapshot.yml
│ ├── build.yml
│ ├── issues-stale.yml
│ ├── publish-docs.yml
│ └── update-release.yml
├── .gitignore
├── .idea
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── copyright
│ ├── AOSP.xml
│ └── profiles_settings.xml
├── deploymentTargetSelector.xml
├── inspectionProfiles
│ ├── ktlint.xml
│ └── profiles_settings.xml
├── kotlinScripting.xml
├── kotlinc.xml
├── runConfigurations.xml
└── vcs.xml
├── ASSETS_LICENSE.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── adaptive
├── README.md
├── api
│ └── current.api
├── build.gradle.kts
├── gradle.properties
└── src
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── google
│ │ └── accompanist
│ │ └── adaptive
│ │ ├── DisplayFeatures.kt
│ │ ├── FoldAwareColumn.kt
│ │ ├── FoldAwareColumnScope.kt
│ │ ├── RowColumnImpl.kt
│ │ ├── RowColumnMeasurementHelper.kt
│ │ └── TwoPane.kt
│ ├── sharedTest
│ └── kotlin
│ │ └── com
│ │ └── google
│ │ └── accompanist
│ │ └── adaptive
│ │ ├── DisplayFeaturesTest.kt
│ │ ├── FoldAwareColumnTest.kt
│ │ └── TwoPaneTest.kt
│ └── test
│ └── resources
│ └── robolectric.properties
├── build-logic
├── convention
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── kotlin
│ │ ├── AndroidLibraryComposeConventionPlugin.kt
│ │ ├── AndroidLibraryConventionPlugin.kt
│ │ ├── AndroidLibraryPublishedConventionPlugin.kt
│ │ ├── AndroidLintConventionPlugin.kt
│ │ └── com
│ │ └── google
│ │ └── accompanist
│ │ ├── AndroidCompose.kt
│ │ ├── BundleInsideHelper.kt
│ │ ├── KotlinAndroid.kt
│ │ └── ProjectExtensions.kt
├── gradle.properties
└── settings.gradle.kts
├── build.gradle
├── checksum.sh
├── docs
├── adaptive.md
├── appcompat-theme.md
├── drawablepainter.md
├── header.png
├── insets
│ └── images
│ │ ├── edge-to-edge-list.jpg
│ │ ├── ime-insets.gif
│ │ └── ime-scroll.gif
├── migration.md
├── migration
│ └── studio.png
├── navigation-animation.md
├── navigation-material.md
├── permissions.md
├── swiperefresh
│ ├── demo.mp4
│ └── tweaked.mp4
├── systemuicontroller.md
├── systemuicontroller
│ └── api-scrim.png
├── themeadapter
│ ├── material-header.png
│ └── material3-header.png
├── updating.md
├── using-snapshot-version.md
└── web.md
├── drawablepainter
├── README.md
├── api
│ └── current.api
├── build.gradle.kts
├── gradle.properties
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── google
│ └── accompanist
│ └── drawablepainter
│ └── DrawablePainter.kt
├── generate_docs.sh
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
└── Social.sketch
├── internal-testutils
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── google
│ │ └── accompanist
│ │ └── internal
│ │ └── test
│ │ ├── ActivityScenario.kt
│ │ ├── Assertions.kt
│ │ ├── IgnoreOnRobolectric.kt
│ │ ├── TestUtils.kt
│ │ └── WaitUntil.kt
│ └── res
│ └── values
│ └── themes.xml
├── mkdocs.yml
├── permissions-lint
├── README.md
├── build.gradle.kts
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── google
│ │ │ └── accompanist
│ │ │ └── permissions
│ │ │ └── lint
│ │ │ ├── PermissionsIssueRegistry.kt
│ │ │ ├── PermissionsLaunchDetector.kt
│ │ │ └── util
│ │ │ ├── ComposableUtils.kt
│ │ │ ├── KotlinMetadataUtils.kt
│ │ │ ├── Names.kt
│ │ │ └── PsiUtils.kt
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── com.android.tools.lint.client.api.IssueRegistry
│ └── test
│ └── java
│ └── com
│ └── google
│ └── accompanist
│ └── permissions
│ └── lint
│ └── PermissionsLaunchDetectorTest.kt
├── permissions
├── README.md
├── api
│ └── current.api
├── build.gradle.kts
├── gradle.properties
└── src
│ ├── androidTest
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── google
│ │ └── accompanist
│ │ └── permissions
│ │ ├── FakeTests.kt
│ │ ├── MultipleAndSinglePermissionsTest.kt
│ │ ├── MultiplePermissionsStateTest.kt
│ │ ├── PermissionStateTest.kt
│ │ ├── RequestMultiplePermissionsTest.kt
│ │ ├── RequestPermissionTest.kt
│ │ ├── TestUtils.kt
│ │ └── test
│ │ ├── EmptyPermissionsTestActivity.kt
│ │ └── PermissionsTestActivity.kt
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── google
│ └── accompanist
│ └── permissions
│ ├── MultiplePermissionsState.kt
│ ├── MutableMultiplePermissionsState.kt
│ ├── MutablePermissionState.kt
│ ├── PermissionState.kt
│ └── PermissionsUtil.kt
├── release
├── secring.gpg.aes
├── signing-cleanup.sh
├── signing-setup.sh
└── signing.properties.aes
├── sample
├── build.gradle.kts
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── google
│ │ └── accompanist
│ │ └── sample
│ │ ├── ImageLoadingSampleUtils.kt
│ │ ├── MainActivity.kt
│ │ ├── MainScreen.kt
│ │ ├── Theme.kt
│ │ ├── adaptive
│ │ ├── BasicTwoPaneSample.kt
│ │ ├── DraggableFoldAwareColumnSample.kt
│ │ ├── HorizontalTwoPaneSample.kt
│ │ ├── NavDrawerFoldAwareColumnSample.kt
│ │ ├── NavRailFoldAwareColumnSample.kt
│ │ └── VerticalTwoPaneSample.kt
│ │ ├── drawablepainter
│ │ └── DocSamples.kt
│ │ └── permissions
│ │ ├── RequestLocationPermissionsSample.kt
│ │ ├── RequestMultiplePermissionsSample.kt
│ │ └── RequestPermissionSample.kt
│ └── res
│ ├── drawable-nodpi
│ └── placeholder.jpg
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── alpha.png
│ ├── ic_launcher_background.xml
│ └── rectangle.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── values-ar
│ └── strings.xml
│ └── values
│ └── strings.xml
├── scripts
└── run-tests.sh
├── settings.gradle.kts
└── spotless
├── copyright.txt
└── greclipse.properties
/.allstar/binary_artifacts.yaml:
--------------------------------------------------------------------------------
1 | # Exemption reason: This repo uses binary artifacts to ship gradle.jar for users. It does not allow any others.
2 | # Exemption timeframe: permanent
3 | optConfig:
4 | optOut: true
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/adaptive-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Adaptive bug report
3 | about: Create a report about adaptive
4 | title: "[Adaptive]"
5 | labels: adaptive
6 | assignees: alexvanyo
7 |
8 | ---
9 |
10 | **Description**
11 |
12 | **Steps to reproduce**
13 |
14 | **Expected behavior**
15 |
16 | **Additional context**
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the bug
11 | A clear and concise description of what the bug is.
12 |
13 | ## To Reproduce
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | ## Expected behavior
21 | A clear and concise description of what you expected to happen.
22 |
23 | ## Screenshots?
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | ## Environment:
27 | - Android OS version: [e.g. Android 5.0]
28 | - Device: [e.g. Emulator, Google Pixel 4]
29 | - Accompanist version: [e.g. v0.X]
30 |
31 | ## Additional context
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/general-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: General Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the bug
11 | A clear and concise description of what the bug is.
12 |
13 | ## To Reproduce (if applicable)
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | ## Expected behavior (if applicable)
21 | A clear and concise description of what you expected to happen.
22 |
23 | ## Screenshots? (if applicable)
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | ## Environment: (if applicable)
27 | - Android OS version: [e.g. Android 5.0]
28 | - Device: [e.g. Emulator, Google Pixel 4]
29 | - Accompanist version: [e.g. v0.X]
30 |
31 | ## Additional context
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/general-other-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: General/Other bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Describe the bug
11 | A clear and concise description of what the bug is.
12 |
13 | ## To Reproduce (if applicable)
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | ## Expected behavior (if applicable)
21 | A clear and concise description of what you expected to happen.
22 |
23 | ## Screenshots? (if applicable)
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | ## Environment: (if applicable)
27 | - Android OS version: [e.g. Android 5.0]
28 | - Device: [e.g. Emulator, Google Pixel 4]
29 | - Accompanist version: [e.g. v0.X]
30 |
31 | ## Additional context
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/navigation-material-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Navigation Material bug report
3 | about: Create a report to help us improve
4 | title: "[Navigation Material] "
5 | labels: ''
6 | assignees: jossiwolf
7 |
8 | ---
9 |
10 | **Description**
11 |
12 | **Steps to reproduce**
13 |
14 | **Expected behavior**
15 |
16 | **Additional context**
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/permissions-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Permissions bug report
3 | about: Create a report to help us improve
4 | title: "[Permissions] "
5 | labels: ''
6 | assignees: bentrengrove
7 |
8 | ---
9 |
10 | **Description**
11 |
12 | **Steps to reproduce**
13 |
14 | **Expected behavior**
15 |
16 | **Additional context**
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/testharness-bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Test harness bug report
3 | about: Create a report about test harness
4 | title: "[Test Harness]"
5 | labels: testharness
6 | assignees: alexvanyo
7 |
8 | ---
9 |
10 | **Description**
11 |
12 | **Steps to reproduce**
13 |
14 | **Expected behavior**
15 |
16 | **Additional context**
17 |
--------------------------------------------------------------------------------
/.github/auto-merge.yml:
--------------------------------------------------------------------------------
1 | # Config for github.com/bobvanderlinden/probot-auto-merge
2 | minApprovals:
3 | COLLABORATOR: 1
4 | requiredLabels:
5 | - automerge
6 | mergeMethod: merge
7 | reportStatus: true
--------------------------------------------------------------------------------
/.github/ci-gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2019 Google LLC
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 | # Turn Gradle daemon off due to https://github.com/Kotlin/dokka/issues/1405
18 | org.gradle.daemon=false
19 |
20 | org.gradle.parallel=true
21 | org.gradle.jvmargs=-Xmx4608m -XX:MaxMetaspaceSize=2048m -XX:+HeapDumpOnOutOfMemoryError
22 | org.gradle.workers.max=2
23 |
24 | kotlin.compiler.execution.strategy=in-process
25 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ### Please add the library name to the PR title. Example: "[Insets] Fixes typo" ###
2 |
--------------------------------------------------------------------------------
/.github/release-drafter.yml:
--------------------------------------------------------------------------------
1 | name-template: 'v$NEXT_PATCH_VERSION 🌈'
2 | tag-template: 'v$NEXT_PATCH_VERSION'
3 | template: |
4 | ## What’s Changed
5 |
6 | $CHANGES
--------------------------------------------------------------------------------
/.github/workflows/automerger.yml:
--------------------------------------------------------------------------------
1 | name: main to snapshot auto merger
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | automerge:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | with:
15 | fetch-depth: '0' # 0 == fetch all history history
16 | ref: 'snapshot'
17 | token: ${{ secrets.AUTOMERGE_PAT }}
18 |
19 | - run: |
20 | git config user.name github-actions
21 | git config user.email github-actions@github.com
22 | git fetch origin
23 | git merge origin/main --no-edit
24 | git push
25 |
--------------------------------------------------------------------------------
/.github/workflows/issues-stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 | on:
3 | schedule:
4 | - cron: '15 3 * * *'
5 |
6 | jobs:
7 | stale:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/stale@v3
11 | with:
12 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
13 | days-before-stale: 45
14 | days-before-close: 5
15 | exempt-all-pr-milestones: true
16 | exempt-issue-labels: 'waiting for info,waiting on dependency'
17 |
--------------------------------------------------------------------------------
/.github/workflows/publish-docs.yml:
--------------------------------------------------------------------------------
1 | name: Publish docs
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*
7 | workflow_dispatch:
8 |
9 | jobs:
10 | deploy_docs:
11 | runs-on: ubuntu-latest
12 | env:
13 | TERM: dumb
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 |
18 | - name: Copy CI gradle.properties
19 | run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties
20 |
21 | - name: Setup java
22 | uses: actions/setup-java@v3
23 | with:
24 | distribution: temurin
25 | java-version: 17
26 |
27 | - name: Setup Gradle
28 | uses: gradle/gradle-build-action@v2
29 |
30 | - name: Setup Python
31 | uses: actions/setup-python@v4
32 | with:
33 | python-version: '3.x'
34 |
35 | - name: Install dependencies
36 | run: |
37 | python3 -m pip install --upgrade pip
38 | python3 -m pip install mkdocs-material=="9.*"
39 |
40 | - name: Generate docs
41 | run: ./generate_docs.sh
42 |
43 | - name: Build site
44 | run: mkdocs build
45 |
46 | - name: Deploy
47 | uses: peaceiris/actions-gh-pages@v3
48 | with:
49 | github_token: ${{ secrets.GITHUB_TOKEN }}
50 | publish_dir: ./site
51 |
--------------------------------------------------------------------------------
/.github/workflows/update-release.yml:
--------------------------------------------------------------------------------
1 | name: Update release
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | update_draft_release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | # pin directly to 6.0.0 because we don't want to update without knowledge
13 | - uses: release-drafter/release-drafter@3f0f87098bd6b5c5b9a36d49c41d998ea58f9348
14 | env:
15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle
2 | .gradle
3 | build/
4 |
5 | captures
6 |
7 | /local.properties
8 |
9 | # IntelliJ .idea folder
10 | .idea/workspace.xml
11 | .idea/libraries
12 | .idea/caches
13 | .idea/navEditor.xml
14 | .idea/tasks.xml
15 | .idea/modules.xml
16 | .idea/compiler.xml
17 | .idea/jarRepositories.xml
18 | .idea/deploymentTargetDropDown.xml
19 | .idea/misc.xml
20 | .idea/androidTestResultsUserPreferences.xml
21 | .idea/deploymentTargetSelector.xml
22 | gradle.xml
23 | *.iml
24 |
25 | # General
26 | .DS_Store
27 | .externalNativeBuild
28 |
29 | # Do not commit plain-text signing info
30 | release/*.properties
31 | release/*.gpg
32 |
33 | # VS Code config
34 | org.eclipse.buildship.core.prefs
35 | .classpath
36 | .project
37 |
38 | # Temporary API docs
39 | docs/api
40 | package-list-coil-base
41 |
42 | # Mkdocs temporary serving folder
43 | docs-gen
44 | site
45 | *.bak
46 |
47 | # Lint reports
48 | lint-report.*
49 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/AOSP.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetSelector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/ktlint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/kotlinScripting.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ASSETS_LICENSE.txt:
--------------------------------------------------------------------------------
1 | All font files are licensed under the SIL OPEN FONT LICENSE license. All other files are licensed under the Apache 2 license.
2 |
3 |
4 | SIL OPEN FONT LICENSE
5 | Version 1.1 - 26 February 2007
6 |
7 | PREAMBLE
8 | The goals of the Open Font License (OFL) are to stimulate worldwide
9 | development of collaborative font projects, to support the font creation
10 | efforts of academic and linguistic communities, and to provide a free and
11 | open framework in which fonts may be shared and improved in partnership
12 | with others.
13 |
14 | The OFL allows the licensed fonts to be used, studied, modified and
15 | redistributed freely as long as they are not sold by themselves. The
16 | fonts, including any derivative works, can be bundled, embedded,
17 | redistributed and/or sold with any software provided that any reserved
18 | names are not used by derivative works. The fonts and derivatives,
19 | however, cannot be released under any other type of license. The
20 | requirement for fonts to remain under this license does not apply
21 | to any document created using the fonts or their derivatives.
22 |
23 | DEFINITIONS
24 | "Font Software" refers to the set of files released by the Copyright
25 | Holder(s) under this license and clearly marked as such. This may
26 | include source files, build scripts and documentation.
27 |
28 | "Reserved Font Name" refers to any names specified as such after the
29 | copyright statement(s).
30 |
31 | "Original Version" refers to the collection of Font Software components as
32 | distributed by the Copyright Holder(s).
33 |
34 | "Modified Version" refers to any derivative made by adding to, deleting,
35 | or substituting — in part or in whole — any of the components of the
36 | Original Version, by changing formats or by porting the Font Software to a
37 | new environment.
38 |
39 | "Author" refers to any designer, engineer, programmer, technical
40 | writer or other person who contributed to the Font Software.
41 |
42 | PERMISSION & CONDITIONS
43 | Permission is hereby granted, free of charge, to any person obtaining
44 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
45 | redistribute, and sell modified and unmodified copies of the Font
46 | Software, subject to the following conditions:
47 |
48 | 1) Neither the Font Software nor any of its individual components,
49 | in Original or Modified Versions, may be sold by itself.
50 |
51 | 2) Original or Modified Versions of the Font Software may be bundled,
52 | redistributed and/or sold with any software, provided that each copy
53 | contains the above copyright notice and this license. These can be
54 | included either as stand-alone text files, human-readable headers or
55 | in the appropriate machine-readable metadata fields within text or
56 | binary files as long as those fields can be easily viewed by the user.
57 |
58 | 3) No Modified Version of the Font Software may use the Reserved Font
59 | Name(s) unless explicit written permission is granted by the corresponding
60 | Copyright Holder. This restriction only applies to the primary font name as
61 | presented to the users.
62 |
63 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
64 | Software shall not be used to promote, endorse or advertise any
65 | Modified Version, except to acknowledge the contribution(s) of the
66 | Copyright Holder(s) and the Author(s) or with their explicit written
67 | permission.
68 |
69 | 5) The Font Software, modified or unmodified, in part or in whole,
70 | must be distributed entirely under this license, and must not be
71 | distributed under any other license. The requirement for fonts to
72 | remain under this license does not apply to any document created
73 | using the Font Software.
74 |
75 | TERMINATION
76 | This license becomes null and void if any of the above conditions are
77 | not met.
78 |
79 | DISCLAIMER
80 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
81 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
82 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
83 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
84 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
85 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
86 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
87 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
88 | OTHER DEALINGS IN THE FONT SOFTWARE.
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## New Features/Libraries
7 |
8 | Before contributing large new features and/or libraries please start a discussion
9 | with us first via GitHub Issues and check that we can support it.
10 | We are unable to support all new features, even though we wish we could! If we
11 | are unable to support adding your feature, we always encourage you to open source it
12 | in your own repository to help the Compose community grow.
13 |
14 | ## Contributor License Agreement
15 |
16 | Contributions to this project must be accompanied by a Contributor License
17 | Agreement. You (or your employer) retain the copyright to your contribution,
18 | this simply gives us permission to use and redistribute your contributions as
19 | part of the project. Head over to to see
20 | your current agreements on file or to sign a new one.
21 |
22 | You generally only need to submit a CLA once, so if you've already submitted one
23 | (even if it was for a different project), you probably don't need to do it
24 | again.
25 |
26 | ## Code Reviews
27 |
28 | All submissions, including submissions by project members, require review. We
29 | use GitHub pull requests for this purpose. Consult
30 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
31 | information on using pull requests.
32 |
33 | ## API Changes
34 |
35 | If you are changing any public APIs, you need to run `./gradlew metalavaGenerateSignatureRelease` which will
36 | update the API signatures.
37 |
38 | ## Formatting
39 |
40 | To apply formatting, we use spotless. Run `./gradlew :pager:spotlessApply` to format the code according
41 | to the spec.
42 |
--------------------------------------------------------------------------------
/adaptive/README.md:
--------------------------------------------------------------------------------
1 | # Adaptive utilities for Jetpack Compose
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | For more information, visit the documentation: https://google.github.io/accompanist/adaptive
6 |
7 | ## Download
8 |
9 | ```groovy
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | implementation "com.google.accompanist:accompanist-adaptive:"
16 | }
17 | ```
18 |
19 | Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
20 |
21 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-adaptive/
--------------------------------------------------------------------------------
/adaptive/api/current.api:
--------------------------------------------------------------------------------
1 | // Signature format: 4.0
2 | package com.google.accompanist.adaptive {
3 |
4 | public final class DisplayFeaturesKt {
5 | method @androidx.compose.runtime.Composable public static java.util.List calculateDisplayFeatures(android.app.Activity activity);
6 | }
7 |
8 | public final class FoldAwareColumnKt {
9 | method @androidx.compose.runtime.Composable public static void FoldAwareColumn(java.util.List extends androidx.window.layout.DisplayFeature> displayFeatures, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.layout.PaddingValues foldPadding, optional androidx.compose.ui.Alignment.Horizontal horizontalAlignment, kotlin.jvm.functions.Function1 super com.google.accompanist.adaptive.FoldAwareColumnScope,kotlin.Unit> content);
10 | }
11 |
12 | @androidx.compose.foundation.layout.LayoutScopeMarker @androidx.compose.runtime.Immutable public interface FoldAwareColumnScope {
13 | method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier align(androidx.compose.ui.Modifier, androidx.compose.ui.Alignment.Horizontal alignment);
14 | method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier alignBy(androidx.compose.ui.Modifier, androidx.compose.ui.layout.VerticalAlignmentLine alignmentLine);
15 | method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier alignBy(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1 super androidx.compose.ui.layout.Measured,java.lang.Integer> alignmentLineBlock);
16 | method @androidx.compose.runtime.Stable public androidx.compose.ui.Modifier ignoreFold(androidx.compose.ui.Modifier);
17 | }
18 |
19 | @kotlin.jvm.JvmInline public final value class FoldAwareConfiguration {
20 | field public static final com.google.accompanist.adaptive.FoldAwareConfiguration.Companion Companion;
21 | }
22 |
23 | public static final class FoldAwareConfiguration.Companion {
24 | method public int getAllFolds();
25 | method public int getHorizontalFoldsOnly();
26 | method public int getVerticalFoldsOnly();
27 | property public final int AllFolds;
28 | property public final int HorizontalFoldsOnly;
29 | property public final int VerticalFoldsOnly;
30 | }
31 |
32 | public final class SplitResult {
33 | ctor public SplitResult(androidx.compose.foundation.gestures.Orientation gapOrientation, androidx.compose.ui.geometry.Rect gapBounds);
34 | method public androidx.compose.ui.geometry.Rect getGapBounds();
35 | method public androidx.compose.foundation.gestures.Orientation getGapOrientation();
36 | property public final androidx.compose.ui.geometry.Rect gapBounds;
37 | property public final androidx.compose.foundation.gestures.Orientation gapOrientation;
38 | }
39 |
40 | public final class TwoPaneKt {
41 | method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(float splitOffset, optional boolean offsetFromStart, optional float gapWidth);
42 | method public static com.google.accompanist.adaptive.TwoPaneStrategy HorizontalTwoPaneStrategy(float splitFraction, optional float gapWidth);
43 | method @androidx.compose.runtime.Composable public static void TwoPane(kotlin.jvm.functions.Function0 first, kotlin.jvm.functions.Function0 second, com.google.accompanist.adaptive.TwoPaneStrategy strategy, java.util.List extends androidx.window.layout.DisplayFeature> displayFeatures, optional androidx.compose.ui.Modifier modifier, optional int foldAwareConfiguration);
44 | method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(float splitOffset, optional boolean offsetFromTop, optional float gapHeight);
45 | method public static com.google.accompanist.adaptive.TwoPaneStrategy VerticalTwoPaneStrategy(float splitFraction, optional float gapHeight);
46 | }
47 |
48 | public fun interface TwoPaneStrategy {
49 | method public com.google.accompanist.adaptive.SplitResult calculateSplitResult(androidx.compose.ui.unit.Density density, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.layout.LayoutCoordinates layoutCoordinates);
50 | }
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/adaptive/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | @file:Suppress("UnstableApiUsage")
17 |
18 | plugins {
19 | alias(libs.plugins.accompanist.android.library)
20 | alias(libs.plugins.accompanist.android.library.compose)
21 | alias(libs.plugins.accompanist.android.library.published)
22 | }
23 |
24 | android {
25 | namespace = "com.google.accompanist.adaptive"
26 |
27 | sourceSets {
28 | named("test") {
29 | java.srcDirs("src/sharedTest/kotlin")
30 | res.srcDirs("src/sharedTest/res")
31 | }
32 | named("androidTest") {
33 | java.srcDirs("src/sharedTest/kotlin")
34 | res.srcDirs("src/sharedTest/res")
35 | }
36 | }
37 | }
38 |
39 | dependencies {
40 | api(libs.compose.foundation.foundation)
41 | api(libs.compose.ui.ui)
42 | api(libs.androidx.window)
43 |
44 | implementation(libs.kotlin.coroutines.android)
45 | implementation(libs.compose.ui.util)
46 |
47 | // ======================
48 | // Test dependencies
49 | // ======================
50 |
51 | androidTestImplementation(project(":internal-testutils"))
52 | testImplementation(project(":internal-testutils"))
53 |
54 | androidTestImplementation(libs.junit)
55 | testImplementation(libs.junit)
56 |
57 | androidTestImplementation(libs.truth)
58 | testImplementation(libs.truth)
59 |
60 | androidTestImplementation(libs.compose.ui.test.junit4)
61 | testImplementation(libs.compose.ui.test.junit4)
62 |
63 | androidTestImplementation(libs.compose.ui.test.manifest)
64 | testImplementation(libs.compose.ui.test.manifest)
65 |
66 | androidTestImplementation(libs.androidx.test.runner)
67 | testImplementation(libs.androidx.test.runner)
68 |
69 | androidTestImplementation(libs.androidx.window.testing)
70 | testImplementation(libs.androidx.window.testing)
71 |
72 | testImplementation(libs.robolectric)
73 | }
74 |
--------------------------------------------------------------------------------
/adaptive/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=accompanist-adaptive
2 | POM_NAME=Accompanist Adaptive library
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/adaptive/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/adaptive/src/main/java/com/google/accompanist/adaptive/DisplayFeatures.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.adaptive
18 |
19 | import android.app.Activity
20 | import androidx.compose.runtime.Composable
21 | import androidx.compose.runtime.getValue
22 | import androidx.compose.runtime.produceState
23 | import androidx.compose.runtime.remember
24 | import androidx.window.layout.DisplayFeature
25 | import androidx.window.layout.WindowInfoTracker
26 |
27 | /**
28 | * Calculates the list of [DisplayFeature]s from the given [activity].
29 | */
30 | @Composable
31 | public fun calculateDisplayFeatures(activity: Activity): List {
32 | val windowLayoutInfo = remember(activity) {
33 | WindowInfoTracker.getOrCreate(activity).windowLayoutInfo(activity)
34 | }
35 | val displayFeatures by produceState(
36 | initialValue = emptyList(),
37 | key1 = windowLayoutInfo
38 | ) {
39 | windowLayoutInfo.collect { info ->
40 | value = info.displayFeatures
41 | }
42 | }
43 |
44 | return displayFeatures
45 | }
46 |
--------------------------------------------------------------------------------
/adaptive/src/sharedTest/kotlin/com/google/accompanist/adaptive/DisplayFeaturesTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.adaptive
18 |
19 | import androidx.activity.ComponentActivity
20 | import androidx.compose.ui.test.junit4.createAndroidComposeRule
21 | import androidx.test.ext.junit.runners.AndroidJUnit4
22 | import androidx.window.layout.DisplayFeature
23 | import androidx.window.layout.FoldingFeature
24 | import androidx.window.layout.WindowLayoutInfo
25 | import androidx.window.testing.layout.FoldingFeature
26 | import androidx.window.testing.layout.WindowLayoutInfoPublisherRule
27 | import com.google.common.truth.Truth.assertThat
28 | import org.junit.Rule
29 | import org.junit.Test
30 | import org.junit.runner.RunWith
31 |
32 | @RunWith(AndroidJUnit4::class)
33 | class DisplayFeaturesTest {
34 |
35 | @get:Rule
36 | val composeTestRule = createAndroidComposeRule()
37 |
38 | @get:Rule
39 | val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()
40 |
41 | @Test
42 | fun empty_folding_features_is_correct() {
43 | lateinit var displayFeatures: List
44 |
45 | composeTestRule.setContent {
46 | displayFeatures = calculateDisplayFeatures(activity = composeTestRule.activity)
47 | }
48 |
49 | windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(WindowLayoutInfo(emptyList()))
50 |
51 | composeTestRule.waitForIdle()
52 |
53 | assertThat(displayFeatures).isEmpty()
54 | }
55 |
56 | @Test
57 | fun single_folding_features_is_correct() {
58 | lateinit var displayFeatures: List
59 |
60 | composeTestRule.setContent {
61 | displayFeatures = calculateDisplayFeatures(activity = composeTestRule.activity)
62 | }
63 |
64 | val fakeFoldingFeature = FoldingFeature(
65 | activity = composeTestRule.activity,
66 | center = 200,
67 | size = 40,
68 | state = FoldingFeature.State.HALF_OPENED,
69 | orientation = FoldingFeature.Orientation.VERTICAL,
70 | )
71 |
72 | windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(
73 | WindowLayoutInfo(
74 | listOf(
75 | fakeFoldingFeature
76 | )
77 | )
78 | )
79 |
80 | composeTestRule.waitForIdle()
81 |
82 | assertThat(displayFeatures).hasSize(1)
83 | assertThat(displayFeatures[0]).isEqualTo(fakeFoldingFeature)
84 | }
85 |
86 | @Test
87 | fun updating_folding_features_is_correct() {
88 | lateinit var displayFeatures: List
89 |
90 | composeTestRule.setContent {
91 | displayFeatures = calculateDisplayFeatures(activity = composeTestRule.activity)
92 | }
93 |
94 | windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(WindowLayoutInfo(emptyList()))
95 |
96 | val fakeFoldingFeature = FoldingFeature(
97 | activity = composeTestRule.activity,
98 | center = 200,
99 | size = 40,
100 | state = FoldingFeature.State.HALF_OPENED,
101 | orientation = FoldingFeature.Orientation.VERTICAL,
102 | )
103 |
104 | windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(
105 | WindowLayoutInfo(
106 | listOf(
107 | fakeFoldingFeature
108 | )
109 | )
110 | )
111 |
112 | composeTestRule.waitForIdle()
113 |
114 | assertThat(displayFeatures).hasSize(1)
115 | assertThat(displayFeatures[0]).isEqualTo(fakeFoldingFeature)
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/adaptive/src/test/resources/robolectric.properties:
--------------------------------------------------------------------------------
1 | # Pin SDK to 30 since Robolectric does not currently support API 31:
2 | # https://github.com/robolectric/robolectric/issues/6635
3 | sdk=30
4 |
--------------------------------------------------------------------------------
/build-logic/convention/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
18 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
19 |
20 | plugins {
21 | `kotlin-dsl`
22 | }
23 |
24 | group = "com.google.accompanist.buildlogic"
25 |
26 | java {
27 | sourceCompatibility = JavaVersion.VERSION_17
28 | targetCompatibility = JavaVersion.VERSION_17
29 | }
30 |
31 | kotlin {
32 | compilerOptions {
33 | jvmTarget = JvmTarget.JVM_17
34 | }
35 | }
36 |
37 | dependencies {
38 | // used by BundleInsideHelper.kt
39 | implementation(libs.apacheAnt)
40 | implementation(libs.shadow)
41 |
42 | compileOnly(libs.android.gradlePlugin)
43 | compileOnly(libs.android.tools.common)
44 | compileOnly(libs.compose.gradlePlugin)
45 | compileOnly(libs.kotlin.gradlePlugin)
46 | compileOnly(libs.metalavaGradle)
47 | compileOnly(libs.gradleMavenPublishPlugin)
48 | implementation(libs.truth)
49 | }
50 |
51 | tasks {
52 | validatePlugins {
53 | enableStricterValidation = true
54 | failOnWarning = true
55 | }
56 | }
57 |
58 | gradlePlugin {
59 | plugins {
60 | register("androidLibrary") {
61 | id = "accompanist.android.library"
62 | implementationClass = "AndroidLibraryConventionPlugin"
63 | }
64 | register("androidLibraryCompose") {
65 | id = "accompanist.android.library.compose"
66 | implementationClass = "AndroidLibraryComposeConventionPlugin"
67 | }
68 | register("androidLint") {
69 | id = "accompanist.android.lint"
70 | implementationClass = "AndroidLintConventionPlugin"
71 | }
72 | register("androidLibraryPublished") {
73 | id = "accompanist.android.library.published"
74 | implementationClass = "AndroidLibraryPublishedConventionPlugin"
75 | }
76 | }
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryComposeConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 | import com.android.build.gradle.LibraryExtension
18 | import com.google.accompanist.configureAndroidCompose
19 | import org.gradle.api.Plugin
20 | import org.gradle.api.Project
21 | import org.gradle.kotlin.dsl.apply
22 | import org.gradle.kotlin.dsl.getByType
23 |
24 | class AndroidLibraryComposeConventionPlugin : Plugin {
25 | override fun apply(target: Project) {
26 | with(target) {
27 | apply(plugin = "com.android.library")
28 | apply(plugin = "org.jetbrains.kotlin.plugin.compose")
29 |
30 | val extension = extensions.getByType()
31 | configureAndroidCompose(extension)
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 | import com.android.build.gradle.LibraryExtension
18 | import com.google.accompanist.configureKotlinAndroid
19 | import org.gradle.api.Plugin
20 | import org.gradle.api.Project
21 | import org.gradle.kotlin.dsl.configure
22 | import org.gradle.kotlin.dsl.dependencies
23 | import org.gradle.kotlin.dsl.kotlin
24 |
25 | class AndroidLibraryConventionPlugin : Plugin {
26 | override fun apply(target: Project) {
27 | with(target) {
28 | with(pluginManager) {
29 | apply("com.android.library")
30 | apply("org.jetbrains.kotlin.android")
31 | }
32 |
33 | extensions.configure {
34 | configureKotlinAndroid(this)
35 | defaultConfig.targetSdk = 35
36 | defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
37 |
38 | buildFeatures.buildConfig = false
39 |
40 | testOptions.animationsDisabled = true
41 | // The resource prefix is derived from the module name,
42 | // so resources inside ":core:module1" must be prefixed with "core_module1_"
43 | resourcePrefix = path.split("""\W""".toRegex()).drop(1).distinct().joinToString(separator = "_").lowercase() + "_"
44 | }
45 |
46 | dependencies {
47 | add("androidTestImplementation", kotlin("test"))
48 | add("testImplementation", kotlin("test"))
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLibraryPublishedConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 | import me.tylerbwong.gradle.metalava.extension.MetalavaExtension
18 | import org.gradle.api.Plugin
19 | import org.gradle.api.Project
20 | import org.gradle.kotlin.dsl.apply
21 | import org.gradle.kotlin.dsl.configure
22 |
23 | class AndroidLibraryPublishedConventionPlugin : Plugin {
24 | override fun apply(target: Project) {
25 | with(target) {
26 | with(pluginManager) {
27 | apply(AndroidLintConventionPlugin::class)
28 |
29 | apply("me.tylerbwong.gradle.metalava")
30 | apply("org.jetbrains.dokka")
31 | apply("com.vanniktech.maven.publish")
32 | }
33 |
34 | extensions.configure {
35 | sourcePaths.setFrom("src/main")
36 | filename.set("api/current.api")
37 | reportLintsAsErrors.set(true)
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/AndroidLintConventionPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 | import com.android.build.api.dsl.ApplicationExtension
18 | import com.android.build.api.dsl.LibraryExtension
19 | import com.android.build.api.dsl.Lint
20 | import org.gradle.api.Plugin
21 | import org.gradle.api.Project
22 | import org.gradle.kotlin.dsl.configure
23 | import java.io.File
24 |
25 | class AndroidLintConventionPlugin : Plugin {
26 | override fun apply(target: Project) {
27 | with(target) {
28 | when {
29 | pluginManager.hasPlugin("com.android.application") ->
30 | configure { lint(Lint::configure) }
31 |
32 | pluginManager.hasPlugin("com.android.library") ->
33 | configure { lint(Lint::configure) }
34 |
35 | else -> {
36 | pluginManager.apply("com.android.lint")
37 | configure(Lint::configure)
38 | }
39 | }
40 | }
41 | }
42 | }
43 |
44 | private fun Lint.configure() {
45 | textReport = true
46 | textOutput = File("stdout")
47 | // We run a full lint analysis as build part in CI, so skip vital checks for assemble tasks
48 | checkReleaseBuilds = false
49 | disable += setOf("GradleOverrides")
50 | }
51 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/google/accompanist/AndroidCompose.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 com.google.accompanist
18 |
19 | import com.android.build.api.dsl.CommonExtension
20 | import org.gradle.api.Project
21 | import org.gradle.api.provider.Provider
22 | import org.gradle.kotlin.dsl.configure
23 | import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
24 |
25 | /**
26 | * Configure Compose-specific options
27 | */
28 | internal fun Project.configureAndroidCompose(
29 | commonExtension: CommonExtension<*, *, *, *, *, *>,
30 | ) {
31 | commonExtension.apply {
32 | buildFeatures {
33 | compose = true
34 | }
35 |
36 | testOptions {
37 | unitTests {
38 | // For Robolectric
39 | isIncludeAndroidResources = true
40 | }
41 | }
42 | }
43 |
44 | extensions.configure {
45 | fun Provider.onlyIfTrue() = flatMap { provider { it.takeIf(String::toBoolean) } }
46 | fun Provider<*>.relativeToRootProject(dir: String) = flatMap {
47 | rootProject.layout.buildDirectory.dir(projectDir.toRelativeString(rootDir))
48 | }.map { it.dir(dir) }
49 |
50 | project.providers.gradleProperty("enableComposeCompilerMetrics").onlyIfTrue()
51 | .relativeToRootProject("compose-metrics")
52 | .let(metricsDestination::set)
53 |
54 | project.providers.gradleProperty("enableComposeCompilerReports").onlyIfTrue()
55 | .relativeToRootProject("compose-reports")
56 | .let(reportsDestination::set)
57 |
58 | // We include source information to match how the main Compose libraries are shipped.
59 | // This allows accompanist to be displayed properly in the layout inspector and systrace
60 | includeSourceInformation.set(true)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/google/accompanist/KotlinAndroid.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 com.google.accompanist
18 |
19 | import com.android.build.api.dsl.CommonExtension
20 | import org.gradle.api.JavaVersion
21 | import org.gradle.api.Project
22 | import org.gradle.api.plugins.JavaPluginExtension
23 | import org.gradle.kotlin.dsl.assign
24 | import org.gradle.kotlin.dsl.configure
25 | import org.gradle.kotlin.dsl.dependencies
26 | import org.gradle.kotlin.dsl.provideDelegate
27 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
28 | import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
29 | import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
30 | import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
31 |
32 | /**
33 | * Configure base Kotlin with Android options
34 | */
35 | internal fun Project.configureKotlinAndroid(
36 | commonExtension: CommonExtension<*, *, *, *, *, *>,
37 | ) {
38 | commonExtension.apply {
39 | compileSdk = 35
40 |
41 | defaultConfig {
42 | minSdk = 21
43 | }
44 |
45 | compileOptions {
46 | sourceCompatibility = JavaVersion.VERSION_1_8
47 | targetCompatibility = JavaVersion.VERSION_1_8
48 | }
49 | }
50 |
51 | configureKotlin()
52 | }
53 |
54 | /**
55 | * Configure base Kotlin options
56 | */
57 | private inline fun Project.configureKotlin() = configure {
58 | // Treat all Kotlin warnings as errors (disabled by default)
59 | // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
60 | val warningsAsErrors: String? by project
61 | when (this) {
62 | is KotlinAndroidProjectExtension -> compilerOptions
63 | is KotlinJvmProjectExtension -> compilerOptions
64 | else -> TODO("Unsupported project extension $this ${T::class}")
65 | }.apply {
66 | jvmTarget = JvmTarget.JVM_1_8
67 | allWarningsAsErrors = warningsAsErrors.toBoolean()
68 | explicitApi()
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/kotlin/com/google/accompanist/ProjectExtensions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 com.google.accompanist
18 |
19 | import org.gradle.api.Project
20 | import org.gradle.api.artifacts.VersionCatalog
21 | import org.gradle.api.artifacts.VersionCatalogsExtension
22 | import org.gradle.kotlin.dsl.getByType
23 |
24 | val Project.libs
25 | get(): VersionCatalog = extensions.getByType().named("libs")
--------------------------------------------------------------------------------
/build-logic/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534
2 | org.gradle.parallel=true
3 | org.gradle.caching=true
4 | org.gradle.configureondemand=true
5 |
6 |
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 | dependencyResolutionManagement {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | gradlePluginPortal()
22 | }
23 | versionCatalogs {
24 | create("libs") {
25 | from(files("../gradle/libs.versions.toml"))
26 | }
27 | }
28 | }
29 |
30 | rootProject.name = "build-logic"
31 | include(":convention")
32 |
--------------------------------------------------------------------------------
/checksum.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2021 The Android Open Source Project
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | RESULT_FILE=$1
18 |
19 | if [ -f $RESULT_FILE ]; then
20 | rm $RESULT_FILE
21 | fi
22 | touch $RESULT_FILE
23 |
24 | checksum_file() {
25 | echo $(openssl md5 $1 | awk '{print $2}')
26 | }
27 |
28 | FILES=()
29 | while read -r -d ''; do
30 | FILES+=("$REPLY")
31 | done < <(find . -type f \( -name "build.gradle*" -o -name "*.versions.toml" -o -name "gradle-wrapper.properties" \) -print0)
32 |
33 | # Loop through files and append MD5 to result file
34 | for FILE in ${FILES[@]}; do
35 | echo $(checksum_file $FILE) >> $RESULT_FILE
36 | done
37 | # Now sort the file so that it is idempotent
38 | sort $RESULT_FILE -o $RESULT_FILE
39 |
--------------------------------------------------------------------------------
/docs/adaptive.md:
--------------------------------------------------------------------------------
1 | # Adaptive utilities for Jetpack Compose
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | A library providing a collection of utilities for adaptive layouts.
6 |
7 | ## calculateDisplayFeatures
8 |
9 | [`calculateDisplayFeatures(activity)`](../api/adaptive/com.google.accompanist.adaptive/calculate-display-features.html) returns the current list of `DisplayFeature`s,
10 | as reported by the [Jetpack WindowManager library](https://developer.android.com/jetpack/androidx/releases/window).
11 |
12 | These contain the list of folds (if any), and can be used to drive components like [`TwoPane`](#TwoPane).
13 |
14 | ## TwoPane
15 |
16 | [`TwoPane`](../api/adaptive/com.google.accompanist.adaptive/-two-pane.html) is a UI component that positions exactly two slots on the screen.
17 |
18 | The default positioning of these two slots is driven by a [`TwoPaneStrategy`](../api/adaptive/com.google.accompanist.adaptive/-two-pane-strategy.html),
19 | which can decide to orient the two slots side-by-side horizontally or vertically, and also configure the gap between them.
20 |
21 | The built-in [`HorizontalTwoPaneStrategy`](../api/adaptive/com.google.accompanist.adaptive/-horizontal-two-pane-strategy.html) and
22 | [`VerticalTwoPaneStrategy`](../api/adaptive/com.google.accompanist.adaptive/-vertical-two-pane-strategy.html) allow positioning the
23 | slots based on a fixed offset, or as some fraction of the space.
24 |
25 | [`TwoPane`](../api/adaptive/com.google.accompanist.adaptive/-two-pane.html) also requires a list of display features (to be retrieved with [`calculateDisplayFeatures`](#calculateDisplayFeatures)),
26 | and optionally a [`FoldAwareConfiguration`](../api/adaptive/com.google.accompanist.adaptive/-fold-aware-configuration.html) to determine which folds to handle automatically.
27 |
28 | When there is a fold that intersects with the [`TwoPane`](../api/adaptive/com.google.accompanist.adaptive/-two-pane.html) component that is obscuring or separating,
29 | the [`TwoPane`](../api/adaptive/com.google.accompanist.adaptive/-two-pane.html) will automatically place the slots to avoid the fold.
30 |
31 | When there is no fold, the default supplied strategy will be used instead.
32 |
33 | ## FoldAwareColumn
34 |
35 | [`FoldAwareColumn`](../api/adaptive/com.google.accompanist.adaptive/-fold-aware-column.html) is a simplified version of [Column](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/package-summary#Column(androidx.compose.ui.Modifier,androidx.compose.foundation.layout.Arrangement.Vertical,androidx.compose.ui.Alignment.Horizontal,kotlin.Function1)) that places children in a fold-aware manner.
36 |
37 | [`FoldAwareColumn`](../api/adaptive/com.google.accompanist.adaptive/-fold-aware-column.html) requires a list of display features (to be retrieved with [`calculateDisplayFeatures`](#calculatedisplayfeatures)) to determine which folds to handle automatically.
38 |
39 | The built-in `foldPadding` parameter is zero, and the values of the vertical padding are used in the layout determine how much space should be left around a fold when placing children.
40 |
41 | When there is a horizontal fold that is obscuring or separating, the layout will begin placing children from the top of the available space. If a child is projected to overlap the fold, then its y-coordinate is increased so it will be placed fully below the fold, as will any other remaining children.
42 |
43 | When there is no fold, the children will be placed consecutively with no y-coordinate adjustments.
44 |
45 | Optionally, children can be modified with the `ignoreFold()` attribute, which means that they will be placed as if no fold is present even if they overlap a fold.
46 |
47 | ## Download
48 |
49 | [](https://search.maven.org/search?q=g:com.google.accompanist)
50 |
51 | ```groovy
52 | repositories {
53 | mavenCentral()
54 | }
55 |
56 | dependencies {
57 | implementation "com.google.accompanist:accompanist-adaptive:"
58 | }
59 | ```
--------------------------------------------------------------------------------
/docs/drawablepainter.md:
--------------------------------------------------------------------------------
1 | # Drawable Painter
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | A library which provides a way to use Android [drawables](https://developer.android.com/guide/topics/resources/drawable-resource) as Jetpack Compose [Painters](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/painter/Painter).
6 |
7 | This library attempts to support most Drawable configuration, as well as [Animatable](https://developer.android.com/reference/android/graphics/drawable/Animatable) drawables, such as [AnimatedVectorDrawable](https://developer.android.com/reference/android/graphics/drawable/AnimatedVectorDrawable).
8 |
9 | ## Usage
10 |
11 | ``` kotlin
12 | @Composable
13 | fun DrawDrawable() {
14 | val drawable = AppCompatResources.getDrawable(LocalContext.current, R.drawable.rectangle)
15 |
16 | Image(
17 | painter = rememberDrawablePainter(drawable = drawable),
18 | contentDescription = "content description",
19 | )
20 | }
21 | ```
22 |
23 | ## Download
24 |
25 | [](https://search.maven.org/search?q=g:com.google.accompanist)
26 |
27 | ```groovy
28 | repositories {
29 | mavenCentral()
30 | }
31 |
32 | dependencies {
33 | implementation "com.google.accompanist:accompanist-drawablepainter:"
34 | }
35 | ```
36 |
37 | Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
38 |
39 | [compose]: https://developer.android.com/jetpack/compose
40 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-drawablepainter/
41 |
--------------------------------------------------------------------------------
/docs/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/header.png
--------------------------------------------------------------------------------
/docs/insets/images/edge-to-edge-list.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/insets/images/edge-to-edge-list.jpg
--------------------------------------------------------------------------------
/docs/insets/images/ime-insets.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/insets/images/ime-insets.gif
--------------------------------------------------------------------------------
/docs/insets/images/ime-scroll.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/insets/images/ime-scroll.gif
--------------------------------------------------------------------------------
/docs/migration.md:
--------------------------------------------------------------------------------
1 | # Migration from dev.chrisbanes.accompanist
2 |
3 | In March 2021, the Accompanist project moved from [github.com/chrisbanes/accompanist](https://github.com/chrisbanes/accompanist) to [github.com/google/accompanist](https://github.com/google/accompanist). At the same time we migrated the libraries over to a new package name and Maven group ID.
4 |
5 | As a summary:
6 |
7 | - All code was refactored from the `dev.chrisbanes.accompanist` root package to `com.google.accompanist` package.
8 | - The Maven group ID was changed from `dev.chrisbanes.accompanist` to `com.google.accompanist`.
9 |
10 | ## Semi-automatic migration...
11 |
12 | The following methods below are available for your information only, but may help if you need to migrate from the old package name.
13 |
14 | !!! warning
15 | Use these at your own risk, but they have worked on multiple projects from my testing. It's a good idea to make sure that you've made a backup or committed any changes before running these.
16 |
17 | ### Android Studio / IntelliJ
18 |
19 | You can use the [Replace in Path](https://www.jetbrains.com/help/idea/finding-and-replacing-text-in-project.html#replace_search_string_in_project) pane (⇧⌘R on Mac) in Android Studio to do a project-wide search and replace.
20 |
21 | 
22 |
23 | - Find query: `dev.chrisbanes.accompanist`
24 | - Replace string: `com.google.accompanist`
25 | - _Optional:_ Set the file mask to `*.kt` so that only Kotlin files are searched. Repeat for `*.gradle`.
26 |
27 | Similar can be achieved in [Visual Studio Code](https://code.visualstudio.com/docs/editor/codebasics#_search-across-files). Other IDEs / text editors are available.
28 |
29 | ### YOLO commands
30 |
31 | These commands while automatically replace any imports and Gradle dependencies for the project in the current directory.
32 |
33 | #### MacOS
34 |
35 | ``` bash
36 | find . -type f \( -name '*.kt' -or -name '*.gradle*' \) \
37 | -exec sed -i '' 's/dev\.chrisbanes\.accompanist/com\.google\.accompanist/' {} \;
38 | ```
39 |
40 | #### Linux
41 |
42 | ``` bash
43 | find . -type f \( -name '*.kt' -or -name '*.gradle*' \) \
44 | -exec sed -i 's/dev\.chrisbanes\.accompanist/com\.google\.accompanist/' {} \;
45 | ```
46 |
--------------------------------------------------------------------------------
/docs/migration/studio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/migration/studio.png
--------------------------------------------------------------------------------
/docs/permissions.md:
--------------------------------------------------------------------------------
1 | # Jetpack Compose Permissions
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | A library which provides [Android runtime permissions](https://developer.android.com/guide/topics/permissions/overview) support for Jetpack Compose.
6 |
7 | !!! warning
8 | The permission APIs are currently experimental and they could change at any time.
9 | All of the APIs are marked with the `@ExperimentalPermissionsApi` annotation.
10 |
11 | ## Usage
12 |
13 | ### `rememberPermissionState` and `rememberMultiplePermissionsState` APIs
14 |
15 | The `rememberPermissionState(permission: String)` API allows you to request a certain permission
16 | to the user and check for the status of the permission.
17 | `rememberMultiplePermissionsState(permissions: List)` offers the same but for multiple
18 | permissions at the same time.
19 |
20 | Both APIs expose properties for you to follow the workflow as described in the
21 | [permissions documentation](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
22 |
23 | !!! caution
24 | The call to the method that requests the permission to the user (e.g. `PermissionState.launchPermissionRequest()`)
25 | needs to be invoked from a non-composable scope. For example, from a side-effect or from a
26 | non-composable callback such as a `Button`'s `onClick` lambda.
27 |
28 | The following code exercises the [permission request workflow](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
29 |
30 | ```kotlin
31 | @OptIn(ExperimentalPermissionsApi::class)
32 | @Composable
33 | private fun FeatureThatRequiresCameraPermission() {
34 |
35 | // Camera permission state
36 | val cameraPermissionState = rememberPermissionState(
37 | android.Manifest.permission.CAMERA
38 | )
39 |
40 | if (cameraPermissionState.status.isGranted) {
41 | Text("Camera permission Granted")
42 | } else {
43 | Column {
44 | val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
45 | // If the user has denied the permission but the rationale can be shown,
46 | // then gently explain why the app requires this permission
47 | "The camera is important for this app. Please grant the permission."
48 | } else {
49 | // If it's the first time the user lands on this feature, or the user
50 | // doesn't want to be asked again for this permission, explain that the
51 | // permission is required
52 | "Camera permission required for this feature to be available. " +
53 | "Please grant the permission"
54 | }
55 | Text(textToShow)
56 | Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
57 | Text("Request permission")
58 | }
59 | }
60 | }
61 | }
62 | ```
63 |
64 | For more examples, refer to the [samples](https://github.com/google/accompanist/tree/main/sample/src/main/java/com/google/accompanist/sample/permissions).
65 |
66 | ## Limitations
67 |
68 | This permissions wrapper is built on top of the available Android platform APIs. We cannot extend
69 | the platform's capabilities. For example, it's not possible to differentiate between the
70 | _it's the first time requesting the permission_ vs _the user doesn't want to be asked again_
71 | use cases.
72 |
73 | ## Download
74 |
75 | [](https://search.maven.org/search?q=g:com.google.accompanist)
76 |
77 | ```groovy
78 | repositories {
79 | mavenCentral()
80 | }
81 |
82 | dependencies {
83 | implementation "com.google.accompanist:accompanist-permissions:"
84 | }
85 | ```
86 |
87 | Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
88 |
89 | [compose]: https://developer.android.com/jetpack/compose
90 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-permissions/
91 |
--------------------------------------------------------------------------------
/docs/swiperefresh/demo.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/swiperefresh/demo.mp4
--------------------------------------------------------------------------------
/docs/swiperefresh/tweaked.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/swiperefresh/tweaked.mp4
--------------------------------------------------------------------------------
/docs/systemuicontroller.md:
--------------------------------------------------------------------------------
1 | # System UI Controller for Jetpack Compose
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | !!! warning
6 | **This library is deprecated, and the API is no longer maintained. We recommend forking the implementation and customising it to your needs.** The original documentation is below.
7 |
8 | ## Migration
9 | Recommendation: If you were using SystemUIController to go edge-to-edge in your activity and change the system bar colors and system bar icon colors, use the new [Activity.enableEdgeToEdge](https://developer.android.com/reference/androidx/activity/ComponentActivity#(androidx.activity.ComponentActivity).enableEdgeToEdge(androidx.activity.SystemBarStyle,androidx.activity.SystemBarStyle)) method available in androidx.activity 1.8.0-alpha03 and later. This method backports the scrims used on some versions of Android. [This](https://github.com/android/nowinandroid/pull/817) is a sample PR of the migration to the new method and removing the dependency on SystemUIController in Now in Android.
10 |
11 | For other usages, migrate to using WindowInsetsControllerCompat or window APIs directly.
12 |
13 | ## Original Documentation
14 | System UI Controller provides easy-to-use utilities for updating the System UI bar colors within Jetpack Compose.
15 |
16 | ## Usage
17 | To control the system UI in your composables, you need to get a [`SystemUiController`](../api/systemuicontroller/systemuicontroller/com.google.accompanist.systemuicontroller/-system-ui-controller/) instance. The library provides the [`rememberSystemUiController()`](../api/systemuicontroller/systemuicontroller/com.google.accompanist.systemuicontroller/remember-system-ui-controller.html) function which returns an instance for the current system (currently only Android).
18 |
19 | In your layouts you can update the system bar colors like so:
20 |
21 | ``` kotlin
22 | // Remember a SystemUiController
23 | val systemUiController = rememberSystemUiController()
24 | val useDarkIcons = !isSystemInDarkTheme()
25 |
26 | DisposableEffect(systemUiController, useDarkIcons) {
27 | // Update all of the system bar colors to be transparent, and use
28 | // dark icons if we're in light theme
29 | systemUiController.setSystemBarsColor(
30 | color = Color.Transparent,
31 | darkIcons = useDarkIcons
32 | )
33 |
34 | // setStatusBarColor() and setNavigationBarColor() also exist
35 |
36 | onDispose {}
37 | }
38 | ```
39 |
40 | ## System bar icon colors
41 | The library automatically handles API level differences when running on Android devices. If we look at the example
42 | of status bar icons, Android only natively supports dark icons on API 23+. This library handles this by automatically
43 | altering the requested color with a scrim, to maintain contrast:
44 |
45 | 
46 |
47 | Similar happens on navigation bar color, which is only available on API 26+.
48 |
49 | ### Modifying scrim logic
50 |
51 | The scrim logic can be modified if needed:
52 |
53 | ``` kotlin
54 | systemUiController.setStatusBarColor(
55 | color = Color.Transparent,
56 | darkIcons = true
57 | ) { requestedColor ->
58 | // TODO: return a darkened color to be used when the system doesn't
59 | // natively support dark icons
60 | }
61 | ```
62 |
63 | ## Samples
64 |
65 | For complete samples, check out the [Insets samples](https://github.com/google/accompanist/tree/main/sample/src/main/java/com/google/accompanist/sample/insets) which all use `SystemUiController` to set transparent system bars.
66 |
67 | ## Download
68 | [](https://search.maven.org/search?q=g:com.google.accompanist)
69 |
70 | ```groovy
71 | repositories {
72 | mavenCentral()
73 | }
74 |
75 | dependencies {
76 | implementation "com.google.accompanist:accompanist-systemuicontroller:"
77 | }
78 | ```
79 |
80 | Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
81 |
82 | [compose]: https://developer.android.com/jetpack/compose
83 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-systemuicontroller/
84 |
--------------------------------------------------------------------------------
/docs/systemuicontroller/api-scrim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/systemuicontroller/api-scrim.png
--------------------------------------------------------------------------------
/docs/themeadapter/material-header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/themeadapter/material-header.png
--------------------------------------------------------------------------------
/docs/themeadapter/material3-header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/docs/themeadapter/material3-header.png
--------------------------------------------------------------------------------
/docs/updating.md:
--------------------------------------------------------------------------------
1 | # Updating & releasing Accompanist
2 |
3 | This doc is mostly for maintainers.
4 |
5 | ## New features & bugfixes
6 | All new features should be uploaded as PRs against the `main` branch.
7 |
8 | Once merged into `main`, they will be automatically merged into the `snapshot` branch.
9 |
10 | ## Jetpack Compose Snapshots
11 |
12 | We publish snapshot versions of Accompanist, which depend on a `SNAPSHOT` versions of Jetpack Compose. These are built from the `snapshot` branch.
13 |
14 | ### Updating to a newer Compose snapshot
15 |
16 | As mentioned above, updating to a new Compose snapshot is done by submitting a new PR against the `snapshot` branch:
17 |
18 | ``` sh
19 | git checkout snapshot && git pull
20 | # Create branch for PR
21 | git checkout -b update_snapshot
22 | ```
23 |
24 | Now edit the project to depend on the new Compose SNAPSHOT version:
25 |
26 | Edit [`/gradle/libs.versions.toml`](https://github.com/google/accompanist/blob/main/gradle/libs.versions.toml):
27 |
28 | Under `[versions]`:
29 |
30 | 1. Update the `composesnapshot` property to be the snapshot number
31 | 2. Ensure that the `compose` property is correct
32 |
33 | Make sure the project builds and test pass:
34 | ```
35 | ./gradlew check
36 | ```
37 |
38 | Now `git commit` the changes and push to GitHub.
39 |
40 | Finally create a PR (with the base branch as `snapshot`) and send for review.
41 |
42 | ## Releasing
43 |
44 | Once the next Jetpack Compose version is out, we're ready to push a new release:
45 |
46 | ### #1: Merge `snapshot` into `main`
47 |
48 | First we merge the `snapshot` branch into `main`:
49 |
50 | ``` sh
51 | git checkout snapshot && git pull
52 | git checkout main && git pull
53 |
54 | # Create branch for PR
55 | git checkout -b main_snapshot_merge
56 |
57 | # Merge in the snapshot branch
58 | git merge snapshot
59 | ```
60 |
61 | ### #2: Update dependencies
62 |
63 | Edit [`/gradle/libs.versions.toml`](https://github.com/google/accompanist/blob/main/gradle/libs.versions.toml):
64 |
65 | Under `[versions]`:
66 |
67 | 1. Update the `composesnapshot` property to a single character (usually `-`). This disables the snapshot repository.
68 | 2. Update the `compose` property to match the new release (i.e. `1.0.0-beta06`)
69 |
70 | Make sure the project builds and test pass:
71 | ```
72 | ./gradlew check
73 | ```
74 |
75 | Commit the changes.
76 |
77 | ### #3: Bump the version number
78 |
79 | Edit [gradle.properties](https://github.com/google/accompanist/blob/main/gradle.properties):
80 |
81 | * Update the `VERSION_NAME` property and remove the `-SNAPSHOT` suffix.
82 |
83 | Commit the changes, using the commit message containing the new version name.
84 |
85 | ### #4: Push to GitHub
86 |
87 | Push the branch to GitHub and create a PR against the `main` branch, and send for review. Once approved and merged, it will be automatically deployed to Maven Central.
88 |
89 | ### #5: Create release
90 |
91 | Once the above PR has been approved and merged, we need to create the GitHub release:
92 |
93 | * Open up the [Releases](https://github.com/google/accompanist/releases) page.
94 | * At the top you should see a 'Draft' release, auto populated with any PRs since the last release. Click 'Edit'.
95 | * Make sure that the version number matches what we released (the tool guesses but is not always correct).
96 | * Double check everything, then press 'Publish release'.
97 |
98 | At this point the release is published. This will trigger the docs action to run, which will auto-deploy a new version of the [website](https://google.github.io/accompanist/).
99 |
100 | ### #6: Prepare the next development version
101 |
102 | The current release is now finished, but we need to update the version for the next development version:
103 |
104 | Edit [gradle.properties](https://github.com/google/accompanist/blob/main/gradle.properties):
105 |
106 | * Update the `VERSION_NAME` property, by increasing the version number, and adding the `-SNAPSHOT` suffix.
107 | * Example: released version: `0.3.0`. Update to `0.3.1-SNAPSHOT`
108 |
109 | `git commit` and push to `main`.
110 |
111 | Finally, merge all of these changes back to `snapshot`:
112 |
113 | ```
114 | git checkout snapshot && git pull
115 | git merge main
116 | git push
117 | ```
--------------------------------------------------------------------------------
/docs/using-snapshot-version.md:
--------------------------------------------------------------------------------
1 | # Using a Snapshot Version of the Library
2 |
3 | If you would like to depend on the cutting edge version of the Accompanist
4 | library, you can use the [snapshot versions][snap] that are published to
5 | [Sonatype OSSRH](https://central.sonatype.org/)'s snapshot repository. These are updated on every commit to `main`.
6 |
7 | To do so:
8 |
9 | ```groovy
10 | repositories {
11 | // ...
12 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
13 | }
14 |
15 | dependencies {
16 | // Check the latest SNAPSHOT version from the link above
17 | classpath 'com.google.accompanist:accompanist-coil:XXX-SNAPSHOT'
18 | }
19 | ```
20 |
21 | You might see a number of different versioned snapshots. If we use an example:
22 |
23 | * `0.3.0-SNAPSHOT` is a build from the `main` branch, and depends on the latest tagged Jetpack Compose release (i.e. [alpha03](https://developer.android.com/jetpack/androidx/releases/compose#1.0.0-alpha03)).
24 | * `0.3.0.compose-6574163-SNAPSHOT` is a build from the `snapshot` branch. This depends on the [SNAPSHOT build](https://androidx.dev) of Jetpack Compose from build `6574163`. You should only use these if you are using Jetpack Compose snapshot versions (see below).
25 |
26 | ### Using Jetpack Compose Snapshots
27 |
28 | If you're using [`SNAPSHOT`](https://androidx.dev) versions of the `androidx.compose` libraries, you might run into issues with the current stable Accompanist release forcing an older version of those libraries.
29 |
30 | We publish snapshot versions of Accompanist which depend on recent Jetpack Compose SNAPSHOT repositories. To find a recent build, look through the [snapshot repository][snap] for any versions in the scheme `x.x.x.compose-YYYY-SNAPSHOT` (for example: `0.3.0.compose-6574163-SNAPSHOT`). The `YYYY` in the scheme is the snapshot build being used from [AndroidX](https://androidx.dev) (from the example: build [`6574163`](https://androidx.dev/snapshots/builds/6574163/artifacts)). You can then use it like so:
31 |
32 |
33 | ``` groovy
34 | repositories {
35 | // ...
36 | maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
37 | }
38 |
39 | dependencies {
40 | // Check the latest SNAPSHOT version from the link above
41 | classpath 'com.google.accompanist:accompanist-coil:XXXX.compose-YYYYY-SNAPSHOT'
42 | }
43 | ```
44 |
45 | These builds are updated regularly, but there's no guarantee that we will create one for a given snapshot number.
46 |
47 | *Note:* you might also see versions in the scheme `x.x.x.ui-YYYY-SNAPSHOT`. These are the same, just using an older suffix.
48 |
49 |
50 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/
--------------------------------------------------------------------------------
/docs/web.md:
--------------------------------------------------------------------------------
1 | # WebView wrapper for Jetpack Compose
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | A library which provides a Jetpack Compose wrapper around Android's WebView.
6 |
7 | !!! warning
8 | **This library is deprecated, and the API is no longer maintained. We recommend forking the implementation and customising it to your needs.** The original documentation is below.
9 |
10 | ## Usage
11 |
12 | To implement this wrapper there are two key APIs which are needed: [`WebView`](../api/web/com.google.accompanist.web/-web-view.html), which is provides the layout, and [`rememberWebViewState(url)`](../api/web/com.google.accompanist.web/remember-web-view-state.html) which provides some remembered state including the URL to display.
13 |
14 | The basic usage is as follows:
15 |
16 | ```kotlin
17 | val state = rememberWebViewState("https://example.com")
18 |
19 | WebView(
20 | state
21 | )
22 | ```
23 |
24 | This will display a WebView in your Compose layout that shows the URL provided.
25 |
26 | There is a larger sample in the sample app which can be found [here](https://github.com/google/accompanist/blob/main/sample/src/main/java/com/google/accompanist/sample/webview/BasicWebViewSample.kt). This sample also shows how to show a loading state.
27 |
28 | ### WebView settings including JavaScript
29 |
30 | By default, JavaScript is disabled in the WebView. To enable it or any other settings you can use the `onCreated` callback.
31 |
32 | ```kotlin
33 | WebView(
34 | state = webViewState,
35 | onCreated = { it.settings.javaScriptEnabled = true }
36 | )
37 | ```
38 |
39 | ### Capturing back presses
40 |
41 | By default the WebView will capture back presses/swipes when relevant and navigate the WebView back. This can be disabled via the parameter on
42 | the Composable.
43 |
44 | ```kotlin
45 | WebView(
46 | ...
47 | captureBackPresses = false
48 | )
49 | ```
50 |
51 | ### Using a subclass of WebView
52 |
53 | If you want to use a subclass of `WebView`, or simply require more control over its instantiation, you can provide a factory.
54 |
55 | ```kotlin
56 | WebView(
57 | ...
58 | factory = { context -> CustomWebView(context) }
59 | )
60 | ```
61 |
62 | ## Download
63 |
64 | [](https://search.maven.org/search?q=g:com.google.accompanist)
65 |
66 | ```groovy
67 | repositories {
68 | mavenCentral()
69 | }
70 |
71 | dependencies {
72 | implementation "com.google.accompanist:accompanist-webview:"
73 | }
74 | ```
75 |
--------------------------------------------------------------------------------
/drawablepainter/README.md:
--------------------------------------------------------------------------------
1 | # Accompanist Drawable Painter
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | For more information, visit the documentation: https://google.github.io/accompanist/drawablepainter
6 |
7 | ## Download
8 |
9 | ```groovy
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | implementation "com.google.accompanist:accompanist-drawablepainter:"
16 | }
17 | ```
18 |
--------------------------------------------------------------------------------
/drawablepainter/api/current.api:
--------------------------------------------------------------------------------
1 | // Signature format: 4.0
2 | package com.google.accompanist.drawablepainter {
3 |
4 | public final class DrawablePainter extends androidx.compose.ui.graphics.painter.Painter implements androidx.compose.runtime.RememberObserver {
5 | ctor public DrawablePainter(android.graphics.drawable.Drawable drawable);
6 | method public android.graphics.drawable.Drawable getDrawable();
7 | method public long getIntrinsicSize();
8 | method public void onAbandoned();
9 | method protected void onDraw(androidx.compose.ui.graphics.drawscope.DrawScope);
10 | method public void onForgotten();
11 | method public void onRemembered();
12 | property public final android.graphics.drawable.Drawable drawable;
13 | property public long intrinsicSize;
14 | }
15 |
16 | public final class DrawablePainterKt {
17 | method @androidx.compose.runtime.Composable public static androidx.compose.ui.graphics.painter.Painter rememberDrawablePainter(android.graphics.drawable.Drawable? drawable);
18 | }
19 |
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/drawablepainter/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | @file:Suppress("UnstableApiUsage")
17 |
18 | plugins {
19 | alias(libs.plugins.accompanist.android.library)
20 | alias(libs.plugins.accompanist.android.library.compose)
21 | alias(libs.plugins.accompanist.android.library.published)
22 | }
23 |
24 | android {
25 | namespace = "com.google.accompanist.drawablepainter"
26 | }
27 |
28 | dependencies {
29 | implementation(libs.compose.ui.ui)
30 | implementation(libs.kotlin.coroutines.android)
31 | }
32 |
--------------------------------------------------------------------------------
/drawablepainter/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=accompanist-drawablepainter
2 | POM_NAME=Accompanist Drawable Painter library
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/drawablepainter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/generate_docs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2021 The Android Open Source Project
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | # Fail on any error
18 | set -ex
19 |
20 | DOCS_ROOT=docs-gen
21 |
22 | [ -d $DOCS_ROOT ] && rm -r $DOCS_ROOT
23 | mkdir $DOCS_ROOT
24 |
25 | # Clear out the old API docs
26 | [ -d docs/api ] && rm -r docs/api
27 | # Build the docs with dokka
28 | ./gradlew dokkaHtmlMultiModule --stacktrace
29 |
30 | # Create a copy of our docs at our $DOCS_ROOT
31 | cp -a docs/* $DOCS_ROOT
32 |
33 | cp README.md $DOCS_ROOT/index.md
34 | cp CONTRIBUTING.md $DOCS_ROOT/contributing.md
35 |
36 | sed -i.bak 's/CONTRIBUTING.md/contributing/' $DOCS_ROOT/index.md
37 | sed -i.bak 's/README.md//' $DOCS_ROOT/index.md
38 | sed -i.bak 's/docs\/header.png/header.png/' $DOCS_ROOT/index.md
39 |
40 | # Convert docs/xxx.md links to just xxx/
41 | sed -i.bak 's/docs\/\([a-zA-Z-]*\).md/\1/' $DOCS_ROOT/index.md
42 |
43 | # Finally delete all of the backup files
44 | find . -name '*.bak' -delete
45 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2020 The Android Open Source Project
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 | # https://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 | # Turn on parallel compilation, caching and on-demand configuration
18 | org.gradle.configureondemand=true
19 | org.gradle.caching=true
20 | org.gradle.parallel=true
21 |
22 | # Declare we support AndroidX
23 | android.useAndroidX=true
24 |
25 | # Increase memory
26 | org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=2048m -XX:+HeapDumpOnOutOfMemoryError
27 |
28 | # Required to publish to Nexus (see https://github.com/gradle/gradle/issues/11308)
29 | systemProp.org.gradle.internal.publish.checksums.insecure=true
30 |
31 | # Increase timeout when pushing to Sonatype (otherwise we get timeouts)
32 | systemProp.org.gradle.internal.http.socketTimeout=120000
33 |
34 | GROUP=com.google.accompanist
35 | # !! No longer need to update this manually when using a Compose SNAPSHOT
36 | VERSION_NAME=0.37.4-SNAPSHOT
37 |
38 | POM_DESCRIPTION=Utilities for Jetpack Compose
39 |
40 | POM_URL=https://github.com/google/accompanist/
41 | POM_SCM_URL=https://github.com/google/accompanist/
42 | POM_SCM_CONNECTION=scm:git:git://github.com/google/accompanist.git
43 | POM_SCM_DEV_CONNECTION=scm:git:git://github.com/google/accompanist.git
44 |
45 | POM_LICENCE_NAME=The Apache Software License, Version 2.0
46 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
47 | POM_LICENCE_DIST=repo
48 |
49 | POM_DEVELOPER_ID=google
50 | POM_DEVELOPER_NAME=Google
51 |
52 | SONATYPE_HOST=DEFAULT
53 | RELEASE_SIGNING_ENABLED=true
54 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jul 10 11:49:25 AEST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
5 | networkTimeout=10000
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | @rem This is normally unused
30 | set APP_BASE_NAME=%~n0
31 | set APP_HOME=%DIRNAME%
32 |
33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
35 |
36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
38 |
39 | @rem Find java.exe
40 | if defined JAVA_HOME goto findJavaFromJavaHome
41 |
42 | set JAVA_EXE=java.exe
43 | %JAVA_EXE% -version >NUL 2>&1
44 | if %ERRORLEVEL% equ 0 goto execute
45 |
46 | echo.
47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
48 | echo.
49 | echo Please set the JAVA_HOME variable in your environment to match the
50 | echo location of your Java installation.
51 |
52 | goto fail
53 |
54 | :findJavaFromJavaHome
55 | set JAVA_HOME=%JAVA_HOME:"=%
56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
57 |
58 | if exist "%JAVA_EXE%" goto execute
59 |
60 | echo.
61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
62 | echo.
63 | echo Please set the JAVA_HOME variable in your environment to match the
64 | echo location of your Java installation.
65 |
66 | goto fail
67 |
68 | :execute
69 | @rem Setup the command line
70 |
71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
72 |
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if %ERRORLEVEL% equ 0 goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | set EXIT_CODE=%ERRORLEVEL%
85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
87 | exit /b %EXIT_CODE%
88 |
89 | :mainEnd
90 | if "%OS%"=="Windows_NT" endlocal
91 |
92 | :omega
93 |
--------------------------------------------------------------------------------
/images/Social.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/images/Social.sketch
--------------------------------------------------------------------------------
/internal-testutils/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | @file:Suppress("UnstableApiUsage")
17 |
18 | plugins {
19 | alias(libs.plugins.accompanist.android.library)
20 | alias(libs.plugins.accompanist.android.library.compose)
21 | }
22 |
23 | android {
24 | namespace = "com.google.accompanist.internal.test"
25 | }
26 |
27 | dependencies {
28 | implementation(libs.kotlin.stdlib)
29 | implementation(libs.kotlin.coroutines.android)
30 |
31 | implementation(libs.compose.foundation.foundation)
32 | api(libs.compose.ui.test.junit4)
33 |
34 | api(libs.androidx.test.core)
35 | implementation(libs.truth)
36 | }
37 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/java/com/google/accompanist/internal/test/ActivityScenario.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.internal.test
18 |
19 | import android.app.Activity
20 | import androidx.test.core.app.ActivityScenario
21 |
22 | public fun ActivityScenario.withActivity(
23 | action: (A) -> T
24 | ): T {
25 | lateinit var result: T
26 | onActivity { result = action(it) }
27 | return result
28 | }
29 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/java/com/google/accompanist/internal/test/Assertions.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 The Android Open Source Project
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 | * https://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 com.google.accompanist.internal.test
18 |
19 | import androidx.compose.ui.graphics.Color
20 | import androidx.compose.ui.graphics.ImageBitmap
21 | import androidx.compose.ui.graphics.toPixelMap
22 | import androidx.compose.ui.test.SemanticsNodeInteraction
23 | import androidx.compose.ui.test.assertHeightIsAtLeast
24 | import androidx.compose.ui.test.assertWidthIsAtLeast
25 | import androidx.compose.ui.unit.Dp
26 | import com.google.common.truth.Truth.assertThat
27 |
28 | /**
29 | * Assert that all of the pixels in this image as of the [expected] color.
30 | */
31 | public fun ImageBitmap.assertPixels(expected: Color, tolerance: Float = 0.001f) {
32 | toPixelMap().buffer.forEach { pixel ->
33 | val color = Color(pixel)
34 | assertThat(color.red).isWithin(tolerance).of(expected.red)
35 | assertThat(color.green).isWithin(tolerance).of(expected.green)
36 | assertThat(color.blue).isWithin(tolerance).of(expected.blue)
37 | assertThat(color.alpha).isWithin(tolerance).of(expected.alpha)
38 | }
39 | }
40 |
41 | /**
42 | * Run the [SemanticsNodeInteraction] provided by [block] repeatedly until either
43 | * the assertion succeeds, or the execution runs past [timeoutMillis].
44 | */
45 | public fun SemanticsNodeInteraction.assertWithTimeout(
46 | timeoutMillis: Long,
47 | block: SemanticsNodeInteraction.() -> SemanticsNodeInteraction,
48 | ): SemanticsNodeInteraction {
49 | val startTime = System.nanoTime()
50 | while (System.nanoTime() - startTime <= timeoutMillis * 1_000_000) {
51 | try {
52 | return block()
53 | } catch (error: AssertionError) {
54 | // If the assertion failed, sleep for 10ms before the next loop iteration
55 | Thread.sleep(10)
56 | }
57 | }
58 | // If we reach here, each assertion has failed and we've reached the time out.
59 | // Run block one last time...
60 | return block()
61 | }
62 |
63 | public val SemanticsNodeInteraction.exists: Boolean
64 | get() = try {
65 | assertExists()
66 | true
67 | } catch (t: Throwable) {
68 | false
69 | }
70 |
71 | public val SemanticsNodeInteraction.isLaidOut: Boolean
72 | get() = try {
73 | assertWidthIsAtLeast(Dp.Hairline).assertHeightIsAtLeast(Dp.Hairline)
74 | true
75 | } catch (t: Throwable) {
76 | false
77 | }
78 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/java/com/google/accompanist/internal/test/IgnoreOnRobolectric.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.internal.test
18 |
19 | /**
20 | * Marker interface to use as a category for filtering out tests when running on Robolectric.
21 | */
22 | public interface IgnoreOnRobolectric
23 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/java/com/google/accompanist/internal/test/TestUtils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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:Suppress("NOTHING_TO_INLINE")
18 |
19 | package com.google.accompanist.internal.test
20 |
21 | public inline fun parameterizedParams(): List> = emptyList()
22 |
23 | public inline fun List>.combineWithParameters(
24 | vararg values: T
25 | ): List> {
26 | if (isEmpty()) {
27 | return values.map { arrayOf(it) }
28 | }
29 |
30 | return fold(emptyList()) { acc, args ->
31 | val result = acc.toMutableList()
32 | values.forEach { v ->
33 | result += ArrayList().apply {
34 | addAll(args)
35 | add(v)
36 | }.toTypedArray()
37 | }
38 | result.toList()
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/java/com/google/accompanist/internal/test/WaitUntil.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.internal.test
18 |
19 | import android.os.Looper
20 | import com.google.common.truth.Truth.assertThat
21 | import java.util.concurrent.TimeoutException
22 |
23 | public fun waitUntil(timeoutMillis: Long = 2_000, condition: () -> Boolean) {
24 | if (Looper.getMainLooper() == Looper.myLooper()) {
25 | assertThat(condition()).isTrue()
26 | }
27 |
28 | val startTime = System.nanoTime()
29 | while (!condition()) {
30 | // Let Android run measure, draw and in general any other async operations.
31 | Thread.sleep(10)
32 | if (System.nanoTime() - startTime > timeoutMillis * 1_000_000) {
33 | throw TimeoutException("Condition still not satisfied after $timeoutMillis ms")
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/internal-testutils/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | # Project information
2 | site_name: 'Accompanist'
3 | site_description: 'A group of libraries to help write Jetpack Compose apps.'
4 | site_author: 'Google'
5 | site_url: 'https://google.github.io/accompanist/'
6 | edit_uri: 'tree/main/docs/'
7 | remote_branch: gh-pages
8 |
9 | docs_dir: docs-gen
10 |
11 | # Repository
12 | repo_name: 'Accompanist'
13 | repo_url: 'https://github.com/google/accompanist'
14 |
15 | # Navigation
16 | nav:
17 | - 'Overview': index.md
18 | - 'System UI Controller':
19 | - 'Guide': systemuicontroller.md
20 | - 'API': api/systemuicontroller/
21 | - 'Drawable Painter':
22 | - 'Guide': drawablepainter.md
23 | - 'API': api/drawablepainter/
24 | - 'Permissions':
25 | - 'Guide': permissions.md
26 | - 'API': api/permissions/
27 | - 'Navigation Animation':
28 | - 'Guide': navigation-animation.md
29 | - 'API': api/navigation-animation/
30 | - 'Navigation Material':
31 | - 'Guide': navigation-material.md
32 | - 'API': api/navigation-material/
33 | - 'Adaptive':
34 | - 'Guide': adaptive.md
35 | - 'API': api/adaptive
36 | - 'Snapshots': using-snapshot-version.md
37 | - 'Contributing': contributing.md
38 | - 'Maintainers':
39 | - 'Update guide': updating.md
40 |
41 | # Configuration
42 | theme:
43 | name: 'material'
44 | language: 'en'
45 | icon:
46 | logo: material/music-clef-treble
47 | palette:
48 | primary: 'black'
49 | accent: 'deep orange'
50 | font:
51 | text: 'Roboto'
52 | code: 'JetBrains Mono'
53 |
54 | # Extensions
55 | markdown_extensions:
56 | - admonition
57 | - attr_list
58 | - codehilite:
59 | guess_lang: false
60 | - footnotes
61 | - toc:
62 | permalink: true
63 | - pymdownx.betterem
64 | - pymdownx.superfences
65 | - pymdownx.tabbed:
66 | alternate_style: true
67 | - pymdownx.details
68 |
--------------------------------------------------------------------------------
/permissions-lint/README.md:
--------------------------------------------------------------------------------
1 | # Lint checks for Permissions for Jetpack Compose
2 |
3 | Lint checks for preventing calling `PermissionState.launchPermissionRequest` and
4 | `MultiplePermissionsState.launchMultiplePermissionRequest()` within the Composition as that throws
5 | a runtime exception.
6 |
7 | These functions should be called inside a regular lambda or a side-effect but never in the
8 | Composition.
9 |
10 | These lint checks will be automatically applied to your project when using
11 | 📫 [Permissions](https://google.github.io/accompanist/permissions/).
12 |
13 | ## Download Permissions for Jetpack Compose
14 |
15 | ```groovy
16 | repositories {
17 | mavenCentral()
18 | }
19 |
20 | dependencies {
21 | implementation "com.google.accompanist:accompanist-permissions:"
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/permissions-lint/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | import com.google.accompanist.BundleInsideHelper
17 | import com.google.accompanist.BundleInsideHelper.forInsideLintJar
18 |
19 | plugins {
20 | `java-library`
21 | id("kotlin")
22 | id(libs.plugins.jetbrains.dokka.get().pluginId)
23 | id(libs.plugins.android.lint.get().pluginId)
24 | }
25 |
26 | lint {
27 | htmlReport = true
28 | htmlOutput = file("lint-report.html")
29 | textReport = true
30 | absolutePaths = false
31 | ignoreTestSources = true
32 | }
33 |
34 | affectedTestConfiguration {
35 | jvmTestTask = "test"
36 | }
37 |
38 | /**
39 | * Creates a configuration for users to use that will be used bundle these dependency
40 | * jars inside of this lint check's jar. This is required because lintPublish does
41 | * not currently support dependencies, so instead we need to bundle any dependencies with the
42 | * lint jar manually. (b/182319899)
43 | */
44 | val bundleInside = forInsideLintJar()
45 |
46 | dependencies {
47 | // Bundle metadataJvm inside the Jar
48 | bundleInside(libs.kotlin.metadataJvm)
49 |
50 | compileOnly(libs.android.tools.lint.api)
51 | compileOnly(libs.kotlin.reflect)
52 | compileOnly(libs.kotlin.stdlib)
53 | compileOnly(libs.kotlin.stdlibJdk8) // Override version from transitive dependencies
54 |
55 | testImplementation(libs.junit)
56 | testImplementation(libs.kotlin.reflect)
57 | testImplementation(libs.kotlin.stdlib)
58 | testImplementation(libs.kotlin.stdlibJdk8) // Override version from transitive dependencies
59 | testImplementation(libs.android.tools.lint.lint)
60 | testImplementation(libs.android.tools.lint.tests)
61 | }
62 |
63 | java {
64 | sourceCompatibility = JavaVersion.VERSION_17
65 | targetCompatibility = JavaVersion.VERSION_17
66 | }
--------------------------------------------------------------------------------
/permissions-lint/src/main/java/com/google/accompanist/permissions/lint/PermissionsIssueRegistry.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions.lint
18 |
19 | import com.android.tools.lint.client.api.IssueRegistry
20 | import com.android.tools.lint.client.api.Vendor
21 | import com.android.tools.lint.detector.api.CURRENT_API
22 | import com.android.tools.lint.detector.api.Issue
23 |
24 | @Suppress("UnstableApiUsage")
25 | public class PermissionsIssueRegistry : IssueRegistry() {
26 |
27 | override val issues: List = listOf(
28 | PermissionsLaunchDetector.PermissionLaunchedDuringComposition
29 | )
30 |
31 | override val api: Int = 10
32 | override val minApi: Int = CURRENT_API
33 |
34 | override val vendor: Vendor = Vendor(
35 | vendorName = "Accompanist Permissions",
36 | identifier = "com.google.accompanist.permissions",
37 | feedbackUrl = "https://github.com/google/accompanist/issues/new/choose"
38 | )
39 | }
40 |
--------------------------------------------------------------------------------
/permissions-lint/src/main/java/com/google/accompanist/permissions/lint/PermissionsLaunchDetector.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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:Suppress("UnstableApiUsage")
18 |
19 | package com.google.accompanist.permissions.lint
20 |
21 | import com.android.tools.lint.detector.api.Category
22 | import com.android.tools.lint.detector.api.Detector
23 | import com.android.tools.lint.detector.api.Implementation
24 | import com.android.tools.lint.detector.api.Issue
25 | import com.android.tools.lint.detector.api.JavaContext
26 | import com.android.tools.lint.detector.api.Scope
27 | import com.android.tools.lint.detector.api.Severity
28 | import com.android.tools.lint.detector.api.SourceCodeScanner
29 | import com.google.accompanist.permissions.lint.util.Name
30 | import com.google.accompanist.permissions.lint.util.Package
31 | import com.google.accompanist.permissions.lint.util.PackageName
32 | import com.google.accompanist.permissions.lint.util.isInvokedWithinComposable
33 | import com.intellij.psi.PsiJavaFile
34 | import com.intellij.psi.PsiMethod
35 | import org.jetbrains.uast.UCallExpression
36 | import java.util.EnumSet
37 |
38 | /**
39 | * [Detector] that checks `PermissionState.launchPermissionRequest` and
40 | * `MultiplePermissionsState.launchMultiplePermissionRequest` calls to make sure they don't happen
41 | * inside the body of a composable function / lambda.
42 | */
43 | public class PermissionsLaunchDetector : Detector(), SourceCodeScanner {
44 |
45 | override fun getApplicableMethodNames(): List = listOf(
46 | LaunchPermissionRequest.shortName, LaunchMultiplePermissionsRequest.shortName
47 | )
48 |
49 | override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
50 | if (!method.isInPackageName(PermissionsPackageName)) return
51 |
52 | if (node.isInvokedWithinComposable()) {
53 | context.report(
54 | PermissionLaunchedDuringComposition,
55 | node,
56 | context.getNameLocation(node),
57 | "Calls to ${method.name} should happen inside a regular lambda or " +
58 | " a side-effect, but never in the Composition."
59 | )
60 | }
61 | }
62 |
63 | public companion object {
64 | public val PermissionLaunchedDuringComposition: Issue = Issue.create(
65 | "PermissionLaunchedDuringComposition",
66 | "Calls to `launchPermissionRequest` or `launchMultiplePermissionRequest` " +
67 | "should happen inside a regular lambda or a side-effect but never in the " +
68 | "Composition.",
69 | "Calls to `launchPermissionRequest` or `launchMultiplePermissionRequest` " +
70 | "in the Composition throw a runtime exception. Please call them inside a regular " +
71 | "lambda or in a side-effect.",
72 | Category.CORRECTNESS, 3, Severity.ERROR,
73 | Implementation(
74 | PermissionsLaunchDetector::class.java,
75 | EnumSet.of(Scope.JAVA_FILE, Scope.TEST_SOURCES)
76 | )
77 | )
78 | }
79 | }
80 |
81 | /**
82 | * Returns whether [this] has [packageName] as its package name.
83 | */
84 | private fun PsiMethod.isInPackageName(packageName: PackageName): Boolean =
85 | packageName.javaPackageName == (containingFile as? PsiJavaFile)?.packageName
86 |
87 | private val PermissionsPackageName = Package("com.google.accompanist.permissions")
88 | private val LaunchPermissionRequest =
89 | Name(PermissionsPackageName, "launchPermissionRequest")
90 | private val LaunchMultiplePermissionsRequest =
91 | Name(PermissionsPackageName, "launchMultiplePermissionRequest")
92 |
--------------------------------------------------------------------------------
/permissions-lint/src/main/java/com/google/accompanist/permissions/lint/util/PsiUtils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions.lint.util
18 |
19 | import com.intellij.psi.PsiClass
20 | import com.intellij.psi.PsiClassOwner
21 | import com.intellij.psi.PsiMethod
22 | import com.intellij.psi.PsiType
23 | import com.intellij.psi.util.InheritanceUtil
24 |
25 | /**
26 | * File copied from
27 | * https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/lint/common/src/main/java/androidx/compose/lint/PsiUtils.kt
28 | */
29 |
30 | /** Returns whether [this] has [packageName] as its package name. */
31 | fun PsiMethod.isInPackageName(packageName: PackageName): Boolean {
32 | val actual = (containingFile as? PsiClassOwner)?.packageName
33 | return packageName.javaPackageName == actual
34 | }
35 |
36 | /** Whether this [PsiMethod] returns Unit */
37 | val PsiMethod.returnsUnit
38 | get() = returnType.isVoidOrUnit
39 |
40 | /**
41 | * Whether this [PsiType] is `void` or [Unit]
42 | *
43 | * In Kotlin 1.6 some expressions now explicitly return [Unit] instead of just being [PsiType.VOID],
44 | * so this returns whether this type is either.
45 | */
46 | val PsiType?.isVoidOrUnit
47 | get() = this == PsiType.VOID || this?.canonicalText == "kotlin.Unit"
48 |
49 | /** @return whether [this] inherits from [name]. Returns `true` if [this] _is_ directly [name]. */
50 | fun PsiType.inheritsFrom(name: Name) = InheritanceUtil.isInheritor(this, name.javaFqn)
51 |
52 | /** @return whether [this] inherits from [name]. Returns `true` if [this] _is_ directly [name]. */
53 | fun PsiClass.inheritsFrom(name: Name) = InheritanceUtil.isInheritor(this, name.javaFqn)
54 |
--------------------------------------------------------------------------------
/permissions-lint/src/main/resources/META-INF/services/com.android.tools.lint.client.api.IssueRegistry:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2021 The Android Open Source Project
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 | # https://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 | com.google.accompanist.permissions.lint.PermissionsIssueRegistry
18 |
--------------------------------------------------------------------------------
/permissions/README.md:
--------------------------------------------------------------------------------
1 | # Permissions for Jetpack Compose
2 |
3 | [](https://search.maven.org/search?q=g:com.google.accompanist)
4 |
5 | For more information, visit the documentation: https://google.github.io/accompanist/permissions
6 |
7 | ## Download
8 |
9 | ```groovy
10 | repositories {
11 | mavenCentral()
12 | }
13 |
14 | dependencies {
15 | implementation "com.google.accompanist:accompanist-permissions:"
16 | }
17 | ```
18 |
19 | Snapshots of the development version are available in [Sonatype's `snapshots` repository][snap]. These are updated on every commit.
20 |
21 | [snap]: https://oss.sonatype.org/content/repositories/snapshots/com/google/accompanist/accompanist-permissions/
--------------------------------------------------------------------------------
/permissions/api/current.api:
--------------------------------------------------------------------------------
1 | // Signature format: 4.0
2 | package com.google.accompanist.permissions {
3 |
4 | @kotlin.RequiresOptIn(message="Accompanist Permissions is experimental. The API may be changed in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalPermissionsApi {
5 | }
6 |
7 | @androidx.compose.runtime.Stable @com.google.accompanist.permissions.ExperimentalPermissionsApi public interface MultiplePermissionsState {
8 | method public boolean getAllPermissionsGranted();
9 | method public java.util.List getPermissions();
10 | method public java.util.List getRevokedPermissions();
11 | method public boolean getShouldShowRationale();
12 | method public void launchMultiplePermissionRequest();
13 | property public abstract boolean allPermissionsGranted;
14 | property public abstract java.util.List permissions;
15 | property public abstract java.util.List revokedPermissions;
16 | property public abstract boolean shouldShowRationale;
17 | }
18 |
19 | public final class MultiplePermissionsStateKt {
20 | method @androidx.compose.runtime.Composable @com.google.accompanist.permissions.ExperimentalPermissionsApi public static com.google.accompanist.permissions.MultiplePermissionsState rememberMultiplePermissionsState(java.util.List permissions, optional kotlin.jvm.functions.Function1 super java.util.Map,kotlin.Unit> onPermissionsResult);
21 | method @androidx.compose.runtime.Composable @com.google.accompanist.permissions.ExperimentalPermissionsApi public static com.google.accompanist.permissions.MultiplePermissionsState rememberMultiplePermissionsState(java.util.List permissions, optional kotlin.jvm.functions.Function1 super java.util.Map,kotlin.Unit> onPermissionsResult, optional java.util.Map previewPermissionStatuses);
22 | }
23 |
24 | @androidx.compose.runtime.Stable @com.google.accompanist.permissions.ExperimentalPermissionsApi public interface PermissionState {
25 | method public String getPermission();
26 | method public com.google.accompanist.permissions.PermissionStatus getStatus();
27 | method public void launchPermissionRequest();
28 | property public abstract String permission;
29 | property public abstract com.google.accompanist.permissions.PermissionStatus status;
30 | }
31 |
32 | public final class PermissionStateKt {
33 | method @androidx.compose.runtime.Composable @com.google.accompanist.permissions.ExperimentalPermissionsApi public static com.google.accompanist.permissions.PermissionState rememberPermissionState(String permission, optional kotlin.jvm.functions.Function1 super java.lang.Boolean,kotlin.Unit> onPermissionResult);
34 | method @androidx.compose.runtime.Composable @com.google.accompanist.permissions.ExperimentalPermissionsApi public static com.google.accompanist.permissions.PermissionState rememberPermissionState(String permission, optional kotlin.jvm.functions.Function1 super java.lang.Boolean,kotlin.Unit> onPermissionResult, optional com.google.accompanist.permissions.PermissionStatus previewPermissionStatus);
35 | }
36 |
37 | @androidx.compose.runtime.Stable @com.google.accompanist.permissions.ExperimentalPermissionsApi public sealed interface PermissionStatus {
38 | }
39 |
40 | public static final class PermissionStatus.Denied implements com.google.accompanist.permissions.PermissionStatus {
41 | ctor public PermissionStatus.Denied(boolean shouldShowRationale);
42 | method public boolean component1();
43 | method public com.google.accompanist.permissions.PermissionStatus.Denied copy(boolean shouldShowRationale);
44 | method public boolean getShouldShowRationale();
45 | property public final boolean shouldShowRationale;
46 | }
47 |
48 | public static final class PermissionStatus.Granted implements com.google.accompanist.permissions.PermissionStatus {
49 | field public static final com.google.accompanist.permissions.PermissionStatus.Granted INSTANCE;
50 | }
51 |
52 | public final class PermissionsUtilKt {
53 | method public static boolean getShouldShowRationale(com.google.accompanist.permissions.PermissionStatus);
54 | method public static boolean isGranted(com.google.accompanist.permissions.PermissionStatus);
55 | }
56 |
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/permissions/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | @file:Suppress("UnstableApiUsage")
17 |
18 | plugins {
19 | alias(libs.plugins.accompanist.android.library)
20 | alias(libs.plugins.accompanist.android.library.compose)
21 | alias(libs.plugins.accompanist.android.library.published)
22 | }
23 |
24 | android {
25 | namespace = "com.google.accompanist.permissions"
26 |
27 | defaultConfig {
28 | // The following argument makes the Android Test Orchestrator run its
29 | // "pm clear" command after each test invocation. This command ensures
30 | // that the app's state is completely cleared between tests.
31 | testInstrumentationRunnerArguments["clearPackageData"] = "true"
32 | }
33 |
34 | testOptions {
35 | execution = "ANDROIDX_TEST_ORCHESTRATOR"
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation(libs.androidx.activity.compose)
41 | implementation(libs.compose.foundation.foundation)
42 | implementation(libs.kotlin.coroutines.android)
43 |
44 | lintChecks(project(":permissions-lint"))
45 | lintPublish(project(":permissions-lint"))
46 |
47 | // ======================
48 | // Test dependencies
49 | // ======================
50 |
51 | androidTestUtil(libs.androidx.test.orchestrator)
52 |
53 | androidTestImplementation(project(":internal-testutils"))
54 | androidTestImplementation(libs.androidx.activity.compose)
55 | androidTestImplementation(libs.compose.material.material)
56 |
57 | androidTestImplementation(libs.junit)
58 | androidTestImplementation(libs.truth)
59 |
60 | androidTestImplementation(libs.compose.ui.test.junit4)
61 | androidTestImplementation(libs.compose.ui.test.manifest)
62 | androidTestImplementation(libs.compose.foundation.foundation)
63 | androidTestImplementation(libs.androidx.test.runner)
64 | androidTestImplementation(libs.androidx.test.rules)
65 | androidTestImplementation(libs.androidx.test.uiAutomator)
66 | }
67 |
--------------------------------------------------------------------------------
/permissions/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=accompanist-permissions
2 | POM_NAME=Accompanist Permissions
3 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/permissions/src/androidTest/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/permissions/src/androidTest/java/com/google/accompanist/permissions/FakeTests.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions
18 |
19 | import androidx.test.filters.SdkSuppress
20 | import org.junit.Test
21 |
22 | /**
23 | * Fake tests to avoid the "No tests found error" when running in Build.VERSION.SDK_INT < 23
24 | */
25 | class FakeTests {
26 |
27 | @SdkSuppress(maxSdkVersion = 22)
28 | @Test
29 | fun fakeTestToAvoidNoTestsFoundErrorInAPI22AndBelow() = Unit
30 |
31 | // More Fake tests to help with sharding: https://github.com/android/android-test/issues/973
32 | @Test
33 | fun fake1() = Unit
34 |
35 | @Test
36 | fun fake2() = Unit
37 |
38 | @Test
39 | fun fake3() = Unit
40 |
41 | @Test
42 | fun fake4() = Unit
43 |
44 | @Test
45 | fun fake5() = Unit
46 |
47 | @Test
48 | fun fake6() = Unit
49 |
50 | @Test
51 | fun fake7() = Unit
52 |
53 | @Test
54 | fun fake8() = Unit
55 |
56 | @Test
57 | fun fake9() = Unit
58 | }
59 |
--------------------------------------------------------------------------------
/permissions/src/androidTest/java/com/google/accompanist/permissions/MultiplePermissionsStateTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions
18 |
19 | import androidx.compose.ui.test.junit4.createAndroidComposeRule
20 | import androidx.test.filters.SdkSuppress
21 | import androidx.test.rule.GrantPermissionRule
22 | import com.google.accompanist.permissions.test.EmptyPermissionsTestActivity
23 | import com.google.common.truth.Truth.assertThat
24 | import org.junit.Rule
25 | import org.junit.Test
26 |
27 | /**
28 | * Simple tests that prove the data comes from the right place
29 | */
30 | @OptIn(ExperimentalPermissionsApi::class)
31 | @SdkSuppress(minSdkVersion = 23)
32 | class MultiplePermissionsStateTest {
33 |
34 | @get:Rule
35 | val composeTestRule = createAndroidComposeRule()
36 |
37 | @get:Rule
38 | val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(
39 | "android.permission.CAMERA",
40 | "android.permission.ACCESS_FINE_LOCATION"
41 | )
42 |
43 | @Test
44 | fun permissionState_hasPermission() {
45 | composeTestRule.setContent {
46 | val state = rememberMultiplePermissionsState(
47 | listOf(
48 | android.Manifest.permission.ACCESS_FINE_LOCATION,
49 | android.Manifest.permission.CAMERA
50 | )
51 | )
52 |
53 | assertThat(state.allPermissionsGranted).isTrue()
54 | assertThat(state.shouldShowRationale).isFalse()
55 | }
56 | }
57 |
58 | @Test
59 | fun permissionTest_shouldShowRationale() {
60 | composeTestRule.activity.shouldShowRequestPermissionRationale = mapOf(
61 | android.Manifest.permission.WRITE_EXTERNAL_STORAGE to true
62 | )
63 |
64 | composeTestRule.setContent {
65 | val state = rememberMultiplePermissionsState(
66 | listOf(
67 | android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
68 | android.Manifest.permission.ACCESS_FINE_LOCATION,
69 | android.Manifest.permission.CAMERA
70 | )
71 | )
72 |
73 | assertThat(state.allPermissionsGranted).isFalse()
74 | assertThat(state.shouldShowRationale).isTrue()
75 | assertThat(state.permissions).hasSize(3)
76 | assertThat(state.revokedPermissions).hasSize(1)
77 | assertThat(state.revokedPermissions[0].permission)
78 | .isEqualTo("android.permission.WRITE_EXTERNAL_STORAGE")
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/permissions/src/androidTest/java/com/google/accompanist/permissions/PermissionStateTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions
18 |
19 | import androidx.compose.ui.test.junit4.createAndroidComposeRule
20 | import androidx.test.filters.SdkSuppress
21 | import androidx.test.rule.GrantPermissionRule
22 | import com.google.accompanist.permissions.test.EmptyPermissionsTestActivity
23 | import com.google.common.truth.Truth.assertThat
24 | import org.junit.Rule
25 | import org.junit.Test
26 |
27 | /**
28 | * Simple tests that prove the data comes from the right place
29 | */
30 | @OptIn(ExperimentalPermissionsApi::class)
31 | @SdkSuppress(minSdkVersion = 23)
32 | class PermissionStateTest {
33 |
34 | @get:Rule
35 | val composeTestRule = createAndroidComposeRule()
36 |
37 | @get:Rule
38 | val permissionRule: GrantPermissionRule =
39 | GrantPermissionRule.grant("android.permission.CAMERA")
40 |
41 | @Test
42 | fun permissionState_hasPermission() {
43 | composeTestRule.setContent {
44 | val state = rememberPermissionState(android.Manifest.permission.CAMERA)
45 | assertThat(state.status.isGranted).isTrue()
46 | assertThat(state.status.shouldShowRationale).isFalse()
47 | }
48 | }
49 |
50 | @Test
51 | fun permissionTest_shouldShowRationale() {
52 | val permission = android.Manifest.permission.ACCESS_FINE_LOCATION
53 | composeTestRule.activity.shouldShowRequestPermissionRationale = mapOf(
54 | permission to true
55 | )
56 |
57 | composeTestRule.setContent {
58 | val state = rememberPermissionState(permission)
59 |
60 | assertThat(state.status.isGranted).isFalse()
61 | assertThat(state.status.shouldShowRationale).isTrue()
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/permissions/src/androidTest/java/com/google/accompanist/permissions/test/EmptyPermissionsTestActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions.test
18 |
19 | import androidx.activity.ComponentActivity
20 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
21 |
22 | @OptIn(ExperimentalPermissionsApi::class)
23 | class EmptyPermissionsTestActivity : ComponentActivity() {
24 |
25 | var shouldShowRequestPermissionRationale: Map = emptyMap()
26 |
27 | override fun shouldShowRequestPermissionRationale(permission: String): Boolean {
28 | if (permission in shouldShowRequestPermissionRationale.keys) {
29 | return shouldShowRequestPermissionRationale[permission]!!
30 | }
31 | return super.shouldShowRequestPermissionRationale(permission)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/permissions/src/androidTest/java/com/google/accompanist/permissions/test/PermissionsTestActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions.test
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Column
23 | import androidx.compose.material.Button
24 | import androidx.compose.material.Text
25 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
26 | import com.google.accompanist.permissions.PermissionStatus
27 | import com.google.accompanist.permissions.rememberPermissionState
28 | import com.google.accompanist.permissions.shouldShowRationale
29 |
30 | @OptIn(ExperimentalPermissionsApi::class)
31 | class PermissionsTestActivity : ComponentActivity() {
32 |
33 | var shouldShowRequestPermissionRationale: Map = emptyMap()
34 |
35 | override fun shouldShowRequestPermissionRationale(permission: String): Boolean {
36 | if (permission in shouldShowRequestPermissionRationale.keys) {
37 | return shouldShowRequestPermissionRationale[permission]!!
38 | }
39 | return super.shouldShowRequestPermissionRationale(permission)
40 | }
41 |
42 | /**
43 | * Code used in `MultipleAndSinglePermissionsTest`
44 | */
45 | override fun onCreate(savedInstanceState: Bundle?) {
46 | super.onCreate(savedInstanceState)
47 | setContent {
48 | Column {
49 | Text("PermissionsTestActivity")
50 |
51 | val state = rememberPermissionState(android.Manifest.permission.CAMERA,)
52 | when (state.status) {
53 | PermissionStatus.Granted -> {
54 | Text("Granted")
55 | }
56 | is PermissionStatus.Denied -> {
57 | val textToShow = if (state.status.shouldShowRationale) {
58 | "ShowRationale"
59 | } else {
60 | "No permission"
61 | }
62 |
63 | Text(textToShow)
64 | Button(onClick = { state.launchPermissionRequest() }) {
65 | Text("Request")
66 | }
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/permissions/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
19 |
20 |
--------------------------------------------------------------------------------
/permissions/src/main/java/com/google/accompanist/permissions/MutablePermissionState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions
18 |
19 | import android.app.Activity
20 | import android.content.Context
21 | import androidx.activity.compose.rememberLauncherForActivityResult
22 | import androidx.activity.result.ActivityResultLauncher
23 | import androidx.activity.result.contract.ActivityResultContracts
24 | import androidx.compose.runtime.Composable
25 | import androidx.compose.runtime.DisposableEffect
26 | import androidx.compose.runtime.Stable
27 | import androidx.compose.runtime.getValue
28 | import androidx.compose.runtime.mutableStateOf
29 | import androidx.compose.runtime.remember
30 | import androidx.compose.runtime.setValue
31 | import androidx.compose.ui.platform.LocalContext
32 |
33 | /**
34 | * Creates a [MutablePermissionState] that is remembered across compositions.
35 | *
36 | * It's recommended that apps exercise the permissions workflow as described in the
37 | * [documentation](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
38 | *
39 | * @param permission the permission to control and observe.
40 | * @param onPermissionResult will be called with whether or not the user granted the permission
41 | * after [PermissionState.launchPermissionRequest] is called.
42 | */
43 | @ExperimentalPermissionsApi
44 | @Composable
45 | internal fun rememberMutablePermissionState(
46 | permission: String,
47 | onPermissionResult: (Boolean) -> Unit = {}
48 | ): MutablePermissionState {
49 | val context = LocalContext.current
50 | val permissionState = remember(permission) {
51 | MutablePermissionState(permission, context, context.findActivity())
52 | }
53 |
54 | // Refresh the permission status when the lifecycle is resumed
55 | PermissionLifecycleCheckerEffect(permissionState)
56 |
57 | // Remember RequestPermission launcher and assign it to permissionState
58 | val launcher = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) {
59 | permissionState.refreshPermissionStatus()
60 | onPermissionResult(it)
61 | }
62 | DisposableEffect(permissionState, launcher) {
63 | permissionState.launcher = launcher
64 | onDispose {
65 | permissionState.launcher = null
66 | }
67 | }
68 |
69 | return permissionState
70 | }
71 |
72 | /**
73 | * A mutable state object that can be used to control and observe permission status changes.
74 | *
75 | * In most cases, this will be created via [rememberMutablePermissionState].
76 | *
77 | * @param permission the permission to control and observe.
78 | * @param context to check the status of the [permission].
79 | * @param activity to check if the user should be presented with a rationale for [permission].
80 | */
81 | @ExperimentalPermissionsApi
82 | @Stable
83 | internal class MutablePermissionState(
84 | override val permission: String,
85 | private val context: Context,
86 | private val activity: Activity
87 | ) : PermissionState {
88 |
89 | override var status: PermissionStatus by mutableStateOf(getPermissionStatus())
90 |
91 | override fun launchPermissionRequest() {
92 | launcher?.launch(
93 | permission
94 | ) ?: throw IllegalStateException("ActivityResultLauncher cannot be null")
95 | }
96 |
97 | internal var launcher: ActivityResultLauncher? = null
98 |
99 | internal fun refreshPermissionStatus() {
100 | status = getPermissionStatus()
101 | }
102 |
103 | private fun getPermissionStatus(): PermissionStatus {
104 | val hasPermission = context.checkPermission(permission)
105 | return if (hasPermission) {
106 | PermissionStatus.Granted
107 | } else {
108 | PermissionStatus.Denied(activity.shouldShowRationale(permission))
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/permissions/src/main/java/com/google/accompanist/permissions/PermissionState.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.permissions
18 |
19 | import androidx.compose.runtime.Composable
20 | import androidx.compose.runtime.Immutable
21 | import androidx.compose.runtime.Stable
22 | import androidx.compose.ui.platform.LocalInspectionMode
23 |
24 | /**
25 | * Creates a [PermissionState] that is remembered across compositions.
26 | *
27 | * It's recommended that apps exercise the permissions workflow as described in the
28 | * [documentation](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
29 | *
30 | * @param permission the permission to control and observe.
31 | * @param onPermissionResult will be called with whether or not the user granted the permission
32 | * after [PermissionState.launchPermissionRequest] is called.
33 | */
34 | @ExperimentalPermissionsApi
35 | @Composable
36 | public fun rememberPermissionState(
37 | permission: String,
38 | onPermissionResult: (Boolean) -> Unit = {}
39 | ): PermissionState {
40 | return rememberPermissionState(permission, onPermissionResult, PermissionStatus.Granted)
41 | }
42 |
43 | /**
44 | * Creates a [PermissionState] that is remembered across compositions.
45 | *
46 | * It's recommended that apps exercise the permissions workflow as described in the
47 | * [documentation](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
48 | *
49 | * @param permission the permission to control and observe.
50 | * @param onPermissionResult will be called with whether or not the user granted the permission
51 | * after [PermissionState.launchPermissionRequest] is called.
52 | * @param previewPermissionStatus provides a [PermissionStatus] when running in a preview.
53 | */
54 | @ExperimentalPermissionsApi
55 | @Composable
56 | public fun rememberPermissionState(
57 | permission: String,
58 | onPermissionResult: (Boolean) -> Unit = {},
59 | previewPermissionStatus: PermissionStatus = PermissionStatus.Granted
60 | ): PermissionState {
61 | return when {
62 | LocalInspectionMode.current -> PreviewPermissionState(permission, previewPermissionStatus)
63 | else -> rememberMutablePermissionState(permission, onPermissionResult)
64 | }
65 | }
66 |
67 | /**
68 | * A state object that can be hoisted to control and observe [permission] status changes.
69 | *
70 | * In most cases, this will be created via [rememberPermissionState].
71 | *
72 | * It's recommended that apps exercise the permissions workflow as described in the
73 | * [documentation](https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions).
74 | */
75 | @ExperimentalPermissionsApi
76 | @Stable
77 | public interface PermissionState {
78 |
79 | /**
80 | * The permission to control and observe.
81 | */
82 | public val permission: String
83 |
84 | /**
85 | * [permission]'s status
86 | */
87 | public val status: PermissionStatus
88 |
89 | /**
90 | * Request the [permission] to the user.
91 | *
92 | * This should always be triggered from non-composable scope, for example, from a side-effect
93 | * or a non-composable callback. Otherwise, this will result in an IllegalStateException.
94 | *
95 | * This triggers a system dialog that asks the user to grant or revoke the permission.
96 | * Note that this dialog might not appear on the screen if the user doesn't want to be asked
97 | * again or has denied the permission multiple times.
98 | * This behavior varies depending on the Android level API.
99 | */
100 | public fun launchPermissionRequest(): Unit
101 | }
102 |
103 | @OptIn(ExperimentalPermissionsApi::class)
104 | @Immutable
105 | internal class PreviewPermissionState(
106 | override val permission: String,
107 | override val status: PermissionStatus
108 | ) : PermissionState {
109 | override fun launchPermissionRequest() {}
110 | }
111 |
--------------------------------------------------------------------------------
/release/secring.gpg.aes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/release/secring.gpg.aes
--------------------------------------------------------------------------------
/release/signing-cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Copyright 2021 The Android Open Source Project
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | rm -f release/*.gpg
18 | rm -f release/*.properties
19 |
--------------------------------------------------------------------------------
/release/signing-setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2021 The Android Open Source Project
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | ENCRYPT_KEY=$1
18 |
19 | if [[ ! -z "$ENCRYPT_KEY" ]]; then
20 | # Decrypt GnuPG keyring
21 | openssl aes-256-cbc -md sha256 -d -in release/secring.gpg.aes -out release/secring.gpg -k ${ENCRYPT_KEY}
22 |
23 | # Decrypt Play Store key
24 | openssl aes-256-cbc -md sha256 -d -in release/signing.properties.aes -out release/signing.properties -k ${ENCRYPT_KEY}
25 |
26 | else
27 | echo "ENCRYPT_KEY is empty"
28 | fi
29 |
--------------------------------------------------------------------------------
/release/signing.properties.aes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/release/signing.properties.aes
--------------------------------------------------------------------------------
/sample/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | @file:Suppress("UnstableApiUsage")
17 |
18 | plugins {
19 | alias(libs.plugins.android.application)
20 | alias(libs.plugins.android.kotlin)
21 | alias(libs.plugins.compose.plugin)
22 | }
23 |
24 | android {
25 | compileSdk = 35
26 |
27 | defaultConfig {
28 | applicationId = "com.google.accompanist.sample"
29 | minSdk = 21
30 | targetSdk = 35
31 |
32 | versionCode = 1
33 | versionName = "1.0"
34 |
35 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
36 | }
37 |
38 | compileOptions {
39 | sourceCompatibility = JavaVersion.VERSION_17
40 | targetCompatibility = JavaVersion.VERSION_17
41 |
42 | isCoreLibraryDesugaringEnabled = true
43 | }
44 |
45 | buildFeatures {
46 | compose = true
47 | }
48 |
49 | buildTypes {
50 | getByName("release") {
51 | signingConfig = signingConfigs.getByName("debug")
52 | }
53 | }
54 |
55 | kotlinOptions {
56 | jvmTarget = "17"
57 | }
58 |
59 | namespace = "com.google.accompanist.sample"
60 | }
61 |
62 | dependencies {
63 | coreLibraryDesugaring(libs.desugar.jdk.libs)
64 |
65 | implementation(project(":adaptive"))
66 | implementation(project(":drawablepainter"))
67 | implementation(project(":permissions"))
68 |
69 | implementation(libs.compose.material.iconsext)
70 | implementation(libs.compose.material3.material3)
71 | implementation(libs.compose.foundation.layout)
72 | debugImplementation(libs.compose.ui.tooling)
73 | implementation(libs.compose.ui.tooling.preview)
74 | implementation(libs.compose.ui.util)
75 |
76 | implementation(libs.androidx.core)
77 | implementation(libs.androidx.activity.compose)
78 | implementation(libs.androidx.lifecycle.runtime)
79 |
80 | implementation(libs.kotlin.stdlib)
81 |
82 | lintChecks(project(":permissions-lint"))
83 | }
84 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/ImageLoadingSampleUtils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample
18 |
19 | import androidx.compose.runtime.Composable
20 | import androidx.compose.runtime.remember
21 |
22 | private val rangeForRandom = (0..100000)
23 |
24 | fun randomSampleImageUrl(
25 | seed: Int = rangeForRandom.random(),
26 | width: Int = 300,
27 | height: Int = width,
28 | ): String {
29 | return "https://picsum.photos/seed/$seed/$width/$height"
30 | }
31 |
32 | /**
33 | * Remember a URL generate by [randomSampleImageUrl].
34 | */
35 | @Composable
36 | fun rememberRandomSampleImageUrl(
37 | seed: Int = rangeForRandom.random(),
38 | width: Int = 300,
39 | height: Int = width,
40 | ): String = remember { randomSampleImageUrl(seed, width, height) }
41 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample
18 |
19 | import android.annotation.SuppressLint
20 | import android.content.Intent
21 | import android.os.Bundle
22 | import androidx.activity.ComponentActivity
23 | import androidx.activity.compose.setContent
24 | import androidx.activity.enableEdgeToEdge
25 |
26 | /**
27 | * A list which automatically populates the list of sample activities in this app
28 | * with the category `com.google.accompanist.sample.SAMPLE_CODE`.
29 | */
30 | class MainActivity : ComponentActivity() {
31 | override fun onCreate(savedInstanceState: Bundle?) {
32 | super.onCreate(savedInstanceState)
33 |
34 | enableEdgeToEdge()
35 | val data = getData(intent.getStringExtra(EXTRA_PATH))
36 |
37 | setContent {
38 | AccompanistSampleTheme {
39 | MainScreen(
40 | listData = data,
41 | onItemClick = { startActivity(it) }
42 | )
43 | }
44 | }
45 | }
46 |
47 | private fun getData(prefix: String?): List {
48 | val myData = mutableListOf()
49 |
50 | val mainIntent = Intent(Intent.ACTION_MAIN, null)
51 | mainIntent.addCategory("com.google.accompanist.sample.SAMPLE_CODE")
52 |
53 | @SuppressLint("QueryPermissionsNeeded") // Only querying our own Activities
54 | val list = packageManager.queryIntentActivities(mainIntent, 0)
55 |
56 | val prefixPath: Array?
57 | var prefixWithSlash = prefix
58 |
59 | if (prefix.isNullOrEmpty()) {
60 | prefixPath = null
61 | } else {
62 | prefixPath = prefix.split("/".toRegex()).toTypedArray()
63 | prefixWithSlash = "$prefix/"
64 | }
65 |
66 | val entries = mutableMapOf()
67 |
68 | list.forEach { info ->
69 | val labelSeq = info.loadLabel(packageManager)
70 | val label = labelSeq?.toString() ?: info.activityInfo.name
71 |
72 | if (prefixWithSlash.isNullOrEmpty() || label.startsWith(prefixWithSlash)) {
73 | val labelPath = label.split("/".toRegex()).toTypedArray()
74 | val nextLabel = if (prefixPath == null) labelPath[0] else labelPath[prefixPath.size]
75 | if ((prefixPath?.size ?: 0) == labelPath.size - 1) {
76 | myData.add(
77 | AccompanistSample(
78 | title = nextLabel,
79 | intent = activityIntent(
80 | info.activityInfo.applicationInfo.packageName,
81 | info.activityInfo.name
82 | )
83 | )
84 | )
85 | } else {
86 | if (entries[nextLabel] == null) {
87 | myData.add(
88 | AccompanistSample(
89 | title = nextLabel,
90 | intent = browseIntent(
91 | if (prefix == "") nextLabel else "$prefix/$nextLabel"
92 | )
93 | )
94 | )
95 | entries[nextLabel] = true
96 | }
97 | }
98 | }
99 | }
100 |
101 | myData.sortBy { it.title }
102 |
103 | return myData
104 | }
105 |
106 | private fun activityIntent(pkg: String, componentName: String): Intent {
107 | val result = Intent()
108 | result.setClassName(pkg, componentName)
109 | return result
110 | }
111 |
112 | private fun browseIntent(path: String): Intent {
113 | val result = Intent()
114 | result.setClass(this, MainActivity::class.java)
115 | result.putExtra(EXTRA_PATH, path)
116 | return result
117 | }
118 | }
119 |
120 | private const val EXTRA_PATH = "com.example.android.apis.Path"
121 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/MainScreen.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample
18 |
19 | import android.content.Intent
20 | import androidx.compose.foundation.clickable
21 | import androidx.compose.foundation.layout.Column
22 | import androidx.compose.foundation.layout.Spacer
23 | import androidx.compose.foundation.layout.WindowInsets
24 | import androidx.compose.foundation.layout.WindowInsetsSides
25 | import androidx.compose.foundation.layout.fillMaxSize
26 | import androidx.compose.foundation.layout.only
27 | import androidx.compose.foundation.layout.safeDrawing
28 | import androidx.compose.foundation.layout.systemBars
29 | import androidx.compose.foundation.layout.windowInsetsBottomHeight
30 | import androidx.compose.foundation.layout.windowInsetsPadding
31 | import androidx.compose.foundation.lazy.LazyColumn
32 | import androidx.compose.foundation.lazy.items
33 | import androidx.compose.material3.ExperimentalMaterial3Api
34 | import androidx.compose.material3.ListItem
35 | import androidx.compose.material3.Surface
36 | import androidx.compose.material3.Text
37 | import androidx.compose.material3.TopAppBar
38 | import androidx.compose.material3.TopAppBarDefaults
39 | import androidx.compose.material3.rememberTopAppBarState
40 | import androidx.compose.runtime.Composable
41 | import androidx.compose.ui.Modifier
42 | import androidx.compose.ui.input.nestedscroll.nestedScroll
43 | import androidx.compose.ui.res.stringResource
44 |
45 | data class AccompanistSample(
46 | val title: String,
47 | val intent: Intent
48 | )
49 |
50 | @OptIn(ExperimentalMaterial3Api::class)
51 | @Composable
52 | fun MainScreen(
53 | listData: List,
54 | onItemClick: (Intent) -> Unit,
55 | modifier: Modifier = Modifier
56 | ) {
57 | Surface(modifier) {
58 | Column {
59 | val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
60 | TopAppBar(
61 | title = { Text(stringResource(R.string.app_name)) },
62 | scrollBehavior = scrollBehavior
63 | )
64 |
65 | ContentList(
66 | listData,
67 | onItemClick,
68 | modifier = Modifier
69 | .fillMaxSize()
70 | .windowInsetsPadding(
71 | WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal)
72 | )
73 | .nestedScroll(scrollBehavior.nestedScrollConnection)
74 | )
75 | }
76 | }
77 | }
78 |
79 | @OptIn(ExperimentalMaterial3Api::class)
80 | @Composable
81 | private fun ContentList(
82 | listData: List,
83 | onItemClick: (Intent) -> Unit,
84 | modifier: Modifier = Modifier
85 | ) {
86 | LazyColumn(
87 | modifier = modifier
88 | ) {
89 | items(listData) {
90 | ListItem(
91 | headlineText = { Text(it.title) },
92 | modifier = Modifier.clickable { onItemClick(it.intent) }
93 | )
94 | }
95 |
96 | item {
97 | Spacer(
98 | Modifier.windowInsetsBottomHeight(
99 | WindowInsets.systemBars
100 | )
101 | )
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/Theme.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample
18 |
19 | import androidx.compose.foundation.isSystemInDarkTheme
20 | import androidx.compose.foundation.layout.Box
21 | import androidx.compose.foundation.layout.PaddingValues
22 | import androidx.compose.foundation.layout.fillMaxSize
23 | import androidx.compose.foundation.layout.padding
24 | import androidx.compose.foundation.layout.safeDrawingPadding
25 | import androidx.compose.material3.MaterialTheme
26 | import androidx.compose.material3.Surface
27 | import androidx.compose.material3.darkColorScheme
28 | import androidx.compose.material3.lightColorScheme
29 | import androidx.compose.runtime.Composable
30 | import androidx.compose.ui.Modifier
31 | import androidx.compose.ui.unit.dp
32 |
33 | @Composable
34 | fun AccompanistSample(
35 | contentPadding: PaddingValues = PaddingValues(16.dp),
36 | content: @Composable () -> Unit
37 | ) {
38 | AccompanistSampleTheme {
39 | Surface(
40 | modifier = Modifier.fillMaxSize()
41 | ) {
42 | Box(
43 | modifier = Modifier.padding(contentPadding).safeDrawingPadding(),
44 | propagateMinConstraints = true
45 | ) {
46 | content()
47 | }
48 | }
49 | }
50 | }
51 |
52 | @Composable
53 | fun AccompanistSampleTheme(
54 | darkTheme: Boolean = isSystemInDarkTheme(),
55 | content: @Composable () -> Unit
56 | ) {
57 | MaterialTheme(
58 | colorScheme = if (darkTheme) darkColorScheme() else lightColorScheme(),
59 | content = content
60 | )
61 | }
62 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/adaptive/BasicTwoPaneSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.adaptive
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Box
23 | import androidx.compose.foundation.layout.fillMaxSize
24 | import androidx.compose.foundation.layout.padding
25 | import androidx.compose.material3.Card
26 | import androidx.compose.material3.Text
27 | import androidx.compose.ui.Alignment
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.unit.dp
30 | import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy
31 | import com.google.accompanist.adaptive.TwoPane
32 | import com.google.accompanist.adaptive.TwoPaneStrategy
33 | import com.google.accompanist.adaptive.VerticalTwoPaneStrategy
34 | import com.google.accompanist.adaptive.calculateDisplayFeatures
35 | import com.google.accompanist.sample.AccompanistSample
36 |
37 | class BasicTwoPaneSample : ComponentActivity() {
38 | override fun onCreate(savedInstanceState: Bundle?) {
39 | super.onCreate(savedInstanceState)
40 | setContent {
41 | AccompanistSample {
42 | val displayFeatures = calculateDisplayFeatures(this)
43 |
44 | TwoPane(
45 | first = {
46 | Card(
47 | modifier = Modifier.padding(8.dp)
48 | ) {
49 | Box(
50 | contentAlignment = Alignment.Center,
51 | modifier = Modifier.fillMaxSize()
52 | ) {
53 | Text("First")
54 | }
55 | }
56 | },
57 | second = {
58 | Card(
59 | modifier = Modifier.padding(8.dp)
60 | ) {
61 | Box(
62 | contentAlignment = Alignment.Center,
63 | modifier = Modifier.fillMaxSize()
64 | ) {
65 | Text("Second")
66 | }
67 | }
68 | },
69 | strategy = TwoPaneStrategy { density, layoutDirection, layoutCoordinates ->
70 | // Split vertically if the height is larger than the width
71 | if (layoutCoordinates.size.height >= layoutCoordinates.size.width) {
72 | VerticalTwoPaneStrategy(
73 | splitFraction = 0.75f
74 | )
75 | } else {
76 | HorizontalTwoPaneStrategy(
77 | splitFraction = 0.75f
78 | )
79 | }.calculateSplitResult(density, layoutDirection, layoutCoordinates)
80 | },
81 | displayFeatures = displayFeatures,
82 | modifier = Modifier.padding(8.dp)
83 | )
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/adaptive/HorizontalTwoPaneSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.adaptive
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Box
23 | import androidx.compose.foundation.layout.fillMaxSize
24 | import androidx.compose.foundation.layout.padding
25 | import androidx.compose.material3.Card
26 | import androidx.compose.material3.Text
27 | import androidx.compose.ui.Alignment
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.unit.dp
30 | import com.google.accompanist.adaptive.FoldAwareConfiguration
31 | import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy
32 | import com.google.accompanist.adaptive.TwoPane
33 | import com.google.accompanist.adaptive.calculateDisplayFeatures
34 | import com.google.accompanist.sample.AccompanistSample
35 |
36 | class HorizontalTwoPaneSample : ComponentActivity() {
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | setContent {
40 | AccompanistSample {
41 | val displayFeatures = calculateDisplayFeatures(this)
42 |
43 | TwoPane(
44 | first = {
45 | Card(
46 | modifier = Modifier.padding(8.dp)
47 | ) {
48 | Box(
49 | contentAlignment = Alignment.Center,
50 | modifier = Modifier.fillMaxSize()
51 | ) {
52 | Text("First")
53 | }
54 | }
55 | },
56 | second = {
57 | Card(
58 | modifier = Modifier.padding(8.dp)
59 | ) {
60 | Box(
61 | contentAlignment = Alignment.Center,
62 | modifier = Modifier.fillMaxSize()
63 | ) {
64 | Text("Second")
65 | }
66 | }
67 | },
68 | strategy = HorizontalTwoPaneStrategy(
69 | splitFraction = 1f / 3f,
70 | ),
71 | displayFeatures = displayFeatures,
72 | foldAwareConfiguration = FoldAwareConfiguration.VerticalFoldsOnly,
73 | modifier = Modifier.padding(8.dp)
74 | )
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/adaptive/NavDrawerFoldAwareColumnSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.adaptive
18 |
19 | import android.app.Activity
20 | import android.os.Bundle
21 | import androidx.activity.ComponentActivity
22 | import androidx.activity.compose.setContent
23 | import androidx.compose.foundation.border
24 | import androidx.compose.foundation.layout.PaddingValues
25 | import androidx.compose.foundation.layout.fillMaxSize
26 | import androidx.compose.foundation.layout.padding
27 | import androidx.compose.foundation.shape.CircleShape
28 | import androidx.compose.material.icons.Icons
29 | import androidx.compose.material.icons.filled.Done
30 | import androidx.compose.material.icons.filled.Face
31 | import androidx.compose.material.icons.filled.Lock
32 | import androidx.compose.material.icons.filled.Search
33 | import androidx.compose.material.icons.filled.Star
34 | import androidx.compose.material.icons.filled.ThumbUp
35 | import androidx.compose.material.icons.filled.Warning
36 | import androidx.compose.material3.ExperimentalMaterial3Api
37 | import androidx.compose.material3.Icon
38 | import androidx.compose.material3.MaterialTheme
39 | import androidx.compose.material3.ModalDrawerSheet
40 | import androidx.compose.material3.ModalNavigationDrawer
41 | import androidx.compose.material3.NavigationDrawerItem
42 | import androidx.compose.material3.Surface
43 | import androidx.compose.material3.Text
44 | import androidx.compose.runtime.Composable
45 | import androidx.compose.runtime.getValue
46 | import androidx.compose.runtime.mutableStateOf
47 | import androidx.compose.runtime.remember
48 | import androidx.compose.runtime.setValue
49 | import androidx.compose.ui.Modifier
50 | import androidx.compose.ui.unit.dp
51 | import com.google.accompanist.adaptive.FoldAwareColumn
52 | import com.google.accompanist.adaptive.calculateDisplayFeatures
53 | import com.google.accompanist.sample.AccompanistSample
54 |
55 | class NavDrawerFoldAwareColumnSample : ComponentActivity() {
56 | override fun onCreate(savedInstanceState: Bundle?) {
57 | super.onCreate(savedInstanceState)
58 | setContent {
59 | AccompanistSample(contentPadding = PaddingValues(all = 0.dp)) {
60 | NavDrawerExample(this)
61 | }
62 | }
63 | }
64 | }
65 |
66 | @OptIn(ExperimentalMaterial3Api::class)
67 | @Composable
68 | fun NavDrawerExample(activity: Activity) {
69 | val icons = listOf(
70 | Icons.Default.Done,
71 | Icons.Default.Face,
72 | Icons.Default.Lock,
73 | Icons.Default.Search,
74 | Icons.Default.ThumbUp,
75 | Icons.Default.Warning,
76 | Icons.Default.Star
77 | )
78 |
79 | var selectedIcon by remember { mutableStateOf(icons[0]) }
80 |
81 | ModalNavigationDrawer(
82 | drawerContent = {
83 | ModalDrawerSheet {
84 | FoldAwareColumn(
85 | displayFeatures = calculateDisplayFeatures(activity),
86 | foldPadding = PaddingValues(vertical = 10.dp)
87 | ) {
88 | icons.forEach {
89 | NavigationDrawerItem(
90 | modifier = Modifier
91 | .padding(5.dp)
92 | .border(2.dp, MaterialTheme.colorScheme.primary, CircleShape),
93 | icon = { Icon(imageVector = it, contentDescription = it.name) },
94 | label = { Text(it.name.substringAfter('.')) },
95 | selected = it == selectedIcon,
96 | onClick = { selectedIcon = it }
97 | )
98 | }
99 | }
100 | }
101 | },
102 | content = { Surface(modifier = Modifier.fillMaxSize()) {} }
103 | )
104 | }
105 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/adaptive/NavRailFoldAwareColumnSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.adaptive
18 |
19 | import android.app.Activity
20 | import android.os.Bundle
21 | import androidx.activity.ComponentActivity
22 | import androidx.activity.compose.setContent
23 | import androidx.compose.foundation.border
24 | import androidx.compose.foundation.layout.Row
25 | import androidx.compose.foundation.layout.fillMaxSize
26 | import androidx.compose.foundation.layout.padding
27 | import androidx.compose.material.icons.Icons
28 | import androidx.compose.material.icons.filled.Done
29 | import androidx.compose.material.icons.filled.Face
30 | import androidx.compose.material.icons.filled.Lock
31 | import androidx.compose.material.icons.filled.Search
32 | import androidx.compose.material.icons.filled.Star
33 | import androidx.compose.material.icons.filled.ThumbUp
34 | import androidx.compose.material.icons.filled.Warning
35 | import androidx.compose.material3.Icon
36 | import androidx.compose.material3.MaterialTheme
37 | import androidx.compose.material3.NavigationRail
38 | import androidx.compose.material3.NavigationRailItem
39 | import androidx.compose.material3.Surface
40 | import androidx.compose.material3.Text
41 | import androidx.compose.runtime.Composable
42 | import androidx.compose.runtime.getValue
43 | import androidx.compose.runtime.mutableStateOf
44 | import androidx.compose.runtime.remember
45 | import androidx.compose.runtime.setValue
46 | import androidx.compose.ui.Modifier
47 | import androidx.compose.ui.unit.dp
48 | import com.google.accompanist.adaptive.FoldAwareColumn
49 | import com.google.accompanist.adaptive.calculateDisplayFeatures
50 | import com.google.accompanist.sample.AccompanistSample
51 |
52 | class NavRailFoldAwareColumnSample : ComponentActivity() {
53 | override fun onCreate(savedInstanceState: Bundle?) {
54 | super.onCreate(savedInstanceState)
55 | setContent {
56 | AccompanistSample {
57 | Row {
58 | NavRail(this@NavRailFoldAwareColumnSample)
59 | Surface(modifier = Modifier.fillMaxSize()) {}
60 | }
61 | }
62 | }
63 | }
64 | }
65 |
66 | @Composable
67 | fun NavRail(activity: Activity) {
68 | val icons = listOf(
69 | Icons.Default.Done,
70 | Icons.Default.Face,
71 | Icons.Default.Lock,
72 | Icons.Default.Search,
73 | Icons.Default.ThumbUp,
74 | Icons.Default.Warning,
75 | Icons.Default.Star
76 | )
77 |
78 | var selectedIcon by remember { mutableStateOf(icons[0]) }
79 |
80 | NavigationRail {
81 | FoldAwareColumn(displayFeatures = calculateDisplayFeatures(activity)) {
82 | icons.forEach {
83 | NavigationRailItem(
84 | modifier = Modifier
85 | .padding(5.dp)
86 | .border(2.dp, MaterialTheme.colorScheme.primary),
87 | selected = it == selectedIcon,
88 | onClick = { selectedIcon = it },
89 | icon = { Icon(imageVector = it, contentDescription = it.name) },
90 | label = { Text(it.name.substringAfter('.')) }
91 | )
92 | }
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/adaptive/VerticalTwoPaneSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.adaptive
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Box
23 | import androidx.compose.foundation.layout.fillMaxSize
24 | import androidx.compose.foundation.layout.padding
25 | import androidx.compose.material3.Card
26 | import androidx.compose.material3.Text
27 | import androidx.compose.ui.Alignment
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.unit.dp
30 | import com.google.accompanist.adaptive.FoldAwareConfiguration
31 | import com.google.accompanist.adaptive.TwoPane
32 | import com.google.accompanist.adaptive.VerticalTwoPaneStrategy
33 | import com.google.accompanist.adaptive.calculateDisplayFeatures
34 | import com.google.accompanist.sample.AccompanistSample
35 |
36 | class VerticalTwoPaneSample : ComponentActivity() {
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 | setContent {
40 | AccompanistSample {
41 | val displayFeatures = calculateDisplayFeatures(this)
42 |
43 | TwoPane(
44 | first = {
45 | Card(
46 | modifier = Modifier.padding(8.dp)
47 | ) {
48 | Box(
49 | contentAlignment = Alignment.Center,
50 | modifier = Modifier.fillMaxSize()
51 | ) {
52 | Text("First")
53 | }
54 | }
55 | },
56 | second = {
57 | Card(
58 | modifier = Modifier.padding(8.dp)
59 | ) {
60 | Box(
61 | contentAlignment = Alignment.Center,
62 | modifier = Modifier.fillMaxSize()
63 | ) {
64 | Text("Second")
65 | }
66 | }
67 | },
68 | strategy = VerticalTwoPaneStrategy(
69 | splitOffset = 200.dp,
70 | ),
71 | displayFeatures = displayFeatures,
72 | foldAwareConfiguration = FoldAwareConfiguration.HorizontalFoldsOnly,
73 | modifier = Modifier.padding(8.dp)
74 | )
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/drawablepainter/DocSamples.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.drawablepainter
18 |
19 | import androidx.compose.foundation.Image
20 | import androidx.compose.runtime.Composable
21 | import androidx.compose.ui.platform.LocalContext
22 | import androidx.core.content.ContextCompat
23 | import com.google.accompanist.drawablepainter.rememberDrawablePainter
24 | import com.google.accompanist.sample.R
25 |
26 | @Composable
27 | fun BasicSample() {
28 | val drawable = ContextCompat.getDrawable(LocalContext.current, R.drawable.rectangle)
29 |
30 | Image(
31 | painter = rememberDrawablePainter(drawable = drawable),
32 | contentDescription = "content description",
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/permissions/RequestLocationPermissionsSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.permissions
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Column
23 | import androidx.compose.foundation.layout.Spacer
24 | import androidx.compose.foundation.layout.height
25 | import androidx.compose.material3.Button
26 | import androidx.compose.material3.Text
27 | import androidx.compose.runtime.Composable
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.unit.dp
30 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
31 | import com.google.accompanist.permissions.rememberMultiplePermissionsState
32 | import com.google.accompanist.sample.AccompanistSample
33 |
34 | class RequestLocationPermissionsSample : ComponentActivity() {
35 | override fun onCreate(savedInstanceState: Bundle?) {
36 | super.onCreate(savedInstanceState)
37 |
38 | setContent {
39 | AccompanistSample {
40 | Sample()
41 | }
42 | }
43 | }
44 | }
45 |
46 | @OptIn(ExperimentalPermissionsApi::class)
47 | @Composable
48 | private fun Sample() {
49 | val locationPermissionsState = rememberMultiplePermissionsState(
50 | listOf(
51 | android.Manifest.permission.ACCESS_COARSE_LOCATION,
52 | android.Manifest.permission.ACCESS_FINE_LOCATION,
53 | )
54 | )
55 |
56 | if (locationPermissionsState.allPermissionsGranted) {
57 | Text("Thanks! I can access your exact location :D")
58 | } else {
59 | Column {
60 | val allPermissionsRevoked =
61 | locationPermissionsState.permissions.size ==
62 | locationPermissionsState.revokedPermissions.size
63 |
64 | val textToShow = if (!allPermissionsRevoked) {
65 | // If not all the permissions are revoked, it's because the user accepted the COARSE
66 | // location permission, but not the FINE one.
67 | "Yay! Thanks for letting me access your approximate location. " +
68 | "But you know what would be great? If you allow me to know where you " +
69 | "exactly are. Thank you!"
70 | } else if (locationPermissionsState.shouldShowRationale) {
71 | // Both location permissions have been denied
72 | "Getting your exact location is important for this app. " +
73 | "Please grant us fine location. Thank you :D"
74 | } else {
75 | // First time the user sees this feature or the user doesn't want to be asked again
76 | "This feature requires location permission"
77 | }
78 |
79 | val buttonText = if (!allPermissionsRevoked) {
80 | "Allow precise location"
81 | } else {
82 | "Request permissions"
83 | }
84 |
85 | Text(text = textToShow)
86 | Spacer(modifier = Modifier.height(8.dp))
87 | Button(onClick = { locationPermissionsState.launchMultiplePermissionRequest() }) {
88 | Text(buttonText)
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/permissions/RequestMultiplePermissionsSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.permissions
18 |
19 | import android.Manifest
20 | import android.os.Bundle
21 | import androidx.activity.ComponentActivity
22 | import androidx.activity.compose.setContent
23 | import androidx.compose.foundation.layout.Column
24 | import androidx.compose.foundation.layout.Spacer
25 | import androidx.compose.foundation.layout.height
26 | import androidx.compose.material3.Button
27 | import androidx.compose.material3.Text
28 | import androidx.compose.runtime.Composable
29 | import androidx.compose.ui.Modifier
30 | import androidx.compose.ui.unit.dp
31 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
32 | import com.google.accompanist.permissions.MultiplePermissionsState
33 | import com.google.accompanist.permissions.PermissionState
34 | import com.google.accompanist.permissions.rememberMultiplePermissionsState
35 | import com.google.accompanist.sample.AccompanistSample
36 |
37 | @OptIn(ExperimentalPermissionsApi::class)
38 | class RequestMultiplePermissionsSample : ComponentActivity() {
39 | override fun onCreate(savedInstanceState: Bundle?) {
40 | super.onCreate(savedInstanceState)
41 |
42 | setContent {
43 | AccompanistSample {
44 | val multiplePermissionsState = rememberMultiplePermissionsState(
45 | listOf(
46 | Manifest.permission.RECORD_AUDIO,
47 | Manifest.permission.CAMERA,
48 | )
49 | )
50 | Sample(multiplePermissionsState)
51 | }
52 | }
53 | }
54 | }
55 |
56 | @OptIn(ExperimentalPermissionsApi::class)
57 | @Composable
58 | private fun Sample(multiplePermissionsState: MultiplePermissionsState) {
59 | if (multiplePermissionsState.allPermissionsGranted) {
60 | // If all permissions are granted, then show screen with the feature enabled
61 | Text("Camera and Read storage permissions Granted! Thank you!")
62 | } else {
63 | Column {
64 | Text(
65 | getTextToShowGivenPermissions(
66 | multiplePermissionsState.revokedPermissions,
67 | multiplePermissionsState.shouldShowRationale
68 | )
69 | )
70 | Spacer(modifier = Modifier.height(8.dp))
71 | Button(onClick = { multiplePermissionsState.launchMultiplePermissionRequest() }) {
72 | Text("Request permissions")
73 | }
74 | }
75 | }
76 | }
77 |
78 | @OptIn(ExperimentalPermissionsApi::class)
79 | private fun getTextToShowGivenPermissions(
80 | permissions: List,
81 | shouldShowRationale: Boolean
82 | ): String {
83 | val revokedPermissionsSize = permissions.size
84 | if (revokedPermissionsSize == 0) return ""
85 |
86 | val textToShow = StringBuilder().apply {
87 | append("The ")
88 | }
89 |
90 | for (i in permissions.indices) {
91 | textToShow.append(permissions[i].permission)
92 | when {
93 | revokedPermissionsSize > 1 && i == revokedPermissionsSize - 2 -> {
94 | textToShow.append(", and ")
95 | }
96 | i == revokedPermissionsSize - 1 -> {
97 | textToShow.append(" ")
98 | }
99 | else -> {
100 | textToShow.append(", ")
101 | }
102 | }
103 | }
104 | textToShow.append(if (revokedPermissionsSize == 1) "permission is" else "permissions are")
105 | textToShow.append(
106 | if (shouldShowRationale) {
107 | " important. Please grant all of them for the app to function properly."
108 | } else {
109 | " denied. The app cannot function without them."
110 | }
111 | )
112 | return textToShow.toString()
113 | }
114 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/google/accompanist/sample/permissions/RequestPermissionSample.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 The Android Open Source Project
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 | * https://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 com.google.accompanist.sample.permissions
18 |
19 | import android.os.Bundle
20 | import androidx.activity.ComponentActivity
21 | import androidx.activity.compose.setContent
22 | import androidx.compose.foundation.layout.Column
23 | import androidx.compose.foundation.layout.Spacer
24 | import androidx.compose.foundation.layout.height
25 | import androidx.compose.material3.Button
26 | import androidx.compose.material3.Text
27 | import androidx.compose.runtime.Composable
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.unit.dp
30 | import com.google.accompanist.permissions.ExperimentalPermissionsApi
31 | import com.google.accompanist.permissions.isGranted
32 | import com.google.accompanist.permissions.rememberPermissionState
33 | import com.google.accompanist.permissions.shouldShowRationale
34 | import com.google.accompanist.sample.AccompanistSample
35 |
36 | class RequestPermissionSample : ComponentActivity() {
37 | override fun onCreate(savedInstanceState: Bundle?) {
38 | super.onCreate(savedInstanceState)
39 |
40 | setContent {
41 | AccompanistSample {
42 | Sample()
43 | }
44 | }
45 | }
46 | }
47 |
48 | @OptIn(ExperimentalPermissionsApi::class)
49 | @Composable
50 | private fun Sample() {
51 | val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA)
52 | if (cameraPermissionState.status.isGranted) {
53 | Text("Camera permission Granted")
54 | } else {
55 | Column {
56 | val textToShow = if (cameraPermissionState.status.shouldShowRationale) {
57 | "The camera is important for this app. Please grant the permission."
58 | } else {
59 | "Camera not available"
60 | }
61 |
62 | Text(textToShow)
63 | Spacer(modifier = Modifier.height(8.dp))
64 | Button(onClick = { cameraPermissionState.launchPermissionRequest() }) {
65 | Text("Request permission")
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-nodpi/placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/drawable-nodpi/placeholder.jpg
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
28 |
29 |
35 |
38 |
41 |
42 |
43 |
44 |
50 |
51 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/alpha.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/drawable/alpha.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/rectangle.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/accompanist/fda7f06a24a42b0b1afa75591e768d82d2941984/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | هذا مضمون \n%s
19 |
20 |
--------------------------------------------------------------------------------
/scripts/run-tests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Copyright 2021 The Android Open Source Project
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # https://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | # Fail on error and print out commands
18 | set -ex
19 |
20 | # By default we don't shard
21 | SHARD_COUNT=0
22 | SHARD_INDEX=0
23 | # By default we don't log
24 | LOG_FILE=""
25 | # By default we run tests on device
26 | DEVICE=true
27 |
28 | # Parse parameters
29 | for i in "$@"; do
30 | case $i in
31 | --shard-count=*)
32 | SHARD_COUNT="${i#*=}"
33 | shift
34 | ;;
35 | --unit-tests)
36 | DEVICE=false
37 | shift
38 | ;;
39 | --shard-index=*)
40 | SHARD_INDEX="${i#*=}"
41 | shift
42 | ;;
43 | --log-file=*)
44 | LOG_FILE="${i#*=}"
45 | shift
46 | ;;
47 | --run-affected)
48 | RUN_AFFECTED=true
49 | shift
50 | ;;
51 | --run-flaky-tests)
52 | RUN_FLAKY=true
53 | shift
54 | ;;
55 | --affected-base-ref=*)
56 | BASE_REF="${i#*=}"
57 | shift
58 | ;;
59 | *)
60 | echo "Unknown option"
61 | exit 1
62 | ;;
63 | esac
64 | done
65 |
66 | # Start logcat if we have a file to log to
67 | if [[ ! -z "$LOG_FILE" ]]; then
68 | adb logcat >$LOG_FILE &
69 | fi
70 |
71 | FILTER_OPTS=""
72 | # Filter out flaky tests if we're not set to run them
73 | if [[ -z "$RUN_FLAKY" ]]; then
74 | FILTER_OPTS="$FILTER_OPTS -Pandroid.testInstrumentationRunnerArguments.notAnnotation=androidx.test.filters.FlakyTest"
75 | fi
76 |
77 | # If we're set to only run affected test, update the Gradle task
78 | if [[ ! -z "$RUN_AFFECTED" ]]; then
79 | if [ "$DEVICE" = true ]; then
80 | TASK="runAffectedAndroidTests"
81 | else
82 | TASK="runAffectedUnitTests"
83 | fi
84 | TASK="$TASK -Paffected_module_detector.enable"
85 |
86 | # If we have a base branch set, add the Gradle property
87 | if [[ ! -z "$BASE_REF" ]]; then
88 | TASK="$TASK -Paffected_base_ref=$BASE_REF"
89 | fi
90 | fi
91 |
92 | # If we don't have a task yet, use the defaults
93 | if [[ -z "$TASK" ]]; then
94 | if [ "$DEVICE" = true ]; then
95 | TASK="connectedCheck"
96 | else
97 | TASK="testDebug"
98 | fi
99 | fi
100 |
101 | SHARD_OPTS=""
102 | if [ "$SHARD_COUNT" -gt "0" ]; then
103 | # If we have a shard count value, create the necessary Gradle property args.
104 | # We assume that SHARD_INDEX has been set too
105 | SHARD_OPTS="$SHARD_OPTS -Pandroid.testInstrumentationRunnerArguments.numShards=$SHARD_COUNT"
106 | SHARD_OPTS="$SHARD_OPTS -Pandroid.testInstrumentationRunnerArguments.shardIndex=$SHARD_INDEX"
107 | fi
108 |
109 | ./gradlew --scan --continue --no-configuration-cache --stacktrace $TASK $FILTER_OPTS $SHARD_OPTS
110 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2023 The Android Open Source Project
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 | * https://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 | pluginManagement {
18 | includeBuild("build-logic")
19 | repositories {
20 | google()
21 | mavenCentral()
22 | gradlePluginPortal()
23 | }
24 | }
25 |
26 | dependencyResolutionManagement {
27 | repositories {
28 | google()
29 | mavenCentral()
30 | }
31 | }
32 |
33 | include(":adaptive")
34 | include(":internal-testutils")
35 | include(":drawablepainter")
36 | include(":permissions")
37 | include(":permissions-lint")
38 | include(":sample")
39 |
40 | rootProject.name = "accompanist"
41 |
42 | check(JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
43 | """
44 | Accompanist requires JDK 17+ but it is currently using JDK ${JavaVersion.current()}.
45 | Java Home: [${System.getProperty("java.home")}]
46 | https://developer.android.com/build/jdks#jdk-config-in-studio
47 | """.trimIndent()
48 | }
--------------------------------------------------------------------------------
/spotless/copyright.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright $YEAR The Android Open Source Project
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 | * https://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 |
--------------------------------------------------------------------------------
/spotless/greclipse.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2020 The Android Open Source Project
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 | # https://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 | #Whether to use 'space', 'tab' or 'mixed' (both) characters for indentation.
18 | #The default value is 'tab'.
19 | org.eclipse.jdt.core.formatter.tabulation.char=space
20 |
21 | #Number of spaces used for indentation in case 'space' characters
22 | #have been selected. The default value is 4.
23 | org.eclipse.jdt.core.formatter.tabulation.size=4
24 |
25 | #Number of spaces used for indentation in case 'mixed' characters
26 | #have been selected. The default value is 4.
27 | org.eclipse.jdt.core.formatter.indentation.size=4
28 |
29 | #Whether or not indentation characters are inserted into empty lines.
30 | #The default value is 'true'.
31 | org.eclipse.jdt.core.formatter.indent_empty_lines=false
32 |
33 | #Number of spaces used for multiline indentation.
34 | #The default value is 2.
35 | groovy.formatter.multiline.indentation=2
36 |
37 | #Length after which list are considered too long. These will be wrapped.
38 | #The default value is 30.
39 | groovy.formatter.longListLength=30
40 |
41 | #Whether opening braces position shall be the next line.
42 | #The default value is 'same'.
43 | groovy.formatter.braces.start=same
44 |
45 | #Whether closing braces position shall be the next line.
46 | #The default value is 'next'.
47 | groovy.formatter.braces.end=next
48 |
49 | #Remove unnecessary semicolons. The default value is 'false'.
50 | groovy.formatter.remove.unnecessary.semicolons=false
--------------------------------------------------------------------------------