diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3cea8b4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 +updates: + # Gradle (version catalog, plugins and wrapper) + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "weekly" + day: "wednesday" + open-pull-requests-limit: 10 + groups: + gradle: + patterns: + - "*" # Prefer a single PR per dependency update round. + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "wednesday" + open-pull-requests-limit: 10 + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..73f8143 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,269 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: # Allows manual trigger of the workflow + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + JAVA_VERSION: '17' + # Robolectric needs JDK 21 to run on the latest Android SDKs + TEST_JAVA_VERSION: '21' + +# Stages: Resolve Version -> Test (lowest and latest Android SDK) -> Build library & sample app -> Tag & Release +# The Test report job publishes the JUnit results of every SDK, also when the tests fail. +# Every stage must succeed for the next one to start. +jobs: + version: + name: Resolve Version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.resolve.outputs.version }} + tag_exists: ${{ steps.resolve.outputs.tag_exists }} + + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Read version from gradle.properties + id: resolve + shell: bash + run: | + VERSION=$(sed -n 's/^VERSION_NAME=\(.*\)$/\1/p' gradle.properties | head -1) + if [ -z "$VERSION" ]; then + echo "::error file=gradle.properties::No VERSION_NAME found" + exit 1 + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + if git ls-remote --exit-code --tags origin "refs/tags/$VERSION" >/dev/null 2>&1; then + echo "tag_exists=true" >> "$GITHUB_OUTPUT" + echo "::notice::Tag $VERSION already present - skip release" + else + echo "tag_exists=false" >> "$GITHUB_OUTPUT" + fi + + echo "### Version \`$VERSION\`" >> "$GITHUB_STEP_SUMMARY" + + test: + name: Test (SDK ${{ matrix.sdk }}) + runs-on: ubuntu-latest + needs: [version] + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + # Android version the Robolectric unit tests run on: the lowest one Robolectric supports + # (23, the library minSdk 21 is no longer supported by Robolectric) and the latest one. + sdk: [23, 37] + + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Setup JDK + uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: ${{ env.TEST_JAVA_VERSION }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + + - name: Select Robolectric SDK + run: echo "sdk=${{ matrix.sdk }}" > flowlayoutmanager/src/test/resources/robolectric.properties + + - name: Test + run: ./gradlew :flowlayoutmanager:testDebugUnitTest + + # Read by the report job + - name: Upload JUnit results + if: always() + uses: actions/upload-artifact@v7 + with: + name: junit-sdk${{ matrix.sdk }} + path: flowlayoutmanager/build/test-results/testDebugUnitTest/*.xml + if-no-files-found: warn + + - name: Upload HTML report + if: failure() + uses: actions/upload-artifact@v7 + with: + name: test-report-sdk${{ matrix.sdk }} + path: flowlayoutmanager/build/reports/tests/ + if-no-files-found: ignore + + report: + name: Test report + runs-on: ubuntu-latest + needs: [test] + if: always() + permissions: + contents: read + actions: read # download the JUnit artifacts + checks: write # publish a check run per SDK + + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + # One check run per junit-sdk artifact, "Unit Tests Result (SDK )" + - name: Publish Unit Tests Result + uses: dorny/test-reporter@v1 + with: + name: Unit Tests Result (SDK $1) + artifact: /junit-sdk(.*)/ + path: '**/*.xml' + reporter: java-junit + fail-on-error: true + # Recent v1 releases default to the job summary only: create the check runs with their state + use-actions-summary: false + + build: + name: Build library & sample app + runs-on: ubuntu-latest + needs: [version, test] + timeout-minutes: 30 + env: + VERSION: ${{ needs.version.outputs.version }} + ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} + ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} + ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} + ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} + + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Setup JDK + uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: ${{ env.JAVA_VERSION }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + + - name: Prepare signing key + if: env.ANDROID_KEYSTORE_BASE64 != '' && github.event_name != 'pull_request' + run: | + echo "$ANDROID_KEYSTORE_BASE64" | base64 -d > "$RUNNER_TEMP/release.keystore" + echo "ANDROID_KEYSTORE_FILE=$RUNNER_TEMP/release.keystore" >> "$GITHUB_ENV" + + - name: Build + run: | + ./gradlew \ + :flowlayoutmanager:assembleRelease \ + :flowlayoutmanager:publishToMavenLocal \ + :app:assembleDebug \ + :app:assembleRelease + + - name: Package + run: | + mkdir -p dist + cp flowlayoutmanager/build/outputs/aar/flowlayoutmanager-release.aar "dist/FlowLayoutManager-${VERSION}.aar" + + # Signed release APK when a keystore is configured, debug APK otherwise + # (an unsigned APK cannot be installed). + APK="$(find app/build/outputs/apk/release -name '*.apk' ! -name '*unsigned*' -print -quit)" + [ -n "$APK" ] || APK="$(find app/build/outputs/apk/debug -name '*.apk' -print -quit)" + if [ -z "$APK" ]; then + echo "::error::No APK produced" + exit 1 + fi + cp "$APK" "dist/FlowLayoutManager-sample-${VERSION}.apk" + ls -lh dist + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: flowlayoutmanager-${{ env.VERSION }} + path: dist/* + if-no-files-found: error + + release: + name: Tag & Release + runs-on: ubuntu-latest + needs: [version, build] + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' + permissions: + contents: write + statuses: write + id-token: write + attestations: write + env: + VERSION: ${{ needs.version.outputs.version }} + + steps: + - uses: actions/checkout@v7 + + - name: Download artifacts + uses: actions/download-artifact@v8 + with: + name: flowlayoutmanager-${{ env.VERSION }} + path: release + + - name: Checksums + run: | + cd release + sha256sum * > SHA256SUMS + cat SHA256SUMS + + - name: Attest build provenance + uses: actions/attest-build-provenance@v4 + with: + subject-path: 'release/*.aar, release/*.apk' + + - name: Tag release + id: tag + if: needs.version.outputs.tag_exists != 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag "$VERSION" + git push origin "$VERSION" + + - name: Create GitHub Release + id: gh_release + if: steps.tag.outcome == 'success' + uses: softprops/action-gh-release@v3 + with: + tag_name: ${{ env.VERSION }} + name: ${{ env.VERSION }} + generate_release_notes: true + files: release/* + + - name: Report release status + if: always() + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if [ "${{ needs.version.outputs.tag_exists }}" = "true" ]; then + STATE=pending + DESCRIPTION="Version $VERSION already released - bump VERSION_NAME in gradle.properties." + elif [ "${{ steps.gh_release.outcome }}" = "success" ]; then + STATE=success + DESCRIPTION="Released $VERSION with library AAR and sample APK." + else + STATE=failure + DESCRIPTION="Release failed with an unexpected error." + fi + gh api repos/${{ github.repository }}/statuses/${{ github.sha }} \ + -f state="$STATE" \ + -f description="$DESCRIPTION" \ + -f context="release" diff --git a/.gitignore b/.gitignore index 8596cd5..ff6c74c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,82 +1,23 @@ -# Built application files -*.apk -*.ap_ - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ - -# Gradle files +# Gradle .gradle/ build/ +.kotlin/ # Local configuration file (sdk path, etc) local.properties -# Windows thumbnail db -Thumbs.db - -# Windows thumbnail db -Thumbs.db - -# OSX files -.DS_Store - -# Proguard folder generated by Eclipse -proguard/ - -# Log Files -*.log - -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder -captures/ - -# IntelliJ -*.iml +# Android Studio / IntelliJ .idea/ -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/dictionaries -.idea/libraries -.idea/* -*/.idea/* - -# Keystore files -# Uncomment the following line if you do not want to check your keystore files in. -#*.jks - -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild - -# Google Services (e.g. APIs or Firebase) -google-services.json - -# Freeline -freeline.py -freeline/ -freeline_project_description.json - -# Android Studio *.iml -.idea -#.idea/workspace.xml - remove # and delete .idea if it better suit your needs. -.gradle -build/ -.navigation captures/ -output.json +.externalNativeBuild/ +.cxx/ -#NDK -obj/ -.externalNativeBuild \ No newline at end of file +# Build outputs +*.apk +*.aab +*.ap_ +*.dex + +# OS files +.DS_Store diff --git a/FlowLayoutManager.zip b/FlowLayoutManager.zip deleted file mode 100644 index 22b00e9..0000000 Binary files a/FlowLayoutManager.zip and /dev/null differ diff --git a/README.md b/README.md index fd1e051..05f8232 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,42 @@ # FlowLayoutManager + +[![CI](https://github.com/simonebortolin/FlowLayoutManager/actions/workflows/ci.yml/badge.svg)](https://github.com/simonebortolin/FlowLayoutManager/actions/workflows/ci.yml) [![](https://jitpack.io/v/simonebortolin/FlowLayoutManager.svg)](https://jitpack.io/#simonebortolin/FlowLayoutManager) +[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg)](https://developer.android.com/about/versions/lollipop) Android 3rd party library to make implementing a FlowLayoutManager -FlowLayoutManager is a layoutManager that works with Android ___RecyclerView___ Widget, to layout views in flow style, with support of ___predictive animations___, item per line limit, auto measurement & alignments (left or right) +FlowLayoutManager is a layoutManager that works with Android ___RecyclerView___ Widget, to layout views in flow style, with support of ___predictive animations___, item per line limit, max lines limit, auto measurement & alignments (left, center or right). Supports min SDK 21. ## Screenshots - - - + + + ## Installation -Step 1. Add it in your **root** build.gradle at the end of repositories: +Add remote maven url (in `settings.gradle`) + +```groovy + dependencyResolutionManagement { + repositories { + google() + mavenCentral() + maven { url "https://jitpack.io" } + } + } +``` - allprojects { - repositories { - ... - maven { url 'https://jitpack.io' } - } - } +Every release also ships the `.aar` and the sample app `.apk` on the [Releases page](https://github.com/simonebortolin/FlowLayoutManager/releases). -Step 2. Add the dependency +Now add a library dependency (remember to check for latest release) - dependencies { - implementation 'com.github.simonebortolin:FlowLayoutManager:1.8.0' - } +```groovy + dependencies { + implementation 'com.github.simonebortolin:FlowLayoutManager:1.9.0' + } +``` Item per line limitation --- @@ -57,6 +67,26 @@ to remove Item per line limitation (recyclerView.getLayoutManager() as FlowLayoutManager).removeItemPerLineLimit() ``` +Max lines limitation +--- +Show at most x lines, the items that do not fit are not laid out +```java +recyclerView.setLayoutManager(new FlowLayoutManager().maxLines(x)); +``` + +```kotlin +recyclerView.setLayoutManager(FlowLayoutManager().maxLines(x)) +``` + +to remove max lines limitation +```java +((FlowLayoutManager)recyclerView.getLayoutManager()).removeMaxLinesLimit(); +``` + +```kotlin +(recyclerView.getLayoutManager() as FlowLayoutManager).removeMaxLinesLimit() +``` + Auto measurement --- ```java @@ -84,7 +114,25 @@ Alignment could be LEFT, CENTER or RIGHT. ## Credits -I thank all the authors of the various commits that I have included in my fork +I thank all the authors of the various commits that I have included in my fork, in particular: + +* [xiaofeng-han/AndroidLibs](https://github.com/xiaofeng-han/AndroidLibs), the original library +* [davidleen](https://github.com/davidleen/FlowLayoutManager) for the max lines limit +* [hees-k](https://github.com/hees-k/FlowLayoutManager) and [idindevelop](https://github.com/idindevelop/FlowLayoutManager) for the build updates + +## Build + +The project builds with Gradle 9 / AGP 9 and JDK 17: + +```bash +./gradlew :flowlayoutmanager:testDebugUnitTest :flowlayoutmanager:assembleRelease :app:assembleDebug +``` + +Unit tests run on the JVM with [Robolectric](https://robolectric.org), so no emulator is needed; they need JDK 21 for the latest Android SDK. CI runs them on the lowest Android SDK Robolectric supports (23) and on the latest one (37), and builds the library only when they pass. + +`minSdk` is set once by `MIN_SDK` in `gradle.properties` for both the library and the sample app, and it is kept as low as the dependencies allow: the sample uses only framework widgets and RecyclerView for this reason. A dependency update that requires a higher `minSdk` makes the build fail (manifest merger), so it never raises it silently. + +CI builds the library AAR and the sample APK on every pull request; on `master` it also tags and releases the version set by `VERSION_NAME` in `gradle.properties` (bump it to release). ## License diff --git a/app/build.gradle b/app/build.gradle index 3bd38d0..bf6e7aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,37 +1,46 @@ -apply plugin: 'com.android.application' +plugins { + alias(libs.plugins.android.application) +} android { - compileSdkVersion androidCompileSdkVersion - - buildToolsVersion buildToolsVersion + namespace = 'com.xiaofeng.androidlibs' + compileSdk = 37 defaultConfig { - applicationId "com.xiaofeng.androidlibs" - minSdkVersion androidMinSdkVersion - targetSdkVersion androidTargetSdkVersion - versionCode versionCode - versionName versionName - vectorDrawables.useSupportLibrary = true + applicationId = 'com.xiaofeng.androidlibs' + minSdk = MIN_SDK as int + targetSdk = 37 + versionCode = VERSION_CODE as int + versionName = VERSION_NAME } + + signingConfigs { + release { + def keystore = System.getenv('ANDROID_KEYSTORE_FILE') + if (keystore) { + storeFile = file(keystore) + storePassword = System.getenv('ANDROID_KEYSTORE_PASSWORD') + keyAlias = System.getenv('ANDROID_KEY_ALIAS') + keyPassword = System.getenv('ANDROID_KEY_PASSWORD') + } + } + } + buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + // Unsigned when no keystore is provided (e.g. pull requests and forks). + if (System.getenv('ANDROID_KEYSTORE_FILE')) { + signingConfig = signingConfigs.release + } } } + compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } } dependencies { - implementation project(":flowlayoutmanager") - - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.vectordrawable:vectordrawable:1.1.0' - implementation(group: 'com.google.android.material', name: 'material', version: supportLibVersion) - implementation(group: 'androidx.appcompat', name: 'appcompat', version: supportLibVersion) - implementation(group: 'androidx.recyclerview', name: 'recyclerview', version: supportLibVersion) - implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation project(':flowlayoutmanager') } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro deleted file mode 100644 index 91b85dd..0000000 --- a/app/proguard-rules.pro +++ /dev/null @@ -1,17 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /home/xiaofeng/Android/Sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/app/src/androidTest/java/com/xiaofeng/androidlibs/ApplicationTest.java b/app/src/androidTest/java/com/xiaofeng/androidlibs/ApplicationTest.java deleted file mode 100644 index b2541f4..0000000 --- a/app/src/androidTest/java/com/xiaofeng/androidlibs/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.xiaofeng.androidlibs; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - * Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ff4a0cb..06b54d3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + + android:exported="true" + android:label="@string/app_name"> @@ -20,4 +19,4 @@ - \ No newline at end of file + diff --git a/app/src/main/java/com/xiaofeng/androidlibs/DemoAdapter.java b/app/src/main/java/com/xiaofeng/androidlibs/DemoAdapter.java index 00a7dc1..7eb61d7 100644 --- a/app/src/main/java/com/xiaofeng/androidlibs/DemoAdapter.java +++ b/app/src/main/java/com/xiaofeng/androidlibs/DemoAdapter.java @@ -39,7 +39,7 @@ public void onBindViewHolder(@NonNull final DemoViewHolder holder, final int pos holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - int adapterPosition = holder.getAdapterPosition(); + int adapterPosition = holder.getBindingAdapterPosition(); if(adapterPosition >= 0 && adapterPosition < items.size()) { items.remove(adapterPosition); notifyItemRemoved(adapterPosition); @@ -49,7 +49,7 @@ public void onClick(View v) { holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { - int adapterPosition = holder.getAdapterPosition(); + int adapterPosition = holder.getBindingAdapterPosition(); if(adapterPosition >= 0 && adapterPosition < items.size()) { List newItems = DemoUtil.listWords(); items.addAll(adapterPosition, newItems); diff --git a/app/src/main/java/com/xiaofeng/androidlibs/MainActivity.java b/app/src/main/java/com/xiaofeng/androidlibs/MainActivity.java index 7c517cb..b40de5e 100644 --- a/app/src/main/java/com/xiaofeng/androidlibs/MainActivity.java +++ b/app/src/main/java/com/xiaofeng/androidlibs/MainActivity.java @@ -1,21 +1,25 @@ package com.xiaofeng.androidlibs; +import android.app.Activity; import android.graphics.Rect; import android.os.Bundle; -import android.view.MenuItem; import android.view.View; import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.bottomnavigation.BottomNavigationView; import com.xiaofeng.flowlayoutmanager.Alignment; import com.xiaofeng.flowlayoutmanager.FlowLayoutManager; import java.util.Objects; -public class MainActivity extends AppCompatActivity { +/** + * Demo of FlowLayoutManager. It uses only framework widgets and RecyclerView, so that the sample + * runs on the same minSdk as the library. + */ +public class MainActivity extends Activity { + + private static final int DEMO_MAX_LINES = 3; RecyclerView recyclerView; FlowLayoutManager flowLayoutManager; @@ -27,55 +31,30 @@ public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull R } }; - private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener - = new BottomNavigationView.OnNavigationItemSelectedListener() { - - @Override - public boolean onNavigationItemSelected(@NonNull MenuItem item) { - switch (item.getItemId()) { - case R.id.navigation_left: - flowLayoutManager = new FlowLayoutManager().setAlignment(Alignment.LEFT); - flowLayoutManager.setAutoMeasureEnabled(true); - - recyclerView.setLayoutManager(flowLayoutManager); - Objects.requireNonNull(recyclerView.getAdapter()).notifyDataSetChanged(); - - return true; - case R.id.navigation_center: - flowLayoutManager = new FlowLayoutManager().setAlignment(Alignment.CENTER); - flowLayoutManager.setAutoMeasureEnabled(true); - - recyclerView.setLayoutManager(flowLayoutManager); - recyclerView.getAdapter().notifyDataSetChanged(); - - return true; - case R.id.navigation_rigth: - flowLayoutManager = new FlowLayoutManager().setAlignment(Alignment.RIGHT); - flowLayoutManager.setAutoMeasureEnabled(true); - - recyclerView.setLayoutManager(flowLayoutManager); - recyclerView.getAdapter().notifyDataSetChanged(); - - return true; - } - return false; - } - }; - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); - BottomNavigationView navigation = findViewById(R.id.navigation); - navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); recyclerView = findViewById(R.id.list); - flowLayoutManager = new FlowLayoutManager().setAlignment(Alignment.LEFT); - flowLayoutManager.setAutoMeasureEnabled(true); - recyclerView.setLayoutManager(flowLayoutManager); recyclerView.setAdapter(new DemoAdapter(DemoUtil.listWords())); - recyclerView.getAdapter().notifyDataSetChanged(); recyclerView.addItemDecoration(itemDecoration); + setLayoutManager(new FlowLayoutManager().setAlignment(Alignment.LEFT)); + + findViewById(R.id.navigation_left).setOnClickListener(v -> + setLayoutManager(new FlowLayoutManager().setAlignment(Alignment.LEFT))); + findViewById(R.id.navigation_center).setOnClickListener(v -> + setLayoutManager(new FlowLayoutManager().setAlignment(Alignment.CENTER))); + findViewById(R.id.navigation_right).setOnClickListener(v -> + setLayoutManager(new FlowLayoutManager().setAlignment(Alignment.RIGHT))); + findViewById(R.id.navigation_max_lines).setOnClickListener(v -> + setLayoutManager(new FlowLayoutManager().setAlignment(Alignment.LEFT).maxLines(DEMO_MAX_LINES))); + } + private void setLayoutManager(FlowLayoutManager layoutManager) { + flowLayoutManager = layoutManager; + flowLayoutManager.setAutoMeasureEnabled(true); + recyclerView.setLayoutManager(flowLayoutManager); + Objects.requireNonNull(recyclerView.getAdapter()).notifyDataSetChanged(); } } diff --git a/app/src/main/res/drawable-v21/ic_menu_camera.xml b/app/src/main/res/drawable-v21/ic_menu_camera.xml deleted file mode 100644 index 7d1c583..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_camera.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_gallery.xml b/app/src/main/res/drawable-v21/ic_menu_gallery.xml deleted file mode 100644 index 2f2ca2a..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_gallery.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_manage.xml b/app/src/main/res/drawable-v21/ic_menu_manage.xml deleted file mode 100644 index 065d9fa..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_manage.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_menu_send.xml b/app/src/main/res/drawable-v21/ic_menu_send.xml deleted file mode 100644 index a554657..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_send.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_share.xml b/app/src/main/res/drawable-v21/ic_menu_share.xml deleted file mode 100644 index 8151b38..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_share.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml b/app/src/main/res/drawable-v21/ic_menu_slideshow.xml deleted file mode 100644 index e750991..0000000 --- a/app/src/main/res/drawable-v21/ic_menu_slideshow.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_short_text_black_24dp.xml b/app/src/main/res/drawable/ic_short_text_black_24dp.xml new file mode 100644 index 0000000..668f2b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_short_text_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/main_activity.xml b/app/src/main/res/layout/main_activity.xml index fd32091..3fa00cb 100644 --- a/app/src/main/res/layout/main_activity.xml +++ b/app/src/main/res/layout/main_activity.xml @@ -1,36 +1,67 @@ - + android:fitsSystemWindows="true" + android:orientation="vertical"> + + + - - - + android:orientation="horizontal"> + +