diff --git a/agendacalendarview/build.gradle b/agendacalendarview/build.gradle index f18bfca..6ca395e 100644 --- a/agendacalendarview/build.gradle +++ b/agendacalendarview/build.gradle @@ -1,9 +1,8 @@ apply plugin: 'com.android.library' -apply plugin: 'me.tatarka.retrolambda' android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 28 + buildToolsVersion '27.0.3' android { lintOptions { @@ -13,7 +12,7 @@ android { defaultConfig { minSdkVersion 14 - targetSdkVersion 23 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -34,14 +33,16 @@ android { } } -apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle' - dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) // Google libraries - compile 'com.android.support:appcompat-v7:23.2.0' - compile 'com.android.support:recyclerview-v7:23.2.0' - compile 'com.android.support:design:23.2.0' + //noinspection GradleCompatible + compile 'com.android.support:appcompat-v7:27.1.0' + //noinspection GradleCompatible + compile 'com.android.support:recyclerview-v7:27.1.0' + //noinspection GradleCompatible + compile 'com.android.support:design:27.1.0' + implementation 'com.android.support:support-annotations:27.1.1' // other libraries compile 'se.emilsjolander:stickylistheaders:2.7.0' diff --git a/agendacalendarview/gradle/wrapper/gradle-wrapper.jar b/agendacalendarview/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7a3265e Binary files /dev/null and b/agendacalendarview/gradle/wrapper/gradle-wrapper.jar differ diff --git a/agendacalendarview/gradle/wrapper/gradle-wrapper.properties b/agendacalendarview/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e59e73c --- /dev/null +++ b/agendacalendarview/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Sep 21 15:27:51 IST 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/agendacalendarview/gradlew b/agendacalendarview/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/agendacalendarview/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/agendacalendarview/gradlew.bat b/agendacalendarview/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/agendacalendarview/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java index 7384685..e77b139 100644 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/AgendaCalendarView.java @@ -19,6 +19,7 @@ import com.github.tibolte.agendacalendarview.agenda.AgendaAdapter; import com.github.tibolte.agendacalendarview.agenda.AgendaView; import com.github.tibolte.agendacalendarview.calendar.CalendarView; +import com.github.tibolte.agendacalendarview.calendar.ViewAdapter; import com.github.tibolte.agendacalendarview.models.BaseCalendarEvent; import com.github.tibolte.agendacalendarview.models.CalendarEvent; import com.github.tibolte.agendacalendarview.models.DayItem; @@ -198,8 +199,8 @@ public void init(List eventList, Calendar minDate, Calendar maxDa CalendarManager.getInstance(getContext()).buildCal(minDate, maxDate, locale, new DayItem(), new WeekItem()); // Feed our views with weeks list and events - mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor); + mCalendarView.init(CalendarManager.getInstance(getContext()), mCalendarDayTextColor, mCalendarCurrentDayColor, mCalendarPastDayTextColor); // Load agenda events and scroll to current day AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor); mAgendaView.getAgendaListView().setAdapter(agendaAdapter); @@ -234,6 +235,27 @@ public void init(Locale locale, List lWeeks, List lDays, Li addEventRenderer(new DefaultEventRenderer()); } + public void initWithCustomAdapter(Locale locale, List lWeeks, List lDays, List lEvents, CalendarPickerController calendarPickerController, ViewAdapter adapter) { + mCalendarPickerController = calendarPickerController; + + CalendarManager.getInstance(getContext()).loadCal(locale, lWeeks, lDays, lEvents); + + // Feed our views with weeks list and events + mCalendarView.initWithCustomAdapter(CalendarManager.getInstance(getContext()), adapter); + + // Load agenda events and scroll to current day + AgendaAdapter agendaAdapter = new AgendaAdapter(mAgendaCurrentDayTextColor); + mAgendaView.getAgendaListView().setAdapter(agendaAdapter); + mAgendaView.getAgendaListView().setOnStickyHeaderChangedListener(this); + + // notify that actually everything is loaded + BusProvider.getInstance().send(new Events.EventsFetched()); + Log.d(LOG_TAG, "CalendarEventTask finished"); + + // add default event renderer + addEventRenderer(new DefaultEventRenderer()); + } + public void addEventRenderer(@NonNull final EventRenderer renderer) { AgendaAdapter adapter = (AgendaAdapter) mAgendaView.getAgendaListView().getAdapter(); adapter.addEventRenderer(renderer); diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java index 7ec0730..c65d3d7 100644 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/CalendarManager.java @@ -28,6 +28,7 @@ public class CalendarManager { private Context mContext; private Locale mLocale; + private boolean showAllDates = true; private Calendar mToday = Calendar.getInstance(); private SimpleDateFormat mWeekdayFormatter; private SimpleDateFormat mMonthHalfNameFormat; @@ -180,7 +181,6 @@ public void buildCal(Calendar minDate, Calendar maxDate, Locale locale, IDayItem } public void loadEvents(List eventList, CalendarEvent noEvent) { - for (IWeekItem weekItem : getWeeks()) { for (IDayItem dayItem : weekItem.getDayItems()) { boolean isEventForDay = false; @@ -198,7 +198,7 @@ public void loadEvents(List eventList, CalendarEvent noEvent) { isEventForDay = true; } } - if (!isEventForDay) { + if (!isEventForDay && isShowAllDates()) { Calendar dayInstance = Calendar.getInstance(); dayInstance.setTime(dayItem.getDate()); CalendarEvent copy = noEvent.copy(); @@ -238,13 +238,24 @@ private List getDayCells(Calendar startCal) { } cal.add(Calendar.DATE, offset); - Log.d(LOG_TAG, String.format("Buiding row week starting at %s", cal.getTime())); - for (int c = 0; c < 7; c++) { + if(isShowAllDates()) { + for (int c = 0; c < 7; c++) { + IDayItem dayItem = mCleanDay.copy(); + dayItem.buildDayItemFromCal(cal); + dayItems.add(dayItem); + cal.add(Calendar.DATE, 1); + } + } else { IDayItem dayItem = mCleanDay.copy(); dayItem.buildDayItemFromCal(cal); - dayItems.add(dayItem); - cal.add(Calendar.DATE, 1); + for (CalendarEvent event : getEvents()) { + if (DateHelper.isBetweenInclusive(dayItem.getDate(), event.getStartTime(), event.getEndTime())) { + dayItems.add(dayItem); + cal.add(Calendar.DATE, 1); + } + } } + Log.d(LOG_TAG, String.format("Buiding row week starting at %s", cal.getTime())); mDays.addAll(dayItems); return dayItems; @@ -257,5 +268,13 @@ private void setLocale(Locale locale) { mMonthHalfNameFormat = new SimpleDateFormat(getContext().getString(R.string.month_half_name_format), locale); } + public boolean isShowAllDates() { + return showAllDates; + } + + public void setShowAllDates(boolean showAllDates) { + this.showAllDates = showAllDates; + } + // endregion } diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewHolder.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewHolder.java new file mode 100644 index 0000000..d004f8f --- /dev/null +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewHolder.java @@ -0,0 +1,14 @@ +package com.github.tibolte.agendacalendarview.calendar; + +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import java.util.Calendar; + +public abstract class BaseViewHolder extends RecyclerView.ViewHolder { + public BaseViewHolder(View itemView) { + super(itemView); + } + public abstract void onBind(T item); +} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewListener.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewListener.java new file mode 100644 index 0000000..057a0a5 --- /dev/null +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/BaseViewListener.java @@ -0,0 +1,4 @@ +package com.github.tibolte.agendacalendarview.calendar; + +public interface BaseViewListener { +} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java index 85ec39c..e7df8a9 100644 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/CalendarView.java @@ -7,21 +7,25 @@ import com.github.tibolte.agendacalendarview.models.CalendarEvent; import com.github.tibolte.agendacalendarview.models.IDayItem; import com.github.tibolte.agendacalendarview.models.IWeekItem; +import com.github.tibolte.agendacalendarview.render.EventRenderer; import com.github.tibolte.agendacalendarview.utils.BusProvider; import com.github.tibolte.agendacalendarview.utils.DateHelper; import com.github.tibolte.agendacalendarview.utils.Events; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.LinearLayout; import android.widget.TextView; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; @@ -55,6 +59,8 @@ public class CalendarView extends LinearLayout { */ private int mCurrentListPosition; + private ViewAdapter viewAdapter; + // region Constructors public CalendarView(Context context) { @@ -66,7 +72,9 @@ public CalendarView(Context context, AttributeSet attrs) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.view_calendar, this, true); + if (inflater != null) { + inflater.inflate(R.layout.view_calendar, this, true); + } setOrientation(VERTICAL); } @@ -144,6 +152,25 @@ public void init(CalendarManager calendarManager, int dayTextColor, int currentD scrollToDate(today, weeks); } + public void initWithCustomAdapter(CalendarManager calendarManager, ViewAdapter adapter) { + Calendar today = calendarManager.getToday(); + Locale locale = calendarManager.getLocale(); + SimpleDateFormat weekDayFormatter = calendarManager.getWeekdayFormatter(); + List weeks = calendarManager.getWeeks(); + setUpHeader(today, weekDayFormatter, locale); + viewAdapter = adapter; + setUpViewAdapter(today, weeks); + scrollToDate(today, weeks); + } + + private void setUpViewAdapter(Calendar today, List weeks) { + if (viewAdapter != null) { + Log.d(LOG_TAG, "Setting adapter with today's calendar: " + today.toString()); + mListViewWeeks.setAdapter(viewAdapter); + viewAdapter.updateWeeksItems(weeks); + } + } + /** * Fired when the Agenda list view changes section. * @@ -183,20 +210,26 @@ private void scrollToPosition(int targetPosition) { } private void updateItemAtPosition(int position) { - WeeksAdapter weeksAdapter = (WeeksAdapter) mListViewWeeks.getAdapter(); - weeksAdapter.notifyItemChanged(position); + if(viewAdapter != null) { + ViewAdapter adapter = (ViewAdapter) mListViewWeeks.getAdapter(); + adapter.notifyItemChanged(position); + } else { + WeeksAdapter weeksAdapter = (WeeksAdapter) mListViewWeeks.getAdapter(); + weeksAdapter.notifyItemChanged(position); + } } /** * Creates a new adapter if necessary and sets up its parameters. */ - private void setUpAdapter(Calendar today, List weeks, int dayTextColor, int currentDayTextColor, int pastDayTextColor) { + private void setUpAdapter(Calendar today, List weeks, int dayTextColor, + int currentDayTextColor, int pastDayTextColor) { if (mWeeksAdapter == null) { Log.d(LOG_TAG, "Setting adapter with today's calendar: " + today.toString()); mWeeksAdapter = new WeeksAdapter(getContext(), today, dayTextColor, currentDayTextColor, pastDayTextColor); mListViewWeeks.setAdapter(mWeeksAdapter); + mWeeksAdapter.updateWeeksItems(weeks); } - mWeeksAdapter.updateWeeksItems(weeks); } private void setUpHeader(Calendar today, SimpleDateFormat weekDayFormatter, Locale locale) { @@ -271,4 +304,8 @@ private int updateSelectedDay(Calendar calendar, IDayItem dayItem) { } // endregion + + public void setViewAdapter(ViewAdapter t) { + this.viewAdapter = t; + } } diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/ViewAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/ViewAdapter.java new file mode 100644 index 0000000..be35a2e --- /dev/null +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/ViewAdapter.java @@ -0,0 +1,194 @@ +package com.github.tibolte.agendacalendarview.calendar; + +import android.content.Context; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.github.tibolte.agendacalendarview.models.IWeekItem; + +import java.util.ArrayList; +import java.util.List; + +public abstract class ViewAdapter> + extends RecyclerView.Adapter { + + private List items = new ArrayList<>(); + private LayoutInflater layoutInflater; + + /** + * Sets items to the adapter and notifies that data set has been changed. + * + * @param items items to set to the adapter + * @throws IllegalArgumentException in case of setting `null` items + */ + public void setItems(List items) { + if (items == null) { + throw new IllegalArgumentException("Cannot set `null` item to the Recycler adapter"); + } + this.items.clear(); + this.items.addAll(items); + notifyDataSetChanged(); + } + + public ViewAdapter(Context context) { + layoutInflater = LayoutInflater.from(context); + items = new ArrayList<>(); + } + + /** + * To be implemented in as specific adapter + * + * @param parent The ViewGroup into which the new View will be added after it is bound to an adapter position. + * @param viewType The view type of the new View. + * @return A new ViewHolder that holds a View of the given view type. + */ + @Override + public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); + + /** + * Called by RecyclerView to display the data at the specified position. This method should + * update the contents of the itemView to reflect the item at the given + * position. + * + * @param holder The ViewHolder which should be updated to represent the contents of the + * item at the given position in the data set. + * @param position The position of the item within the adapter's data set. + */ + @Override + public void onBindViewHolder(VH holder, int position) { + T item = items.get(position); + holder.onBind(item); + } + + /** + * Returns the total number of items in the data set held by the adapter. + * + * @return The total number of items in this adapter. + */ + @Override + public int getItemCount() { + return items != null ? items.size() : 0; + } + + /** + * Returns all items from the data set held by the adapter. + * + * @return All of items in this adapter. + */ + public List getItems() { + return items; + } + + /** + * Returns an items from the data set at a certain position. + * + * @return All of items in this adapter. + */ + public T getItem(int position) { + return items.get(position); + } + + /** + * Adds item to the end of the data set. + * Notifies that item has been inserted. + * + * @param item item which has to be added to the adapter. + */ + public void add(T item) { + if (item == null) { + throw new IllegalArgumentException("Cannot add null item to the Recycler adapter"); + } + items.add(item); + notifyItemInserted(items.size() - 1); + } + + /** + * Adds list of items to the end of the adapter's data set. + * Notifies that item has been inserted. + * + * @param items items which has to be added to the adapter. + */ + public void addAll(List items) { + if (items == null) { + throw new IllegalArgumentException("Cannot add `null` items to the Recycler adapter"); + } + this.items.addAll(items); + notifyItemRangeInserted(this.items.size() - items.size(), items.size()); + } + + /** + * Clears all the items in the adapter. + */ + public void clear() { + items.clear(); + notifyDataSetChanged(); + } + + /** + * Removes an item from the adapter. + * Notifies that item has been removed. + * + * @param item to be removed + */ + public void remove(T item) { + int position = items.indexOf(item); + if (position > -1) { + items.remove(position); + notifyItemRemoved(position); + } + } + + /** + * Returns whether adapter is empty or not. + * + * @return `true` if adapter is empty or `false` otherwise + */ + public boolean isEmpty() { + return getItemCount() == 0; + } + + /** + * Indicates whether each item in the data set can be represented with a unique identifier + * of type {@link Long}. + * + * @param hasStableIds Whether items in data set have unique identifiers or not. + * @see #hasStableIds() + * @see #getItemId(int) + */ + @Override + public void setHasStableIds(boolean hasStableIds) { + super.setHasStableIds(hasStableIds); + } + + /** + * Inflates a view. + * + * @param layout layout to me inflater + * @param parent container where to inflate + * @param attachToRoot whether to attach to root or not + * @return inflated View + */ + @NonNull + protected View inflate(@LayoutRes final int layout, @Nullable final ViewGroup parent, final boolean attachToRoot) { + return layoutInflater.inflate(layout, parent, attachToRoot); + } + + /** + * Inflates a view. + * + * @param layout layout to me inflater + * @param parent container where to inflate + * @return inflated View + */ + @NonNull + protected View inflate(@LayoutRes final int layout, final @Nullable ViewGroup parent) { + return inflate(layout, parent, false); + } + + public abstract void updateWeeksItems(List weeks); +} diff --git a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java index be9d493..14e937b 100644 --- a/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java +++ b/agendacalendarview/src/main/java/com/github/tibolte/agendacalendarview/calendar/weekslist/WeeksAdapter.java @@ -2,6 +2,8 @@ import com.github.tibolte.agendacalendarview.CalendarManager; import com.github.tibolte.agendacalendarview.R; +import com.github.tibolte.agendacalendarview.calendar.BaseViewHolder; +import com.github.tibolte.agendacalendarview.calendar.ViewAdapter; import com.github.tibolte.agendacalendarview.models.IDayItem; import com.github.tibolte.agendacalendarview.models.IWeekItem; import com.github.tibolte.agendacalendarview.utils.BusProvider; @@ -11,10 +13,12 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; import android.graphics.Typeface; import android.graphics.drawable.GradientDrawable; +import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -28,7 +32,7 @@ import java.util.Calendar; import java.util.List; -public class WeeksAdapter extends RecyclerView.Adapter { +public class WeeksAdapter extends ViewAdapter { public static final long FADE_DURATION = 250; @@ -41,7 +45,13 @@ public class WeeksAdapter extends RecyclerView.Adapter { /** * List of layout containers for each day @@ -124,11 +134,18 @@ public WeekViewHolder(View itemView) { setUpChildren(daysContainer); } + @Override + public void onBind(IWeekItem item) { + + } + + @SuppressLint("SetTextI18n") public void bindWeek(IWeekItem weekItem, Calendar today) { setUpMonthOverlay(); List dayItems = weekItem.getDayItems(); + for (int c = 0; c < dayItems.size(); c++) { final IDayItem dayItem = dayItems.get(c); LinearLayout cellItem = mCells.get(c); diff --git a/app/build.gradle b/app/build.gradle index 6275e6c..a337caf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' -apply plugin: 'me.tatarka.retrolambda' android { - compileSdkVersion 23 - buildToolsVersion "23.0.1" + compileSdkVersion 28 + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.github.tibolte.sample" minSdkVersion 14 - targetSdkVersion 23 + targetSdkVersion 28 versionCode 1 versionName "1.0" } @@ -33,18 +32,16 @@ android { } } -configurations { - compile.exclude module: 'support-annotations' -} - dependencies { compile project(':agendacalendarview') compile fileTree(dir: 'libs', include: ['*.jar']) // Google libraries - compile 'com.android.support:appcompat-v7:23.1.1' - + //noinspection GradleCompatible + compile 'com.android.support:appcompat-v7:27.1.0' + compile 'com.jakewharton:butterknife:8.6.0' // Other libraries - compile 'com.jakewharton:butterknife:7.0.0' + implementation 'com.android.support:support-annotations:27.1.1' + annotationProcessor "com.jakewharton:butterknife-compiler:8.6.0" } diff --git a/app/src/main/java/com/github/tibolte/sample/MainActivity.java b/app/src/main/java/com/github/tibolte/sample/MainActivity.java index 7c68fc7..a60a224 100644 --- a/app/src/main/java/com/github/tibolte/sample/MainActivity.java +++ b/app/src/main/java/com/github/tibolte/sample/MainActivity.java @@ -1,5 +1,11 @@ package com.github.tibolte.sample; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; + import com.github.tibolte.agendacalendarview.AgendaCalendarView; import com.github.tibolte.agendacalendarview.CalendarManager; import com.github.tibolte.agendacalendarview.CalendarPickerController; @@ -9,29 +15,25 @@ import com.github.tibolte.agendacalendarview.models.IDayItem; import com.github.tibolte.agendacalendarview.models.IWeekItem; import com.github.tibolte.agendacalendarview.models.WeekItem; - -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.support.v7.widget.Toolbar; -import android.util.Log; +import com.github.tibolte.sample.weekslist.WeeksAdapter; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Locale; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity implements CalendarPickerController { private static final String LOG_TAG = MainActivity.class.getSimpleName(); - @Bind(R.id.activity_toolbar) + @BindView(R.id.activity_toolbar) Toolbar mToolbar; - @Bind(R.id.agenda_calendar_view) + @BindView(R.id.agenda_calendar_view) AgendaCalendarView mAgendaCalendarView; + private WeeksAdapter mWeeksAdapter; // region Lifecycle methods @@ -65,15 +67,20 @@ protected void onCreate(Bundle savedInstanceState) { //////// This can be done once in another thread CalendarManager calendarManager = CalendarManager.getInstance(getApplicationContext()); calendarManager.buildCal(minDate, maxDate, Locale.getDefault(), new DayItem(), new WeekItem()); + calendarManager.setShowAllDates(false); calendarManager.loadEvents(eventList, new BaseCalendarEvent()); //////// List readyEvents = calendarManager.getEvents(); List readyDays = calendarManager.getDays(); List readyWeeks = calendarManager.getWeeks(); - mAgendaCalendarView.init(Locale.getDefault(), readyWeeks,readyDays,readyEvents,this); - mAgendaCalendarView.addEventRenderer(new DrawableEventRenderer()); - + mWeeksAdapter = new WeeksAdapter(this, calendarManager.getToday(), + this.getResources().getColor(R.color.blue_dark), + this.getResources().getColor(R.color.blue_selected), + this.getResources().getColor(R.color.orange_dark)); + mAgendaCalendarView.initWithCustomAdapter(Locale.getDefault(), + readyWeeks,readyDays,readyEvents,this, mWeeksAdapter); + mAgendaCalendarView.enableFloatingIndicator(false); } // endregion diff --git a/app/src/main/java/com/github/tibolte/sample/weekslist/WeekListView.java b/app/src/main/java/com/github/tibolte/sample/weekslist/WeekListView.java new file mode 100644 index 0000000..7743e51 --- /dev/null +++ b/app/src/main/java/com/github/tibolte/sample/weekslist/WeekListView.java @@ -0,0 +1,144 @@ +package com.github.tibolte.sample.weekslist; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; + +import com.github.tibolte.agendacalendarview.utils.BusProvider; +import com.github.tibolte.agendacalendarview.utils.Events; + +public class WeekListView extends RecyclerView { + private boolean mUserScrolling = false; + private boolean mScrolling = false; + + // region Constructors + + public WeekListView(Context context) { + super(context); + } + + public WeekListView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public WeekListView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + // endregion + + // region Public methods + + /** + * Enable snapping behaviour for this recyclerView + * + * @param enabled enable or disable the snapping behaviour + */ + public void setSnapEnabled(boolean enabled) { + if (enabled) { + addOnScrollListener(mScrollListener); + } else { + removeOnScrollListener(mScrollListener); + } + } + + // endregion + + // region Private methods + + private OnScrollListener mScrollListener = new OnScrollListener() { + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + } + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + final WeeksAdapter weeksAdapter = (WeeksAdapter) getAdapter(); + + switch (newState) { + case SCROLL_STATE_IDLE: + if (mUserScrolling) { + scrollToView(getCenterView()); + postDelayed(() -> weeksAdapter.setDragging(false), 700); // Wait for recyclerView to settle + } + + mUserScrolling = false; + mScrolling = false; + break; + // If scroll is caused by a touch (scroll touch, not any touch) + case SCROLL_STATE_DRAGGING: + BusProvider.getInstance().send(new Events.CalendarScrolledEvent()); + // If scroll was initiated already, this is not a user scrolling, but probably a tap, else set userScrolling + if (!mScrolling) { + mUserScrolling = true; + } + weeksAdapter.setDragging(true); + break; + case SCROLL_STATE_SETTLING: + // The user's finger is not touching the list anymore, no need + // for any alpha animation then + weeksAdapter.setAlphaSet(true); + mScrolling = true; + break; + } + } + }; + + private View getChildClosestToPosition(int y) { + if (getChildCount() <= 0) { + return null; + } + + int itemHeight = getChildAt(0).getMeasuredHeight(); + + int closestY = 9999; + View closestChild = null; + + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + + int childCenterY = ((int) child.getY() + (itemHeight / 2)); + int yDistance = childCenterY - y; + + // If child center is closer than previous closest, set it as closest + if (Math.abs(yDistance) < Math.abs(closestY)) { + closestY = yDistance; + closestChild = child; + } + } + + return closestChild; + } + + private View getCenterView() { + return getChildClosestToPosition(getMeasuredHeight() / 2); + } + + private void scrollToView(View child) { + if (child == null) { + return; + } + + stopScroll(); + + int scrollDistance = getScrollDistance(child); + + if (scrollDistance != 0) { + smoothScrollBy(0, scrollDistance); + } + } + + private int getScrollDistance(View child) { + int itemHeight = getChildAt(0).getMeasuredHeight(); + int centerY = getMeasuredHeight() / 2; + + int childCenterY = ((int) child.getY() + (itemHeight / 2)); + + return childCenterY - centerY; + } + + // endregion +} diff --git a/app/src/main/java/com/github/tibolte/sample/weekslist/WeeksAdapter.java b/app/src/main/java/com/github/tibolte/sample/weekslist/WeeksAdapter.java new file mode 100644 index 0000000..b230ffa --- /dev/null +++ b/app/src/main/java/com/github/tibolte/sample/weekslist/WeeksAdapter.java @@ -0,0 +1,292 @@ +package com.github.tibolte.sample.weekslist; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; +import android.support.annotation.NonNull; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.github.tibolte.agendacalendarview.CalendarManager; +import com.github.tibolte.agendacalendarview.R; +import com.github.tibolte.agendacalendarview.calendar.BaseViewHolder; +import com.github.tibolte.agendacalendarview.calendar.ViewAdapter; +import com.github.tibolte.agendacalendarview.models.IDayItem; +import com.github.tibolte.agendacalendarview.models.IWeekItem; +import com.github.tibolte.agendacalendarview.utils.BusProvider; +import com.github.tibolte.agendacalendarview.utils.DateHelper; +import com.github.tibolte.agendacalendarview.utils.Events; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +public class WeeksAdapter extends ViewAdapter { + + public static final long FADE_DURATION = 250; + + private Context mContext; + private Calendar mToday; + private List mWeeksList = new ArrayList<>(); + private boolean mDragging; + private boolean mAlphaSet; + private int mDayTextColor, mPastDayTextColor, mCurrentDayColor; + + // region Constructor + + public WeeksAdapter(Context context) { + super(context); + } + + public WeeksAdapter(Context context, Calendar today, int dayTextColor, int currentDayTextColor, + int pastDayTextColor) { + super(context); + this.mToday = today; + this.mContext = context; + this.mDayTextColor = dayTextColor; + this.mCurrentDayColor = currentDayTextColor; + this.mPastDayTextColor = pastDayTextColor; + } + + // endregion + + public void updateWeeksItems(List weekItems) { + this.mWeeksList.clear(); + this.mWeeksList.addAll(weekItems); + notifyDataSetChanged(); + } + + // region Getters/setters + + public List getWeeksList() { + return mWeeksList; + } + + public boolean isDragging() { + return mDragging; + } + + public void setDragging(boolean dragging) { + if (dragging != this.mDragging) { + this.mDragging = dragging; + notifyItemRangeChanged(0, mWeeksList.size()); + } + } + + public boolean isAlphaSet() { + return mAlphaSet; + } + + public void setAlphaSet(boolean alphaSet) { + mAlphaSet = alphaSet; + } + + // endregion + + // region RecyclerView.Adapter methods + + @Override + public WeekViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_week, + parent, false); + return new WeekViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull WeekViewHolder weekViewHolder, int position) { + IWeekItem weekItem = mWeeksList.get(position); + weekViewHolder.bindWeek(weekItem, mToday); + } + + @Override + public int getItemCount() { + return mWeeksList.size(); + } + // endregion + + // region Class - WeekViewHolder + + public class WeekViewHolder extends BaseViewHolder { + + /** + * List of layout containers for each day + */ + private List mCells; + private TextView mTxtMonth; + private FrameLayout mMonthBackground; + + public WeekViewHolder(View itemView) { + super(itemView); + mTxtMonth = (TextView) itemView.findViewById(R.id.month_label); + mMonthBackground = (FrameLayout) itemView.findViewById(R.id.month_background); + LinearLayout daysContainer = (LinearLayout) itemView.findViewById(R.id.week_days_container); + setUpChildren(daysContainer); + } + + @Override + public void onBind(IWeekItem item) { + bindWeek(item, mToday); + } + + @SuppressLint("SetTextI18n") + public void bindWeek(IWeekItem weekItem, Calendar today) { + setUpMonthOverlay(); + + List dayItems = weekItem.getDayItems(); + + for (int c = 0; c < dayItems.size(); c++) { + final IDayItem dayItem = dayItems.get(c); + LinearLayout cellItem = mCells.get(c); + TextView txtDay = (TextView) cellItem.findViewById(R.id.view_day_day_label); + TextView txtMonth = (TextView) cellItem.findViewById(R.id.view_day_month_label); + View circleView = cellItem.findViewById(R.id.view_day_circle_selected); + cellItem.setOnClickListener(v->BusProvider.getInstance().send(new + Events.DayClickedEvent(dayItem))); + + txtMonth.setVisibility(View.GONE); + txtDay.setTextColor(mDayTextColor); + txtMonth.setTextColor(mDayTextColor); + circleView.setVisibility(View.GONE); + + txtDay.setTypeface(null, Typeface.NORMAL); + txtMonth.setTypeface(null, Typeface.NORMAL); + + // Display the day + txtDay.setText(Integer.toString(dayItem.getValue())); + + // Highlight first day of the month + if (dayItem.isFirstDayOfTheMonth() && !dayItem.isSelected()) { + txtMonth.setVisibility(View.VISIBLE); + txtMonth.setText(dayItem.getMonth()); + txtDay.setTypeface(null, Typeface.BOLD); + txtMonth.setTypeface(null, Typeface.BOLD); + } + + // Check if this day is in the past + if (today.getTime().after(dayItem.getDate()) && !DateHelper.sameDate(today, dayItem.getDate())) { + txtDay.setTextColor(mPastDayTextColor); + txtMonth.setTextColor(mPastDayTextColor); + } + + // Highlight the cell if this day is today + if (dayItem.isToday() && !dayItem.isSelected()) { + txtDay.setTextColor(mCurrentDayColor); + } + + // Show a circle if the day is selected + if (dayItem.isSelected()) { + txtDay.setTextColor(mDayTextColor); + circleView.setVisibility(View.VISIBLE); + GradientDrawable drawable = (GradientDrawable) circleView.getBackground(); + drawable.setStroke((int) (1 * Resources.getSystem().getDisplayMetrics().density), mDayTextColor); + } + + // Check if the month label has to be displayed + if (dayItem.getValue() == 15) { + mTxtMonth.setVisibility(View.VISIBLE); + SimpleDateFormat monthDateFormat = new SimpleDateFormat(mContext.getResources().getString(R.string.month_name_format), CalendarManager.getInstance().getLocale()); + String month = monthDateFormat.format(weekItem.getDate()).toUpperCase(); + if (today.get(Calendar.YEAR) != weekItem.getYear()) { + month = month + String.format(" %d", weekItem.getYear()); + } + mTxtMonth.setText(month); + } + } + } + + private void setUpChildren(LinearLayout daysContainer) { + mCells = new ArrayList<>(); + for (int i = 0; i < daysContainer.getChildCount(); i++) { + mCells.add((LinearLayout) daysContainer.getChildAt(i)); + } + } + + private void setUpMonthOverlay() { + mTxtMonth.setVisibility(View.GONE); + + if (isDragging()) { + AnimatorSet animatorSetFadeIn = new AnimatorSet(); + animatorSetFadeIn.setDuration(FADE_DURATION); + ObjectAnimator animatorTxtAlphaIn = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 1f); + ObjectAnimator animatorBackgroundAlphaIn = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 1f); + animatorSetFadeIn.playTogether( + animatorTxtAlphaIn + //animatorBackgroundAlphaIn + ); + animatorSetFadeIn.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + setAlphaSet(true); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animatorSetFadeIn.start(); + } else { + AnimatorSet animatorSetFadeOut = new AnimatorSet(); + animatorSetFadeOut.setDuration(FADE_DURATION); + ObjectAnimator animatorTxtAlphaOut = ObjectAnimator.ofFloat(mTxtMonth, "alpha", mTxtMonth.getAlpha(), 0f); + ObjectAnimator animatorBackgroundAlphaOut = ObjectAnimator.ofFloat(mMonthBackground, "alpha", mMonthBackground.getAlpha(), 0f); + animatorSetFadeOut.playTogether( + animatorTxtAlphaOut + //animatorBackgroundAlphaOut + ); + animatorSetFadeOut.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + + } + + @Override + public void onAnimationEnd(Animator animation) { + setAlphaSet(false); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + animatorSetFadeOut.start(); + } + + if (isAlphaSet()) { + //mMonthBackground.setAlpha(1f); + mTxtMonth.setAlpha(1f); + } else { + //mMonthBackground.setAlpha(0f); + mTxtMonth.setAlpha(0f); + } + } + } + + // endregion +} diff --git a/build.gradle b/build.gradle index a803c76..fbf78fd 100644 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.android.tools.build:gradle:3.1.4' classpath 'me.tatarka:gradle-retrolambda:3.1.0' // NOTE: Do not place your application dependencies here; they belong @@ -16,6 +17,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d1eecad..f0fd4a5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip