├── sample
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ └── layout
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── c_calendar.xml
│ │ │ │ └── calendar_header.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ │ └── com
│ │ │ └── molo17
│ │ │ └── customizablecalendar
│ │ │ └── sample
│ │ │ ├── MainActivity.java
│ │ │ └── CalendarViewInteractor.java
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── molo17
│ │ │ └── customizablecalendar
│ │ │ └── sample
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── molo17
│ │ └── customizablecalendar
│ │ └── sample
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── library
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── attrs.xml
│ │ │ ├── drawable
│ │ │ │ ├── rectangle.xml
│ │ │ │ ├── left_rounded_rectangle.xml
│ │ │ │ ├── right_rounded_rectangle.xml
│ │ │ │ ├── empty_circle.xml
│ │ │ │ └── circle.xml
│ │ │ └── layout
│ │ │ │ ├── sub_view.xml
│ │ │ │ ├── week_day_view.xml
│ │ │ │ ├── calendar_view.xml
│ │ │ │ ├── customizable_calendar.xml
│ │ │ │ └── calendar_cell.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── molo17
│ │ │ │ └── customizablecalendar
│ │ │ │ └── library
│ │ │ │ ├── view
│ │ │ │ ├── HeaderView.java
│ │ │ │ ├── SubView.java
│ │ │ │ ├── WeekDaysView.java
│ │ │ │ ├── CustomizableCalendarView.java
│ │ │ │ ├── MonthView.java
│ │ │ │ ├── CalendarView.java
│ │ │ │ └── BaseView.java
│ │ │ │ ├── presenter
│ │ │ │ ├── interfeaces
│ │ │ │ │ ├── CustomizableCalendarPresenter.java
│ │ │ │ │ └── BasePresenter.java
│ │ │ │ └── implementations
│ │ │ │ │ └── CustomizableCalendarPresenterImpl.java
│ │ │ │ ├── interactors
│ │ │ │ ├── LayoutInteractor.java
│ │ │ │ ├── ViewInjector.java
│ │ │ │ ├── ViewInteractor.java
│ │ │ │ └── AUCalendar.java
│ │ │ │ ├── utils
│ │ │ │ └── DateUtils.java
│ │ │ │ ├── model
│ │ │ │ ├── CalendarFields.java
│ │ │ │ ├── CalendarItem.java
│ │ │ │ └── Calendar.java
│ │ │ │ ├── components
│ │ │ │ ├── HeaderView.java
│ │ │ │ ├── SubView.java
│ │ │ │ ├── WeekDaysView.java
│ │ │ │ ├── CustomizableCalendar.java
│ │ │ │ ├── MonthGridView.java
│ │ │ │ └── CalendarRecyclerView.java
│ │ │ │ └── adapter
│ │ │ │ ├── WeekDaysViewAdapter.java
│ │ │ │ ├── CalendarViewAdapter.java
│ │ │ │ └── MonthAdapter.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── molo17
│ │ │ └── customizablecalendar
│ │ │ └── library
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── molo17
│ │ └── customizablecalendar
│ │ └── library
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── static
├── Logo.jpg
├── CalendarDemo.gif
└── CalendarPreview1.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── LICENSE
├── gradlew.bat
├── .gitignore
├── gradlew
└── README.md
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/library/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':library'
2 |
--------------------------------------------------------------------------------
/static/Logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/static/Logo.jpg
--------------------------------------------------------------------------------
/static/CalendarDemo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/static/CalendarDemo.gif
--------------------------------------------------------------------------------
/static/CalendarPreview1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/static/CalendarPreview1.png
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | library
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/library/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 240dp
4 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MOLO17/CustomizableCalendar/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/library/src/main/res/drawable/rectangle.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/library/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/HeaderView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | /**
4 | * Created by francescofurlan on 30/06/17.
5 | */
6 |
7 | public interface HeaderView extends BaseView {
8 | }
9 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 09:59:42 CEST 2017
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-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/SubView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | /**
4 | * Created by francescofurlan on 30/06/17.
5 | */
6 |
7 | public interface SubView extends BaseView {
8 | void onMonthChanged(String month);
9 | }
10 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/left_rounded_rectangle.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/right_rounded_rectangle.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CustomizableCalendar
3 | day month year
4 | First day selected
5 | Last day selected
6 |
7 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/WeekDaysView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | /**
4 | * Created by francescofurlan on 30/06/17.
5 | */
6 |
7 | public interface WeekDaysView extends BaseView {
8 | void onFirstDayOfWeek(int firstDayOfWeek);
9 | }
10 |
--------------------------------------------------------------------------------
/library/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/CustomizableCalendarView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | /**
4 | * Created by francescofurlan on 23/06/17.
5 | */
6 |
7 | public interface CustomizableCalendarView extends BaseView {
8 | void onCurrentMonthChanged(String month);
9 | }
10 |
--------------------------------------------------------------------------------
/library/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/MonthView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 |
4 | import org.joda.time.DateTime;
5 |
6 | /**
7 | * Created by francescofurlan on 23/06/17.
8 | */
9 |
10 | public interface MonthView extends BaseView {
11 | void setSelected(DateTime dateSelected);
12 |
13 | void refreshDays();
14 |
15 | void unsubscribe();
16 | }
17 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/CalendarView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | import android.support.annotation.LayoutRes;
4 |
5 | /**
6 | * Created by francescofurlan on 03/07/17.
7 | */
8 |
9 | public interface CalendarView extends BaseView {
10 | void setMonthLayoutResId(@LayoutRes int layoutResId);
11 |
12 | void setDayLayoutResId(@LayoutRes int layoutResId);
13 | }
14 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/molo17/customizablecalendar/sample/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.sample;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/library/src/test/java/com/molo17/customizablecalendar/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/library/src/main/res/layout/sub_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
13 |
14 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/presenter/interfeaces/CustomizableCalendarPresenter.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.presenter.interfeaces;
2 |
3 | import com.molo17.customizablecalendar.library.interactors.ViewInjector;
4 | import com.molo17.customizablecalendar.library.view.CustomizableCalendarView;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by francescofurlan on 23/06/17.
10 | */
11 |
12 | public interface CustomizableCalendarPresenter extends BasePresenter, ViewInjector {
13 | List setupWeekDays();
14 | }
15 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/week_day_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/interactors/LayoutInteractor.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.interactors;
2 |
3 | import android.support.annotation.LayoutRes;
4 |
5 | /**
6 | * Created by francescofurlan on 26/06/17.
7 | */
8 |
9 | public interface LayoutInteractor {
10 | void setCustomizableCalendarLayoutResId(@LayoutRes int resId);
11 |
12 | void setHeaderLayoutResId(@LayoutRes int resId);
13 |
14 | void setWeekDayResId(@LayoutRes int resId);
15 |
16 | void setSubViewResId(@LayoutRes int resId);
17 |
18 | void setMonthResId(@LayoutRes int resId);
19 |
20 | void setDayResId(@LayoutRes int resId);
21 | }
22 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/calendar_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
13 |
14 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/view/BaseView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.view;
2 |
3 | import android.support.annotation.LayoutRes;
4 |
5 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
6 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
7 |
8 | /**
9 | * Created by francescofurlan on 23/06/17.
10 | */
11 |
12 | public interface BaseView {
13 | void refreshData();
14 |
15 | void setLayoutResId(@LayoutRes int layoutResId);
16 |
17 | void injectViewInteractor(ViewInteractor viewInteractor);
18 |
19 | void injectPresenter(CustomizableCalendarPresenter presenter);
20 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/presenter/interfeaces/BasePresenter.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.presenter.interfeaces;
2 |
3 | import android.support.annotation.LayoutRes;
4 | import android.view.View;
5 |
6 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
7 | import com.molo17.customizablecalendar.library.view.BaseView;
8 |
9 | /**
10 | * Created by francescofurlan on 23/06/17.
11 | */
12 |
13 | public interface BasePresenter {
14 | void setView(T view);
15 |
16 | void onBindView(View rootView);
17 |
18 | void injectViewInteractor(ViewInteractor viewInteractor);
19 |
20 | void setLayoutResId(@LayoutRes int layoutResId);
21 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/interactors/ViewInjector.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.interactors;
2 |
3 | import com.molo17.customizablecalendar.library.view.CalendarView;
4 | import com.molo17.customizablecalendar.library.view.HeaderView;
5 | import com.molo17.customizablecalendar.library.view.SubView;
6 | import com.molo17.customizablecalendar.library.view.WeekDaysView;
7 |
8 | /**
9 | * Created by francescofurlan on 30/06/17.
10 | */
11 |
12 | public interface ViewInjector {
13 | void injectCalendarView(CalendarView calendarView);
14 |
15 | void injectHeaderView(HeaderView headerView);
16 |
17 | void injectSubView(SubView subView);
18 |
19 | void injectWeekDaysView(WeekDaysView weekDaysView);
20 | }
21 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/empty_circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
13 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/library/src/main/res/drawable/circle.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
13 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/molo17/customizablecalendar/sample/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.sample;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.molo17.customizablecalendar.sample.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/library/src/androidTest/java/com/molo17/customizablecalendar/library/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.molo17.customizablecalendar.library.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/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 /Users/francescofurlan/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/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 /Users/francescofurlan/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 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/utils/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.utils;
2 |
3 | import java.util.Calendar;
4 |
5 | /**
6 | * Created by francescofurlan on 23/06/17.
7 | */
8 |
9 | public class DateUtils {
10 | public static int getDaysInMonth(int month, int year) {
11 | switch (month) {
12 | case Calendar.JANUARY:
13 | case Calendar.MARCH:
14 | case Calendar.MAY:
15 | case Calendar.JULY:
16 | case Calendar.AUGUST:
17 | case Calendar.OCTOBER:
18 | case Calendar.DECEMBER:
19 | return 31;
20 | case Calendar.APRIL:
21 | case Calendar.JUNE:
22 | case Calendar.SEPTEMBER:
23 | case Calendar.NOVEMBER:
24 | return 30;
25 | case Calendar.FEBRUARY:
26 | return (year % 4 == 0) ? 29 : 28;
27 | default:
28 | throw new IllegalArgumentException("Invalid Month");
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 MOLO17
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/library/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion "26.0.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 19
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 |
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 |
15 | }
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | }
27 |
28 | dependencies {
29 | compile fileTree(dir: 'libs', include: ['*.jar'])
30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
31 | exclude group: 'com.android.support', module: 'support-annotations'
32 | })
33 | compile 'com.android.support:appcompat-v7:26.1.0'
34 | compile 'com.android.support:recyclerview-v7:26.1.0'
35 | testCompile 'junit:junit:4.12'
36 | compile 'joda-time:joda-time:2.9.9'
37 |
38 | provided "io.reactivex.rxjava2:rxjava:+"
39 | }
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion "26.0.2"
6 | defaultConfig {
7 | applicationId "com.molo17.customizablecalendar"
8 | minSdkVersion 19
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | compileOptions {
21 | sourceCompatibility JavaVersion.VERSION_1_8
22 | targetCompatibility JavaVersion.VERSION_1_8
23 | }
24 | }
25 |
26 | dependencies {
27 | compile fileTree(include: ['*.jar'], dir: 'libs')
28 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
29 | exclude group: 'com.android.support', module: 'support-annotations'
30 | })
31 | compile 'com.android.support:appcompat-v7:26.1.0'
32 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
33 | testCompile 'junit:junit:4.12'
34 | compile 'com.jakewharton:butterknife:8.8.1'
35 | annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
36 | compile 'io.reactivex.rxjava2:rxjava:2.1.7'
37 | compile project(':library')
38 | }
39 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/model/CalendarFields.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.model;
2 |
3 | import android.support.annotation.StringDef;
4 |
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 |
8 | import static com.molo17.customizablecalendar.library.model.CalendarFields.CURRENT_MONTH;
9 | import static com.molo17.customizablecalendar.library.model.CalendarFields.FIRST_DAY_OF_WEEK;
10 | import static com.molo17.customizablecalendar.library.model.CalendarFields.FIRST_SELECTED_DAY;
11 | import static com.molo17.customizablecalendar.library.model.CalendarFields.LAST_SELECTED_DAY;
12 | import static com.molo17.customizablecalendar.library.model.CalendarFields.MONTHS;
13 | import static com.molo17.customizablecalendar.library.model.CalendarFields.MULTIPLE_SELECTION;
14 |
15 | /**
16 | * Created by francescofurlan on 30/06/17.
17 | */
18 |
19 | @StringDef({
20 | FIRST_SELECTED_DAY,
21 | LAST_SELECTED_DAY,
22 | CURRENT_MONTH,
23 | MONTHS,
24 | MULTIPLE_SELECTION,
25 | FIRST_DAY_OF_WEEK
26 | })
27 |
28 | @Retention(RetentionPolicy.SOURCE)
29 | public @interface CalendarFields {
30 | String FIRST_SELECTED_DAY = "firstSelectedDay";
31 | String LAST_SELECTED_DAY = "lastSelectedDay";
32 | String CURRENT_MONTH = "currentMonth";
33 | String MONTHS = "months";
34 | String MULTIPLE_SELECTION = "multipleSelection";
35 | String FIRST_DAY_OF_WEEK = "firstDayOfWeek";
36 | }
--------------------------------------------------------------------------------
/sample/src/main/res/layout/c_calendar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/customizable_calendar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
19 |
20 |
26 |
27 |
32 |
33 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/interactors/ViewInteractor.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.interactors;
2 |
3 | import android.view.View;
4 | import android.view.ViewGroup;
5 |
6 | import com.molo17.customizablecalendar.library.adapter.WeekDaysViewAdapter;
7 | import com.molo17.customizablecalendar.library.model.CalendarItem;
8 |
9 | import org.joda.time.DateTime;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Created by francescofurlan on 26/06/17.
15 | */
16 |
17 | public interface ViewInteractor {
18 | void onCustomizableCalendarBindView(View view);
19 |
20 | void onHeaderBindView(ViewGroup view);
21 |
22 | void onWeekDaysBindView(View view);
23 |
24 | void onWeekDayBindView(WeekDaysViewAdapter.WeekDayVH holder, String weekDay);
25 |
26 | void onSubViewBindView(View view, String month);
27 |
28 | void onCalendarBindView(View view);
29 |
30 | void onMonthBindView(View view);
31 |
32 | View onMonthCellBindView(View view, CalendarItem currentItem);
33 |
34 | boolean hasImplementedDayCalculation();
35 |
36 | List calculateDays(int year, int month, int firstDayOfMonth, int lastDayOfMonth);
37 |
38 | boolean hasImplementedSelection();
39 |
40 | int setSelected(boolean multipleSelection, DateTime dateSelected);
41 |
42 | boolean hasImplementedMonthCellBinding();
43 |
44 | View getMonthGridView(View rootView);
45 |
46 | boolean hasImplementedWeekDayNameFormat();
47 |
48 | String formatWeekDayName(String nameOfDay);
49 | }
50 |
--------------------------------------------------------------------------------
/library/src/main/res/layout/calendar_cell.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
22 |
23 |
31 |
32 |
39 |
40 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/model/CalendarItem.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.model;
2 |
3 | import org.joda.time.DateTime;
4 |
5 | import java.util.Calendar;
6 |
7 | /**
8 | * Created by francescofurlan on 23/06/17.
9 | */
10 |
11 | public class CalendarItem {
12 | private long id;
13 | private DateTime dateTime;
14 | private boolean selected;
15 |
16 | public CalendarItem(Calendar calendar) {
17 | this.dateTime = new DateTime(calendar);
18 | this.id = calendar.getTimeInMillis();
19 | }
20 |
21 | public CalendarItem(DateTime dateTime) {
22 | this.dateTime = dateTime;
23 | this.id = dateTime.getMillis();
24 | }
25 |
26 | public CalendarItem(int day, int month, int year) {
27 | this.dateTime = new DateTime(year, month, day, 0, 0);
28 | this.id = dateTime.getMillis();
29 | }
30 |
31 | public DateTime getDateTime() {
32 | return dateTime;
33 | }
34 |
35 | public void setDateTime(DateTime dateTime) {
36 | this.dateTime = dateTime;
37 | }
38 |
39 | public boolean isSelectable() {
40 | return selected;
41 | }
42 |
43 | public void setSelectable(boolean selected) {
44 | this.selected = selected;
45 | }
46 |
47 | public long getId() {
48 | return id;
49 | }
50 |
51 | public void setId(long id) {
52 | this.id = id;
53 | }
54 |
55 | public int compareTo(DateTime today) {
56 | return dateTime.compareTo(today);
57 | }
58 |
59 | public String getDayString() {
60 | return getDay() + "";
61 | }
62 |
63 | public int getDay() {
64 | return dateTime.getDayOfMonth();
65 | }
66 |
67 | public int getMonth() {
68 | return dateTime.getMonthOfYear();
69 | }
70 |
71 | public int getYear() {
72 | return dateTime.getYear();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/HeaderView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.LayoutRes;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.widget.RelativeLayout;
8 |
9 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
10 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
11 |
12 | /**
13 | * Created by francescofurlan on 23/06/17.
14 | */
15 |
16 | public class HeaderView extends RelativeLayout implements com.molo17.customizablecalendar.library.view.HeaderView {
17 | private CustomizableCalendarPresenter presenter;
18 | private ViewInteractor viewInteractor;
19 | private Context context;
20 |
21 | public HeaderView(Context context) {
22 | this(context, null);
23 | }
24 |
25 | public HeaderView(Context context, AttributeSet attrs) {
26 | this(context, attrs, 0);
27 | }
28 |
29 | public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
30 | super(context, attrs, defStyleAttr);
31 | init(context);
32 | }
33 |
34 | private void init(Context context) {
35 | this.context = context;
36 | }
37 |
38 | @Override
39 | public void refreshData() {
40 |
41 | }
42 |
43 | @Override
44 | public void setLayoutResId(@LayoutRes int layoutResId) {
45 | if (layoutResId != -1) {
46 | LayoutInflater.from(context).inflate(layoutResId, this);
47 | }
48 | }
49 |
50 | @Override
51 | public void injectViewInteractor(ViewInteractor viewInteractor) {
52 | this.viewInteractor = viewInteractor;
53 | this.viewInteractor.onHeaderBindView(this);
54 | }
55 |
56 | @Override
57 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
58 | this.presenter = presenter;
59 | this.presenter.injectHeaderView(this);
60 | }
61 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/molo17/customizablecalendar/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 |
6 | import com.molo17.customizablecalendar.library.components.CustomizableCalendar;
7 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
8 | import com.molo17.customizablecalendar.library.model.Calendar;
9 |
10 | import org.joda.time.DateTime;
11 |
12 | import butterknife.BindView;
13 | import butterknife.ButterKnife;
14 | import io.reactivex.disposables.CompositeDisposable;
15 |
16 | public class MainActivity extends AppCompatActivity {
17 |
18 | @BindView(R.id.view_month)
19 | CustomizableCalendar customizableCalendar;
20 |
21 | private CompositeDisposable subscriptions;
22 |
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_main);
27 | ButterKnife.bind(this);
28 | subscriptions = new CompositeDisposable();
29 | updateData();
30 | }
31 |
32 | private void updateData() {
33 | // setting up first and last month that must be showed in the calendar
34 | DateTime firstMonth = new DateTime().withDayOfMonth(1);
35 | DateTime lastMonth = new DateTime().plusMonths(3).withDayOfMonth(1);
36 |
37 | // create the Calendar obj and setting it up with some configs like:
38 | // - first selected day
39 | // - last selected day
40 | // - multiple selection
41 | final Calendar calendar = new Calendar(firstMonth, lastMonth);
42 | calendar.setFirstSelectedDay(new DateTime().plusDays(4));
43 | calendar.setLastSelectedDay(new DateTime().plusDays(6));
44 | calendar.setMultipleSelection(true);
45 |
46 | // create a CalendarViewInteractor obj needed to interact with the CustomizableCalendar
47 | final CalendarViewInteractor calendarViewInteractor = new CalendarViewInteractor(getBaseContext());
48 |
49 | // create the AUCalendar obj and observes changes on it
50 | AUCalendar auCalendar = AUCalendar.getInstance(calendar);
51 | calendarViewInteractor.updateCalendar(calendar);
52 | subscriptions.add(
53 | auCalendar.observeChangesOnCalendar()
54 | .subscribe(changeSet -> calendarViewInteractor.updateCalendar(calendar))
55 | );
56 |
57 | // inject (set) the calendarViewInteractor to the CustomizableCalendar
58 | customizableCalendar.injectViewInteractor(calendarViewInteractor);
59 | }
60 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/androidstudio
3 |
4 | ### AndroidStudio ###
5 | # Covers files to be ignored for android development using Android Studio.
6 |
7 | # Built application files
8 | *.apk
9 | *.ap_
10 |
11 | # Files for the ART/Dalvik VM
12 | *.dex
13 |
14 | # Java class files
15 | *.class
16 |
17 | # Generated files
18 | bin/
19 | gen/
20 | out/
21 |
22 | # Gradle files
23 | .gradle
24 | .gradle/
25 | build/
26 |
27 | # Signing files
28 | .signing/
29 |
30 | # Local configuration file (sdk path, etc)
31 | local.properties
32 |
33 | # Proguard folder generated by Eclipse
34 | proguard/
35 |
36 | # Log Files
37 | *.log
38 |
39 | # Android Studio
40 | /*/build/
41 | /*/local.properties
42 | /*/out
43 | /*/*/build
44 | /*/*/production
45 | captures/
46 | .navigation/
47 | *.ipr
48 | *~
49 | *.swp
50 |
51 | # Android Patch
52 | gen-external-apklibs
53 |
54 | # External native build folder generated in Android Studio 2.2 and later
55 | .externalNativeBuild
56 |
57 | # NDK
58 | obj/
59 |
60 | # IntelliJ IDEA
61 | *.iml
62 | *.iws
63 | /out/
64 | .idea/
65 |
66 | # User-specific configurations
67 | .idea/libraries/
68 | .idea/workspace.xml
69 | .idea/tasks.xml
70 | .idea/.name
71 | .idea/compiler.xml
72 | .idea/copyright/profiles_settings.xml
73 | .idea/encodings.xml
74 | .idea/misc.xml
75 | .idea/modules.xml
76 | .idea/scopes/scope_settings.xml
77 | .idea/dictionaries
78 | .idea/vcs.xml
79 | .idea/jsLibraryMappings.xml
80 | .idea/datasources.xml
81 | .idea/dataSources.ids
82 | .idea/sqlDataSources.xml
83 | .idea/dynamic.xml
84 | .idea/uiDesigner.xml
85 |
86 | # Keystore files
87 | *.jks
88 |
89 | # OS-specific files
90 | .DS_Store
91 | .DS_Store?
92 | ._*
93 | .Spotlight-V100
94 | .Trashes
95 | ehthumbs.db
96 | Thumbs.db
97 |
98 | # Legacy Eclipse project files
99 | .classpath
100 | .project
101 |
102 | # Mobile Tools for Java (J2ME)
103 | .mtj.tmp/
104 |
105 | # Package Files #
106 | *.jar
107 | *.war
108 | *.ear
109 |
110 | # virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
111 | hs_err_pid*
112 |
113 | ## Plugin-specific files:
114 |
115 | # mpeltonen/sbt-idea plugin
116 | .idea_modules/
117 |
118 | # JIRA plugin
119 | atlassian-ide-plugin.xml
120 |
121 | # Mongo Explorer plugin
122 | .idea/mongoSettings.xml
123 |
124 | # Crashlytics plugin (for Android Studio and IntelliJ)
125 | com_crashlytics_export_strings.xml
126 | crashlytics.properties
127 | crashlytics-build.properties
128 | fabric.properties
129 |
130 | ### AndroidStudio Patch ###
131 | # Google Services plugin
132 | google-services.json
133 |
134 | !/gradle/wrapper/gradle-wrapper.jar
135 |
136 | # End of https://www.gitignore.io/api/androidstudio
137 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/adapter/WeekDaysViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.LayoutRes;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 |
11 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * Created by francescofurlan on 28/06/17.
18 | */
19 |
20 | public class WeekDaysViewAdapter extends RecyclerView.Adapter {
21 |
22 | private Context context;
23 | private List weekDays = new ArrayList<>();
24 | private ItemClickListener clickListener;
25 | private ViewInteractor viewInteractor;
26 | private @LayoutRes int layoutResId;
27 |
28 | public WeekDaysViewAdapter(Context context, List weekDays, @LayoutRes int layoutResId, ViewInteractor viewInteractor) {
29 | this.context = context;
30 | this.weekDays = weekDays;
31 | this.layoutResId = layoutResId;
32 | this.viewInteractor = viewInteractor;
33 | }
34 |
35 | @Override
36 | public WeekDayVH onCreateViewHolder(ViewGroup parent, int viewType) {
37 | View view = LayoutInflater.from(context).inflate(layoutResId, parent, false);
38 | return new WeekDayVH(view);
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(WeekDayVH holder, int position) {
43 | String weekDay = getItem(position);
44 | holder.weekDayTxt.setText(weekDay);
45 | viewInteractor.onWeekDayBindView(holder, weekDay);
46 | }
47 |
48 | @Override
49 | public int getItemCount() {
50 | return weekDays.size();
51 | }
52 |
53 | public String getItem(int position) {
54 | return weekDays.get(position);
55 | }
56 |
57 | public void setClickListener(ItemClickListener clickListener) {
58 | this.clickListener = clickListener;
59 | }
60 |
61 | public interface ItemClickListener {
62 | void onItemClick(View view, int position);
63 | }
64 |
65 | public class WeekDayVH extends RecyclerView.ViewHolder implements View.OnClickListener {
66 | TextView weekDayTxt;
67 |
68 | public WeekDayVH(View itemView) {
69 | super(itemView);
70 | weekDayTxt = itemView.findViewById(android.R.id.summary);
71 | itemView.setOnClickListener(this);
72 | }
73 |
74 | @Override
75 | public void onClick(View view) {
76 | if (clickListener != null) {
77 | clickListener.onItemClick(view, getAdapterPosition());
78 | }
79 | }
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/model/Calendar.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.model;
2 |
3 | import org.joda.time.DateTime;
4 | import org.joda.time.Months;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.Locale;
9 |
10 | /**
11 | * Created by francescofurlan on 27/06/17.
12 | */
13 |
14 | public class Calendar {
15 | private DateTime firstMonth;
16 | private DateTime firstSelectedDay;
17 | private DateTime lastSelectedDay;
18 | private DateTime currentMonth;
19 | private List months;
20 | private boolean multipleSelection;
21 | private int firstDayOfWeek;
22 |
23 | public Calendar(DateTime firstMonth, DateTime lastMonth) {
24 | this.firstMonth = firstMonth;
25 | this.firstDayOfWeek = java.util.Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek();
26 |
27 | DateTime startMonth = firstMonth.plusMonths(1);
28 | int monthsBetweenCount = Months.monthsBetween(firstMonth, lastMonth).getMonths();
29 |
30 | months = new ArrayList<>();
31 |
32 | months.add(firstMonth);
33 | currentMonth = firstMonth;
34 |
35 | DateTime monthToAdd = new DateTime(startMonth.getYear(), startMonth.getMonthOfYear(), 1, 0, 0);
36 | for (int i = 0; i <= monthsBetweenCount; i++) {
37 | months.add(monthToAdd);
38 | monthToAdd = monthToAdd.plusMonths(1);
39 | }
40 | }
41 |
42 | public DateTime getFirstSelectedDay() {
43 | return firstSelectedDay;
44 | }
45 |
46 | public void setFirstSelectedDay(DateTime firstSelectedDay) {
47 | this.firstSelectedDay = firstSelectedDay;
48 | }
49 |
50 | public DateTime getLastSelectedDay() {
51 | return lastSelectedDay;
52 | }
53 |
54 | public void setLastSelectedDay(DateTime lastSelectedDay) {
55 | this.lastSelectedDay = lastSelectedDay;
56 | }
57 |
58 | public DateTime getCurrentMonth() {
59 | return currentMonth;
60 | }
61 |
62 | public void setCurrentMonth(DateTime currentMonth) {
63 | this.currentMonth = currentMonth;
64 | }
65 |
66 | public List getMonths() {
67 | return months;
68 | }
69 |
70 | public void setMonths(List months) {
71 | this.months = months;
72 | }
73 |
74 | public boolean isMultipleSelectionEnabled() {
75 | return multipleSelection;
76 | }
77 |
78 | public void setMultipleSelection(boolean multipleSelection) {
79 | this.multipleSelection = multipleSelection;
80 | }
81 |
82 | public int getFirstDayOfWeek() {
83 | return firstDayOfWeek;
84 | }
85 |
86 | public void setFirstDayOfWeek(int firstDayOfWeek) {
87 | this.firstDayOfWeek = firstDayOfWeek;
88 | }
89 |
90 | public DateTime getFirstMonth() {
91 | return firstMonth;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/calendar_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
28 |
29 |
42 |
43 |
44 |
45 |
51 |
52 |
65 |
66 |
79 |
80 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/SubView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.LayoutRes;
6 | import android.text.TextUtils;
7 | import android.util.AttributeSet;
8 | import android.view.LayoutInflater;
9 | import android.widget.RelativeLayout;
10 | import android.widget.TextView;
11 |
12 | import com.molo17.customizablecalendar.library.R;
13 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
14 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
15 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
16 |
17 | import org.joda.time.DateTime;
18 |
19 | import java.util.Locale;
20 |
21 | /**
22 | * Created by francescofurlan on 23/06/17.
23 | */
24 |
25 | public class SubView extends RelativeLayout implements com.molo17.customizablecalendar.library.view.SubView {
26 | TextView monthTxt;
27 |
28 | private ViewInteractor viewInteractor;
29 |
30 | private @LayoutRes int layoutResId = R.layout.sub_view;
31 | private CustomizableCalendarPresenter presenter;
32 | private Context context;
33 |
34 | public SubView(Context context) {
35 | this(context, null);
36 | }
37 |
38 | public SubView(Context context, AttributeSet attrs) {
39 | this(context, attrs, 0);
40 | }
41 |
42 | public SubView(Context context, AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | init(context, attrs);
45 | }
46 |
47 | private void init(Context context, AttributeSet attrs) {
48 | this.context = context;
49 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomizableCalendar);
50 | if (typedArray != null) {
51 | layoutResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_layout, R.layout.sub_view);
52 | typedArray.recycle();
53 | }
54 |
55 | LayoutInflater.from(context).inflate(layoutResId, this);
56 | monthTxt = (TextView) findViewById(android.R.id.message);
57 | }
58 |
59 | @Override
60 | public void onMonthChanged(String month) {
61 | monthTxt.setText(month);
62 | if (viewInteractor != null) {
63 | viewInteractor.onSubViewBindView(this, month);
64 | }
65 | }
66 |
67 | @Override
68 | public void refreshData() {
69 | }
70 |
71 | @Override
72 | public void setLayoutResId(@LayoutRes int layoutResId) {
73 | this.layoutResId = layoutResId;
74 | }
75 |
76 | @Override
77 | public void injectViewInteractor(ViewInteractor viewInteractor) {
78 | this.viewInteractor = viewInteractor;
79 | DateTime firstMonth = AUCalendar.getInstance().getFirstMonth();
80 | String month = firstMonth.toString("MMMMM", Locale.getDefault());
81 | if (!TextUtils.isEmpty(month)) {
82 | String formattedMonth = month.substring(0, 1).toUpperCase(Locale.getDefault()) + month.substring(1);
83 | onMonthChanged(formattedMonth);
84 | }
85 | }
86 |
87 | @Override
88 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
89 | this.presenter = presenter;
90 | this.presenter.injectSubView(this);
91 | }
92 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/WeekDaysView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.LayoutRes;
6 | import android.support.annotation.Nullable;
7 | import android.support.v7.widget.GridLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.util.AttributeSet;
10 |
11 | import com.molo17.customizablecalendar.library.R;
12 | import com.molo17.customizablecalendar.library.adapter.WeekDaysViewAdapter;
13 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
14 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
15 |
16 | import java.util.List;
17 |
18 | /**
19 | * Created by francescofurlan on 23/06/17.
20 | */
21 |
22 | public class WeekDaysView extends RecyclerView implements com.molo17.customizablecalendar.library.view.WeekDaysView {
23 | WeekDaysViewAdapter weekDaysViewAdapter;
24 | private Context context;
25 | private @LayoutRes int layoutResId = -1;
26 | private ViewInteractor viewInteractor;
27 | private Integer firstDayOfWeek;
28 | private CustomizableCalendarPresenter presenter;
29 | private List weekDays;
30 |
31 | public WeekDaysView(Context context) {
32 | this(context, null);
33 | }
34 |
35 | public WeekDaysView(Context context, @Nullable AttributeSet attrs) {
36 | this(context, attrs, 0);
37 | }
38 |
39 | public WeekDaysView(Context context, @Nullable AttributeSet attrs, int defStyle) {
40 | super(context, attrs, defStyle);
41 | init(context, attrs);
42 | }
43 |
44 | private void init(Context context, AttributeSet attrs) {
45 | this.context = context;
46 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomizableCalendar);
47 | layoutResId = R.layout.week_day_view;
48 | if (typedArray != null) {
49 | layoutResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_layout, R.layout.week_day_view);
50 | typedArray.recycle();
51 | }
52 | }
53 |
54 | public void setWeekDays() {
55 | weekDaysViewAdapter = new WeekDaysViewAdapter(context, weekDays, layoutResId, viewInteractor);
56 | setAdapter(weekDaysViewAdapter);
57 | setLayoutManager(new GridLayoutManager(context, weekDays.size()));
58 | }
59 |
60 | @Override
61 | public void refreshData() {
62 |
63 | }
64 |
65 | @Override
66 | public void setLayoutResId(@LayoutRes int layoutResId) {
67 | this.layoutResId = layoutResId;
68 | }
69 |
70 | @Override
71 | public void injectViewInteractor(ViewInteractor viewInteractor) {
72 | this.viewInteractor = viewInteractor;
73 | viewInteractor.onWeekDaysBindView(this);
74 | weekDays = presenter.setupWeekDays();
75 | updateWeekDays();
76 | }
77 |
78 | @Override
79 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
80 | this.presenter = presenter;
81 | presenter.injectWeekDaysView(this);
82 | updateWeekDays();
83 | }
84 |
85 | @Override
86 | public void onFirstDayOfWeek(int firstDayOfWeek) {
87 | this.firstDayOfWeek = firstDayOfWeek;
88 | }
89 |
90 | private void updateWeekDays() {
91 | viewInteractor.onWeekDaysBindView(this);
92 | weekDays = presenter.setupWeekDays();
93 | setWeekDays();
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/CustomizableCalendar.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.Nullable;
6 | import android.util.AttributeSet;
7 | import android.view.LayoutInflater;
8 | import android.widget.LinearLayout;
9 |
10 | import com.molo17.customizablecalendar.library.R;
11 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
12 | import com.molo17.customizablecalendar.library.presenter.implementations.CustomizableCalendarPresenterImpl;
13 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
14 | import com.molo17.customizablecalendar.library.view.CustomizableCalendarView;
15 |
16 | /**
17 | * Created by francescofurlan on 23/06/17.
18 | */
19 |
20 | public class CustomizableCalendar extends LinearLayout implements CustomizableCalendarView {
21 |
22 | HeaderView headerView;
23 |
24 | WeekDaysView weekDaysView;
25 |
26 | SubView subView;
27 |
28 | CalendarRecyclerView calendarRecyclerView;
29 |
30 | CustomizableCalendarPresenter presenter;
31 |
32 | private int layoutResId = -1;
33 |
34 | public CustomizableCalendar(Context context) {
35 | this(context, null);
36 | }
37 |
38 | public CustomizableCalendar(Context context, @Nullable AttributeSet attrs) {
39 | this(context, attrs, 0);
40 | }
41 |
42 | public CustomizableCalendar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
43 | super(context, attrs, defStyleAttr);
44 | init(context, attrs, defStyleAttr);
45 | }
46 |
47 | private void init(Context context, AttributeSet attrs, int defStyleAttr) {
48 | if (presenter == null) {
49 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomizableCalendar);
50 | presenter = new CustomizableCalendarPresenterImpl();
51 | presenter.setView(this);
52 | layoutResId = R.layout.customizable_calendar;
53 | if (typedArray != null) {
54 | layoutResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_layout, R.layout.customizable_calendar);
55 | typedArray.recycle();
56 | }
57 |
58 | LayoutInflater.from(context).inflate(layoutResId, this);
59 | headerView = (HeaderView) findViewById(android.R.id.primary);
60 | weekDaysView = (WeekDaysView) findViewById(android.R.id.text1);
61 | subView = (SubView) findViewById(android.R.id.text2);
62 | calendarRecyclerView = (CalendarRecyclerView) findViewById(android.R.id.content);
63 | }
64 | }
65 |
66 | public CustomizableCalendarPresenter getPresenter() {
67 | return presenter;
68 | }
69 |
70 | @Override
71 | public void injectViewInteractor(ViewInteractor viewInteractor) {
72 | viewInteractor.onCustomizableCalendarBindView(this);
73 | presenter.injectViewInteractor(viewInteractor);
74 | headerView.injectPresenter(presenter);
75 | calendarRecyclerView.injectPresenter(presenter);
76 | subView.injectPresenter(presenter);
77 | weekDaysView.injectPresenter(presenter);
78 | }
79 |
80 | @Override
81 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
82 | this.presenter = presenter;
83 | presenter.setView(this);
84 | }
85 |
86 | @Override
87 | public void onCurrentMonthChanged(String month) {
88 | subView.onMonthChanged(month);
89 | }
90 |
91 | @Override
92 | public void refreshData() {
93 |
94 | }
95 |
96 | @Override
97 | public void setLayoutResId(int layoutResId) {
98 | this.layoutResId = layoutResId;
99 | }
100 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/molo17/customizablecalendar/sample/CalendarViewInteractor.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.sample;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.RelativeLayout;
8 | import android.widget.TextView;
9 |
10 | import com.molo17.customizablecalendar.library.adapter.WeekDaysViewAdapter;
11 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
12 | import com.molo17.customizablecalendar.library.model.Calendar;
13 | import com.molo17.customizablecalendar.library.model.CalendarItem;
14 |
15 | import org.joda.time.DateTime;
16 |
17 | import java.util.List;
18 |
19 | /**
20 | * Created by francescofurlan on 03/07/17.
21 | */
22 |
23 | public class CalendarViewInteractor implements ViewInteractor {
24 | private Context context;
25 | private Calendar calendar;
26 | private TextView firstDaySelectedTxt;
27 | private TextView lastDaySelectedTxt;
28 |
29 | CalendarViewInteractor(Context context) {
30 | this.context = context;
31 | }
32 |
33 | @Override
34 | public void onCustomizableCalendarBindView(View view) {
35 |
36 | }
37 |
38 | @Override
39 | public void onHeaderBindView(ViewGroup view) {
40 | RelativeLayout layout = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.calendar_header, view);
41 | firstDaySelectedTxt = (TextView) layout.findViewById(R.id.first_day_selected);
42 | lastDaySelectedTxt = (TextView) layout.findViewById(R.id.last_day_selected);
43 | updateCalendar(calendar);
44 | }
45 |
46 | @Override
47 | public void onWeekDaysBindView(View view) {
48 |
49 | }
50 |
51 | @Override
52 | public void onWeekDayBindView(WeekDaysViewAdapter.WeekDayVH holder, String weekDay) {
53 |
54 | }
55 |
56 | @Override
57 | public void onSubViewBindView(View view, String month) {
58 |
59 | }
60 |
61 | @Override
62 | public void onCalendarBindView(View view) {
63 |
64 | }
65 |
66 | @Override
67 | public void onMonthBindView(View view) {
68 |
69 | }
70 |
71 | @Override
72 | public View onMonthCellBindView(View view, CalendarItem currentItem) {
73 | return null;
74 | }
75 |
76 | @Override
77 | public boolean hasImplementedDayCalculation() {
78 | return false;
79 | }
80 |
81 | @Override
82 | public List calculateDays(int year, int month, int firstDayOfMonth, int lastDayOfMonth) {
83 | return null;
84 | }
85 |
86 | @Override
87 | public boolean hasImplementedSelection() {
88 | return false;
89 | }
90 |
91 | @Override
92 | public int setSelected(boolean multipleSelection, DateTime dateSelected) {
93 | return -1;
94 | }
95 |
96 | @Override
97 | public boolean hasImplementedMonthCellBinding() {
98 | return false;
99 | }
100 |
101 | @Override
102 | public View getMonthGridView(View rootView) {
103 | return null;
104 | }
105 |
106 | @Override
107 | public boolean hasImplementedWeekDayNameFormat() {
108 | return false;
109 | }
110 |
111 | @Override
112 | public String formatWeekDayName(String nameOfDay) {
113 | return null;
114 | }
115 |
116 | void updateCalendar(Calendar calendar) {
117 | this.calendar = calendar;
118 | if (firstDaySelectedTxt != null && lastDaySelectedTxt != null) {
119 | DateTime firstDate = calendar.getFirstSelectedDay();
120 | DateTime lastDate = calendar.getLastSelectedDay();
121 | if (firstDate != null) {
122 | firstDaySelectedTxt.setText(firstDate.toString("dd MMMMM yyyy"));
123 | }
124 | if (lastDate != null) {
125 | lastDaySelectedTxt.setText(lastDate.toString("dd MMMMM yyyy"));
126 | }
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/adapter/CalendarViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.LayoutRes;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 |
11 | import com.molo17.customizablecalendar.library.R;
12 | import com.molo17.customizablecalendar.library.components.MonthGridView;
13 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
14 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
15 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
16 | import com.molo17.customizablecalendar.library.view.BaseView;
17 |
18 | import org.joda.time.DateTime;
19 |
20 | /**
21 | * Created by francescofurlan on 23/06/17.
22 | */
23 |
24 | public class CalendarViewAdapter extends RecyclerView.Adapter implements BaseView {
25 | private Context context;
26 | private AUCalendar calendar;
27 | private int layoutResId = -1;
28 | private int dayLayoutResId = -1;
29 | private ViewInteractor viewInteractor;
30 |
31 | public CalendarViewAdapter(Context context) {
32 | this.context = context;
33 | this.calendar = AUCalendar.getInstance();
34 | }
35 |
36 | @Override
37 | public int getItemCount() {
38 | return calendar.getMonths().size();
39 | }
40 |
41 | @Override
42 | public CalendarViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
43 | View rootView;
44 | if (layoutResId != -1 && layoutResId != R.layout.calendar_view) {
45 | rootView = LayoutInflater.from(context).inflate(layoutResId, null);
46 | rootView = viewInteractor.getMonthGridView(rootView);
47 | } else {
48 | MonthGridView monthGridView = new MonthGridView(context);
49 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
50 | monthGridView.setLayoutParams(params);
51 | rootView = monthGridView;
52 | }
53 |
54 | if (viewInteractor != null) {
55 | viewInteractor.onMonthBindView(rootView);
56 | }
57 | return new CalendarViewHolder(rootView, layoutResId, dayLayoutResId, viewInteractor);
58 | }
59 |
60 | @Override
61 | public void onBindViewHolder(final CalendarViewHolder viewHolder, final int position) {
62 | DateTime currentMonth = calendar.getMonths().get(position);
63 | viewHolder.monthView.setCurrentMonth(currentMonth);
64 | }
65 |
66 | @Override
67 | public void refreshData() {
68 | notifyDataSetChanged();
69 | }
70 |
71 | @Override
72 | public void setLayoutResId(@LayoutRes int layoutResId) {
73 | this.layoutResId = layoutResId;
74 | }
75 |
76 | public void setDayLayoutResId(@LayoutRes int layoutResId) {
77 | this.dayLayoutResId = layoutResId;
78 | }
79 |
80 | @Override
81 | public void injectViewInteractor(ViewInteractor viewInteractor) {
82 | this.viewInteractor = viewInteractor;
83 | }
84 |
85 | @Override
86 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
87 | }
88 |
89 | static class CalendarViewHolder extends RecyclerView.ViewHolder {
90 | MonthGridView monthView;
91 |
92 | CalendarViewHolder(View view, int layoutResId, int dayLayoutResId, ViewInteractor viewInteractor) {
93 | super(view);
94 | monthView = (MonthGridView) view;
95 | monthView.setLayoutResId(layoutResId);
96 | monthView.setDayLayoutResId(dayLayoutResId);
97 | monthView.injectViewInteractor(viewInteractor);
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/MonthGridView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.LayoutRes;
6 | import android.support.annotation.Nullable;
7 | import android.util.AttributeSet;
8 | import android.view.LayoutInflater;
9 | import android.widget.GridView;
10 | import android.widget.LinearLayout;
11 |
12 | import com.molo17.customizablecalendar.library.R;
13 | import com.molo17.customizablecalendar.library.adapter.MonthAdapter;
14 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
15 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
16 | import com.molo17.customizablecalendar.library.model.CalendarItem;
17 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
18 | import com.molo17.customizablecalendar.library.view.BaseView;
19 |
20 | import org.joda.time.DateTime;
21 |
22 | /**
23 | * Created by francescofurlan on 23/06/17.
24 | */
25 |
26 | public class MonthGridView extends LinearLayout implements BaseView {
27 | protected DateTime monthDateTime;
28 | private MonthAdapter calendarAdapter;
29 | private GridView calendarGrid;
30 | private DateTime currentMonth;
31 | private
32 | @LayoutRes
33 | int layoutResId = -1;
34 | private
35 | @LayoutRes
36 | int dayLayoutResId = -1;
37 | private ViewInteractor viewInteractor;
38 |
39 | public MonthGridView(Context context) {
40 | this(context, null);
41 | }
42 |
43 | public MonthGridView(Context context, @Nullable AttributeSet attrs) {
44 | this(context, attrs, 0);
45 | }
46 |
47 | public MonthGridView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
48 | super(context, attrs, defStyleAttr);
49 | init(context, attrs);
50 | }
51 |
52 | private void init(Context context, AttributeSet attrs) {
53 | monthDateTime = new DateTime();
54 | layoutResId = R.layout.calendar_view;
55 |
56 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomizableCalendar);
57 | if (typedArray != null) {
58 | layoutResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_month_layout, R.layout.calendar_view);
59 | dayLayoutResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_cell_layout, R.layout.calendar_cell);
60 | typedArray.recycle();
61 | }
62 |
63 | }
64 |
65 | @Override
66 | public void setLayoutResId(@LayoutRes int layoutResId) {
67 | if (layoutResId != -1) {
68 | this.layoutResId = layoutResId;
69 | }
70 | }
71 |
72 | public void setDayLayoutResId(int dayLayoutResId) {
73 | if (layoutResId != -1) {
74 | this.dayLayoutResId = dayLayoutResId;
75 | }
76 | }
77 |
78 | @Override
79 | public void injectViewInteractor(ViewInteractor viewInteractor) {
80 | this.viewInteractor = viewInteractor;
81 | bindViews();
82 | setupCalendar();
83 | }
84 |
85 | @Override
86 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
87 |
88 | }
89 |
90 | private void bindViews() {
91 | LinearLayout calendarLayout = (LinearLayout) LayoutInflater.from(getContext()).inflate(layoutResId, this);
92 | calendarGrid = (GridView) calendarLayout.findViewById(android.R.id.widget_frame);
93 | }
94 |
95 | private void setupCalendar() {
96 | if (currentMonth == null) {
97 | currentMonth = AUCalendar.getInstance().getCurrentMonth();
98 | }
99 | calendarAdapter = new MonthAdapter(getContext(), currentMonth);
100 |
101 | calendarAdapter.setLayoutResId(dayLayoutResId);
102 |
103 | calendarAdapter.injectViewInteractor(viewInteractor);
104 |
105 | calendarAdapter.refreshDays();
106 |
107 | calendarGrid.setAdapter(calendarAdapter);
108 |
109 | calendarGrid.setOnItemClickListener((parent, view, position, id) -> {
110 | Object currentObj = calendarAdapter.getItem(position);
111 | if (currentObj != null) {
112 | CalendarItem calendarItem = (CalendarItem) currentObj;
113 | if (calendarItem.isSelectable()) {
114 | calendarAdapter.setSelected(calendarItem.getDateTime());
115 | }
116 | }
117 | });
118 | }
119 |
120 | @Override
121 | public void refreshData() {
122 | setupCalendar();
123 | }
124 |
125 | public void subscribe() {
126 | if (calendarAdapter != null) {
127 | calendarAdapter.subscribe();
128 | }
129 | }
130 |
131 | public void unsubscribe() {
132 | if (calendarAdapter != null) {
133 | calendarAdapter.unsubscribe();
134 | }
135 | }
136 |
137 | public void setCurrentMonth(DateTime currentMonth) {
138 | this.currentMonth = currentMonth;
139 | setupCalendar();
140 | }
141 | }
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/components/CalendarRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.components;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.support.annotation.LayoutRes;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.PagerSnapHelper;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.util.AttributeSet;
10 | import android.view.View;
11 |
12 | import com.molo17.customizablecalendar.library.R;
13 | import com.molo17.customizablecalendar.library.adapter.CalendarViewAdapter;
14 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
15 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
16 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
17 | import com.molo17.customizablecalendar.library.view.CalendarView;
18 |
19 | import org.joda.time.DateTime;
20 |
21 | /**
22 | * Created by francescofurlan on 23/06/17.
23 | */
24 |
25 | public class CalendarRecyclerView extends RecyclerView implements CalendarView {
26 | private CalendarViewAdapter calendarViewAdapter;
27 | private ViewInteractor viewInteractor;
28 | private Context context;
29 | private CustomizableCalendarPresenter presenter;
30 | private AUCalendar calendar;
31 | private
32 | @LayoutRes
33 | int monthResId = R.layout.calendar_view;
34 | private
35 | @LayoutRes
36 | int monthCellResId = R.layout.calendar_cell;
37 |
38 | public CalendarRecyclerView(Context context) {
39 | this(context, null);
40 | }
41 |
42 | public CalendarRecyclerView(Context context, AttributeSet attrs) {
43 | this(context, attrs, 0);
44 | }
45 |
46 | public CalendarRecyclerView(Context context, AttributeSet attrs, int defStyle) {
47 | super(context, attrs, defStyle);
48 | init(context, attrs);
49 | }
50 |
51 | private void init(Context context, AttributeSet attrs) {
52 | this.context = context;
53 |
54 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomizableCalendar);
55 | if (typedArray != null) {
56 | monthResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_month_layout, R.layout.calendar_view);
57 | monthCellResId = typedArray.getResourceId(R.styleable.CustomizableCalendar_cell_layout, R.layout.calendar_cell);
58 | typedArray.recycle();
59 | }
60 |
61 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
62 | linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
63 | setLayoutManager(linearLayoutManager);
64 | this.calendar = AUCalendar.getInstance();
65 | }
66 |
67 | @Override
68 | public void refreshData() {
69 | calendarViewAdapter.refreshData();
70 | }
71 |
72 | @Override
73 | public void setLayoutResId(@LayoutRes int layoutResId) {
74 |
75 | }
76 |
77 | @Override
78 | public void injectViewInteractor(ViewInteractor viewInteractor) {
79 | this.viewInteractor = viewInteractor;
80 | if (viewInteractor != null) {
81 | viewInteractor.onCalendarBindView(this);
82 | }
83 | setupCalendarAdapter();
84 | setupCalendarScroll();
85 | }
86 |
87 | @Override
88 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
89 | this.presenter = presenter;
90 | this.presenter.injectCalendarView(this);
91 | }
92 |
93 | private void setupCalendarAdapter() {
94 | calendarViewAdapter = new CalendarViewAdapter(context);
95 | calendarViewAdapter.injectViewInteractor(viewInteractor);
96 | calendarViewAdapter.setLayoutResId(monthResId);
97 | calendarViewAdapter.setDayLayoutResId(monthCellResId);
98 | setAdapter(calendarViewAdapter);
99 | }
100 |
101 | private void setupCalendarScroll() {
102 | PagerSnapHelper snapHelper = new PagerSnapHelper();
103 | snapHelper.attachToRecyclerView(this);
104 | addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {
105 | @Override
106 | public void onChildViewAttachedToWindow(View view) {
107 | MonthGridView monthGridView = (MonthGridView) view;
108 | monthGridView.subscribe();
109 | }
110 |
111 | @Override
112 | public void onChildViewDetachedFromWindow(View view) {
113 | MonthGridView monthGridView = (MonthGridView) view;
114 | monthGridView.unsubscribe();
115 | }
116 | });
117 |
118 | addOnScrollListener(new OnScrollListener() {
119 | @Override
120 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
121 | super.onScrollStateChanged(recyclerView, newState);
122 | switch (newState) {
123 | case SCROLL_STATE_IDLE: {
124 | View view = snapHelper.findSnapView(getLayoutManager());
125 | if (view != null) {
126 | int currentPosition = getChildAdapterPosition(view);
127 | DateTime currentMonth = calendar.getMonths().get(currentPosition);
128 | calendar.setCurrentMonth(currentMonth);
129 | }
130 | }
131 | }
132 | }
133 | });
134 | }
135 |
136 | @Override
137 | public void setMonthLayoutResId(@LayoutRes int layoutResId) {
138 | calendarViewAdapter.setLayoutResId(layoutResId);
139 | }
140 |
141 | @Override
142 | public void setDayLayoutResId(@LayoutRes int layoutResId) {
143 | calendarViewAdapter.setDayLayoutResId(layoutResId);
144 | }
145 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/interactors/AUCalendar.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.interactors;
2 |
3 | import com.molo17.customizablecalendar.library.model.Calendar;
4 | import com.molo17.customizablecalendar.library.model.CalendarFields;
5 |
6 | import org.joda.time.DateTime;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import io.reactivex.BackpressureStrategy;
12 | import io.reactivex.Flowable;
13 | import io.reactivex.FlowableEmitter;
14 |
15 | /**
16 | * Created by francescofurlan on 30/06/17.
17 | */
18 |
19 | public class AUCalendar {
20 | private static AUCalendar AUCalendarInstance;
21 | private Calendar calendar;
22 | private List onChangeListenerList = new ArrayList<>();
23 |
24 | public static AUCalendar getInstance() {
25 | if (AUCalendarInstance == null) {
26 | AUCalendarInstance = new AUCalendar();
27 | }
28 | return AUCalendarInstance;
29 | }
30 |
31 | public static AUCalendar getInstance(Calendar calendar) {
32 | getInstance();
33 | if (calendar != null) {
34 | AUCalendarInstance.setCalendar(calendar);
35 | }
36 | return AUCalendarInstance;
37 | }
38 |
39 | public DateTime getFirstMonth() {
40 | return calendar.getFirstMonth();
41 | }
42 |
43 | public Calendar getCalendar() {
44 | return calendar;
45 | }
46 |
47 | public void setCalendar(Calendar calendar) {
48 | this.calendar = calendar;
49 | }
50 |
51 | public Flowable observeChangesOnCalendar() {
52 | return Flowable.create((FlowableEmitter emitter) -> {
53 | CalendarObjectChangeListener objectChangeListener = emitter::onNext;
54 | addChangeListener(objectChangeListener);
55 | emitter.setCancellable(() -> removeChangeListener(objectChangeListener));
56 | }, BackpressureStrategy.BUFFER);
57 | }
58 |
59 | private void addChangeListener(CalendarObjectChangeListener objectChangeListener) {
60 | onChangeListenerList.add(objectChangeListener);
61 | }
62 |
63 | private void removeChangeListener(CalendarObjectChangeListener objectChangeListener) {
64 | onChangeListenerList.remove(objectChangeListener);
65 | }
66 |
67 | private void emitOnChange(ChangeSet changeSet) {
68 | for (CalendarObjectChangeListener onChangeListener : onChangeListenerList) {
69 | onChangeListener.onChange(changeSet);
70 | }
71 | }
72 |
73 | private void emitOnChange(String changedField) {
74 | CalendarChangeSet changeSet = new CalendarChangeSet();
75 | changeSet.addChangedField(changedField);
76 | emitOnChange(changeSet);
77 | }
78 |
79 | public DateTime getFirstSelectedDay() {
80 | return calendar.getFirstSelectedDay();
81 | }
82 |
83 | public void setFirstSelectedDay(DateTime firstSelectedDay) {
84 | if (calendar.getFirstSelectedDay() != firstSelectedDay) {
85 | calendar.setFirstSelectedDay(firstSelectedDay);
86 | emitOnChange(CalendarFields.FIRST_SELECTED_DAY);
87 | }
88 | }
89 |
90 | public DateTime getLastSelectedDay() {
91 | return calendar.getLastSelectedDay();
92 | }
93 |
94 | public void setLastSelectedDay(DateTime lastSelectedDay) {
95 | if (calendar.getLastSelectedDay() != lastSelectedDay) {
96 | calendar.setLastSelectedDay(lastSelectedDay);
97 | emitOnChange(CalendarFields.LAST_SELECTED_DAY);
98 | }
99 | }
100 |
101 | public DateTime getCurrentMonth() {
102 | return calendar.getCurrentMonth();
103 | }
104 |
105 | public void setCurrentMonth(DateTime currentMonth) {
106 | if (calendar.getCurrentMonth() != currentMonth) {
107 | calendar.setCurrentMonth(currentMonth);
108 | emitOnChange(CalendarFields.CURRENT_MONTH);
109 | }
110 | }
111 |
112 | public List getMonths() {
113 | return calendar.getMonths();
114 | }
115 |
116 | public void setMonths(List months) {
117 | if (calendar.getMonths() != months) {
118 | calendar.setMonths(months);
119 | emitOnChange(CalendarFields.MONTHS);
120 | }
121 | }
122 |
123 | public boolean isMultipleSelectionEnabled() {
124 | return calendar.isMultipleSelectionEnabled();
125 | }
126 |
127 | public void setMultipleSelection(boolean multipleSelection) {
128 | if (calendar.isMultipleSelectionEnabled() != multipleSelection) {
129 | calendar.setMultipleSelection(multipleSelection);
130 | emitOnChange(CalendarFields.MULTIPLE_SELECTION);
131 | }
132 | }
133 |
134 | public int getFirstDayOfWeek() {
135 | return calendar.getFirstDayOfWeek();
136 | }
137 |
138 | public void setFirstDayOfWeek(int firstDayOfWeek) {
139 | if (calendar.getFirstDayOfWeek() != firstDayOfWeek) {
140 | calendar.setFirstDayOfWeek(firstDayOfWeek);
141 | emitOnChange(CalendarFields.FIRST_DAY_OF_WEEK);
142 | }
143 | }
144 |
145 | public interface ChangeSet {
146 | List getChangedFields();
147 |
148 | boolean isFieldChanged(String fieldName);
149 |
150 | String toString();
151 | }
152 |
153 | public interface CalendarObjectChangeListener {
154 | void onChange(ChangeSet changeSet);
155 | }
156 |
157 | private class CalendarChangeSet implements ChangeSet {
158 | private List changedFields = new ArrayList<>();
159 |
160 | public void setChangedFiels(List changedFields) {
161 | this.changedFields = changedFields;
162 | }
163 |
164 | public void addChangedField(String changedField) {
165 | this.changedFields.add(changedField);
166 | }
167 |
168 | @Override
169 | public List getChangedFields() {
170 | return changedFields;
171 | }
172 |
173 | @Override
174 | public boolean isFieldChanged(String fieldName) {
175 | return changedFields.contains(fieldName);
176 | }
177 |
178 | @Override
179 | public String toString() {
180 | StringBuilder fieldChanges = new StringBuilder();
181 | for (String fieldChanged : changedFields) {
182 | fieldChanges.append(" ").append(fieldChanged);
183 | }
184 | return fieldChanges.toString();
185 | }
186 | }
187 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/presenter/implementations/CustomizableCalendarPresenterImpl.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.presenter.implementations;
2 |
3 | import android.support.annotation.LayoutRes;
4 | import android.text.TextUtils;
5 | import android.view.View;
6 |
7 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
8 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
9 | import com.molo17.customizablecalendar.library.model.CalendarFields;
10 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
11 | import com.molo17.customizablecalendar.library.view.CalendarView;
12 | import com.molo17.customizablecalendar.library.view.CustomizableCalendarView;
13 | import com.molo17.customizablecalendar.library.view.HeaderView;
14 | import com.molo17.customizablecalendar.library.view.SubView;
15 | import com.molo17.customizablecalendar.library.view.WeekDaysView;
16 |
17 | import org.joda.time.DateTime;
18 |
19 | import java.text.DateFormatSymbols;
20 | import java.util.ArrayList;
21 | import java.util.List;
22 | import java.util.Locale;
23 |
24 | import io.reactivex.disposables.CompositeDisposable;
25 |
26 | /**
27 | * Created by francescofurlan on 23/06/17.
28 | */
29 |
30 | public class CustomizableCalendarPresenterImpl implements CustomizableCalendarPresenter {
31 | private AUCalendar calendar;
32 | private CalendarView calendarView;
33 | private HeaderView headerView;
34 | private SubView subView;
35 | private WeekDaysView weekDaysView;
36 | private ViewInteractor viewInteractor;
37 | private CustomizableCalendarView view;
38 | private CompositeDisposable subscriptions = new CompositeDisposable();
39 |
40 | @Override
41 | public void injectViewInteractor(ViewInteractor viewInteractor) {
42 | this.viewInteractor = viewInteractor;
43 | }
44 |
45 | @Override
46 | public void setLayoutResId(@LayoutRes int layoutResId) {
47 | view.setLayoutResId(layoutResId);
48 | }
49 |
50 | @Override
51 | public void setView(CustomizableCalendarView view) {
52 | this.view = view;
53 | if (viewInteractor != null) {
54 | view.injectViewInteractor(viewInteractor);
55 | }
56 | calendar = AUCalendar.getInstance();
57 | subscriptions.add(
58 | calendar.observeChangesOnCalendar()
59 | .subscribe(changeSet -> {
60 | boolean currentMonthChanged = changeSet.isFieldChanged(CalendarFields.CURRENT_MONTH);
61 | boolean firstDayOfWeekChanged = changeSet.isFieldChanged(CalendarFields.FIRST_DAY_OF_WEEK);
62 | boolean firstSelectedDayChanged = changeSet.isFieldChanged(CalendarFields.FIRST_SELECTED_DAY);
63 | boolean lastSelectedDayChanged = changeSet.isFieldChanged(CalendarFields.LAST_SELECTED_DAY);
64 |
65 | if (currentMonthChanged) {
66 | onCurrentMonthChanged(calendar.getCurrentMonth());
67 | }
68 |
69 | if (firstDayOfWeekChanged) {
70 | if (weekDaysView != null) {
71 | weekDaysView.onFirstDayOfWeek(calendar.getFirstDayOfWeek());
72 | }
73 | }
74 |
75 | if (firstDayOfWeekChanged || firstSelectedDayChanged || lastSelectedDayChanged) {
76 | if (calendarView != null) {
77 | calendarView.refreshData();
78 | }
79 | }
80 | })
81 | );
82 | }
83 |
84 | @Override
85 | public void onBindView(View rootView) {
86 | viewInteractor.onCustomizableCalendarBindView(rootView);
87 | }
88 |
89 | private void onCurrentMonthChanged(DateTime currentMonth) {
90 | String month = currentMonth.toString("MMMMM", Locale.getDefault());
91 | if (view != null && !TextUtils.isEmpty(month)) {
92 | String formattedMonth = month.substring(0, 1).toUpperCase(Locale.getDefault()) + month.substring(1);
93 | view.onCurrentMonthChanged(formattedMonth);
94 | }
95 | }
96 |
97 | @Override
98 | public void injectCalendarView(CalendarView calendarView) {
99 | this.calendarView = calendarView;
100 | this.calendarView.injectViewInteractor(viewInteractor);
101 | }
102 |
103 | @Override
104 | public void injectHeaderView(HeaderView headerView) {
105 | this.headerView = headerView;
106 | this.headerView.injectViewInteractor(viewInteractor);
107 | }
108 |
109 | @Override
110 | public void injectSubView(SubView subView) {
111 | this.subView = subView;
112 | this.subView.injectViewInteractor(viewInteractor);
113 | }
114 |
115 | @Override
116 | public void injectWeekDaysView(WeekDaysView weekDaysView) {
117 | this.weekDaysView = weekDaysView;
118 | this.weekDaysView.injectViewInteractor(viewInteractor);
119 | }
120 |
121 | @Override
122 | public List setupWeekDays() {
123 | String[] namesOfDays = DateFormatSymbols.getInstance(Locale.getDefault()).getShortWeekdays();
124 | int firstDayOfWeek = calendar.getFirstDayOfWeek();
125 |
126 | List weekDays = new ArrayList<>();
127 | for (int i = firstDayOfWeek; i < namesOfDays.length; i++) {
128 | String nameOfDay = namesOfDays[i];
129 | String formattedNameOfDay = getFormattedDayOfDay(nameOfDay);
130 | if (formattedNameOfDay != null) {
131 | weekDays.add(formattedNameOfDay);
132 | }
133 | }
134 | for (int i = 0; i < firstDayOfWeek; i++) {
135 | String nameOfDay = namesOfDays[i];
136 | String formattedNameOfDay = getFormattedDayOfDay(nameOfDay);
137 | if (formattedNameOfDay != null) {
138 | weekDays.add(formattedNameOfDay);
139 | }
140 | }
141 | return weekDays;
142 | }
143 |
144 | private String getFormattedDayOfDay(String nameOfDay) {
145 | if (!TextUtils.isEmpty(nameOfDay)) {
146 | if (viewInteractor.hasImplementedWeekDayNameFormat()) {
147 | return viewInteractor.formatWeekDayName(nameOfDay);
148 | } else {
149 | return nameOfDay.substring(0, 1).toUpperCase(Locale.getDefault());
150 | }
151 | }
152 | return null;
153 | }
154 |
155 | // @Override
156 | // public void setCustomizableCalendarLayoutResId(@LayoutRes int resId) {
157 | // if (view != null) {
158 | // view.setLayoutResId(resId);
159 | // }
160 | // }
161 | //
162 | // @Override
163 | // public void setHeaderLayoutResId(@LayoutRes int resId) {
164 | // if (headerView != null) {
165 | // headerView.setLayoutResId(resId);
166 | // }
167 | // }
168 | //
169 | // @Override
170 | // public void setWeekDayResId(@LayoutRes int resId) {
171 | // if (weekDaysView != null) {
172 | // weekDaysView.setLayoutResId(resId);
173 | // }
174 | // }
175 | //
176 | // @Override
177 | // public void setSubViewResId(@LayoutRes int resId) {
178 | // if (subView != null) {
179 | // subView.setLayoutResId(resId);
180 | // }
181 | // }
182 | //
183 | // @Override
184 | // public void setMonthResId(@LayoutRes int resId) {
185 | // if (calendarView != null) {
186 | // calendarView.setMonthLayoutResId(resId);
187 | // }
188 | // }
189 | //
190 | // @Override
191 | // public void setDayResId(@LayoutRes int resId) {
192 | // if (calendarView != null) {
193 | // calendarView.setDayLayoutResId(resId);
194 | // }
195 | // }
196 | }
197 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # CustomizableCalendar
7 |
8 | This library allows you to create a completely customizable calendar.
9 |
You can use `CustomizableCalendar` to create your calendar, customizing UI and behaviour.
10 |
11 |
12 |
13 |
14 |
15 | # Features
16 |
17 | * Custom header (should be implemented by the user);
18 | * Custom sub view (month name by default);
19 | * Custom weekly days view;
20 | * Custom date view;
21 | * Possibility to implement selection on day click;
22 | * Possibility to implement weekly day calculation;
23 | * Receive updates of Calendar (with AUCalendar);
24 | * Every change to AUCalendar is notified and automatically refreshes UI;
25 |
26 | # Limitations
27 |
28 | * Only portrait orientation is supported
29 |
30 | # Gradle
31 | ```gradle
32 | allprojects {
33 | repositories {
34 | ...
35 | maven { url "https://jitpack.io" }
36 | }
37 | }
38 | ```
39 |
40 | ```gradle
41 | dependencies {
42 | compile 'com.github.MOLO17:CustomizableCalendar:v0.1.4'
43 | }
44 | ```
45 |
46 | # Dependencies
47 |
48 | * RecyclerView
49 | * [Joda-Time](https://github.com/JodaOrg/joda-time)
50 | * [RxJava2](https://github.com/ReactiveX/RxJava)
51 | * ~[ButterKnife](https://github.com/JakeWharton/butterknife)~ used on version <= 0.1.3
52 | * ~[Retrolambda](https://github.com/orfjackal/retrolambda)~ used on version <= 0.1.3
53 |
54 | # Usage
55 |
56 | ## Add to your layout
57 |
58 | ### XML
59 |
60 | Add CustomizableCalendar to your layout
61 |
62 | ```xml
63 |
67 | ```
68 |
69 | ### Java
70 |
71 | First of all you should create a class that implements `ViewInteractor` interface (you can find the explanation in the `How to customize > Java` section).
72 |
73 | After that go in the Activity/Fragment where you added the `CustomizableCalendar` View;
74 | here you should specify the first month and the last month, to do this, create a `Calendar` (located in `com.molo17.customizablecalendar.library.model`) object.
75 |
76 | An example of `CustomizableCalendar` init is the following:
77 | ```java
78 | ...
79 |
80 | @BindView(R.id.customizable_calendar)
81 | CustomizableCalendar customizableCalendar;
82 |
83 | private CompositeDisposable subscriptions;
84 |
85 | ...
86 |
87 | @Override
88 | protected void onCreate(Bundle savedInstanceState) {
89 | super.onCreate(savedInstanceState);
90 | setContentView(R.layout.activity_main);
91 | ButterKnife.bind(this);
92 |
93 | DateTime today = new DateTime();
94 |
95 | // setting up first and last month that must be showed in the calendar
96 | DateTime firstMonth = today.withDayOfMonth(1);
97 | DateTime lastMonth = today.plusMonths(3).withDayOfMonth(1);
98 |
99 | // create the Calendar obj and setting it up with some configs like:
100 | // - first selected day
101 | // - last selected day
102 | // - multiple selection
103 |
104 | final Calendar calendar = new Calendar(firstMonth, lastMonth);
105 | calendar.setFirstSelectedDay(today.plusDays(4));
106 |
107 | // if you don't want the multiple selection mode just skip the 2 lines below
108 | calendar.setLastSelectedDay(today.plusDays(6));
109 | calendar.setMultipleSelection(true);
110 |
111 | // create a ViewInteractor obj needed to interact with the CustomizableCalendar
112 | final YourViewInteractorClass calendarViewInteractor = new YourViewInteractorClass();
113 |
114 | // create an AUCalendar object (a Calendar wrapper that operates as a singleton and provides all the updates)
115 | AUCalendar auCalendar = AUCalendar.getInstance(calendar);
116 |
117 | // this is needed to receives all Calendar updates (using RxJava 2)
118 | subscriptions.add(
119 | auCalendar.observeChangesOnCalendar().subscribe(new Consumer() {
120 | @Override
121 | public void accept(AUCalendar.ChangeSet changeSet) throws Exception {
122 | // with ChangeSet you can be aware of which Calendar fields are changed
123 | // you can use changeSet.isFieldChanged(...) passing the name of the field;
124 | // name of the fields can be retrieved using CalendarFields interface;
125 | // AUCalendar is already updated because it's a singleton,
126 | // so for retrieving the updated data you can just use AUCalendar getters
127 | }
128 | })
129 | );
130 |
131 | // injecting the ViewInteractor to the CustomizableCalendar View
132 | customizableCalendar.injectViewInteractor(calendarViewInteractor)
133 | }
134 |
135 | @Override
136 | protected void onDestroy() {
137 | super.onDestroy();
138 | subscriptions.clear();
139 | }
140 |
141 | ...
142 | ```
143 |
144 | ## How to customize
145 |
146 | ### XML
147 |
148 | If you want to customize the components you should create a separeted layout and add the reference to the `customizable_calendar` View with the tag `app:layout="@layout/your_layout"`
149 |
150 | An example of a custom layout is the following:
151 |
152 | ```xml
153 |
154 |
160 |
161 |
165 |
166 |
171 |
172 |
178 |
179 |
184 |
185 |
186 | ```
187 | **NOTE** that ids must not be different from the ones above, so:
188 | * `@android:id/primary` for **HeaderView**;
189 | * `@android:id/text1` for **WeekDaysView**;
190 | * `@android:id/text2` for **SubView**;
191 | * `@android:id/content` for **CalendarRecyclerView**;
192 |
193 |
194 |
195 |
196 |
197 | #### HeaderView
198 |
199 | First (red) rectangle of the screenshot above.
200 |
It's a `RelativeLayout`, you should create your own layout.
201 |
202 | #### WeekDaysView
203 |
204 | Third (light blue) rectangle of the screenshot above.
205 |
It's a `RecyclerView`, the ViewHolder item is already implemented.
206 |
You can create your own ViewHolder layout using a `RelativeLayout` with a `TextView` that has `@android:id/summary` as id.
207 |
208 | #### SubView
209 |
210 | Second (green) rectangle of the screenshot above.
211 |
It's a `RelativeLayout`, implemented by default with the name of the month centered.
212 |
If you want to create your own layout make sure to have a `TextView` with id `@android:id/summary`.
213 |
214 | #### CalendarRecyclerView
215 |
216 | Fourth (blue) rectangle of the screenshot above.
217 |
It's a `RelativeLayout`, implemented by default with a `LinearLayout` (with a `GridLayout` inside) for the month and a `RelativeLayout` for the day.
218 |
If you want to create your own month layout you can specify `app:month_layout="@layout/your_layout"` for the month and `app:cell_layout="@layout/your_layout"` for the day.
219 |
Make sure to use `@android:id/widget_frame` as id for the `GridView` and `@android:id/background`, `@android:id/startSelectingText`, `@android:id/stopSelectingText`, `@android:id/title` respectively for single selection background, first day selection background (in multiple selection mode), last day selection background (in multiple selection mode) and the `TextView` where the day is displayed.
220 |
221 | ### Java
222 |
223 | All code customization can be applied using the `ViewInteractor`.
224 |
225 | Here are listed all of the methods with a small description:
226 | * `void onCustomizableCalendarBindView(View view)`
227 |
Here you can customize the `CustomizableCalendar` View.
228 |
This method is called after `customizableCalendar.injectViewInteractor(...)`.
229 |
230 | * `void onHeaderBindView(ViewGroup view)`
231 |
Here you can customize the `HeaderView` View, inflating your layout etc...
232 |
This method is called after `headerView.injectViewInteractor(...)`.
233 |
234 | * `void onWeekDaysBindView(View view)`
235 |
Here you can customize the `WeekDays` View.
236 |
This method is called after `weekDays.injectViewInteractor(...)`.
237 |
238 | * `void onWeekDayBindView(WeekDaysViewAdapter.WeekDayVH holder, String weekDay)`
239 |
Here you can customize the `WeekDayVH` ViewHolder.
240 |
This method is called after `onBindViewHolder` of `WeekDaysViewAdapter`.
241 |
242 | * `void onSubViewBindView(View view, String month)`
243 |
Here you can customize the `SubView` View.
244 |
This method is called after `onMonthChanged`.
245 |
246 | * `void onCalendarBindView(View view)`
247 |
Here you can customize the `CalendarRecyclerView` View.
248 |
This method is called after `calendarRecyclerView.injectViewInteractor(...)`.
249 |
250 | * `void onMonthBindView(View view)`
251 |
Here you can customize the `MonthGridView` View.
252 |
This method is called after `onCreateViewHolder` of `CalendarViewAdapter`.
253 |
254 | * `View onMonthCellBindView(View view, CalendarItem currentItem)`
255 |
Here you can customize the `GridViewCell` View.
256 |
This method is called in the `getView` of `MonthAdapter`, you must return the customized view.
257 |
258 | * `boolean hasImplementedMonthCellBinding()`
259 |
Here you should return `true` if you have implemented the above method (`onMonthCellBindView`).
260 |
This method is called in the `getView` method of `MonthAdapter`.
261 |
262 | * `List calculateDays(int year, int month, int firstDayOfMonth, int lastDayOfMonth)`
263 |
Here you can calculate the days of the month (if you want for example to include `Saturday` and `Sunday`)
264 |
This method is called in the `getView` of `MonthAdapter`.
265 |
266 | * `boolean hasImplementedDayCalculation()`
267 |
Here you should return `true` if you have implemented the above method (`calculateDays`).
268 |
This method is called in the `refreshDays` method of `MonthAdapter`.
269 |
270 | * `int setSelected(boolean multipleSelection, DateTime dateSelected)`
271 |
Here you can calculate the selection of the day.
272 |
This method is called in the `setSelected` method of `MonthAdapter`.
273 |
You must return 0, 1 or -1 respectively for `first selection`, `last selection` and `no selection`.
274 |
275 | * `boolean hasImplementedSelection()`
276 |
Here you should return `true` if you have implemented the above method (`setSelected`).
277 |
This method is called in the `setSelected` method of `MonthAdapter`.
278 |
279 | * `String formatWeekDayName(String nameOfDay);`
280 |
Here you can format the name of the week day.
281 |
This method is called after `injectViewInteractor` method of `WeekDaysView`.
282 |
You should return the formatted name of the week day.
283 |
284 | * `boolean hasImplementedWeekDayNameFormat()`
285 |
Here you should return `true` if you have implemented the above method (`formatWeekDayName`).
286 |
This method is called after `injectViewInteractor` method of `WeekDaysView`.
287 |
288 | * `View getMonthGridView(View rootView)`
289 |
Here you can create your customized `MonthGridView`.
290 |
You should return a `MonthGridView`.
291 |
This method is called in the `onCreateViewHolder` method of `CalendarViewAdapter`.
292 |
293 | Getting Help
294 | ------------
295 | To report a specific problem or feature request, [open a new issue here on Github](https://github.com/MOLO17/CustomizableCalendar/issues/new). For questions, suggestions, or anything else, email us at sales@molo17.com.
296 |
--------------------------------------------------------------------------------
/library/src/main/java/com/molo17/customizablecalendar/library/adapter/MonthAdapter.java:
--------------------------------------------------------------------------------
1 | package com.molo17.customizablecalendar.library.adapter;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.support.annotation.LayoutRes;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.BaseAdapter;
10 | import android.widget.TextView;
11 |
12 | import com.molo17.customizablecalendar.library.R;
13 | import com.molo17.customizablecalendar.library.interactors.AUCalendar;
14 | import com.molo17.customizablecalendar.library.interactors.ViewInteractor;
15 | import com.molo17.customizablecalendar.library.model.CalendarFields;
16 | import com.molo17.customizablecalendar.library.model.CalendarItem;
17 | import com.molo17.customizablecalendar.library.presenter.interfeaces.CustomizableCalendarPresenter;
18 | import com.molo17.customizablecalendar.library.utils.DateUtils;
19 | import com.molo17.customizablecalendar.library.view.MonthView;
20 |
21 | import org.joda.time.DateTime;
22 |
23 | import java.util.ArrayList;
24 | import java.util.Calendar;
25 | import java.util.List;
26 |
27 | import io.reactivex.disposables.CompositeDisposable;
28 |
29 | /**
30 | * Created by francescofurlan on 23/06/17.
31 | */
32 |
33 | public class MonthAdapter extends BaseAdapter implements MonthView {
34 | private Context context;
35 | private AUCalendar calendar;
36 | private int layoutResId;
37 | private List days;
38 | private ViewInteractor viewInteractor;
39 |
40 | private DateTime currentMonth;
41 | private DateTime firstSelectedDay;
42 | private DateTime lastSelectedDay;
43 | private boolean multipleSelection;
44 | private int firstDayOfWeek;
45 |
46 | private CompositeDisposable subscriptions;
47 | private boolean subscribed;
48 |
49 | public MonthAdapter(Context context, DateTime currentMonth) {
50 | this.context = context;
51 | this.subscriptions = new CompositeDisposable();
52 | this.calendar = AUCalendar.getInstance();
53 | this.layoutResId = R.layout.calendar_cell;
54 | this.currentMonth = currentMonth.withDayOfMonth(1).withMillisOfDay(0);
55 | initFromCalendar();
56 | subscribe();
57 | }
58 |
59 | private void initFromCalendar() {
60 | firstSelectedDay = calendar.getFirstSelectedDay();
61 | if (firstSelectedDay != null) {
62 | firstSelectedDay = firstSelectedDay.withMillisOfDay(0);
63 | }
64 | lastSelectedDay = calendar.getLastSelectedDay();
65 | if (lastSelectedDay != null) {
66 | lastSelectedDay = lastSelectedDay.withMillisOfDay(0);
67 | }
68 | multipleSelection = calendar.isMultipleSelectionEnabled();
69 | firstDayOfWeek = calendar.getFirstDayOfWeek();
70 | }
71 |
72 | @Override
73 | public int getCount() {
74 | return days.size();
75 | }
76 |
77 | @Override
78 | public Object getItem(int position) {
79 | return days.get(position);
80 | }
81 |
82 | @Override
83 | public long getItemId(int position) {
84 | final CalendarItem item = days.get(position);
85 | if (item != null) {
86 | return days.get(position).getId();
87 | }
88 | return -1;
89 | }
90 |
91 | @Override
92 | public View getView(int position, View view, ViewGroup parent) {
93 | final CalendarItem currentItem = days.get(position);
94 |
95 | if (view == null) {
96 | LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
97 | view = inflater.inflate(layoutResId, null);
98 | }
99 |
100 | if (viewInteractor != null && viewInteractor.hasImplementedMonthCellBinding()) {
101 | view = viewInteractor.onMonthCellBindView(view, currentItem);
102 | } else {
103 | final TextView dayView = view.findViewById(android.R.id.title);
104 | final View background = view.findViewById(android.R.id.background);
105 | final View startSelectionView = view.findViewById(android.R.id.startSelectingText);
106 | final View endSelectionView = view.findViewById(android.R.id.stopSelectingText);
107 |
108 | startSelectionView.setVisibility(View.GONE);
109 | endSelectionView.setVisibility(View.GONE);
110 |
111 | if (currentItem == null) {
112 | background.setBackground(null);
113 | dayView.setText(null);
114 | } else if (currentItem.compareTo(calendar.getFirstMonth().withMillisOfDay(0)) < 0) {
115 | currentItem.setSelectable(false);
116 | background.setBackground(null);
117 | dayView.setTextColor(Color.BLACK);
118 | dayView.setText(currentItem.getDayString());
119 | dayView.setAlpha(0.6f);
120 | } else {
121 | currentItem.setSelectable(true);
122 | dayView.setAlpha(1f);
123 | Integer backgroundResource = null;
124 | if (firstSelectedDay != null) {
125 | int startSelectedCompared = currentItem.compareTo(firstSelectedDay);
126 | if (!multipleSelection) {
127 | if (startSelectedCompared == 0) {
128 | backgroundResource = R.drawable.empty_circle;
129 | }
130 | } else if (startSelectedCompared == 0) {
131 | if (lastSelectedDay == null || lastSelectedDay.equals(currentItem.getDateTime())) {
132 | backgroundResource = R.drawable.circle;
133 | } else {
134 | backgroundResource = R.drawable.left_rounded_rectangle;
135 | endSelectionView.setVisibility(View.VISIBLE);
136 | }
137 | } else if (startSelectedCompared > 0 && lastSelectedDay != null) {
138 | int endSelectedCompared = currentItem.compareTo(lastSelectedDay);
139 | if (endSelectedCompared == 0) {
140 | backgroundResource = R.drawable.right_rounded_rectangle;
141 | startSelectionView.setVisibility(View.VISIBLE);
142 | } else if (endSelectedCompared < 0) {
143 | backgroundResource = R.drawable.rectangle;
144 | startSelectionView.setVisibility(View.VISIBLE);
145 | endSelectionView.setVisibility(View.VISIBLE);
146 | }
147 | }
148 | }
149 |
150 | int color = Color.BLACK;
151 | if (backgroundResource != null) {
152 | background.setBackgroundResource(backgroundResource);
153 | if (multipleSelection) {
154 | color = Color.WHITE;
155 | }
156 | } else {
157 | background.setBackground(null);
158 | }
159 |
160 | dayView.setTextColor(color);
161 | dayView.setText(currentItem.getDayString());
162 | }
163 | }
164 |
165 | return view;
166 | }
167 |
168 | @Override
169 | public void refreshData() {
170 | refreshDays();
171 | }
172 |
173 | @Override
174 | public void setLayoutResId(@LayoutRes int layoutResId) {
175 | if (layoutResId != -1) {
176 | this.layoutResId = layoutResId;
177 | }
178 | }
179 |
180 | @Override
181 | public void injectViewInteractor(ViewInteractor viewInteractor) {
182 | this.viewInteractor = viewInteractor;
183 | }
184 |
185 | @Override
186 | public void injectPresenter(CustomizableCalendarPresenter presenter) {
187 | }
188 |
189 | /**
190 | * Select the day specified if multiple selection mode is not enabled,
191 | * otherwise adjust the ends of the selection:
192 | * first end will be set if the day specified is before the first end;
193 | * last end will be set if the day specified is after the last end;
194 | *
195 | * @param dateSelected a DateTime object that represents the day that
196 | * should be selected
197 | */
198 | @Override
199 | public void setSelected(DateTime dateSelected) {
200 | if (viewInteractor != null && viewInteractor.hasImplementedSelection()) {
201 | int itemSelected = viewInteractor.setSelected(multipleSelection, dateSelected);
202 | switch (itemSelected) {
203 | case 0:
204 | notifyFirstSelectionUpdated(dateSelected);
205 | break;
206 | case 1:
207 | notifyLastSelectionUpdated(dateSelected);
208 | break;
209 | default:
210 | return;
211 | }
212 | } else {
213 | if (!multipleSelection) {
214 | notifyFirstSelectionUpdated(dateSelected);
215 | } else {
216 | if (firstSelectedDay != null) {
217 | int startSelectedCompared = dateSelected.compareTo(firstSelectedDay);
218 | if (startSelectedCompared < 0) {
219 | notifyFirstSelectionUpdated(dateSelected);
220 | } else if (lastSelectedDay != null) {
221 | int endSelectedCompared = dateSelected.compareTo(lastSelectedDay);
222 | if ((startSelectedCompared >= 0 && endSelectedCompared < 0) || endSelectedCompared > 0) {
223 | notifyLastSelectionUpdated(dateSelected);
224 | }
225 | } else {
226 | notifyLastSelectionUpdated(dateSelected);
227 | }
228 | } else {
229 | notifyFirstSelectionUpdated(dateSelected);
230 | }
231 | }
232 | }
233 | notifyDataSetChanged();
234 | }
235 |
236 | private void notifyFirstSelectionUpdated(DateTime startSelected) {
237 | this.firstSelectedDay = startSelected;
238 | this.calendar.setFirstSelectedDay(startSelected);
239 | }
240 |
241 | private void notifyLastSelectionUpdated(DateTime endSelected) {
242 | this.lastSelectedDay = endSelected;
243 | this.calendar.setLastSelectedDay(endSelected);
244 | }
245 |
246 | @Override
247 | public final void refreshDays() {
248 | final int empties;
249 | final int year = currentMonth.getYear();
250 | final int month = currentMonth.getMonthOfYear();
251 | final int firstDayOfMonth = currentMonth.getDayOfWeek() + 1;
252 | final int lastDayOfMonth = DateUtils.getDaysInMonth(month - 1, year);
253 | List updatedDays = new ArrayList<>();
254 |
255 | if (viewInteractor != null && viewInteractor.hasImplementedDayCalculation()) {
256 | days = viewInteractor.calculateDays(year, month, firstDayOfMonth, lastDayOfMonth);
257 | } else {
258 | // default days calculation
259 | if (firstDayOfMonth == firstDayOfWeek) {
260 | empties = 0;
261 | } else if (firstDayOfMonth < firstDayOfWeek) {
262 | empties = Calendar.SATURDAY - (firstDayOfWeek - 1);
263 | } else {
264 | empties = firstDayOfMonth - firstDayOfWeek;
265 | }
266 |
267 | int totDays = lastDayOfMonth + empties;
268 | for (int day = 1, position = 1; position <= totDays; position++) {
269 | if (position > empties) {
270 | updatedDays.add(new CalendarItem(day++, month, year));
271 | } else {
272 | updatedDays.add(null);
273 | }
274 | }
275 |
276 | }
277 | if (!updatedDays.equals(days)) {
278 | days = updatedDays;
279 | notifyDataSetChanged();
280 | }
281 | }
282 |
283 | public void subscribe() {
284 | if (!subscribed) {
285 | subscriptions.add(
286 | calendar.observeChangesOnCalendar()
287 | .subscribe(changeSet -> {
288 | if (changeSet.isFieldChanged(CalendarFields.FIRST_DAY_OF_WEEK)
289 | || changeSet.isFieldChanged(CalendarFields.FIRST_SELECTED_DAY)
290 | || changeSet.isFieldChanged(CalendarFields.LAST_SELECTED_DAY)) {
291 | initFromCalendar();
292 | refreshDays();
293 | }
294 | })
295 | );
296 | subscribed = true;
297 | }
298 | }
299 |
300 | @Override
301 | public void unsubscribe() {
302 | if (subscribed) {
303 | subscriptions.clear();
304 | subscribed = false;
305 | }
306 | }
307 | }
--------------------------------------------------------------------------------