forked from github/szkolny
[Gradle] Extract nachos dependency.
This commit is contained in:
parent
75b3485ab4
commit
15f9db5ca6
@ -171,7 +171,7 @@ dependencies {
|
||||
implementation "eu.szkolny:cafebar:5bf0c618de"
|
||||
implementation "eu.szkolny:material-about-library:0534abf316"
|
||||
implementation project(":mhttp")
|
||||
implementation project(":nachos")
|
||||
implementation "eu.szkolny:nachos:0e5dfcaceb"
|
||||
//implementation project(":Navigation")
|
||||
implementation project(":szkolny-font")
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion setup.compileSdk
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 15
|
||||
targetSdkVersion setup.targetSdk
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "com.android.support:support-compat:28.0.0"
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
def isReleaseBuild() {
|
||||
return VERSION_NAME.contains("SNAPSHOT") == false
|
||||
}
|
||||
|
||||
def getReleaseRepositoryUrl() {
|
||||
return ARTIFACT_REPO
|
||||
}
|
||||
|
||||
def getSnapshotRepositoryUrl() {
|
||||
return ARTIFACT_SNAPSHOT_REPO
|
||||
}
|
||||
|
||||
def getRepositoryUsername() {
|
||||
return System.properties['username']
|
||||
}
|
||||
|
||||
def getRepositoryPassword() {
|
||||
return System.properties['password']
|
||||
}
|
||||
|
||||
afterEvaluate { project ->
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
pom.groupId = GROUP
|
||||
pom.artifactId = POM_ARTIFACT_ID
|
||||
pom.version = VERSION_NAME
|
||||
|
||||
repository(url: getReleaseRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
snapshotRepository(url: getSnapshotRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name POM_NAME
|
||||
packaging POM_PACKAGING
|
||||
description POM_DESCRIPTION
|
||||
url POM_URL
|
||||
|
||||
scm {
|
||||
url POM_SCM_URL
|
||||
connection POM_SCM_CONNECTION
|
||||
developerConnection POM_SCM_DEV_CONNECTION
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name POM_LICENCE_NAME
|
||||
url POM_LICENCE_URL
|
||||
distribution POM_LICENCE_DIST
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id POM_DEVELOPER_ID
|
||||
name POM_DEVELOPER_NAME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task installArchives(type: Upload) {
|
||||
description "Installs the artifacts to the local Maven repository."
|
||||
configuration = configurations['archives']
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
pom.groupId = GROUP
|
||||
pom.artifactId = POM_ARTIFACT_ID
|
||||
pom.version = VERSION_NAME
|
||||
|
||||
repository url: "file://${System.properties['user.home']}/.m2/repository"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
task androidJavadocs(type: Javadoc) {
|
||||
source = android.sourceSets.main.java.srcDirs
|
||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
failOnError = false
|
||||
}
|
||||
|
||||
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
|
||||
classifier = 'javadoc'
|
||||
from androidJavadocs.destinationDir
|
||||
}
|
||||
|
||||
task androidSourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives androidSourcesJar
|
||||
archives androidJavadocsJar
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.hootsuite.nachos">
|
||||
|
||||
</manifest>
|
@ -1,78 +0,0 @@
|
||||
package com.hootsuite.nachos;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
|
||||
public class ChipConfiguration {
|
||||
|
||||
private final int mChipHorizontalSpacing;
|
||||
private final ColorStateList mChipBackground;
|
||||
private final int mChipCornerRadius;
|
||||
private final int mChipTextColor;
|
||||
private final int mChipTextSize;
|
||||
private final int mChipHeight;
|
||||
private final int mChipVerticalSpacing;
|
||||
private final int mMaxAvailableWidth;
|
||||
|
||||
/**
|
||||
* Creates a new ChipConfiguration. You can pass in {@code -1} or {@code null} for any of the parameters to indicate that parameter should be
|
||||
* ignored.
|
||||
*
|
||||
* @param chipHorizontalSpacing the amount of horizontal space (in pixels) to put between consecutive chips
|
||||
* @param chipBackground the {@link ColorStateList} to set as the background of the chips
|
||||
* @param chipCornerRadius the corner radius of the chip background, in pixels
|
||||
* @param chipTextColor the color to set as the text color of the chips
|
||||
* @param chipTextSize the font size (in pixels) to use for the text of the chips
|
||||
* @param chipHeight the height (in pixels) of each chip
|
||||
* @param chipVerticalSpacing the amount of vertical space (in pixels) to put between chips on consecutive lines
|
||||
* @param maxAvailableWidth the maximum available with for a chip (the width of a full line of text in the text view)
|
||||
*/
|
||||
ChipConfiguration(int chipHorizontalSpacing,
|
||||
ColorStateList chipBackground,
|
||||
int chipCornerRadius,
|
||||
int chipTextColor,
|
||||
int chipTextSize,
|
||||
int chipHeight,
|
||||
int chipVerticalSpacing,
|
||||
int maxAvailableWidth) {
|
||||
mChipHorizontalSpacing = chipHorizontalSpacing;
|
||||
mChipBackground = chipBackground;
|
||||
mChipCornerRadius = chipCornerRadius;
|
||||
mChipTextColor = chipTextColor;
|
||||
mChipTextSize = chipTextSize;
|
||||
mChipHeight = chipHeight;
|
||||
mChipVerticalSpacing = chipVerticalSpacing;
|
||||
mMaxAvailableWidth = maxAvailableWidth;
|
||||
}
|
||||
|
||||
public int getChipHorizontalSpacing() {
|
||||
return mChipHorizontalSpacing;
|
||||
}
|
||||
|
||||
public ColorStateList getChipBackground() {
|
||||
return mChipBackground;
|
||||
}
|
||||
|
||||
public int getChipCornerRadius() {
|
||||
return mChipCornerRadius;
|
||||
}
|
||||
|
||||
public int getChipTextColor() {
|
||||
return mChipTextColor;
|
||||
}
|
||||
|
||||
public int getChipTextSize() {
|
||||
return mChipTextSize;
|
||||
}
|
||||
|
||||
public int getChipHeight() {
|
||||
return mChipHeight;
|
||||
}
|
||||
|
||||
public int getChipVerticalSpacing() {
|
||||
return mChipVerticalSpacing;
|
||||
}
|
||||
|
||||
public int getMaxAvailableWidth() {
|
||||
return mMaxAvailableWidth;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,30 +0,0 @@
|
||||
package com.hootsuite.nachos.chip;
|
||||
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public interface Chip {
|
||||
|
||||
/**
|
||||
* @return the text represented by this Chip
|
||||
*/
|
||||
CharSequence getText();
|
||||
|
||||
/**
|
||||
* @return the data associated with this Chip or null if no data is associated with it
|
||||
*/
|
||||
@Nullable
|
||||
Object getData();
|
||||
|
||||
/**
|
||||
* @return the width of the Chip or -1 if the Chip hasn't been given the chance to calculate its width
|
||||
*/
|
||||
int getWidth();
|
||||
|
||||
/**
|
||||
* Sets the UI state.
|
||||
*
|
||||
* @param stateSet one of the state constants in {@link android.view.View}
|
||||
*/
|
||||
void setState(int[] stateSet);
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package com.hootsuite.nachos.chip;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
|
||||
/**
|
||||
* Interface to allow the creation and configuration of chips
|
||||
*
|
||||
* @param <C> The type of {@link Chip} that the implementation will create/configure
|
||||
*/
|
||||
public interface ChipCreator<C extends Chip> {
|
||||
|
||||
/**
|
||||
* Creates a chip from the given context and text. Use this method when creating a brand new chip from a piece of text.
|
||||
*
|
||||
* @param context the {@link Context} to use to initialize the chip
|
||||
* @param text the text the Chip should represent
|
||||
* @param data the data to associate with the Chip, or null to associate no data
|
||||
* @return the created chip
|
||||
*/
|
||||
C createChip(@NonNull Context context, @NonNull CharSequence text, @Nullable Object data);
|
||||
|
||||
/**
|
||||
* Creates a chip from the given context and existing chip. Use this method when recreating a chip from an existing one.
|
||||
*
|
||||
* @param context the {@link Context} to use to initialize the chip
|
||||
* @param existingChip the chip that the created chip should be based on
|
||||
* @return the created chip
|
||||
*/
|
||||
C createChip(@NonNull Context context, @NonNull C existingChip);
|
||||
|
||||
/**
|
||||
* Applies the given {@link ChipConfiguration} to the given {@link Chip}. Use this method to customize the appearance/behavior of a chip before
|
||||
* adding it to the text.
|
||||
*
|
||||
* @param chip the chip to configure
|
||||
* @param chipConfiguration the configuration to apply to the chip
|
||||
*/
|
||||
void configureChip(@NonNull C chip, @NonNull ChipConfiguration chipConfiguration);
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package com.hootsuite.nachos.chip;
|
||||
|
||||
public class ChipInfo {
|
||||
|
||||
private final CharSequence mText;
|
||||
private final Object mData;
|
||||
|
||||
public ChipInfo(CharSequence text, Object data) {
|
||||
this.mText = text;
|
||||
this.mData = data;
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return mData;
|
||||
}
|
||||
}
|
@ -1,511 +0,0 @@
|
||||
package com.hootsuite.nachos.chip;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.style.ImageSpan;
|
||||
|
||||
import androidx.annotation.Dimension;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.hootsuite.nachos.R;
|
||||
|
||||
/**
|
||||
* A Span that displays text and an optional icon inside of a material design chip. The chip's dimensions, colors etc. can be extensively customized
|
||||
* through the various setter methods available in this class.
|
||||
* The basic structure of the chip is the following:
|
||||
* For chips with the icon on right:
|
||||
* <pre>
|
||||
*
|
||||
* (chip vertical spacing / 2)
|
||||
* ----------------------------------------------------------
|
||||
* | |
|
||||
* (left margin) | (padding edge) text (padding between image) icon | (right margin)
|
||||
* | |
|
||||
* ----------------------------------------------------------
|
||||
* (chip vertical spacing / 2)
|
||||
*
|
||||
* </pre>
|
||||
* For chips with the icon on the left (see {@link #setShowIconOnLeft(boolean)}):
|
||||
* <pre>
|
||||
*
|
||||
* (chip vertical spacing / 2)
|
||||
* ----------------------------------------------------------
|
||||
* | |
|
||||
* (left margin) | icon (padding between image) text (padding edge) | (right margin)
|
||||
* | |
|
||||
* ----------------------------------------------------------
|
||||
* (chip vertical spacing / 2)
|
||||
* </pre>
|
||||
*/
|
||||
public class ChipSpan extends ImageSpan implements Chip {
|
||||
|
||||
private static final float SCALE_PERCENT_OF_CHIP_HEIGHT = 0.70f;
|
||||
private static final boolean ICON_ON_LEFT_DEFAULT = true;
|
||||
|
||||
private int[] mStateSet = new int[]{};
|
||||
|
||||
private String mEllipsis;
|
||||
|
||||
private ColorStateList mDefaultBackgroundColor;
|
||||
private ColorStateList mBackgroundColor;
|
||||
private int mTextColor;
|
||||
private int mCornerRadius = -1;
|
||||
private int mIconBackgroundColor;
|
||||
|
||||
private int mTextSize = -1;
|
||||
private int mPaddingEdgePx;
|
||||
private int mPaddingBetweenImagePx;
|
||||
private int mLeftMarginPx;
|
||||
private int mRightMarginPx;
|
||||
private int mMaxAvailableWidth = -1;
|
||||
|
||||
private CharSequence mText;
|
||||
private String mTextToDraw;
|
||||
|
||||
private Drawable mIcon;
|
||||
private boolean mShowIconOnLeft = ICON_ON_LEFT_DEFAULT;
|
||||
|
||||
private int mChipVerticalSpacing = 0;
|
||||
private int mChipHeight = -1;
|
||||
private int mChipWidth = -1;
|
||||
private int mIconWidth;
|
||||
|
||||
private int mCachedSize = -1;
|
||||
|
||||
private Object mData;
|
||||
|
||||
/**
|
||||
* Constructs a new ChipSpan.
|
||||
*
|
||||
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
|
||||
* @param text the text for the ChipSpan to display
|
||||
* @param icon an optional icon (can be {@code null}) for the ChipSpan to display
|
||||
*/
|
||||
public ChipSpan(@NonNull Context context, @NonNull CharSequence text, @Nullable Drawable icon, Object data) {
|
||||
super(icon);
|
||||
mIcon = icon;
|
||||
mText = text;
|
||||
mTextToDraw = mText.toString();
|
||||
|
||||
mEllipsis = context.getString(R.string.chip_ellipsis);
|
||||
|
||||
mDefaultBackgroundColor = ContextCompat.getColorStateList(context, R.color.chip_material_background);
|
||||
mBackgroundColor = mDefaultBackgroundColor;
|
||||
|
||||
mTextColor = ContextCompat.getColor(context, R.color.chip_default_text_color);
|
||||
mIconBackgroundColor = ContextCompat.getColor(context, R.color.chip_default_icon_background_color);
|
||||
|
||||
Resources resources = context.getResources();
|
||||
mPaddingEdgePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_edge);
|
||||
mPaddingBetweenImagePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_between_image);
|
||||
mLeftMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_left_margin);
|
||||
mRightMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_right_margin);
|
||||
|
||||
mData = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor to recreate a ChipSpan from an existing one
|
||||
*
|
||||
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
|
||||
* @param chipSpan the ChipSpan to copy
|
||||
*/
|
||||
public ChipSpan(@NonNull Context context, @NonNull ChipSpan chipSpan) {
|
||||
this(context, chipSpan.getText(), chipSpan.getDrawable(), chipSpan.getData());
|
||||
|
||||
mDefaultBackgroundColor = chipSpan.mDefaultBackgroundColor;
|
||||
mTextColor = chipSpan.mTextColor;
|
||||
mIconBackgroundColor = chipSpan.mIconBackgroundColor;
|
||||
mCornerRadius = chipSpan.mCornerRadius;
|
||||
|
||||
mTextSize = chipSpan.mTextSize;
|
||||
mPaddingEdgePx = chipSpan.mPaddingEdgePx;
|
||||
mPaddingBetweenImagePx = chipSpan.mPaddingBetweenImagePx;
|
||||
mLeftMarginPx = chipSpan.mLeftMarginPx;
|
||||
mRightMarginPx = chipSpan.mRightMarginPx;
|
||||
mMaxAvailableWidth = chipSpan.mMaxAvailableWidth;
|
||||
|
||||
mShowIconOnLeft = chipSpan.mShowIconOnLeft;
|
||||
|
||||
mChipVerticalSpacing = chipSpan.mChipVerticalSpacing;
|
||||
mChipHeight = chipSpan.mChipHeight;
|
||||
|
||||
mStateSet = chipSpan.mStateSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getData() {
|
||||
return mData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the height of the chip. This height should not include any extra spacing (for extra vertical spacing call {@link #setChipVerticalSpacing(int)}).
|
||||
* The background of the chip will fill the full height provided here. If this method is never called, the chip will have the height of one full line
|
||||
* of text by default. If {@code -1} is passed here, the chip will revert to this default behavior.
|
||||
*
|
||||
* @param chipHeight the height to set in pixels
|
||||
*/
|
||||
public void setChipHeight(int chipHeight) {
|
||||
mChipHeight = chipHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vertical spacing to include in between chips. Half of the value set here will be placed as empty space above the chip and half the value
|
||||
* will be placed as empty space below the chip. Therefore chips on consecutive lines will have the full value as vertical space in between them.
|
||||
* This spacing is achieved by adjusting the font metrics used by the text view containing these chips; however it does not come into effect until
|
||||
* at least one chip is created. Note that vertical spacing is dependent on having a fixed chip height (set in {@link #setChipHeight(int)}). If a
|
||||
* height is not specified in that method, the value set here will be ignored.
|
||||
*
|
||||
* @param chipVerticalSpacing the vertical spacing to set in pixels
|
||||
*/
|
||||
public void setChipVerticalSpacing(int chipVerticalSpacing) {
|
||||
mChipVerticalSpacing = chipVerticalSpacing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the font size for the chip's text. If this method is never called, the chip text will have the same font size as the text in the TextView
|
||||
* containing this chip by default. If {@code -1} is passed here, the chip will revert to this default behavior.
|
||||
*
|
||||
* @param size the font size to set in pixels
|
||||
*/
|
||||
public void setTextSize(int size) {
|
||||
mTextSize = size;
|
||||
invalidateCachedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color for the chip's text.
|
||||
*
|
||||
* @param color the color to set (as a hexadecimal number in the form 0xAARRGGBB)
|
||||
*/
|
||||
public void setTextColor(int color) {
|
||||
mTextColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets where the icon (if an icon was provided in the constructor) will appear.
|
||||
*
|
||||
* @param showIconOnLeft if true, the icon will appear on the left, otherwise the icon will appear on the right
|
||||
*/
|
||||
public void setShowIconOnLeft(boolean showIconOnLeft) {
|
||||
this.mShowIconOnLeft = showIconOnLeft;
|
||||
invalidateCachedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the left margin. This margin will appear as empty space (it will not share the chip's background color) to the left of the chip.
|
||||
*
|
||||
* @param leftMarginPx the left margin to set in pixels
|
||||
*/
|
||||
public void setLeftMargin(int leftMarginPx) {
|
||||
mLeftMarginPx = leftMarginPx;
|
||||
invalidateCachedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the right margin. This margin will appear as empty space (it will not share the chip's background color) to the right of the chip.
|
||||
*
|
||||
* @param rightMarginPx the right margin to set in pixels
|
||||
*/
|
||||
public void setRightMargin(int rightMarginPx) {
|
||||
this.mRightMarginPx = rightMarginPx;
|
||||
invalidateCachedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background color. To configure which color in the {@link ColorStateList} is shown you can call {@link #setState(int[])}.
|
||||
* Passing {@code null} here will cause the chip to revert to it's default background.
|
||||
*
|
||||
* @param backgroundColor a {@link ColorStateList} containing backgrounds for different states.
|
||||
* @see #setState(int[])
|
||||
*/
|
||||
public void setBackgroundColor(@Nullable ColorStateList backgroundColor) {
|
||||
mBackgroundColor = backgroundColor != null ? backgroundColor : mDefaultBackgroundColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chip background corner radius.
|
||||
*
|
||||
* @param cornerRadius The corner radius value, in pixels.
|
||||
*/
|
||||
public void setCornerRadius(@Dimension int cornerRadius) {
|
||||
mCornerRadius = cornerRadius;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the icon background color. This is the color of the circle that gets drawn behind the icon passed to the
|
||||
* {@link #ChipSpan(Context, CharSequence, Drawable, Object)} constructor}
|
||||
*
|
||||
* @param iconBackgroundColor the icon background color to set (as a hexadecimal number in the form 0xAARRGGBB)
|
||||
*/
|
||||
public void setIconBackgroundColor(int iconBackgroundColor) {
|
||||
mIconBackgroundColor = iconBackgroundColor;
|
||||
}
|
||||
|
||||
public void setMaxAvailableWidth(int maxAvailableWidth) {
|
||||
mMaxAvailableWidth = maxAvailableWidth;
|
||||
invalidateCachedSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the UI state. This state will be reflected in the background color drawn for the chip.
|
||||
*
|
||||
* @param stateSet one of the state constants in {@link android.view.View}
|
||||
* @see #setBackgroundColor(ColorStateList)
|
||||
*/
|
||||
@Override
|
||||
public void setState(int[] stateSet) {
|
||||
this.mStateSet = stateSet != null ? stateSet : new int[]{};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth() {
|
||||
// If we haven't actually calculated a chip width yet just return -1, otherwise return the chip width + margins
|
||||
return mChipWidth != -1 ? (mLeftMarginPx + mChipWidth + mRightMarginPx) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
|
||||
boolean usingFontMetrics = (fm != null);
|
||||
|
||||
// Adjust the font metrics regardless of whether or not there is a cached size so that the text view can maintain its height
|
||||
if (usingFontMetrics) {
|
||||
adjustFontMetrics(paint, fm);
|
||||
}
|
||||
|
||||
if (mCachedSize == -1 && usingFontMetrics) {
|
||||
mIconWidth = (mIcon != null) ? calculateChipHeight(fm.top, fm.bottom) : 0;
|
||||
|
||||
int actualWidth = calculateActualWidth(paint);
|
||||
mCachedSize = actualWidth;
|
||||
|
||||
if (mMaxAvailableWidth != -1) {
|
||||
int maxAvailableWidthMinusMargins = mMaxAvailableWidth - mLeftMarginPx - mRightMarginPx;
|
||||
if (actualWidth > maxAvailableWidthMinusMargins) {
|
||||
mTextToDraw = mText + mEllipsis;
|
||||
|
||||
while ((calculateActualWidth(paint) > maxAvailableWidthMinusMargins) && mTextToDraw.length() > 0) {
|
||||
int lastCharacterIndex = mTextToDraw.length() - mEllipsis.length() - 1;
|
||||
if (lastCharacterIndex < 0) {
|
||||
break;
|
||||
}
|
||||
mTextToDraw = mTextToDraw.substring(0, lastCharacterIndex) + mEllipsis;
|
||||
}
|
||||
|
||||
// Avoid a negative width
|
||||
mChipWidth = Math.max(0, maxAvailableWidthMinusMargins);
|
||||
mCachedSize = mMaxAvailableWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mCachedSize;
|
||||
}
|
||||
|
||||
private int calculateActualWidth(Paint paint) {
|
||||
// Only change the text size if a text size was set
|
||||
if (mTextSize != -1) {
|
||||
paint.setTextSize(mTextSize);
|
||||
}
|
||||
|
||||
int totalPadding = mPaddingEdgePx;
|
||||
|
||||
// Find text width
|
||||
Rect bounds = new Rect();
|
||||
paint.getTextBounds(mTextToDraw, 0, mTextToDraw.length(), bounds);
|
||||
int textWidth = bounds.width();
|
||||
|
||||
if (mIcon != null) {
|
||||
totalPadding += mPaddingBetweenImagePx;
|
||||
} else {
|
||||
totalPadding += mPaddingEdgePx;
|
||||
}
|
||||
|
||||
mChipWidth = totalPadding + textWidth + mIconWidth;
|
||||
return getWidth();
|
||||
}
|
||||
|
||||
public void invalidateCachedSize() {
|
||||
mCachedSize = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the provided font metrics to make it seem like the font takes up {@code mChipHeight + mChipVerticalSpacing} pixels in height.
|
||||
* This effectively ensures that the TextView will have a height equal to {@code mChipHeight + mChipVerticalSpacing} + whatever padding it has set.
|
||||
* In {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} the chip itself is drawn to that it is vertically centered with
|
||||
* {@code mChipVerticalSpacing / 2} pixels of space above and below it
|
||||
*
|
||||
* @param paint the paint whose font metrics should be adjusted
|
||||
* @param fm the font metrics object to populate through {@link Paint#getFontMetricsInt(Paint.FontMetricsInt)}
|
||||
*/
|
||||
private void adjustFontMetrics(Paint paint, Paint.FontMetricsInt fm) {
|
||||
// Only actually adjust font metrics if we have a chip height set
|
||||
if (mChipHeight != -1) {
|
||||
paint.getFontMetricsInt(fm);
|
||||
int textHeight = fm.descent - fm.ascent;
|
||||
// Break up the vertical spacing in half because half will go above the chip, half will go below the chip
|
||||
int halfSpacing = mChipVerticalSpacing / 2;
|
||||
|
||||
// Given that the text is centered vertically within the chip, the amount of space above or below the text (inbetween the text and chip)
|
||||
// is half their difference in height:
|
||||
int spaceBetweenChipAndText = (mChipHeight - textHeight) / 2;
|
||||
|
||||
int textTop = fm.top;
|
||||
int chipTop = fm.top - spaceBetweenChipAndText;
|
||||
|
||||
int textBottom = fm.bottom;
|
||||
int chipBottom = fm.bottom + spaceBetweenChipAndText;
|
||||
|
||||
// The text may have been taller to begin with so we take the most negative coordinate (highest up) to be the top of the content
|
||||
int topOfContent = Math.min(textTop, chipTop);
|
||||
// Same as above but we want the largest positive coordinate (lowest down) to be the bottom of the content
|
||||
int bottomOfContent = Math.max(textBottom, chipBottom);
|
||||
|
||||
// Shift the top up by halfSpacing and the bottom down by halfSpacing
|
||||
int topOfContentWithSpacing = topOfContent - halfSpacing;
|
||||
int bottomOfContentWithSpacing = bottomOfContent + halfSpacing;
|
||||
|
||||
// Change the font metrics so that the TextView thinks the font takes up the vertical space of a chip + spacing
|
||||
fm.ascent = topOfContentWithSpacing;
|
||||
fm.descent = bottomOfContentWithSpacing;
|
||||
fm.top = topOfContentWithSpacing;
|
||||
fm.bottom = bottomOfContentWithSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateChipHeight(int top, int bottom) {
|
||||
// If a chip height was set we can return that, otherwise calculate it from top and bottom
|
||||
return mChipHeight != -1 ? mChipHeight : bottom - top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
|
||||
// Shift everything mLeftMarginPx to the left to create an empty space on the left (creating the margin)
|
||||
x += mLeftMarginPx;
|
||||
if (mChipHeight != -1) {
|
||||
// If we set a chip height, adjust to vertically center chip in the line
|
||||
// Adding (bottom - top) / 2 shifts the chip down so the top of it will be centered vertically
|
||||
// Subtracting (mChipHeight / 2) shifts the chip back up so that the center of it will be centered vertically (as desired)
|
||||
top += ((bottom - top) / 2) - (mChipHeight / 2);
|
||||
bottom = top + mChipHeight;
|
||||
}
|
||||
|
||||
// Perform actual drawing
|
||||
drawBackground(canvas, x, top, bottom, paint);
|
||||
drawText(canvas, x, top, bottom, paint, mTextToDraw);
|
||||
if (mIcon != null) {
|
||||
drawIcon(canvas, x, top, bottom, paint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
|
||||
int backgroundColor = mBackgroundColor.getColorForState(mStateSet, mBackgroundColor.getDefaultColor());
|
||||
paint.setColor(backgroundColor);
|
||||
int height = calculateChipHeight(top, bottom);
|
||||
RectF rect = new RectF(x, top, x + mChipWidth, bottom);
|
||||
int cornerRadius = (mCornerRadius != -1) ? mCornerRadius : height / 2;
|
||||
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint);
|
||||
paint.setColor(mTextColor);
|
||||
}
|
||||
|
||||
private void drawText(Canvas canvas, float x, int top, int bottom, Paint paint, CharSequence text) {
|
||||
if (mTextSize != -1) {
|
||||
paint.setTextSize(mTextSize);
|
||||
}
|
||||
int height = calculateChipHeight(top, bottom);
|
||||
Paint.FontMetrics fm = paint.getFontMetrics();
|
||||
|
||||
// The top value provided here is the y coordinate for the very top of the chip
|
||||
// The y coordinate we are calculating is where the baseline of the text will be drawn
|
||||
// Our objective is to have the midpoint between the top and baseline of the text be in line with the vertical center of the chip
|
||||
// First we add height / 2 which will put the baseline at the vertical center of the chip
|
||||
// Then we add half the height of the text which will lower baseline so that the midpoint is at the vertical center of the chip as desired
|
||||
float adjustedY = top + ((height / 2) + ((-fm.top - fm.bottom) / 2));
|
||||
|
||||
// The x coordinate provided here is the left-most edge of the chip
|
||||
// If there is no icon or the icon is on the right, then the text will start at the left-most edge, but indented with the edge padding, so we
|
||||
// add mPaddingEdgePx
|
||||
// If there is an icon and it's on the left, the text will start at the left-most edge, but indented by the combined width of the icon and
|
||||
// the padding between the icon and text, so we add (mIconWidth + mPaddingBetweenImagePx)
|
||||
float adjustedX = x + ((mIcon == null || !mShowIconOnLeft) ? mPaddingEdgePx : (mIconWidth + mPaddingBetweenImagePx));
|
||||
|
||||
canvas.drawText(text, 0, text.length(), adjustedX, adjustedY, paint);
|
||||
}
|
||||
|
||||
private void drawIcon(Canvas canvas, float x, int top, int bottom, Paint paint) {
|
||||
drawIconBackground(canvas, x, top, bottom, paint);
|
||||
drawIconBitmap(canvas, x, top, bottom, paint);
|
||||
}
|
||||
|
||||
private void drawIconBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
|
||||
int height = calculateChipHeight(top, bottom);
|
||||
|
||||
paint.setColor(mIconBackgroundColor);
|
||||
|
||||
// Since it's a circle the diameter is equal to the height, so the radius == diameter / 2 == height / 2
|
||||
int radius = height / 2;
|
||||
// The coordinates that get passed to drawCircle are for the center of the circle
|
||||
// x is the left edge of the chip, (x + mChipWidth) is the right edge of the chip
|
||||
// So the center of the circle is one radius distance from either the left or right edge (depending on which side the icon is being drawn on)
|
||||
float circleX = mShowIconOnLeft ? (x + radius) : (x + mChipWidth - radius);
|
||||
// The y coordinate is always just one radius distance from the top
|
||||
canvas.drawCircle(circleX, top + radius, radius, paint);
|
||||
|
||||
paint.setColor(mTextColor);
|
||||
}
|
||||
|
||||
private void drawIconBitmap(Canvas canvas, float x, int top, int bottom, Paint paint) {
|
||||
int height = calculateChipHeight(top, bottom);
|
||||
|
||||
// Create a scaled down version of the bitmap to fit within the circle (whose diameter == height)
|
||||
Bitmap iconBitmap = Bitmap.createBitmap(mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Bitmap scaledIconBitMap = scaleDown(iconBitmap, (float) height * SCALE_PERCENT_OF_CHIP_HEIGHT, true);
|
||||
iconBitmap.recycle();
|
||||
Canvas bitmapCanvas = new Canvas(scaledIconBitMap);
|
||||
mIcon.setBounds(0, 0, bitmapCanvas.getWidth(), bitmapCanvas.getHeight());
|
||||
mIcon.draw(bitmapCanvas);
|
||||
|
||||
// We are drawing a square icon inside of a circle
|
||||
// The coordinates we pass to canvas.drawBitmap have to be for the top-left corner of the bitmap
|
||||
// The bitmap should be inset by half of (circle width - bitmap width)
|
||||
// Since it's a circle, the circle's width is equal to it's height which is equal to the chip height
|
||||
float xInsetWithinCircle = (height - bitmapCanvas.getWidth()) / 2;
|
||||
|
||||
// The icon x coordinate is going to be insetWithinCircle pixels away from the left edge of the circle
|
||||
// If the icon is on the left, the left edge of the circle is just x
|
||||
// If the icon is on the right, the left edge of the circle is x + mChipWidth - height
|
||||
float iconX = mShowIconOnLeft ? (x + xInsetWithinCircle) : (x + mChipWidth - height + xInsetWithinCircle);
|
||||
|
||||
// The y coordinate works the same way (only it's always from the top edge)
|
||||
float yInsetWithinCircle = (height - bitmapCanvas.getHeight()) / 2;
|
||||
float iconY = top + yInsetWithinCircle;
|
||||
|
||||
canvas.drawBitmap(scaledIconBitMap, iconX, iconY, paint);
|
||||
}
|
||||
|
||||
private Bitmap scaleDown(Bitmap realImage, float maxImageSize, boolean filter) {
|
||||
float ratio = Math.min(maxImageSize / realImage.getWidth(), maxImageSize / realImage.getHeight());
|
||||
int width = Math.round(ratio * realImage.getWidth());
|
||||
int height = Math.round(ratio * realImage.getHeight());
|
||||
return Bitmap.createScaledBitmap(realImage, width, height, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mText.toString();
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package com.hootsuite.nachos.chip;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
|
||||
public class ChipSpanChipCreator implements ChipCreator<ChipSpan> {
|
||||
|
||||
@Override
|
||||
public ChipSpan createChip(@NonNull Context context, @NonNull CharSequence text, Object data) {
|
||||
return new ChipSpan(context, text, null, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChipSpan createChip(@NonNull Context context, @NonNull ChipSpan existingChip) {
|
||||
return new ChipSpan(context, existingChip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureChip(@NonNull ChipSpan chip, @NonNull ChipConfiguration chipConfiguration) {
|
||||
int chipHorizontalSpacing = chipConfiguration.getChipHorizontalSpacing();
|
||||
ColorStateList chipBackground = chipConfiguration.getChipBackground();
|
||||
int chipCornerRadius = chipConfiguration.getChipCornerRadius();
|
||||
int chipTextColor = chipConfiguration.getChipTextColor();
|
||||
int chipTextSize = chipConfiguration.getChipTextSize();
|
||||
int chipHeight = chipConfiguration.getChipHeight();
|
||||
int chipVerticalSpacing = chipConfiguration.getChipVerticalSpacing();
|
||||
int maxAvailableWidth = chipConfiguration.getMaxAvailableWidth();
|
||||
|
||||
if (chipHorizontalSpacing != -1) {
|
||||
chip.setLeftMargin(chipHorizontalSpacing / 2);
|
||||
chip.setRightMargin(chipHorizontalSpacing / 2);
|
||||
}
|
||||
if (chipBackground != null) {
|
||||
chip.setBackgroundColor(chipBackground);
|
||||
}
|
||||
if (chipCornerRadius != -1) {
|
||||
chip.setCornerRadius(chipCornerRadius);
|
||||
}
|
||||
if (chipTextColor != Color.TRANSPARENT) {
|
||||
chip.setTextColor(chipTextColor);
|
||||
}
|
||||
if (chipTextSize != -1) {
|
||||
chip.setTextSize(chipTextSize);
|
||||
}
|
||||
if (chipHeight != -1) {
|
||||
chip.setChipHeight(chipHeight);
|
||||
}
|
||||
if (chipVerticalSpacing != -1) {
|
||||
chip.setChipVerticalSpacing(chipVerticalSpacing);
|
||||
}
|
||||
if (maxAvailableWidth != -1) {
|
||||
chip.setMaxAvailableWidth(maxAvailableWidth);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
package com.hootsuite.nachos.terminator;
|
||||
|
||||
import android.text.Editable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This interface is used to handle the management of characters that should trigger the creation of chips in a text view.
|
||||
*
|
||||
* @see ChipTokenizer
|
||||
*/
|
||||
public interface ChipTerminatorHandler {
|
||||
|
||||
/**
|
||||
* When a chip terminator character is encountered in newly inserted text, all tokens in the whole text view will be chipified
|
||||
*/
|
||||
int BEHAVIOR_CHIPIFY_ALL = 0;
|
||||
|
||||
/**
|
||||
* When a chip terminator character is encountered in newly inserted text, only the current token (that in which the chip terminator character
|
||||
* was found) will be chipified. This token may extend beyond where the chip terminator character was located.
|
||||
*/
|
||||
int BEHAVIOR_CHIPIFY_CURRENT_TOKEN = 1;
|
||||
|
||||
/**
|
||||
* When a chip terminator character is encountered in newly inserted text, only the text from the previous chip up until the chip terminator
|
||||
* character will be chipified. This may not be an entire token.
|
||||
*/
|
||||
int BEHAVIOR_CHIPIFY_TO_TERMINATOR = 2;
|
||||
|
||||
/**
|
||||
* Constant for use with {@link #setPasteBehavior(int)}. Use this if a paste should behave the same as a standard text input (the chip temrinators
|
||||
* will all behave according to their pre-determined behavior set through {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}).
|
||||
*/
|
||||
int PASTE_BEHAVIOR_USE_DEFAULT = -1;
|
||||
|
||||
/**
|
||||
* Sets all the characters that will be marked as chip terminators. This will replace any previously set chip terminators.
|
||||
*
|
||||
* @param chipTerminators a map of characters to be marked as chip terminators to behaviors that describe how to respond to the characters, or null
|
||||
* to remove all chip terminators
|
||||
*/
|
||||
void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators);
|
||||
|
||||
/**
|
||||
* Adds a character as a chip terminator. When the provided character is encountered in entered text, the nearby text will be chipified according
|
||||
* to the behavior provided here.
|
||||
* {@code behavior} Must be one of:
|
||||
* <ul>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param character the character to mark as a chip terminator
|
||||
* @param behavior the behavior describing how to respond to the chip terminator
|
||||
*/
|
||||
void addChipTerminator(char character, int behavior);
|
||||
|
||||
/**
|
||||
* Customizes the way paste events are handled.
|
||||
* If one of:
|
||||
* <ul>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
|
||||
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
|
||||
* </ul>
|
||||
* is passed, all chip terminators will be handled with that behavior when a paste event occurs.
|
||||
* If {@link #PASTE_BEHAVIOR_USE_DEFAULT} is passed, whatever behavior is configured for a particular chip terminator
|
||||
* (through {@link #setChipTerminators(Map)} or {@link #addChipTerminator(char, int)} will be used for that chip terminator
|
||||
*
|
||||
* @param pasteBehavior the behavior to use on a paste event
|
||||
*/
|
||||
void setPasteBehavior(int pasteBehavior);
|
||||
|
||||
/**
|
||||
* Parses the provided text looking for characters marked as chip terminators through {@link #addChipTerminator(char, int)} and {@link #setChipTerminators(Map)}.
|
||||
* The provided {@link Editable} will be modified if chip terminators are encountered.
|
||||
*
|
||||
* @param tokenizer the {@link ChipTokenizer} to use to identify and chipify tokens in the text
|
||||
* @param text the text in which to search for chip terminators tokens to be chipped
|
||||
* @param start the index at which to begin looking for chip terminators (inclusive)
|
||||
* @param end the index at which to end looking for chip terminators (exclusive)
|
||||
* @param isPasteEvent true if this handling is for a paste event in which case the behavior set in {@link #setPasteBehavior(int)} will be used,
|
||||
* otherwise false
|
||||
* @return an non-negative integer indicating the index where the cursor (selection) should be placed once the handling is complete,
|
||||
* or a negative integer indicating that the cursor should not be moved.
|
||||
*/
|
||||
int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent);
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
package com.hootsuite.nachos.terminator;
|
||||
|
||||
import android.text.Editable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DefaultChipTerminatorHandler implements ChipTerminatorHandler {
|
||||
|
||||
@Nullable
|
||||
private Map<Character, Integer> mChipTerminators;
|
||||
private int mPasteBehavior = BEHAVIOR_CHIPIFY_TO_TERMINATOR;
|
||||
|
||||
@Override
|
||||
public void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators) {
|
||||
mChipTerminators = chipTerminators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChipTerminator(char character, int behavior) {
|
||||
if (mChipTerminators == null) {
|
||||
mChipTerminators = new HashMap<>();
|
||||
}
|
||||
|
||||
mChipTerminators.put(character, behavior);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasteBehavior(int pasteBehavior) {
|
||||
mPasteBehavior = pasteBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent) {
|
||||
// If we don't have a tokenizer or any chip terminators, there's nothing to look for
|
||||
if (mChipTerminators == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
TextIterator textIterator = new TextIterator(text, start, end);
|
||||
int selectionIndex = -1;
|
||||
|
||||
characterLoop:
|
||||
while (textIterator.hasNextCharacter()) {
|
||||
char theChar = textIterator.nextCharacter();
|
||||
if (isChipTerminator(theChar)) {
|
||||
int behavior = (isPasteEvent && mPasteBehavior != PASTE_BEHAVIOR_USE_DEFAULT) ? mPasteBehavior : mChipTerminators.get(theChar);
|
||||
int newSelection = -1;
|
||||
switch (behavior) {
|
||||
case BEHAVIOR_CHIPIFY_ALL:
|
||||
selectionIndex = handleChipifyAll(textIterator, tokenizer);
|
||||
break characterLoop;
|
||||
case BEHAVIOR_CHIPIFY_CURRENT_TOKEN:
|
||||
newSelection = handleChipifyCurrentToken(textIterator, tokenizer);
|
||||
break;
|
||||
case BEHAVIOR_CHIPIFY_TO_TERMINATOR:
|
||||
newSelection = handleChipifyToTerminator(textIterator, tokenizer);
|
||||
break;
|
||||
}
|
||||
|
||||
if (newSelection != -1) {
|
||||
selectionIndex = newSelection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectionIndex;
|
||||
}
|
||||
|
||||
private int handleChipifyAll(TextIterator textIterator, ChipTokenizer tokenizer) {
|
||||
textIterator.deleteCharacter(true);
|
||||
tokenizer.terminateAllTokens(textIterator.getText());
|
||||
return textIterator.totalLength();
|
||||
}
|
||||
|
||||
private int handleChipifyCurrentToken(TextIterator textIterator, ChipTokenizer tokenizer) {
|
||||
textIterator.deleteCharacter(true);
|
||||
Editable text = textIterator.getText();
|
||||
int index = textIterator.getIndex();
|
||||
int tokenStart = tokenizer.findTokenStart(text, index);
|
||||
int tokenEnd = tokenizer.findTokenEnd(text, index);
|
||||
if (tokenStart < tokenEnd) {
|
||||
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, tokenEnd), null);
|
||||
textIterator.replace(tokenStart, tokenEnd, chippedText);
|
||||
return tokenStart + chippedText.length();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int handleChipifyToTerminator(TextIterator textIterator, ChipTokenizer tokenizer) {
|
||||
Editable text = textIterator.getText();
|
||||
int index = textIterator.getIndex();
|
||||
if (index > 0) {
|
||||
int tokenStart = tokenizer.findTokenStart(text, index);
|
||||
if (tokenStart < index) {
|
||||
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, index), null);
|
||||
textIterator.replace(tokenStart, index + 1, chippedText);
|
||||
} else {
|
||||
textIterator.deleteCharacter(false);
|
||||
}
|
||||
} else {
|
||||
textIterator.deleteCharacter(false);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private boolean isChipTerminator(char character) {
|
||||
return mChipTerminators != null && mChipTerminators.keySet().contains(character);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
package com.hootsuite.nachos.terminator;
|
||||
|
||||
import android.text.Editable;
|
||||
|
||||
public class TextIterator {
|
||||
|
||||
private Editable mText;
|
||||
private int mStart;
|
||||
private int mEnd;
|
||||
|
||||
private int mIndex;
|
||||
|
||||
public TextIterator(Editable text, int start, int end) {
|
||||
mText = text;
|
||||
mStart = start;
|
||||
mEnd = end;
|
||||
|
||||
mIndex = mStart - 1; // Subtract 1 so that the first call to nextCharacter() will return the first character
|
||||
}
|
||||
|
||||
public int totalLength() {
|
||||
return mText.length();
|
||||
}
|
||||
|
||||
public int windowLength() {
|
||||
return mEnd - mStart;
|
||||
}
|
||||
|
||||
public Editable getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
public boolean hasNextCharacter() {
|
||||
return (mIndex + 1) < mEnd;
|
||||
}
|
||||
|
||||
public char nextCharacter() {
|
||||
mIndex++;
|
||||
return mText.charAt(mIndex);
|
||||
}
|
||||
|
||||
public void deleteCharacter(boolean maintainIndex) {
|
||||
mText.replace(mIndex, mIndex + 1, "");
|
||||
if (!maintainIndex) {
|
||||
mIndex--;
|
||||
}
|
||||
mEnd--;
|
||||
}
|
||||
|
||||
public void replace(int replaceStart, int replaceEnd, CharSequence chippedText) {
|
||||
mText.replace(replaceStart, replaceEnd, chippedText);
|
||||
|
||||
// Update indexes
|
||||
int newLength = chippedText.length();
|
||||
int oldLength = replaceEnd - replaceStart;
|
||||
mIndex = replaceStart + newLength - 1;
|
||||
mEnd += newLength - oldLength;
|
||||
}
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package com.hootsuite.nachos.tokenizer;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.Spanned;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
import com.hootsuite.nachos.chip.Chip;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Base implementation of the {@link ChipTokenizer} interface that performs no actions and returns default values.
|
||||
* This class allows for the easy creation of a ChipTokenizer that only implements some of the methods of the interface.
|
||||
*/
|
||||
public abstract class BaseChipTokenizer implements ChipTokenizer {
|
||||
|
||||
@Override
|
||||
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findTokenStart(CharSequence charSequence, int i) {
|
||||
// Do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findTokenEnd(CharSequence charSequence, int i) {
|
||||
// Do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
|
||||
// Do nothing
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence terminateToken(CharSequence charSequence, @Nullable Object data) {
|
||||
// Do nothing
|
||||
return charSequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateAllTokens(Editable text) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findChipStart(Chip chip, Spanned text) {
|
||||
// Do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findChipEnd(Chip chip, Spanned text) {
|
||||
// Do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Chip[] findAllChips(int start, int end, Spanned text) {
|
||||
return new Chip[]{};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertChipToToken(Chip chip, Editable text) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChip(Chip chip, Editable text) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChipAndPadding(Chip chip, Editable text) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
package com.hootsuite.nachos.tokenizer;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.Spanned;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
import com.hootsuite.nachos.chip.Chip;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An extension of {@link android.widget.MultiAutoCompleteTextView.Tokenizer Tokenizer} that provides extra support
|
||||
* for chipification.
|
||||
* <p>
|
||||
* In the context of this interface, a token is considered to be plain (non-chipped) text. Once a token is terminated it becomes or contains a chip.
|
||||
* </p>
|
||||
* <p>
|
||||
* The CharSequences passed to the ChipTokenizer methods may contain both chipped text
|
||||
* and plain text so the tokenizer must have some method of distinguishing between the two (e.g. using a delimeter character.
|
||||
* The {@link #terminateToken(CharSequence, Object)} method is where a chip can be formed and returned to replace the plain text.
|
||||
* Whatever class the implementation deems to represent a chip, must implement the {@link Chip} interface.
|
||||
* </p>
|
||||
*
|
||||
* @see SpanChipTokenizer
|
||||
*/
|
||||
public interface ChipTokenizer {
|
||||
|
||||
/**
|
||||
* Configures this ChipTokenizer to produce chips with the provided attributes. For each of these attributes, {@code -1} or {@code null} may be
|
||||
* passed to indicate that the attribute may be ignored.
|
||||
* <p>
|
||||
* This will also apply the provided {@link ChipConfiguration} to any existing chips in the provided text.
|
||||
* </p>
|
||||
*
|
||||
* @param text the text in which to search for existing chips to apply the configuration to
|
||||
* @param chipConfiguration a {@link ChipConfiguration} containing customizations for the chips produced by this class
|
||||
*/
|
||||
void applyConfiguration(Editable text, ChipConfiguration chipConfiguration);
|
||||
|
||||
/**
|
||||
* Returns the start of the token that ends at offset
|
||||
* <code>cursor</code> within <code>text</code>.
|
||||
*/
|
||||
int findTokenStart(CharSequence text, int cursor);
|
||||
|
||||
/**
|
||||
* Returns the end of the token (minus trailing punctuation)
|
||||
* that begins at offset <code>cursor</code> within <code>text</code>.
|
||||
*/
|
||||
int findTokenEnd(CharSequence text, int cursor);
|
||||
|
||||
/**
|
||||
* Searches through {@code text} for any tokens.
|
||||
*
|
||||
* @param text the text in which to search for un-terminated tokens
|
||||
* @return a list of {@link Pair}s of the form (startIndex, endIndex) containing the locations of all
|
||||
* unterminated tokens
|
||||
*/
|
||||
@NonNull
|
||||
List<Pair<Integer, Integer>> findAllTokens(CharSequence text);
|
||||
|
||||
/**
|
||||
* Returns <code>text</code>, modified, if necessary, to ensure that
|
||||
* it ends with a token terminator (for example a space or comma).
|
||||
*/
|
||||
CharSequence terminateToken(CharSequence text, @Nullable Object data);
|
||||
|
||||
/**
|
||||
* Terminates (converts from token into chip) all unterminated tokens in the provided text.
|
||||
* This method CAN alter the provided text.
|
||||
*
|
||||
* @param text the text in which to terminate all tokens
|
||||
*/
|
||||
void terminateAllTokens(Editable text);
|
||||
|
||||
/**
|
||||
* Finds the index of the first character in {@code text} that is a part of {@code chip}
|
||||
*
|
||||
* @param chip the chip whose start should be found
|
||||
* @param text the text in which to search for the start of {@code chip}
|
||||
* @return the start index of the chip
|
||||
*/
|
||||
int findChipStart(Chip chip, Spanned text);
|
||||
|
||||
/**
|
||||
* Finds the index of the character after the last character in {@code text} that is a part of {@code chip}
|
||||
*
|
||||
* @param chip the chip whose end should be found
|
||||
* @param text the text in which to search for the end of {@code chip}
|
||||
* @return the end index of the chip
|
||||
*/
|
||||
int findChipEnd(Chip chip, Spanned text);
|
||||
|
||||
/**
|
||||
* Searches through {@code text} for any chips
|
||||
*
|
||||
* @param start index to start looking for terminated tokens (inclusive)
|
||||
* @param end index to end looking for terminated tokens (exclusive)
|
||||
* @param text the text in which to search for terminated tokens
|
||||
* @return a list of objects implementing the {@link Chip} interface to represent the terminated tokens
|
||||
*/
|
||||
@NonNull
|
||||
Chip[] findAllChips(int start, int end, Spanned text);
|
||||
|
||||
/**
|
||||
* Effectively does the opposite of {@link #terminateToken(CharSequence, Object)} by reverting the provided chip back into a token.
|
||||
* This method CAN alter the provided text.
|
||||
*
|
||||
* @param chip the chip to revert into a token
|
||||
* @param text the text in which the chip resides
|
||||
*/
|
||||
void revertChipToToken(Chip chip, Editable text);
|
||||
|
||||
/**
|
||||
* Removes a chip and any text it encompasses from {@code text}. This method CAN alter the provided text.
|
||||
*
|
||||
* @param chip the chip to remove
|
||||
* @param text the text to remove the chip from
|
||||
*/
|
||||
void deleteChip(Chip chip, Editable text);
|
||||
|
||||
/**
|
||||
* Removes a chip, any text it encompasses AND any padding text (such as spaces) that may have been inserted when the chip was created in
|
||||
* {@link #terminateToken(CharSequence, Object)} or after. This method CAN alter the provided text.
|
||||
*
|
||||
* @param chip the chip to remove
|
||||
* @param text the text to remove the chip and padding from
|
||||
*/
|
||||
void deleteChipAndPadding(Chip chip, Editable text);
|
||||
}
|
@ -1,248 +0,0 @@
|
||||
package com.hootsuite.nachos.tokenizer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.hootsuite.nachos.ChipConfiguration;
|
||||
import com.hootsuite.nachos.chip.Chip;
|
||||
import com.hootsuite.nachos.chip.ChipCreator;
|
||||
import com.hootsuite.nachos.chip.ChipSpan;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A default implementation of {@link ChipTokenizer}.
|
||||
* This implementation does the following:
|
||||
* <ul>
|
||||
* <li>Surrounds each token with a space and the Unit Separator ASCII control character (31) - See the diagram below
|
||||
* <ul>
|
||||
* <li>The spaces are included so that android keyboards can distinguish the chips as different words and provide accurate
|
||||
* autocorrect suggestions</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>Replaces each token with a {@link ChipSpan} containing the same text, once the token terminates</li>
|
||||
* <li>Uses the values passed to {@link #applyConfiguration(Editable, ChipConfiguration)} to configure any ChipSpans that get created</li>
|
||||
* </ul>
|
||||
* Each terminated token will therefore look like the following (this is what will be returned from {@link #terminateToken(CharSequence, Object)}):
|
||||
* <pre>
|
||||
* -----------------------------------------------------------
|
||||
* | SpannableString |
|
||||
* | ---------------------------------------------------- |
|
||||
* | | ChipSpan | |
|
||||
* | | | |
|
||||
* | | space separator text separator space | |
|
||||
* | | | |
|
||||
* | ---------------------------------------------------- |
|
||||
* -----------------------------------------------------------
|
||||
* </pre>
|
||||
*
|
||||
* @see ChipSpan
|
||||
*/
|
||||
public class SpanChipTokenizer<C extends Chip> implements ChipTokenizer {
|
||||
|
||||
/**
|
||||
* The character used to separate chips internally is the US (Unit Separator) ASCII control character.
|
||||
* This character is used because it's untypable so we have complete control over when chips are created.
|
||||
*/
|
||||
public static final char CHIP_SPAN_SEPARATOR = 31;
|
||||
public static final char AUTOCORRECT_SEPARATOR = ' ';
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@Nullable
|
||||
private ChipConfiguration mChipConfiguration;
|
||||
@NonNull
|
||||
private ChipCreator<C> mChipCreator;
|
||||
@NonNull
|
||||
private Class<C> mChipClass;
|
||||
|
||||
private Comparator<Pair<Integer, Integer>> mReverseTokenIndexesSorter = new Comparator<Pair<Integer, Integer>>() {
|
||||
@Override
|
||||
public int compare(Pair<Integer, Integer> lhs, Pair<Integer, Integer> rhs) {
|
||||
return rhs.first - lhs.first;
|
||||
}
|
||||
};
|
||||
|
||||
public SpanChipTokenizer(Context context, @NonNull ChipCreator<C> chipCreator, @NonNull Class<C> chipClass) {
|
||||
mContext = context;
|
||||
mChipCreator = chipCreator;
|
||||
mChipClass = chipClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
|
||||
mChipConfiguration = chipConfiguration;
|
||||
|
||||
for (C chip : findAllChips(0, text.length(), text)) {
|
||||
// Recreate the chips with the new configuration
|
||||
int chipStart = findChipStart(chip, text);
|
||||
deleteChip(chip, text);
|
||||
text.insert(chipStart, terminateToken(mChipCreator.createChip(mContext, chip)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findTokenStart(CharSequence text, int cursor) {
|
||||
int i = cursor;
|
||||
|
||||
// Work backwards until we find a CHIP_SPAN_SEPARATOR
|
||||
while (i > 0 && text.charAt(i - 1) != CHIP_SPAN_SEPARATOR) {
|
||||
i--;
|
||||
}
|
||||
// Work forwards to skip over any extra whitespace at the beginning of the token
|
||||
while (i > 0 && i < text.length() && Character.isWhitespace(text.charAt(i))) {
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findTokenEnd(CharSequence text, int cursor) {
|
||||
int i = cursor;
|
||||
int len = text.length();
|
||||
|
||||
// Work forwards till we find a CHIP_SPAN_SEPARATOR
|
||||
while (i < len) {
|
||||
if (text.charAt(i) == CHIP_SPAN_SEPARATOR) {
|
||||
return (i - 1); // subtract one because the CHIP_SPAN_SEPARATOR will be preceded by a space
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
|
||||
List<Pair<Integer, Integer>> unterminatedTokens = new ArrayList<>();
|
||||
|
||||
boolean insideChip = false;
|
||||
// Iterate backwards through the text (to avoid messing up indexes)
|
||||
for (int index = text.length() - 1; index >= 0; index--) {
|
||||
char theCharacter = text.charAt(index);
|
||||
|
||||
// Every time we hit a CHIP_SPAN_SEPARATOR character we switch from being inside to outside
|
||||
// or outside to inside a chip
|
||||
// This check must happen before the whitespace check because CHIP_SPAN_SEPARATOR is considered a whitespace character
|
||||
if (theCharacter == CHIP_SPAN_SEPARATOR) {
|
||||
insideChip = !insideChip;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Completely skip over whitespace
|
||||
if (Character.isWhitespace(theCharacter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we're ever outside a chip, see if the text we're in is a viable token for chipification
|
||||
if (!insideChip) {
|
||||
int tokenStart = findTokenStart(text, index);
|
||||
int tokenEnd = findTokenEnd(text, index);
|
||||
|
||||
// Can only actually be chipified if there's at least one character between them
|
||||
if (tokenEnd - tokenStart >= 1) {
|
||||
unterminatedTokens.add(new Pair<>(tokenStart, tokenEnd));
|
||||
index = tokenStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
return unterminatedTokens;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence terminateToken(CharSequence text, @Nullable Object data) {
|
||||
// Remove leading/trailing whitespace
|
||||
CharSequence trimmedText = text.toString().trim();
|
||||
return terminateToken(mChipCreator.createChip(mContext, trimmedText, data));
|
||||
}
|
||||
|
||||
private CharSequence terminateToken(C chip) {
|
||||
if (chip == null)
|
||||
return new SpannableString("");
|
||||
// Surround the text with CHIP_SPAN_SEPARATOR and spaces
|
||||
// The spaces allow autocorrect to correctly identify words
|
||||
String chipSeparator = Character.toString(CHIP_SPAN_SEPARATOR);
|
||||
String autoCorrectSeparator = Character.toString(AUTOCORRECT_SEPARATOR);
|
||||
CharSequence textWithSeparator = autoCorrectSeparator + chipSeparator + chip.getText() + chipSeparator + autoCorrectSeparator;
|
||||
|
||||
// Build the container object to house the ChipSpan and space
|
||||
SpannableString spannableString = new SpannableString(textWithSeparator);
|
||||
|
||||
// Attach the ChipSpan
|
||||
if (mChipConfiguration != null) {
|
||||
mChipCreator.configureChip(chip, mChipConfiguration);
|
||||
}
|
||||
spannableString.setSpan(chip, 0, textWithSeparator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
return spannableString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateAllTokens(Editable text) {
|
||||
List<Pair<Integer, Integer>> unterminatedTokens = findAllTokens(text);
|
||||
// Sort in reverse order (so index changes don't affect anything)
|
||||
Collections.sort(unterminatedTokens, mReverseTokenIndexesSorter);
|
||||
for (Pair<Integer, Integer> indexes : unterminatedTokens) {
|
||||
int start = indexes.first;
|
||||
int end = indexes.second;
|
||||
CharSequence textToChip = text.subSequence(start, end);
|
||||
CharSequence chippedText = terminateToken(textToChip, null);
|
||||
text.replace(start, end, chippedText);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findChipStart(Chip chip, Spanned text) {
|
||||
return text.getSpanStart(chip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int findChipEnd(Chip chip, Spanned text) {
|
||||
return text.getSpanEnd(chip);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@NonNull
|
||||
@Override
|
||||
public C[] findAllChips(int start, int end, Spanned text) {
|
||||
C[] spansArray = text.getSpans(start, end, mChipClass);
|
||||
return (spansArray != null) ? spansArray : (C[]) Array.newInstance(mChipClass, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertChipToToken(Chip chip, Editable text) {
|
||||
int chipStart = findChipStart(chip, text);
|
||||
int chipEnd = findChipEnd(chip, text);
|
||||
text.removeSpan(chip);
|
||||
text.replace(chipStart, chipEnd, chip.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChip(Chip chip, Editable text) {
|
||||
int chipStart = findChipStart(chip, text);
|
||||
int chipEnd = findChipEnd(chip, text);
|
||||
text.removeSpan(chip);
|
||||
// On the emulator for some reason the text automatically gets deleted and chipStart and chipEnd end up both being -1, so in that case we
|
||||
// don't need to call text.delete(...)
|
||||
if (chipStart != chipEnd) {
|
||||
text.delete(chipStart, chipEnd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteChipAndPadding(Chip chip, Editable text) {
|
||||
// This implementation does not add any extra padding outside of the span so we can just delete the chip normally
|
||||
deleteChip(chip, text);
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package com.hootsuite.nachos.validator;
|
||||
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A {@link NachoValidator} that deems text to be invalid if it contains
|
||||
* unterminated tokens and fixes the text by chipifying all the unterminated tokens.
|
||||
*/
|
||||
public class ChipifyingNachoValidator implements NachoValidator {
|
||||
|
||||
@Override
|
||||
public boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text) {
|
||||
|
||||
// The text is considered valid if there are no unterminated tokens (everything is a chip)
|
||||
List<Pair<Integer, Integer>> unterminatedTokens = chipTokenizer.findAllTokens(text);
|
||||
return unterminatedTokens.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText) {
|
||||
SpannableStringBuilder newText = new SpannableStringBuilder(invalidText);
|
||||
chipTokenizer.terminateAllTokens(newText);
|
||||
return newText;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.hootsuite.nachos.validator;
|
||||
|
||||
public interface IllegalCharacterIdentifier {
|
||||
boolean isCharacterIllegal(Character c);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package com.hootsuite.nachos.validator;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
|
||||
|
||||
/**
|
||||
* Interface used to ensure that a given CharSequence complies to a particular format.
|
||||
*/
|
||||
public interface NachoValidator {
|
||||
|
||||
/**
|
||||
* Validates the specified text.
|
||||
*
|
||||
* @return true If the text currently in the text editor is valid.
|
||||
* @see #fixText(ChipTokenizer, CharSequence)
|
||||
*/
|
||||
boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text);
|
||||
|
||||
/**
|
||||
* Corrects the specified text to make it valid.
|
||||
*
|
||||
* @param invalidText A string that doesn't pass validation: isValid(invalidText)
|
||||
* returns false
|
||||
* @return A string based on invalidText such as invoking isValid() on it returns true.
|
||||
* @see #isValid(ChipTokenizer, CharSequence)
|
||||
*/
|
||||
CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
# See https://github.com/robolectric/robolectric/issues/1334
|
||||
android.library.reference.1=../../build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.2.1'
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#F0F0F0"/>
|
||||
</selector>
|
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="NachoTextView">
|
||||
<attr name="chipHorizontalSpacing" format="reference|dimension" />
|
||||
<attr name="chipBackground" format="reference|color"/>
|
||||
<attr name="chipCornerRadius" format="reference|dimension"/>
|
||||
<attr name="chipTextColor" format="reference|color"/>
|
||||
<attr name="chipTextSize" format="reference|dimension"/>
|
||||
<attr name="chipHeight" format="reference|dimension"/>
|
||||
<attr name="chipVerticalSpacing" format="reference|dimension"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="chip_default_text_color">#DE000000</color>
|
||||
<color name="chip_default_icon_background_color">#517FA4</color>
|
||||
</resources>
|
@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="chip_default_padding_edge">12dp</dimen>
|
||||
<dimen name="chip_default_padding_between_image">8dp</dimen>
|
||||
<dimen name="chip_default_left_margin">0dp</dimen>
|
||||
<dimen name="chip_default_right_margin">0dp</dimen>
|
||||
</resources>
|
@ -1,3 +0,0 @@
|
||||
<resources>
|
||||
<string name="chip_ellipsis">…</string>
|
||||
</resources>
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<style name="DefaultChipSuggestionTextView">
|
||||
<item name="chipHorizontalSpacing">6dp</item>
|
||||
<item name="chipBackground">@color/chip_material_background</item>
|
||||
<item name="chipTextSize">14sp</item>
|
||||
<item name="chipHeight">32dp</item>
|
||||
<item name="chipVerticalSpacing">4dp</item>
|
||||
</style>
|
||||
</resources>
|
@ -3,7 +3,7 @@ include ':wear'
|
||||
include ':codegen'
|
||||
include ':annotation'
|
||||
rootProject.name='Szkolny.eu'
|
||||
include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font', ':nachos'
|
||||
include ':app', ':agendacalendarview', ':mhttp', ':szkolny-font'
|
||||
/*
|
||||
include ':Navigation'
|
||||
project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user