├── .gitignore ├── README.md ├── build.gradle ├── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── azurechen │ │ └── fcalendar │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── azurechen │ │ └── fcalendar │ │ ├── data │ │ ├── CalendarAdapter.java │ │ ├── Day.java │ │ └── Event.java │ │ ├── view │ │ └── LockScrollView.java │ │ └── widget │ │ ├── FlexibleCalendar.java │ │ └── UICalendar.java │ └── res │ ├── drawable-hdpi │ ├── ic_navigate_before_black.png │ ├── ic_navigate_before_white.png │ ├── ic_navigate_next_black.png │ └── ic_navigate_next_white.png │ ├── drawable-mdpi │ ├── ic_navigate_before_black.png │ ├── ic_navigate_before_white.png │ ├── ic_navigate_next_black.png │ └── ic_navigate_next_white.png │ ├── drawable-xhdpi │ ├── ic_navigate_before_black.png │ ├── ic_navigate_before_white.png │ ├── ic_navigate_next_black.png │ └── ic_navigate_next_white.png │ ├── drawable-xxhdpi │ ├── ic_navigate_before_black.png │ ├── ic_navigate_before_white.png │ ├── ic_navigate_next_black.png │ ├── ic_navigate_next_white.png │ └── icon_flash_white.png │ ├── drawable-xxxhdpi │ ├── ic_navigate_before_black.png │ ├── ic_navigate_before_white.png │ ├── ic_navigate_next_black.png │ └── ic_navigate_next_white.png │ ├── drawable │ ├── circle_black_solid_background.xml │ ├── circle_black_stroke_background.xml │ ├── circle_white_solid_background.xml │ └── circle_white_stroke_background.xml │ ├── layout │ ├── layout_day.xml │ ├── layout_day_of_week.xml │ └── widget_flexible_calendar.xml │ └── values │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── azurechen │ │ └── fcalendarsample │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── azurechen │ │ └── fcalendarsample │ │ └── 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 │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | */build 8 | *.iml 9 | /.idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Android Flexible Calendar 2 | ========================= 3 | 4 | Flexible Calendar is a pretty light and simple calendar library. Developers can add a basic calendar with a custom style and attributes to their app easily. 5 | 6 | The most special feature is that you can toggle the calendar between collapsed or expanded state with smooth animation, therefore developer can use the space of screen more efficiently. 7 | 8 | 9 | Demo 10 | ------- 11 | Demo 12 | 13 | Usage 14 | ----- 15 | 16 | ###View 17 | 18 | First, set a namespace like "custom" in your root view. 19 | 20 | ```xml 21 | 35 | ``` 36 | 37 | Finally, set the adapter of calendar, and you can bind events and call some methods later. 38 | 39 | ```java 40 | FlexibleCalendar viewCalendar = (FlexibleCalendar) findViewById(R.id.calendar); 41 | Calendar cal = Calendar.getInstance(); 42 | CalendarAdapter adapter = new CalendarAdapter(this, cal); 43 | viewCalendar.setAdapter(adapter); 44 | ``` 45 | 46 | ###Themes 47 | 48 | There are five default themes with different colors, but you are definitely able to set attributes like colors by yourself. 49 | 50 | ###Attributes 51 | 52 | The following is some attributes: 53 | 54 | ```xml 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | ``` 80 | And this is a sample about all attributes you can set: 81 | 82 | ```xml 83 | 98 | ``` 99 | 100 | ###Methods 101 | 102 | ```java 103 | // UI getters and setters 104 | int getStyle() 105 | void setStyle(int style) 106 | boolean isShowWeek() 107 | void setShowWeek(boolean showWeek) 108 | int getFirstDayOfWeek() 109 | void setFirstDayOfWeek(int firstDayOfWeek) 110 | int getState() 111 | void setState(int state) 112 | int getTextColor() 113 | void setTextColor(int textColor) 114 | int getPrimaryColor() 115 | void setPrimaryColor(int primaryColor) 116 | int getTodayItemTextColor() 117 | void setTodayItemTextColor(int todayItemTextColor) 118 | Drawable getTodayItemBackgroundDrawable() 119 | void setTodayItemBackgroundDrawable(Drawable todayItemBackgroundDrawable) 120 | int getSelectedItemTextColor() 121 | void setSelectedItemTextColor(int selectedItemTextColor) 122 | Drawable getSelectedItemBackgroundDrawable() 123 | void setSelectedItemBackgroundDrawable(Drawable selectedItemBackground) 124 | Drawable getButtonLeftDrawable() 125 | void setButtonLeftDrawable(Drawable buttonLeftDrawable) 126 | Drawable getButtonRightDrawable() 127 | void setButtonRightDrawable(Drawable buttonRightDrawable) 128 | //Day getSelectedItem() 129 | //void setSelectedItem(Day selectedItem) 130 | 131 | // Calendar control methods 132 | void setAdapter(CalendarAdapter adapter) 133 | void addEventTag(int numYear, int numMonth, int numDay) 134 | void prevMonth() 135 | void nextMonth() 136 | void prevWeek() 137 | void nextWeek() 138 | int getYear() 139 | int getMonth() 140 | Day getSelectedDay() 141 | boolean isSelectedDay(Day day) 142 | boolean isToady(Day day) 143 | int getSelectedItemPosition() 144 | int getTodayItemPosition() 145 | void collapse(int duration) 146 | void expand(int duration) 147 | void select(Day day) 148 | void setStateWithUpdateUI(int state) 149 | void setCalendarListener(CalendarListener listener) 150 | ``` 151 | 152 | ###Events 153 | 154 | There are some events will be triggered on specific state: 155 | 156 | ```java 157 | // triggered when a day is selected programmatically or clicked by user. 158 | void onDaySelect(); 159 | 160 | // triggered only when the views of day on calendar are clicked by user. 161 | void onItemClick(View v); 162 | 163 | // triggered when the data of calendar are updated by changing month or adding events. 164 | void onDataUpdate(); 165 | 166 | // triggered when the month are changed. 167 | void onMonthChange(); 168 | 169 | // triggered when the week position are changed. 170 | void onWeekChange(int position); 171 | ``` 172 | 173 | In order to listen these events, you should register a CalendarListener first, like the following example: 174 | 175 | ```java 176 | viewCalendar.setCalendarListener(new FlexibleCalendar.CalendarListener() { 177 | @Override 178 | public void onDaySelect() { 179 | Day day = viewCalendar.getSelectedDay(); 180 | Log.i(getClass().getName(), "Selected Day: " 181 | + day.getYear() + "/" + (day.getMonth() + 1) + "/" + day.getDay()); 182 | } 183 | 184 | @Override 185 | public void onItemClick(View v) { 186 | Day day = viewCalendar.getSelectedDay(); 187 | Log.i(getClass().getName(), "The Day of Clicked View: " 188 | + day.getYear() + "/" + (day.getMonth() + 1) + "/" + day.getDay()); 189 | } 190 | 191 | @Override 192 | public void onDataUpdate() { 193 | Log.i(getClass().getName(), "Data Updated"); 194 | } 195 | 196 | @Override 197 | public void onMonthChange() { 198 | Log.i(getClass().getName(), "Month Changed" 199 | + ". Current Year: " + viewCalendar.getYear() 200 | + ", Current Month: " + (viewCalendar.getMonth() + 1)); 201 | } 202 | 203 | @Override 204 | public void onWeekChange(int position) { 205 | Log.i(getClass().getName(), "Week Changed" 206 | + ". Current Year: " + viewCalendar.getYear() 207 | + ", Current Month: " + (viewCalendar.getMonth() + 1) 208 | + ", Current Week position of Month: " + position); 209 | } 210 | }); 211 | ``` -------------------------------------------------------------------------------- /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:1.3.0' 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 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/demo.gif -------------------------------------------------------------------------------- /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/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 10 15:27:10 PDT 2013 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.2.1-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 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 22 10 | versionCode 1 11 | versionName "1.0" 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:22.2.0' 24 | } 25 | -------------------------------------------------------------------------------- /library/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 /home/azurechen/Applications/android-sdk-linux/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 | -------------------------------------------------------------------------------- /library/src/androidTest/java/com/azurechen/fcalendar/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/data/CalendarAdapter.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.data; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | import android.widget.TextView; 8 | 9 | import com.azurechen.fcalendar.R; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Calendar; 13 | 14 | public class CalendarAdapter { 15 | 16 | private int mFirstDayOfWeek = 0; 17 | private Calendar mCal; 18 | private LayoutInflater mInflater; 19 | 20 | ArrayList mItemList = new ArrayList<>(); 21 | ArrayList mViewList = new ArrayList<>(); 22 | ArrayList mEventList = new ArrayList<>(); 23 | 24 | public CalendarAdapter(Context context, Calendar cal) { 25 | this.mCal = (Calendar) cal.clone(); 26 | this.mCal.set(Calendar.DAY_OF_MONTH, 1); 27 | 28 | mInflater = LayoutInflater.from(context); 29 | 30 | refresh(); 31 | } 32 | 33 | // public methods 34 | public int getCount() { 35 | return mItemList.size(); 36 | } 37 | 38 | public Day getItem(int position) { 39 | return mItemList.get(position); 40 | } 41 | 42 | public View getView(final int position) { 43 | return mViewList.get(position); 44 | } 45 | 46 | public void setFirstDayOfWeek(int firstDayOfWeek) { 47 | mFirstDayOfWeek = firstDayOfWeek; 48 | } 49 | 50 | public Calendar getCalendar() { 51 | return mCal; 52 | } 53 | 54 | public void addEvent(Event event) { 55 | mEventList.add(event); 56 | } 57 | 58 | public void refresh() { 59 | // clear data 60 | mItemList.clear(); 61 | mViewList.clear(); 62 | 63 | // set calendar 64 | int year = mCal.get(Calendar.YEAR); 65 | int month = mCal.get(Calendar.MONTH); 66 | 67 | mCal.set(year, month, 1); 68 | 69 | int lastDayOfMonth = mCal.getActualMaximum(Calendar.DAY_OF_MONTH); 70 | int firstDayOfWeek = mCal.get(Calendar.DAY_OF_WEEK) - 1; 71 | 72 | // generate day list 73 | int offset = 0 - (firstDayOfWeek - mFirstDayOfWeek) + 1; 74 | int length = (int) Math.ceil((float) (lastDayOfMonth - offset + 1) / 7) * 7; 75 | for (int i = offset; i < length + offset; i++) { 76 | int numYear; 77 | int numMonth; 78 | int numDay; 79 | 80 | Calendar tempCal = Calendar.getInstance(); 81 | if (i <= 0) { // prev month 82 | if (month == 0) { 83 | numYear = year - 1; 84 | numMonth = 11; 85 | } else { 86 | numYear = year; 87 | numMonth = month - 1; 88 | } 89 | tempCal.set(numYear, numMonth, 1); 90 | numDay = tempCal.getActualMaximum(Calendar.DAY_OF_MONTH) + i; 91 | } else if (i > lastDayOfMonth) { // next month 92 | if (month == 11) { 93 | numYear = year + 1; 94 | numMonth = 0; 95 | } else { 96 | numYear = year; 97 | numMonth = month + 1; 98 | } 99 | tempCal.set(numYear, numMonth, 1); 100 | numDay = i - lastDayOfMonth; 101 | } else { 102 | numYear = year; 103 | numMonth = month; 104 | numDay = i; 105 | } 106 | 107 | Day day = new Day(numYear, numMonth, numDay); 108 | 109 | View view = mInflater.inflate(R.layout.layout_day, null); 110 | TextView txtDay = (TextView) view.findViewById(R.id.txt_day); 111 | ImageView imgEventTag = (ImageView) view.findViewById(R.id.img_event_tag); 112 | 113 | txtDay.setText(String.valueOf(day.getDay())); 114 | if (day.getMonth() != mCal.get(Calendar.MONTH)) { 115 | txtDay.setAlpha(0.3f); 116 | } 117 | 118 | for (int j = 0; j < mEventList.size(); j++) { 119 | Event event = mEventList.get(j); 120 | if (day.getYear() == event.getYear() 121 | && day.getMonth() == event.getMonth() 122 | && day.getDay() == event.getDay()) { 123 | imgEventTag.setVisibility(View.VISIBLE); 124 | } 125 | } 126 | 127 | mItemList.add(day); 128 | mViewList.add(view); 129 | } 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/data/Day.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.data; 2 | 3 | public class Day { 4 | 5 | private int mYear; 6 | private int mMonth; 7 | private int mDay; 8 | 9 | public Day(int year, int month, int day){ 10 | this.mYear = year; 11 | this.mMonth = month; 12 | this.mDay = day; 13 | } 14 | 15 | public int getMonth(){ 16 | return mMonth; 17 | } 18 | 19 | public int getYear(){ 20 | return mYear; 21 | } 22 | 23 | public int getDay(){ 24 | return mDay; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/data/Event.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.data; 2 | 3 | public class Event { 4 | 5 | private int mYear; 6 | private int mMonth; 7 | private int mDay; 8 | 9 | public Event(int year, int month, int day){ 10 | this.mYear = year; 11 | this.mMonth = month; 12 | this.mDay = day; 13 | } 14 | 15 | public int getMonth(){ 16 | return mMonth; 17 | } 18 | 19 | public int getYear(){ 20 | return mYear; 21 | } 22 | 23 | public int getDay(){ 24 | return mDay; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/view/LockScrollView.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | import android.widget.ScrollView; 7 | 8 | /** 9 | * Created by azurechen on 7/31/15. 10 | */ 11 | public class LockScrollView extends ScrollView { 12 | public LockScrollView(Context context) { 13 | super(context); 14 | } 15 | 16 | public LockScrollView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public LockScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | } 23 | 24 | @Override 25 | public boolean onInterceptTouchEvent(MotionEvent ev) { 26 | return false; 27 | } 28 | @Override 29 | public boolean onTouchEvent(MotionEvent ev) { 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/widget/FlexibleCalendar.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Handler; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.animation.Animation; 10 | import android.view.animation.Transformation; 11 | import android.widget.LinearLayout; 12 | import android.widget.TableLayout; 13 | import android.widget.TableRow; 14 | import android.widget.TextView; 15 | 16 | import com.azurechen.fcalendar.R; 17 | import com.azurechen.fcalendar.data.CalendarAdapter; 18 | import com.azurechen.fcalendar.data.Day; 19 | import com.azurechen.fcalendar.data.Event; 20 | 21 | import java.text.SimpleDateFormat; 22 | import java.util.Calendar; 23 | 24 | /** 25 | * Created by azurechen on 7/29/15. 26 | */ 27 | public class FlexibleCalendar extends UICalendar { 28 | 29 | private CalendarAdapter mAdapter; 30 | private CalendarListener mListener; 31 | 32 | private int mInitHeight = 0; 33 | 34 | private Handler mHandler = new Handler(); 35 | private boolean mIsWaitingForUpdate = false; 36 | 37 | private int mCurrentWeekIndex; 38 | 39 | public FlexibleCalendar(Context context) { 40 | super(context); 41 | } 42 | 43 | public FlexibleCalendar(Context context, AttributeSet attrs) { 44 | super(context, attrs); 45 | } 46 | 47 | public FlexibleCalendar(Context context, AttributeSet attrs, int defStyleAttr) { 48 | super(context, attrs, defStyleAttr); 49 | } 50 | 51 | @Override 52 | protected void init(Context context) { 53 | super.init(context); 54 | 55 | if (isInEditMode()) { 56 | Calendar cal = Calendar.getInstance(); 57 | CalendarAdapter adapter = new CalendarAdapter(context, cal); 58 | setAdapter(adapter); 59 | } 60 | 61 | setStateWithUpdateUI(getState()); 62 | 63 | // bind events 64 | mBtnPrevMonth.setOnClickListener(new OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | prevMonth(); 68 | } 69 | }); 70 | 71 | mBtnNextMonth.setOnClickListener(new OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | nextMonth(); 75 | } 76 | }); 77 | 78 | mBtnPrevWeek.setOnClickListener(new OnClickListener() { 79 | @Override 80 | public void onClick(View v) { 81 | prevWeek(); 82 | } 83 | }); 84 | 85 | mBtnNextWeek.setOnClickListener(new OnClickListener() { 86 | @Override 87 | public void onClick(View v) { 88 | nextWeek(); 89 | } 90 | }); 91 | } 92 | 93 | @Override 94 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 95 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 96 | 97 | mInitHeight = mTableBody.getMeasuredHeight(); 98 | 99 | if (mIsWaitingForUpdate) { 100 | redraw(); 101 | mHandler.post(new Runnable() { 102 | @Override 103 | public void run() { 104 | collapseTo(mCurrentWeekIndex); 105 | } 106 | }); 107 | mIsWaitingForUpdate = false; 108 | if (mListener != null) { 109 | mListener.onDataUpdate(); 110 | } 111 | } 112 | } 113 | 114 | @Override 115 | protected void redraw() { 116 | // redraw all views of week 117 | TableRow rowWeek = (TableRow) mTableHead.getChildAt(0); 118 | if (rowWeek != null) { 119 | for (int i = 0; i < rowWeek.getChildCount(); i++) { 120 | ((TextView) rowWeek.getChildAt(i)).setTextColor(getTextColor()); 121 | } 122 | } 123 | // redraw all views of day 124 | if (mAdapter != null) { 125 | for (int i = 0; i < mAdapter.getCount(); i++) { 126 | Day day = mAdapter.getItem(i); 127 | View view = mAdapter.getView(i); 128 | TextView txtDay = (TextView) view.findViewById(R.id.txt_day); 129 | txtDay.setBackgroundColor(Color.TRANSPARENT); 130 | txtDay.setTextColor(getTextColor()); 131 | 132 | // set today's item 133 | if (isToady(day)) { 134 | txtDay.setBackgroundDrawable(getTodayItemBackgroundDrawable()); 135 | txtDay.setTextColor(getTodayItemTextColor()); 136 | } 137 | 138 | // set the selected item 139 | if (isSelectedDay(day)) { 140 | txtDay.setBackgroundDrawable(getSelectedItemBackgroundDrawable()); 141 | txtDay.setTextColor(getSelectedItemTextColor()); 142 | } 143 | } 144 | } 145 | } 146 | 147 | @Override 148 | protected void reload() { 149 | if (mAdapter != null) { 150 | mAdapter.refresh(); 151 | 152 | // reset UI 153 | SimpleDateFormat dateFormat = new SimpleDateFormat("MMM yyyy"); 154 | dateFormat.setTimeZone(mAdapter.getCalendar().getTimeZone()); 155 | mTxtTitle.setText(dateFormat.format(mAdapter.getCalendar().getTime())); 156 | mTableHead.removeAllViews(); 157 | mTableBody.removeAllViews(); 158 | 159 | TableRow rowCurrent; 160 | 161 | // set day of week 162 | int[] dayOfWeekIds = { 163 | R.string.sunday, 164 | R.string.monday, 165 | R.string.tuesday, 166 | R.string.wednesday, 167 | R.string.thursday, 168 | R.string.friday, 169 | R.string.saturday 170 | }; 171 | rowCurrent = new TableRow(mContext); 172 | rowCurrent.setLayoutParams(new TableLayout.LayoutParams( 173 | ViewGroup.LayoutParams.MATCH_PARENT, 174 | ViewGroup.LayoutParams.WRAP_CONTENT)); 175 | for (int i = 0; i < 7; i++) { 176 | View view = mInflater.inflate(R.layout.layout_day_of_week, null); 177 | TextView txtDayOfWeek = (TextView) view.findViewById(R.id.txt_day_of_week); 178 | txtDayOfWeek.setText(dayOfWeekIds[(i + getFirstDayOfWeek()) % 7]); 179 | view.setLayoutParams(new TableRow.LayoutParams( 180 | 0, 181 | ViewGroup.LayoutParams.WRAP_CONTENT, 182 | 1)); 183 | rowCurrent.addView(view); 184 | } 185 | mTableHead.addView(rowCurrent); 186 | 187 | // set day view 188 | for (int i = 0; i < mAdapter.getCount(); i++) { 189 | final int position = i; 190 | 191 | if (position % 7 == 0) { 192 | rowCurrent = new TableRow(mContext); 193 | rowCurrent.setLayoutParams(new TableLayout.LayoutParams( 194 | ViewGroup.LayoutParams.MATCH_PARENT, 195 | ViewGroup.LayoutParams.WRAP_CONTENT)); 196 | mTableBody.addView(rowCurrent); 197 | } 198 | final View view = mAdapter.getView(position); 199 | view.setLayoutParams(new TableRow.LayoutParams( 200 | 0, 201 | ViewGroup.LayoutParams.WRAP_CONTENT, 202 | 1)); 203 | view.setOnClickListener(new OnClickListener() { 204 | @Override 205 | public void onClick(View v) { 206 | onItemClicked(v, mAdapter.getItem(position)); 207 | } 208 | }); 209 | rowCurrent.addView(view); 210 | } 211 | 212 | redraw(); 213 | mIsWaitingForUpdate = true; 214 | } 215 | } 216 | 217 | private int getSuitableRowIndex() { 218 | if (getSelectedItemPosition() != -1) { 219 | View view = mAdapter.getView(getSelectedItemPosition()); 220 | TableRow row = (TableRow) view.getParent(); 221 | 222 | return mTableBody.indexOfChild(row); 223 | } else if (getTodayItemPosition() != -1) { 224 | View view = mAdapter.getView(getTodayItemPosition()); 225 | TableRow row = (TableRow) view.getParent(); 226 | 227 | return mTableBody.indexOfChild(row); 228 | } else { 229 | return 0; 230 | } 231 | } 232 | 233 | private void onItemClicked(View view, Day day) { 234 | select(day); 235 | 236 | Calendar cal = mAdapter.getCalendar(); 237 | 238 | int newYear = day.getYear(); 239 | int newMonth = day.getMonth(); 240 | int oldYear = cal.get(Calendar.YEAR); 241 | int oldMonth = cal.get(Calendar.MONTH); 242 | if (newMonth != oldMonth) { 243 | cal.set(day.getYear(), day.getMonth(), 1); 244 | 245 | if (newYear > oldYear || newMonth > oldMonth) { 246 | mCurrentWeekIndex = 0; 247 | } 248 | if (newYear < oldYear || newMonth < oldMonth) { 249 | mCurrentWeekIndex = -1; 250 | } 251 | if (mListener != null) { 252 | mListener.onMonthChange(); 253 | } 254 | reload(); 255 | } 256 | 257 | if (mListener != null) { 258 | mListener.onItemClick(view); 259 | } 260 | } 261 | 262 | // public methods 263 | public void setAdapter(CalendarAdapter adapter) { 264 | mAdapter = adapter; 265 | adapter.setFirstDayOfWeek(getFirstDayOfWeek()); 266 | 267 | reload(); 268 | 269 | // init week 270 | mCurrentWeekIndex = getSuitableRowIndex(); 271 | } 272 | 273 | public void addEventTag(int numYear, int numMonth, int numDay) { 274 | mAdapter.addEvent(new Event(numYear, numMonth, numDay)); 275 | 276 | reload(); 277 | } 278 | 279 | public void prevMonth() { 280 | Calendar cal = mAdapter.getCalendar(); 281 | if (cal.get(Calendar.MONTH) == cal.getActualMinimum(Calendar.MONTH)) { 282 | cal.set((cal.get(Calendar.YEAR) - 1), cal.getActualMaximum(Calendar.MONTH), 1); 283 | } else { 284 | cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) - 1); 285 | } 286 | reload(); 287 | if (mListener != null) { 288 | mListener.onMonthChange(); 289 | } 290 | } 291 | 292 | public void nextMonth() { 293 | Calendar cal = mAdapter.getCalendar(); 294 | if (cal.get(Calendar.MONTH) == cal.getActualMaximum(Calendar.MONTH)) { 295 | cal.set((cal.get(Calendar.YEAR) + 1), cal.getActualMinimum(Calendar.MONTH), 1); 296 | } else { 297 | cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1); 298 | } 299 | reload(); 300 | if (mListener != null) { 301 | mListener.onMonthChange(); 302 | } 303 | } 304 | 305 | public void prevWeek() { 306 | if (mCurrentWeekIndex - 1 < 0) { 307 | mCurrentWeekIndex = -1; 308 | prevMonth(); 309 | } else { 310 | mCurrentWeekIndex--; 311 | collapseTo(mCurrentWeekIndex); 312 | } 313 | } 314 | 315 | public void nextWeek() { 316 | if (mCurrentWeekIndex + 1 >= mTableBody.getChildCount()) { 317 | mCurrentWeekIndex = 0; 318 | nextMonth(); 319 | } else { 320 | mCurrentWeekIndex++; 321 | collapseTo(mCurrentWeekIndex); 322 | } 323 | } 324 | 325 | public int getYear() { 326 | return mAdapter.getCalendar().get(Calendar.YEAR); 327 | } 328 | 329 | public int getMonth() { 330 | return mAdapter.getCalendar().get(Calendar.MONTH); 331 | } 332 | 333 | public Day getSelectedDay() { 334 | return new Day( 335 | getSelectedItem().getYear(), 336 | getSelectedItem().getMonth(), 337 | getSelectedItem().getDay()); 338 | } 339 | 340 | public boolean isSelectedDay(Day day) { 341 | return day != null 342 | && getSelectedItem() != null 343 | && day.getYear() == getSelectedItem().getYear() 344 | && day.getMonth() == getSelectedItem().getMonth() 345 | && day.getDay() == getSelectedItem().getDay(); 346 | } 347 | 348 | public boolean isToady(Day day) { 349 | Calendar todayCal = Calendar.getInstance(); 350 | return day != null 351 | && day.getYear() == todayCal.get(Calendar.YEAR) 352 | && day.getMonth() == todayCal.get(Calendar.MONTH) 353 | && day.getDay() == todayCal.get(Calendar.DAY_OF_MONTH); 354 | } 355 | 356 | public int getSelectedItemPosition() { 357 | int position = -1; 358 | for (int i = 0; i < mAdapter.getCount(); i++) { 359 | Day day = mAdapter.getItem(i); 360 | 361 | if (isSelectedDay(day)) { 362 | position = i; 363 | break; 364 | } 365 | } 366 | return position; 367 | } 368 | 369 | public int getTodayItemPosition() { 370 | int position = -1; 371 | for (int i = 0; i < mAdapter.getCount(); i++) { 372 | Day day = mAdapter.getItem(i); 373 | 374 | if (isToady(day)) { 375 | position = i; 376 | break; 377 | } 378 | } 379 | return position; 380 | } 381 | 382 | public void collapse(int duration) { 383 | if (getState() == STATE_EXPANDED) { 384 | setState(STATE_PROCESSING); 385 | 386 | mLayoutBtnGroupMonth.setVisibility(GONE); 387 | mLayoutBtnGroupWeek.setVisibility(VISIBLE); 388 | mBtnPrevWeek.setClickable(false); 389 | mBtnNextWeek.setClickable(false); 390 | 391 | int index = getSuitableRowIndex(); 392 | mCurrentWeekIndex = index; 393 | 394 | final int currentHeight = mInitHeight; 395 | final int targetHeight = mTableBody.getChildAt(index).getMeasuredHeight(); 396 | int tempHeight = 0; 397 | for (int i = 0; i < index; i++) { 398 | tempHeight += mTableBody.getChildAt(i).getMeasuredHeight(); 399 | } 400 | final int topHeight = tempHeight; 401 | 402 | Animation anim = new Animation() { 403 | @Override 404 | protected void applyTransformation(float interpolatedTime, Transformation t) { 405 | 406 | mScrollViewBody.getLayoutParams().height = (interpolatedTime == 1) 407 | ? targetHeight 408 | : currentHeight - (int) ((currentHeight - targetHeight) * interpolatedTime); 409 | mScrollViewBody.requestLayout(); 410 | 411 | if (mScrollViewBody.getMeasuredHeight() < topHeight + targetHeight) { 412 | int position = topHeight + targetHeight - mScrollViewBody.getMeasuredHeight(); 413 | mScrollViewBody.smoothScrollTo(0, position); 414 | } 415 | 416 | if (interpolatedTime == 1) { 417 | setState(STATE_COLLAPSED); 418 | 419 | mBtnPrevWeek.setClickable(true); 420 | mBtnNextWeek.setClickable(true); 421 | } 422 | } 423 | }; 424 | anim.setDuration(duration); 425 | startAnimation(anim); 426 | } 427 | } 428 | 429 | private void collapseTo(int index) { 430 | if (getState() == STATE_COLLAPSED) { 431 | if (index == -1) { 432 | index = mTableBody.getChildCount() - 1; 433 | } 434 | mCurrentWeekIndex = index; 435 | 436 | final int targetHeight = mTableBody.getChildAt(index).getMeasuredHeight(); 437 | int tempHeight = 0; 438 | for (int i = 0; i < index; i++) { 439 | tempHeight += mTableBody.getChildAt(i).getMeasuredHeight(); 440 | } 441 | final int topHeight = tempHeight; 442 | 443 | mScrollViewBody.getLayoutParams().height = targetHeight; 444 | mScrollViewBody.requestLayout(); 445 | 446 | mHandler.post(new Runnable() { 447 | @Override 448 | public void run() { 449 | mScrollViewBody.smoothScrollTo(0, topHeight); 450 | } 451 | }); 452 | 453 | 454 | if (mListener != null) { 455 | mListener.onWeekChange(mCurrentWeekIndex); 456 | } 457 | } 458 | } 459 | 460 | public void expand(int duration) { 461 | if (getState() == STATE_COLLAPSED) { 462 | setState(STATE_PROCESSING); 463 | 464 | mLayoutBtnGroupMonth.setVisibility(VISIBLE); 465 | mLayoutBtnGroupWeek.setVisibility(GONE); 466 | mBtnPrevMonth.setClickable(false); 467 | mBtnNextMonth.setClickable(false); 468 | 469 | final int currentHeight = mScrollViewBody.getMeasuredHeight(); 470 | final int targetHeight = mInitHeight; 471 | 472 | Animation anim = new Animation() { 473 | @Override 474 | protected void applyTransformation(float interpolatedTime, Transformation t) { 475 | 476 | mScrollViewBody.getLayoutParams().height = (interpolatedTime == 1) 477 | ? LinearLayout.LayoutParams.WRAP_CONTENT 478 | : currentHeight - (int) ((currentHeight - targetHeight) * interpolatedTime); 479 | mScrollViewBody.requestLayout(); 480 | 481 | if (interpolatedTime == 1) { 482 | setState(STATE_EXPANDED); 483 | 484 | mBtnPrevMonth.setClickable(true); 485 | mBtnNextMonth.setClickable(true); 486 | } 487 | } 488 | }; 489 | anim.setDuration(duration); 490 | startAnimation(anim); 491 | } 492 | } 493 | 494 | public void select(Day day) { 495 | setSelectedItem(new Day(day.getYear(), day.getMonth(), day.getDay())); 496 | redraw(); 497 | 498 | if (mListener != null) { 499 | mListener.onDaySelect(); 500 | } 501 | } 502 | 503 | public void setStateWithUpdateUI(int state) { 504 | setState(state); 505 | 506 | if (getState() != state) { 507 | mIsWaitingForUpdate = true; 508 | requestLayout(); 509 | } 510 | } 511 | 512 | // callback 513 | public void setCalendarListener(CalendarListener listener) { 514 | mListener = listener; 515 | } 516 | 517 | public interface CalendarListener { 518 | 519 | // triggered when a day is selected programmatically or clicked by user. 520 | void onDaySelect(); 521 | 522 | // triggered only when the views of day on calendar are clicked by user. 523 | void onItemClick(View v); 524 | 525 | // triggered when the data of calendar are updated by changing month or adding events. 526 | void onDataUpdate(); 527 | 528 | // triggered when the month are changed. 529 | void onMonthChange(); 530 | 531 | // triggered when the week position are changed. 532 | void onWeekChange(int position); 533 | } 534 | } 535 | -------------------------------------------------------------------------------- /library/src/main/java/com/azurechen/fcalendar/widget/UICalendar.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendar.widget; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.Drawable; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.ImageButton; 11 | import android.widget.LinearLayout; 12 | import android.widget.RelativeLayout; 13 | import android.widget.TableLayout; 14 | import android.widget.TextView; 15 | 16 | import com.azurechen.fcalendar.R; 17 | import com.azurechen.fcalendar.data.Day; 18 | import com.azurechen.fcalendar.view.LockScrollView; 19 | 20 | /** 21 | * Created by AzureChen on 15/8/9. 22 | */ 23 | public abstract class UICalendar extends LinearLayout { 24 | 25 | // Style 26 | public static final int STYLE_LIGHT = 0; 27 | public static final int STYLE_PINK = 1; 28 | public static final int STYLE_ORANGE = 2; 29 | public static final int STYLE_BLUE = 3; 30 | public static final int STYLE_GREEN = 4; 31 | // Day of Week 32 | public static final int SUNDAY = 0; 33 | public static final int MONDAY = 1; 34 | public static final int TUESDAY = 2; 35 | public static final int WEDNESDAY = 3; 36 | public static final int THURSDAY = 4; 37 | public static final int FRIDAY = 5; 38 | public static final int SATURDAY = 6; 39 | // State 40 | public static final int STATE_EXPANDED = 0; 41 | public static final int STATE_COLLAPSED = 1; 42 | public static final int STATE_PROCESSING = 2; 43 | 44 | protected Context mContext; 45 | protected LayoutInflater mInflater; 46 | 47 | // UI 48 | protected LinearLayout mLayoutRoot; 49 | protected TextView mTxtTitle; 50 | protected TableLayout mTableHead; 51 | protected LockScrollView mScrollViewBody; 52 | protected TableLayout mTableBody; 53 | protected RelativeLayout mLayoutBtnGroupMonth; 54 | protected RelativeLayout mLayoutBtnGroupWeek; 55 | protected ImageButton mBtnPrevMonth; 56 | protected ImageButton mBtnNextMonth; 57 | protected ImageButton mBtnPrevWeek; 58 | protected ImageButton mBtnNextWeek; 59 | 60 | // Attributes 61 | private int mStyle = STYLE_LIGHT; 62 | private boolean mShowWeek = true; 63 | private int mFirstDayOfWeek = SUNDAY; 64 | private int mState = STATE_EXPANDED; 65 | 66 | private int mTextColor = Color.BLACK; 67 | private int mPrimaryColor = Color.WHITE; 68 | 69 | private int mTodayItemTextColor = Color.BLACK; 70 | private Drawable mTodayItemBackgroundDrawable = 71 | getResources().getDrawable(R.drawable.circle_black_stroke_background); 72 | private int mSelectedItemTextColor = Color.WHITE; 73 | private Drawable mSelectedItemBackgroundDrawable = 74 | getResources().getDrawable(R.drawable.circle_black_solid_background); 75 | 76 | private Drawable mButtonLeftDrawable = 77 | getResources().getDrawable(R.drawable.ic_navigate_before_black); 78 | private Drawable mButtonRightDrawable = 79 | getResources().getDrawable(R.drawable.ic_navigate_next_black); 80 | 81 | private Day mSelectedItem = null; 82 | 83 | public UICalendar(Context context) { 84 | this(context, null); 85 | } 86 | 87 | public UICalendar(Context context, AttributeSet attrs) { 88 | this(context, attrs, 0); 89 | } 90 | 91 | public UICalendar(Context context, AttributeSet attrs, int defStyleAttr) { 92 | super(context, attrs, defStyleAttr); 93 | 94 | init(context); 95 | TypedArray attributes = context.getTheme().obtainStyledAttributes( 96 | attrs, R.styleable.UICalendar, defStyleAttr, 0); 97 | setAttributes(attributes); 98 | attributes.recycle(); 99 | } 100 | 101 | protected abstract void redraw(); 102 | protected abstract void reload(); 103 | 104 | protected void init(Context context) { 105 | mContext = context; 106 | mInflater = LayoutInflater.from(mContext); 107 | 108 | // load rootView from xml 109 | View rootView = mInflater.inflate(R.layout.widget_flexible_calendar, this, true); 110 | 111 | // init UI 112 | mLayoutRoot = (LinearLayout) rootView.findViewById(R.id.layout_root); 113 | mTxtTitle = (TextView) rootView.findViewById(R.id.txt_title); 114 | mTableHead = (TableLayout) rootView.findViewById(R.id.table_head); 115 | mScrollViewBody = (LockScrollView) rootView.findViewById(R.id.scroll_view_body); 116 | mTableBody = (TableLayout) rootView.findViewById(R.id.table_body); 117 | mLayoutBtnGroupMonth = (RelativeLayout) rootView.findViewById(R.id.layout_btn_group_month); 118 | mLayoutBtnGroupWeek = (RelativeLayout) rootView.findViewById(R.id.layout_btn_group_week); 119 | mBtnPrevMonth = (ImageButton) rootView.findViewById(R.id.btn_prev_month); 120 | mBtnNextMonth = (ImageButton) rootView.findViewById(R.id.btn_next_month); 121 | mBtnPrevWeek = (ImageButton) rootView.findViewById(R.id.btn_prev_week); 122 | mBtnNextWeek = (ImageButton) rootView.findViewById(R.id.btn_next_week); 123 | } 124 | 125 | protected void setAttributes(TypedArray attrs) { 126 | // set attributes by the values from XML 127 | setStyle(attrs.getInt(R.styleable.UICalendar_style, mStyle)); 128 | setShowWeek(attrs.getBoolean(R.styleable.UICalendar_showWeek, mShowWeek)); 129 | setFirstDayOfWeek(attrs.getInt(R.styleable.UICalendar_firstDayOfWeek, mFirstDayOfWeek)); 130 | setState(attrs.getInt(R.styleable.UICalendar_state, mState)); 131 | 132 | setTextColor(attrs.getColor(R.styleable.UICalendar_textColor, mTextColor)); 133 | setPrimaryColor(attrs.getColor(R.styleable.UICalendar_primaryColor, mPrimaryColor)); 134 | 135 | setTodayItemTextColor(attrs.getColor( 136 | R.styleable.UICalendar_todayItem_textColor, mTodayItemTextColor)); 137 | Drawable todayItemBackgroundDrawable = 138 | attrs.getDrawable(R.styleable.UICalendar_todayItem_background); 139 | if (todayItemBackgroundDrawable != null) { 140 | setTodayItemBackgroundDrawable(todayItemBackgroundDrawable); 141 | } else { 142 | setTodayItemBackgroundDrawable(mTodayItemBackgroundDrawable); 143 | } 144 | 145 | setSelectedItemTextColor(attrs.getColor( 146 | R.styleable.UICalendar_selectedItem_textColor, mSelectedItemTextColor)); 147 | Drawable selectedItemBackgroundDrawable = 148 | attrs.getDrawable(R.styleable.UICalendar_selectedItem_background); 149 | if (selectedItemBackgroundDrawable != null) { 150 | setSelectedItemBackgroundDrawable(selectedItemBackgroundDrawable); 151 | } else { 152 | setSelectedItemBackgroundDrawable(mSelectedItemBackgroundDrawable); 153 | } 154 | 155 | Drawable buttonLeftDrawable = 156 | attrs.getDrawable(R.styleable.UICalendar_buttonLeft_drawable); 157 | if (buttonLeftDrawable != null) { 158 | setButtonLeftDrawable(buttonLeftDrawable); 159 | } else { 160 | setButtonLeftDrawable(mButtonLeftDrawable); 161 | } 162 | 163 | Drawable buttonRightDrawable = 164 | attrs.getDrawable(R.styleable.UICalendar_buttonRight_drawable); 165 | if (buttonRightDrawable != null) { 166 | setButtonRightDrawable(buttonRightDrawable); 167 | } else { 168 | setButtonRightDrawable(mButtonRightDrawable); 169 | } 170 | 171 | Day selectedItem = null; 172 | } 173 | 174 | // getters and setters 175 | public int getStyle() { 176 | return mStyle; 177 | } 178 | 179 | public void setStyle(int style) { 180 | this.mStyle = style; 181 | 182 | if (style == STYLE_LIGHT) { 183 | setTextColor(Color.BLACK); 184 | setPrimaryColor(Color.WHITE); 185 | setTodayItemTextColor(Color.BLACK); 186 | setTodayItemBackgroundDrawable( 187 | getResources().getDrawable(R.drawable.circle_black_stroke_background)); 188 | setSelectedItemTextColor(Color.WHITE); 189 | setSelectedItemBackgroundDrawable( 190 | getResources().getDrawable(R.drawable.circle_black_solid_background)); 191 | setButtonLeftDrawable( 192 | getResources().getDrawable(R.drawable.ic_navigate_before_black)); 193 | setButtonRightDrawable( 194 | getResources().getDrawable(R.drawable.ic_navigate_next_black)); 195 | } else { 196 | setTextColor(Color.WHITE); 197 | setTodayItemTextColor(Color.WHITE); 198 | setTodayItemBackgroundDrawable( 199 | getResources().getDrawable(R.drawable.circle_white_stroke_background)); 200 | setSelectedItemBackgroundDrawable( 201 | getResources().getDrawable(R.drawable.circle_white_solid_background)); 202 | setButtonLeftDrawable( 203 | getResources().getDrawable(R.drawable.ic_navigate_before_white)); 204 | setButtonRightDrawable( 205 | getResources().getDrawable(R.drawable.ic_navigate_next_white)); 206 | 207 | int color = 0; 208 | if (style == STYLE_PINK) { 209 | color = mContext.getResources().getColor(R.color.primary_pink); 210 | } 211 | if (style == STYLE_ORANGE) { 212 | color = mContext.getResources().getColor(R.color.primary_orange); 213 | } 214 | if (style == STYLE_BLUE) { 215 | color = mContext.getResources().getColor(R.color.primary_blue); 216 | } 217 | if (style == STYLE_GREEN) { 218 | color = mContext.getResources().getColor(R.color.primary_green); 219 | } 220 | setPrimaryColor(color); 221 | setSelectedItemTextColor(color); 222 | } 223 | } 224 | 225 | public boolean isShowWeek() { 226 | return mShowWeek; 227 | } 228 | 229 | public void setShowWeek(boolean showWeek) { 230 | this.mShowWeek = showWeek; 231 | 232 | if (showWeek) { 233 | mTableHead.setVisibility(VISIBLE); 234 | } else { 235 | mTableHead.setVisibility(GONE); 236 | } 237 | } 238 | 239 | public int getFirstDayOfWeek() { 240 | return mFirstDayOfWeek; 241 | } 242 | 243 | public void setFirstDayOfWeek(int firstDayOfWeek) { 244 | this.mFirstDayOfWeek = firstDayOfWeek; 245 | reload(); 246 | } 247 | 248 | public int getState() { 249 | return mState; 250 | } 251 | 252 | public void setState(int state) { 253 | this.mState = state; 254 | 255 | if (mState == STATE_EXPANDED) { 256 | mLayoutBtnGroupMonth.setVisibility(VISIBLE); 257 | mLayoutBtnGroupWeek.setVisibility(GONE); 258 | } 259 | if (mState == STATE_COLLAPSED) { 260 | mLayoutBtnGroupMonth.setVisibility(GONE); 261 | mLayoutBtnGroupWeek.setVisibility(VISIBLE); 262 | } 263 | } 264 | 265 | public int getTextColor() { 266 | return mTextColor; 267 | } 268 | 269 | public void setTextColor(int textColor) { 270 | this.mTextColor = textColor; 271 | redraw(); 272 | 273 | mTxtTitle.setTextColor(mTextColor); 274 | } 275 | 276 | public int getPrimaryColor() { 277 | return mPrimaryColor; 278 | } 279 | 280 | public void setPrimaryColor(int primaryColor) { 281 | this.mPrimaryColor = primaryColor; 282 | redraw(); 283 | 284 | mLayoutRoot.setBackgroundColor(mPrimaryColor); 285 | } 286 | 287 | public int getTodayItemTextColor() { 288 | return mTodayItemTextColor; 289 | } 290 | 291 | public void setTodayItemTextColor(int todayItemTextColor) { 292 | this.mTodayItemTextColor = todayItemTextColor; 293 | redraw(); 294 | } 295 | 296 | public Drawable getTodayItemBackgroundDrawable() { 297 | return mTodayItemBackgroundDrawable; 298 | } 299 | 300 | public void setTodayItemBackgroundDrawable(Drawable todayItemBackgroundDrawable) { 301 | this.mTodayItemBackgroundDrawable = todayItemBackgroundDrawable; 302 | redraw(); 303 | } 304 | 305 | public int getSelectedItemTextColor() { 306 | return mSelectedItemTextColor; 307 | } 308 | 309 | public void setSelectedItemTextColor(int selectedItemTextColor) { 310 | this.mSelectedItemTextColor = selectedItemTextColor; 311 | redraw(); 312 | } 313 | 314 | public Drawable getSelectedItemBackgroundDrawable() { 315 | return mSelectedItemBackgroundDrawable; 316 | } 317 | 318 | public void setSelectedItemBackgroundDrawable(Drawable selectedItemBackground) { 319 | this.mSelectedItemBackgroundDrawable = selectedItemBackground; 320 | redraw(); 321 | } 322 | 323 | public Drawable getButtonLeftDrawable() { 324 | return mButtonLeftDrawable; 325 | } 326 | 327 | public void setButtonLeftDrawable(Drawable buttonLeftDrawable) { 328 | this.mButtonLeftDrawable = buttonLeftDrawable; 329 | mBtnPrevMonth.setImageDrawable(buttonLeftDrawable); 330 | mBtnPrevWeek.setImageDrawable(buttonLeftDrawable); 331 | } 332 | 333 | public Drawable getButtonRightDrawable() { 334 | return mButtonRightDrawable; 335 | } 336 | 337 | public void setButtonRightDrawable(Drawable buttonRightDrawable) { 338 | this.mButtonRightDrawable = buttonRightDrawable; 339 | mBtnNextMonth.setImageDrawable(buttonRightDrawable); 340 | mBtnNextWeek.setImageDrawable(buttonRightDrawable); 341 | } 342 | 343 | public Day getSelectedItem() { 344 | return mSelectedItem; 345 | } 346 | 347 | public void setSelectedItem(Day selectedItem) { 348 | this.mSelectedItem = selectedItem; 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/ic_navigate_before_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-hdpi/ic_navigate_before_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/ic_navigate_before_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-hdpi/ic_navigate_before_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/ic_navigate_next_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-hdpi/ic_navigate_next_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/ic_navigate_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-hdpi/ic_navigate_next_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/ic_navigate_before_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-mdpi/ic_navigate_before_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/ic_navigate_before_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-mdpi/ic_navigate_before_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/ic_navigate_next_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-mdpi/ic_navigate_next_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/ic_navigate_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-mdpi/ic_navigate_next_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/ic_navigate_before_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xhdpi/ic_navigate_before_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/ic_navigate_before_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xhdpi/ic_navigate_before_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/ic_navigate_next_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xhdpi/ic_navigate_next_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/ic_navigate_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xhdpi/ic_navigate_next_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/ic_navigate_before_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxhdpi/ic_navigate_before_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/ic_navigate_before_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxhdpi/ic_navigate_before_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/ic_navigate_next_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxhdpi/ic_navigate_next_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/ic_navigate_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxhdpi/ic_navigate_next_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/icon_flash_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxhdpi/icon_flash_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/ic_navigate_before_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxxhdpi/ic_navigate_before_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/ic_navigate_before_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxxhdpi/ic_navigate_before_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/ic_navigate_next_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxxhdpi/ic_navigate_next_black.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/ic_navigate_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azurechen/android-flexible-calendar/f27de67723d22e734cf9e2c90b2cc654fefca7e2/library/src/main/res/drawable-xxxhdpi/ic_navigate_next_white.png -------------------------------------------------------------------------------- /library/src/main/res/drawable/circle_black_solid_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/circle_black_stroke_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/circle_white_solid_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/circle_white_stroke_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /library/src/main/res/layout/layout_day.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 25 | 26 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /library/src/main/res/layout/layout_day_of_week.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | -------------------------------------------------------------------------------- /library/src/main/res/layout/widget_flexible_calendar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 18 | 19 | 25 | 26 | 32 | 33 | 34 | 35 | 39 | 40 | 46 | 47 | 53 | 54 | 55 | 56 | 65 | 66 | 67 | 68 | 72 | 73 | 74 | 75 | 80 | 81 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /library/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /library/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #F59293 5 | #FBAF3F 6 | #4B9DD6 7 | #2CB4B4 8 | 9 | -------------------------------------------------------------------------------- /library/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 36dp 6 | 36dp 7 | 8 | 9 | 24dp 10 | 24dp 11 | 120dp 12 | 1dp 13 | 14 | -------------------------------------------------------------------------------- /library/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Flexible Calendar 4 | 5 | MON 6 | TUE 7 | WED 8 | THU 9 | FRI 10 | SAT 11 | SUN 12 | 13 | 14 | -------------------------------------------------------------------------------- /library/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.azurechen.fcalendarsample" 9 | minSdkVersion 19 10 | targetSdkVersion 22 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(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | 26 | compile project(':library') 27 | } 28 | -------------------------------------------------------------------------------- /sample/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 /home/azurechen/Applications/android-sdk-linux/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 | -------------------------------------------------------------------------------- /sample/src/androidTest/java/com/azurechen/fcalendarsample/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendarsample; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /sample/src/main/java/com/azurechen/fcalendarsample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.azurechen.fcalendarsample; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.azurechen.fcalendar.data.CalendarAdapter; 10 | import com.azurechen.fcalendar.data.Day; 11 | import com.azurechen.fcalendar.widget.FlexibleCalendar; 12 | 13 | import java.util.Calendar; 14 | 15 | 16 | public class MainActivity extends Activity { 17 | 18 | @Override 19 | protected void onCreate(Bundle savedInstanceState) { 20 | super.onCreate(savedInstanceState); 21 | setContentView(R.layout.activity_main); 22 | 23 | final FlexibleCalendar viewCalendar = (FlexibleCalendar) findViewById(R.id.calendar); 24 | final Button btnCollapse = (Button) findViewById(R.id.btn_collapse); 25 | final Button btnExpand = (Button) findViewById(R.id.btn_expand); 26 | 27 | // init calendar 28 | Calendar cal = Calendar.getInstance(); 29 | CalendarAdapter adapter = new CalendarAdapter(this, cal); 30 | viewCalendar.setAdapter(adapter); 31 | 32 | // bind events of calendar 33 | viewCalendar.setCalendarListener(new FlexibleCalendar.CalendarListener() { 34 | @Override 35 | public void onDaySelect() { 36 | Day day = viewCalendar.getSelectedDay(); 37 | Log.i(getClass().getName(), "Selected Day: " 38 | + day.getYear() + "/" + (day.getMonth() + 1) + "/" + day.getDay()); 39 | } 40 | 41 | @Override 42 | public void onItemClick(View v) { 43 | Day day = viewCalendar.getSelectedDay(); 44 | Log.i(getClass().getName(), "The Day of Clicked View: " 45 | + day.getYear() + "/" + (day.getMonth() + 1) + "/" + day.getDay()); 46 | } 47 | 48 | @Override 49 | public void onDataUpdate() { 50 | Log.i(getClass().getName(), "Data Updated"); 51 | } 52 | 53 | @Override 54 | public void onMonthChange() { 55 | Log.i(getClass().getName(), "Month Changed" 56 | + ". Current Year: " + viewCalendar.getYear() 57 | + ", Current Month: " + (viewCalendar.getMonth() + 1)); 58 | } 59 | 60 | @Override 61 | public void onWeekChange(int position) { 62 | Log.i(getClass().getName(), "Week Changed" 63 | + ". Current Year: " + viewCalendar.getYear() 64 | + ", Current Month: " + (viewCalendar.getMonth() + 1) 65 | + ", Current Week position of Month: " + position); 66 | } 67 | }); 68 | 69 | // use methods 70 | viewCalendar.addEventTag(2015, 8, 10); 71 | viewCalendar.addEventTag(2015, 8, 14); 72 | viewCalendar.addEventTag(2015, 8, 23); 73 | 74 | viewCalendar.select(new Day(2015, 4, 22)); 75 | 76 | btnCollapse.setOnClickListener(new View.OnClickListener() { 77 | @Override 78 | public void onClick(View v) { 79 | viewCalendar.collapse(500); 80 | } 81 | }); 82 | btnExpand.setOnClickListener(new View.OnClickListener() { 83 | @Override 84 | public void onClick(View v) { 85 | viewCalendar.expand(500); 86 | } 87 | }); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | 17 | 21 | 22 |