diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php index 7added162f..4f65202a2c 100644 --- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php +++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php @@ -76,9 +76,11 @@ final class PhabricatorCalendarEventSearchEngine $display_start = $start_day->format('U'); $display_end = $next->format('U'); - // 0 = Sunday is always the start of the week, for now - $start_of_week = 0; - $end_of_week = 6 - $start_of_week; + $preferences = $viewer->loadPreferences(); + $pref_week_day = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY; + + $start_of_week = $preferences->getPreference($pref_week_day, 0); + $end_of_week = ($start_of_week + 6) % 7; $first_of_month = $start_day->format('w'); $last_of_month = id(clone $next)->modify('-1 day')->format('w'); @@ -87,9 +89,10 @@ final class PhabricatorCalendarEventSearchEngine $min_range = $display_start; if ($this->isMonthView($saved) && - $first_of_month > $start_of_week) { + $first_of_month !== $start_of_week) { + $interim_day_num = ($first_of_month + 7 - $start_of_week) % 7; $min_range = id(clone $start_day) - ->modify('-'.$first_of_month.' days') + ->modify('-'.$interim_day_num.' days') ->format('U'); } } @@ -97,9 +100,10 @@ final class PhabricatorCalendarEventSearchEngine $max_range = $display_end; if ($this->isMonthView($saved) && - $last_of_month < $end_of_week) { + $last_of_month !== $end_of_week) { + $interim_day_num = ($end_of_week + 7 - $last_of_month) % 7; $max_range = id(clone $next) - ->modify('+'.(6 - $first_of_month).' days') + ->modify('+'.$interim_day_num.' days') ->format('U'); } diff --git a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php index 661a1172b7..5fbf825d22 100644 --- a/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php +++ b/src/applications/settings/panel/PhabricatorDateTimeSettingsPanel.php @@ -19,6 +19,7 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { $username = $user->getUsername(); $pref_time = PhabricatorUserPreferences::PREFERENCE_TIME_FORMAT; + $pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY; $preferences = $user->loadPreferences(); $errors = array(); @@ -30,7 +31,12 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { $errors[] = pht('The selected timezone is not a valid timezone.'); } - $preferences->setPreference($pref_time, $request->getStr($pref_time)); + $preferences->setPreference( + $pref_time, + $request->getStr($pref_time)); + $preferences->setPreference( + $pref_week_start, + $request->getStr($pref_week_start)); if (!$errors) { $preferences->save(); @@ -72,6 +78,14 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { ->setCaption( pht('Format used when rendering a time of day.')) ->setValue($preferences->getPreference($pref_time))) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel(pht('Week Starts On')) + ->setOptions($this->getWeekDays()) + ->setName($pref_week_start) + ->setCaption( + pht('Calendar weeks will start with this day.')) + ->setValue($preferences->getPreference($pref_week_start, 0))) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Save Account Settings'))); @@ -86,4 +100,16 @@ final class PhabricatorDateTimeSettingsPanel extends PhabricatorSettingsPanel { $form_box, ); } + + private function getWeekDays() { + return array( + pht('Sunday'), + pht('Monday'), + pht('Tuesday'), + pht('Wednesday'), + pht('Thursday'), + pht('Friday'), + pht('Saturday'), + ); + } } diff --git a/src/applications/settings/storage/PhabricatorUserPreferences.php b/src/applications/settings/storage/PhabricatorUserPreferences.php index 3248dc8b2a..7732df5568 100644 --- a/src/applications/settings/storage/PhabricatorUserPreferences.php +++ b/src/applications/settings/storage/PhabricatorUserPreferences.php @@ -9,6 +9,7 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO { const PREFERENCE_TITLES = 'titles'; const PREFERENCE_MONOSPACED_TEXTAREAS = 'monospaced-textareas'; const PREFERENCE_TIME_FORMAT = 'time-format'; + const PREFERENCE_WEEK_START_DAY = 'week-start-day'; const PREFERENCE_RE_PREFIX = 're-prefix'; const PREFERENCE_NO_SELF_MAIL = 'self-mail'; diff --git a/src/view/phui/calendar/PHUICalendarMonthView.php b/src/view/phui/calendar/PHUICalendarMonthView.php index fd2ca4e458..d6bb7d1a32 100644 --- a/src/view/phui/calendar/PHUICalendarMonthView.php +++ b/src/view/phui/calendar/PHUICalendarMonthView.php @@ -59,24 +59,10 @@ final class PHUICalendarMonthView extends AphrontView { $days = $this->getDatesInMonth(); $cell_lists = array(); - $empty_cell = array( - 'list' => null, - 'date' => null, - 'uri' => null, - 'count' => 0, - 'class' => null, - ); require_celerity_resource('phui-calendar-month-css'); $first = reset($days); - $start_of_week = 0; - - $empty = $first->format('w'); - - for ($ii = 0; $ii < $empty; $ii++) { - $cell_lists[] = $empty_cell; - } foreach ($days as $day) { $day_number = $day->format('j'); @@ -133,9 +119,6 @@ final class PHUICalendarMonthView extends AphrontView { foreach ($cell_lists_by_week as $week_of_cell_lists) { $cells = array(); - while (count($week_of_cell_lists) < 7) { - $week_of_cell_lists[] = $empty_cell; - } foreach ($week_of_cell_lists as $cell_list) { $cells[] = $this->getEventListCell($cell_list); } @@ -309,18 +292,28 @@ final class PHUICalendarMonthView extends AphrontView { } private function getDayNamesHeader() { + list($week_start, $week_end) = $this->getWeekStartAndEnd(); + + $weekday_names = array( + $this->getDayHeader(pht('Sun'), pht('Sunday'), true), + $this->getDayHeader(pht('Mon'), pht('Monday')), + $this->getDayHeader(pht('Tue'), pht('Tuesday')), + $this->getDayHeader(pht('Wed'), pht('Wednesday')), + $this->getDayHeader(pht('Thu'), pht('Thursday')), + $this->getDayHeader(pht('Fri'), pht('Friday')), + $this->getDayHeader(pht('Sat'), pht('Saturday'), true), + ); + + $sorted_weekday_names = array(); + + for ($i = $week_start; $i < ($week_start + 7); $i++) { + $sorted_weekday_names[] = $weekday_names[$i % 7]; + } + return phutil_tag( 'tr', array('class' => 'phui-calendar-day-of-week-header'), - array( - $this->getDayHeader(pht('Sun'), pht('Sunday'), true), - $this->getDayHeader(pht('Mon'), pht('Monday')), - $this->getDayHeader(pht('Tue'), pht('Tuesday')), - $this->getDayHeader(pht('Wed'), pht('Wednesday')), - $this->getDayHeader(pht('Thu'), pht('Thursday')), - $this->getDayHeader(pht('Fri'), pht('Friday')), - $this->getDayHeader(pht('Sat'), pht('Saturday'), true), - )); + $sorted_weekday_names); } private function getDayHeader($short, $long, $is_weekend = false) { @@ -466,8 +459,8 @@ final class PHUICalendarMonthView extends AphrontView { list($next_year, $next_month) = $this->getNextYearAndMonth(); $end_date = new DateTime("{$next_year}-{$next_month}-01", $timezone); - $start_of_week = 0; - $end_of_week = 6 - $start_of_week; + list($start_of_week, $end_of_week) = $this->getWeekStartAndEnd(); + $days_in_month = id(clone $end_date)->modify('-1 day')->format('d'); $first_month_day_date = new DateTime("{$year}-{$month}-01", $timezone); @@ -477,17 +470,19 @@ final class PHUICalendarMonthView extends AphrontView { $last_weekday_of_month = $last_month_day_date->format('w'); $num_days_display = $days_in_month; - if ($start_of_week < $first_weekday_of_month) { - $num_days_display += $first_weekday_of_month; + if ($start_of_week !== $first_weekday_of_month) { + $interim_start_num = ($first_weekday_of_month + 7 - $start_of_week) % 7; + $num_days_display += $interim_start_num; + $day_date = id(clone $first_month_day_date) + ->modify('-'.$interim_start_num.' days'); } - if ($end_of_week > $last_weekday_of_month) { - $num_days_display += (6 - $last_weekday_of_month); - $end_date->modify('+'.(6 - $last_weekday_of_month).' days'); + if ($end_of_week !== $last_weekday_of_month) { + $interim_end_day_num = ($end_of_week - $last_weekday_of_month + 7) % 7; + $num_days_display += $interim_end_day_num; + $end_date->modify('+'.$interim_end_day_num.' days'); } $days = array(); - $day_date = id(clone $first_month_day_date) - ->modify('-'.$first_weekday_of_month.' days'); for ($day = 1; $day <= $num_days_display; $day++) { $day_epoch = $day_date->format('U'); @@ -513,14 +508,13 @@ final class PHUICalendarMonthView extends AphrontView { } private function getThisWeekRange() { - $week_start = 0; - $week_end = 6; + list($week_start, $week_end) = $this->getWeekStartAndEnd(); $today = $this->getTodayMidnight(); $date_weekday = $today->format('w'); - $days_from_week_start = $date_weekday - $week_start; - $days_to_week_end = $week_end - $date_weekday + 1; + $days_from_week_start = ($date_weekday + 7 - $week_start) % 7; + $days_to_week_end = 7 - $days_from_week_start; $modify = '-'.$days_from_week_start.' days'; $week_start_date = id(clone $today)->modify($modify); @@ -531,6 +525,16 @@ final class PHUICalendarMonthView extends AphrontView { return array($week_start_date, $week_end_date); } + private function getWeekStartAndEnd() { + $preferences = $this->user->loadPreferences(); + $pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY; + + $week_start = $preferences->getPreference($pref_week_start, 0); + $week_end = ($week_start + 6) % 7; + + return array($week_start, $week_end); + } + private function getDateTime() { $user = $this->user; $timezone = new DateTimeZone($user->getTimezoneIdentifier());