diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..96cc43e
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..97626ba
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..326e24e
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/animated_vector_drawable_24_2_1.xml b/.idea/libraries/animated_vector_drawable_24_2_1.xml
new file mode 100644
index 0000000..e0c746d
--- /dev/null
+++ b/.idea/libraries/animated_vector_drawable_24_2_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/appcompat_v7_24_2_1.xml b/.idea/libraries/appcompat_v7_24_2_1.xml
new file mode 100644
index 0000000..efdb838
--- /dev/null
+++ b/.idea/libraries/appcompat_v7_24_2_1.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/library_2_4_0.xml b/.idea/libraries/library_2_4_0.xml
new file mode 100644
index 0000000..eedfc0d
--- /dev/null
+++ b/.idea/libraries/library_2_4_0.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_annotations_24_2_1.xml b/.idea/libraries/support_annotations_24_2_1.xml
new file mode 100644
index 0000000..8ce9120
--- /dev/null
+++ b/.idea/libraries/support_annotations_24_2_1.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_compat_24_2_1.xml b/.idea/libraries/support_compat_24_2_1.xml
new file mode 100644
index 0000000..644ba85
--- /dev/null
+++ b/.idea/libraries/support_compat_24_2_1.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_core_ui_24_2_1.xml b/.idea/libraries/support_core_ui_24_2_1.xml
new file mode 100644
index 0000000..865c5af
--- /dev/null
+++ b/.idea/libraries/support_core_ui_24_2_1.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_core_utils_24_2_1.xml b/.idea/libraries/support_core_utils_24_2_1.xml
new file mode 100644
index 0000000..98a3039
--- /dev/null
+++ b/.idea/libraries/support_core_utils_24_2_1.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_fragment_24_2_1.xml b/.idea/libraries/support_fragment_24_2_1.xml
new file mode 100644
index 0000000..d697b37
--- /dev/null
+++ b/.idea/libraries/support_fragment_24_2_1.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_media_compat_24_2_1.xml b/.idea/libraries/support_media_compat_24_2_1.xml
new file mode 100644
index 0000000..387aa09
--- /dev/null
+++ b/.idea/libraries/support_media_compat_24_2_1.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_v4_24_2_1.xml b/.idea/libraries/support_v4_24_2_1.xml
new file mode 100644
index 0000000..9afc61a
--- /dev/null
+++ b/.idea/libraries/support_v4_24_2_1.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/support_vector_drawable_24_2_1.xml b/.idea/libraries/support_vector_drawable_24_2_1.xml
new file mode 100644
index 0000000..e7e9164
--- /dev/null
+++ b/.idea/libraries/support_vector_drawable_24_2_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..7158618
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.8
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..25285bf
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..7f68460
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0ed8e92
--- /dev/null
+++ b/README.md
@@ -0,0 +1,123 @@
+TimelyTimeView
+==============
+
+
+## Animated Time View like Timely app
+
+Screenshots:
+--------
+
+![Screenshots/screenshot1](https://github.com/iballan/TimelyTextView/raw/master/Screenshots/TimelyTimeView_screenshot.gif) ![Screenshots/screenshot2](https://github.com/iballan/TimelyTextView/raw/master/Screenshots/TimelyView_Screenshot.gif)
+
+
+
+Usage :
+
+XML Layout:
+``` xml
+
+
+
+
+```
+
+Java:
+``` java
+ public class MainActivity extends Activity {
+ private TimelyTimeView ttv;
+ TimelyShortTimeView tstv_hours;
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ // TimelyTimeView
+ ttv = (TimelyTimeView) findViewById(R.id.ttv);
+ ttv.setTextColor(Color.WHITE);
+ ttv.setSeperatorsTextSize(50);
+
+ // Then whenever you want to set the time and animate to it
+ ttv.setTime("00:00:00"); // As formatted String
+ // OR
+ ttv.setTime(new int[]{12:12:12});
+ // OR
+ ttv.setTime(new Date());
+
+ // ------------------
+ // TimelyShortTimeView for (hour:min)
+ tstv_hours = (TimelyShortTimeView) findViewById(R.id.tstv_hours);
+ tstv_hours.setTextColor(Color.BLACK);
+ tstv_hours.setTimeFormat(TimelyShortTimeView.FORMAT_HOUR_MIN); // can be set as TimelyShortTimeView.FORMAT_MIN_SEC
+ tstv_hours.setSeperatorsTextSize(50);
+
+ // Then whenever you want to set the time and animate to it
+ ttv.setTime("00:00"); // As formatted String
+ // OR
+ ttv.setTime(new int[]{20:20});
+ // OR
+ ttv.setTime(new Date());
+ // OR
+ long timeAsMilliseconds = new Date().getTime();
+ ttv.setTime(timeAsMilliseconds);
+ }
+ }
+```
+
+Install
+--------
+
+You can install using Gradle:
+
+```gradle
+ repositories {
+ maven { url "https://jitpack.io" }
+ }
+ dependencies {
+ compile 'com.github.iballan:TimelyView:1.0.0'
+ }
+```
+
+Contact me:
+--------
+
+Twitter: [@mbh01t](https://twitter.com/mbh01t)
+
+Github: [iballan](https://github.com/iballan)
+
+Website: [www.mbh01.com](http://mbh01.com)
+
+Credits:
+--------
+
+TimelyTextView : https://github.com/adnan-SM/TimelyTextView
+
+Sriram Ramani article : http://sriramramani.wordpress.com/2013/10/14/number-tweening/
+
+License
+--------
+
+ Copyright 2014 Mohamad Ballan.
+
+ 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.
\ No newline at end of file
diff --git a/Screenshots/TimelyTimeView_screenshot.gif b/Screenshots/TimelyTimeView_screenshot.gif
new file mode 100644
index 0000000..eb35d1c
Binary files /dev/null and b/Screenshots/TimelyTimeView_screenshot.gif differ
diff --git a/Screenshots/TimelyView_Screenshot.gif b/Screenshots/TimelyView_Screenshot.gif
new file mode 100644
index 0000000..28fe9d7
Binary files /dev/null and b/Screenshots/TimelyView_Screenshot.gif differ
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..820e90f
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,16 @@
+buildscript {
+ repositories {
+// mavenCentral()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.2.0'
+ }
+}
+
+allprojects {
+ repositories {
+// mavenCentral()
+ jcenter()
+ }
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..372c368
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Sep 20 17:09:14 EEST 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..91a7e26
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..8a0b282
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/proguard-project.txt b/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/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/sample/.gitignore b/sample/.gitignore
new file mode 100644
index 0000000..34e5e5d
--- /dev/null
+++ b/sample/.gitignore
@@ -0,0 +1,34 @@
+# built application files
+*.apk
+*.ap_
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+gen/
+
+# Local configuration file (sdk path, etc)
+local.properties
+gradle.properties
+
+# Eclipse project files
+.classpath
+.project
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Intellij project files
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# OSX files
+.DS_Store
+.gradle
\ No newline at end of file
diff --git a/sample/build.gradle b/sample/build.gradle
new file mode 100644
index 0000000..cf84f2d
--- /dev/null
+++ b/sample/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 24
+ buildToolsVersion "24.0.2"
+
+ defaultConfig {
+ minSdkVersion 9
+ targetSdkVersion 24
+ versionCode 1
+ versionName "1.0.0"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+}
+
+dependencies {
+ compile project(':timelyview')
+ compile 'com.android.support:appcompat-v7:24.2.1'
+}
diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9805ad5
--- /dev/null
+++ b/sample/src/main/AndroidManifest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/src/main/java/com/mbh/timelyview/sample/MainActivity.java b/sample/src/main/java/com/mbh/timelyview/sample/MainActivity.java
new file mode 100644
index 0000000..900b2cb
--- /dev/null
+++ b/sample/src/main/java/com/mbh/timelyview/sample/MainActivity.java
@@ -0,0 +1,29 @@
+package com.mbh.timelyview.sample;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.View;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public void btn_timelyTimeViewClicked(View v){
+ TimelyTimeViewActivity.start(MainActivity.this);
+ }
+ public void btn_timelyViewClicked(View v){
+ TimelyViewActivity.start(MainActivity.this);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+}
diff --git a/sample/src/main/java/com/mbh/timelyview/sample/TimelyTimeViewActivity.java b/sample/src/main/java/com/mbh/timelyview/sample/TimelyTimeViewActivity.java
new file mode 100644
index 0000000..6694dcd
--- /dev/null
+++ b/sample/src/main/java/com/mbh/timelyview/sample/TimelyTimeViewActivity.java
@@ -0,0 +1,89 @@
+package com.mbh.timelyview.sample;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mbh.timelyview.TimelyShortTimeView;
+import com.mbh.timelyview.TimelyTimeView;
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class TimelyTimeViewActivity extends AppCompatActivity {
+
+ TimelyTimeView ttv;
+ TimelyShortTimeView tstv_hours, tstv_mins;
+ Timer timer;
+
+ public static void start(Context context) {
+ Intent starter = new Intent(context, TimelyTimeViewActivity.class);
+ context.startActivity(starter);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_timely_time_view);
+
+ ttv = (TimelyTimeView) findViewById(R.id.ttv);
+ tstv_hours = (TimelyShortTimeView) findViewById(R.id.tstv_hours);
+ tstv_mins = (TimelyShortTimeView) findViewById(R.id.tstv_mins);
+
+ // Full time 00:00:00
+ ttv.setTextColor(Color.WHITE);
+ ttv.setSeperatorsTextSize(50);
+ ttv.setTime(new int[]{99, 99, 99});
+ ttv.setTime(new int[]{0, 0, 0});
+
+ // Short time *HOURS:MINUTES* 00:00
+ tstv_hours.setTextColor(Color.BLACK);
+ tstv_hours.setTimeFormat(TimelyShortTimeView.FORMAT_HOUR_MIN);
+ tstv_hours.setSeperatorsTextSize(50);
+ tstv_hours.setTime("99:99");
+ tstv_hours.setTime("00:00");
+
+ // Short time *MINUTES:SECONDS* 00:00
+ tstv_mins.setTextColor(Color.WHITE);
+ tstv_mins.setTimeFormat(TimelyShortTimeView.FORMAT_MIN_SEC);
+ tstv_mins.setSeperatorsTextSize(50);
+ tstv_mins.setStrokeWidth(20f);
+ tstv_mins.setTime("99:99");
+ tstv_mins.setTime("00:00");
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ timer = new Timer();
+ timer.scheduleAtFixedRate(getTimerTask(), 1500, 1000);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ timer.cancel();
+ timer = null;
+ }
+
+ private TimerTask getTimerTask() {
+ return new TimerTask() {
+ @Override
+ public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Date now = new Date();
+ ttv.setTime(now);
+
+ tstv_mins.setTime(now.getTime()); // You give as milliseconds
+ tstv_hours.setTime(now);
+ }
+ });
+ }
+ };
+ }
+}
diff --git a/sample/src/main/java/com/mbh/timelyview/sample/TimelyViewActivity.java b/sample/src/main/java/com/mbh/timelyview/sample/TimelyViewActivity.java
new file mode 100644
index 0000000..af91e71
--- /dev/null
+++ b/sample/src/main/java/com/mbh/timelyview/sample/TimelyViewActivity.java
@@ -0,0 +1,122 @@
+package com.mbh.timelyview.sample;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+import com.mbh.timelyview.TimelyView;
+import com.nineoldandroids.animation.ObjectAnimator;
+
+import java.util.Random;
+
+public class TimelyViewActivity extends AppCompatActivity {
+ public static final int DURATION = 1000;
+ public static final int NO_VALUE = -1;
+ private TimelyView timelyView = null;
+ private SeekBar seekBar = null;
+ private Spinner fromSpinner = null;
+ private Spinner toSpinner = null;
+ private volatile ObjectAnimator objectAnimator = null;
+
+ private volatile int from = NO_VALUE;
+ private volatile int to = NO_VALUE;
+ Handler handler;
+ public int getRandomColor(){
+ Random rnd = new Random();
+ return Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_timely_view);
+
+ timelyView = (TimelyView) findViewById(R.id.textView1);
+ seekBar = (SeekBar) findViewById(R.id.seekBar);
+ fromSpinner = (Spinner) findViewById(R.id.fromSpinner);
+ toSpinner = (Spinner) findViewById(R.id.toSpinner);
+
+ handler = new Handler();
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i <10; i++) {
+ final int from = i;
+ final int to = i==9?0:i+1;
+ handler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ timelyView.setTextColor(getRandomColor());
+ timelyView.animate(from, to).start();
+ }
+ }, 900);
+ try{Thread.sleep(1000);}catch (Exception e){}
+ }
+ }
+ }).start();
+
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.from_numbers_array, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ fromSpinner.setAdapter(adapter);
+ toSpinner.setAdapter(adapter);
+ fromSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ from = position - 1;
+ if(from != NO_VALUE && to != NO_VALUE) {
+ objectAnimator = timelyView.animate(from, to);
+ objectAnimator.setDuration(DURATION);
+ } else {
+ objectAnimator = null;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ }
+ });
+ toSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ to = position - 1;
+ if(from != NO_VALUE && to != NO_VALUE) {
+ objectAnimator = timelyView.animate(from, to);
+ objectAnimator.setDuration(DURATION);
+ } else {
+ objectAnimator = null;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+
+ }
+ });
+
+ seekBar.setMax(DURATION);
+ seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if(objectAnimator != null) objectAnimator.setCurrentPlayTime(progress);
+ }
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {}
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {}
+ });
+ }
+
+ public static void start(Context context) {
+ Intent starter = new Intent(context, TimelyViewActivity.class);
+ context.startActivity(starter);
+ }
+}
diff --git a/sample/src/main/res/drawable-hdpi/ic_launcher.png b/sample/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
Binary files /dev/null and b/sample/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/drawable-mdpi/ic_launcher.png b/sample/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
Binary files /dev/null and b/sample/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/drawable-xhdpi/ic_launcher.png b/sample/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
Binary files /dev/null and b/sample/src/main/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..595aad9
--- /dev/null
+++ b/sample/src/main/res/layout/activity_main.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/layout/activity_timely_time_view.xml b/sample/src/main/res/layout/activity_timely_time_view.xml
new file mode 100644
index 0000000..f82fff3
--- /dev/null
+++ b/sample/src/main/res/layout/activity_timely_time_view.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/layout/activity_timely_view.xml b/sample/src/main/res/layout/activity_timely_view.xml
new file mode 100644
index 0000000..d93ec2c
--- /dev/null
+++ b/sample/src/main/res/layout/activity_timely_view.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/src/main/res/menu/main.xml b/sample/src/main/res/menu/main.xml
new file mode 100644
index 0000000..c002028
--- /dev/null
+++ b/sample/src/main/res/menu/main.xml
@@ -0,0 +1,9 @@
+
diff --git a/sample/src/main/res/values-sw720dp-land/dimens.xml b/sample/src/main/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..61e3fa8
--- /dev/null
+++ b/sample/src/main/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,9 @@
+
+
+
+ 128dp
+
+
diff --git a/sample/src/main/res/values-v11/styles.xml b/sample/src/main/res/values-v11/styles.xml
new file mode 100644
index 0000000..ceeda01
--- /dev/null
+++ b/sample/src/main/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/sample/src/main/res/values-v14/styles.xml b/sample/src/main/res/values-v14/styles.xml
new file mode 100644
index 0000000..edd95f9
--- /dev/null
+++ b/sample/src/main/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/sample/src/main/res/values-w820dp/dimens.xml b/sample/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/sample/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+
+
+ 64dp
+
diff --git a/sample/src/main/res/values/arrays.xml b/sample/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..1f3943c
--- /dev/null
+++ b/sample/src/main/res/values/arrays.xml
@@ -0,0 +1,16 @@
+
+
+
+ - Pick a number
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+
+
\ No newline at end of file
diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..55c1e59
--- /dev/null
+++ b/sample/src/main/res/values/dimens.xml
@@ -0,0 +1,7 @@
+
+
+
+ 16dp
+ 16dp
+
+
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7292a2f
--- /dev/null
+++ b/sample/src/main/res/values/strings.xml
@@ -0,0 +1,10 @@
+
+
+
+ Timely View
+ Settings
+
+ Timely View
+ Timely Time View
+
+
diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml
new file mode 100644
index 0000000..91a546b
--- /dev/null
+++ b/sample/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..8b4f834
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':timelyview'
+include ':sample'
\ No newline at end of file
diff --git a/timelyview/.gitignore b/timelyview/.gitignore
new file mode 100644
index 0000000..34e5e5d
--- /dev/null
+++ b/timelyview/.gitignore
@@ -0,0 +1,34 @@
+# built application files
+*.apk
+*.ap_
+
+# files for the dex VM
+*.dex
+
+# Java class files
+*.class
+
+# generated files
+bin/
+gen/
+
+# Local configuration file (sdk path, etc)
+local.properties
+gradle.properties
+
+# Eclipse project files
+.classpath
+.project
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Intellij project files
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# OSX files
+.DS_Store
+.gradle
\ No newline at end of file
diff --git a/timelyview/build.gradle b/timelyview/build.gradle
new file mode 100644
index 0000000..772acc0
--- /dev/null
+++ b/timelyview/build.gradle
@@ -0,0 +1,28 @@
+apply plugin: 'com.android.library'
+
+dependencies {
+ compile 'com.nineoldandroids:library:2.4.0'
+}
+
+android {
+ compileSdkVersion 24
+ buildToolsVersion "24.0.2"
+
+ defaultConfig {
+ minSdkVersion 1
+ targetSdkVersion 24
+ versionCode 1
+ versionName "1.0.0"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/AndroidManifest.xml b/timelyview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..00958ae
--- /dev/null
+++ b/timelyview/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/timelyview/src/main/java/com/mbh/timelyview/TimelyShortTimeView.java b/timelyview/src/main/java/com/mbh/timelyview/TimelyShortTimeView.java
new file mode 100644
index 0000000..9a12e7a
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/TimelyShortTimeView.java
@@ -0,0 +1,158 @@
+package com.mbh.timelyview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.TextView;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Created By MBH on 2016-10-05.
+ */
+
+public class TimelyShortTimeView extends TimelyTimeCommon {
+ private int timeFormat = 1; // Default HOUR_MIN;
+ public static final int FORMAT_HOUR_MIN = 1;
+ public static final int FORMAT_MIN_SEC = 2;
+
+ private int[] timeIntArr = {0,0};
+
+ public TimelyShortTimeView(Context context) {
+ super(context);
+ }
+
+ public TimelyShortTimeView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public TimelyShortTimeView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public TimelyShortTimeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void init() {
+ inflate(getContext(), R.layout.timely_shorttimeview_layout, this);
+
+ h_left = (TimelyView) findViewById(R.id.ttv_hours_left);
+ h_right = (TimelyView) findViewById(R.id.ttv_hours_right);
+ min_left = (TimelyView) findViewById(R.id.ttv_minutes_left);
+ min_right = (TimelyView) findViewById(R.id.ttv_minutes_right);
+
+ seperator1 = (TextView) findViewById(R.id.tv_seperator1);
+
+ array_timelyViews = new SparseArray<>();
+ array_seperators = new SparseArray<>();
+
+ array_timelyViews.put(0, h_left);
+ array_timelyViews.put(1, h_right);
+ array_timelyViews.put(2, min_left);
+ array_timelyViews.put(3, min_right);
+
+
+ array_seperators.put(0, seperator1);
+
+
+ for (int i = 0; i < array_timelyViews.size(); i++){
+ array_timelyViews.valueAt(i).setTextColorAndCorner(textColor, isRoundedCorner);
+ }
+
+ for (int i = 0; i < array_seperators.size(); i++){
+ TextView tv = array_seperators.valueAt(i);
+ tv.setTextColor(textColor);
+ tv.setTextSize(seperatorsTextSize);
+ }
+ }
+
+ @Override
+ boolean isShortTime() {
+ return true;
+ }
+
+ @Override
+ protected void setTimeToTimelyViews(int[] timeArray) {
+ animateCarefully(h_left, animationType==ANIMATION_ZOOM?-1:(timeIntArr[0] % 100) / 10,
+ (timeArray[0] % 100) / 10);
+ animateCarefully(h_right, animationType==ANIMATION_ZOOM?-1:timeIntArr[0]% 10,
+ timeArray[0]% 10);
+
+ animateCarefully(min_left, animationType==ANIMATION_ZOOM?-1:(timeIntArr[1] % 100) / 10,
+ (timeArray[1] % 100) / 10);
+ animateCarefully(min_right, animationType==ANIMATION_ZOOM?-1:timeIntArr[1]% 10,
+ timeArray[1]% 10);
+
+ timeIntArr = timeArray;
+ }
+
+ @Override
+ public void setTime(Date date) {
+ TimelyTimeUtils.checkNull(date);
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ int[] tempArray = new int[2];
+ if(timeFormat == FORMAT_HOUR_MIN){
+ tempArray[0] = cal.get(Calendar.HOUR_OF_DAY);
+ tempArray[1] = cal.get(Calendar.MINUTE);
+ }else {
+ tempArray[0] = cal.get(Calendar.MINUTE);
+ tempArray[1] = cal.get(Calendar.SECOND);
+ }
+
+ setTimeIfNotEqual(tempArray, timeIntArr);
+ }
+
+ @Override
+ public void setTime(int[] timeIntArray) {
+ setTimeChecked(timeIntArray, timeIntArr);
+ }
+
+ /**
+ * Set time formatted from string
+ * @param formattedTime: time should be formatted as 00:00
+ */
+ @Override
+ public void setTime(String formattedTime){
+ TimelyTimeUtils.checkNull(formattedTime);
+ if(formattedTime.length() != 5) // 5 = 00:00 as string length
+ throw new IllegalArgumentException("Time format should be 00:00, not "+formattedTime);
+ String[] splitted = formattedTime.split(":");
+ if(splitted.length != 2) // 2 = 00 00 as splitted string
+ throw new IllegalArgumentException("Time format should be 00:00, not "+formattedTime);
+ int field1 = TimelyTimeUtils.tryParseInt(splitted[0], -1);
+ int field2 = TimelyTimeUtils.tryParseInt(splitted[1], -1);
+
+ setTime(new int[]{field1, field2});
+ }
+
+ @Override
+ public void setTime(long milliseconds) {
+ TimelyTimeUtils.checkValidPositiveLong(milliseconds);
+ int field1, field2;
+ if(timeFormat == FORMAT_HOUR_MIN){
+ field1 = (int)((milliseconds / (1000*60*60)) % 24);// Hours
+ field2 = (int) ((milliseconds / (1000*60)) % 60);// minutes
+ }else {
+ field1 = (int) ((milliseconds / (1000*60)) % 60); // minutes
+ field2 = (int) (milliseconds / 1000) % 60 ; // seconds
+ }
+ TimelyTimeUtils.checkValidPositiveInt(field1);
+ TimelyTimeUtils.checkValidPositiveInt(field2);
+ setTime(new int[]{field1, field2});
+ }
+
+ public int getTimeFormat() {
+ return timeFormat;
+ }
+
+ public void setTimeFormat(int timeFormat) {
+ this.timeFormat = timeFormat;
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeCommon.java b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeCommon.java
new file mode 100644
index 0000000..17c0666
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeCommon.java
@@ -0,0 +1,176 @@
+package com.mbh.timelyview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.nineoldandroids.animation.ObjectAnimator;
+
+import java.util.Date;
+
+/**
+ * Created By MBH on 2016-10-05.
+ */
+
+abstract class TimelyTimeCommon extends LinearLayout{
+ public final static int ANIMATION_ZOOM = 1;
+ public final static int ANIMATION_MATERIAL = 2;
+
+ protected SparseArray array_timelyViews;
+ protected SparseArray array_seperators;
+ protected TimelyView h_left, h_right;
+ protected TimelyView min_left, min_right;
+
+ protected TextView seperator1;
+
+ protected int textColor = Color.BLACK;
+ protected boolean isRoundedCorner = true;
+ protected int seperatorsTextSize = 16;
+ protected float strokeWidth = 5.0f;
+ protected int animationType = ANIMATION_MATERIAL;
+
+ public TimelyTimeCommon(Context context) {
+ super(context);
+ init();
+ }
+
+ public TimelyTimeCommon(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public TimelyTimeCommon(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ handleAttributes(context, attrs);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public TimelyTimeCommon(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init();
+ handleAttributes(context, attrs);
+ }
+
+ protected void animateCarefully(TimelyView timelyView, int start, int end){
+ ObjectAnimator oa;
+ if(start == -1) {
+ oa = timelyView.animateCarefully(end);
+ }else {
+ oa = timelyView.animateCarefully(start, end);
+ }
+ if (oa != null) oa.start();
+ }
+
+ abstract void init();
+
+
+ protected void handleAttributes(Context context, AttributeSet attrs) {
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TimelyView);
+ textColor = typedArray.getColor(R.styleable.TimelyTimeView_text_color, Color.BLACK);
+ isRoundedCorner = typedArray.getBoolean(R.styleable.TimelyTimeView_rounded_corner, true);
+ seperatorsTextSize = typedArray.getInt(R.styleable.TimelyTimeView_seperatorsTextSize, 20);
+ animationType = typedArray.getInt(R.styleable.TimelyTimeView_animation_type, ANIMATION_MATERIAL);
+ strokeWidth = typedArray.getFloat(R.styleable.TimelyTimeView_stroke_width, 5.0f);
+ typedArray.recycle();
+ }
+
+ abstract boolean isShortTime();
+
+ abstract void setTimeToTimelyViews(int[] timeArray);
+
+ abstract public void setTime(Date date);
+
+ abstract public void setTime(int[] timeIntArray);
+
+ abstract public void setTime(long milliseconds);
+
+ abstract public void setTime(String formattedTime);
+
+ public void setTextColor(int textColor){
+ this.textColor = textColor;
+ setTextColor(array_timelyViews, array_seperators, textColor);
+ }
+
+ public void setStrokeWidth(float strokeWidth){
+ if(strokeWidth<=0f) throw new IllegalArgumentException("Stroke width must be more than 0");
+ this.strokeWidth = strokeWidth;
+ for (int i = 0; i < array_timelyViews.size(); i++){
+ array_timelyViews.valueAt(i).setStrokeWidth(strokeWidth);
+ }
+ }
+
+ /**
+ * Set text color to all timelyviews and textviews(seperators)
+ * @param _timelyViews: Array of timely views
+ * @param _seperators: array of seperators
+ * @param textColor: new text color to be set
+ */
+ protected void setTextColor(SparseArray _timelyViews , SparseArray _seperators, int textColor){
+
+ for (int i = 0; i < _timelyViews.size(); i++){
+ _timelyViews.valueAt(i).setTextColor(textColor);
+ }
+
+ for (int i = 0; i < _seperators.size(); i++){
+ _seperators.valueAt(i).setTextColor(textColor);
+ }
+ }
+
+ /**
+ * This will check the arrays before applying it to the TimelyViews, cuz the array will be provided by user
+ * @param newArray: New array provided by user
+ * @param olderArray: Array that present the previous time
+ */
+ protected void setTimeChecked(int[] newArray, int[] olderArray){
+ TimelyTimeUtils.checkTimelyTimeArray(newArray, isShortTime());
+ setTimeIfNotEqual(newArray, olderArray);
+ }
+
+ /**
+ * Start animation if new time different from the older one, otherwise do nothing
+ * @param arrayToShow: Array needs to be shown
+ * @param prevArray: Array that present the previous time
+ */
+ protected void setTimeIfNotEqual(int[] arrayToShow, int[] prevArray){
+ if(TimelyTimeUtils.compareArrays(arrayToShow, prevArray)){
+ return;
+ }
+ setTimeToTimelyViews(arrayToShow);
+ }
+
+ /**
+ * Will change the (":") seperators text size which is not included in the timely views
+ * @param _seperators: seperators textviews
+ * @param seperatorsTextSize: text size to be set
+ */
+ private void setSeperatorsTextSize(SparseArray _seperators,int seperatorsTextSize){
+ for (int i = 0; i < _seperators.size(); i++){
+ _seperators.valueAt(i).setTextSize(seperatorsTextSize);
+ }
+ }
+
+ private void setRoundedCorner(SparseArray _timelyViews,boolean isRoundedCorner){
+ for (int i = 0; i < _timelyViews.size(); i++){
+ _timelyViews.valueAt(i).setRoundedCorner(isRoundedCorner);
+ }
+ }
+
+ public void setSeperatorsTextSize(int seperatorsTextSize){
+ if(seperatorsTextSize <= 0) throw new IllegalArgumentException("Textsize cannot be less than or equals to 0");
+ this.seperatorsTextSize = seperatorsTextSize;
+ setSeperatorsTextSize(array_seperators, seperatorsTextSize);
+ }
+
+ private void setRoundedCorner(boolean isRoundedCorner){
+ this.isRoundedCorner = isRoundedCorner;
+ setRoundedCorner(array_timelyViews, isRoundedCorner);
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeUtils.java b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeUtils.java
new file mode 100644
index 0000000..0d0100e
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeUtils.java
@@ -0,0 +1,53 @@
+package com.mbh.timelyview;
+
+/**
+ * Created By MBH on 2016-10-03.
+ */
+
+class TimelyTimeUtils {
+ static boolean compareArrays(int[] array1, int[] array2) {
+ if (array1 != null && array2 != null){
+ if (array1.length != array2.length)
+ return false;
+ else
+ for (int i = 0; i < array2.length; i++) {
+ if (array2[i] != array1[i]) {
+ return false;
+ }
+ }
+ }else{
+ return false;
+ }
+ return true;
+ }
+
+ static void checkNull(Object object){
+ if(object == null) throw new IllegalArgumentException("Argument cannot be null");
+ }
+
+ static void checkValidPositiveInt(int num){
+ if(num < 0) throw new IllegalArgumentException("Number cannot be less than zero 0");
+ }
+
+ static void checkValidPositiveLong(long num){
+ if(num < 0) throw new IllegalArgumentException("Number cannot be less than zero 0");
+ }
+
+ static void checkTimelyTimeArray(int [] timelyArray, boolean isShort){
+ checkNull(timelyArray);
+ int length = isShort?2:3;
+ if(timelyArray.length != length) throw new IllegalArgumentException("Array should have 3 elements for Hour, Min, Sec");
+ for (int timelyInt :
+ timelyArray) {
+ if(timelyInt<0) throw new IllegalArgumentException("Time cannot be less than Zero");
+ }
+ }
+
+ static int tryParseInt (String str, int def){
+ try {
+ return Integer.parseInt(str);
+ } catch (NumberFormatException e) {
+ return def;
+ }
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeView.java b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeView.java
new file mode 100644
index 0000000..f98bc27
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/TimelyTimeView.java
@@ -0,0 +1,161 @@
+package com.mbh.timelyview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.widget.TextView;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import static com.mbh.timelyview.TimelyTimeUtils.checkNull;
+import static com.mbh.timelyview.TimelyTimeUtils.checkValidPositiveInt;
+import static com.mbh.timelyview.TimelyTimeUtils.checkValidPositiveLong;
+import static com.mbh.timelyview.TimelyTimeUtils.tryParseInt;
+
+/**
+ * Created By MBH on 2016-10-03.
+ */
+
+public class TimelyTimeView extends TimelyTimeCommon {
+ protected TimelyView sec_left, sec_right;
+ protected TextView seperator2;
+
+ private int[] timeIntArr = {0,0,0};
+
+ public TimelyTimeView(Context context) {
+ super(context);
+ }
+
+ public TimelyTimeView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public TimelyTimeView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ public TimelyTimeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ boolean isShortTime() {
+ return false;
+ }
+
+ /**
+ * Set time formatted from string
+ * @param formattedTime: time should be formatted as 00:00:00
+ */
+ @Override
+ public void setTime(String formattedTime){
+ checkNull(formattedTime);
+ if(formattedTime.length() != 8) // 8 = 00:00:00 as string length
+ throw new IllegalArgumentException("Time format should be 00:00:00, not "+formattedTime);
+ String[] splitted = formattedTime.split(":");
+ if(splitted.length != 3) // 3 = 00 00 00 as splitted string
+ throw new IllegalArgumentException("Time format should be 00:00:00, not "+formattedTime);
+ int hour = tryParseInt(splitted[0], -1);
+ int min = tryParseInt(splitted[1], -1);
+ int sec = tryParseInt(splitted[2], -1);
+
+ setTime(new int[]{hour, min, sec});
+ }
+
+ @Override
+ public void setTime(int[] timeIntArray){
+ setTimeChecked(timeIntArray, timeIntArr);
+ }
+
+ @Override
+ public void setTime(long milliseconds) {
+ checkValidPositiveLong(milliseconds);
+ final int hour = (int)((milliseconds / (1000*60*60)) % 24);
+ checkValidPositiveInt(hour);
+ final int min = (int) ((milliseconds / (1000*60)) % 60);
+ checkValidPositiveInt(min);
+ final int sec = (int) (milliseconds / 1000) % 60;
+ checkValidPositiveInt(sec);
+ setTime(new int[]{hour, min, sec});
+ }
+
+ @Override
+ public void setTime(Date date){
+ checkNull(date);
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ int[] tempArray = new int[3];
+ tempArray[0] = cal.get(Calendar.HOUR_OF_DAY);
+ tempArray[1] = cal.get(Calendar.MINUTE);
+ tempArray[2] = cal.get(Calendar.SECOND);
+
+ setTimeIfNotEqual(tempArray, timeIntArr);
+ }
+
+ @Override
+ protected void setTimeToTimelyViews(int[] timeArray){
+
+ animateCarefully(h_left, animationType==ANIMATION_ZOOM?-1:(timeIntArr[0] % 100) / 10,
+ (timeArray[0] % 100) / 10);
+ animateCarefully(h_right, animationType==ANIMATION_ZOOM?-1:timeIntArr[0]% 10,
+ timeArray[0]% 10);
+
+ animateCarefully(min_left, animationType==ANIMATION_ZOOM?-1:(timeIntArr[1] % 100) / 10,
+ (timeArray[1] % 100) / 10);
+ animateCarefully(min_right, animationType==ANIMATION_ZOOM?-1:timeIntArr[1]% 10,
+ timeArray[1]% 10);
+
+ animateCarefully(sec_left, animationType==ANIMATION_ZOOM?-1:(timeIntArr[2] % 100) / 10,
+ (timeArray[2] % 100) / 10);
+ animateCarefully(sec_right, animationType==ANIMATION_ZOOM?-1:timeIntArr[2]% 10,
+ timeArray[2]% 10);
+
+ timeIntArr = timeArray;
+ }
+
+ @Override
+ protected void init() {
+ inflate(getContext(), R.layout.timely_timeview_layout, this);
+
+ h_left = (TimelyView) findViewById(R.id.ttv_hours_left);
+ h_right = (TimelyView) findViewById(R.id.ttv_hours_right);
+ min_left = (TimelyView) findViewById(R.id.ttv_minutes_left);
+ min_right = (TimelyView) findViewById(R.id.ttv_minutes_right);
+ sec_left = (TimelyView) findViewById(R.id.ttv_seconds_left);
+ sec_right = (TimelyView) findViewById(R.id.ttv_seconds_right);
+
+ seperator1 = (TextView) findViewById(R.id.tv_seperator1);
+ seperator2 = (TextView) findViewById(R.id.tv_seperator2);
+
+ array_timelyViews = new SparseArray<>();
+ array_seperators = new SparseArray<>();
+
+ array_timelyViews.put(0, h_left);
+ array_timelyViews.put(1, h_right);
+ array_timelyViews.put(2, min_left);
+ array_timelyViews.put(3, min_right);
+ array_timelyViews.put(4, sec_left);
+ array_timelyViews.put(5, sec_right);
+
+
+ array_seperators.put(0, seperator1);
+ array_seperators.put(1, seperator2);
+
+
+ for (int i = 0; i < array_timelyViews.size(); i++){
+ array_timelyViews.valueAt(i).setTextColorAndCorner(textColor, isRoundedCorner);
+ }
+
+ for (int i = 0; i < array_seperators.size(); i++){
+ TextView tv = array_seperators.valueAt(i);
+ tv.setTextColor(textColor);
+ tv.setTextSize(seperatorsTextSize);
+ }
+
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/TimelyView.java b/timelyview/src/main/java/com/mbh/timelyview/TimelyView.java
new file mode 100644
index 0000000..d754b90
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/TimelyView.java
@@ -0,0 +1,184 @@
+package com.mbh.timelyview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.mbh.timelyview.animation.TimelyEvaluator;
+import com.mbh.timelyview.model.NumberUtils;
+import com.nineoldandroids.animation.ObjectAnimator;
+import com.nineoldandroids.util.Property;
+
+public class TimelyView extends View {
+ private static final float RATIO = 1f; // square
+// private static final float RATIO = 4f / 3f; // for any ratio
+ private static final Property CONTROL_POINTS_PROPERTY = new Property(float[][].class, "controlPoints") {
+ @Override
+ public float[][] get(TimelyView object) {
+ return object.getControlPoints();
+ }
+
+ @Override
+ public void set(TimelyView object, float[][] value) {
+ object.setControlPoints(value);
+ }
+ };
+ private Paint mPaint = null;
+ private Path mPath = null;
+ private float[][] controlPoints = null;
+ private int textColor = Color.BLACK;
+ private boolean isRoundedCorner = true;
+ private float strokeWidth = 5.0f;
+ int lastEnd = -1;
+ int lastStart = -1;
+
+ private int width = 1;
+ private int height = 1;
+
+ public TimelyView(Context context) {
+ super(context);
+ init();
+ }
+
+ public TimelyView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TimelyView);
+ textColor = typedArray.getColor(R.styleable.TimelyView_text_color, Color.BLACK);
+ isRoundedCorner = typedArray.getBoolean(R.styleable.TimelyView_rounded_corner, true);
+ typedArray.recycle();
+ init();
+ }
+
+ public TimelyView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public void setTextColor(int color) {
+ this.textColor = color;
+ init();
+ }
+
+ public void setRoundedCorner(boolean isRoundedCorner){
+ this.isRoundedCorner = isRoundedCorner;
+ init();
+ }
+
+ protected void setTextColorAndCorner(int textColor, boolean isRoundedCorner){
+ this.textColor = textColor;
+ this.isRoundedCorner = isRoundedCorner;
+ init();
+ }
+
+ public float[][] getControlPoints() {
+ return controlPoints;
+ }
+
+ public void setControlPoints(float[][] controlPoints) {
+ this.controlPoints = controlPoints;
+ invalidate();
+ }
+
+ public ObjectAnimator animate(int start, int end) {
+ lastEnd = end; lastStart = start;
+ float[][] startPoints = NumberUtils.getControlPointsFor(start);
+ float[][] endPoints = NumberUtils.getControlPointsFor(end);
+
+ return ObjectAnimator.ofObject(this, CONTROL_POINTS_PROPERTY, new TimelyEvaluator(), startPoints, endPoints);
+ }
+
+ public ObjectAnimator animate(int end) {
+ lastEnd = end;
+ float[][] startPoints = NumberUtils.getControlPointsFor(-1);
+ float[][] endPoints = NumberUtils.getControlPointsFor(end);
+
+ return ObjectAnimator.ofObject(this, CONTROL_POINTS_PROPERTY, new TimelyEvaluator(), startPoints, endPoints);
+ }
+
+ protected ObjectAnimator animateCarefully(int end){
+ if(lastEnd == end) return null;
+
+ return animate(end);
+ }
+
+ protected ObjectAnimator animateCarefully(int start, int end){
+ if(lastEnd ==-1|| lastStart==-1){
+ lastEnd = end; lastStart = start;
+ }else if(lastEnd == end && lastStart == start){
+ return null;
+ }
+
+ return animate(start,end);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (controlPoints == null) return;
+
+ int length = controlPoints.length;
+
+// height = getMeasuredHeight();
+// width = getMeasuredWidth();
+
+ float minDimen = height > width ? width : height;
+
+ mPath.reset();
+ mPath.moveTo(minDimen * controlPoints[0][0], minDimen * controlPoints[0][1]);
+ for (int i = 1; i < length; i += 3) {
+ mPath.cubicTo(minDimen * controlPoints[i][0], minDimen * controlPoints[i][1],
+ minDimen * controlPoints[i + 1][0], minDimen * controlPoints[i + 1][1],
+ minDimen * controlPoints[i + 2][0], minDimen * controlPoints[i + 2][1]);
+ }
+ canvas.drawPath(mPath, mPaint);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ width = getMeasuredWidth();
+ height = getMeasuredHeight();
+ int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
+ int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();
+
+ int maxWidth = (int) (heigthWithoutPadding * RATIO);
+ int maxHeight = (int) (widthWithoutPadding / RATIO);
+
+ if (widthWithoutPadding > maxWidth) {
+ width = maxWidth + getPaddingLeft() + getPaddingRight()+(int)strokeWidth;
+ } else {
+ height = maxHeight + getPaddingTop() + getPaddingBottom()+(int)strokeWidth;
+ }
+
+ setMeasuredDimension(width, height);
+ }
+
+ public float getStrokeWidth() {
+ return strokeWidth;
+ }
+
+ public void setStrokeWidth(float strokeWidth) {
+ this.strokeWidth = strokeWidth;
+ init();
+ }
+
+ private void init() {
+ // A new paint with the style as stroke.
+ mPaint = new Paint();
+ mPaint.setAntiAlias(true);
+ mPaint.setColor(textColor);
+ mPaint.setStrokeWidth(strokeWidth);
+ mPaint.setStyle(Paint.Style.STROKE);
+ if (isRoundedCorner) {
+ mPaint.setStrokeJoin(Paint.Join.ROUND);
+ mPaint.setStrokeCap(Paint.Cap.ROUND);
+ }
+ mPath = new Path();
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/animation/TimelyEvaluator.java b/timelyview/src/main/java/com/mbh/timelyview/animation/TimelyEvaluator.java
new file mode 100644
index 0000000..f773eff
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/animation/TimelyEvaluator.java
@@ -0,0 +1,27 @@
+package com.mbh.timelyview.animation;
+
+import com.nineoldandroids.animation.TypeEvaluator;
+
+public class TimelyEvaluator implements TypeEvaluator {
+ private float[][] _cachedPoints = null;
+
+ @Override
+ public float[][] evaluate(float fraction, float[][] startValue, float[][] endValue) {
+ int pointsCount = startValue.length;
+ initCache(pointsCount);
+
+ for(int i = 0; i < pointsCount; i++) {
+ _cachedPoints[i][0] = startValue[i][0] + fraction * (endValue[i][0] - startValue[i][0]);
+ _cachedPoints[i][1] = startValue[i][1] + fraction * (endValue[i][1] - startValue[i][1]);
+ }
+
+ return _cachedPoints;
+ }
+
+ private void initCache(int pointsCount) {
+ if(_cachedPoints == null || _cachedPoints.length != pointsCount) {
+ _cachedPoints = new float[pointsCount][2];
+ }
+ }
+
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/NumberUtils.java b/timelyview/src/main/java/com/mbh/timelyview/model/NumberUtils.java
new file mode 100644
index 0000000..acc6a8a
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/NumberUtils.java
@@ -0,0 +1,48 @@
+package com.mbh.timelyview.model;
+
+
+import com.mbh.timelyview.model.number.Eight;
+import com.mbh.timelyview.model.number.Five;
+import com.mbh.timelyview.model.number.Four;
+import com.mbh.timelyview.model.number.Nine;
+import com.mbh.timelyview.model.number.Null;
+import com.mbh.timelyview.model.number.One;
+import com.mbh.timelyview.model.number.Seven;
+import com.mbh.timelyview.model.number.Six;
+import com.mbh.timelyview.model.number.Three;
+import com.mbh.timelyview.model.number.Two;
+import com.mbh.timelyview.model.number.Zero;
+
+import java.security.InvalidParameterException;
+
+public class NumberUtils {
+
+ public static float[][] getControlPointsFor(int start) {
+ switch (start) {
+ case (-1):
+ return Null.getInstance().getControlPoints();
+ case 0:
+ return Zero.getInstance().getControlPoints();
+ case 1:
+ return One.getInstance().getControlPoints();
+ case 2:
+ return Two.getInstance().getControlPoints();
+ case 3:
+ return Three.getInstance().getControlPoints();
+ case 4:
+ return Four.getInstance().getControlPoints();
+ case 5:
+ return Five.getInstance().getControlPoints();
+ case 6:
+ return Six.getInstance().getControlPoints();
+ case 7:
+ return Seven.getInstance().getControlPoints();
+ case 8:
+ return Eight.getInstance().getControlPoints();
+ case 9:
+ return Nine.getInstance().getControlPoints();
+ default:
+ throw new InvalidParameterException("Unsupported number requested. Must be between -1,9");
+ }
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/core/Figure.java b/timelyview/src/main/java/com/mbh/timelyview/model/core/Figure.java
new file mode 100644
index 0000000..f85d084
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/core/Figure.java
@@ -0,0 +1,26 @@
+package com.mbh.timelyview.model.core;
+
+/**
+ * Model class for cubic bezier figure
+ */
+public abstract class Figure {
+ private static final int NO_VALUE = -1;
+
+ private int pointsCount = NO_VALUE;
+
+ //A chained sequence of points P0,P1,P2,P3/0,P1,P2,P3/0,...
+ private float[][] controlPoints = null;
+
+ protected Figure(float[][] controlPoints) {
+ this.controlPoints = controlPoints;
+ this.pointsCount = (controlPoints.length + 2) / 3;
+ }
+
+ public int getPointsCount() {
+ return pointsCount;
+ }
+
+ public float[][] getControlPoints() {
+ return controlPoints;
+ }
+}
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Eight.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Eight.java
new file mode 100644
index 0000000..e8063ca
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Eight.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Eight extends Figure {
+ private static final float[][] POINTS = {
+ {0.558011049723757f, 0.530386740331492f}, {0.243093922651934f, 0.524861878453039f}, {0.243093922651934f, 0.104972375690608f},
+ {0.558011049723757f, 0.104972375690608f}, {0.850828729281768f, 0.104972375690608f}, {0.850828729281768f, 0.530386740331492f},
+ {0.558011049723757f, 0.530386740331492f}, {0.243093922651934f, 0.530386740331492f}, {0.198895027624309f, 0.988950276243094f},
+ {0.558011049723757f, 0.988950276243094f}, {0.850828729281768f, 0.988950276243094f}, {0.850828729281768f, 0.530386740331492f},
+ {0.558011049723757f, 0.530386740331492f}
+ };
+
+ private static Eight INSTANCE = new Eight();
+
+ protected Eight() {
+ super(POINTS);
+ }
+
+ public static Eight getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Five.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Five.java
new file mode 100644
index 0000000..d35c32e
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Five.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Five extends Figure {
+ private static final float[][] POINTS = {
+ {0.806629834254144f, 0.110497237569061f}, {0.502762430939227f, 0.110497237569061f}, {0.502762430939227f, 0.110497237569061f},
+ {0.502762430939227f, 0.110497237569061f}, {0.397790055248619f, 0.430939226519337f}, {0.397790055248619f, 0.430939226519337f},
+ {0.397790055248619f, 0.430939226519337f}, {0.535911602209945f, 0.364640883977901f}, {0.801104972375691f, 0.469613259668508f},
+ {0.801104972375691f, 0.712707182320442f}, {0.773480662983425f, 1.01104972375691f}, {0.375690607734807f, 1.0939226519337f},
+ {0.248618784530387f, 0.850828729281768f}
+ };
+
+ private static Five INSTANCE = new Five();
+
+ protected Five() {
+ super(POINTS);
+ }
+
+ public static Five getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Four.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Four.java
new file mode 100644
index 0000000..0dc86e6
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Four.java
@@ -0,0 +1,24 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Four extends Figure {
+ private static final float[][] POINTS = {
+ {0.856353591160221f, 0.806629834254144f}, {0.856353591160221f, 0.806629834254144f}, {0.237569060773481f, 0.806629834254144f},
+ {0.237569060773481f, 0.806629834254144f}, {0.237569060773481f, 0.806629834254144f}, {0.712707182320442f, 0.138121546961326f},
+ {0.712707182320442f, 0.138121546961326f}, {0.712707182320442f, 0.138121546961326f}, {0.712707182320442f, 0.806629834254144f},
+ {0.712707182320442f, 0.806629834254144f}, {0.712707182320442f, 0.806629834254144f}, {0.712707182320442f, 0.988950276243094f},
+ {0.712707182320442f, 0.988950276243094f}
+
+ };
+
+ private static Four INSTANCE = new Four();
+
+ protected Four() {
+ super(POINTS);
+ }
+
+ public static Four getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Nine.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Nine.java
new file mode 100644
index 0000000..424f0df
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Nine.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Nine extends Figure {
+ private static final float[][] POINTS = {
+ {0.80939226519337f, 0.552486187845304f}, {0.685082872928177f, 0.751381215469613f}, {0.298342541436464f, 0.740331491712707f},
+ {0.259668508287293f, 0.408839779005525f}, {0.232044198895028f, 0.0441988950276243f}, {0.81767955801105f, -0.0441988950276243f},
+ {0.850828729281768f, 0.408839779005525f}, {0.839779005524862f, 0.596685082872928f}, {0.712707182320442f, 0.668508287292818f},
+ {0.497237569060773f, 0.994475138121547f}, {0.497237569060773f, 0.994475138121547f}, {0.497237569060773f, 0.994475138121547f},
+ {0.497237569060773f, 0.994475138121547f}
+ };
+
+ private static Nine INSTANCE = new Nine();
+
+ protected Nine() {
+ super(POINTS);
+ }
+
+ public static Nine getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Null.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Null.java
new file mode 100644
index 0000000..df9bc21
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Null.java
@@ -0,0 +1,24 @@
+package com.mbh.timelyview.model.number;
+
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Null extends Figure {
+ private static final float[][] POINTS = {
+ {0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, 0.5f},
+ {0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, 0.5f},
+ {0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, 0.5f},
+ {0.5f, 0.5f}, {0.5f, 0.5f}, {0.5f, 0.5f},
+ {0.5f, 0.5f}
+ };
+
+ private static final Null INSTANCE = new Null();
+
+ private Null() {
+ super(POINTS);
+ }
+
+ public static Null getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/One.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/One.java
new file mode 100644
index 0000000..cb62736
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/One.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class One extends Figure {
+ private static final float[][] POINTS = {
+ {0.425414364640884f, 0.113259668508287f}, {0.425414364640884f, 0.113259668508287f}, {0.577348066298343f, 0.113259668508287f},
+ {0.577348066298343f, 0.113259668508287f}, {0.577348066298343f, 0.113259668508287f}, {0.577348066298343f, 1f},
+ {0.577348066298343f, 1f}, {0.577348066298343f, 1f}, {0.577348066298343f, 1f},
+ {0.577348066298343f, 1f}, {0.577348066298343f, 1f}, {0.577348066298343f, 1f},
+ {0.577348066298343f, 1f}
+ };
+
+ private static One INSTANCE = new One();
+
+ protected One() {
+ super(POINTS);
+ }
+
+ public static One getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Seven.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Seven.java
new file mode 100644
index 0000000..cac06dc
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Seven.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Seven extends Figure {
+ private static final float[][] POINTS = {
+ {0.259668508287293f, 0.116022099447514f}, {0.259668508287293f, 0.116022099447514f}, {0.87292817679558f, 0.116022099447514f},
+ {0.87292817679558f, 0.116022099447514f}, {0.87292817679558f, 0.116022099447514f}, {0.7f, 0.422099447513812f},
+ {0.7f, 0.422099447513812f}, {0.7f, 0.422099447513812f}, {0.477348066298343f, 0.733149171270718f},
+ {0.477348066298343f, 0.733149171270718f}, {0.477348066298343f, 0.733149171270718f}, {0.25414364640884f, 1f},
+ {0.25414364640884f, 1f}
+ };
+
+ private static Seven INSTANCE = new Seven();
+
+ protected Seven() {
+ super(POINTS);
+ }
+
+ public static Seven getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Six.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Six.java
new file mode 100644
index 0000000..61c7129
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Six.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Six extends Figure {
+ private static final float[][] POINTS = {
+ {0.607734806629834f, 0.110497237569061f}, {0.607734806629834f, 0.110497237569061f}, {0.607734806629834f, 0.110497237569061f},
+ {0.607734806629834f, 0.110497237569061f}, {0.392265193370166f, 0.43646408839779f}, {0.265193370165746f, 0.50828729281768f},
+ {0.25414364640884f, 0.696132596685083f}, {0.287292817679558f, 1.13017127071823f}, {0.87292817679558f, 1.06077348066298f},
+ {0.845303867403315f, 0.696132596685083f}, {0.806629834254144f, 0.364640883977901f}, {0.419889502762431f, 0.353591160220994f},
+ {0.295580110497238f, 0.552486187845304f}
+ };
+
+ private static Six INSTANCE = new Six();
+
+ protected Six() {
+ super(POINTS);
+ }
+
+ public static Six getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Three.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Three.java
new file mode 100644
index 0000000..016b7d5
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Three.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Three extends Figure {
+ private static final float[][] POINTS = {
+ {0.361878453038674f, 0.298342541436464f}, {0.348066298342541f, 0.149171270718232f}, {0.475138121546961f, 0.0994475138121547f},
+ {0.549723756906077f, 0.0994475138121547f}, {0.861878453038674f, 0.0994475138121547f}, {0.806629834254144f, 0.530386740331492f},
+ {0.549723756906077f, 0.530386740331492f}, {0.87292817679558f, 0.530386740331492f}, {0.828729281767956f, 0.994475138121547f},
+ {0.552486187845304f, 0.994475138121547f}, {0.298342541436464f, 0.994475138121547f}, {0.30939226519337f, 0.828729281767956f},
+ {0.312154696132597f, 0.790055248618785f}
+ };
+
+ private static Three INSTANCE = new Three();
+
+ protected Three() {
+ super(POINTS);
+ }
+
+ public static Three getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Two.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Two.java
new file mode 100644
index 0000000..84d9442
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Two.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Two extends Figure {
+ private static final float[][] POINTS = {
+ {0.30939226519337f, 0.331491712707182f}, {0.325966850828729f, 0.0110497237569061f}, {0.790055248618785f, 0.0220994475138122f},
+ {0.798342541436464f, 0.337016574585635f}, {0.798342541436464f, 0.430939226519337f}, {0.718232044198895f, 0.541436464088398f},
+ {0.596685082872928f, 0.674033149171271f}, {0.519337016574586f, 0.762430939226519f}, {0.408839779005525f, 0.856353591160221f},
+ {0.314917127071823f, 0.977900552486188f}, {0.314917127071823f, 0.977900552486188f}, {0.812154696132597f, 0.977900552486188f},
+ {0.812154696132597f, 0.977900552486188f}
+ };
+
+ private static Two INSTANCE = new Two();
+
+ protected Two() {
+ super(POINTS);
+ }
+
+ public static Two getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/java/com/mbh/timelyview/model/number/Zero.java b/timelyview/src/main/java/com/mbh/timelyview/model/number/Zero.java
new file mode 100644
index 0000000..05a45d0
--- /dev/null
+++ b/timelyview/src/main/java/com/mbh/timelyview/model/number/Zero.java
@@ -0,0 +1,23 @@
+package com.mbh.timelyview.model.number;
+
+import com.mbh.timelyview.model.core.Figure;
+
+public class Zero extends Figure {
+ private static final float[][] POINTS = {
+ {0.24585635359116f, 0.552486187845304f}, {0.24585635359116f, 0.331491712707182f}, {0.370165745856354f, 0.0994475138121547f},
+ {0.552486187845304f, 0.0994475138121547f}, {0.734806629834254f, 0.0994475138121547f}, {0.861878453038674f, 0.331491712707182f},
+ {0.861878453038674f, 0.552486187845304f}, {0.861878453038674f, 0.773480662983425f}, {0.734806629834254f, 0.994475138121547f},
+ {0.552486187845304f, 0.994475138121547f}, {0.370165745856354f, 0.994475138121547f}, {0.24585635359116f, 0.773480662983425f},
+ {0.24585635359116f, 0.552486187845304f}
+ };
+
+ private static Zero INSTANCE = new Zero();
+
+ protected Zero() {
+ super(POINTS);
+ }
+
+ public static Zero getInstance() {
+ return INSTANCE;
+ }
+}
\ No newline at end of file
diff --git a/timelyview/src/main/res/layout/timely_shorttimeview_layout.xml b/timelyview/src/main/res/layout/timely_shorttimeview_layout.xml
new file mode 100644
index 0000000..cbd082d
--- /dev/null
+++ b/timelyview/src/main/res/layout/timely_shorttimeview_layout.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/timelyview/src/main/res/layout/timely_timeview_layout.xml b/timelyview/src/main/res/layout/timely_timeview_layout.xml
new file mode 100644
index 0000000..cbe773f
--- /dev/null
+++ b/timelyview/src/main/res/layout/timely_timeview_layout.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/timelyview/src/main/res/values/attrs.xml b/timelyview/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..f07036b
--- /dev/null
+++ b/timelyview/src/main/res/values/attrs.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/timelyview/src/main/res/values/strings.xml b/timelyview/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c578b59
--- /dev/null
+++ b/timelyview/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ :
+
\ No newline at end of file
diff --git a/timelyview/src/main/res/values/styles.xml b/timelyview/src/main/res/values/styles.xml
new file mode 100644
index 0000000..1e08abf
--- /dev/null
+++ b/timelyview/src/main/res/values/styles.xml
@@ -0,0 +1,12 @@
+
+
+
+
+