diff --git a/README.md b/README.md index eb128b5..15df7da 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,39 @@ - # Showcase - -With **Showcase**, you can easily show tooltips. **Showcase** will highlight the view and show tooltip on it. You can customize title and description text fields, backgrounds and arrow positions. You can also find out how the user closed the showcase and in multi focus situations you can find out which view was clicked. +[![](https://jitpack.io/v/trendyol/showcase.svg)](https://jitpack.io/#trendyol/showcase) + + + +With **Showcase**, you can easily show tooltips. **Showcase** will highlight the view and show tooltip on it. You can +customize title and description text fields, backgrounds and arrow positions. You can also find out how the user closed +the showcase and in multi focus situations you can find out which view was clicked. + +## Installation + +- To implement **Showcase** to your Android project via Gradle, you need to add Jitpack repository to your + root `build.gradle`. -# Installation - - To implement **Showcase** to your Android project via Gradle, you need to add Jitpack repository to your root build.gradle. ``` allprojects { repositories { ... - maven { url 'https://jitpack.io' } + maven { url "https://jitpack.io" } } } ``` - - After adding Jitpack repository, you can add **Showcase** dependency to your app level build.gradle. + +- After adding Jitpack repository, you can add **Showcase** dependency to your app level `build.gradle`. + ``` dependencies { - implementation "com.trendyol.showcase:showcase:1.0.0" + implementation "com.github.trendyol::showcase:2.0.0" } ``` -# Usage +## Usage + You can easily use ShowcaseManager.Builder to create **Showcase**. + ``` val showcaseManager = ShowcaseManager.Builder() .focus(myView) @@ -53,53 +64,56 @@ val showcaseManager = ShowcaseManager.Builder() showcaseManager.show(context) // or showcaseManager.show(context, REQUEST_CODE_SHOWCASE_CLICKED) ``` -# Builder Configuration -| Usage | Description | Optional | Default Value | StyleRes | -|:-----------------------------------------------|:---------------------------------------------------------|:---------|:-----------------------------|:---------| -| `builder.focus(View)` | view to be focused on | no | null | no | -| `builder.focus(Array)` | view array to be focused on | no | null | no | -| `builder.resId(Int)` | Showcase.Theme style | yes | null | yes | -| `builder.titleText(String)` | text to be showed on top of the tooltip | yes | "" | no | -| `builder.descriptionText(String)` | description text will be displayed on tooltip | yes | "" | no | -| `builder.titleTextColor(Int)` | titleText's color | yes | Color.BLACK | yes | -| `builder.descriptionTextColor(Int)` | descriptionText's color | yes | Color.BLACK | yes | -| `builder.titleTextSize(Int)` | titleText's text size in SP | yes | 18 SP | no | -| `builder.descriptionTextSize(Int)` | descriptionText's text size in SP | yes | 14 SP | no | -| `builder.titleTextFontFamily(String)` | titleText's fontFamily | yes | sans-serif | yes | -| `builder.descriptionTextFontFamily(String)` | descriptionText's fontFamily | yes | sans-serif | yes | -| `builder.titleTextStyle(Int)` | titleText's textStyle | yes | Typeface.NORMAL | yes | -| `builder.descriptionTextStyle(Int)` | descriptionText's textStyle | yes | Typeface.NORMAL | yes | -| `builder.backgroundColor(Int)` | background color of tooltip | yes | Color.WHITE | yes | -| `builder.closeButtonColor(Int)` | closeButton's color | yes | Color.BLACK | yes | -| `builder.showCloseButton(Boolean)` | show close button on tooltip | yes | true | yes | -| `builder.arrowResource(Int)` | custom icon resource for arrow. | yes | ic_arrow_down or ic_arrow_up | no | -| `builder.arrowPosition(ArrowPosition)` | arrow can be placed under or over the tooltip | yes | ArrowPosition.AUTO | no | -| `builder.arrowPercentage(Int)` | arrow position percentage can be decided | yes | null | no | -| `builder.highlightType(HighlightType)` | view can be highlighted with a circle shape or rectangle | yes | HighlightType.RECTANGLE | no | -| `builder.cancelListener(CancelListener)` | will be called after user quit from tooltip | yes | null | no | -| `builder.windowBackgroundColor(Int)` | background of the window's color can be decided | yes | Color.BLACK | yes | -| `builder.windowBackgroundTint(Int)` | alpha value of window's background color | yes | 204 | no | -| `builder.titleTextSize(Int)` | titleText's text size in SP | yes | 18 | no | -| `builder.cancellableFromOutsideTouch(Boolean)` | outside touch from tooltip will act as close click | yes | false | yes | -| `builder.showcaseViewClickable(Boolean)` | makes the showcase view clickable or not | yes | false | yes | -| `builder.isDebugMode(Boolean)` | tooltip won't be presented | yes | false | no | -| `builder.attachOnParentLifecycle(Boolean)` | observe parent lifecycle and dismiss showcase | yes | false | no | -| `builder.textPosition(TextPosition)` | text can be positioning center, end and start | yes | TextPosition.START | no | -| `builder.imageUrl(String)` | show image on tooltip | yes | null | no | -| `builder.customContent(Int)` | show given layout | yes | null | no | -| `builder.statusBarVisible(Boolean)` | statusBar visibility of window | yes | true | no | -| `builder.toolTipVisible(Boolean)` | tooltip visibility | yes | true | no | -| `builder.highlightRadius(Float, Float, Float, Float)` | tooltip visibility | yes | 0f, 0f, 0f, 0f | no | -| `builder.setSlidableContentList(List)` | show slidable content | yes | null | no | -| `builder.showDurationMillis(Long)` | duration of the tooltip visibility | yes | 2000L | no | -| `builder.showcaseViewVisibleIndefinitely(Boolean)` | controls tooltip visibility condition | yes | true | no | -| `builder.build()` | will return ShowcaseManager instance | no | | | -| `showcaseManager.show(Context)` | show the tooltip with set attributes on | no | | | -# Action Result +### Builder Configuration + +| Usage | Description | Optional | Default Value | StyleRes | +|:--------------------------------------------------------|:---------------------------------------------------------|:---------|:-----------------------------|:---------| +| `builder.focus(View)` | view to be focused on | no | null | no | +| `builder.focus(Array)` | view array to be focused on | no | null | no | +| `builder.resId(Int)` | Showcase.Theme style | yes | null | yes | +| `builder.titleText(String)` | text to be showed on top of the tooltip | yes | "" | no | +| `builder.descriptionText(String)` | description text will be displayed on tooltip | yes | "" | no | +| `builder.titleTextColor(Int)` | titleText's color | yes | Color.BLACK | yes | +| `builder.descriptionTextColor(Int)` | descriptionText's color | yes | Color.BLACK | yes | +| `builder.titleTextSize(Int)` | titleText's text size in SP | yes | 18 SP | no | +| `builder.descriptionTextSize(Int)` | descriptionText's text size in SP | yes | 14 SP | no | +| `builder.titleTextFontFamily(String)` | titleText's fontFamily | yes | sans-serif | yes | +| `builder.descriptionTextFontFamily(String)` | descriptionText's fontFamily | yes | sans-serif | yes | +| `builder.titleTextStyle(Int)` | titleText's textStyle | yes | Typeface.NORMAL | yes | +| `builder.descriptionTextStyle(Int)` | descriptionText's textStyle | yes | Typeface.NORMAL | yes | +| `builder.backgroundColor(Int)` | background color of tooltip | yes | Color.WHITE | yes | +| `builder.closeButtonColor(Int)` | closeButton's color | yes | Color.BLACK | yes | +| `builder.showCloseButton(Boolean)` | show close button on tooltip | yes | true | yes | +| `builder.arrowResource(Int)` | custom icon resource for arrow. | yes | ic_arrow_down or ic_arrow_up | no | +| `builder.arrowPosition(ArrowPosition)` | arrow can be placed under or over the tooltip | yes | ArrowPosition.AUTO | no | +| `builder.arrowPercentage(Int)` | arrow position percentage can be decided | yes | null | no | +| `builder.highlightType(HighlightType)` | view can be highlighted with a circle shape or rectangle | yes | HighlightType.RECTANGLE | no | +| `builder.cancelListener(CancelListener)` | will be called after user quit from tooltip | yes | null | no | +| `builder.windowBackgroundColor(Int)` | background of the window's color can be decided | yes | Color.BLACK | yes | +| `builder.windowBackgroundTint(Int)` | alpha value of window's background color | yes | 204 | no | +| `builder.titleTextSize(Int)` | titleText's text size in SP | yes | 18 | no | +| `builder.cancellableFromOutsideTouch(Boolean)` | outside touch from tooltip will act as close click | yes | false | yes | +| `builder.showcaseViewClickable(Boolean)` | makes the showcase view clickable or not | yes | false | yes | +| `builder.isDebugMode(Boolean)` | tooltip won't be presented | yes | false | no | +| `builder.attachOnParentLifecycle(Boolean)` | observe parent lifecycle and dismiss showcase | yes | false | no | +| `builder.textPosition(TextPosition)` | text can be positioning center, end and start | yes | TextPosition.START | no | +| `builder.imageUrl(String)` | show image on tooltip | yes | null | no | +| `builder.customContent(Int)` | show given layout | yes | null | no | +| `builder.statusBarVisible(Boolean)` | statusBar visibility of window | yes | true | no | +| `builder.toolTipVisible(Boolean)` | tooltip visibility | yes | true | no | +| `builder.highlightRadius(Float, Float, Float, Float)` | tooltip visibility | yes | 0f, 0f, 0f, 0f | no | +| `builder.setSlidableContentList(List)` | show slidable content | yes | null | no | +| `builder.showDurationMillis(Long)` | duration of the tooltip visibility | yes | 2000L | no | +| `builder.showcaseViewVisibleIndefinitely(Boolean)` | controls tooltip visibility condition | yes | true | no | +| `builder.build()` | will return ShowcaseManager instance | no | | | +| `showcaseManager.show(Context)` | show the tooltip with set attributes on | no | | | + +### Action Result By overriding `onActivityResult` you can get feedback based on the types in the ActionType class. -If the actionType is `HIGHLIGHT_CLICKED`, the `KEY_SELECTED_VIEW_INDEX` parameter returns the index of the clicked view. If no view is clicked, the index will be -1. +If the actionType is `HIGHLIGHT_CLICKED`, the `KEY_SELECTED_VIEW_INDEX` parameter returns the index of the clicked view. +If no view is clicked, the index will be -1. ``` override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -115,8 +129,7 @@ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) License -------- - - Copyright 2021 Trendyol.com + Copyright 2023 Trendyol.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/build.gradle b/build.gradle index 3efda47..031cd98 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.5.0' + ext.kotlin_version = '1.7.20' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' } @@ -15,7 +15,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f6b961f..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 90e4792..774fae8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jun 11 08:49:55 EET 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/gradlew b/gradlew index cccdd3d..4f906e0 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f955316..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/library/build.gradle b/library/build.gradle index 62cb09a..5a7d0c5 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,8 +1,6 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-parcelize' -apply plugin: 'com.github.dcendents.android-maven' group = 'com.trendyol.showcase' @@ -12,13 +10,11 @@ ext { } android { - compileSdkVersion 30 + compileSdkVersion 33 defaultConfig { minSdkVersion 17 - targetSdkVersion 30 - versionCode 14 - versionName "1.3.1" + targetSdkVersion 33 vectorDrawables.useSupportLibrary = true } @@ -28,7 +24,8 @@ android { } buildFeatures { - dataBinding = true + buildConfig = false + viewBinding = true } buildTypes { @@ -37,22 +34,16 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + namespace 'com.trendyol.showcase' } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.viewpager2:viewpager2:1.0.0' - implementation 'com.github.bumptech.glide:glide:4.12.0' + implementation 'com.github.bumptech.glide:glide:4.15.1' testImplementation 'junit:junit:4.13.2' } - -repositories { - mavenCentral() -} diff --git a/library/src/main/AndroidManifest.xml b/library/src/main/AndroidManifest.xml index 1955d6e..50cf057 100644 --- a/library/src/main/AndroidManifest.xml +++ b/library/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/library/src/main/java/com/trendyol/showcase/ui/ViewExtensions.kt b/library/src/main/java/com/trendyol/showcase/ui/ViewExtensions.kt new file mode 100644 index 0000000..ded221b --- /dev/null +++ b/library/src/main/java/com/trendyol/showcase/ui/ViewExtensions.kt @@ -0,0 +1,67 @@ +package com.trendyol.showcase.ui + +import android.content.res.ColorStateList +import android.util.TypedValue +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat +import androidx.core.widget.ImageViewCompat +import com.bumptech.glide.Glide +import com.trendyol.showcase.ui.tooltip.AbsoluteArrowPosition +import com.trendyol.showcase.ui.tooltip.TooltipView +import com.trendyol.showcase.ui.tooltip.TooltipViewState + +internal fun TooltipView.setTooltipViewState(tooltipViewState: TooltipViewState) { + bind(tooltipViewState) +} + +internal fun TooltipView.placeTooltip(margin: Int, arrowPosition: AbsoluteArrowPosition) { + if (arrowPosition == AbsoluteArrowPosition.UP) { + (layoutParams as? ConstraintLayout.LayoutParams)?.apply { + topToTop = 0 // parent + bottomToBottom = -1 + topMargin = margin + } + } else if (arrowPosition == AbsoluteArrowPosition.DOWN) { + (layoutParams as? ConstraintLayout.LayoutParams)?.apply { + topToTop = -1 + bottomToBottom = 0 // parent + bottomMargin = margin + } + } +} + +internal fun TextView.setTextSizeInSp(size: Float) { + setTextSize(TypedValue.COMPLEX_UNIT_SP, size) +} + +internal fun ImageView.layoutMarginStart(margin: Int, percentage: Int?) { + (layoutParams as? ConstraintLayout.LayoutParams)?.apply { + percentage?.let { + endToEnd = 0 + horizontalBias = (it.toFloat() / 100) + } ?: run { + this.marginStart = margin + } + } +} + +internal fun ImageView.setDrawableRes(@DrawableRes drawableRes: Int) { + setImageDrawable(ContextCompat.getDrawable(context, drawableRes)) +} + +internal fun View.isVisible(isVisible: Boolean) { + visibility = if (isVisible) View.VISIBLE else View.GONE +} + +internal fun ImageView.setTint(@ColorInt color: Int) { + ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color)) +} + +internal fun ImageView.loadImage(imageUrl: String) { + Glide.with(context).load(imageUrl).into(this) +} diff --git a/library/src/main/java/com/trendyol/showcase/ui/binding/BindingSetter.kt b/library/src/main/java/com/trendyol/showcase/ui/binding/BindingSetter.kt deleted file mode 100644 index 7dd4f1f..0000000 --- a/library/src/main/java/com/trendyol/showcase/ui/binding/BindingSetter.kt +++ /dev/null @@ -1,72 +0,0 @@ -package com.trendyol.showcase.ui.binding - -import android.util.TypedValue -import android.view.View -import android.widget.ImageView -import android.widget.TextView -import androidx.annotation.DrawableRes -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.ContextCompat -import androidx.databinding.BindingAdapter -import com.trendyol.showcase.ui.tooltip.AbsoluteArrowPosition -import com.trendyol.showcase.ui.tooltip.ArrowPosition -import com.trendyol.showcase.ui.tooltip.TooltipView -import com.trendyol.showcase.ui.tooltip.TooltipViewState - -object BindingSetter { - - @JvmStatic - @BindingAdapter("tooltipViewState") - internal fun TooltipView.setTooltipViewState(tooltipViewState: TooltipViewState) { - bind(tooltipViewState) - } - - @JvmStatic - @BindingAdapter(value = ["applyMargin", "arrowPosition"], requireAll = true) - internal fun TooltipView.placeTooltip(margin: Int, arrowPosition: AbsoluteArrowPosition) { - if (arrowPosition == AbsoluteArrowPosition.UP) { - (layoutParams as? ConstraintLayout.LayoutParams)?.apply { - topToTop = 0 // parent - bottomToBottom = -1 - topMargin = margin - } - } else if (arrowPosition == AbsoluteArrowPosition.DOWN) { - (layoutParams as? ConstraintLayout.LayoutParams)?.apply { - topToTop = -1 - bottomToBottom = 0 // parent - bottomMargin = margin - } - } - } - - @JvmStatic - @BindingAdapter("textSizeInSP") - internal fun TextView.setTextSizeInSp(size: Float) { - setTextSize(TypedValue.COMPLEX_UNIT_SP, size) - } - - @JvmStatic - @BindingAdapter(value = ["arrowHorizontalPosition", "arrowPercentage"], requireAll = true) - internal fun ImageView.layoutMarginStart(margin: Int, percentage: Int?) { - (layoutParams as? ConstraintLayout.LayoutParams)?.apply { - percentage?.let { - endToEnd = 0 - horizontalBias = (it.toFloat() / 100) - } ?: run { - this.marginStart = margin - } - } - } - - @JvmStatic - @BindingAdapter("drawableRes") - internal fun ImageView.setDrawableRes(@DrawableRes drawableRes: Int) { - setImageDrawable(ContextCompat.getDrawable(context, drawableRes)) - } - - @JvmStatic - @BindingAdapter("isVisible") - internal fun View.isVisible(isVisible: Boolean) { - visibility = if (isVisible) View.VISIBLE else View.GONE - } -} diff --git a/library/src/main/java/com/trendyol/showcase/ui/binding/ImageBindingAdapter.kt b/library/src/main/java/com/trendyol/showcase/ui/binding/ImageBindingAdapter.kt deleted file mode 100644 index 0ae649f..0000000 --- a/library/src/main/java/com/trendyol/showcase/ui/binding/ImageBindingAdapter.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.trendyol.showcase.ui.binding - -import android.widget.ImageView -import androidx.databinding.BindingAdapter -import com.bumptech.glide.Glide - -@BindingAdapter("sc_imageUrl") -fun ImageView.loadImage(imageUrl: String) { - Glide.with(context).load(imageUrl).into(this) -} diff --git a/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseActivity.kt b/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseActivity.kt index e9e1487..9ec9284 100644 --- a/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseActivity.kt +++ b/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseActivity.kt @@ -6,6 +6,9 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import com.trendyol.showcase.showcase.ShowcaseModel import com.trendyol.showcase.util.ActionType @@ -18,7 +21,6 @@ class ShowcaseActivity : AppCompatActivity() { overridePendingTransition(android.R.anim.fade_in, 0) handler = Handler(Looper.getMainLooper()) - val showcaseModel = intent?.extras?.getParcelable(BUNDLE_KEY) as? ShowcaseModel showcaseModel?.let { model -> val view = ShowcaseView(this).apply { @@ -29,11 +31,12 @@ class ShowcaseActivity : AppCompatActivity() { } setContentView(view) if (model.isShowcaseViewVisibleIndefinitely.not()) { - handler.postDelayed( - { finishShowcase(ActionType.EXIT) }, - model.showDuration - ) + handler.postDelayed( + { finishShowcase(ActionType.EXIT) }, + model.showDuration + ) } + updateStatusBar(model.isStatusBarVisible) } } @@ -52,7 +55,21 @@ class ShowcaseActivity : AppCompatActivity() { finishShowcase(ActionType.EXIT) } + private fun updateStatusBar(isStatusBarVisible: Boolean) { + WindowCompat.setDecorFitsSystemWindows(window, true) + val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) + if (isStatusBarVisible) { + windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + windowInsetsController.show(WindowInsetsCompat.Type.statusBars()) + } else { + windowInsetsController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()) + } + } + companion object { - const val BUNDLE_KEY = "bundle_key" + + internal const val BUNDLE_KEY = "bundle_key" } } diff --git a/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseView.kt b/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseView.kt index 56b7c0b..63d67ef 100644 --- a/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseView.kt +++ b/library/src/main/java/com/trendyol/showcase/ui/showcase/ShowcaseView.kt @@ -6,13 +6,14 @@ import android.graphics.RectF import android.util.AttributeSet import android.view.LayoutInflater import androidx.constraintlayout.widget.ConstraintLayout -import androidx.databinding.DataBindingUtil -import com.trendyol.showcase.R +import androidx.core.view.isVisible import com.trendyol.showcase.databinding.LayoutShowcaseBinding import com.trendyol.showcase.showcase.ShowcaseModel +import com.trendyol.showcase.ui.placeTooltip +import com.trendyol.showcase.ui.setTooltipViewState import com.trendyol.showcase.ui.tooltip.AbsoluteArrowPosition -import com.trendyol.showcase.util.ActionType import com.trendyol.showcase.ui.tooltip.TooltipViewState +import com.trendyol.showcase.util.ActionType import com.trendyol.showcase.util.OnTouchClickListener import com.trendyol.showcase.util.TooltipFieldUtil import com.trendyol.showcase.util.getDensity @@ -23,19 +24,13 @@ import com.trendyol.showcase.util.statusBarHeight class ShowcaseView @JvmOverloads constructor( context: Context, - attrs: AttributeSet? = null + attrs: AttributeSet? = null, ) : ConstraintLayout(context, attrs) { - private val binding: LayoutShowcaseBinding - + private val binding = LayoutShowcaseBinding.inflate(LayoutInflater.from(context), this, true) private var showcaseModel: ShowcaseModel? = null private var clickListener: ((ActionType, Int) -> (Unit))? = null - init { - val inflater = LayoutInflater.from(context) - binding = DataBindingUtil.inflate(inflater, R.layout.layout_showcase, this, true) - } - override fun dispatchDraw(canvas: Canvas) { val showcaseModel = this.showcaseModel ?: return super.dispatchDraw(canvas) @@ -92,15 +87,25 @@ class ShowcaseView @JvmOverloads constructor( val showcaseModel = this.showcaseModel ?: return listenClickEvents() - val arrowPosition = TooltipFieldUtil.decideArrowPosition(showcaseModel, resources.getHeightInPixels()) - val arrowMargin = TooltipFieldUtil.calculateArrowMargin(showcaseModel.horizontalCenter(), resources.getDensity()) + val arrowMargin = TooltipFieldUtil.calculateArrowMargin( + horizontalCenter = showcaseModel.horizontalCenter(), + density = resources.getDensity() + ) val marginFromBottom = getMarginFromBottom(showcaseModel, arrowPosition) - - binding.showcaseViewState = ShowcaseViewState(margin = marginFromBottom) - binding.tooltipViewState = TooltipViewState(showcaseModel = showcaseModel, arrowPosition = arrowPosition, arrowMargin = arrowMargin) + val showcaseViewState = ShowcaseViewState(margin = marginFromBottom) + val tooltipViewState = TooltipViewState( + showcaseModel = showcaseModel, + arrowPosition = arrowPosition, + arrowMargin = arrowMargin + ) setCustomContent() - binding.executePendingBindings() + + with(binding.tooltipView) { + isVisible = tooltipViewState.isToolTipVisible() + placeTooltip(showcaseViewState.margin, tooltipViewState.arrowPosition) + setTooltipViewState(tooltipViewState) + } } private fun getMarginFromBottom(showcaseModel: ShowcaseModel, arrowPosition: AbsoluteArrowPosition): Int { @@ -181,9 +186,9 @@ class ShowcaseView @JvmOverloads constructor( } companion object { - private const val CONST_VIEW_NOT_FOUND = -1 const val KEY_ACTION_TYPE = "action-type" const val KEY_SELECTED_VIEW_INDEX = "clicked-view-index" + private const val CONST_VIEW_NOT_FOUND = -1 } } diff --git a/library/src/main/java/com/trendyol/showcase/ui/slidablecontent/SlidableContentAdapter.kt b/library/src/main/java/com/trendyol/showcase/ui/slidablecontent/SlidableContentAdapter.kt index 08df1cb..40d4fcf 100644 --- a/library/src/main/java/com/trendyol/showcase/ui/slidablecontent/SlidableContentAdapter.kt +++ b/library/src/main/java/com/trendyol/showcase/ui/slidablecontent/SlidableContentAdapter.kt @@ -3,19 +3,19 @@ package com.trendyol.showcase.ui.slidablecontent import android.graphics.Typeface import android.view.LayoutInflater import android.view.ViewGroup -import androidx.databinding.DataBindingUtil +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView -import com.trendyol.showcase.R import com.trendyol.showcase.databinding.ItemSlidableContentBinding +import com.trendyol.showcase.ui.loadImage +import com.trendyol.showcase.ui.setTextSizeInSp internal class SlidableContentAdapter(private val slidableContentList: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerViewHolder = ViewPagerViewHolder( - DataBindingUtil.inflate( + ItemSlidableContentBinding.inflate( LayoutInflater.from(parent.context), - R.layout.item_slidable_content, parent, false ) @@ -27,20 +27,38 @@ internal class SlidableContentAdapter(private val slidableContentList: List (Unit))? = null init { - val inflater = LayoutInflater.from(context) - binding = DataBindingUtil.inflate(inflater, R.layout.layout_tooltip, rootView as ViewGroup, true) - with(binding) { layoutContents.setOnClickListener { sendActionType(ActionType.SHOWCASE_CLICKED) @@ -42,19 +44,56 @@ class TooltipView @JvmOverloads constructor( internal fun bind(tooltipViewState: TooltipViewState) { with(binding) { - this.tooltipViewState = tooltipViewState - textViewTooltipTitle.typeface = Typeface.create( - tooltipViewState.getTitleTextFontFamily(), - tooltipViewState.getTitleTextStyle() - ) - textViewTooltipDescription.typeface = Typeface.create( - tooltipViewState.getDescriptionTextFontFamily(), - tooltipViewState.getDescriptionTextStyle() - ) + with(textViewTooltipTitle) { + typeface = Typeface.create( + tooltipViewState.getTitleTextFontFamily(), + tooltipViewState.getTitleTextStyle() + ) + text = tooltipViewState.getTitle() + textAlignment = tooltipViewState.getTextPosition() + setTextColor(tooltipViewState.getTitleTextColor()) + isVisible = tooltipViewState.getTitleVisibility() + setTextSizeInSp(tooltipViewState.getTitleTextSize()) + } + with(textViewTooltipDescription) { + typeface = Typeface.create( + tooltipViewState.getDescriptionTextFontFamily(), + tooltipViewState.getDescriptionTextStyle() + ) + text = tooltipViewState.getDescription() + textAlignment = tooltipViewState.getTextPosition() + setTextColor(tooltipViewState.getDescriptionTextColor()) + isVisible = tooltipViewState.getDescriptionVisibility() + setTextSizeInSp(tooltipViewState.getDescriptionTextSize()) + } setupViewPager(tooltipViewState.showcaseModel.slidableContentList.orEmpty()) - executePendingBindings() + with(imageViewTopArrow) { + visibility = tooltipViewState.getTopArrowVisibility() + setTint(tooltipViewState.getBackgroundColor()) + layoutMarginStart(tooltipViewState.arrowMargin, tooltipViewState.getArrowPercentage()) + setImageDrawable(ContextCompat.getDrawable(context, tooltipViewState.getTopArrowResource())) + } + layoutContents.isClickable = tooltipViewState.isShowcaseViewClickable() + cardContent.visibility = tooltipViewState.getContentVisibility() + layoutBubble.background = ColorDrawable(tooltipViewState.getBackgroundColor()) + with(imageView) { + visibility = tooltipViewState.getImageViewVisibility() + loadImage(tooltipViewState.getImageUrl()) + } + textViewSlidableContentPosition.isVisible = tooltipViewState.isSlidableContentVisible() + viewPager.isVisible = tooltipViewState.isSlidableContentVisible() + with(imageViewTooltipClose) { + visibility = tooltipViewState.getCloseButtonVisibility() + setTint(tooltipViewState.getCloseButtonColor()) + } + with(imageViewBottomArrow) { + visibility = tooltipViewState.getBottomArrowVisibility() + setTint(tooltipViewState.getBackgroundColor()) + layoutMarginStart(tooltipViewState.arrowMargin, tooltipViewState.getArrowPercentage()) + setImageDrawable(ContextCompat.getDrawable(context, tooltipViewState.getBottomArrowResource())) + } } } diff --git a/library/src/main/res/layout/item_slidable_content.xml b/library/src/main/res/layout/item_slidable_content.xml index f784305..24405e5 100644 --- a/library/src/main/res/layout/item_slidable_content.xml +++ b/library/src/main/res/layout/item_slidable_content.xml @@ -1,66 +1,44 @@ - + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> - + - - + - - - - - - - - - \ No newline at end of file + + diff --git a/library/src/main/res/layout/layout_showcase.xml b/library/src/main/res/layout/layout_showcase.xml index 54e8da2..0dc4207 100644 --- a/library/src/main/res/layout/layout_showcase.xml +++ b/library/src/main/res/layout/layout_showcase.xml @@ -1,34 +1,13 @@ - + - - - - - - - - - - - - - - + android:layout_height="wrap_content" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + diff --git a/library/src/main/res/layout/layout_tooltip.xml b/library/src/main/res/layout/layout_tooltip.xml index de11529..85c0463 100644 --- a/library/src/main/res/layout/layout_tooltip.xml +++ b/library/src/main/res/layout/layout_tooltip.xml @@ -1,182 +1,136 @@ - - - - - - - - + + + + + app:layout_constraintBottom_toTopOf="@id/imageViewBottomArrow" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@id/imageViewTopArrow"> - - - + android:layout_marginStart="@dimen/showcase_margin_20dp" + android:layout_marginEnd="@dimen/showcase_margin_20dp" + app:cardCornerRadius="@dimen/showcase_card_radius" + app:cardElevation="0dp"> - + android:layout_height="wrap_content"> - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_chainStyle="spread_inside" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + + + + + + + + + + + + + + diff --git a/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateFactory.kt b/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateFactory.kt index b655ddd..8018677 100644 --- a/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateFactory.kt +++ b/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateFactory.kt @@ -60,7 +60,6 @@ internal object TooltipViewStateFactory { radiusBottomEnd = 0F, radiusBottomStart = 0F, radiusTopEnd = 0F, - attachOnParentLifecycle = true, descriptionTextFontFamily = "sans-serif", isToolTipVisible = true, slidableContentList = listOf(), diff --git a/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateTest.kt b/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateTest.kt index 2548bd8..58bcb23 100644 --- a/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateTest.kt +++ b/library/src/test/java/com/trendyol/showcase/ui/tooltip/TooltipViewStateTest.kt @@ -23,8 +23,9 @@ class TooltipViewStateTest { @Test fun `when imageUrl is not empty then getImageViewVisibility() returns VISIBLE`() { //when - val tooltipViewState = - TooltipViewStateFactory.provideTooltipViewState(imageUrl = "https://cdn.dsmcdn.com/Assets/t/y/creative/mobile/InstantDelivery/instant-ty-onboarding.png") + val tooltipViewState = TooltipViewStateFactory.provideTooltipViewState( + imageUrl = "https://upload.wikimedia.org/wikipedia/commons/7/7c/Aspect_ratio_16_9_example.jpg" + ) //then val expectedResult = View.VISIBLE diff --git a/sample/build.gradle b/sample/build.gradle index 68ccb70..1587fb6 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -1,21 +1,20 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' android { - compileSdkVersion 30 + compileSdkVersion 33 defaultConfig { applicationId "com.trendyol.showcase" minSdkVersion 17 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName "1.0" } buildFeatures { + buildConfig = false viewBinding = true - dataBinding = true } buildTypes { @@ -24,16 +23,14 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + namespace 'com.trendyol.sample' } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(path: ':library') - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - - implementation 'androidx.appcompat:appcompat:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - implementation 'com.trendyol:medusa:0.10.1' - implementation 'com.google.android.material:material:1.3.0-alpha03' + implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'com.trendyol:medusa:0.10.3' + implementation 'com.google.android.material:material:1.8.0' } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index daf5217..2369a2b 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,24 +1,22 @@ - + + + + android:theme="@style/AppTheme"> - + - - diff --git a/sample/src/main/java/com/trendyol/sample/MainActivity.kt b/sample/src/main/java/com/trendyol/sample/MainActivity.kt index 17c2020..36c46c3 100644 --- a/sample/src/main/java/com/trendyol/sample/MainActivity.kt +++ b/sample/src/main/java/com/trendyol/sample/MainActivity.kt @@ -31,11 +31,11 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), Navigator.Naviga } private fun initializeBottomBarListener() { - bottomNavigation.setOnNavigationItemSelectedListener { + bottomNavigation.setOnItemSelectedListener { navigator.switchTab(it.order) true } - bottomNavigation.setOnNavigationItemReselectedListener { + bottomNavigation.setOnItemReselectedListener { val selectedTabIndex = it.order if (navigator.hasOnlyRoot(selectedTabIndex).not()) { navigator.reset(selectedTabIndex) @@ -57,20 +57,16 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), Navigator.Naviga ) private fun getRootFragments(): ArrayList = arrayListOf( - SampleFragment.newInstance(), - OneFragment.newInstance(), - TwoFragment.newInstance(), - ThreeFragment.newInstance(), + SampleFragment.newInstance(isStatusBarVisible = true), + SampleFragment.newInstance(isStatusBarVisible = false), + SecondarySampleFragment(1), + SecondarySampleFragment(2), ) fun getNavigator(): Navigator { return navigator } - fun setNavigator(navigator: Navigator) { - this.navigator = navigator - } - override fun onTabChanged(tabIndex: Int) { val bottomNavigationView = bottomNavigation val selectedItemId = bottomNavigationView.menu.getItem(tabIndex).itemId diff --git a/sample/src/main/java/com/trendyol/sample/OneFragment.kt b/sample/src/main/java/com/trendyol/sample/OneFragment.kt deleted file mode 100644 index a7f86af..0000000 --- a/sample/src/main/java/com/trendyol/sample/OneFragment.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.trendyol.sample - -import androidx.fragment.app.Fragment - -class OneFragment : Fragment(R.layout.fragment_one){ - - companion object{ - @JvmStatic - fun newInstance() = OneFragment() - } -} \ No newline at end of file diff --git a/sample/src/main/java/com/trendyol/sample/SampleFragment.kt b/sample/src/main/java/com/trendyol/sample/SampleFragment.kt index ed02c98..8214eb6 100644 --- a/sample/src/main/java/com/trendyol/sample/SampleFragment.kt +++ b/sample/src/main/java/com/trendyol/sample/SampleFragment.kt @@ -8,8 +8,11 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.WindowManager import androidx.core.content.ContextCompat +import androidx.core.os.bundleOf +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import com.trendyol.medusalib.navigator.Navigator @@ -26,81 +29,58 @@ import com.trendyol.showcase.util.ActionType class SampleFragment : Fragment() { private var binding: FragmentSampleBinding? = null - - protected val fragmentNavigator: Navigator? + private val fragmentNavigator: Navigator? get() = (activity as? MainActivity)?.getNavigator() - - private var medusaLifecycleOwner: MedusaLifecycleOwner? = null + private lateinit var medusaLifecycleOwner: MedusaLifecycleOwner + private val isStatusBarVisible by lazy { + requireArguments().getBoolean(KEY_IS_STATUS_BAR_VISIBLE) + } override fun onResume() { super.onResume() - if (medusaLifecycleOwner != null) { - if (!isHidden && userVisibleHint) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) - } + if (isVisible) { + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME) } } override fun onPause() { super.onPause() - if (medusaLifecycleOwner != null) { - if (!isHidden && userVisibleHint) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) - } + if (isVisible) { + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE) } } override fun onDestroyView() { - if (medusaLifecycleOwner != null) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) - medusaLifecycleOwner = null - } + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY) super.onDestroyView() } override fun onStart() { super.onStart() - if (medusaLifecycleOwner == null) { - return - } - if (!isHidden && userVisibleHint) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) + if (isVisible) { + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) } } override fun onStop() { - if (medusaLifecycleOwner != null) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) - } + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) super.onStop() } override fun onHiddenChanged(hidden: Boolean) { super.onHiddenChanged(hidden) - if (medusaLifecycleOwner != null) { - if (hidden) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) - } else { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) - } - } - } - - override fun setUserVisibleHint(isVisibleToUser: Boolean) { - super.setUserVisibleHint(isVisibleToUser) - if (medusaLifecycleOwner != null) { - if (isVisibleToUser && isResumed) { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) - } else { - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) - } + if (hidden) { + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP) + } else { + updateStatusBar(isStatusBarVisible) + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START) } } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ): View { val binding = FragmentSampleBinding.inflate(inflater, container, false) this.binding = binding @@ -110,10 +90,9 @@ class SampleFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) medusaLifecycleOwner = MedusaLifecycleOwner() - medusaLifecycleOwner!!.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) - if (isStatusBarVisible) { - requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) - } + medusaLifecycleOwner.lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE) + + updateStatusBar(isStatusBarVisible) with(binding!!) { buttonTop.setOnClickListener { @@ -126,7 +105,9 @@ class SampleFragment : Fragment() { .titleTextFontFamily("sans-serif") .descriptionTextColor(ContextCompat.getColor(context, R.color.colorPrimary)) .backgroundColor(ContextCompat.getColor(context, R.color.colorPrimaryDark)) - .imageUrl("https://cdn.dsmcdn.com/Assets/t/y/creative/mobile/InstantDelivery/instant-ty-onboarding.png") + .imageUrl( + "https://upload.wikimedia.org/wikipedia/commons/7/7c/Aspect_ratio_16_9_example.jpg" + ) .showCloseButton(true) .cancellableFromOutsideTouch(true) .arrowPosition(ArrowPosition.AUTO) @@ -139,11 +120,11 @@ class SampleFragment : Fragment() { .show( this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, - medusaLifecycleOwner!! + medusaLifecycleOwner ) if (isFragmentTransactionTest) { view.postDelayed({ - fragmentNavigator?.start(OneFragment()) + fragmentNavigator?.start(SecondarySampleFragment(1)) }, 3000) } } @@ -169,7 +150,7 @@ class SampleFragment : Fragment() { view.postDelayed({ requireActivity().supportFragmentManager .beginTransaction() - .replace(R.id.containerMain, OneFragment()) + .replace(R.id.containerMain, SecondarySampleFragment(2)) .commitAllowingStateLoss() }, 3000) } @@ -198,7 +179,7 @@ class SampleFragment : Fragment() { .toolTipVisible(false) .statusBarVisible(isStatusBarVisible) .build() - .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner!!) + .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner) } buttonFocusMultipleView.setOnClickListener { @@ -213,7 +194,7 @@ class SampleFragment : Fragment() { .textPosition(TextPosition.START) .statusBarVisible(isStatusBarVisible) .build() - .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner!!) + .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner) } buttonSlidableContent.setOnClickListener { @@ -223,7 +204,7 @@ class SampleFragment : Fragment() { .showCloseButton(false) .cancellableFromOutsideTouch(true) .build() - .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner!!) + .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner) } imageTop.setOnClickListener { @@ -234,7 +215,7 @@ class SampleFragment : Fragment() { .showcaseViewClickable(true) .statusBarVisible(isStatusBarVisible) .build() - .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner!!) + .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner) } buttonVanishingShowcase.setOnClickListener { @@ -246,7 +227,7 @@ class SampleFragment : Fragment() { .titleText("This showcase will vanish in 4 seconds") .showcaseViewVisibleIndefinitely(false) .build() - .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner!!) + .show(this@SampleFragment, REQUEST_CODE_SHOWCASE_CLICKED, medusaLifecycleOwner) } } } @@ -254,8 +235,7 @@ class SampleFragment : Fragment() { private fun buildSlidableContentList(): List { val context = requireContext() val baseSlidableContent = slidableContent { - imageUrl = - "https://cdn.dsmcdn.com/Assets/t/y/creative/mobile/InstantDelivery/instant-ty-onboarding.png" + imageUrl = "https://upload.wikimedia.org/wikipedia/commons/7/7c/Aspect_ratio_16_9_example.jpg" titleTextColor = ContextCompat.getColor(context, R.color.black) titleTextSize = 16f titleTextFontFamily = "sans-serif" @@ -289,11 +269,27 @@ class SampleFragment : Fragment() { } companion object { + private const val REQUEST_CODE_SHOWCASE_CLICKED = 101 - private const val isStatusBarVisible = true private const val isFragmentTransactionTest = false + private const val KEY_IS_STATUS_BAR_VISIBLE = "key_is_status_bar_visible" + + fun newInstance(isStatusBarVisible: Boolean) = SampleFragment().apply { + arguments = bundleOf(KEY_IS_STATUS_BAR_VISIBLE to isStatusBarVisible) + } - @JvmStatic - fun newInstance() = SampleFragment() + fun Fragment.updateStatusBar(isStatusBarVisible: Boolean) { + val window = requireActivity().window + WindowCompat.setDecorFitsSystemWindows(window, true) + val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) + if (isStatusBarVisible) { + windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_TOUCH + windowInsetsController.show(WindowInsetsCompat.Type.statusBars()) + } else { + windowInsetsController.systemBarsBehavior = + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()) + } + } } } diff --git a/sample/src/main/java/com/trendyol/sample/SecondarySampleFragment.kt b/sample/src/main/java/com/trendyol/sample/SecondarySampleFragment.kt new file mode 100644 index 0000000..a50626b --- /dev/null +++ b/sample/src/main/java/com/trendyol/sample/SecondarySampleFragment.kt @@ -0,0 +1,22 @@ +package com.trendyol.sample + +import android.os.Bundle +import android.view.View +import android.widget.TextView +import androidx.fragment.app.Fragment +import com.trendyol.sample.SampleFragment.Companion.updateStatusBar + +class SecondarySampleFragment(private val index: Int) : Fragment(R.layout.fragment_secondary_sample) { + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + view.findViewById(R.id.text_id).text = "Fragment $index" + } + + override fun onHiddenChanged(hidden: Boolean) { + super.onHiddenChanged(hidden) + if (hidden.not()) { + updateStatusBar(true) + } + } +} diff --git a/sample/src/main/java/com/trendyol/sample/TextFragment.kt b/sample/src/main/java/com/trendyol/sample/TextFragment.kt deleted file mode 100644 index ccb50e7..0000000 --- a/sample/src/main/java/com/trendyol/sample/TextFragment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.trendyol.sample - -import androidx.fragment.app.Fragment - -class TextFragment : Fragment(R.layout.fragment_text) \ No newline at end of file diff --git a/sample/src/main/java/com/trendyol/sample/ThreeFragment.kt b/sample/src/main/java/com/trendyol/sample/ThreeFragment.kt deleted file mode 100644 index e41dfdf..0000000 --- a/sample/src/main/java/com/trendyol/sample/ThreeFragment.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.trendyol.sample - -import androidx.fragment.app.Fragment - -class ThreeFragment : Fragment(R.layout.fragment_three){ - - companion object{ - @JvmStatic - fun newInstance() = ThreeFragment() - } -} \ No newline at end of file diff --git a/sample/src/main/java/com/trendyol/sample/TwoFragment.kt b/sample/src/main/java/com/trendyol/sample/TwoFragment.kt deleted file mode 100644 index 039b662..0000000 --- a/sample/src/main/java/com/trendyol/sample/TwoFragment.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.trendyol.sample - -import androidx.fragment.app.Fragment - -class TwoFragment : Fragment(R.layout.fragment_two){ - - companion object{ - @JvmStatic - fun newInstance() = TwoFragment() - } -} \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 5769f31..6bdc37b 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -1,27 +1,27 @@ - - - - + android:layout_height="match_parent"> - - - \ No newline at end of file + + + + + diff --git a/sample/src/main/res/layout/fragment_one.xml b/sample/src/main/res/layout/fragment_one.xml deleted file mode 100644 index 58decad..0000000 --- a/sample/src/main/res/layout/fragment_one.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_secondary_sample.xml b/sample/src/main/res/layout/fragment_secondary_sample.xml new file mode 100644 index 0000000..4771bc3 --- /dev/null +++ b/sample/src/main/res/layout/fragment_secondary_sample.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/sample/src/main/res/layout/fragment_text.xml b/sample/src/main/res/layout/fragment_text.xml deleted file mode 100644 index 8a3ee06..0000000 --- a/sample/src/main/res/layout/fragment_text.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_three.xml b/sample/src/main/res/layout/fragment_three.xml deleted file mode 100644 index bcffc42..0000000 --- a/sample/src/main/res/layout/fragment_three.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/sample/src/main/res/layout/fragment_two.xml b/sample/src/main/res/layout/fragment_two.xml deleted file mode 100644 index 812f053..0000000 --- a/sample/src/main/res/layout/fragment_two.xml +++ /dev/null @@ -1,9 +0,0 @@ - - \ No newline at end of file diff --git a/sample/src/main/res/menu/bottom_navigation.xml b/sample/src/main/res/menu/bottom_navigation.xml index 8820581..2274b04 100644 --- a/sample/src/main/res/menu/bottom_navigation.xml +++ b/sample/src/main/res/menu/bottom_navigation.xml @@ -4,20 +4,20 @@ + android:title="Status Bar"/> + android:title="No Status Bar" /> + android:title="Fragment 1" /> + android:title="Fragment 2" /> \ No newline at end of file diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml index 38956ae..6373c8a 100644 --- a/sample/src/main/res/values/colors.xml +++ b/sample/src/main/res/values/colors.xml @@ -1,8 +1,8 @@ - #008577 - #00574B - #D81B60 + #ffb800 + #f27a1a + #1be7ff #000000 #ffffff diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 1f0cf0e..e0ad594 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - TooltipShowCase + Showcase Sample diff --git a/screenshots/1.png b/screenshots/1.png index 4c31d10..5b49009 100644 Binary files a/screenshots/1.png and b/screenshots/1.png differ diff --git a/screenshots/2.png b/screenshots/2.png index 372f7fb..4933c07 100644 Binary files a/screenshots/2.png and b/screenshots/2.png differ diff --git a/screenshots/3.png b/screenshots/3.png index 428d95f..d9a2a62 100644 Binary files a/screenshots/3.png and b/screenshots/3.png differ diff --git a/screenshots/4.png b/screenshots/4.png index a06f51d..37cdb4e 100644 Binary files a/screenshots/4.png and b/screenshots/4.png differ diff --git a/screenshots/5.png b/screenshots/5.png index 1d83e48..1be8944 100644 Binary files a/screenshots/5.png and b/screenshots/5.png differ diff --git a/screenshots/6.png b/screenshots/6.png index 8a65337..15da55e 100644 Binary files a/screenshots/6.png and b/screenshots/6.png differ