├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mikesu │ │ └── expandablecalendarandroid │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── horizontalexpcalendar ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mikesu │ │ └── horizontalexpcalendar │ │ ├── HorizontalExpApplication.java │ │ ├── HorizontalExpCalendar.java │ │ ├── adapter │ │ └── CalendarAdapter.java │ │ ├── animator │ │ └── CalendarAnimation.java │ │ ├── common │ │ ├── Animations.java │ │ ├── Config.java │ │ ├── Constants.java │ │ ├── Marks.java │ │ └── Utils.java │ │ ├── listener │ │ ├── SmallAnimationListener.java │ │ └── SmallPageChangeListener.java │ │ ├── model │ │ └── MarkSetup.java │ │ └── view │ │ ├── cell │ │ ├── BaseCellView.java │ │ ├── DayCellView.java │ │ └── LabelCellView.java │ │ └── page │ │ └── PageView.java │ └── res │ ├── drawable │ ├── mark_custom1.xml │ ├── mark_custom2.xml │ ├── mark_selected.xml │ └── mark_today.xml │ ├── layout │ ├── animate_view.xml │ ├── day_cell_view.xml │ ├── horizontal_exp_calendar.xml │ ├── label_cell_view.xml │ ├── mark_cell_view.xml │ └── page_view.xml │ └── values │ ├── attrs.xml │ ├── strings.xml │ └── value.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | /.idea/ 10 | app/libs/ 11 | app/src/main/res/drawable/ 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-HorizontalExpandableCalendar--Android-green.svg?style=true)](https://android-arsenal.com/details/1/4215) 2 | 3 | # ! Unsupported ! 4 | # Horizontal Expandable Calendar - Android 5 | 6 | ## Preview 7 | [![YoutubePreview](https://img.youtube.com/vi/wiMT5O0hk9Q/0.jpg)](https://www.youtube.com/watch?v=wiMT5O0hk9Q) 8 | ``` 9 | https://youtu.be/wiMT5O0hk9Q 10 | ``` 11 | [![Screen1](https://i.imgur.com/8U7sU9i.png)](https://i.imgur.com/8U7sU9i.png) 12 | [![Screen2](https://i.imgur.com/m6QVDhy.png)](https://i.imgur.com/m6QVDhy.png) 13 | 14 | ## Installation 15 | 16 | Copy horizontalexpcalendar (1) module from this repository into your project's root directory project (2), then add dependency 17 | ``` 18 | compile project(':horizontalexpcalendar') 19 | ``` 20 | in your application build.gradle file (3) to horizontalexpcalendar module. 21 | Screenshot below 22 | 23 | ![Installation](http://i.imgur.com/Q7ZZ1fQ.png) 24 | 25 | ## Configuration & Customization 26 | ``` 27 | -> wiki 28 | ``` 29 | 30 | ## Dependencies 31 | ``` 32 | module is using: compile 'net.danlew:android.joda:2.9.4.1' 33 | ``` 34 | 35 | ## License 36 | ``` 37 | Copyright 2016 Michał Sułek 38 | 39 | Licensed under the Apache License, Version 2.0 (the "License"); 40 | you may not use this file except in compliance with the License. 41 | You may obtain a copy of the License at 42 | 43 | http://www.apache.org/licenses/LICENSE-2.0 44 | 45 | Unless required by applicable law or agreed to in writing, software 46 | distributed under the License is distributed on an "AS IS" BASIS, 47 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | See the License for the specific language governing permissions and 49 | limitations under the License. 50 | ``` 51 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.mikesu.expandablecalendarexample" 9 | minSdkVersion 16 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:24.1.1' 25 | compile project(':horizontalexpcalendar') 26 | } 27 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/mikesu/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/mikesu/expandablecalendarandroid/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.expandablecalendarandroid; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.util.Log; 6 | import com.mikesu.horizontalexpcalendar.HorizontalExpCalendar; 7 | import com.mikesu.horizontalexpcalendar.common.Config; 8 | import org.joda.time.DateTime; 9 | 10 | /** 11 | * Created by MikeSu on 04/08/16. 12 | * www.michalsulek.pl 13 | */ 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | private static final String TAG = MainActivity.class.getName(); 17 | private HorizontalExpCalendar horizontalExpCalendar; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | horizontalExpCalendar = (HorizontalExpCalendar) findViewById(R.id.calendar); 25 | horizontalExpCalendar.setHorizontalExpCalListener(new HorizontalExpCalendar.HorizontalExpCalListener() { 26 | @Override 27 | public void onCalendarScroll(DateTime dateTime) { 28 | Log.i(TAG, "onCalendarScroll: " + dateTime.toString()); 29 | } 30 | 31 | @Override 32 | public void onDateSelected(DateTime dateTime) { 33 | Log.i(TAG, "onDateSelected: " + dateTime.toString()); 34 | } 35 | 36 | @Override 37 | public void onChangeViewPager(Config.ViewPagerType viewPagerType) { 38 | Log.i(TAG, "onChangeViewPager: " + viewPagerType.name()); 39 | } 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ExpandableCalendarExample 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sulo61/HorizontalExpandableCalendar-Android/180021a761477696ef899c0b99870f39d5abb1d3/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /horizontalexpcalendar/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /horizontalexpcalendar/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 16 9 | targetSdkVersion 24 10 | versionCode 2 11 | versionName "1.1" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile 'com.android.support:appcompat-v7:24.1.1' 24 | compile 'net.danlew:android.joda:2.9.4.1' 25 | } 26 | -------------------------------------------------------------------------------- /horizontalexpcalendar/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\__ANDROID\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/HorizontalExpApplication.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar; 2 | 3 | import android.app.Application; 4 | import net.danlew.android.joda.JodaTimeAndroid; 5 | 6 | /** 7 | * Created by MikeSu on 04.01.2017. 8 | * www.michalsulek.pl 9 | */ 10 | 11 | public class HorizontalExpApplication extends Application { 12 | @Override 13 | public void onCreate() { 14 | super.onCreate(); 15 | JodaTimeAndroid.init(this); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/HorizontalExpCalendar.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.res.TypedArray; 6 | import android.support.v4.view.ViewPager; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | import android.view.ViewTreeObserver; 10 | import android.widget.GridLayout; 11 | import android.widget.LinearLayout; 12 | import android.widget.RelativeLayout; 13 | import android.widget.TextView; 14 | 15 | import com.mikesu.horizontalexpcalendar.adapter.CalendarAdapter; 16 | import com.mikesu.horizontalexpcalendar.common.Animations; 17 | import com.mikesu.horizontalexpcalendar.common.Config; 18 | import com.mikesu.horizontalexpcalendar.common.Marks; 19 | import com.mikesu.horizontalexpcalendar.common.Utils; 20 | import com.mikesu.horizontalexpcalendar.listener.SmallPageChangeListener; 21 | import com.mikesu.horizontalexpcalendar.view.page.PageView; 22 | 23 | import org.joda.time.DateTime; 24 | 25 | /** 26 | * Created by MikeSu on 23/04/18. 27 | * www.michalsulek.pl 28 | */ 29 | 30 | public class HorizontalExpCalendar extends RelativeLayout implements PageView.PageViewListener, Animations.AnimationsListener { 31 | 32 | private TextView titleTextView; 33 | private RelativeLayout centerContainer; 34 | private GridLayout animateContainer; 35 | 36 | private ViewPager monthViewPager; 37 | private CalendarAdapter monthPagerAdapter; 38 | 39 | private ViewPager weekViewPager; 40 | private CalendarAdapter weekPagerAdapter; 41 | 42 | private Animations animations; 43 | private HorizontalExpCalListener horizontalExpCalListener; 44 | 45 | private boolean lock; 46 | 47 | public HorizontalExpCalendar(Context context, AttributeSet attrs) { 48 | super(context, attrs); 49 | init(attrs); 50 | } 51 | 52 | public HorizontalExpCalendar(Context context, AttributeSet attrs, int defStyleAttr) { 53 | super(context, attrs, defStyleAttr); 54 | init(attrs); 55 | } 56 | 57 | public void setHorizontalExpCalListener(HorizontalExpCalListener horizontalExpCalListener) { 58 | this.horizontalExpCalListener = horizontalExpCalListener; 59 | } 60 | 61 | public void removeHorizontalExpCalListener() { 62 | this.horizontalExpCalListener = null; 63 | } 64 | 65 | @Override 66 | protected void onDetachedFromWindow() { 67 | animations.unbind(); 68 | Marks.clear(); 69 | super.onDetachedFromWindow(); 70 | } 71 | 72 | private void init(AttributeSet attributeSet) { 73 | inflate(getContext(), R.layout.horizontal_exp_calendar, this); 74 | 75 | centerContainer = (RelativeLayout) findViewById(R.id.center_container); 76 | lock = false; 77 | 78 | setValuesFromAttr(attributeSet); 79 | setupCellWidth(); 80 | 81 | Marks.init(); 82 | Marks.markToday(); 83 | Marks.refreshMarkSelected(Config.selectionDate); 84 | renderCustomMarks(); 85 | 86 | initAnimation(); 87 | } 88 | 89 | private void renderCustomMarks() { 90 | // custom1 91 | Marks.refreshCustomMark(new DateTime().minusDays(5), Marks.CustomMarks.CUSTOM1, true); 92 | Marks.refreshCustomMark(new DateTime().plusDays(1), Marks.CustomMarks.CUSTOM1, true); 93 | Marks.refreshCustomMark(new DateTime().plusDays(4), Marks.CustomMarks.CUSTOM1, true); 94 | // custom2 95 | Marks.refreshCustomMark(new DateTime().minusDays(7), Marks.CustomMarks.CUSTOM2, true); 96 | Marks.refreshCustomMark(new DateTime().plusDays(1), Marks.CustomMarks.CUSTOM2, true); 97 | Marks.refreshCustomMark(new DateTime().plusDays(10), Marks.CustomMarks.CUSTOM2, true); 98 | } 99 | 100 | private void setCellHeight() { 101 | Config.cellHeight = Config.monthViewPagerHeight / (Config.MONTH_ROWS + Utils.dayLabelExtraRow()); 102 | } 103 | 104 | public void setupCellWidth() { 105 | getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 106 | @Override 107 | public void onGlobalLayout() { 108 | HorizontalExpCalendar.this.getViewTreeObserver().removeOnGlobalLayoutListener(this); 109 | Config.cellWidth = getMeasuredWidth() / Config.COLUMNS; 110 | setupViews(); 111 | } 112 | }); 113 | } 114 | 115 | private void setValuesFromAttr(AttributeSet attributeSet) { 116 | TypedArray typedArray = getContext().obtainStyledAttributes(attributeSet, R.styleable.HorizontalExpCalendar); 117 | if (typedArray != null) { 118 | setupTopContainerFromAttr(typedArray); 119 | setupMiddleContainerFromAttr(typedArray); 120 | setupBottomContainerFromAttr(typedArray); 121 | setupExpandedFromAttr(typedArray); 122 | typedArray.recycle(); 123 | } 124 | 125 | setHeightToCenterContainer(Utils.isMonthView() ? Config.monthViewPagerHeight : Config.weekViewPagerHeight); 126 | } 127 | 128 | @SuppressLint("WrongViewCast") 129 | private void setupBottomContainerFromAttr(TypedArray typedArray) { 130 | if (typedArray.hasValue(R.styleable.HorizontalExpCalendar_bottom_container_height)) { 131 | ((LinearLayout.LayoutParams) findViewById(R.id.bottom_container).getLayoutParams()).height = 132 | typedArray.getDimensionPixelSize(R.styleable.HorizontalExpCalendar_bottom_container_height, 133 | LinearLayout.LayoutParams.WRAP_CONTENT); 134 | } 135 | } 136 | 137 | private void setupMiddleContainerFromAttr(TypedArray typedArray) { 138 | if (typedArray.hasValue(R.styleable.HorizontalExpCalendar_center_container_expanded_height)) { 139 | Config.monthViewPagerHeight = typedArray.getDimensionPixelSize( 140 | R.styleable.HorizontalExpCalendar_center_container_expanded_height, LinearLayout.LayoutParams.WRAP_CONTENT); 141 | 142 | setCellHeight(); 143 | 144 | Config.weekViewPagerHeight = Config.cellHeight * (Config.USE_DAY_LABELS ? 2 : 1); 145 | } 146 | } 147 | 148 | @SuppressLint("WrongViewCast") 149 | private void setupTopContainerFromAttr(TypedArray typedArray) { 150 | if (typedArray.hasValue(R.styleable.HorizontalExpCalendar_top_container_height)) { 151 | ((LinearLayout.LayoutParams) findViewById(R.id.top_container).getLayoutParams()).height = 152 | typedArray.getDimensionPixelSize(R.styleable.HorizontalExpCalendar_top_container_height, 153 | LinearLayout.LayoutParams.WRAP_CONTENT); 154 | } 155 | } 156 | 157 | private void setupExpandedFromAttr(TypedArray typedArray) { 158 | if (typedArray.hasValue(R.styleable.HorizontalExpCalendar_expanded)) { 159 | Config.currentViewPager = typedArray.getBoolean(R.styleable.HorizontalExpCalendar_expanded, true) ? 160 | Config.ViewPagerType.MONTH : Config.ViewPagerType.WEEK; 161 | } 162 | } 163 | 164 | private void initAnimation() { 165 | animations = new Animations(getContext(), HorizontalExpCalendar.this, Utils.animateContainerExtraTopOffset(getResources())); 166 | } 167 | 168 | private void setupViews() { 169 | initTopContainer(); 170 | initCenterContainer(); 171 | initBottomContainer(); 172 | initAnimateContainer(); 173 | refreshTitleTextView(); 174 | } 175 | 176 | private void initAnimateContainer() { 177 | animateContainer = (GridLayout) findViewById(R.id.animate_container); 178 | animateContainer.getLayoutParams().height = Config.cellHeight; 179 | int sideMargin = Utils.animateContainerExtraSideOffset(getResources()); 180 | animateContainer.setPadding(sideMargin, 0, sideMargin, 0); 181 | } 182 | 183 | private void initTopContainer() { 184 | titleTextView = (TextView) findViewById(R.id.title); 185 | findViewById(R.id.scroll_to_today_button).setOnClickListener(new OnClickListener() { 186 | @Override 187 | public void onClick(View view) { 188 | if (!isLocked()) { 189 | lock(); 190 | scrollToDate(new DateTime(), true, true, true); 191 | unlock(); 192 | } 193 | } 194 | }); 195 | } 196 | 197 | private void initCenterContainer() { 198 | initMonthViewPager(); 199 | initWeekViewPager(); 200 | } 201 | 202 | private void initBottomContainer() { 203 | findViewById(R.id.collapse_button).setOnClickListener(new OnClickListener() { 204 | @Override 205 | public void onClick(View view) { 206 | collapse(); 207 | } 208 | }); 209 | 210 | findViewById(R.id.expand_button).setOnClickListener(new OnClickListener() { 211 | @Override 212 | public void onClick(View view) { 213 | expand(); 214 | } 215 | }); 216 | } 217 | 218 | public void collapse() { 219 | if (!isLocked()) { 220 | lock(); 221 | if (Config.currentViewPager != Config.ViewPagerType.WEEK) { 222 | switchToView(Config.ViewPagerType.WEEK); 223 | } 224 | unlock(); 225 | if (horizontalExpCalListener != null) { 226 | horizontalExpCalListener.onCalendarScroll(Config.scrollDate.withDayOfWeek(1)); 227 | } 228 | } 229 | } 230 | 231 | public boolean isExpanded() { 232 | return Config.currentViewPager == Config.ViewPagerType.MONTH; 233 | } 234 | 235 | public void expand() { 236 | if (!isLocked()) { 237 | lock(); 238 | if (Config.currentViewPager != Config.ViewPagerType.MONTH) { 239 | switchToView(Config.ViewPagerType.MONTH); 240 | } 241 | unlock(); 242 | if (horizontalExpCalListener != null) { 243 | horizontalExpCalListener.onCalendarScroll(Config.scrollDate.withDayOfWeek(7)); 244 | } 245 | } 246 | } 247 | 248 | private void switchToView(final Config.ViewPagerType switchTo) { 249 | if (monthViewPager == null || weekPagerAdapter == null) return; 250 | Config.currentViewPager = switchTo; 251 | animations.clearAnimationsListener(); 252 | animations.startHidePagerAnimation(); 253 | } 254 | 255 | private void initMonthViewPager() { 256 | monthViewPager = (ViewPager) findViewById(R.id.month_view_pager); 257 | monthPagerAdapter = new CalendarAdapter(getContext(), Config.ViewPagerType.MONTH, this); 258 | monthViewPager.setAdapter(monthPagerAdapter); 259 | monthViewPager.setCurrentItem(Utils.monthPositionFromDate(Config.INIT_DATE)); 260 | monthViewPager.addOnPageChangeListener(new SmallPageChangeListener() { 261 | @Override 262 | public void scrollStart() { 263 | if (Utils.isMonthView()) { 264 | lock(); 265 | } 266 | } 267 | 268 | @Override 269 | public void scrollEnd() { 270 | if (Utils.isMonthView()) { 271 | Config.scrollDate = Utils.getDateByMonthPosition(monthViewPager.getCurrentItem()); 272 | if (Utils.isTheSameMonthToScrollDate(Config.selectionDate)) { 273 | Config.scrollDate = Config.selectionDate.toDateTime(); 274 | } 275 | refreshTitleTextView(); 276 | if (horizontalExpCalListener != null) { 277 | horizontalExpCalListener.onCalendarScroll(Config.scrollDate.withDayOfMonth(1)); 278 | } 279 | unlock(); 280 | } 281 | } 282 | }); 283 | monthViewPager.setVisibility(Utils.isMonthView() ? VISIBLE : GONE); 284 | } 285 | 286 | private void initWeekViewPager() { 287 | weekViewPager = (ViewPager) findViewById(R.id.week_view_pager); 288 | weekPagerAdapter = new CalendarAdapter(getContext(), Config.ViewPagerType.WEEK, this); 289 | weekViewPager.setAdapter(weekPagerAdapter); 290 | setWeekViewPagerPosition(Utils.weekPositionFromDate(Config.INIT_DATE), false); 291 | weekViewPager.addOnPageChangeListener(new SmallPageChangeListener() { 292 | @Override 293 | public void scrollStart() { 294 | if (!Utils.isMonthView()) { 295 | lock(); 296 | } 297 | } 298 | 299 | @Override 300 | public void scrollEnd() { 301 | if (!Utils.isMonthView()) { 302 | Config.scrollDate = Utils.getDateByWeekPosition(weekViewPager.getCurrentItem()); 303 | if (Utils.weekPositionFromDate(Config.scrollDate) == Utils.weekPositionFromDate(Config.selectionDate)) { 304 | Config.scrollDate = Config.selectionDate; 305 | } 306 | refreshTitleTextView(); 307 | if (horizontalExpCalListener != null) { 308 | horizontalExpCalListener.onCalendarScroll(Config.scrollDate.withDayOfWeek(1)); 309 | } 310 | unlock(); 311 | } 312 | } 313 | }); 314 | weekViewPager.setVisibility(!Utils.isMonthView() ? VISIBLE : GONE); 315 | } 316 | 317 | public void scrollToDate(DateTime dateTime, boolean animate) { 318 | if (Config.currentViewPager == Config.ViewPagerType.MONTH && Utils.isTheSameMonthToScrollDate(dateTime)) { 319 | return; 320 | } 321 | if (Config.currentViewPager == Config.ViewPagerType.WEEK && Utils.isTheSameWeekToScrollDate(dateTime) && Utils.isTheSameMonthToScrollDate(dateTime)) { 322 | return; 323 | } 324 | 325 | boolean isMonthView = Utils.isMonthView(); 326 | scrollToDate(dateTime, isMonthView, !isMonthView, animate); 327 | } 328 | 329 | private void setWeekViewPagerPosition(int position, boolean animate) { 330 | weekViewPager.setCurrentItem(position, animate); 331 | } 332 | 333 | private void setMonthViewPagerPosition(int position, boolean animate) { 334 | monthViewPager.setCurrentItem(position, animate); 335 | } 336 | 337 | private void refreshTitleTextView() { 338 | DateTime titleDate = Config.scrollDate; 339 | if (Config.currentViewPager == Config.ViewPagerType.MONTH) { 340 | if (Utils.isTheSameMonthToScrollDate(Config.selectionDate)) { 341 | titleDate = Config.selectionDate; 342 | } 343 | } else { 344 | if (Utils.isTheSameWeekToScrollDate(Config.selectionDate)) { 345 | titleDate = Config.selectionDate; 346 | } 347 | } 348 | titleTextView.setText(String.format("%s - %s", titleDate.getYear(), titleDate.getMonthOfYear())); 349 | } 350 | 351 | private void lock() { 352 | lock = true; 353 | } 354 | 355 | private void unlock() { 356 | lock = false; 357 | } 358 | 359 | private boolean isLocked() { 360 | return lock; 361 | } 362 | 363 | public void setVisible() { 364 | setVisibility(View.VISIBLE); 365 | if (Config.cellWidth == 0) { 366 | setupCellWidth(); 367 | } 368 | if (Config.cellHeight == 0) { 369 | setCellHeight(); 370 | } 371 | } 372 | 373 | public void setGone() { 374 | setVisibility(View.GONE); 375 | } 376 | 377 | @Override 378 | public void scrollToDate(DateTime dateTime, boolean scrollMonthPager, boolean scrollWeekPager, boolean animate) { 379 | if (scrollMonthPager) { 380 | setMonthViewPagerPosition(Utils.monthPositionFromDate(dateTime), animate); 381 | } 382 | if (scrollWeekPager) { 383 | setWeekViewPagerPosition(Utils.weekPositionFromDate(dateTime), animate); 384 | } 385 | } 386 | 387 | @Override 388 | public void animateContainerAddView(View view) { 389 | animateContainer.addView(view); 390 | } 391 | 392 | @Override 393 | public void animateContainerRemoveViews() { 394 | animateContainer.removeAllViews(); 395 | } 396 | 397 | @Override 398 | public void updateMarks() { 399 | if (Config.currentViewPager == Config.ViewPagerType.MONTH) { 400 | monthPagerAdapter.updateMarks(); 401 | } else { 402 | weekPagerAdapter.updateMarks(); 403 | } 404 | } 405 | 406 | @Override 407 | public void changeViewPager(Config.ViewPagerType viewPagerType) { 408 | if (horizontalExpCalListener != null) { 409 | horizontalExpCalListener.onChangeViewPager(viewPagerType); 410 | } 411 | } 412 | 413 | @Override 414 | public void onDayClick(DateTime dateTime) { 415 | scrollToDate(dateTime, true); 416 | 417 | Marks.refreshMarkSelected(dateTime); 418 | updateMarks(); 419 | 420 | refreshTitleTextView(); 421 | 422 | if (horizontalExpCalListener != null) { 423 | horizontalExpCalListener.onDateSelected(dateTime); 424 | } 425 | } 426 | 427 | @Override 428 | public void setHeightToCenterContainer(int height) { 429 | ((LinearLayout.LayoutParams) centerContainer.getLayoutParams()).height = height; 430 | centerContainer.requestLayout(); 431 | } 432 | 433 | @Override 434 | public void setTopMarginToAnimContainer(int margin) { 435 | ((RelativeLayout.LayoutParams) animateContainer.getLayoutParams()).topMargin = margin; 436 | } 437 | 438 | @Override 439 | public void setWeekPagerVisibility(int visibility) { 440 | weekViewPager.setVisibility(visibility); 441 | } 442 | 443 | @Override 444 | public void setMonthPagerVisibility(int visibility) { 445 | monthViewPager.setVisibility(visibility); 446 | } 447 | 448 | @Override 449 | public void setAnimatedContainerVisibility(int visibility) { 450 | animateContainer.setVisibility(visibility); 451 | } 452 | 453 | @Override 454 | public void setMonthPagerAlpha(float alpha) { 455 | monthViewPager.setAlpha(alpha); 456 | } 457 | 458 | @Override 459 | public void setWeekPagerAlpha(float alpha) { 460 | weekViewPager.setAlpha(alpha); 461 | } 462 | 463 | public interface HorizontalExpCalListener { 464 | void onCalendarScroll(DateTime dateTime); 465 | 466 | void onDateSelected(DateTime dateTime); 467 | 468 | void onChangeViewPager(Config.ViewPagerType viewPagerType); 469 | } 470 | } -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/adapter/CalendarAdapter.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import com.mikesu.horizontalexpcalendar.common.Config; 9 | import com.mikesu.horizontalexpcalendar.common.Utils; 10 | import com.mikesu.horizontalexpcalendar.view.page.PageView; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by MikeSu on 09.08.2016. 16 | * www.michalsulek.pl 17 | */ 18 | public class CalendarAdapter extends PagerAdapter { 19 | 20 | private PageView.PageViewListener pageViewListener; 21 | private Config.ViewPagerType viewPagerType; 22 | private List visiblePages; 23 | private Context context; 24 | 25 | public CalendarAdapter(Context context, Config.ViewPagerType viewPagerType, PageView.PageViewListener pageViewListener) { 26 | this.pageViewListener = pageViewListener; 27 | this.viewPagerType = viewPagerType; 28 | this.visiblePages = new ArrayList<>(); 29 | this.context = context; 30 | } 31 | 32 | @Override 33 | public int getCount() { 34 | switch (viewPagerType) { 35 | case MONTH: 36 | return Utils.monthPositionFromDate(Config.END_DATE); 37 | case WEEK: 38 | return Utils.weekPositionFromDate(Config.END_DATE); 39 | default: 40 | return 0; 41 | } 42 | } 43 | 44 | @Override 45 | public boolean isViewFromObject(View view, Object object) { 46 | return view == object; 47 | } 48 | 49 | @Override 50 | public Object instantiateItem(ViewGroup container, int position) { 51 | PageView pageView = new PageView(context, viewPagerType, pageViewListener); 52 | visiblePages.add(pageView); 53 | 54 | container.addView(pageView, 0); 55 | 56 | switch (viewPagerType) { 57 | case MONTH: 58 | pageView.setup(Utils.getDateByMonthPosition(position)); 59 | break; 60 | case WEEK: 61 | pageView.setup(Utils.getDateByWeekPosition(position)); 62 | break; 63 | default: 64 | Log.e(CalendarAdapter.class.getName(), "instantiateItem, unknown view pager type"); 65 | } 66 | 67 | return pageView; 68 | } 69 | 70 | @Override 71 | public void destroyItem(ViewGroup container, int position, Object object) { 72 | visiblePages.remove(object); 73 | container.removeView((PageView) object); 74 | } 75 | 76 | public void updateMarks() { 77 | for (PageView pageView : visiblePages) { 78 | pageView.updateMarks(); 79 | } 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/animator/CalendarAnimation.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.animator; 2 | 3 | import android.animation.ValueAnimator; 4 | import com.mikesu.horizontalexpcalendar.listener.SmallAnimationListener; 5 | 6 | /** 7 | * Created by MikeSu on 18/08/16. 8 | * www.michalsulek.pl 9 | */ 10 | public class CalendarAnimation extends ValueAnimator { 11 | 12 | public void setListener(SmallAnimationListener smallAnimationListener) { 13 | addUpdateListener(smallAnimationListener); 14 | addListener(smallAnimationListener); 15 | start(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/common/Animations.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.common; 2 | 3 | import android.animation.Animator; 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.GridLayout; 8 | import com.mikesu.horizontalexpcalendar.animator.CalendarAnimation; 9 | import com.mikesu.horizontalexpcalendar.listener.SmallAnimationListener; 10 | import com.mikesu.horizontalexpcalendar.view.cell.BaseCellView; 11 | import com.mikesu.horizontalexpcalendar.view.cell.DayCellView; 12 | import org.joda.time.DateTime; 13 | 14 | /** 15 | * Created by MikeSu on 18/08/16. 16 | * www.michalsulek.pl 17 | */ 18 | 19 | public class Animations { 20 | 21 | private static final String TAG = Animations.class.getName(); 22 | 23 | private CalendarAnimation decreasingAlphaAnimation; 24 | private CalendarAnimation increasingAlphaAnimation; 25 | private CalendarAnimation decreasingSizeAnimation; 26 | private CalendarAnimation increasingSizeAnimation; 27 | private int expandedTopMargin; 28 | private int collapsedTopMargin; 29 | 30 | private AnimationsListener animationsListener; 31 | private Context context; 32 | private int extraTopMarginOffset; 33 | 34 | public Animations(Context context, AnimationsListener animationsListener, int extraTopMarginOffset) { 35 | this.context = context; 36 | this.animationsListener = animationsListener; 37 | this.extraTopMarginOffset = extraTopMarginOffset; 38 | initAnimation(); 39 | } 40 | 41 | public void unbind() { 42 | this.context = null; 43 | this.animationsListener = null; 44 | } 45 | 46 | private void initAnimation() { 47 | decreasingAlphaAnimation = new CalendarAnimation(); 48 | decreasingAlphaAnimation.setFloatValues(Constants.ANIMATION_DECREASING_VALUES[0], Constants.ANIMATION_DECREASING_VALUES[1]); 49 | decreasingAlphaAnimation.setDuration(Constants.ANIMATION_ALPHA_DURATION); 50 | 51 | increasingAlphaAnimation = new CalendarAnimation(); 52 | increasingAlphaAnimation.setFloatValues(Constants.ANIMATION_INCREASING_VALUES[0], Constants.ANIMATION_INCREASING_VALUES[1]); 53 | increasingAlphaAnimation.setDuration(Constants.ANIMATION_ALPHA_DURATION); 54 | 55 | decreasingSizeAnimation = new CalendarAnimation(); 56 | decreasingSizeAnimation.setFloatValues(Constants.ANIMATION_DECREASING_VALUES[0], Constants.ANIMATION_DECREASING_VALUES[1]); 57 | decreasingSizeAnimation.setDuration(Constants.ANIMATION_SIZE_DURATION); 58 | 59 | increasingSizeAnimation = new CalendarAnimation(); 60 | increasingSizeAnimation.setFloatValues(Constants.ANIMATION_INCREASING_VALUES[0], Constants.ANIMATION_INCREASING_VALUES[1]); 61 | increasingSizeAnimation.setDuration(Constants.ANIMATION_SIZE_DURATION); 62 | 63 | expandedTopMargin = 0; 64 | collapsedTopMargin = 0; 65 | } 66 | 67 | public void startHidePagerAnimation() { 68 | if (animationsListener == null || decreasingAlphaAnimation == null) { 69 | Log.e(TAG, "startHidePagerAnimation, animationsListener or decreasingAlphaAnimation is null"); 70 | return; 71 | } 72 | decreasingAlphaAnimation.setListener(new SmallAnimationListener() { 73 | @Override 74 | public void animationStart(Animator animation) { 75 | if (animationsListener == null) return; 76 | 77 | if (Utils.isMonthView()) { 78 | animationsListener.setMonthPagerVisibility(View.GONE); 79 | animationsListener.setWeekPagerVisibility(View.VISIBLE); 80 | } else { 81 | animationsListener.setMonthPagerVisibility(View.VISIBLE); 82 | animationsListener.setWeekPagerVisibility(View.GONE); 83 | } 84 | 85 | animationsListener.setAnimatedContainerVisibility(View.VISIBLE); 86 | addCellsToAnimateContainer(); 87 | expandedTopMargin = Config.cellHeight * (Utils.getWeekOfMonth(getAnimateContainerDate()) - 88 | 1 + Utils.dayLabelExtraRow()) + extraTopMarginOffset; 89 | collapsedTopMargin = Config.cellHeight * (Utils.dayLabelExtraRow()); 90 | animationsListener.setTopMarginToAnimContainer((Utils.isMonthView() ? collapsedTopMargin : expandedTopMargin)); 91 | } 92 | 93 | @Override 94 | public void animationEnd(Animator animation) { 95 | if (animationsListener == null) return; 96 | 97 | animationsListener.setMonthPagerVisibility(View.GONE); 98 | animationsListener.setWeekPagerVisibility(View.GONE); 99 | clearAnimationsListener(); 100 | if (Utils.isMonthView()) { 101 | startIncreaseSizeAnimation(); 102 | } else { 103 | startDecreaseSizeAnimation(); 104 | } 105 | } 106 | 107 | @Override 108 | public void animationUpdate(Object value) { 109 | if (animationsListener == null) return; 110 | 111 | if (Utils.isMonthView()) { 112 | animationsListener.setWeekPagerAlpha((float) value); 113 | } else { 114 | animationsListener.setMonthPagerAlpha((float) value); 115 | } 116 | } 117 | }); 118 | } 119 | 120 | private void startShowPagerAnimation() { 121 | increasingAlphaAnimation.setListener(new SmallAnimationListener() { 122 | @Override 123 | public void animationStart(Animator animation) { 124 | if (animationsListener == null) return; 125 | 126 | if (Utils.isMonthView()) { 127 | animationsListener.setMonthPagerVisibility(View.VISIBLE); 128 | animationsListener.setWeekPagerVisibility(View.GONE); 129 | } else { 130 | animationsListener.setMonthPagerVisibility(View.GONE); 131 | animationsListener.setWeekPagerVisibility(View.VISIBLE); 132 | } 133 | 134 | if (Utils.isMonthView()) { 135 | if (Utils.isTheSameWeekToScrollDate(Config.selectionDate)) { 136 | Config.scrollDate = Config.selectionDate; 137 | } 138 | } else { 139 | if (Config.SCROLL_TO_SELECTED_AFTER_COLLAPSE && Utils.isTheSameMonthToScrollDate(Config.selectionDate)) { 140 | Config.scrollDate = Config.selectionDate; 141 | } else { 142 | Config.scrollDate = Config.scrollDate.withDayOfMonth(1); 143 | } 144 | } 145 | 146 | if (Utils.isMonthView()) { 147 | animationsListener.scrollToDate(Config.scrollDate, true, false, false); 148 | animationsListener.setHeightToCenterContainer(Config.monthViewPagerHeight); 149 | animationsListener.changeViewPager(Config.ViewPagerType.MONTH); 150 | } else { 151 | animationsListener.scrollToDate(Config.scrollDate, false, true, false); 152 | animationsListener.setHeightToCenterContainer(Config.weekViewPagerHeight); 153 | animationsListener.changeViewPager(Config.ViewPagerType.WEEK); 154 | } 155 | animationsListener.updateMarks(); 156 | } 157 | 158 | @Override 159 | public void animationEnd(Animator animation) { 160 | clearAnimationsListener(); 161 | if (animationsListener == null) return; 162 | animationsListener.setAnimatedContainerVisibility(View.GONE); 163 | animationsListener.animateContainerRemoveViews(); 164 | if (Utils.isMonthView()) { 165 | animationsListener.setMonthPagerVisibility(View.VISIBLE); 166 | animationsListener.setWeekPagerVisibility(View.GONE); 167 | } else { 168 | animationsListener.setMonthPagerVisibility(View.GONE); 169 | animationsListener.setWeekPagerVisibility(View.VISIBLE); 170 | } 171 | } 172 | 173 | @Override 174 | public void animationUpdate(Object value) { 175 | if (animationsListener == null) return; 176 | if (Utils.isMonthView()) { 177 | animationsListener.setMonthPagerAlpha((float) value); 178 | } else { 179 | animationsListener.setWeekPagerAlpha((float) value); 180 | } 181 | } 182 | }); 183 | } 184 | 185 | private void startDecreaseSizeAnimation() { 186 | decreasingSizeAnimation.setListener(new SmallAnimationListener() { 187 | @Override 188 | public void animationStart(Animator animation) { 189 | if (animationsListener == null) return; 190 | animationsListener.setHeightToCenterContainer(Config.monthViewPagerHeight); 191 | } 192 | 193 | @Override 194 | public void animationEnd(Animator animation) { 195 | if (animationsListener == null) return; 196 | animationsListener.setHeightToCenterContainer(Config.weekViewPagerHeight); 197 | clearAnimationsListener(); 198 | startShowPagerAnimation(); 199 | } 200 | 201 | @Override 202 | public void animationUpdate(Object value) { 203 | if (animationsListener == null) return; 204 | animationsListener.setHeightToCenterContainer(getAnimationCenterContainerHeight((float) value)); 205 | animationsListener.setTopMarginToAnimContainer( 206 | (int) ((expandedTopMargin - collapsedTopMargin) * (float) value) + collapsedTopMargin); 207 | } 208 | }); 209 | } 210 | 211 | private void startIncreaseSizeAnimation() { 212 | increasingSizeAnimation.setListener(new SmallAnimationListener() { 213 | @Override 214 | public void animationStart(Animator animation) { 215 | if (animationsListener == null) return; 216 | animationsListener.setHeightToCenterContainer(Config.weekViewPagerHeight); 217 | } 218 | 219 | @Override 220 | public void animationEnd(Animator animation) { 221 | if (animationsListener == null) return; 222 | animationsListener.setHeightToCenterContainer(Config.monthViewPagerHeight); 223 | clearAnimationsListener(); 224 | startShowPagerAnimation(); 225 | } 226 | 227 | @Override 228 | public void animationUpdate(Object value) { 229 | if (animationsListener == null) return; 230 | animationsListener.setHeightToCenterContainer(getAnimationCenterContainerHeight((float) value)); 231 | animationsListener.setTopMarginToAnimContainer( 232 | (int) ((expandedTopMargin - collapsedTopMargin) * (float) value) + collapsedTopMargin); 233 | } 234 | }); 235 | } 236 | 237 | private int getAnimationCenterContainerHeight(float value) { 238 | return (int) ((((Config.monthViewPagerHeight - Config.weekViewPagerHeight) * value)) + Config.weekViewPagerHeight); 239 | } 240 | 241 | public void clearAnimationsListener() { 242 | decreasingAlphaAnimation.removeAllListeners(); 243 | increasingAlphaAnimation.removeAllListeners(); 244 | decreasingSizeAnimation.removeAllListeners(); 245 | increasingSizeAnimation.removeAllListeners(); 246 | } 247 | 248 | private DateTime getAnimateContainerDate() { 249 | if (!Utils.isMonthView()) { 250 | if (Utils.isTheSameMonthToScrollDate(Config.selectionDate)) { 251 | return Config.selectionDate; 252 | } else { 253 | return Config.scrollDate; 254 | } 255 | } else { 256 | if (Utils.isTheSameWeekToScrollDate(Config.selectionDate)) { 257 | return Config.selectionDate; 258 | } else { 259 | return Config.scrollDate; 260 | } 261 | } 262 | } 263 | 264 | private void addCellsToAnimateContainer() { 265 | animationsListener.animateContainerRemoveViews(); 266 | 267 | DateTime animateInitDate = getAnimateContainerDate().minusDays(Utils.firstDayOffset()).withDayOfWeek(1); 268 | 269 | for (int d = 0; d < 7; d++) { 270 | DateTime cellDate = animateInitDate.plusDays(d + Utils.firstDayOffset()); 271 | 272 | DayCellView dayCellView = new DayCellView(context); 273 | 274 | GridLayout.LayoutParams cellParams = new GridLayout.LayoutParams(GridLayout.spec(0), GridLayout.spec(d)); 275 | cellParams.height = Config.cellHeight; 276 | cellParams.width = Config.cellWidth; 277 | dayCellView.setLayoutParams(cellParams); 278 | dayCellView.setDayNumber(cellDate.getDayOfMonth()); 279 | dayCellView.setDayType(Utils.isWeekendByColumnNumber(d) ? BaseCellView.DayType.WEEKEND : BaseCellView.DayType.NO_WEEKEND); 280 | dayCellView.setMark(Marks.getMark(cellDate), Config.cellHeight); 281 | dayCellView.setTimeType(getTimeType(cellDate)); 282 | 283 | animationsListener.animateContainerAddView(dayCellView); 284 | } 285 | } 286 | 287 | private DayCellView.TimeType getTimeType(DateTime cellTime) { 288 | if (cellTime.getMonthOfYear() < Config.scrollDate.getMonthOfYear()) { 289 | return DayCellView.TimeType.PAST; 290 | } else if (cellTime.getMonthOfYear() > Config.scrollDate.getMonthOfYear()) { 291 | return DayCellView.TimeType.FUTURE; 292 | } else { 293 | return DayCellView.TimeType.CURRENT; 294 | } 295 | } 296 | 297 | public interface AnimationsListener { 298 | void setHeightToCenterContainer(int height); 299 | 300 | void setTopMarginToAnimContainer(int margin); 301 | 302 | void setWeekPagerVisibility(int visibility); 303 | 304 | void setMonthPagerVisibility(int visibility); 305 | 306 | void setAnimatedContainerVisibility(int visibility); 307 | 308 | void setMonthPagerAlpha(float alpha); 309 | 310 | void setWeekPagerAlpha(float alpha); 311 | 312 | void scrollToDate(DateTime dateTime, boolean scrollMonthPager, boolean scrollWeekPager, boolean animate); 313 | 314 | void animateContainerAddView(View view); 315 | 316 | void animateContainerRemoveViews(); 317 | 318 | void updateMarks(); 319 | 320 | void changeViewPager(Config.ViewPagerType viewPagerType); 321 | } 322 | 323 | } 324 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/common/Config.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.common; 2 | 3 | import android.graphics.Color; 4 | import android.util.Log; 5 | 6 | import org.joda.time.DateTime; 7 | 8 | /** 9 | * Created by MikeSu on 08/08/16. 10 | * www.michalsulek.pl 11 | */ 12 | 13 | public class Config { 14 | 15 | /* CONFIGURATION */ 16 | private static final ViewPagerType INIT_VIEW = ViewPagerType.MONTH; 17 | private static final int RANGE_MONTHS_BEFORE_INIT = 12; 18 | private static final int RANGE_MONTHS_AFTER_INIT = 18; 19 | public static final DateTime INIT_DATE = new DateTime(); 20 | public static final FirstDay FIRST_DAY_OF_WEEK = FirstDay.MONDAY; 21 | public static final int CELL_WEEKEND_BACKGROUND = Color.WHITE; 22 | public static final int CELL_NON_WEEKEND_BACKGROUND = Color.WHITE; 23 | public static final int CELL_TEXT_CURRENT_MONTH_COLOR = Color.BLACK; 24 | public static final int CELL_TEXT_ANOTHER_MONTH_COLOR = Color.parseColor("#c3c6cd"); 25 | public static final boolean USE_DAY_LABELS = true; 26 | public static final boolean SCROLL_TO_SELECTED_AFTER_COLLAPSE = true; 27 | /* END CONFIGURATION */ 28 | 29 | private static DateTime getStartDate() { 30 | DateTime START_BACK_BY_RANGE = INIT_DATE.plusMonths(-RANGE_MONTHS_BEFORE_INIT); 31 | DateTime START_BACK_TO_FIRST_DAY_OF_MONTH = START_BACK_BY_RANGE.plusDays(-START_BACK_BY_RANGE.getDayOfMonth() + 1); 32 | return START_BACK_TO_FIRST_DAY_OF_MONTH.plusDays(-START_BACK_TO_FIRST_DAY_OF_MONTH.getDayOfWeek() + 1); 33 | } 34 | 35 | private static DateTime getEndDate() { 36 | DateTime END_FORWARD_BY_RANGE = INIT_DATE.plusMonths(RANGE_MONTHS_AFTER_INIT + 1); 37 | DateTime END_BACK_TO_FIRST_DAY_OF_MONTH = END_FORWARD_BY_RANGE.plusDays(-END_FORWARD_BY_RANGE.getDayOfMonth() + 1); 38 | return END_BACK_TO_FIRST_DAY_OF_MONTH.plusDays(7 - END_BACK_TO_FIRST_DAY_OF_MONTH.getDayOfWeek() + 1); 39 | } 40 | 41 | public static DateTime START_DATE = getStartDate(); 42 | public static final DateTime END_DATE = getEndDate(); 43 | 44 | public static final int MONTH_ROWS = 6; 45 | public static final int WEEK_ROWS = 1; 46 | public static final int COLUMNS = 7; 47 | 48 | public static ViewPagerType currentViewPager = INIT_VIEW; 49 | public static DateTime scrollDate = INIT_DATE; 50 | public static DateTime selectionDate = new DateTime(); 51 | public static int cellWidth = 0; 52 | public static int cellHeight = 0; 53 | public static int monthViewPagerHeight; 54 | public static int weekViewPagerHeight; 55 | 56 | public enum ViewPagerType { 57 | MONTH, 58 | WEEK 59 | } 60 | 61 | public enum FirstDay { 62 | SUNDAY, 63 | MONDAY 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/common/Constants.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.common; 2 | 3 | /** 4 | * Created by MikeSu on 08.08.2016. 5 | * www.michalsulek.pl 6 | */ 7 | 8 | public class Constants { 9 | 10 | public static final String[] NAME_OF_DAYS = new String[]{"Nd", "Pon", "Wt", "Śr", "Czw", "Pt", "Sob"}; 11 | 12 | public static final float[] ANIMATION_INCREASING_VALUES = new float[]{0.0f, 1.0f}; 13 | public static final float[] ANIMATION_DECREASING_VALUES = new float[]{1.0f, 0.0f}; 14 | public static final int ANIMATION_ALPHA_DURATION = 300; 15 | public static final int ANIMATION_SIZE_DURATION = 200; 16 | } 17 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/common/Marks.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.common; 2 | 3 | import android.util.Log; 4 | import com.mikesu.horizontalexpcalendar.model.MarkSetup; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import org.joda.time.DateTime; 8 | 9 | /** 10 | * Created by MikeSu on 09.08.2016. 11 | * www.michalsulek.pl 12 | */ 13 | 14 | public class Marks { 15 | 16 | private static final String TAG = Marks.class.getName(); 17 | private static Map marksMap; 18 | private static boolean locked = false; 19 | 20 | public static final float MARK_CUSTOM1_SIZE_PROPORTION_TO_CELL = 0.15f; 21 | public static final float MARK_CUSTOM2_HEIGHT_PROPORTION_TO_CELL = 0.4f; 22 | public static final float MARK_CUSTOM2_WIDTH_PROPORTION_TO_CELL = 0.08f; 23 | 24 | public static void init() { 25 | marksMap = new HashMap<>(); 26 | } 27 | 28 | public static void markToday() { 29 | if (isLocked()) { 30 | return; 31 | } 32 | lock(); 33 | MarkSetup markSetup = getMark(new DateTime()); 34 | if (markSetup == null) { 35 | addNewMark(new DateTime(), new MarkSetup(true, false)); 36 | } else { 37 | markSetup.setToday(true); 38 | } 39 | unlock(); 40 | } 41 | 42 | public static void refreshMarkSelected(DateTime newSelection) { 43 | if (isLocked()) { 44 | return; 45 | } 46 | lock(); 47 | MarkSetup oldSelectionSetup = getMark(Config.selectionDate); 48 | if (oldSelectionSetup != null) { 49 | oldSelectionSetup.setSelected(false); 50 | if (oldSelectionSetup.canBeDeleted()) { 51 | marksMap.remove(dateTimeToStringKey(Config.selectionDate)); 52 | } 53 | } 54 | 55 | MarkSetup newSelectionSetup = getMark(newSelection); 56 | if (newSelectionSetup == null) { 57 | newSelectionSetup = new MarkSetup(); 58 | marksMap.put(dateTimeToStringKey(newSelection), newSelectionSetup); 59 | } 60 | newSelectionSetup.setSelected(true); 61 | 62 | Config.selectionDate = newSelection; 63 | 64 | unlock(); 65 | } 66 | 67 | public static void refreshCustomMark(DateTime dateTime, CustomMarks customMarks, boolean mark) { 68 | if (isLocked()) { 69 | return; 70 | } 71 | lock(); 72 | MarkSetup markSetup = getMark(dateTime); 73 | if (markSetup == null) { 74 | markSetup = new MarkSetup(); 75 | addNewMark(dateTime, markSetup); 76 | } 77 | switch (customMarks) { 78 | case CUSTOM1: 79 | markSetup.setCustom1(mark); 80 | break; 81 | case CUSTOM2: 82 | markSetup.setCustom2(mark); 83 | break; 84 | default: 85 | Log.e(TAG, "markCustom, unknown case: " + customMarks.name()); 86 | } 87 | 88 | if (mark) { 89 | if (markSetup.canBeDeleted()) { 90 | marksMap.remove(dateTimeToStringKey(dateTime)); 91 | } 92 | } 93 | 94 | unlock(); 95 | } 96 | 97 | public static void clear() { 98 | marksMap.clear(); 99 | } 100 | 101 | private static void addNewMark(DateTime dateTime, MarkSetup markSetup) { 102 | marksMap.put(dateTimeToStringKey(dateTime), markSetup); 103 | } 104 | 105 | public static MarkSetup getMark(DateTime dateTime) { 106 | return marksMap.get(dateTimeToStringKey(dateTime)); 107 | } 108 | 109 | private static String dateTimeToStringKey(DateTime dateTime) { 110 | return dateTime.getYear() + "-" + dateTime.getMonthOfYear() + "-" + dateTime.getDayOfMonth(); 111 | } 112 | 113 | public static void lock() { 114 | locked = true; 115 | } 116 | 117 | public static void unlock() { 118 | locked = false; 119 | } 120 | 121 | public static boolean isLocked() { 122 | return locked; 123 | } 124 | 125 | public enum CustomMarks { 126 | CUSTOM1, 127 | CUSTOM2 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/common/Utils.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.common; 2 | 3 | import android.content.res.Resources; 4 | import java.util.Random; 5 | import org.joda.time.DateTime; 6 | 7 | /** 8 | * Created by MikeSu on 08/08/16. 9 | * www.michalsulek.pl 10 | */ 11 | 12 | public class Utils { 13 | 14 | public static int monthPositionFromDate(DateTime dateTo) { 15 | DateTime dateFrom = Config.START_DATE.withDayOfWeek(7); 16 | return ((dateTo.getYear() - dateFrom.getYear()) * 12) + (dateTo.getMonthOfYear() - dateFrom.getMonthOfYear()); 17 | } 18 | 19 | public static int weekPositionFromDate(DateTime dateTo) { 20 | DateTime dateFrom = Config.START_DATE.toDateTime(); 21 | DateTime dateToWithFixedSeconds = dateTo 22 | .minusDays(firstDayOffset()) 23 | .withSecondOfMinute(dateFrom.getSecondOfMinute()) 24 | .withMillisOfSecond(dateFrom.getMillisOfSecond()); 25 | int weeksBetween = 0; 26 | while (dateFrom.isBefore(dateToWithFixedSeconds.plusDays(1))) { 27 | weeksBetween++; 28 | dateFrom = dateFrom.plusWeeks(1); 29 | } 30 | return weeksBetween - 1; 31 | } 32 | 33 | public static boolean isWeekendByColumnNumber(int column) { 34 | switch (Config.FIRST_DAY_OF_WEEK) { 35 | case SUNDAY: 36 | return (column == 0 || column == 6); 37 | case MONDAY: 38 | return (column == 5 || column == 6); 39 | default: 40 | return false; 41 | } 42 | } 43 | 44 | public static int getRandomColor() { 45 | return new Random().nextInt(40) + 215; 46 | } 47 | 48 | public static int dayLabelExtraRow() { 49 | return Config.USE_DAY_LABELS ? 1 : 0; 50 | } 51 | 52 | public static int dayLabelExtraChildCount() { 53 | return Config.USE_DAY_LABELS ? 7 : 0; 54 | } 55 | 56 | public static boolean isMonthView() { 57 | return Config.currentViewPager == Config.ViewPagerType.MONTH; 58 | } 59 | 60 | public static DateTime getDateByMonthPosition(int position) { 61 | return Config.START_DATE.withDayOfWeek(7 + firstDayOffset()).withDayOfMonth(1).plusMonths(position); 62 | } 63 | 64 | public static DateTime getDateByWeekPosition(int position) { 65 | return Config.START_DATE.withDayOfWeek(7 + firstDayOffset()).plusWeeks(position); 66 | } 67 | 68 | public static boolean isTheSameMonthToScrollDate(DateTime dateTime) { 69 | return isTheSameMonth(Config.scrollDate, dateTime); 70 | } 71 | 72 | public static boolean isTheSameMonth(DateTime dateTime1, DateTime dateTime2) { 73 | return (dateTime1.getYear() == dateTime2.getYear()) && (dateTime1.getMonthOfYear() == dateTime2.getMonthOfYear()); 74 | } 75 | 76 | public static boolean isTheSameWeekToScrollDate(DateTime dateTime) { 77 | return isTheSameWeek(Config.scrollDate, dateTime); 78 | } 79 | 80 | public static boolean isTheSameWeek(DateTime dateTime1, DateTime dateTime2) { 81 | DateTime firstDateMovedByFirstDayOfWeek = dateTime1.minusDays(firstDayOffset()); 82 | DateTime secondDateMovedByFirstDayOfWeek = dateTime2.minusDays(firstDayOffset()); 83 | return (firstDateMovedByFirstDayOfWeek.getYear() == secondDateMovedByFirstDayOfWeek.getYear()) && 84 | (firstDateMovedByFirstDayOfWeek.getWeekOfWeekyear() == secondDateMovedByFirstDayOfWeek.getWeekOfWeekyear()); 85 | } 86 | 87 | public static int firstDayOffset() { 88 | switch (Config.FIRST_DAY_OF_WEEK) { 89 | case SUNDAY: 90 | return -1; 91 | case MONDAY: 92 | return 0; 93 | } 94 | return 0; 95 | } 96 | 97 | public static int getWeekOfMonth(DateTime dateTime) { 98 | return ((dateTime.getDayOfMonth() + dateTime.withDayOfMonth(1).getDayOfWeek() - 2 - firstDayOffset()) / 7) + 1; 99 | } 100 | 101 | public static int animateContainerExtraTopOffset(Resources resources) { 102 | float density = resources.getDisplayMetrics().density; 103 | if (density >= 4.0) { 104 | return 0; 105 | } 106 | if (density >= 3.0) { 107 | return 0; 108 | } 109 | if (density >= 2.0) { 110 | return 1; 111 | } 112 | if (density >= 1.5) { 113 | return 2; 114 | } 115 | if (density >= 1.0) { 116 | return 2; 117 | } 118 | return 0; 119 | } 120 | 121 | public static int animateContainerExtraSideOffset(Resources resources) { 122 | float density = resources.getDisplayMetrics().density; 123 | if (density >= 4.0) { 124 | return 2; 125 | } 126 | if (density >= 3.0) { 127 | return 2; 128 | } 129 | if (density >= 2.0) { 130 | return 2; 131 | } 132 | if (density >= 1.5) { 133 | return 2; 134 | } 135 | if (density >= 1.0) { 136 | return 0; 137 | } 138 | return 0; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/listener/SmallAnimationListener.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.listener; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | 6 | /** 7 | * Created by MikeSu on 18/08/16. 8 | * www.michalsulek.pl 9 | */ 10 | public abstract class SmallAnimationListener implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { 11 | 12 | @Override 13 | public void onAnimationUpdate(ValueAnimator valueAnimator) { 14 | animationUpdate(valueAnimator.getAnimatedValue()); 15 | } 16 | 17 | @Override 18 | public void onAnimationStart(Animator animator) { 19 | animationStart(animator); 20 | } 21 | 22 | @Override 23 | public void onAnimationEnd(Animator animator) { 24 | animationEnd(animator); 25 | } 26 | 27 | @Override 28 | public void onAnimationCancel(Animator animator) { 29 | animationEnd(animator); 30 | } 31 | 32 | @Override 33 | public void onAnimationRepeat(Animator animator) { 34 | // IGNORE 35 | } 36 | 37 | public abstract void animationStart(Animator animation); 38 | 39 | public abstract void animationEnd(Animator animation); 40 | 41 | public abstract void animationUpdate(Object value); 42 | } 43 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/listener/SmallPageChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.listener; 2 | 3 | import android.support.v4.view.ViewPager; 4 | 5 | /** 6 | * Created by MikeSu on 05/08/16. 7 | * www.michalsulek.pl 8 | */ 9 | 10 | public abstract class SmallPageChangeListener implements ViewPager.OnPageChangeListener { 11 | 12 | @Override 13 | public void onPageScrollStateChanged(int state) { 14 | if (state == ViewPager.SCROLL_STATE_IDLE) { 15 | scrollEnd(); 16 | } else if (state == ViewPager.SCROLL_STATE_DRAGGING) { 17 | scrollStart(); 18 | } 19 | } 20 | 21 | @Override 22 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 23 | // IGNORE 24 | } 25 | 26 | @Override 27 | public void onPageSelected(int position) { 28 | // IGNORE 29 | } 30 | 31 | public abstract void scrollStart(); 32 | 33 | public abstract void scrollEnd(); 34 | } 35 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/model/MarkSetup.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.model; 2 | 3 | /** 4 | * Created by MikeSu on 09.08.2016. 5 | * www.michalsulek.pl 6 | */ 7 | 8 | public class MarkSetup { 9 | 10 | private boolean today; 11 | private boolean selected; 12 | private boolean custom1; 13 | private boolean custom2; 14 | 15 | public MarkSetup() { 16 | this.today = false; 17 | this.selected = false; 18 | this.custom1 = false; 19 | this.custom2 = false; 20 | } 21 | 22 | public MarkSetup(boolean today, boolean selected) { 23 | this(today, selected, false); 24 | } 25 | 26 | public MarkSetup(boolean today, boolean selected, boolean custom1) { 27 | this(today, selected, custom1, false); 28 | } 29 | 30 | public MarkSetup(boolean today, boolean selected, boolean custom1, boolean custom2) { 31 | this.today = today; 32 | this.selected = selected; 33 | this.custom1 = custom1; 34 | this.custom2 = custom2; 35 | } 36 | 37 | public boolean isToday() { 38 | return today; 39 | } 40 | 41 | public void setToday(boolean today) { 42 | this.today = today; 43 | } 44 | 45 | public boolean isSelected() { 46 | return selected; 47 | } 48 | 49 | public void setSelected(boolean selected) { 50 | this.selected = selected; 51 | } 52 | 53 | public boolean isCustom1() { 54 | return custom1; 55 | } 56 | 57 | public void setCustom1(boolean custom1) { 58 | this.custom1 = custom1; 59 | } 60 | 61 | public boolean isCustom2() { 62 | return custom2; 63 | } 64 | 65 | public void setCustom2(boolean custom2) { 66 | this.custom2 = custom2; 67 | } 68 | 69 | public boolean canBeDeleted() { 70 | return !today && !selected && !custom1 && !custom2; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/view/cell/BaseCellView.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.view.cell; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.FrameLayout; 6 | import com.mikesu.horizontalexpcalendar.common.Config; 7 | 8 | /** 9 | * Created by MikeSu on 08.08.2016. 10 | * www.michalsulek.pl 11 | */ 12 | 13 | public abstract class BaseCellView extends FrameLayout { 14 | 15 | protected DayType dayType; 16 | 17 | public BaseCellView(Context context) { 18 | super(context); 19 | } 20 | 21 | public BaseCellView(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | } 24 | 25 | public BaseCellView(Context context, AttributeSet attrs, int defStyleAttr) { 26 | super(context, attrs, defStyleAttr); 27 | } 28 | 29 | 30 | protected void setTextBackgroundByDayType() { 31 | if (this.dayType == DayType.WEEKEND) { 32 | setBackgroundColor(Config.CELL_WEEKEND_BACKGROUND); 33 | } else { 34 | setBackgroundColor(Config.CELL_NON_WEEKEND_BACKGROUND); 35 | } 36 | } 37 | 38 | public enum DayType { 39 | WEEKEND, 40 | NO_WEEKEND 41 | } 42 | 43 | public enum TimeType { 44 | PAST, 45 | CURRENT, 46 | FUTURE 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/view/cell/DayCellView.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.view.cell; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.FrameLayout; 8 | import android.widget.TextView; 9 | 10 | import com.mikesu.horizontalexpcalendar.R; 11 | import com.mikesu.horizontalexpcalendar.common.Config; 12 | import com.mikesu.horizontalexpcalendar.common.Marks; 13 | import com.mikesu.horizontalexpcalendar.model.MarkSetup; 14 | 15 | /** 16 | * Created by MikeSu on 04/08/16. 17 | * www.michalsulek.pl 18 | */ 19 | 20 | public class DayCellView extends BaseCellView { 21 | 22 | private TextView text; 23 | private TimeType timeType; 24 | private FrameLayout markContainer; 25 | 26 | private MarkSetup markSetup; 27 | private View markToday; 28 | private View markSelected; 29 | private View markCustom1; 30 | private View markCustom2; 31 | 32 | public DayCellView(Context context) { 33 | super(context); 34 | init(); 35 | } 36 | 37 | public DayCellView(Context context, AttributeSet attrs) { 38 | super(context, attrs); 39 | init(); 40 | } 41 | 42 | public DayCellView(Context context, AttributeSet attrs, int defStyleAttr) { 43 | super(context, attrs, defStyleAttr); 44 | init(); 45 | } 46 | 47 | private void init() { 48 | initView(); 49 | } 50 | 51 | private void initView() { 52 | inflate(getContext(), R.layout.day_cell_view, this); 53 | 54 | text = (TextView) findViewById(R.id.text); 55 | markContainer = (FrameLayout) findViewById(R.id.mark_container); 56 | markToday = findViewById(R.id.mark_today_view); 57 | markSelected = findViewById(R.id.mark_selected_view); 58 | markCustom1 = findViewById(R.id.mark_custom1); 59 | markCustom2 = findViewById(R.id.mark_custom2); 60 | 61 | text.setTextColor(Config.CELL_TEXT_CURRENT_MONTH_COLOR); 62 | } 63 | 64 | public void setTimeType(TimeType timeType) { 65 | this.timeType = timeType; 66 | setTextColor(); 67 | } 68 | 69 | public void setDayNumber(int dayNumber) { 70 | this.text.setText(String.valueOf(dayNumber)); 71 | } 72 | 73 | public void setDayType(DayType dayType) { 74 | this.dayType = dayType; 75 | setTextBackgroundByDayType(); 76 | } 77 | 78 | 79 | private void setTextColor() { 80 | if (markSetup == null) { 81 | colorTextWithoutMark(); 82 | } else { 83 | if (markSetup.isToday() && markSetup.isSelected()) { 84 | text.setTextColor(Color.WHITE); 85 | return; 86 | } 87 | if (markSetup.isToday() && !markSetup.isSelected()) { 88 | text.setTextColor(Color.parseColor("#f65f00")); 89 | return; 90 | } 91 | if (!markSetup.isToday() && markSetup.isSelected()) { 92 | text.setTextColor(Color.WHITE); 93 | return; 94 | } 95 | colorTextWithoutMark(); 96 | } 97 | } 98 | 99 | public void colorTextWithoutMark() { 100 | if ((timeType != TimeType.CURRENT) && ((Config.currentViewPager == Config.ViewPagerType.MONTH) )) { 101 | text.setTextColor(Config.CELL_TEXT_ANOTHER_MONTH_COLOR); 102 | } else { 103 | text.setTextColor(Config.CELL_TEXT_CURRENT_MONTH_COLOR); 104 | } 105 | } 106 | 107 | public void setMark(MarkSetup markSetup, int size) { 108 | setSize(size); 109 | setMarkSetup(markSetup); 110 | } 111 | 112 | private void setSize(int size) { 113 | LayoutParams markParams = (LayoutParams) markContainer.getLayoutParams(); 114 | markParams.height = size; 115 | markParams.width = size; 116 | 117 | setupCustom1Mark(size); 118 | setupCustom2Mark(size); 119 | } 120 | 121 | private void setupCustom1Mark(int size) { 122 | LayoutParams markCustomParams = (LayoutParams) markCustom1.getLayoutParams(); 123 | int markCustomPercentSize = (int) (size * Marks.MARK_CUSTOM1_SIZE_PROPORTION_TO_CELL); 124 | markCustomParams.height = markCustomPercentSize; 125 | markCustomParams.width = markCustomPercentSize; 126 | } 127 | 128 | private void setupCustom2Mark(int size) { 129 | LayoutParams markCustomParams = (LayoutParams) markCustom2.getLayoutParams(); 130 | markCustomParams.height = (int) (size * Marks.MARK_CUSTOM2_HEIGHT_PROPORTION_TO_CELL); 131 | markCustomParams.width = (int) (size * Marks.MARK_CUSTOM2_WIDTH_PROPORTION_TO_CELL); 132 | } 133 | 134 | public void setMarkSetup(MarkSetup markSetup) { 135 | this.markSetup = markSetup; 136 | setMarkToView(); 137 | setTextColor(); 138 | } 139 | 140 | private void setMarkToView() { 141 | if (markSetup == null) { 142 | markContainer.setVisibility(GONE); 143 | } else { 144 | markContainer.setVisibility(VISIBLE); 145 | // markToday.setVisibility(markSetup.isToday() ? VISIBLE : GONE); 146 | markSelected.setVisibility(markSetup.isSelected() ? VISIBLE : GONE); 147 | markCustom1.setVisibility(markSetup.isCustom1() ? VISIBLE : GONE); 148 | markCustom2.setVisibility(markSetup.isCustom2() ? VISIBLE : GONE); 149 | } 150 | } 151 | } -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/view/cell/LabelCellView.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.view.cell; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.TextView; 6 | import com.mikesu.horizontalexpcalendar.R; 7 | 8 | /** 9 | * Created by MikeSu on 04/08/16. 10 | * www.michalsulek.pl 11 | */ 12 | 13 | public class LabelCellView extends BaseCellView { 14 | 15 | private TextView text; 16 | 17 | public LabelCellView(Context context) { 18 | super(context); 19 | init(); 20 | } 21 | 22 | public LabelCellView(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | init(); 25 | } 26 | 27 | public LabelCellView(Context context, AttributeSet attrs, int defStyleAttr) { 28 | super(context, attrs, defStyleAttr); 29 | init(); 30 | } 31 | 32 | private void init() { 33 | initView(); 34 | } 35 | 36 | private void initView() { 37 | inflate(getContext(), R.layout.label_cell_view, this); 38 | 39 | text = (TextView) findViewById(R.id.text); 40 | } 41 | 42 | public void setText(String text) { 43 | this.text.setText(text); 44 | } 45 | 46 | public void setDayType(DayType dayType) { 47 | this.dayType = dayType; 48 | setTextBackgroundByDayType(); 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/java/com/mikesu/horizontalexpcalendar/view/page/PageView.java: -------------------------------------------------------------------------------- 1 | package com.mikesu.horizontalexpcalendar.view.page; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | import android.widget.FrameLayout; 6 | import android.widget.GridLayout; 7 | import com.mikesu.horizontalexpcalendar.R; 8 | import com.mikesu.horizontalexpcalendar.common.Config; 9 | import com.mikesu.horizontalexpcalendar.common.Constants; 10 | import com.mikesu.horizontalexpcalendar.common.Marks; 11 | import com.mikesu.horizontalexpcalendar.common.Utils; 12 | import com.mikesu.horizontalexpcalendar.view.cell.BaseCellView; 13 | import com.mikesu.horizontalexpcalendar.view.cell.DayCellView; 14 | import com.mikesu.horizontalexpcalendar.view.cell.LabelCellView; 15 | import org.joda.time.DateTime; 16 | 17 | /** 18 | * Created by MikeSu on 09.08.2016. 19 | * www.michalsulek.pl 20 | */ 21 | public class PageView extends FrameLayout implements View.OnClickListener { 22 | 23 | private PageViewListener pageViewListener; 24 | private GridLayout gridLayout; 25 | private DateTime pageDate; 26 | 27 | private Config.ViewPagerType viewPagerType; 28 | private int rows; 29 | 30 | public PageView(Context context) { 31 | this(context, null, null); 32 | } 33 | 34 | public PageView(Context context, Config.ViewPagerType viewPagerType, PageViewListener pageViewListener) { 35 | super(context); 36 | if (pageViewListener != null) { 37 | this.pageViewListener = pageViewListener; 38 | } 39 | if (viewPagerType != null) { 40 | this.viewPagerType = viewPagerType; 41 | this.rows = viewPagerType == Config.ViewPagerType.MONTH ? Config.MONTH_ROWS : Config.WEEK_ROWS; 42 | init(); 43 | } 44 | } 45 | 46 | private void init() { 47 | initViews(); 48 | } 49 | 50 | private void initViews() { 51 | inflate(getContext(), R.layout.page_view, this); 52 | gridLayout = (GridLayout) findViewById(R.id.grid_layout); 53 | gridLayout.setColumnCount(Config.COLUMNS); 54 | gridLayout.setRowCount(rows + (Utils.dayLabelExtraRow())); 55 | } 56 | 57 | public void setup(DateTime pageDate) { 58 | this.pageDate = pageDate; 59 | addCellsToGrid(); 60 | } 61 | 62 | private void addCellsToGrid() { 63 | DateTime cellDate; 64 | if (viewPagerType == Config.ViewPagerType.MONTH) { 65 | cellDate = pageDate.withDayOfMonth(1).plusDays(-pageDate.withDayOfMonth(1).getDayOfWeek() + 1 + Utils.firstDayOffset()); 66 | } else { 67 | cellDate = pageDate.plusDays(-pageDate.getDayOfWeek() + 1 + Utils.firstDayOffset()); 68 | } 69 | addLabels(); 70 | addDays(cellDate); 71 | } 72 | 73 | private void addDays(DateTime cellDate) { 74 | for (int r = Utils.dayLabelExtraRow(); r < rows + (Utils.dayLabelExtraRow()); r++) { 75 | for (int c = 0; c < Config.COLUMNS; c++) { 76 | DayCellView dayCellView = new DayCellView(getContext()); 77 | 78 | GridLayout.LayoutParams cellParams = new GridLayout.LayoutParams(GridLayout.spec(r), GridLayout.spec(c)); 79 | cellParams.height = Config.cellHeight; 80 | cellParams.width = Config.cellWidth; 81 | dayCellView.setTag(cellDate); 82 | dayCellView.setLayoutParams(cellParams); 83 | dayCellView.setDayNumber(cellDate.getDayOfMonth()); 84 | dayCellView.setDayType(Utils.isWeekendByColumnNumber(c) ? BaseCellView.DayType.WEEKEND : BaseCellView.DayType.NO_WEEKEND); 85 | dayCellView.setMark(Marks.getMark(cellDate), Config.cellHeight); 86 | dayCellView.setOnClickListener(this); 87 | 88 | if (viewPagerType == Config.ViewPagerType.MONTH) { 89 | dayCellView.setTimeType(getTimeType(cellDate)); 90 | } 91 | 92 | gridLayout.addView(dayCellView); 93 | 94 | cellDate = cellDate.plusDays(1); 95 | } 96 | } 97 | } 98 | 99 | private void addLabels() { 100 | if (Config.USE_DAY_LABELS) { 101 | for (int l = 0; l < Config.COLUMNS; l++) { 102 | LabelCellView label = new LabelCellView(getContext()); 103 | 104 | GridLayout.LayoutParams labelParams = new GridLayout.LayoutParams(GridLayout.spec(0), GridLayout.spec(l)); 105 | labelParams.height = Config.cellHeight; 106 | labelParams.width = Config.cellWidth; 107 | label.setLayoutParams(labelParams); 108 | label.setText(Constants.NAME_OF_DAYS[(l + 1 + Utils.firstDayOffset()) % 7]); 109 | label.setDayType(Utils.isWeekendByColumnNumber(l) ? BaseCellView.DayType.WEEKEND : BaseCellView.DayType.NO_WEEKEND); 110 | 111 | gridLayout.addView(label); 112 | 113 | } 114 | } 115 | } 116 | 117 | private DayCellView.TimeType getTimeType(DateTime cellTime) { 118 | if (cellTime.getMonthOfYear() < pageDate.getMonthOfYear()) { 119 | return DayCellView.TimeType.PAST; 120 | } else if (cellTime.getMonthOfYear() > pageDate.getMonthOfYear()) { 121 | return DayCellView.TimeType.FUTURE; 122 | } else { 123 | return DayCellView.TimeType.CURRENT; 124 | } 125 | } 126 | 127 | public void updateMarks() { 128 | for (int c = Utils.dayLabelExtraChildCount(); c < gridLayout.getChildCount(); c++) { 129 | DayCellView dayCellView = (DayCellView) gridLayout.getChildAt(c); 130 | dayCellView.setMarkSetup(Marks.getMark((DateTime) dayCellView.getTag())); 131 | } 132 | } 133 | 134 | @Override 135 | public void onClick(View view) { 136 | if (pageViewListener != null) { 137 | pageViewListener.onDayClick((DateTime) view.getTag()); 138 | } 139 | } 140 | 141 | public interface PageViewListener { 142 | void onDayClick(DateTime dateTime); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/drawable/mark_custom1.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/drawable/mark_custom2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/drawable/mark_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/drawable/mark_today.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/layout/animate_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/layout/day_cell_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /horizontalexpcalendar/src/main/res/layout/horizontal_exp_calendar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 24 | 25 |