From 40a550fedd29adc8057829d75b48338459a84328 Mon Sep 17 00:00:00 2001 From: Olivier Demolliens Date: Wed, 25 Mar 2015 19:18:15 +0100 Subject: [PATCH] Fix Gradle configuration --- .idea/misc.xml | 101 ++ .idea/workspace.xml | 864 +++++++++++++----- LibraryJar/.classpath | 9 + LibraryJar/.gitignore | 13 + LibraryJar/.idea/.name | 1 + LibraryJar/.idea/compiler.xml | 23 + .../.idea/copyright/profiles_settings.xml | 3 + LibraryJar/.idea/encodings.xml | 5 + LibraryJar/.idea/misc.xml | 5 + LibraryJar/.idea/modules.xml | 9 + LibraryJar/.idea/scopes/scope_settings.xml | 5 + LibraryJar/.idea/vcs.xml | 7 + LibraryJar/.idea/workspace.xml | 248 +++++ LibraryJar/.project | 33 + LibraryJar/AndroidManifest.xml | 5 + LibraryJar/build.gradle | 21 + LibraryJar/build.xml | 92 ++ LibraryJar/ic_launcher-web.png | Bin 0 -> 51614 bytes LibraryJar/lint.xml | 3 + LibraryJar/proguard-project.txt | 20 + LibraryJar/project.properties | 15 + LibraryJar/res/values/attrs.xml | 18 + LibraryJar/settings.gradle | 1 + .../export/AllCapsTransformationMethod.java | 54 ++ .../android/export/TransformationMethod2.java | 35 + .../pixlui/components/button/Button.java | 52 ++ .../pixlui/components/checkbox/CheckBox.java | 171 ++++ .../edittext/AutoCompleteEditText.java | 763 ++++++++++++++++ .../AutoCompleteEditTextBatchListener.java | 29 + .../AutoCompleteEditTextFocusListener.java | 29 + .../pixlui/components/edittext/EditText.java | 50 + .../edittext/EditTextBatchListener.java | 29 + .../edittext/EditTextFocusListener.java | 29 + .../components/imageview/ImageView.java | 160 ++++ .../imageview/ImageViewLayoutAnimator.java | 72 ++ .../linearlayout/LinearLayoutAnimator.java | 73 ++ .../components/radiobutton/RadioButton.java | 168 ++++ .../relativelayout/RelativeLayout.java | 146 +++ .../RelativeLayoutAnimator.java | 72 ++ .../textview/AutoResizeTextView.java | 102 +++ .../textview/EllipsizingTextView.java | 202 ++++ .../components/textview/FontFactory.java | 62 ++ .../pixlui/components/textview/TextView.java | 59 ++ .../CustomPasswordTransformationMethod.java | 250 +++++ .../neopixl/pixlui/intern/FontStyleView.java | 9 + .../neopixl/pixlui/intern/PixlUIContants.java | 28 + .../neopixl/pixlui/intern/PixlUIUtils.java | 31 + Sample/project.properties | 2 +- settings.gradle | 2 +- 49 files changed, 3945 insertions(+), 235 deletions(-) create mode 100644 LibraryJar/.classpath create mode 100644 LibraryJar/.gitignore create mode 100644 LibraryJar/.idea/.name create mode 100644 LibraryJar/.idea/compiler.xml create mode 100644 LibraryJar/.idea/copyright/profiles_settings.xml create mode 100644 LibraryJar/.idea/encodings.xml create mode 100644 LibraryJar/.idea/misc.xml create mode 100644 LibraryJar/.idea/modules.xml create mode 100644 LibraryJar/.idea/scopes/scope_settings.xml create mode 100644 LibraryJar/.idea/vcs.xml create mode 100644 LibraryJar/.idea/workspace.xml create mode 100644 LibraryJar/.project create mode 100644 LibraryJar/AndroidManifest.xml create mode 100644 LibraryJar/build.gradle create mode 100644 LibraryJar/build.xml create mode 100644 LibraryJar/ic_launcher-web.png create mode 100644 LibraryJar/lint.xml create mode 100644 LibraryJar/proguard-project.txt create mode 100644 LibraryJar/project.properties create mode 100644 LibraryJar/res/values/attrs.xml create mode 100644 LibraryJar/settings.gradle create mode 100644 LibraryJar/src/com/android/export/AllCapsTransformationMethod.java create mode 100644 LibraryJar/src/com/android/export/TransformationMethod2.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/button/Button.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/checkbox/CheckBox.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditText.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextBatchListener.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextFocusListener.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/EditText.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextBatchListener.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextFocusListener.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageView.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageViewLayoutAnimator.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/linearlayout/LinearLayoutAnimator.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/radiobutton/RadioButton.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayout.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayoutAnimator.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/textview/AutoResizeTextView.java create mode 100755 LibraryJar/src/com/neopixl/pixlui/components/textview/EllipsizingTextView.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/textview/FontFactory.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/components/textview/TextView.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/intern/CustomPasswordTransformationMethod.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/intern/FontStyleView.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/intern/PixlUIContants.java create mode 100644 LibraryJar/src/com/neopixl/pixlui/intern/PixlUIUtils.java diff --git a/.idea/misc.xml b/.idea/misc.xml index f3b00d6..0a718dc 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,10 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 23c16e5..91966bb 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -18,7 +18,9 @@ - + + + @@ -43,59 +45,67 @@ - + - - - - - + + + - + - - + + + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -104,6 +114,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -120,44 +150,6 @@ - + + + + + + + @@ -1132,6 +1545,7 @@ @@ -1155,7 +1569,7 @@ - + @@ -1167,108 +1581,71 @@ - + - - - - - - - - - - + - - - - - - - - - - - - + + + + - - - - - @@ -1279,17 +1656,6 @@ - - - - - - - - - - - @@ -1511,24 +1877,23 @@ - + - - - - + + + - + @@ -1539,6 +1904,7 @@ + @@ -1564,11 +1930,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -1584,7 +1978,6 @@ - @@ -1592,7 +1985,6 @@ - @@ -1600,7 +1992,6 @@ - @@ -1608,7 +1999,6 @@ - @@ -1661,27 +2051,10 @@ - - - - - - - - - - - - - - - - - @@ -1689,7 +2062,6 @@ - @@ -1697,7 +2069,6 @@ - @@ -1705,7 +2076,6 @@ - @@ -1721,7 +2091,6 @@ - @@ -1729,7 +2098,6 @@ - @@ -1737,7 +2105,6 @@ - @@ -1745,7 +2112,6 @@ - @@ -1753,7 +2119,6 @@ - @@ -1761,7 +2126,6 @@ - @@ -1769,7 +2133,6 @@ - @@ -1777,7 +2140,6 @@ - @@ -1785,26 +2147,23 @@ - - - - - + + + - @@ -1812,23 +2171,6 @@ - - - - - - - - - - - - - - - - - @@ -1836,7 +2178,6 @@ - @@ -1844,7 +2185,6 @@ - @@ -1852,9 +2192,7 @@ - - - + @@ -1862,6 +2200,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1874,34 +2240,66 @@ - + - - + + - + - - + + - + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LibraryJar/.classpath b/LibraryJar/.classpath new file mode 100644 index 0000000..5176974 --- /dev/null +++ b/LibraryJar/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/LibraryJar/.gitignore b/LibraryJar/.gitignore new file mode 100644 index 0000000..d55ceeb --- /dev/null +++ b/LibraryJar/.gitignore @@ -0,0 +1,13 @@ +bin/ +.metadata/ +.settings +gen/ +PushPixl/target/classes/com/neopixl/pushpixl/core/NPNotification.class +PushPixl/target/classes/com/neopixl/pushpixl/core/NPNotificationManager.class +PushPixl/target/classes/com/neopixl/pushpixl/core/NPQuietTime.class +PushPixl/target/classes/com/neopixl/pushpixl/core/NPRestPixlConf.class +PushPixl/target/classes/com/neopixl/pushpixl/core/NPURLBuilder.class +PushPixl/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +RestPixl/target/RestPixl-0.0.1-SNAPSHOT.jar +PixlLogger-1.0.0-SNAPSHOT.jar +target/ \ No newline at end of file diff --git a/LibraryJar/.idea/.name b/LibraryJar/.idea/.name new file mode 100644 index 0000000..729bdde --- /dev/null +++ b/LibraryJar/.idea/.name @@ -0,0 +1 @@ +Library \ No newline at end of file diff --git a/LibraryJar/.idea/compiler.xml b/LibraryJar/.idea/compiler.xml new file mode 100644 index 0000000..217af47 --- /dev/null +++ b/LibraryJar/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/LibraryJar/.idea/copyright/profiles_settings.xml b/LibraryJar/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/LibraryJar/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LibraryJar/.idea/encodings.xml b/LibraryJar/.idea/encodings.xml new file mode 100644 index 0000000..e206d70 --- /dev/null +++ b/LibraryJar/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/LibraryJar/.idea/misc.xml b/LibraryJar/.idea/misc.xml new file mode 100644 index 0000000..28b71f5 --- /dev/null +++ b/LibraryJar/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/LibraryJar/.idea/modules.xml b/LibraryJar/.idea/modules.xml new file mode 100644 index 0000000..c095a7d --- /dev/null +++ b/LibraryJar/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/LibraryJar/.idea/scopes/scope_settings.xml b/LibraryJar/.idea/scopes/scope_settings.xml new file mode 100644 index 0000000..922003b --- /dev/null +++ b/LibraryJar/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/LibraryJar/.idea/vcs.xml b/LibraryJar/.idea/vcs.xml new file mode 100644 index 0000000..def6a6a --- /dev/null +++ b/LibraryJar/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/LibraryJar/.idea/workspace.xml b/LibraryJar/.idea/workspace.xml new file mode 100644 index 0000000..9676a0b --- /dev/null +++ b/LibraryJar/.idea/workspace.xml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + localhost + 5050 + + + + + + + 1426017010241 + 1426017010241 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LibraryJar/.project b/LibraryJar/.project new file mode 100644 index 0000000..05c64e2 --- /dev/null +++ b/LibraryJar/.project @@ -0,0 +1,33 @@ + + + PixlUI + + + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + diff --git a/LibraryJar/AndroidManifest.xml b/LibraryJar/AndroidManifest.xml new file mode 100644 index 0000000..c6f4877 --- /dev/null +++ b/LibraryJar/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + + diff --git a/LibraryJar/build.gradle b/LibraryJar/build.gradle new file mode 100644 index 0000000..e1b23c0 --- /dev/null +++ b/LibraryJar/build.gradle @@ -0,0 +1,21 @@ +apply plugin: 'com.android.library' +android { + compileSdkVersion 19 + buildToolsVersion = rootProject.ext.buildToolsVersion + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + } + } + + +} + +dependencies { +} \ No newline at end of file diff --git a/LibraryJar/build.xml b/LibraryJar/build.xml new file mode 100644 index 0000000..a10a914 --- /dev/null +++ b/LibraryJar/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LibraryJar/ic_launcher-web.png b/LibraryJar/ic_launcher-web.png new file mode 100644 index 0000000000000000000000000000000000000000..4131fb0c65644442ce70071b0cfafb9e631ba228 GIT binary patch literal 51614 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 xu%_)Z + + \ No newline at end of file diff --git a/LibraryJar/proguard-project.txt b/LibraryJar/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/LibraryJar/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/LibraryJar/project.properties b/LibraryJar/project.properties new file mode 100644 index 0000000..93c8c3c --- /dev/null +++ b/LibraryJar/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-21 +android.library=true diff --git a/LibraryJar/res/values/attrs.xml b/LibraryJar/res/values/attrs.xml new file mode 100644 index 0000000..7333dfd --- /dev/null +++ b/LibraryJar/res/values/attrs.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LibraryJar/settings.gradle b/LibraryJar/settings.gradle new file mode 100644 index 0000000..711ec4b --- /dev/null +++ b/LibraryJar/settings.gradle @@ -0,0 +1 @@ +rootProject.name='PixlUI' diff --git a/LibraryJar/src/com/android/export/AllCapsTransformationMethod.java b/LibraryJar/src/com/android/export/AllCapsTransformationMethod.java new file mode 100644 index 0000000..9984ca3 --- /dev/null +++ b/LibraryJar/src/com/android/export/AllCapsTransformationMethod.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +package com.android.export; + +import java.util.Locale; + +import android.content.Context; +import android.graphics.Rect; +import android.view.View; + +/** + * Transforms source text into an ALL CAPS string, locale-aware. + * + * @hide + */ +public class AllCapsTransformationMethod implements TransformationMethod2 { + + @SuppressWarnings("unused") + private boolean mEnabled; + private Locale mLocale; + + public AllCapsTransformationMethod(Context context) { + mLocale = context.getResources().getConfiguration().locale; + } + + @Override + public CharSequence getTransformation(CharSequence source, View view) { + return source != null ? source.toString().toUpperCase(mLocale) : null; + } + + @Override + public void onFocusChanged(View view, CharSequence sourceText, + boolean focused, int direction, Rect previouslyFocusedRect) { + } + + @Override + public void setLengthChangesAllowed(boolean allowLengthChanges) { + mEnabled = allowLengthChanges; + } + +} diff --git a/LibraryJar/src/com/android/export/TransformationMethod2.java b/LibraryJar/src/com/android/export/TransformationMethod2.java new file mode 100644 index 0000000..e90ba5b --- /dev/null +++ b/LibraryJar/src/com/android/export/TransformationMethod2.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * 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. + */ +package com.android.export; + +import android.text.method.TransformationMethod; + +/** + * TransformationMethod2 extends the TransformationMethod interface + * and adds the ability to relax restrictions of TransformationMethod. + * + * @hide + */ +public interface TransformationMethod2 extends TransformationMethod { + /** + * Relax the contract of TransformationMethod to allow length changes, + * or revert to the length-restricted behavior. + * + * @param allowLengthChanges true to allow the transformation to change the length + * of the input string. + */ + public void setLengthChangesAllowed(boolean allowLengthChanges); +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/button/Button.java b/LibraryJar/src/com/neopixl/pixlui/components/button/Button.java new file mode 100644 index 0000000..900c656 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/button/Button.java @@ -0,0 +1,52 @@ +package com.neopixl.pixlui.components.button; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import com.neopixl.pixlui.R; +import com.neopixl.pixlui.components.textview.FontFactory; +import com.neopixl.pixlui.intern.FontStyleView; +import com.neopixl.pixlui.intern.PixlUIUtils; + +public class Button extends android.widget.Button implements FontStyleView { + + public Button(Context context) { + super(context, null); + } + + public Button(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public Button(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setCustomFont(context, attrs, defStyle); + } + + private void setCustomFont(Context ctx, AttributeSet attrs, int defStyle) { + PixlUIUtils.setCustomFont(ctx, this, + R.styleable.com_neopixl_pixlui_components_button_Button, + R.styleable.com_neopixl_pixlui_components_button_Button_typeface, + attrs, defStyle); + + PixlUIUtils.setCustomFont(ctx, this, ""); + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) + * @param ctx + * @param Font Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if(tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/checkbox/CheckBox.java b/LibraryJar/src/com/neopixl/pixlui/components/checkbox/CheckBox.java new file mode 100644 index 0000000..5276ed3 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/checkbox/CheckBox.java @@ -0,0 +1,171 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.checkbox; + +import com.android.export.AllCapsTransformationMethod; +import com.neopixl.pixlui.components.textview.FontFactory; +import com.neopixl.pixlui.intern.PixlUIContants; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.util.AttributeSet; + +/** + * Provide more possibility with CheckBox and enable new methods on old api + * + * @author Olivier Demolliens. @odemolliens Dev with Neopixl + */ +public class CheckBox extends android.widget.CheckBox { + + + private static String BUTTON_ATTRIBUTE_FONT_NAME = "typeface"; + private static final String BUTTON_OS_ATTRIBUTE_TEXT_ALL_CAPS = "textAllCaps"; + + /** + * State + */ + private boolean mOldDeviceTextAllCaps; + + public CheckBox(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + checkBoxVersion(); + setCustomFont(context, attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + public CheckBox(Context context, AttributeSet attrs) { + super(context, attrs); + checkBoxVersion(); + setCustomFont(context, attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + public CheckBox(Context context) { + super(context); + checkBoxVersion(); + } + + /** + * Define what version of code we need to use + */ + private void checkBoxVersion() { + if (android.os.Build.VERSION.SDK_INT < 14) { + setOldDeviceTextAllCaps(true); + } else { + setOldDeviceTextAllCaps(false); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setCustomFont(Context ctx, AttributeSet attrs) { + String typefaceName = attrs.getAttributeValue( + PixlUIContants.SCHEMA_URL, BUTTON_ATTRIBUTE_FONT_NAME); + + if (typefaceName != null) { + setPaintFlags(this.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG + | Paint.LINEAR_TEXT_FLAG); + setCustomFont(ctx, typefaceName); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setAllCaps(Context ctx, AttributeSet attrs) { + + if(!isInEditMode()){ + int indexSize = attrs.getAttributeCount(); + + boolean allCaps = false; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + BUTTON_OS_ATTRIBUTE_TEXT_ALL_CAPS)) { + allCaps = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + if (allCaps) { + setAllCaps(allCaps); + } + } + } + + /** + * Use this method to uppercase all char in text. + * + * @param allCaps + */ + @SuppressLint("NewApi") + @Override + public void setAllCaps(boolean allCaps) { + if (this.isOldDeviceTextAllCaps()) { + if (allCaps) { + setTransformationMethod(new AllCapsTransformationMethod( + getContext())); + } else { + setTransformationMethod(null); + } + } else { + super.setAllCaps(allCaps); + } + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) + * + * @param ctx + * @param Font + * Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if (tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + + public boolean isOldDeviceTextAllCaps() { + return mOldDeviceTextAllCaps; + } + + public void setOldDeviceTextAllCaps(boolean mOldDeviceTextAllCaps) { + this.mOldDeviceTextAllCaps = mOldDeviceTextAllCaps; + } + + +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditText.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditText.java new file mode 100644 index 0000000..270124e --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditText.java @@ -0,0 +1,763 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.edittext; + +import java.util.List; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.os.SystemClock; +import android.provider.Settings; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.AttributeSet; +import android.view.ActionMode; +import android.view.ActionMode.Callback; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputConnectionWrapper; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; + +import com.android.export.AllCapsTransformationMethod; +import com.neopixl.pixlui.components.textview.FontFactory; +import com.neopixl.pixlui.intern.CustomPasswordTransformationMethod; +import com.neopixl.pixlui.intern.PixlUIContants; + +/** + * Provide more possibility with EditText and enable new methods on old api + * + * @author Olivier Demolliens. @odemolliens Dev with Neopixl + */ +public class AutoCompleteEditText extends android.widget.AutoCompleteTextView { + + /** + * XML Attribute + */ + private static final String EDITTEXT_ATTRIBUTE_FONT_NAME = "typeface"; + private static final String EDITTEXT_ATTRIBUTE_COPY_AND_PASTE = "copyandpaste"; + private static final String EDITTEXT_ATTRIBUTE_CANCEL_CLIPBOARD_CONTENT = "clearclipboardcontent"; + private static final String EDITTEXT_ATTRIBUTE_AUTO_FOCUS = "autofocus"; + private static final String EDITTEXT_OS_ATTRIBUTE_TEXT_ALL_CAPS = "textAllCaps"; + + /** + * Provider Keyboard + */ + private static final String EDITTEXT_KEYBOARD_SENSE = "com.htc.android.htcime/.HTCIMEService"; + private static final String EDITTEXT_KEYBOARD_OLD_SAMSUNG = "com.sec.android.inputmethod.axt9/.AxT9IME"; + private static final String EDITTEXT_KEYBOARD_SAMSUNG = "com.sec.android.inputmethod/.SamsungKeypad"; + private static final String EDITTEXT_KEYBOARD_LG = "com.lge.ime/.LgeImeImpl"; + private static final String EDITTEXT_KEYBOARD_SWIFTKEY_TRIAL = "com.touchtype.swiftkey.phone.trial/com.touchtype.KeyboardService"; + private static final String EDITTEXT_KEYBOARD_SWYPE_DRAGON = "com.nuance.swype.trial/com.nuance.swype.input.IME"; + private static final String EDITTEXT_KEYBOARD_SWIFTKEY = "com.touchtype.swiftkey/com.touchtype.KeyboardService"; + + + /** + * Listeners + */ + private AutoCompleteEditTextBatchListener listenerBatch; + private AutoCompleteEditTextFocusListener listenerFocus; + private CustomTextWatcher listenerTextWatcherInternal; + + /** + * State + */ + private boolean mOldDeviceKeyboard; + private boolean mOldDeviceTextAllCaps; + private boolean mAutoFocus; + private boolean mCustomPassWordTransformation; + + private InputMethodManager mImm; + + @Override + public InputConnection onCreateInputConnection(EditorInfo outAttrs) { + return new CustomInputConnection( + super.onCreateInputConnection(outAttrs), true, this); + } + + public AutoCompleteEditText(Context context) { + super(context); + editTextVersion(); + } + + public AutoCompleteEditText(Context context, AttributeSet attrs) { + super(context, attrs); + editTextVersion(); + setCustomFont(context, attrs); + setDisableCopyAndPaste(context, attrs); + setCancelClipboard(context, attrs); + setAutoFocus(context,attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + public AutoCompleteEditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + editTextVersion(); + setCustomFont(context, attrs); + setDisableCopyAndPaste(context, attrs); + setCancelClipboard(context, attrs); + setAutoFocus(context,attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + /** + * Define what version of code we need to use + */ + private void editTextVersion() { + if (android.os.Build.VERSION.SDK_INT < 14) { + setOldDeviceKeyboard(true); + setOldDeviceTextAllCaps(true); + + } else { + setOldDeviceKeyboard(true); + setOldDeviceTextAllCaps(false); + } + + //Custom internal listener + setListenerTextWatcherInternal(new CustomTextWatcher(this)); + addTextChangedListener(getListenerTextWatcherInternal()); + + //System service + mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + + //Autofocus disabled by default + mAutoFocus = false; + mCustomPassWordTransformation = false; + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setCustomFont(Context ctx, AttributeSet attrs) { + String typefaceName = attrs.getAttributeValue( + PixlUIContants.SCHEMA_URL, EDITTEXT_ATTRIBUTE_FONT_NAME); + + if (typefaceName != null) { + setPaintFlags(this.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG + | Paint.LINEAR_TEXT_FLAG); + setCustomFont(ctx, typefaceName); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setDisableCopyAndPaste(Context ctx, AttributeSet attrs) { + boolean disableCopyAndPaste = attrs.getAttributeBooleanValue( + PixlUIContants.SCHEMA_URL, EDITTEXT_ATTRIBUTE_COPY_AND_PASTE, + true); + + if (!disableCopyAndPaste && !isInEditMode()) { + disableCopyAndPaste(); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setCancelClipboard(Context ctx, AttributeSet attrs) { + boolean cancelClipboard = attrs.getAttributeBooleanValue( + PixlUIContants.SCHEMA_URL, + EDITTEXT_ATTRIBUTE_CANCEL_CLIPBOARD_CONTENT, false); + + if (cancelClipboard && !isInEditMode()) { + cancelClipBoardContent(); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setAllCaps(Context ctx, AttributeSet attrs) { + + if(!isInEditMode()){ + int indexSize = attrs.getAttributeCount(); + + boolean allCaps = false; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + EDITTEXT_OS_ATTRIBUTE_TEXT_ALL_CAPS)) { + allCaps = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + if (allCaps && !isInEditMode()) { + setAllCaps(allCaps); + } + } + } + + /** + * Enable autofocus mode (for keyboard). + * + * @param ctx + * @param attrs + */ + private void setAutoFocus(Context ctx, AttributeSet attrs) { + + if(!isInEditMode()){ + int indexSize = attrs.getAttributeCount(); + + boolean autoFocus = false; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + EDITTEXT_ATTRIBUTE_AUTO_FOCUS)) { + autoFocus = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + if (autoFocus && !isInEditMode()) { + setAutoFocus(autoFocus); + } + } + } + + /** + * Use this method to uppercase all char in text. + * + * @param allCaps + */ + @SuppressLint("NewApi") + @Override + public void setAllCaps(boolean allCaps) { + + //FIXME: if user input new char, it's generate a crash on Paint methods + if (this.isOldDeviceTextAllCaps()) { + if (allCaps) { + setTransformationMethod(new AllCapsTransformationMethod( + getContext())); + } else { + setTransformationMethod(null); + } + } else { + super.setAllCaps(allCaps); + } + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) a + * + * @param ctx + * @param Font + * Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if (tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + + /** + * Disable cut/copy/paste + */ + @SuppressLint("NewApi") + public void disableCopyAndPaste() { + if (android.os.Build.VERSION.SDK_INT < 11) { + this.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + menu.clear(); + } + }); + } else { + this.setCustomSelectionActionModeCallback(new Callback() { + + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + public void onDestroyActionMode(ActionMode mode) { + } + + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return false; + } + + public boolean onActionItemClicked(ActionMode mode, + MenuItem item) { + return false; + } + }); + } + } + + @SuppressWarnings("deprecation") + @SuppressLint("NewApi") + /* + * Cancel clipboard content + */ + public void cancelClipBoardContent() { + + if (android.os.Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) getContext() + .getSystemService(Context.CLIPBOARD_SERVICE); + if (clipboard != null) { + clipboard.setText(""); + } + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getContext() + .getSystemService(Context.CLIPBOARD_SERVICE); + if (clipboard != null && clipboard.getPrimaryClip() != null + && clipboard.getPrimaryClip().getItemCount() > 0) { + android.content.ClipData clip = android.content.ClipData + .newPlainText("", ""); + clipboard.setPrimaryClip(clip); + } + } + } + + /** + * Used to intercept the focus + */ + @Override + protected void onFocusChanged(boolean focused, int direction, + Rect previouslyFocusedRect) { + AutoCompleteEditTextFocusListener listener = getFocusListener(); + if (listener != null) { + if (focused) { + listener.requestFocus(this); + } else { + listener.loseFocus(this); + } + } + + super.onFocusChanged(focused, direction, previouslyFocusedRect); + + if(mAutoFocus){ + if(focused){ + mImm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT | InputMethodManager.SHOW_FORCED); + }else{ + mImm.hideSoftInputFromWindow(this.getWindowToken(), 0); + } + mImm.toggleSoftInput(0, 0); + } + } + + /** + * Force show keyboard + */ + public void showKeyboard() { + this.requestFocus(); + + + Context context = getContext(); + if(Activity.class.isInstance(context)) { + ((Activity)context).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); + } + + //mImm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT | InputMethodManager.SHOW_FORCED); + //mImm.toggleSoftInput(0, 0); + + // Trick used to create a fake touch event on the editText + MotionEvent event = MotionEvent.obtain(0, SystemClock.uptimeMillis(), + MotionEvent.ACTION_DOWN | MotionEvent.ACTION_UP, this.getMeasuredWidth(), 0, 0); + this.onTouchEvent(event); + event.recycle(); + } + + /** + * Force hide keyboard + */ + public void hideKeyboard() { + this.clearFocus(); + + Context context = getContext(); + if(Activity.class.isInstance(context)) { + ((Activity)context).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + } + //mImm.hideSoftInputFromWindow(this.getWindowToken(), 0); + //mImm.toggleSoftInput(0, 0); + } + + /** + * Get keyboard name (usefull to know if user used a custom keyboard, like + * HackerKeyboard or SenseKeyboard or...) + * + * @return keyboard name + package + * + */ + private String getKeyboardName() { + return Settings.Secure.getString(getContext().getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD); + } + + /** + * Return if cellphone use a sense keyboard (HTC) + * + * @return + */ + public boolean isASenseKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_SENSE)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a Swype + Dragon + * + * @return + */ + public boolean isASwypeDragonKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_SWYPE_DRAGON)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a SwiftKeyTrial + * + * @return + */ + public boolean isASwiftKeyTrialKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_SWIFTKEY_TRIAL)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a SwiftKey + * + * @return + */ + public boolean isASwiftKeyKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_SWIFTKEY)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a old samsung keyboard + * + * @return + */ + public boolean isAOldSamsungKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_OLD_SAMSUNG)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a samsung keyboard + * + * @return + */ + public boolean isASamsungKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_SAMSUNG)) { + return true; + } else { + return false; + } + } + + /** + * Return if cellphone use a lg keyboard + * + * @return + */ + public boolean isALGKeyboard() { + if (getKeyboardName().equals(EDITTEXT_KEYBOARD_LG)) { + return true; + } else { + return false; + } + } + + /** + * Test if user use a custom keyboard + * + * @return + */ + public boolean isUsingCustomInputMethod() { + InputMethodManager imm = (InputMethodManager) getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + List mInputMethodProperties = imm + .getEnabledInputMethodList(); + final int N = mInputMethodProperties.size(); + for (int i = 0; i < N; i++) { + InputMethodInfo imi = mInputMethodProperties.get(i); + if (imi.getId().equals( + Settings.Secure.getString( + getContext().getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD))) { + if ((imi.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) { + return true; + } + } + } + return false; + } + + private class CustomTextWatcher implements TextWatcher{ + + private AutoCompleteEditText mEdittext; + + public CustomTextWatcher(AutoCompleteEditText editText) { + super(); + setEdittext(editText); + } + + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, + int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, + int count) { + + AutoCompleteEditTextBatchListener listener = getEdittext() + .getBatchListener(); + + if(listener!=null && count == 1){ + listener.addNewChar(getEdittext()); + } + } + + public AutoCompleteEditText getEdittext() { + return mEdittext; + } + + public void setEdittext(AutoCompleteEditText mEdittext) { + this.mEdittext = mEdittext; + } + } + + private class CustomInputConnection extends InputConnectionWrapper { + + private int mLastLength; + private AutoCompleteEditText mEdittext; + private KeyEvent mKeyEvent; + + public CustomInputConnection(InputConnection target, boolean mutable, + AutoCompleteEditText editText) { + super(target, mutable); + setEdittext(editText); + } + + @Override + public boolean beginBatchEdit() { + mLastLength = length(); + mKeyEvent = null; + return super.beginBatchEdit(); + } + + @Override + public boolean commitText(CharSequence text, int newCursorPosition) { + //WorkAround for Samsung/HTC keyboard + try { + return super.commitText(text, newCursorPosition); + } catch (IndexOutOfBoundsException e) { + return true; + } + } + + @Override + public boolean sendKeyEvent(KeyEvent event) { + mKeyEvent = event; + + AutoCompleteEditTextBatchListener listener = getEdittext() + .getBatchListener(); + + if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) { + String text = getEdittext().getText().toString(); + + if (listener != null && event.getAction() == KeyEvent.ACTION_DOWN) { + if (text.length() == 0) { + listener.deleteKeyboardButton(getEdittext(), true); + } else { + listener.deleteKeyboardButton(getEdittext(), false); + } + } + } + return super.sendKeyEvent(event); + } + + @Override + public boolean endBatchEdit() { + + final int newLength = length(); + + AutoCompleteEditTextBatchListener listener = getEdittext().getBatchListener(); + + if (listener != null /*&& !getEdittext().isOldDeviceKeyboard()*/) { + if (newLength <= mLastLength) { + if (mLastLength - newLength == 1) { + + if (mKeyEvent == null) { + listener.deleteKeyboardButton(getEdittext(), false); + }/* else { + char unicodeChar = (char) mKeyEvent + .getUnicodeChar(); + String text = getEdittext().getText().toString(); + text = text + unicodeChar; + getEdittext().setText(text); + listener.addNewChar(getEdittext()); + }*/ + + } else if (mLastLength == 0 && newLength == 0) { + + if (mKeyEvent == null) { + listener.deleteKeyboardButton(getEdittext(), true); + }/* else { + char unicodeChar = (char) mKeyEvent + .getUnicodeChar(); + String text = getEdittext().getText().toString(); + text = text + unicodeChar; + getEdittext().setText(text); + listener.addNewChar(getEdittext()); + }*/ + + } else { + /*if (mKeyEvent != null) { + char unicodeChar = (char) mKeyEvent + .getUnicodeChar(); + String text = getEdittext().getText().toString(); + text = text + unicodeChar; + getEdittext().setText(text); + listener.addNewChar(getEdittext()); + }*/ + } + } /*else { + listener.addNewChar(getEdittext()); + }*/ + } + return super.endBatchEdit(); + } + + public AutoCompleteEditText getEdittext() { + return mEdittext; + } + + public void setEdittext(AutoCompleteEditText mEdittext) { + this.mEdittext = mEdittext; + } + } + + public boolean isOldDeviceTextAllCaps() { + return mOldDeviceTextAllCaps; + } + + public void setOldDeviceTextAllCaps(boolean mOldDeviceTextAllCaps) { + this.mOldDeviceTextAllCaps = mOldDeviceTextAllCaps; + } + + public boolean isOldDeviceKeyboard() { + return mOldDeviceKeyboard; + } + + public void setOldDeviceKeyboard(boolean mOldDevice) { + this.mOldDeviceKeyboard = mOldDevice; + } + + private AutoCompleteEditTextBatchListener getBatchListener() { + return listenerBatch; + } + + public void setBatchListener(AutoCompleteEditTextBatchListener listener) { + this.listenerBatch = listener; + } + + private AutoCompleteEditTextFocusListener getFocusListener() { + return listenerFocus; + } + + public void setFocusListener(AutoCompleteEditTextFocusListener listenerFocus) { + this.listenerFocus = listenerFocus; + } + + public CustomTextWatcher getListenerTextWatcherInternal() { + return listenerTextWatcherInternal; + } + + public void setListenerTextWatcherInternal( + CustomTextWatcher listenerTextWatcherInternal) { + this.listenerTextWatcherInternal = listenerTextWatcherInternal; + } + + public boolean isAutoFocus() { + return mAutoFocus; + } + + public void setAutoFocus(boolean mAutoFocus) { + this.mAutoFocus = mAutoFocus; + } + + public boolean isCustomPassWordTransformation() { + return mCustomPassWordTransformation; + } + + public void setCustomPassWordTransformation( + boolean mCustomPassWordTransformation) { + this.mCustomPassWordTransformation = mCustomPassWordTransformation; + if(this.mCustomPassWordTransformation){ + this.setTransformationMethod(new CustomPasswordTransformationMethod()); + } + } +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextBatchListener.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextBatchListener.java new file mode 100644 index 0000000..798e7f5 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextBatchListener.java @@ -0,0 +1,29 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.edittext; + +/** + * Usefull if you need to track user input (especially delete button) + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public interface AutoCompleteEditTextBatchListener +{ + public void addNewChar(AutoCompleteEditText edittext); + public void deleteKeyboardButton(AutoCompleteEditText edittext, boolean emptyText); +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextFocusListener.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextFocusListener.java new file mode 100644 index 0000000..13023a1 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/AutoCompleteEditTextFocusListener.java @@ -0,0 +1,29 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.edittext; + +/** + * Usefull if you need to track edittext focus + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public interface AutoCompleteEditTextFocusListener +{ + public void requestFocus(AutoCompleteEditText edittext); + public void loseFocus(AutoCompleteEditText edittext); +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditText.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditText.java new file mode 100644 index 0000000..45c0285 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditText.java @@ -0,0 +1,50 @@ +package com.neopixl.pixlui.components.edittext; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import com.neopixl.pixlui.R; +import com.neopixl.pixlui.components.textview.FontFactory; +import com.neopixl.pixlui.intern.FontStyleView; +import com.neopixl.pixlui.intern.PixlUIUtils; + +public class EditText extends android.widget.EditText implements FontStyleView { + + public EditText(Context context) { + super(context, null); + } + + public EditText(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public EditText(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setCustomFont(context, attrs, defStyle); + } + + private void setCustomFont(Context ctx, AttributeSet attrs, int defStyle) { + PixlUIUtils.setCustomFont(ctx, this, + R.styleable.com_neopixl_pixlui_components_edittext_EditText, + R.styleable.com_neopixl_pixlui_components_edittext_EditText_typeface, + attrs, defStyle); + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) + * @param ctx + * @param Font Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if(tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextBatchListener.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextBatchListener.java new file mode 100644 index 0000000..a838cee --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextBatchListener.java @@ -0,0 +1,29 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.edittext; + +/** + * Usefull if you need to track user input (especially delete button) + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public interface EditTextBatchListener +{ + public void addNewChar(EditText edittext); + public void deleteKeyboardButton(EditText edittext, boolean emptyText); +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextFocusListener.java b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextFocusListener.java new file mode 100644 index 0000000..e758904 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/edittext/EditTextFocusListener.java @@ -0,0 +1,29 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.edittext; + +/** + * Usefull if you need to track edittext focus + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public interface EditTextFocusListener +{ + public void requestFocus(EditText edittext); + public void loseFocus(EditText edittext); +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageView.java b/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageView.java new file mode 100644 index 0000000..f42d3e6 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageView.java @@ -0,0 +1,160 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.imageview; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +/** + * Add alpha method for old api + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public class ImageView extends android.widget.ImageView { + + /** + * XML Attribute + */ + private static final String IMAGEVIEW_OS_ATTRIBUTE_TEXT_ALPHA = "alpha"; + + /** + * State + */ + private boolean mOldDeviceTextAlpha; + + /** + * Attribute value + * @param context + */ + private float mAlpha = 1; + + public ImageView(Context context) { + super(context); + editTextVersion(); + } + + public ImageView(Context context, AttributeSet attrs) { + super(context, attrs); + editTextVersion(); + if (isOldDeviceTextAlpha()) { + setAlpha(context, attrs); + } + } + + public ImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + editTextVersion(); + if (isOldDeviceTextAlpha()) { + setAlpha(context, attrs); + } + } + + /** + * Define what version of code we need to use + */ + private void editTextVersion() { + if (android.os.Build.VERSION.SDK_INT < 11) { + setOldDeviceTextAlpha(true); + } else { + setOldDeviceTextAlpha(false); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setAlpha(Context ctx, AttributeSet attrs) { + + if(!isInEditMode()){ + int indexSize = attrs.getAttributeCount(); + + float xmlAlpha = 1; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + IMAGEVIEW_OS_ATTRIBUTE_TEXT_ALPHA)) { + xmlAlpha = attrs.getAttributeFloatValue(i, 1); + break; + } + } + if (xmlAlpha != 1) { + setAlpha(xmlAlpha); + } + } + } + + /** + * Enable apha for old api + * @param alpha + */ + @SuppressLint("NewApi") + @Override + public void setAlpha(float alpha) { + if (this.isOldDeviceTextAlpha()) { + set_Alpha(alpha); + }else{ + super.setAlpha(alpha); + } + } + + /** + * Enable apha for old api + * @param alpha + */ + @Override + @Deprecated + public void setAlpha(int alpha) { + if (this.isOldDeviceTextAlpha()) { + set_Alpha(alpha); + }else{ + super.setAlpha(alpha); + } + } + + @Override + public void onDraw(Canvas canvas){ + if(mAlpha!=1){ + int drawedAlpha = (int) (mAlpha * 100); + canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), drawedAlpha, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); + } + super.onDraw(canvas); + } + + public boolean isOldDeviceTextAlpha() { + return mOldDeviceTextAlpha; + } + + public void setOldDeviceTextAlpha(boolean mOldDeviceTextAlpha) { + this.mOldDeviceTextAlpha = mOldDeviceTextAlpha; + } + + public float get_Alpha() { + return mAlpha; + } + + public void set_Alpha(float mAlpha) { + this.mAlpha = mAlpha; + } + +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageViewLayoutAnimator.java b/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageViewLayoutAnimator.java new file mode 100644 index 0000000..f529dde --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/imageview/ImageViewLayoutAnimator.java @@ -0,0 +1,72 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.imageview; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.Animation; + +public class ImageViewLayoutAnimator extends ImageView +{ + private Animation inAnimation; + private Animation outAnimation; + + + @SuppressLint("NewApi") + public ImageViewLayoutAnimator(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public ImageViewLayoutAnimator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setInAnimation(Animation inAnimation) + { + this.inAnimation = inAnimation; + } + + public void setOutAnimation(Animation outAnimation) + { + this.outAnimation = outAnimation; + } + + @Override + public void setVisibility(int visibility) + { + if (getVisibility() != visibility) + { + if (visibility == VISIBLE) + { + if (inAnimation != null) { + startAnimation(inAnimation); + } + } + else if ((visibility == INVISIBLE) || (visibility == GONE)) + { + if (outAnimation != null){ + startAnimation(outAnimation); + } + } + } + + super.setVisibility(visibility); + } +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/linearlayout/LinearLayoutAnimator.java b/LibraryJar/src/com/neopixl/pixlui/components/linearlayout/LinearLayoutAnimator.java new file mode 100644 index 0000000..aef1e69 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/linearlayout/LinearLayoutAnimator.java @@ -0,0 +1,73 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.linearlayout; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.Animation; +import android.widget.LinearLayout; + +public class LinearLayoutAnimator extends LinearLayout +{ + private Animation inAnimation; + private Animation outAnimation; + + + @SuppressLint("NewApi") + public LinearLayoutAnimator(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public LinearLayoutAnimator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setInAnimation(Animation inAnimation) + { + this.inAnimation = inAnimation; + } + + public void setOutAnimation(Animation outAnimation) + { + this.outAnimation = outAnimation; + } + + @Override + public void setVisibility(int visibility) + { + if (getVisibility() != visibility) + { + if (visibility == VISIBLE) + { + if (inAnimation != null) { + startAnimation(inAnimation); + } + } + else if ((visibility == INVISIBLE) || (visibility == GONE)) + { + if (outAnimation != null){ + startAnimation(outAnimation); + } + } + } + + super.setVisibility(visibility); + } +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/radiobutton/RadioButton.java b/LibraryJar/src/com/neopixl/pixlui/components/radiobutton/RadioButton.java new file mode 100644 index 0000000..d71ac44 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/radiobutton/RadioButton.java @@ -0,0 +1,168 @@ +package com.neopixl.pixlui.components.radiobutton; + +import com.android.export.AllCapsTransformationMethod; +import com.neopixl.pixlui.components.textview.FontFactory; +import com.neopixl.pixlui.intern.PixlUIContants; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.util.AttributeSet; + +/* + Copyright 2014 Olivier Demolliens + + 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. + */ +public class RadioButton extends android.widget.RadioButton { + + /** + * XML attribute + */ + private static String RADIOBUTTON_ATTRIBUTE_FONT_NAME = "typeface"; + private static final String RADIOBUTTON_OS_ATTRIBUTE_TEXT_ALL_CAPS = "textAllCaps"; + + /** + * State + */ + private boolean mOldDeviceTextAllCaps; + + public RadioButton(Context context) { + super(context); + radioButtonVersion(); + } + + public RadioButton(Context context, AttributeSet attrs) { + super(context, attrs); + radioButtonVersion(); + setCustomFont(context, attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + public RadioButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + radioButtonVersion(); + setCustomFont(context, attrs); + if (isOldDeviceTextAllCaps()) { + setAllCaps(context, attrs); + } + } + + /** + * Define what version of code we need to use + */ + private void radioButtonVersion() { + if (android.os.Build.VERSION.SDK_INT < 14) { + setOldDeviceTextAllCaps(true); + } else { + setOldDeviceTextAllCaps(false); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setCustomFont(Context ctx, AttributeSet attrs) { + + String typefaceName = attrs.getAttributeValue( + PixlUIContants.SCHEMA_URL, RADIOBUTTON_ATTRIBUTE_FONT_NAME); + + if (typefaceName != null) { + setPaintFlags(this.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG + | Paint.LINEAR_TEXT_FLAG); + setCustomFont(ctx, typefaceName); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + @SuppressLint("NewApi") + private void setAllCaps(Context ctx, AttributeSet attrs) { + + if (!isInEditMode()) { + int indexSize = attrs.getAttributeCount(); + + boolean allCaps = false; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + RADIOBUTTON_OS_ATTRIBUTE_TEXT_ALL_CAPS)) { + allCaps = attrs.getAttributeBooleanValue(i, false); + break; + } + } + + if (allCaps) { + setAllCaps(allCaps); + } + } + } + + /** + * Use this method to uppercase all char in text. + * + * @param allCaps + */ + @SuppressLint("NewApi") + public void setAllCaps(boolean allCaps) { + if (this.isOldDeviceTextAllCaps()) { + if (allCaps) { + setTransformationMethod(new AllCapsTransformationMethod( + getContext())); + } else { + setTransformationMethod(null); + } + } else { + super.setAllCaps(allCaps); + } + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) + * + * @param ctx + * @param Font + * Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if (tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + + public boolean isOldDeviceTextAllCaps() { + return mOldDeviceTextAllCaps; + } + + public void setOldDeviceTextAllCaps(boolean mOldDeviceTextAllCaps) { + this.mOldDeviceTextAllCaps = mOldDeviceTextAllCaps; + } + +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayout.java b/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayout.java new file mode 100644 index 0000000..00e035d --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayout.java @@ -0,0 +1,146 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.relativelayout; + + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; + +/** + * Add alpha method for old api + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public class RelativeLayout extends android.widget.RelativeLayout { + + /** + * XML Attribute + */ + private static final String RELATIVE_LAYOUT_OS_ATTRIBUTE_TEXT_ALPHA = "alpha"; + + /** + * State + */ + private boolean mOldDeviceTextAlpha; + + /** + * Attribute value + * @param context + */ + private float mAlpha = 1; + + public RelativeLayout(Context context) { + super(context); + editTextVersion(); + } + + public RelativeLayout(Context context, AttributeSet attrs) { + super(context, attrs); + editTextVersion(); + if (isOldDeviceTextAlpha()) { + setAlpha(context, attrs); + } + } + + public RelativeLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + editTextVersion(); + if (isOldDeviceTextAlpha()) { + setAlpha(context, attrs); + } + } + + /** + * Define what version of code we need to use + */ + private void editTextVersion() { + if (android.os.Build.VERSION.SDK_INT < 11) { + setOldDeviceTextAlpha(true); + } else { + setOldDeviceTextAlpha(false); + } + } + + /** + * XML methods + * + * @param ctx + * @param attrs + */ + private void setAlpha(Context ctx, AttributeSet attrs) { + + if(!isInEditMode()){ + int indexSize = attrs.getAttributeCount(); + + float xmlAlpha = 1; + + for (int i = 0; i < indexSize; i++) { + if (attrs.getAttributeName(i).equals( + RELATIVE_LAYOUT_OS_ATTRIBUTE_TEXT_ALPHA)) { + xmlAlpha = attrs.getAttributeFloatValue(i, 1); + break; + } + } + if (xmlAlpha != 1) { + setAlpha(xmlAlpha); + } + } + } + + /** + * Enable apha for old api + * @param alpha + */ + @SuppressLint("NewApi") + @Override + public void setAlpha(float alpha) { + if (this.isOldDeviceTextAlpha()) { + set_Alpha(alpha); + }else{ + super.setAlpha(alpha); + } + } + + @Override + public void onDraw(Canvas canvas){ + if(mAlpha!=1){ + int drawedAlpha = (int) (mAlpha * 255); + canvas.saveLayerAlpha(0, 0, canvas.getWidth(), canvas.getHeight(), drawedAlpha, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); + } + super.onDraw(canvas); + } + + public boolean isOldDeviceTextAlpha() { + return mOldDeviceTextAlpha; + } + + public void setOldDeviceTextAlpha(boolean mOldDeviceTextAlpha) { + this.mOldDeviceTextAlpha = mOldDeviceTextAlpha; + } + + public float get_Alpha() { + return mAlpha; + } + + public void set_Alpha(float mAlpha) { + this.mAlpha = mAlpha; + } + +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayoutAnimator.java b/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayoutAnimator.java new file mode 100644 index 0000000..6c7dc02 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/relativelayout/RelativeLayoutAnimator.java @@ -0,0 +1,72 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.relativelayout; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.Animation; + +public class RelativeLayoutAnimator extends RelativeLayout +{ + private Animation inAnimation; + private Animation outAnimation; + + + @SuppressLint("NewApi") + public RelativeLayoutAnimator(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + } + + public RelativeLayoutAnimator(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setInAnimation(Animation inAnimation) + { + this.inAnimation = inAnimation; + } + + public void setOutAnimation(Animation outAnimation) + { + this.outAnimation = outAnimation; + } + + @Override + public void setVisibility(int visibility) + { + if (getVisibility() != visibility) + { + if (visibility == VISIBLE) + { + if (inAnimation != null) { + startAnimation(inAnimation); + } + } + else if ((visibility == INVISIBLE) || (visibility == GONE)) + { + if (outAnimation != null){ + startAnimation(outAnimation); + } + } + } + + super.setVisibility(visibility); + } +} diff --git a/LibraryJar/src/com/neopixl/pixlui/components/textview/AutoResizeTextView.java b/LibraryJar/src/com/neopixl/pixlui/components/textview/AutoResizeTextView.java new file mode 100644 index 0000000..ce9288a --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/textview/AutoResizeTextView.java @@ -0,0 +1,102 @@ +package com.neopixl.pixlui.components.textview; + +import android.content.Context; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.TypedValue; + +/** + * + * @author odemolliens - jclemot + * + */ +public class AutoResizeTextView extends TextView { + + // Attributes + private Paint mTestPaint; + private float defaultTextSize; + + + public AutoResizeTextView(Context context) { + super(context); + initialize(); + } + + public AutoResizeTextView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(); + } + + public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initialize(); + } + + private void initialize() { + mTestPaint = new Paint(); + mTestPaint.set(this.getPaint()); + defaultTextSize = getTextSize(); + } + + /* + * Re size the font so the specified text fits in the text box assuming the text box is the specified width. + */ + private void refitText(String text, int textWidth) { + + if (textWidth <= 0 || text.length() == 0) + return; + + int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight(); + + // this is most likely a non-relevant call + if (targetWidth <= 2) + return; + + // text already fits with the xml-defined font size? + mTestPaint.set(this.getPaint()); + mTestPaint.setTextSize(defaultTextSize); + if (mTestPaint.measureText(text) <= targetWidth) { + this.setTextSize(TypedValue.COMPLEX_UNIT_PX, defaultTextSize); + return; + } + + // adjust text size using binary search for efficiency + float hi = defaultTextSize; + float lo = 2; + final float threshold = 0.5f; // How close we have to be + while (hi - lo > threshold) { + float size = (hi + lo) / 2; + mTestPaint.setTextSize(size); + if (mTestPaint.measureText(text) >= targetWidth) + hi = size; // too big + else + lo = size; // too small + + } + + // Use lo so that we undershoot rather than overshoot + this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int parentWidth = MeasureSpec.getSize(widthMeasureSpec); + int height = getMeasuredHeight(); + refitText(this.getText().toString(), parentWidth); + this.setMeasuredDimension(parentWidth, height); + } + + @Override + protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) { + refitText(text.toString(), this.getWidth()); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + if (w != oldw || h != oldh) { + refitText(this.getText().toString(), w); + } + } + +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/textview/EllipsizingTextView.java b/LibraryJar/src/com/neopixl/pixlui/components/textview/EllipsizingTextView.java new file mode 100755 index 0000000..45efaf0 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/textview/EllipsizingTextView.java @@ -0,0 +1,202 @@ +package com.neopixl.pixlui.components.textview; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.text.Layout; +import android.text.Layout.Alignment; +import android.text.StaticLayout; +import android.text.TextUtils.TruncateAt; +import android.util.AttributeSet; +import android.widget.TextView; + +public class EllipsizingTextView extends TextView { + private static final String ELLIPSIS = "\u2026"; + private static final Pattern DEFAULT_END_PUNCTUATION = Pattern.compile("[\\.,\u2026;:\\s]*$", Pattern.DOTALL); + + public interface EllipsizeListener { + void ellipsizeStateChanged(boolean ellipsized); + } + + private final List ellipsizeListeners = new ArrayList(); + private boolean isEllipsized; + private boolean isStale; + private boolean programmaticChange; + private String fullText; + private int maxLines; + private float lineSpacingMultiplier = 1.0f; + private float lineAdditionalVerticalPadding = 0.0f; + /** + * The end punctuation which will be removed when appending #ELLIPSIS. + */ + private Pattern endPunctuationPattern; + + public EllipsizingTextView(Context context) { + this(context, null); + } + + public EllipsizingTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public EllipsizingTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + super.setEllipsize(null); + TypedArray a = context.obtainStyledAttributes(attrs, new int[] { android.R.attr.maxLines }); + setMaxLines(a.getInt(0, Integer.MAX_VALUE)); + setEndPunctuationPattern(DEFAULT_END_PUNCTUATION); + } + + public void setEndPunctuationPattern(Pattern pattern) { + this.endPunctuationPattern = pattern; + } + + public void addEllipsizeListener(EllipsizeListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + ellipsizeListeners.add(listener); + } + + public void removeEllipsizeListener(EllipsizeListener listener) { + ellipsizeListeners.remove(listener); + } + + public boolean isEllipsized() { + return isEllipsized; + } + + @Override + public void setMaxLines(int maxLines) { + super.setMaxLines(maxLines); + this.maxLines = maxLines; + isStale = true; + } + + public int getMaxLines() { + return maxLines; + } + + public boolean ellipsizingLastFullyVisibleLine() { + return maxLines == Integer.MAX_VALUE; + } + + @Override + public void setLineSpacing(float add, float mult) { + this.lineAdditionalVerticalPadding = add; + this.lineSpacingMultiplier = mult; + super.setLineSpacing(add, mult); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int before, + int after) { + super.onTextChanged(text, start, before, after); + if (!programmaticChange) { + fullText = text.toString(); + isStale = true; + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (ellipsizingLastFullyVisibleLine()) { + isStale = true; + } + } + + public void setPadding(int left, int top, int right, int bottom) { + super.setPadding(left, top, right, bottom); + if (ellipsizingLastFullyVisibleLine()) { + isStale = true; + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (isStale) { + resetText(); + } + super.onDraw(canvas); + } + + private void resetText() { + String workingText = fullText; + boolean ellipsized = false; + Layout layout = createWorkingLayout(workingText); + int linesCount = getLinesCount(); + if (layout.getLineCount() > linesCount) { + // We have more lines of text than we are allowed to display. + workingText = fullText.substring(0, layout.getLineEnd(linesCount - 1)).trim(); + while (createWorkingLayout(workingText + ELLIPSIS).getLineCount() > linesCount) { + int lastSpace = workingText.lastIndexOf(' '); + if (lastSpace == -1) { + break; + } + workingText = workingText.substring(0, lastSpace); + } + // We should do this in the loop above, but it's cheaper this way. + workingText = endPunctuationPattern.matcher(workingText).replaceFirst(""); + workingText = workingText + ELLIPSIS; + ellipsized = true; + } + if (!workingText.equals(getText())) { + programmaticChange = true; + try { + setText(workingText); + } finally { + programmaticChange = false; + } + } + isStale = false; + if (ellipsized != isEllipsized) { + isEllipsized = ellipsized; + for (EllipsizeListener listener : ellipsizeListeners) { + listener.ellipsizeStateChanged(ellipsized); + } + } + } + + /** + * Get how many lines of text we are allowed to display. + */ + private int getLinesCount() { + if (ellipsizingLastFullyVisibleLine()) { + int fullyVisibleLinesCount = getFullyVisibleLinesCount(); + if (fullyVisibleLinesCount == -1) { + return 1; + } else { + return fullyVisibleLinesCount; + } + } else { + return maxLines; + } + } + + /** + * Get how many lines of text we can display so their full height is visible. + */ + private int getFullyVisibleLinesCount() { + Layout layout = createWorkingLayout(""); + int height = getHeight() - getPaddingTop() - getPaddingBottom(); + int lineHeight = layout.getLineBottom(0); + return height / lineHeight; + } + + private Layout createWorkingLayout(String workingText) { + return new StaticLayout(workingText, getPaint(), + getWidth() - getPaddingLeft() - getPaddingRight(), + Alignment.ALIGN_NORMAL, lineSpacingMultiplier, + lineAdditionalVerticalPadding, false /* includepad */); + } + + @Override + public void setEllipsize(TruncateAt where) { + // Ellipsize settings are not respected + } +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/textview/FontFactory.java b/LibraryJar/src/com/neopixl/pixlui/components/textview/FontFactory.java new file mode 100644 index 0000000..a62b10b --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/textview/FontFactory.java @@ -0,0 +1,62 @@ +/* + Copyright 2013 Neopixl - Olivier Demolliens + +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. + */ +package com.neopixl.pixlui.components.textview; + +import java.util.HashMap; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.Log; + +/** + * Manage font + * @author Olivier Demolliens. @odemolliens + * Dev with Neopixl + */ +public class FontFactory { + private static FontFactory instance; + private HashMap fontMap = new HashMap(); + private Context context; + + private FontFactory(Context context) { + this.context = context.getApplicationContext(); + } + + public static FontFactory getInstance(Context context) { + if(instance == null){ + return instance = new FontFactory(context); + } else { + return instance; + } + } + + public Typeface getFont(String font) { + Typeface typeface = fontMap.get(font); + if (typeface == null) { + try { + typeface = Typeface.createFromAsset(context.getResources().getAssets(), "fonts/" + font); + fontMap.put(font, typeface); + } catch (Exception e) { + Log.e("FontFactory", "Could not get typeface: " + e.getMessage() + " with name: " + font); + return null; + } + + } + return typeface; + } +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/components/textview/TextView.java b/LibraryJar/src/com/neopixl/pixlui/components/textview/TextView.java new file mode 100644 index 0000000..b6a1f19 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/components/textview/TextView.java @@ -0,0 +1,59 @@ +package com.neopixl.pixlui.components.textview; + +import com.neopixl.pixlui.R; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; +import com.neopixl.pixlui.intern.FontStyleView; +import com.neopixl.pixlui.intern.PixlUIUtils; + +/** + * TextView with custom font by XML or Code + * This class provided too a font factory + * @author odemolliens + * + */ +public class TextView extends EllipsizingTextView implements FontStyleView { + + public TextView(Context context) { + this(context, null); + } + + public TextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setCustomFont(context, attrs, defStyle); + } + + private void setCustomFont(Context ctx, AttributeSet attrs, int defStyle) { + PixlUIUtils.setCustomFont(ctx, this, + R.styleable.com_neopixl_pixlui_components_textview_TextView, + R.styleable.com_neopixl_pixlui_components_textview_TextView_typeface, + attrs, defStyle); + } + + /** + * Use this method to set a custom font in your code (/assets/fonts/) + * @param ctx + * @param Font Name, don't forget to add file extension + * @return + */ + public boolean setCustomFont(Context ctx, String font) { + Typeface tf = FontFactory.getInstance(ctx).getFont(font); + if(tf != null) { + setTypeface(tf); + return true; + } else { + return false; + } + } + + @Override + protected void onSizeChanged (int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + } +} \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/intern/CustomPasswordTransformationMethod.java b/LibraryJar/src/com/neopixl/pixlui/intern/CustomPasswordTransformationMethod.java new file mode 100644 index 0000000..57f972a --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/intern/CustomPasswordTransformationMethod.java @@ -0,0 +1,250 @@ +/* + Copyright 2013 Neopixl + +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. + */ +package com.neopixl.pixlui.intern; + +import android.text.method.PasswordTransformationMethod; +import android.view.View; + +public class CustomPasswordTransformationMethod extends +PasswordTransformationMethod { + @Override + public CharSequence getTransformation(CharSequence source, View view) { + return new CustomPasswordCharSequence(source); + } + + private class CustomPasswordCharSequence implements CharSequence { + + private CharSequence mSource; + + public CustomPasswordCharSequence(CharSequence source) { + setSource(source); + } + + public char charAt(int index) { + return (char) 42; + } + + public int length() { + return getSource().length(); + } + + public CharSequence subSequence(int start, int end) { + return getSource().subSequence(start, end); + } + + private CharSequence getSource() { + return mSource; + } + + private void setSource(CharSequence mSource) { + this.mSource = mSource; + } + } +}; +/* +0 value:�� +33 value:! +34 value:" +35 value:# +36 value:$ +37 value:% +38 value:& +39 value:' +40 value:( +41 value:) +42 value:* +43 value:+ +44 value:, +45 value:- +46 value:. +47 value:/ +48 value:0 +49 value:1 +50 value:2 +51 value:3 +52 value:4 +53 value:5 +54 value:6 +55 value:7 +56 value:8 +57 value:9 +58 value:: +59 value:; +60 value:< +61 value:= +62 value:> +63 value:? +64 value:@ +65 value:A +66 value:B +67 value:C +68 value:D +69 value:E +70 value:F +71 value:G +72 value:H +73 value:I +74 value:J +75 value:K +76 value:L +77 value:M +78 value:N +79 value:O +80 value:P +81 value:Q +82 value:R +83 value:S +84 value:T +85 value:U +86 value:V +87 value:W +88 value:X +89 value:Y +90 value:Z +91 value:[ +92 value:\ +93 value:] +94 value:^ +95 value:_ +96 value:` +97 value:a +98 value:b +99 value:c +100 value:d +101 value:e +102 value:f +103 value:g +104 value:h +105 value:i +106 value:j +107 value:k +108 value:l +109 value:m +110 value:n +111 value:o +112 value:p +113 value:q +114 value:r +115 value:s +116 value:t +117 value:u +118 value:v +119 value:w +120 value:x +121 value:y +122 value:z +123 value:{ +124 value:| +125 value:} +126 value:~ +161 value:¡ +162 value:¢ +163 value:£ +164 value:¤ +165 value:¥ +166 value:¦ +167 value:§ +168 value:¨ +169 value:© +170 value:ª +171 value:« +172 value:¬ +173 value:­ +174 value:® +175 value:¯ +176 value:° +177 value:± +178 value:² +179 value:³ +180 value:´ +181 value:µ +182 value:¶ +183 value:· +184 value:¸ +185 value:¹ +186 value:º +187 value:» +188 value:¼ +189 value:½ +190 value:¾ +191 value:¿ +192 value:À +193 value:Á +194 value: +195 value:à +196 value:Ä +197 value:Å +198 value:Æ +199 value:Ç +200 value:È +201 value:É +202 value:Ê +203 value:Ë +204 value:Ì +205 value:Í +206 value:Î +207 value:Ï +208 value:Ð +209 value:Ñ +210 value:Ò +211 value:Ó +212 value:Ô +213 value:Õ +214 value:Ö +215 value:× +216 value:Ø +217 value:Ù +218 value:Ú +219 value:Û +220 value:Ü +221 value:Ý +222 value:Þ +223 value:ß +224 value:à +225 value:á +226 value:â +227 value:ã +228 value:ä +229 value:å +230 value:æ +231 value:ç +232 value:è +233 value:é +234 value:ê +235 value:ë +236 value:ì +237 value:í +238 value:î +239 value:ï +240 value:ð +241 value:ñ +242 value:ò +243 value:ó +244 value:ô +245 value:õ +246 value:ö +247 value:÷ +248 value:ø +249 value:ù +250 value:ú +251 value:û +252 value:ü +253 value:ý +254 value:þ +255 value:ÿ + */ \ No newline at end of file diff --git a/LibraryJar/src/com/neopixl/pixlui/intern/FontStyleView.java b/LibraryJar/src/com/neopixl/pixlui/intern/FontStyleView.java new file mode 100644 index 0000000..757f808 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/intern/FontStyleView.java @@ -0,0 +1,9 @@ +package com.neopixl.pixlui.intern; + +import android.content.Context; + +public interface FontStyleView { + public boolean setCustomFont(Context ctx, String font); + public void setPaintFlags(int flags); + public int getPaintFlags(); +} diff --git a/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIContants.java b/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIContants.java new file mode 100644 index 0000000..46d4418 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIContants.java @@ -0,0 +1,28 @@ +/* + Copyright 2013 Neopixl + +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. + */ +package com.neopixl.pixlui.intern; + +public class PixlUIContants { + + public static String SCHEMA_URL = "http://schemas.android.com/apk/com.neopixl.pixlui"; + public static String SCHEMA_URL_OS ="http://schemas.android.com/apk/res/android"; + + public class LetterSpacing { + public final static float NORMAL = 0; + } +} diff --git a/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIUtils.java b/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIUtils.java new file mode 100644 index 0000000..9c3a8e9 --- /dev/null +++ b/LibraryJar/src/com/neopixl/pixlui/intern/PixlUIUtils.java @@ -0,0 +1,31 @@ +package com.neopixl.pixlui.intern; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Paint; +import android.util.AttributeSet; + +public class PixlUIUtils { + + public static void setCustomFont(Context ctx, FontStyleView view, int[] attrs, int typefaceId, AttributeSet set, int defStyle) { + + // Retrieve style attributes. + TypedArray a = ctx.obtainStyledAttributes(set, attrs, defStyle, 0); + String typefaceName = a.getString(typefaceId); + a.recycle(); + + if(typefaceName != null) { + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG | Paint.LINEAR_TEXT_FLAG); + view.setCustomFont(ctx, typefaceName); + } + } + + public static void setCustomFont(Context ctx, FontStyleView view, String typefaceName) { + + + if(typefaceName != null) { + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG | Paint.LINEAR_TEXT_FLAG); + view.setCustomFont(ctx, typefaceName); + } + } +} diff --git a/Sample/project.properties b/Sample/project.properties index bcff037..7d2df92 100644 --- a/Sample/project.properties +++ b/Sample/project.properties @@ -12,4 +12,4 @@ # Project target. target=android-18 -android.library.reference.1=../Library +android.library.reference.1=../LibraryJar diff --git a/settings.gradle b/settings.gradle index 6b67321..37ba8f5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ rootProject.name = 'PixlUI' -include ':Library', ':Sample' +include ':Library',/*':LibraryJar',*/ ':Sample'