Download Template | Example App | Config Examples
All whisper.yaml
template samples can be found in /yaml-samples/.
- Easy to use with simple and short one liners.
- Ready to use out of the box with no required setup. Just call
Whisper
with a profile and it handles the rest! - Tons of configurations including custom sounds, vibration, fonts, shadow/layers, gradients, and so many design options! See configuration.md for all configurable fields with documentation, examples, and screenshots.
- Make config changes at runtime in code or import the whisper.yaml template with your config changes (applies automatically. See the collection of samples for inspiration).
- Comprehensive documentation throughout the entire codebase, configuration yaml, README, and configurations.md.
- Non-modal to not interfere with user interaction, background processes, and foreground loading.
- Display as many or as little Whispers on screen at once.
- Dynamic durations based on message length auto-dismiss Whispers without having to consider what the best time out is for each Whisper (developer defined durations or none at all are also options).
- Whisper can double as a debugging tool! Use Whisper.Trace or Whisper.Debug for Whispers that only will display for debug builds (no need to comment out or delete these for release!).
Check out the example app for Whisper to test out Whisper and the many configuration options!
- Usage / Examples
- YAML Setup / Configuration
- Syntax / Setup
- Configuration Options
- Other Functions and Considerations
- Installation
- Versioning
- License
The following is the same as using Whisper.default(). This example does not contain a set onClick action or time out duration. The Whisper will auto-dismiss based on message length and Whisper.GlobalConfig.timeoutLengthPerCharacter.
In this example, this
is the Activity.
Whisper(this, "I am a Whisper using the Default profile. I will auto-dismiss if not clicked.") |
The following demonstrates displaying multiple Whispers at once, different forms of auto-dismissing, and how they are queued for auto-dismissing (skipping in order any that are not set for auto-dismissal).
In the example, this
is the Activity.
- The info Whisper has a set duration and will auto-dismiss once it is displayed on screen for that amount of time.
- The warn Whisper has a duration of 0 meaning it will never auto-dismiss (but can be dismissed by tapping it or calling a Whisper removal function like Whisper.remove() or Whisper.clear()).
- The error Whisper does not have a defined duration meaning the duration before auto-dismissing will be based automatically by the message length and Whisper.GlobalConfig.timeoutLengthPerCharacter.
Whisper.info(this, "Auto-dismiss set for 2.5 seconds", 2500)
Whisper.warn(this, "Never auto-dismiss", 0)
Whisper.error(this, "Auto-dismiss time out driven by message length") |
The following demonstrates dismissing a Whisper by tapping it and performing an action when tapped (opening another Whisper in this case). Alternatives to closing a Whisper includes letting it auto-dismiss, calling Whisper.remove(), or calling Whisper.clear(). Whisper.remove()
and Whisper.clear()
are demonstrated in Example 4.
NOTE: A defined onClick is not required for dismissing a Whisper by tapping it. Leaving the onClick
parameter undefined or null will still allow a user to tap a Whisper to dismiss it (as long as Whisper.GlobalConfig.tapToDismiss is true).
Whisper.critical(
activity = this,
message = "Tap to dismiss and perform an additional action",
duration = 0
) { activity, whisperId ->
Whisper.info(activity, "You closed the previous Whisper!")
} |
The following demonstrates the use of Whisper.remove() and Whisper.clear(). Whispers can also be dismissed by letting them auto-dismiss or by tapping (as long as Whisper.GlobalConfig.tapToDismiss is true). See Example 2 and Example 3 for demonstrations of Whispers closing in other ways.
val whisperId = Whisper.trace(
activity = this,
message = "Whisper 1: Use my returned Whisper ID when calling Whisper.remove()",
duration = 0
)
Whisper.fatal(
activity = this,
message = "Whisper 2: Dismiss me with Whisper.clear()",
duration = 0
)
Whisper.fatal(
activity = this,
message = "Whisper 3: Dismiss me with Whisper.clear()",
duration = 0
)
// ...
// Button onClick action for "Pass Whisper 1's Whisper ID to Whisper.remove()":
Whisper.remove(this, whisperId)
// Button onClick action for "Call Whisper.clear()":
Whisper.clear(this) |
Sample whisper.yaml's can be copied or downloaded from /yaml-samples/.
While not required to use Whisper, it is highly recommended to add a whisper.yaml configuration file with your desired changes to your project. The YAML configuration file is an optional file that automatically sets Whisper configurations (Whisper searches for the file and applies it during the first Whisper call. Default values are used if whisper.yaml is not found).
- Any
whisper.yaml
from /yaml-samples/ can be used. Or if preferred, the default whisper.yaml file can be downloaded/copied here. - Add whisper.yaml to your module's assets resource folder (See screenshot below)
Example: YourProject\app\src\main\assets\whisper.yaml - YAML file name must be whisper.yaml. However, this can be changed to a different file name and extension by updating
Whisper.GlobalConfig.yamlFileName
. This change MUST be made before any other calls are made to Whisper. Because of the confusion this may cause, it is not recommended to change the whisper.yaml file name. - Update the YAML with your desired changes. Any option you do not wish to change from the default value can be left untouched or removed from the YAML file.
- Done! The first Whisper created in the lifecycle of your app will apply the whisper.yaml settings. The first time a Whisper is opened, the YAML is applied. If a yaml file is not found or present, all configuration options are set to their default values.
For all YAML configurable fields, examples, and documentation, please see configuration.md.
The following YAML functions are unnecessary to call for most use cases. These functions will either apply whisper.yaml if it has not been applied yet or force it to apply again. However, whisper.yaml automatically applies when calling Whisper for the first time in your app's lifecycle (thus meaning these functions should not be used in standard use cases).
-
- If a whisper.yaml config is present in your project, this function applies it to your Whisper settings only if whisper.yaml has not already been applied prior in the lifecycle of the app. whisper.yaml automatically applies to your settings when creating a Whisper for the first time in your app's lifecycle. The only time this function may need to be called is if there was dynamic code value changes made to Whisper.GlobalConfig or the profiles prior to creating your first whisper. This so whisper.yaml does not overwrite those programmatic changes.
Note: It is not recommended to ever make Whisper.GlobalConfig or profile changes programmatically. Recommended is to only use whisper.yaml for configuration changes.
- If a whisper.yaml config is present in your project, this function applies it to your Whisper settings only if whisper.yaml has not already been applied prior in the lifecycle of the app. whisper.yaml automatically applies to your settings when creating a Whisper for the first time in your app's lifecycle. The only time this function may need to be called is if there was dynamic code value changes made to Whisper.GlobalConfig or the profiles prior to creating your first whisper. This so whisper.yaml does not overwrite those programmatic changes.
-
- If a whisper.yaml config is present in your project, this function will overwrite any config changes made. This includes if prior changes were made programmatically to Whisper.GlobalConfig, the profiles, or if whisper.yaml was already applied prior in the life of your app. whisper.yaml automatically applies to your settings when creating a Whisper for the first time in your app's lifecycle. The only time this function may be needed is if dynamic code value changes were made to Whisper.GlobalConfig or the profiles that now need to be reverted. This so whisper.yaml overwrites all those programmatic changes no longer needed.
Note: It is not recommended to ever make Whisper.GlobalConfig or profile changes programmatically. Recommended is to only use whisper.yaml for configuration changes.
- If a whisper.yaml config is present in your project, this function will overwrite any config changes made. This includes if prior changes were made programmatically to Whisper.GlobalConfig, the profiles, or if whisper.yaml was already applied prior in the life of your app. whisper.yaml automatically applies to your settings when creating a Whisper for the first time in your app's lifecycle. The only time this function may be needed is if dynamic code value changes were made to Whisper.GlobalConfig or the profiles that now need to be reverted. This so whisper.yaml overwrites all those programmatic changes no longer needed.
Main usage and examples of Whisper can be found in Usage / Examples.
All Whisper profiles have 4 function parameters to open a Whisper. Two are mandatory and two are optional:
activity
- Activity / Required- Active Activity. Needed for displaying the Whisper and determining if the app is running in debug.
message
- String / Required- Message text to display within the Whisper.
duration
- Long / Optional- How long the Whisper displays for before being auto-dismissed.
duration
cannot be less than Whisper.GlobalConfig.durationDisplayMinimum. If it is, this value is used instead.duration
can be greater than Whisper.GlobalConfig.durationDisplayMaximum, however.- If this
duration
parameter is undefined, an auto-dismissing time out will still be used. The time out will be defined by the combination of themessage
length and Whisper.GlobalConfig.timeoutLengthPerCharacter. - To have the Whisper never auto-dismiss, pass 0 as the
duration
.
onClick
- (Activity, String) -> Unit / Optional- Will execute the passed block of code when tapped.
- Will also close the individual Whisper when tapped regardless if
onClick
is defined (as long as Whisper.GlobalConfig.tapToDismiss remains true). - Available within
onClick
will be the Activity and its unique Whisper ID. - NOTE: If a Whisper does not have a time out (
duration
passed was 0) and Whisper.GlobalConfig.tapToDismiss is set to false, the Whisper can still be dismissed in theonClick
by passing the unique Whisper ID to Whisper.remove() or calling Whisper.clear().
Activities that may use Whisper should add Whsiper.finish()
to their onDestroy. Without it, the following error may display in the logs: android.view.WindowLeaked
override fun onDestroy() {
super.onDestroy()
Whisper.finish(this)
}
Calling Whisper with a profile is the main use of Whisper. There are 8 profile options to allow for different colors and styles for better customizing Whisper. Two profiles, trace and debug, are reserved as debugging Whispers that do not show in release builds of the app.
Creates a new Whisper using the Default profile. Can be called with Whisper()
, Whisper.invoke()
, or Whisper.default()
.
Whisper(activity, "Default Whisper profile")
// or
Whisper.invoke(activity, "Default Whisper profile")
// or
Whisper.default(activity, "Default Whisper profile") |
Creates a new Whisper using the Info profile.
Whisper.info(activity, "Info Whisper profile") |
Creates a new Whisper using the Warn profile.
Whisper.warn(activity, "Warn Whisper profile") |
Creates a new Whisper using the Error profile.
Whisper.error(activity, "Error Whisper profile") |
Creates a new Whisper using the Fatal profile.
Whisper.fatal(activity, "Fatal Whisper profile") |
Creates a new Whisper using the Critical profile.
Whisper.critical(activity, "Critical Whisper profile") |
Creates a new Whisper using the Trace profile. Whisper.debug()
and Whisper.trace()
will only be created if the app running in a debug build.
Whisper.trace(activity, "Trace Whisper profile") |
Creates a new Whisper using the Debug profile. Whisper.debug()
and Whisper.trace()
will only be created if the app running in a debug build.
Whisper.debug(activity, "Debug Whisper profile") |
There are two ways to update from the default configurations:
- Updating and importing the whisper.yaml into your project (recommended)
- Programmatically in code (not recommended in most cases)
Please see the configuration.md documentation for more information, examples, and screenshots of each configuration option.
See the configuration markdown for an example of each configuration option. Each config options (both GlobalConfig and Profile Specific) can be navigated to directly with the links below
- pixelDensityUnit
- positionOnScreen
- sortOrder
- maxVisible
- displaySpace
- timeoutLengthPerCharacter
- durationDisplayMinimum
- durationDisplayMaximum
- animationTransitionDuration
- timeoutOnlyForOldestWhisper
- tapToDismiss
- Offset
- Profile
Whispers can be dismissed in multiple ways. This includes an auto-dismiss time out, a set-dismiss time out, clicking the Whisper (so long as Whisper.GlobalConfig.tapToDismiss is true), or using Whisper.remove() or Whisper.clear().
-
- Anytime a Whisper is created, a unique
whisperId
(UUID) will be returned. This can be ignored if there is no intention of callingWhisper.remove()
for that specific Whisper. Otherwise, thiswhisperId
can be stored and used anytime to dismiss the active Whisper (nothing will happen if the Whisper is already dismissed). For a demonstration, see example 4.Whisper.remove(activity, whisperId)
- Anytime a Whisper is created, a unique
-
- All active Whispers (visibly being displayed and invisible Whispers queued) can all be removed by calling
Whisper.clear()
Whisper.clear(activity)
- All active Whispers (visibly being displayed and invisible Whispers queued) can all be removed by calling
To get a real-time count of all active Whispers (visibly being displayed and invisible Whispers queued), use the following:
Whisper.activeWhisperCount()
A custom vibration can be applied per Whisper profile. More information and configuration details can be found in configurations.md.
If using Vibrate, make sure your module's AndroidManifest.xml
includes the following, otherwise vibration will not work:
<uses-permission android:name="android.permission.VIBRATE"/>
The device's notification or a custom sound file can be played per Whisper profile.
If using a custom sound file, the file must be in module's res/raw
directory. The set value must be the sound file name without the extension.
Example: src/main/res/raw/horn.mp3 -> "horn"
Custom fonts can be applied per profile by setting the font file name to Whisper.PROFILE.design.text.font.fontFamily.
Custom fonts need to be in the module's /assets/
directory. Fonts should be either .ttf
or .otf
. The set value should be the font name with the extension (with the same casing as the file name).
Example: src/main/assets/Miracode.ttf -> "Miracode.ttf"
Whispers do not need to be placed in coroutines. However, if Whispers need to be placed in a coroutine, using Dispatchers.Main
is recommended to ensure proper behavior.
This may look like the following:
CoroutineScope(Dispatchers.Main).launch {
// Whispers here
}
- Add JitPack to your project's root
build.gradle
at the end ofrepositories
:
-
dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { mavenCentral() maven { url 'https://jitpack.io' } } }
- In the
build.gradle
of the module(s) you wish to use Whisper with, add the following todependencies
:
-
dependencies { // Required: Installs the .aar without any documentation. implementation 'com.github.digidemic:whisper:1.0.0' // Optional: Displays documentation while writing coding. implementation 'com.github.digidemic:whisper:1.0.0:javadoc' // Optional: Displays documentation (more comprehensive than javadoc in some cases) and uncompiled code when stepping into library. implementation 'com.github.digidemic:whisper:1.0.0:sources' }
- Sync gradle successfully.
- Done! Your Android project is now ready to use Whisper. Go to Examples or Syntax for Whisper usage!
- SemVer is used for versioning.
- Given a version number MAJOR . MINOR . PATCH
- MAJOR version - Incompatible API changes.
- MINOR version - Functionality added in a backwards-compatible manner.
- PATCH version - Backwards-compatible bug fixes.
Whisper created by Adam Steinberg of DIGIDEMIC, LLC
Copyright 2024 DIGIDEMIC, LLC
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
http://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.
The Whisper Example App uses fonts: Acrylic.otf
, Miracode.ttf
, and Tachyo.otf
. All are under SIL OPEN FONT LICENSE Version 1.1. A copy of each license can be found in in example app's assets directory.
Whisper consumes another DIGIDEMIC library, Kyaml, to read and apply the whisper.yaml config file.