diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04baeb4885a27130ce59d352f46281ccc96b55d8..1bf10d33771eabfaf7f3c5ea34fe1d2385c4b12c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -123,3 +123,56 @@ create-release: ./systemAppsUpdateInfo/scripts/create-release.sh \ "$APK_PATH" "$UNSIGNED_APK" "$COMMUNITY_APK" "$OFFICIAL_APK" +.update-from-upstream: + image: registry.gitlab.e.foundation/e/tools/docker-tools:latest + stage: update-from-upstream + rules: + - if: '$CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_NAME == $LOCAL_BRANCH' + variables: + CI_PROJECT_SSH_URL: git@gitlab.e.foundation:$CI_PROJECT_PATH + GIT_STRATEGY: none + before_script: + - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - echo "${SSH_E_ROBOT_PRIVATE_KEY}" | tr -d '\r' | ssh-add - + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo "${SSH_KNOWN_HOSTS}" > ~/.ssh/known_hosts + - echo "${SSH_KNOWN_HOSTS}" + - chmod 644 ~/.ssh/known_hosts + - git config --global user.email $GITLAB_USER_EMAIL + - git config --global user.name "$GITLAB_USER_NAME" + - cd $CI_BUILD_DIR + - rm -rf $CI_PROJECT_DIR + - git clone $CI_PROJECT_SSH_URL $CI_PROJECT_DIR + - cd $CI_PROJECT_DIR + script: + - git config http.sslverify false + # update $UPSTREAM_BRANCH & tags + - git fetch origin + - git checkout $UPSTREAM_BRANCH + - git remote add upstream $UPSTREAM_URL + - git fetch upstream + - git pull upstream $UPSTREAM_DEFAULT_BRANCH + - git push origin $UPSTREAM_BRANCH + - git push origin --tags + # checkout to latest tag commit to $TEMP_LATEST_TAG_BRANCH + - git checkout $(git describe --tags --abbrev=0) + - git checkout -b $TEMP_LATEST_TAG_BRANCH + # merge $LOCAL_BRANCH with $TEMP_LATEST_TAG_BRANCH & push + - git checkout $LOCAL_BRANCH + - git merge $TEMP_LATEST_TAG_BRANCH + - git push origin $LOCAL_BRANCH + # remove unwanted local branch & remote + - git branch -D $TEMP_LATEST_TAG_BRANCH + - git remote remove upstream + +update-default-branch: + extends: .update-from-upstream + variables: + LOCAL_BRANCH: main + UPSTREAM_BRANCH: master + UPSTREAM_DEFAULT_BRANCH: master + UPSTREAM_URL: https://github.com/Etar-Group/Etar-Calendar + TEMP_LATEST_TAG_BRANCH: latest_upstream_tag_branch + allow_failure: true diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 39bf80f758b19e0857b64ac1f94e957145a83422..51c82a778d9b3f125e6bba92f43f7c1b68f99a49 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,7 +20,7 @@ android { targetSdk = 34 versionCode = 47 versionName = "1.0.47" - applicationId = "ws.xsoh.etar" + applicationId = "foundation.e.calendar" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -141,6 +141,9 @@ dependencies { // lifecycle val lifecycle_version = "2.8.4" implementation("androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version") + + // elib + implementation("foundation.e:elib:0.0.1-alpha11") } tasks.preBuild.dependsOn(":aarGen") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3b1b75d19d13694e0da276cb0b63572f2718126b..d7c9ba11b8fea6e9d28ca6425c5c1885327f8654 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,6 +21,7 @@ package="ws.xsoh.etar" android:installLocation="auto"> + @@ -59,7 +60,7 @@ android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/standalone_app_label" - android:taskAffinity="ws.xsoh.etar.task" + android:taskAffinity="foundation.e.calendar.task" android:requiredAccountType="*" android:usesCleartextTraffic="false" android:theme="@style/CalendarAppThemeLight"> @@ -87,6 +88,13 @@ + + + + + mEventList = Collections.emptyList(); + + private void showCalendarPickerDialog() { + FragmentManager fragmentManager = getSupportFragmentManager(); + CalendarPickerDialogFragment fragment = + ((CalendarPickerDialogFragment) fragmentManager.findFragmentByTag(CalendarPickerDialogFragment.FRAGMENT_TAG)); + + if (fragment != null) { + fragment.dismiss(); + } + + fragment = new CalendarPickerDialogFragment(mEventList.size()); + fragment.show(fragmentManager, CalendarPickerDialogFragment.FRAGMENT_TAG); + } @Override protected void onNewIntent(Intent intent) { @@ -255,6 +277,15 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH mController.sendEvent(this, EventType.GO_TO, time, time, -1, ViewType.CURRENT); } } + handleEventsOnNewIntent(intent); + } + + private void handleEventsOnNewIntent(Intent intent) { + if (intent.hasExtra(AllInOneActivity.BUNDLE_KEY_MULTIPLE_EVENTS) + && intent.getExtras().containsKey(BUNDLE_KEY_MULTIPLE_EVENTS)) { + Bundle bundle = intent.getExtras(); + handleEvents(bundle, intent); + } } @Override @@ -385,6 +416,57 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH prefs.registerOnSharedPreferenceChangeListener(this); mContentResolver = getContentResolver(); + + // Save and restore flow for handling import of multiple events + if (icicle == null) { + handleEvents(icicle, getIntent()); + } else { + mEventList = ((List) icicle.getSerializable(BUNDLE_KEY_RESTORE_MULTIPLE_EVENTS)); + } + } + + private void handleEvents(Bundle bundle, Intent intent) { + mEventList = getEventList(bundle, intent); + if (mEventList.isEmpty()) { + return; + } + + // TODO: 19/08/2024 Decide to show dialog for consecutive .ics import. Now it replaces previous one. + showCalendarPickerDialog(); + } + + private List getEventList(Bundle icicle, Intent intent) { + final List eventModelList = new ArrayList<>(); + + final ArrayList bundles = intent.getParcelableArrayListExtra(AllInOneActivity.BUNDLE_KEY_MULTIPLE_EVENTS); + + if (bundles == null || bundles.isEmpty()) { + return eventModelList; + } + + for (Bundle bundle : bundles) { + long eventId = -1; + Uri data = intent.getData(); + if (data != null) { + try { + eventId = Long.parseLong(data.getLastPathSegment()); + } catch (NumberFormatException e) { + if (DEBUG) { + Log.d(TAG, "Create new event"); + } + } + } else if (icicle != null && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) { + eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID, -1); + } + + final CalendarEventModel eventModel = new CalendarEventModel(getApplicationContext(), bundle); + if (eventId > -1) { + eventModel.mId = eventId; + } + eventModelList.add(eventModel); + } + + return eventModelList; } private void checkAppPermissions() { @@ -629,7 +711,6 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH mCalIntentReceiver = Utils.setTimeChangesReceiver(this, mTimeChangesUpdater); } - @Override protected void onPause() { super.onPause(); @@ -670,6 +751,7 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH super.onSaveInstanceState(outState); outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime()); outState.putInt(BUNDLE_KEY_RESTORE_VIEW, mCurrentView); + outState.putSerializable(BUNDLE_KEY_RESTORE_MULTIPLE_EVENTS, new ArrayList<>(mEventList)); if (mCurrentView == ViewType.EDIT) { outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId()); } else if (mCurrentView == ViewType.AGENDA) { @@ -1442,6 +1524,70 @@ public class AllInOneActivity extends AbstractCalendarActivity implements EventH return false; } + @Override + public void onCalendarPicked(long selectedCalendarId, String ownerAccount, String syncAccountName) { + saveEventsInPickedCalendar(selectedCalendarId, ownerAccount, syncAccountName); + } + + @Override + public void onCalendarUnavailable() { + showAddCalendarDialog(); + } + + private void showAddCalendarDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.no_syncable_calendars) + .setIconAttribute(android.R.attr.alertDialogIcon) + .setMessage(R.string.no_calendars_found) + .setPositiveButton(R.string.add_calendar, (dialog, which) -> { + Intent nextIntent = new Intent(this, SettingsActivity.class); + startActivity(nextIntent); + }) + .setNegativeButton(android.R.string.no, null); + + builder.show(); + } + + @Override + public void onCalendarPickerError() { + Toast.makeText(this, R.string.pick_calendar_error_importing_events, Toast.LENGTH_SHORT).show(); + } + + private void saveEventsInPickedCalendar(long selectedCalendarId, String ownerAccount, String syncAccountName) { + final EditEventHelper editEventHelper = new EditEventHelper(this); + + int addedEventcounter = 0; + + for (CalendarEventModel event : mEventList) { + event.mCalendarId = selectedCalendarId; + event.mOwnerAccount = ownerAccount; + event.mSyncAccountName = syncAccountName; + + if (editEventHelper.saveEvent(event, null, 0)) { + addedEventcounter++; + } else { + Toast.makeText( + this, + getString(R.string.import_multi_event_single_event_failure_toast, event.mTitle), + Toast.LENGTH_SHORT + ).show(); + } + } + + if (addedEventcounter > 0) { + Toast.makeText(this, getString(R.string.import_multi_event_confirmation_toast), Toast.LENGTH_SHORT).show(); + navigateToFirstEventOccurrence(); + } + } + + private void navigateToFirstEventOccurrence() { + CalendarEventModel calendarEventModel = mEventList.get(0); + long start = calendarEventModel.mStart; + long end = calendarEventModel.mEnd; + CalendarController.getInstance(this).launchViewEvent(-1, start, end, + Attendees.ATTENDEE_STATUS_NONE); + } + private class QueryHandler extends AsyncQueryHandler { public QueryHandler(ContentResolver cr) { super(cr); diff --git a/app/src/main/java/com/android/calendar/CalendarEventModel.java b/app/src/main/java/com/android/calendar/CalendarEventModel.java index 466536a13c541fdf07c702512c947fae3a78f2db..66f8353ada0e28305f3d4731e4ae955003c89381 100644 --- a/app/src/main/java/com/android/calendar/CalendarEventModel.java +++ b/app/src/main/java/com/android/calendar/CalendarEventModel.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2024 MURENA SAS * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -16,9 +17,15 @@ package com.android.calendar; +import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY; +import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME; +import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME; + import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.os.Bundle; +import android.provider.CalendarContract; import android.provider.CalendarContract.Attendees; import android.provider.CalendarContract.Calendars; import android.provider.CalendarContract.Events; @@ -146,6 +153,89 @@ public class CalendarEventModel implements Serializable { } } + public CalendarEventModel(Context context, Bundle bundle) { + this(context); + + if (bundle == null) { + return; + } + + final String title = bundle.getString(Events.TITLE); + if (title != null) { + mTitle = title; + } + + final String location = bundle.getString(Events.EVENT_LOCATION); + if (location != null) { + mLocation = location; + } + + final String description = bundle.getString(Events.DESCRIPTION); + if (description != null) { + mDescription = description; + } + + final String url = bundle.getString(ExtendedProperty.URL); + if (url != null) { + mUrl = url; + } + + final int availability = bundle.getInt(Events.AVAILABILITY, -1); + if (availability != -1) { + mAvailability = availability; + mAvailabilityExplicitlySet = true; + } + + final int accessLevel = bundle.getInt(Events.ACCESS_LEVEL, -1); + if (accessLevel != -1) { + mAccessLevel = accessLevel; + } + + final String rrule = bundle.getString(Events.RRULE); + if (!TextUtils.isEmpty(rrule)) { + mRrule = rrule; + } + + final String timezone = bundle.getString(Events.EVENT_TIMEZONE); + if (timezone != null) { + mTimezone = timezone; + } + + final long beginTime = bundle.getLong(EXTRA_EVENT_BEGIN_TIME, -1); + if (beginTime > -1) { + mStart = beginTime; + } + + final long endTime = bundle.getLong(EXTRA_EVENT_END_TIME, -1); + if (endTime > -1) { + mEnd = endTime; + } + + final boolean isAllDay = bundle.getBoolean(EXTRA_EVENT_ALL_DAY, false); + if (isAllDay) { + mAllDay = isAllDay; + } + + final String organizer = bundle.getString(CalendarContract.Events.ORGANIZER, ""); + if (!organizer.isEmpty()) { + mOrganizer = organizer; + } + + final String emails = bundle.getString(Intent.EXTRA_EMAIL); + if (!TextUtils.isEmpty(emails)) { + final String[] emailArray = emails.split("[ ,;]"); + for (String email : emailArray) { + if (!TextUtils.isEmpty(email) && email.contains("@")) { + email = email.trim(); + if (!mAttendeesList.containsKey(email)) { + mAttendeesList.put(email, new Attendee("", email)); + } + } + } + } + } + + public CalendarEventModel(Context context, Intent intent) { this(context); diff --git a/app/src/main/java/com/android/calendar/DayOfMonthDrawable.java b/app/src/main/java/com/android/calendar/DayOfMonthDrawable.java index 3c1431a80735fe8c0cd1b026eb3ab218c0b16c63..7f6c843fd9b9ab8b00de30bcbe01cb92e2f7ed9c 100644 --- a/app/src/main/java/com/android/calendar/DayOfMonthDrawable.java +++ b/app/src/main/java/com/android/calendar/DayOfMonthDrawable.java @@ -44,7 +44,7 @@ public class DayOfMonthDrawable extends Drawable { mTextSize = c.getResources().getDimension(R.dimen.today_icon_text_size); mPaint = new Paint(); mPaint.setAlpha(255); - mPaint.setColor(c.getResources().getColor(R.color.titleTextColor)); + mPaint.setColor(c.getResources().getColor(R.color.appbar_icon_color)); mPaint.setTypeface(Typeface.DEFAULT_BOLD); mPaint.setTextSize(mTextSize); mPaint.setTextAlign(Paint.Align.CENTER); diff --git a/app/src/main/java/com/android/calendar/DayView.java b/app/src/main/java/com/android/calendar/DayView.java index 0a42cb53f20e2794334d19243a9dc85629382c53..30e5785b33f176c9f61f7ab5d057d5e024648b1e 100644 --- a/app/src/main/java/com/android/calendar/DayView.java +++ b/app/src/main/java/com/android/calendar/DayView.java @@ -358,7 +358,7 @@ public class DayView extends View implements View.OnCreateContextMenuListener, protected final EventGeometry mEventGeometry; private static float GRID_LINE_LEFT_MARGIN = 0; - private static final float GRID_LINE_INNER_WIDTH = 1; + private static final float GRID_LINE_INNER_WIDTH = 2; private static final int DAY_GAP = 1; private static final int HOUR_GAP = 1; @@ -1070,7 +1070,7 @@ public class DayView extends View implements View.OnCreateContextMenuListener, } mTodayAnimator = ObjectAnimator.ofInt(this, "animateTodayAlpha", mAnimateTodayAlpha, 255); - mAnimateToday = true; + mAnimateToday = false; mTodayAnimatorListener.setFadingIn(true); mTodayAnimatorListener.setAnimator(mTodayAnimator); mTodayAnimator.addListener(mTodayAnimatorListener); diff --git a/app/src/main/java/com/android/calendar/EventUtils.java b/app/src/main/java/com/android/calendar/EventUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..4fc170ffe12155316cbfcb012b53bc97614e5f00 --- /dev/null +++ b/app/src/main/java/com/android/calendar/EventUtils.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.android.calendar; + +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.provider.CalendarContract; +import android.text.TextUtils; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; + +import com.android.calendar.event.EditEventActivity; +import com.android.calendar.event.ExtendedProperty; +import com.android.calendar.icalendar.Attendee; +import com.android.calendar.icalendar.IcalendarUtils; +import com.android.calendar.icalendar.VEvent; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.TimeZone; + +import ws.xsoh.etar.R; + +public class EventUtils { + private final static String TAG = EventUtils.class.getName(); + private EventUtils() { + } + + @NonNull + public static Bundle createBundleFromEvent(VEvent event, Context context) { + Bundle bundle = new Bundle(); + + bundle.putString(CalendarContract.Events.TITLE, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.SUMMARY))); + bundle.putString(CalendarContract.Events.EVENT_LOCATION, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.LOCATION))); + bundle.putString(CalendarContract.Events.DESCRIPTION, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.DESCRIPTION))); + bundle.putString(ExtendedProperty.URL, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.URL))); + bundle.putString(CalendarContract.Events.ORGANIZER, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.ORGANIZER))); + bundle.putString(CalendarContract.Events.RRULE, + IcalendarUtils.uncleanseString(event.getProperty(VEvent.RRULE))); + + if (event.mAttendees.size() > 0) { + StringBuilder builder = new StringBuilder(); + for (Attendee attendee : event.mAttendees) { + builder.append(attendee.mEmail); + builder.append(","); + } + bundle.putString(Intent.EXTRA_EMAIL, builder.toString()); + } + + String dtStart = event.getProperty(VEvent.DTSTART); + String dtStartParam = event.getPropertyParameters(VEvent.DTSTART); + if (!TextUtils.isEmpty(dtStart)) { + bundle.putLong(CalendarContract.EXTRA_EVENT_BEGIN_TIME, + getLocalTimeFromString(dtStart, dtStartParam, context)); + } + + String dtEnd = event.getProperty(VEvent.DTEND); + String dtEndParam = event.getPropertyParameters(VEvent.DTEND); + if (dtEnd != null && !TextUtils.isEmpty(dtEnd)) { + bundle.putLong(CalendarContract.EXTRA_EVENT_END_TIME, + getLocalTimeFromString(dtEnd, dtEndParam, context)); + } else { + // Treat start date as end date if un-specified + dtEnd = dtStart; + dtEndParam = dtStartParam; + } + + boolean isAllDay = getLocalTimeFromString(dtEnd, dtEndParam, context) + - getLocalTimeFromString(dtStart, dtStartParam, context) == 24*60*60*1000; + + + if (isTimeStartOfDay(dtStart, dtStartParam, context)) { + bundle.putBoolean(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay); + } + //Check if some special property which say it is a "All-Day" event. + + String microsoft_all_day_event = event.getProperty("X-MICROSOFT-CDO-ALLDAYEVENT"); + if (!TextUtils.isEmpty(microsoft_all_day_event) && microsoft_all_day_event.equals("TRUE")) { + bundle.putBoolean(CalendarContract.EXTRA_EVENT_ALL_DAY, true); + } + + bundle.putBoolean(EditEventActivity.EXTRA_READ_ONLY, true); + + return bundle; + } + + private static boolean isTimeStartOfDay(String dtStart, String dtStartParam, Context context) { + // convert to epoch milli seconds + long timeStamp = getLocalTimeFromString(dtStart, dtStartParam, context); + Date date = new Date(timeStamp); + + DateFormat dateFormat = new SimpleDateFormat("HH:mm"); + String dateStr = dateFormat.format(date); + if (dateStr.equals("00:00")) { + return true; + } + return false; + } + + private static long getLocalTimeFromString(String iCalDate, String iCalDateParam, Context context) { + // see https://tools.ietf.org/html/rfc5545#section-3.3.5 + + // FORM #2: DATE WITH UTC TIME, e.g. 19980119T070000Z + if (iCalDate.endsWith("Z")) { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + + try { + format.parse(iCalDate); + format.setTimeZone(TimeZone.getDefault()); + return format.getCalendar().getTimeInMillis(); + } catch (ParseException exception) { + Log.e(TAG, "Can't parse iCalDate:", exception); + } + } + + // FORM #3: DATE WITH LOCAL TIME AND TIME ZONE REFERENCE, e.g. TZID=America/New_York:19980119T020000 + else if (iCalDateParam != null && iCalDateParam.startsWith("TZID=")) { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); + String timeZone = iCalDateParam.substring(5).replace("\"", ""); + // This is a pretty hacky workaround to prevent exact parsing of VTimezones. + // It assumes the TZID to be refered to with one of the names recognizable by Java. + // (which are quite a lot, see e.g. http://tutorials.jenkov.com/java-date-time/java-util-timezone.html) + if (Arrays.asList(TimeZone.getAvailableIDs()).contains(timeZone)) { + format.setTimeZone(TimeZone.getTimeZone(timeZone)); + } else { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + String convertedTimeZoneId = android.icu.util.TimeZone + .getIDForWindowsID(timeZone, "001"); + if (convertedTimeZoneId != null && !convertedTimeZoneId.equals("")) { + format.setTimeZone(TimeZone.getTimeZone(convertedTimeZoneId)); + } else { + format.setTimeZone(TimeZone.getDefault()); + Toast.makeText( + context, + context.getString(R.string.cal_import_error_time_zone_msg, timeZone), + Toast.LENGTH_SHORT).show(); + } + } else { + format.setTimeZone(TimeZone.getDefault()); + Toast.makeText( + context, + context.getString(R.string.cal_import_error_time_zone_msg, timeZone), + Toast.LENGTH_SHORT).show(); + } + } + try { + format.parse(iCalDate); + return format.getCalendar().getTimeInMillis(); + } catch (ParseException exception) { + Log.e(TAG, "Can't parse iCalDate:", exception); + } + } + + // ONLY DATE, e.g. 20190415 + else if (iCalDateParam != null && iCalDateParam.equals("VALUE=DATE")) { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd"); + format.setTimeZone(TimeZone.getDefault()); + + try { + format.parse(iCalDate); + return format.getCalendar().getTimeInMillis(); + } catch (ParseException exception) { + Log.e(TAG, "Can't parse iCalDate:", exception); + } + } + + // FORM #1: DATE WITH LOCAL TIME, e.g. 19980118T230000 + else { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); + format.setTimeZone(TimeZone.getDefault()); + + try { + format.parse(iCalDate); + return format.getCalendar().getTimeInMillis(); + } catch (ParseException exception) { + Log.e(TAG, "Can't parse iCalDate:", exception); + } + } + + Toast.makeText(context, context.getString(R.string.cal_import_error_date_msg, iCalDate), Toast.LENGTH_SHORT).show(); + + return System.currentTimeMillis(); + } +} diff --git a/app/src/main/java/com/android/calendar/ImportActivity.java b/app/src/main/java/com/android/calendar/ImportActivity.java index c55f31c6fcb5a8a6dc0f9f91a5602485f9772c52..f97988d084d7a27ff46728471f07b346317ce530 100644 --- a/app/src/main/java/com/android/calendar/ImportActivity.java +++ b/app/src/main/java/com/android/calendar/ImportActivity.java @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + package com.android.calendar; import android.app.Activity; @@ -25,9 +43,11 @@ import java.io.File; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.LinkedList; +import java.util.List; import java.util.TimeZone; import ws.xsoh.etar.R; @@ -142,15 +162,37 @@ public class ImportActivity extends Activity { return; } - Intent calIntent = new Intent(Intent.ACTION_INSERT); - calIntent.setType("vnd.android.cursor.item/event"); - LinkedList events = calendar.getAllEvents(); - if (events == null) { + if (events == null || events.isEmpty()) { showErrorToast(); return; } + if (events.size() == 1){ + handleSingleEvent(calendar); + } else { + handleMultipleEvents(events); + } + } + + private void handleMultipleEvents(List events) { + Intent intent = new Intent(this, AllInOneActivity.class); + ArrayList bundleList = new ArrayList<>(); + + for (VEvent event : events) { + bundleList.add(EventUtils.createBundleFromEvent(event, this)); + } + + intent.putParcelableArrayListExtra(AllInOneActivity.BUNDLE_KEY_MULTIPLE_EVENTS, bundleList); + startActivity(intent); + + finish(); + } + + private void handleSingleEvent(VCalendar calendar) { + Intent calIntent = new Intent(Intent.ACTION_INSERT); + calIntent.setType("vnd.android.cursor.item/event"); + VEvent firstEvent = calendar.getAllEvents().getFirst(); calIntent.putExtra(CalendarContract.Events.TITLE, IcalendarUtils.uncleanseString(firstEvent.getProperty(VEvent.SUMMARY))); diff --git a/app/src/main/java/com/android/calendar/Utils.java b/app/src/main/java/com/android/calendar/Utils.java index fd7396b4625ea03e63afd13b7b8ab20d7661c9ac..b95b4687db1a3654a57eec6d10bb1439d4f2a4bf 100644 --- a/app/src/main/java/com/android/calendar/Utils.java +++ b/app/src/main/java/com/android/calendar/Utils.java @@ -242,26 +242,8 @@ public class Utils { * exist but cannot be configured by the user. */ public static boolean isMonetAvailable(Context context) { - if (Build.VERSION.SDK_INT < 31) { - return false; - } - - // Wallpaper-based theming requires a color extraction engine and is enabled when the `flag_monet` - // config flag is enabled in SystemUI. It's unclear how to access this information from a - // normal application. - // - // To determine whether Material You is available on the device, we use a naive heuristic which - // is to compare the palette against known default values in AOSP. - Resources resources = context.getResources(); - int probe1 = resources.getColor(android.R.color.system_accent1_500, context.getTheme()); - int probe2 = resources.getColor(android.R.color.system_accent2_500, context.getTheme()); - if (probe1 == Color.parseColor("#007fac") && probe2 == Color.parseColor("#657985")) { - // AOSP palette - Log.d(TAG, "Material You not available - Detected AOSP palette"); - return false; - } - return true; + return false; } public static int getViewTypeFromIntentAndSharedPref(Activity activity) { diff --git a/app/src/main/java/com/android/calendar/alerts/AlertReceiver.java b/app/src/main/java/com/android/calendar/alerts/AlertReceiver.java index caf099ff11b1da5808547dcc3daeffa65a1b9eb7..a909d90b07faefe2d5a42850d53bef1336b09389 100644 --- a/app/src/main/java/com/android/calendar/alerts/AlertReceiver.java +++ b/app/src/main/java/com/android/calendar/alerts/AlertReceiver.java @@ -20,6 +20,7 @@ package com.android.calendar.alerts; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; +import android.app.TaskStackBuilder; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentUris; @@ -137,7 +138,7 @@ public class AlertReceiver extends BroadcastReceiver { if (Utils.isUpsideDownCakeOrLater() && !Utils.canScheduleAlarms(context)) { return; } - context.startForegroundService(intent); + context.startService(intent); } else { context.startService(intent); } @@ -682,6 +683,15 @@ public class AlertReceiver extends BroadcastReceiver { geoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // If this intent cannot be handled, do not create the map action if (isResolveIntent(context, geoIntent)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context); + geoIntent = createMapActivityIntent(context, urlSpans); + if (geoIntent != null) { + taskStackBuilder.addNextIntentWithParentStack(geoIntent); + return taskStackBuilder.getPendingIntent(0, + PendingIntent.FLAG_UPDATE_CURRENT | Utils.PI_FLAG_IMMUTABLE); + } + } Intent broadcastIntent = new Intent(MAP_ACTION); broadcastIntent.setClass(context, AlertReceiver.class); broadcastIntent.putExtra(EXTRA_EVENT_ID, eventId); diff --git a/app/src/main/java/com/android/calendar/alerts/AlertService.java b/app/src/main/java/com/android/calendar/alerts/AlertService.java index 1caab2322f683ae1c1ef31ee8af25a5362ef740a..ef49aa36b3bf457a059c2cf216dbd9becb17f135 100644 --- a/app/src/main/java/com/android/calendar/alerts/AlertService.java +++ b/app/src/main/java/com/android/calendar/alerts/AlertService.java @@ -534,15 +534,13 @@ public class AlertService extends Service { int newState = -1; boolean newAlert = false; - // Uncomment for the behavior of clearing out alerts after the - // events ended. b/1880369 - // - // if (endTime < currentTime) { - // newState = CalendarAlerts.DISMISSED; - // } else + // clearing out alerts after the events ended. b/1880369 + if (endTime < currentTime) { + newState = CalendarAlerts.STATE_DISMISSED; + } // Remove declined events - boolean sendAlert = !declined; + boolean sendAlert = !declined && newState != CalendarAlerts.STATE_DISMISSED; // Check for experimental reminder settings. if (remindRespondedOnly) { // If the experimental setting is turned on, then only send @@ -930,27 +928,6 @@ public class AlertService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { - - if (Utils.isOreoOrLater()) { - createChannels(this); - Notification notification = new NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID) - .setContentTitle(getString(R.string.foreground_notification_title)) - .setSmallIcon(R.drawable.stat_notify_refresh_events) - .setShowWhen(false) - .build(); - if (Utils.isQOrLater()) { - int serviceType; - if (Utils.isUpsideDownCakeOrLater()) { - serviceType = FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED; - } else { - serviceType = FOREGROUND_SERVICE_TYPE_DATA_SYNC; - } - ServiceCompat.startForeground(this, 1337, notification, serviceType); - } else { - startForeground(1337, notification); - } - } - Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent.getExtras(); diff --git a/app/src/main/java/com/android/calendar/event/CalendarPickerAdapter.java b/app/src/main/java/com/android/calendar/event/CalendarPickerAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..8c1e25ad2063fe0f15079f9aa49856f035254dd6 --- /dev/null +++ b/app/src/main/java/com/android/calendar/event/CalendarPickerAdapter.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.android.calendar.event; + +import android.content.Context; +import android.database.Cursor; +import android.provider.CalendarContract; +import android.view.View; +import android.widget.ResourceCursorAdapter; +import android.widget.TextView; + +import com.android.calendar.Utils; + +import ws.xsoh.etar.R; + +public class CalendarPickerAdapter extends ResourceCursorAdapter { + + public CalendarPickerAdapter(Context context, int resourceId, Cursor cursor) { + super(context, resourceId, cursor, 0); // No selection flags added to avoid deprecated call + setDropDownViewResource(R.layout.calendars_dropdown_item); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + View colorBar = view.findViewById(R.id.color); + int colorColumn = cursor.getColumnIndexOrThrow(CalendarContract.Calendars.CALENDAR_COLOR); + if (colorBar != null) { + colorBar.setBackgroundColor( + Utils.getDisplayColorFromColor( + context, + cursor.getInt(colorColumn) + ) + ); + } + + int nameColumn = cursor.getColumnIndexOrThrow(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME); + int ownerColumn = cursor.getColumnIndexOrThrow(CalendarContract.Calendars.OWNER_ACCOUNT); + + TextView name = view.findViewById(R.id.calendar_name); + if (name == null) return; + String displayName = cursor.getString(nameColumn); + name.setText(displayName); + + TextView accountName = view.findViewById(R.id.account_name); + if (accountName == null) return; + accountName.setText(cursor.getString(ownerColumn)); + accountName.setVisibility(TextView.VISIBLE); + } +} diff --git a/app/src/main/java/com/android/calendar/event/CalendarPickerDialogFragment.java b/app/src/main/java/com/android/calendar/event/CalendarPickerDialogFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..0f7ca9c7aed4f1ec9e42d62c2a65fbea34f8ed2b --- /dev/null +++ b/app/src/main/java/com/android/calendar/event/CalendarPickerDialogFragment.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.android.calendar.event; + + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.provider.CalendarContract; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Spinner; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.DialogFragment; + +import ws.xsoh.etar.R; + +/** + * Allows the user to quickly import a multi event cal file. + */ +public class CalendarPickerDialogFragment extends DialogFragment implements AdapterView.OnItemSelectedListener, CalendarPickerQueryListener { + + public static final String FRAGMENT_TAG = "PICK_CALENDAR_DIALOG"; + public static final int SPINNER_DEFAULT_POSITION = 0; + private static final int TOKEN_CALENDARS = 8; + private static final int EVENT_INDEX_OWNER_ACCOUNT = 2; + private static final int EVENT_INDEX_ACCOUNT_NAME = 11; + private static final String BUNDLE_KEY_RESTORE_SELECTED_SPINNER_ITEM_POSITION = "selected_spinner_item_position"; + private static final String BUNDLE_KEY_RESTORE_NUMBER_OF_EVENTS = "number_of_events"; + private String mSyncAccountName = null; + private long mPickedCalendarId = -1; + private Cursor mCalendarsCursor; + private String mOwnerAccount; + private Spinner mCalendarsSpinner; + private int mSelectedSpinnerItemPosition = SPINNER_DEFAULT_POSITION; + // Instance of class that request to show this dialog and which expect the selected calendar + private CalendarPickerDialogListener calendarPickerDialogListener; + private int mNumberOfEvents; + + public CalendarPickerDialogFragment() { + } + + public CalendarPickerDialogFragment(int numberOfEvents) { + this.mNumberOfEvents = numberOfEvents; + } + + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + if (context instanceof CalendarPickerDialogListener) { + calendarPickerDialogListener = (CalendarPickerDialogListener) context; + } else { + throw new RuntimeException(context + " must implement CalendarPickerDialogListener"); + } + } + + @Override + public void onDetach() { + calendarPickerDialogListener = null; + super.onDetach(); + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + initiateCalendarQueryHandler(); + + // Save and restore flow + if (savedInstanceState != null) { + mSelectedSpinnerItemPosition = savedInstanceState.getInt(BUNDLE_KEY_RESTORE_SELECTED_SPINNER_ITEM_POSITION); + mNumberOfEvents = savedInstanceState.getInt(BUNDLE_KEY_RESTORE_NUMBER_OF_EVENTS); + } + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(BUNDLE_KEY_RESTORE_SELECTED_SPINNER_ITEM_POSITION, mSelectedSpinnerItemPosition); + outState.putInt(BUNDLE_KEY_RESTORE_NUMBER_OF_EVENTS, mNumberOfEvents); + } + + @Override + public void onDestroyView() { + closeCursor(); + super.onDestroyView(); + } + + @NonNull + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + // onCreateDialog() gets called before onCreateView(), so the view needs to be created and supplied here + // getView() returns null at this point + View view = LayoutInflater.from(requireContext()).inflate(R.layout.pick_calendar_dialog, null); + + mCalendarsSpinner = view.findViewById(R.id.calendars_spinner); + mCalendarsSpinner.setSelection(mSelectedSpinnerItemPosition); + + TextView dialogMessage = view.findViewById(R.id.pick_calendar_dialog_text); + dialogMessage.setText(getString(R.string.pick_calendar_dialog_text, mNumberOfEvents)); + + return new AlertDialog.Builder(requireActivity()) + .setTitle(R.string.pick_calendar_dialog_title) + .setView(view) + .setPositiveButton(R.string.pick_calendar_dialog_validate, + (dialog, which) -> { + calendarPickerDialogListener.onCalendarPicked(mPickedCalendarId, mOwnerAccount, mSyncAccountName); + dismiss(); + }) + .setNegativeButton(android.R.string.cancel, (dialog, which) -> dismiss()) + .create(); + } + + private void closeCursor() { + if (mCalendarsCursor != null && !mCalendarsCursor.isClosed()) { + mCalendarsCursor.close(); + } + } + + private void initiateCalendarQueryHandler() { + final ContentResolver contentResolver = requireActivity().getContentResolver(); + if (contentResolver == null) { + return; + } + + CalendarPickerQueryHandler calendarPickerQueryHandler = new CalendarPickerQueryHandler(contentResolver, requireActivity(), this); + + calendarPickerQueryHandler.startQuery( + TOKEN_CALENDARS, + null, + CalendarContract.Calendars.CONTENT_URI, + EditEventHelper.CALENDARS_PROJECTION, + EditEventHelper.CALENDARS_WHERE_WRITEABLE_VISIBLE, + null /* selection args */, + null /* sort order */ + ); + } + + public void setCalendarsCursor(Cursor cursor) { + mCalendarsCursor = cursor; + + if (mCalendarsCursor.moveToFirst()) { + mOwnerAccount = mCalendarsCursor.getString(EVENT_INDEX_OWNER_ACCOUNT); + mSyncAccountName = mCalendarsCursor.getString(EVENT_INDEX_ACCOUNT_NAME); + bindCalendarSpinnerUi(); + } + } + + private void bindCalendarSpinnerUi() { + CalendarPickerAdapter adapter = new CalendarPickerAdapter(requireContext(), + R.layout.calendars_spinner_item, + mCalendarsCursor); + + mCalendarsSpinner.setAdapter(adapter); + mCalendarsSpinner.setOnItemSelectedListener(this); + + // Restore Spinner's position if there's any saved on configuration changes + if (mSelectedSpinnerItemPosition != SPINNER_DEFAULT_POSITION) { + mCalendarsSpinner.setSelection(mSelectedSpinnerItemPosition); + } + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + mSelectedSpinnerItemPosition = position; + mPickedCalendarId = id; + } + + @Override + public void onNothingSelected(AdapterView parent) { + mPickedCalendarId = -1; + } + + @Override + public void onCursorAvailable(Cursor cursor) { + setCalendarsCursor(cursor); + } + + @Override + public void onCursorUnavailable() { + dismiss(); + calendarPickerDialogListener.onCalendarUnavailable(); + } + + @Override + public void onCalendarPickerError() { + calendarPickerDialogListener.onCalendarPickerError(); + } + + public interface CalendarPickerDialogListener { + void onCalendarPicked(long selectedCalendarId, String ownerAccount, String syncAccountName); + + void onCalendarUnavailable(); + + void onCalendarPickerError(); + } +} + diff --git a/app/src/main/java/com/android/calendar/event/CalendarPickerQueryHandler.java b/app/src/main/java/com/android/calendar/event/CalendarPickerQueryHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..ac8704651f2377f19857238f030838a904806b89 --- /dev/null +++ b/app/src/main/java/com/android/calendar/event/CalendarPickerQueryHandler.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.android.calendar.event; + +import android.app.Activity; +import android.content.AsyncQueryHandler; +import android.content.ContentResolver; +import android.database.Cursor; +import android.database.MatrixCursor; + +import com.android.calendar.Utils; + +import java.lang.ref.WeakReference; + +public class CalendarPickerQueryHandler extends AsyncQueryHandler { + private final WeakReference activityReference; + private final WeakReference listenerReference; + + public CalendarPickerQueryHandler(ContentResolver contentResolver, Activity activity, CalendarPickerQueryListener calendarPickerQueryListener) { + super(contentResolver); + activityReference = new WeakReference<>(activity); + listenerReference = new WeakReference<>(calendarPickerQueryListener); + } + + @Override + protected void onQueryComplete(int token, Object cookie, Cursor cursor) { + super.onQueryComplete(token, cookie, cursor); + + final CalendarPickerQueryListener queryListener = listenerReference.get(); + + if (queryListener == null) { + return; + } + + if (cursor == null || cursor.getCount() == 0) { + queryListener.onCursorUnavailable(); + return; + } + + final Activity activity = activityReference.get(); + if (activity == null || activity.isFinishing()) { + cursor.close(); + queryListener.onCalendarPickerError(); + return; + } + + try (cursor) { + MatrixCursor matrixCursor = Utils.matrixCursorFromCursor(cursor); + queryListener.onCursorAvailable(matrixCursor); + } + } +} diff --git a/app/src/main/java/com/android/calendar/event/CalendarPickerQueryListener.java b/app/src/main/java/com/android/calendar/event/CalendarPickerQueryListener.java new file mode 100644 index 0000000000000000000000000000000000000000..b8aca376364345f71e84560c6d0873f31c7d3061 --- /dev/null +++ b/app/src/main/java/com/android/calendar/event/CalendarPickerQueryListener.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 MURENA SAS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.android.calendar.event; + +import android.database.Cursor; + +public interface CalendarPickerQueryListener { + void onCursorAvailable(Cursor cursor); + + void onCursorUnavailable(); + + void onCalendarPickerError(); +} diff --git a/app/src/main/java/com/android/calendar/icalendar/VCalendar.java b/app/src/main/java/com/android/calendar/icalendar/VCalendar.java index 8799eb4357cc8f82b6d2a7a3a52f4b0903ac86a8..bdbd84937f6a8721b546f8f6ebfd19c2b7d55971 100644 --- a/app/src/main/java/com/android/calendar/icalendar/VCalendar.java +++ b/app/src/main/java/com/android/calendar/icalendar/VCalendar.java @@ -33,7 +33,7 @@ public class VCalendar { public static String CALSCALE = "CALSCALE"; public static String METHOD = "METHOD"; - public final static String PRODUCT_IDENTIFIER = "-//Etar//ws.xsoh.etar"; + public final static String PRODUCT_IDENTIFIER = "-//Etar//foundation.e.calendar"; // Stores the -arity of the attributes that this component can have private final static HashMap sPropertyList = new HashMap(); diff --git a/app/src/main/java/com/android/calendar/icalendar/VEvent.java b/app/src/main/java/com/android/calendar/icalendar/VEvent.java index 09d3b7f92e01ba52028c207e03ab438626aa4db0..9311bbd82a5bd7d73f907ef5f7e99300184bdaab 100644 --- a/app/src/main/java/com/android/calendar/icalendar/VEvent.java +++ b/app/src/main/java/com/android/calendar/icalendar/VEvent.java @@ -90,7 +90,7 @@ public class VEvent { mAttendees = new LinkedList(); // Generate and add a unique identifier to this event - iCal requisite - addProperty(UID , UUID.randomUUID().toString() + "@ws.xsoh.etar"); + addProperty(UID , UUID.randomUUID().toString() + "@foundation.e.calendar"); addTimeStamp(); } diff --git a/app/src/main/java/com/android/calendar/month/MonthWeekEventsView.java b/app/src/main/java/com/android/calendar/month/MonthWeekEventsView.java index e0a183bb0872c035d4805c0104f8fef859c4e7df..e7345585c2382ee34e282ba29fbe49d05a6edb0e 100644 --- a/app/src/main/java/com/android/calendar/month/MonthWeekEventsView.java +++ b/app/src/main/java/com/android/calendar/month/MonthWeekEventsView.java @@ -28,6 +28,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.Paint.Style; +import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.provider.CalendarContract.Attendees; @@ -43,8 +44,6 @@ import android.view.MotionEvent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; -import androidx.core.content.ContextCompat; - import com.android.calendar.DynamicTheme; import com.android.calendar.Event; import com.android.calendar.LunarUtils; @@ -161,6 +160,7 @@ public class MonthWeekEventsView extends SimpleWeekView { private int mAnimateTodayAlpha = 0; private ObjectAnimator mTodayAnimator = null; private int[] mDayXs; + private static final int EVENT_ADJUST_VALUE = 15; /** * Shows up as an error if we don't include this. @@ -281,7 +281,6 @@ public class MonthWeekEventsView extends SimpleWeekView { mTextSizeEvent *= mScale; mTextSizeEventTitle *= mScale; mTextSizeWeekNum *= mScale; - mDaySeparatorInnerWidth *= mScale; mEventYOffsetPortrait *= mScale; mEventSquareWidth *= mScale; mEventSquareHeight *= mScale; @@ -456,10 +455,8 @@ public class MonthWeekEventsView extends SimpleWeekView { protected void onDraw(Canvas canvas) { drawBackground(canvas); drawWeekNums(canvas); - drawDaySeparators(canvas); - if (mHasToday && mAnimateToday) { - drawToday(canvas); - } + drawHorizontalDaySeparators(canvas); + drawVerticalDaySeparators(canvas); if (mShowDetailsInMonth) { drawEvents(canvas); } else { @@ -491,7 +488,7 @@ public class MonthWeekEventsView extends SimpleWeekView { } @Override - protected void drawDaySeparators(Canvas canvas) { + protected void drawHorizontalDaySeparators(Canvas canvas) { final int coordinatesPerLine = 4; // There are mNumDays - 1 vertical lines and 1 horizontal, so the total is mNumDays float[] lines = new float[mNumDays * coordinatesPerLine]; @@ -502,6 +499,17 @@ public class MonthWeekEventsView extends SimpleWeekView { lines[i++] = 0; lines[i++] = mWidth; lines[i++] = 0; + + p.setColor(mDaySeparatorInnerColor); + p.setStrokeWidth(mDaySeparatorInnerWidth * 4); + canvas.drawLines(lines, 0, lines.length, p); + } + @Override + protected void drawVerticalDaySeparators(Canvas canvas) { + final int coordinatesPerLine = 4; + // There are mNumDays - 1 vertical lines and 1 horizontal, so the total is mNumDays + float[] lines = new float[mNumDays * coordinatesPerLine]; + int i = 0; int y0 = 0; int y1 = mHeight; @@ -514,7 +522,7 @@ public class MonthWeekEventsView extends SimpleWeekView { lines[i++] = y1; } p.setColor(mDaySeparatorInnerColor); - p.setStrokeWidth(mDaySeparatorInnerWidth); + p.setStrokeWidth(mDaySeparatorInnerWidth * 2); canvas.drawLines(lines, 0, lines.length, p); } @@ -522,7 +530,7 @@ public class MonthWeekEventsView extends SimpleWeekView { protected void drawBackground(Canvas canvas) { int i = 0; int offset = 0; - r.top = mDaySeparatorInnerWidth; + r.top = 0; r.bottom = mHeight; if (mShowWeekNum) { i++; @@ -564,14 +572,6 @@ public class MonthWeekEventsView extends SimpleWeekView { canvas.drawRect(r, p); } if (mHasToday) { - int selectedColor = ContextCompat.getColor(mContext, DynamicTheme.getColorId(DynamicTheme.getPrimaryColor(mContext))); - - if (Utils.getSharedPreference(mContext, "pref_theme", "light").equals("light")) { - p.setColor(selectedColor); - p.setAlpha(72); - } else { - p.setColor(mMonthBGTodayColor); - } r.left = computeDayLeftPosition(mTodayIndex); r.right = computeDayLeftPosition(mTodayIndex + 1); canvas.drawRect(r, p); @@ -624,21 +624,46 @@ public class MonthWeekEventsView extends SimpleWeekView { Time time = new Time(mTimeZone); time.setJulianDay(julianMonday); + int todayTextY = getResources().getDimensionPixelSize(R.dimen.current_date_text_y); + int todayEventMargin = getResources().getDimensionPixelSize(R.dimen.current_date_text_event_margin); + for (; i < numCount; i++) { + x = computeDayLeftPosition(i - offset) - (mSidePaddingMonthNumber); + + final float monthNumberTextX = getMonthNumberTextX(x); + if (mHasToday && todayIndex == i) { - mMonthNumPaint.setColor(mMonthNumTodayColor); - mMonthNumPaint.setFakeBoldText(isBold = true); + mMonthNumPaint.setFakeBoldText(isBold = false); if (i + 1 < numCount) { // Make sure the color will be set back on the next // iteration isFocusMonth = !mFocusDay[i + 1]; } + mMonthNumPaint.setColor(getContext().getResources().getColor(R.color.colorAccent)); + final int todayCircleRadius = getResources().getDimensionPixelSize(R.dimen.current_date_bg_size); + + //check text width & height to calculate circle cx and cy values + Rect bounds = new Rect(); + mMonthNumPaint.getTextBounds(mDayNumbers[i], 0, mDayNumbers[i].length(), bounds); + + int textHeight = bounds.height(); + final int todayCircleCenterY = y + todayTextY - (textHeight / 2) - todayEventMargin; + + canvas.drawCircle(monthNumberTextX, + todayCircleCenterY, + todayCircleRadius, mMonthNumPaint); + mMonthNumPaint.setColor(mMonthNumTodayColor); } else if (mFocusDay[i] != isFocusMonth) { isFocusMonth = mFocusDay[i]; mMonthNumPaint.setColor(isFocusMonth ? mMonthNumColor : mMonthNumOtherColor); } - x = computeDayLeftPosition(i - offset) - (mSidePaddingMonthNumber); - canvas.drawText(mDayNumbers[i], x, y, mMonthNumPaint); + + mMonthNumPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.day_number_text_size)); + + mMonthNumPaint.setTextAlign(Align.CENTER); + + canvas.drawText(mDayNumbers[i], monthNumberTextX, + y + todayTextY - todayEventMargin, mMonthNumPaint); if (isBold) { mMonthNumPaint.setFakeBoldText(isBold = false); } @@ -701,6 +726,21 @@ public class MonthWeekEventsView extends SimpleWeekView { } } + private float getMonthNumberTextX(int x) { + final float monthNumberMarginEnd; + if (mShowWeekNum) { + monthNumberMarginEnd = getMonthNumberMarginEnd(); + } else { + monthNumberMarginEnd = 0; + } + + return x - (((float) mWidth / mNumDays) / 2f) + mSidePaddingMonthNumber + monthNumberMarginEnd; + } + + private float getMonthNumberMarginEnd() { + return getResources().getDimensionPixelSize(R.dimen.day_number_margin_end); + } + protected void drawEvents(Canvas canvas) { if (mEvents == null || mEvents.isEmpty()) { return; @@ -1339,8 +1379,8 @@ public class MonthWeekEventsView extends SimpleWeekView { // we want to match the existing appearance of the "event square".) r.left = mBoxBoundaries.getX(); r.right = mBoxBoundaries.getRightEdge(spanningDays) - mStrokeWidthAdj; - r.top = mBoxBoundaries.getY() + mStrokeWidthAdj; - r.bottom = mBoxBoundaries.getY() + mEventHeight * numberOfLines + mBorderSpace * 2 - mStrokeWidthAdj; + r.top = mBoxBoundaries.getY() + mStrokeWidthAdj + EVENT_ADJUST_VALUE; + r.bottom = mBoxBoundaries.getY() + mEventHeight * numberOfLines + mBorderSpace * 2 - mStrokeWidthAdj + EVENT_ADJUST_VALUE; } } @@ -1355,8 +1395,8 @@ public class MonthWeekEventsView extends SimpleWeekView { public void setRectangle(int spanningDays, int numberOfLines) { r.left = mBoxBoundaries.getX(); r.right = mBoxBoundaries.getX() + mEventSquareWidth; - r.top = mBoxBoundaries.getY() + mEventAscentHeight - mEventSquareHeight; - r.bottom = mBoxBoundaries.getY() + mEventAscentHeight + (numberOfLines - 1) * mEventHeight; + r.top = mBoxBoundaries.getY() + mEventAscentHeight - mEventSquareHeight + EVENT_ADJUST_VALUE; + r.bottom = mBoxBoundaries.getY() + mEventAscentHeight + (numberOfLines - 1) * mEventHeight + EVENT_ADJUST_VALUE; } } protected class FixedHeightRegularBoundariesSetter extends RegularBoundariesSetter { @@ -1639,7 +1679,7 @@ public class MonthWeekEventsView extends SimpleWeekView { lineText = baseText.subSequence(mTextLayout.getLineStart(i), mTextLayout.getLineEnd(i)); } - canvas.drawText(lineText.toString(), mBoundaries.getTextX(), mBoundaries.getTextY(), + canvas.drawText(lineText.toString(), mBoundaries.getTextX(), mBoundaries.getTextY() + EVENT_ADJUST_VALUE, getTextPaint()); mBoundaries.moveLinesDown(1); } diff --git a/app/src/main/java/com/android/calendar/month/SimpleWeekView.java b/app/src/main/java/com/android/calendar/month/SimpleWeekView.java index aab255912f7f7a5e57ae8ee47a95ec03ec0e6063..8cb0bd95b5a85061c28ca4966b394d27412e6539 100644 --- a/app/src/main/java/com/android/calendar/month/SimpleWeekView.java +++ b/app/src/main/java/com/android/calendar/month/SimpleWeekView.java @@ -406,7 +406,8 @@ public class SimpleWeekView extends View { protected void onDraw(Canvas canvas) { drawBackground(canvas); drawWeekNums(canvas); - drawDaySeparators(canvas); + drawHorizontalDaySeparators(canvas); + drawVerticalDaySeparators(canvas); } /** @@ -471,7 +472,20 @@ public class SimpleWeekView extends View { * * @param canvas The canvas to draw on */ - protected void drawDaySeparators(Canvas canvas) { + protected void drawHorizontalDaySeparators(Canvas canvas) { + if (mHasSelectedDay) { + r.top = 1; + r.bottom = mHeight - 1; + r.left = mSelectedLeft + 1; + r.right = mSelectedRight - 1; + p.setStrokeWidth(MINI_TODAY_OUTLINE_WIDTH); + p.setStyle(Style.STROKE); + p.setColor(mTodayOutlineColor); + canvas.drawRect(r, p); + } + } + + protected void drawVerticalDaySeparators(Canvas canvas) { if (mHasSelectedDay) { r.top = 1; r.bottom = mHeight - 1; diff --git a/app/src/main/java/com/android/calendar/settings/MainListPreferences.kt b/app/src/main/java/com/android/calendar/settings/MainListPreferences.kt index eacc79f3d51357e8dd5485e6e3644c7f0253fdc5..f83616f8bee720f37d8b8e9c89dffc36675cfb38 100644 --- a/app/src/main/java/com/android/calendar/settings/MainListPreferences.kt +++ b/app/src/main/java/com/android/calendar/settings/MainListPreferences.kt @@ -197,7 +197,7 @@ class MainListPreferences : PreferenceFragmentCompat() { */ private fun launchDavX5Login() { val davX5Intent = Intent() - davX5Intent.setClassName("at.bitfire.davdroid", "at.bitfire.davdroid.ui.setup.LoginActivity") + davX5Intent.setClassName("foundation.e.accountmanager", "at.bitfire.davdroid.ui.setup.LoginActivity") if (requireActivity().packageManager.resolveActivity(davX5Intent, 0) != null) { startActivityForResult(davX5Intent, ACTION_REQUEST_CODE_DAVX5_SETUP) diff --git a/app/src/main/java/com/android/calendar/widget/CalendarAppWidgetService.java b/app/src/main/java/com/android/calendar/widget/CalendarAppWidgetService.java index d26d10f414a77b3100e30de34f687445a724706c..24b4203fdd2f807afb812feab692126581568f51 100644 --- a/app/src/main/java/com/android/calendar/widget/CalendarAppWidgetService.java +++ b/app/src/main/java/com/android/calendar/widget/CalendarAppWidgetService.java @@ -297,7 +297,7 @@ public class CalendarAppWidgetService extends RemoteViewsService { int past_bg_color = R.color.agenda_past_days_bar_background_color; views.setInt(R.id.widget_row, "setBackgroundResource", past_bg_color); } else { - int future_bg_color = DynamicTheme.getWidgetBackgroundStyle(mContext); + int future_bg_color = R.color.calendar_future_bg_color; views.setInt(R.id.widget_row, "setBackgroundResource", future_bg_color); } diff --git a/app/src/main/res/drawable/actionbar_cursor.xml b/app/src/main/res/drawable/actionbar_cursor.xml index 2ffd9680bf34f24e47bc59e63d865653ce62d8de..571cdc6f6b71035ed1cf29aa5c7ae2243e57af87 100644 --- a/app/src/main/res/drawable/actionbar_cursor.xml +++ b/app/src/main/res/drawable/actionbar_cursor.xml @@ -1,6 +1,6 @@ - + diff --git a/app/src/main/res/drawable/button_drawable.xml b/app/src/main/res/drawable/button_drawable.xml new file mode 100644 index 0000000000000000000000000000000000000000..abc11ff714b2b828a305b7b14de09cfe9ba43dc7 --- /dev/null +++ b/app/src/main/res/drawable/button_drawable.xml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/e_day_1.xml b/app/src/main/res/drawable/e_day_1.xml new file mode 100644 index 0000000000000000000000000000000000000000..2615cefb0633e22db8ba0da5bdebb17c4c9bbb1a --- /dev/null +++ b/app/src/main/res/drawable/e_day_1.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_10.xml b/app/src/main/res/drawable/e_day_10.xml new file mode 100644 index 0000000000000000000000000000000000000000..145c3f9289225e5cbc9f862210bd35e99cf30318 --- /dev/null +++ b/app/src/main/res/drawable/e_day_10.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_11.xml b/app/src/main/res/drawable/e_day_11.xml new file mode 100644 index 0000000000000000000000000000000000000000..293efbd24808ca01954ad79e0e99a1e4dca2aa74 --- /dev/null +++ b/app/src/main/res/drawable/e_day_11.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_12.xml b/app/src/main/res/drawable/e_day_12.xml new file mode 100644 index 0000000000000000000000000000000000000000..b5b31ecdf49cd79de2f3ba6ba29e3d1765f52d9b --- /dev/null +++ b/app/src/main/res/drawable/e_day_12.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_13.xml b/app/src/main/res/drawable/e_day_13.xml new file mode 100644 index 0000000000000000000000000000000000000000..65d6553055014603c345ca33b8ee2bcf64706d65 --- /dev/null +++ b/app/src/main/res/drawable/e_day_13.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_14.xml b/app/src/main/res/drawable/e_day_14.xml new file mode 100644 index 0000000000000000000000000000000000000000..1f9c341ef31f37bbc43e0db6a51a9cbb66d4d6cb --- /dev/null +++ b/app/src/main/res/drawable/e_day_14.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_15.xml b/app/src/main/res/drawable/e_day_15.xml new file mode 100644 index 0000000000000000000000000000000000000000..e67c43fc4cd6f44fbd15ab1c9b3301fd2988551d --- /dev/null +++ b/app/src/main/res/drawable/e_day_15.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_16.xml b/app/src/main/res/drawable/e_day_16.xml new file mode 100644 index 0000000000000000000000000000000000000000..ceecd0f5b17e7a396610c5858e9bc7bee05ab5fa --- /dev/null +++ b/app/src/main/res/drawable/e_day_16.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_17.xml b/app/src/main/res/drawable/e_day_17.xml new file mode 100644 index 0000000000000000000000000000000000000000..9417f7769d4a7704b28bb42d5962c44c891b02d2 --- /dev/null +++ b/app/src/main/res/drawable/e_day_17.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_18.xml b/app/src/main/res/drawable/e_day_18.xml new file mode 100644 index 0000000000000000000000000000000000000000..77e3a93a9a8730330f4a2de26590cc99d0bb3b28 --- /dev/null +++ b/app/src/main/res/drawable/e_day_18.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_19.xml b/app/src/main/res/drawable/e_day_19.xml new file mode 100644 index 0000000000000000000000000000000000000000..83ef274e9d7d0cf5e684323fc07e1f9e8525b60c --- /dev/null +++ b/app/src/main/res/drawable/e_day_19.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_2.xml b/app/src/main/res/drawable/e_day_2.xml new file mode 100644 index 0000000000000000000000000000000000000000..325e7842cee85804e49809803ad8b414feefd212 --- /dev/null +++ b/app/src/main/res/drawable/e_day_2.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_20.xml b/app/src/main/res/drawable/e_day_20.xml new file mode 100644 index 0000000000000000000000000000000000000000..1cb30c1bd22193e8f0a4dc42a23f093a306a0a49 --- /dev/null +++ b/app/src/main/res/drawable/e_day_20.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_21.xml b/app/src/main/res/drawable/e_day_21.xml new file mode 100644 index 0000000000000000000000000000000000000000..d42dfec1ca99759433b01fb537c4b26575c6c12f --- /dev/null +++ b/app/src/main/res/drawable/e_day_21.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_22.xml b/app/src/main/res/drawable/e_day_22.xml new file mode 100644 index 0000000000000000000000000000000000000000..37e939517150430e57a5d0d4398da7b01090d3e3 --- /dev/null +++ b/app/src/main/res/drawable/e_day_22.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_23.xml b/app/src/main/res/drawable/e_day_23.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f0681024f7698cfd11500d40db27d4e9c798d57 --- /dev/null +++ b/app/src/main/res/drawable/e_day_23.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_24.xml b/app/src/main/res/drawable/e_day_24.xml new file mode 100644 index 0000000000000000000000000000000000000000..5f2c750c78f4da2a1d99e1b78f0dda9f8d2bc89f --- /dev/null +++ b/app/src/main/res/drawable/e_day_24.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_25.xml b/app/src/main/res/drawable/e_day_25.xml new file mode 100644 index 0000000000000000000000000000000000000000..13e270fa9de2fce8c1bf04b8a7399d2be366c2b5 --- /dev/null +++ b/app/src/main/res/drawable/e_day_25.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_26.xml b/app/src/main/res/drawable/e_day_26.xml new file mode 100644 index 0000000000000000000000000000000000000000..8c83d4348bd562e2190d86baa488b47ec47a6208 --- /dev/null +++ b/app/src/main/res/drawable/e_day_26.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_27.xml b/app/src/main/res/drawable/e_day_27.xml new file mode 100644 index 0000000000000000000000000000000000000000..d801bd5cf9a109d089fed9f1b59018b23dda7344 --- /dev/null +++ b/app/src/main/res/drawable/e_day_27.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_28.xml b/app/src/main/res/drawable/e_day_28.xml new file mode 100644 index 0000000000000000000000000000000000000000..feb57377fc1f6d6d16d63c98123b71f59c8ac30e --- /dev/null +++ b/app/src/main/res/drawable/e_day_28.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_29.xml b/app/src/main/res/drawable/e_day_29.xml new file mode 100644 index 0000000000000000000000000000000000000000..5704f10aee2aac31393fa245816e7903cc3ab621 --- /dev/null +++ b/app/src/main/res/drawable/e_day_29.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_3.xml b/app/src/main/res/drawable/e_day_3.xml new file mode 100644 index 0000000000000000000000000000000000000000..5dc2f3396c22d8ece9c4e5ea14ee7023624aff52 --- /dev/null +++ b/app/src/main/res/drawable/e_day_3.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_30.xml b/app/src/main/res/drawable/e_day_30.xml new file mode 100644 index 0000000000000000000000000000000000000000..2fc6176c4aa53039e66685bef3802f386690df98 --- /dev/null +++ b/app/src/main/res/drawable/e_day_30.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_31.xml b/app/src/main/res/drawable/e_day_31.xml new file mode 100644 index 0000000000000000000000000000000000000000..9a5ac3fc378342e6fee7f5ca883c9790dc3f536b --- /dev/null +++ b/app/src/main/res/drawable/e_day_31.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_4.xml b/app/src/main/res/drawable/e_day_4.xml new file mode 100644 index 0000000000000000000000000000000000000000..c61ba00710cd07a97d8a69d0eddf42f59f4c3629 --- /dev/null +++ b/app/src/main/res/drawable/e_day_4.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_5.xml b/app/src/main/res/drawable/e_day_5.xml new file mode 100644 index 0000000000000000000000000000000000000000..7d04e2d6e57d6fc916258579af3a13967fd342df --- /dev/null +++ b/app/src/main/res/drawable/e_day_5.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_6.xml b/app/src/main/res/drawable/e_day_6.xml new file mode 100644 index 0000000000000000000000000000000000000000..5024d1e08af9f2ffeb0a154982475ddba0fdb81a --- /dev/null +++ b/app/src/main/res/drawable/e_day_6.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_7.xml b/app/src/main/res/drawable/e_day_7.xml new file mode 100644 index 0000000000000000000000000000000000000000..b997ef30f99d85c2149c8f17a64d925805223106 --- /dev/null +++ b/app/src/main/res/drawable/e_day_7.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_8.xml b/app/src/main/res/drawable/e_day_8.xml new file mode 100644 index 0000000000000000000000000000000000000000..52c781f3a7cf0b7c468b31b288bdfb752442d683 --- /dev/null +++ b/app/src/main/res/drawable/e_day_8.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_day_9.xml b/app/src/main/res/drawable/e_day_9.xml new file mode 100644 index 0000000000000000000000000000000000000000..005054128149c9871f9c345d1a81e1eb1e69b647 --- /dev/null +++ b/app/src/main/res/drawable/e_day_9.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/drawable/e_month_april.xml b/app/src/main/res/drawable/e_month_april.xml new file mode 100644 index 0000000000000000000000000000000000000000..aabee11d1c10ab2f114ba6696f064d097f391a55 --- /dev/null +++ b/app/src/main/res/drawable/e_month_april.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_august.xml b/app/src/main/res/drawable/e_month_august.xml new file mode 100644 index 0000000000000000000000000000000000000000..6e389a6e9079a1e8d15fbff94429ada8cb2a7c77 --- /dev/null +++ b/app/src/main/res/drawable/e_month_august.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_december.xml b/app/src/main/res/drawable/e_month_december.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c6c648e7a591ee6b9ad0acbe8a14c4c4603aaca --- /dev/null +++ b/app/src/main/res/drawable/e_month_december.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_february.xml b/app/src/main/res/drawable/e_month_february.xml new file mode 100644 index 0000000000000000000000000000000000000000..92fb99180b4cd668c4a577359e87382838110c0b --- /dev/null +++ b/app/src/main/res/drawable/e_month_february.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_january.xml b/app/src/main/res/drawable/e_month_january.xml new file mode 100644 index 0000000000000000000000000000000000000000..625c573501afb91304d6da86621be08c0688310e --- /dev/null +++ b/app/src/main/res/drawable/e_month_january.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_july.xml b/app/src/main/res/drawable/e_month_july.xml new file mode 100644 index 0000000000000000000000000000000000000000..05c9581728541a01f04c6e0f08e91eb2f820ca3d --- /dev/null +++ b/app/src/main/res/drawable/e_month_july.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_june.xml b/app/src/main/res/drawable/e_month_june.xml new file mode 100644 index 0000000000000000000000000000000000000000..9214d62157e5cc22832f879d52f9a2d02bec1b05 --- /dev/null +++ b/app/src/main/res/drawable/e_month_june.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_march.xml b/app/src/main/res/drawable/e_month_march.xml new file mode 100644 index 0000000000000000000000000000000000000000..dc99f42e2f5f1d6ac746760b9ba5c3b66eea2785 --- /dev/null +++ b/app/src/main/res/drawable/e_month_march.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_may.xml b/app/src/main/res/drawable/e_month_may.xml new file mode 100644 index 0000000000000000000000000000000000000000..6aaacd2dcdfd09bf6f8ec911c233306265b236eb --- /dev/null +++ b/app/src/main/res/drawable/e_month_may.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_november.xml b/app/src/main/res/drawable/e_month_november.xml new file mode 100644 index 0000000000000000000000000000000000000000..f1de93e55bc4597a46308c9f2016c6018254b3ad --- /dev/null +++ b/app/src/main/res/drawable/e_month_november.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_october.xml b/app/src/main/res/drawable/e_month_october.xml new file mode 100644 index 0000000000000000000000000000000000000000..ccc0a23d6de0ce62671a503f616d333fd3e45903 --- /dev/null +++ b/app/src/main/res/drawable/e_month_october.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/e_month_september.xml b/app/src/main/res/drawable/e_month_september.xml new file mode 100644 index 0000000000000000000000000000000000000000..0ea87d4777edd826b10b356b97019759ddfad97c --- /dev/null +++ b/app/src/main/res/drawable/e_month_september.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_add_event.xml b/app/src/main/res/drawable/ic_add_event.xml index e3979cd7f2597352b82bfd3fc497ddeb53641ef9..21ea03fc5e7052fd9107c6d45a1565380b03d5cc 100644 --- a/app/src/main/res/drawable/ic_add_event.xml +++ b/app/src/main/res/drawable/ic_add_event.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml index 71d5bbd292695e3461a7c44f142b0ff3beb7210b..afa5b58fa7beef8e5b7fc097a644f20a07b61da5 100644 --- a/app/src/main/res/drawable/ic_arrow_back.xml +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_baseline_calendar_dayofmonth.xml b/app/src/main/res/drawable/ic_baseline_calendar_dayofmonth.xml index fd08d39ef8f0d2672b0ad01333851356250869dd..f750846400312afa3863564987623776dd9f9129 100644 --- a/app/src/main/res/drawable/ic_baseline_calendar_dayofmonth.xml +++ b/app/src/main/res/drawable/ic_baseline_calendar_dayofmonth.xml @@ -1,5 +1,5 @@ - + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/drawable/ic_delete_event.xml b/app/src/main/res/drawable/ic_delete_event.xml index 8bed121aa6071a86efcb777ff68cd15b8ba4ae31..fadc29db299c21cc9f25ecd7a0fac7f77c39154e 100644 --- a/app/src/main/res/drawable/ic_delete_event.xml +++ b/app/src/main/res/drawable/ic_delete_event.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_edit_event.xml b/app/src/main/res/drawable/ic_edit_event.xml index 46462b57260d4227f22b10e58562ea2e1030a681..db28c372a0d53d915bba894de8c2b568d0f5d839 100644 --- a/app/src/main/res/drawable/ic_edit_event.xml +++ b/app/src/main/res/drawable/ic_edit_event.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 8659cacedcf211b6f425afd692e6d4c23597ff8a..4d26f5bbbcac93f31b5c2e19538de16a4e278ce9 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,17 +1,40 @@ + + - - - - + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index a93768503fa2dfc398e32b7491617ee12c0c21bd..80e8f47c9c1b8f85ca4a64340f535ab3a18d9e63 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -1,41 +1,34 @@ + + - - - - - - - - - + + + + diff --git a/app/src/main/res/drawable/ic_menu_cancel.xml b/app/src/main/res/drawable/ic_menu_cancel.xml index 8514014e61a2fb1132eab4d8751be9bb61caace9..8099e3af98d2fe93d9e01cdb94b8822245c3e9d9 100644 --- a/app/src/main/res/drawable/ic_menu_cancel.xml +++ b/app/src/main/res/drawable/ic_menu_cancel.xml @@ -1,5 +1,5 @@ - + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> diff --git a/app/src/main/res/drawable/ic_menu_navigator.xml b/app/src/main/res/drawable/ic_menu_navigator.xml index de103a677fe2678032988ebab7cd5e9d07ed6b16..f10a32f12aa5ab119318ea28cc69e103989b665f 100644 --- a/app/src/main/res/drawable/ic_menu_navigator.xml +++ b/app/src/main/res/drawable/ic_menu_navigator.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_recurrence_bubble_fill.xml b/app/src/main/res/drawable/ic_recurrence_bubble_fill.xml index ef2d66058535cab939ff4a03cdd2e46a7417d6bf..f274a2232b3b5b2ad38bd481205c13da8b512e7f 100644 --- a/app/src/main/res/drawable/ic_recurrence_bubble_fill.xml +++ b/app/src/main/res/drawable/ic_recurrence_bubble_fill.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorPrimary"> + android:tint="@color/colorAccent"> diff --git a/app/src/main/res/drawable/ic_recurrence_bubble_outline.xml b/app/src/main/res/drawable/ic_recurrence_bubble_outline.xml index 8b84d43e1c6e98027570781eb1fab4489c142cc9..f53e685531de76ac23082b5b5775c560378ebd76 100644 --- a/app/src/main/res/drawable/ic_recurrence_bubble_outline.xml +++ b/app/src/main/res/drawable/ic_recurrence_bubble_outline.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/ic_share_event.xml b/app/src/main/res/drawable/ic_share_event.xml index 045bbc0c0e0460bb7b515c1d80914a253bc7efc3..f2777172d8241f82a9a7a670c3fce017c1437260 100644 --- a/app/src/main/res/drawable/ic_share_event.xml +++ b/app/src/main/res/drawable/ic_share_event.xml @@ -1,4 +1,4 @@ - diff --git a/app/src/main/res/drawable/today_icon.xml b/app/src/main/res/drawable/today_icon.xml index 87b7d69f10b7016563b3e8773a590aa53aa4a259..4a372da139a850304fc8351104aca4e96b0427b3 100644 --- a/app/src/main/res/drawable/today_icon.xml +++ b/app/src/main/res/drawable/today_icon.xml @@ -18,11 +18,9 @@ + android:gravity="center" /> + android:gravity="center" /> diff --git a/app/src/main/res/layout-sw600dp/agenda_day.xml b/app/src/main/res/layout-sw600dp/agenda_day.xml index d9137e8fcdb5b286589437264afdb12b72526d36..9fb78b4eb0291033ff647436b22297f01f68f509 100644 --- a/app/src/main/res/layout-sw600dp/agenda_day.xml +++ b/app/src/main/res/layout-sw600dp/agenda_day.xml @@ -16,6 +16,7 @@ diff --git a/app/src/main/res/layout-sw600dp/agenda_item.xml b/app/src/main/res/layout-sw600dp/agenda_item.xml index f861f54cd6599decd27eee7997872407bae1ca09..6644f1bdccd7b4235d0fb069f6f1145a0d843294 100644 --- a/app/src/main/res/layout-sw600dp/agenda_item.xml +++ b/app/src/main/res/layout-sw600dp/agenda_item.xml @@ -19,6 +19,7 @@ android:id="@android:id/content" android:layout_height="wrap_content" android:layout_width="match_parent" + android:backgroundTint="@color/background_color" android:minHeight="80dip" android:columnCount="3" android:rowCount="2"> diff --git a/app/src/main/res/layout-sw600dp/full_month_header.xml b/app/src/main/res/layout-sw600dp/full_month_header.xml index fb6cee51ff8fc9b3127762d9ac229135c770fc68..31985a34e6202e2918a33c22f9f01e5fdcd4de88 100644 --- a/app/src/main/res/layout-sw600dp/full_month_header.xml +++ b/app/src/main/res/layout-sw600dp/full_month_header.xml @@ -15,6 +15,7 @@ --> - - - - - - - diff --git a/app/src/main/res/layout/agenda_day.xml b/app/src/main/res/layout/agenda_day.xml index 1a5d6c4fd625ce87bcd91c8d98de3966ee35dbef..5e2a18c8cb150cce89575cb4d073c563a05a3732 100644 --- a/app/src/main/res/layout/agenda_day.xml +++ b/app/src/main/res/layout/agenda_day.xml @@ -17,6 +17,7 @@ @@ -34,7 +35,8 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/agenda_fragment.xml b/app/src/main/res/layout/agenda_fragment.xml index db9b554662f219f1314df06545f50767e2a0e4df..59dfed2d2e7701fad9d7e86c4f289a4d1e963a9c 100644 --- a/app/src/main/res/layout/agenda_fragment.xml +++ b/app/src/main/res/layout/agenda_fragment.xml @@ -37,6 +37,6 @@ android:layout_height="match_parent" android:layout_width="0px" android:layout_weight=".60" - android:background="#FFFFFFFF" + android:background="@color/background_color" android:layout_marginTop="5dip"/> - + \ No newline at end of file diff --git a/app/src/main/res/layout/agenda_item.xml b/app/src/main/res/layout/agenda_item.xml index 16f815066eccbda3502372325108d4104c1ed240..1d739bff7d5c7d0936889686700bf92f64f3fcc5 100644 --- a/app/src/main/res/layout/agenda_item.xml +++ b/app/src/main/res/layout/agenda_item.xml @@ -19,6 +19,7 @@ android:id="@android:id/content" android:layout_height="wrap_content" android:layout_width="match_parent" + android:backgroundTint="@color/background_color" android:minHeight="64dip" android:columnCount="3" android:rowCount="2"> @@ -97,4 +98,4 @@ android:visibility="gone" android:contentDescription="@string/acessibility_selected_marker_description" android:background="@drawable/list_multi_left_activated_holo" /> - + \ No newline at end of file diff --git a/app/src/main/res/layout/alert_activity.xml b/app/src/main/res/layout/alert_activity.xml index 51b1086f1f0e137847a77e17b23991359942befd..58e06ac23fef62212e7297b9a829cac20e4a3ac2 100644 --- a/app/src/main/res/layout/alert_activity.xml +++ b/app/src/main/res/layout/alert_activity.xml @@ -40,6 +40,7 @@ android:layout_height="wrap_content" android:layout_weight="1" style="?android:attr/buttonBarButtonStyle" + android:textColor="@color/colorAccent" android:text="@string/dismiss_all_label" /> diff --git a/app/src/main/res/layout/alert_item.xml b/app/src/main/res/layout/alert_item.xml index 79563f1d994cd8bc20e366fe0461eeba1c68f10e..d4f4df366dd5c9b973e3debd40913a8197e603c2 100644 --- a/app/src/main/res/layout/alert_item.xml +++ b/app/src/main/res/layout/alert_item.xml @@ -16,6 +16,7 @@ @@ -58,6 +60,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" + android:textColor="@color/color_default_secondary_text" android:ellipsize="end" android:maxLines="1" android:textSize="14sp" /> @@ -70,7 +73,8 @@ android:layout_marginLeft="5dip" android:src="@drawable/ic_repeat_dark" android:focusable="false" - android:clickable="false" /> + android:clickable="false" + app:tint="@color/colorAccent" /> diff --git a/app/src/main/res/layout/all_in_one_material.xml b/app/src/main/res/layout/all_in_one_material.xml index 32d464e1d10ea8b3cf83e33f6c652b73f6d29bce..3c0420362555d99c90e475ee75d00b9c77efca65 100644 --- a/app/src/main/res/layout/all_in_one_material.xml +++ b/app/src/main/res/layout/all_in_one_material.xml @@ -29,7 +29,12 @@ style="@style/Widget.CalendarAppTheme.ActionBar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" - android:minHeight="?attr/actionBarSize" /> + android:elevation="4dp" + app:popupTheme="@style/Widget.CalendarAppTheme.ActionBar.PopupTheme" + android:minHeight="?attr/actionBarSize" + app:titleTextColor="@color/appbar_text_color" + app:subtitleTextColor="@color/appbar_text_color" + android:theme="@style/Widget.CalendarAppTheme.ActionBar"/> @@ -49,5 +55,9 @@ android:layout_height="match_parent" android:layout_gravity="start" android:fitsSystemWindows="true" - app:menu="@menu/calendar_view" /> + android:background="@color/navigation_drawer_color" + app:menu="@menu/calendar_view" + app:itemTextColor="@color/navigation_drawer_selector" + app:itemIconTint="@color/navigation_drawer_selector" + app:theme="@style/NavigationDrawer"/> diff --git a/app/src/main/res/layout/app_bar.xml b/app/src/main/res/layout/app_bar.xml index 6091f83c3a0bc1c84ff488ad625d578aca1b3280..a81c44aec380a3d0f3a463ff978e61605f5fa023 100644 --- a/app/src/main/res/layout/app_bar.xml +++ b/app/src/main/res/layout/app_bar.xml @@ -4,8 +4,10 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" style="@style/Widget.CalendarAppTheme.ActionBar" + android:elevation="4dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" + app:titleTextColor="@color/appbar_text_color" app:theme="@style/Widget.CalendarAppTheme.ActionBar" app:titleTextAppearance="?attr/settings_titleText" /> diff --git a/app/src/main/res/layout/appwidget.xml b/app/src/main/res/layout/appwidget.xml index 765aae0ca4c7edc1dabc343190c16c9656bbc778..dd8df58597edffc06d9ae1ad7f1053b1dff7534d 100644 --- a/app/src/main/res/layout/appwidget.xml +++ b/app/src/main/res/layout/appwidget.xml @@ -28,6 +28,7 @@ android:id="@+id/header" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@color/colorPrimaryDark" android:gravity="center_vertical|start" android:minHeight="48dip" android:orientation="vertical" diff --git a/app/src/main/res/layout/bubble_event.xml b/app/src/main/res/layout/bubble_event.xml index 30acc4e173cb4dcd489be4ca5dc75f1f5a1cf2cf..cbd7943f4ae692b5768dd0ea0fa59fd835b17881 100644 --- a/app/src/main/res/layout/bubble_event.xml +++ b/app/src/main/res/layout/bubble_event.xml @@ -40,7 +40,8 @@ android:layout_gravity="center" android:layout_marginRight="6dip" android:src="@drawable/ic_alarm_white" - /> + android:tint="@color/foreground_color" + /> + android:tint="@color/foreground_color" + /> + tools:text="@tools:sample/lorem/random" + /> + android:textColor="@color/color_default_primary_text" + tools:text="@tools:sample/lorem/random" + /> diff --git a/app/src/main/res/layout/create_event_dialog.xml b/app/src/main/res/layout/create_event_dialog.xml index c5a0693d48baf14988fc2916bb58dbf36c6d6a1d..aac5b612f908df962eb5c33dbbec818c75233ea0 100644 --- a/app/src/main/res/layout/create_event_dialog.xml +++ b/app/src/main/res/layout/create_event_dialog.xml @@ -80,7 +80,7 @@ android:ellipsize="marquee" android:singleLine="true" android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="?attr/calendar_owner_text_color" /> + android:textColor="@color/color_default_secondary_text" /> diff --git a/app/src/main/res/layout/edit_event_all.xml b/app/src/main/res/layout/edit_event_all.xml index db2cf21fe6072038c1aaf64719ca615d7e13adea..004c3a0af77e3f26ed5fca292c7ebacd8b0283de 100644 --- a/app/src/main/res/layout/edit_event_all.xml +++ b/app/src/main/res/layout/edit_event_all.xml @@ -33,23 +33,29 @@ app:constraint_referenced_ids="timezone_icon,timezone_button" /> - + android:paddingTop="10dp"> + + + + app:layout_constraintTop_toBottomOf="@+id/title_row" /> @@ -407,6 +416,7 @@ android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginEnd="24dp" + android:textColorHint="@color/edit_event_hint_text_color" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/where_icon" app:layout_constraintTop_toBottomOf="@+id/add_attendees_row"> @@ -439,6 +449,7 @@ android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginEnd="24dp" + android:textColorHint="@color/edit_event_hint_text_color" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/description_icon" app:layout_constraintTop_toBottomOf="@+id/where_row"> @@ -471,6 +482,7 @@ android:layout_height="wrap_content" android:layout_marginStart="12dp" android:layout_marginEnd="24dp" + android:textColorHint="@color/edit_event_hint_text_color" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/url_icon" app:layout_constraintTop_toBottomOf="@+id/description_row"> diff --git a/app/src/main/res/layout/edit_event_custom_actionbar.xml b/app/src/main/res/layout/edit_event_custom_actionbar.xml index bad5ca704d16f642df6699d4cbcff1342fc912f7..c7b0f0a2585134e2805156ac572a2b33aa29e752 100644 --- a/app/src/main/res/layout/edit_event_custom_actionbar.xml +++ b/app/src/main/res/layout/edit_event_custom_actionbar.xml @@ -13,49 +13,28 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + android:layout_height="?attr/actionBarSize"> + + - - - - +