├── app
├── .gitignore
├── src
│ └── main
│ │ ├── preset1-web.png
│ │ ├── ic_launcher-web.png
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── single_preset1.png
│ │ │ ├── single_preset2.png
│ │ │ ├── single_preset3.png
│ │ │ ├── multiple_preset1.png
│ │ │ ├── multiple_preset2.png
│ │ │ ├── multiple_preset3.png
│ │ │ ├── multiple_preset4.png
│ │ │ ├── multiple_preset5.png
│ │ │ ├── multiple_preset6.png
│ │ │ ├── warning_icon.xml
│ │ │ ├── action_preview_on_icon.xml
│ │ │ ├── action_refresh_icon.xml
│ │ │ ├── action_preview_off_icon.xml
│ │ │ └── eventlock_icon.xml
│ │ ├── values
│ │ │ ├── attrs.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── urls.xml
│ │ │ ├── styles.xml
│ │ │ ├── internal.xml
│ │ │ ├── constants.xml
│ │ │ └── strings.xml
│ │ ├── layout
│ │ │ ├── content_main.xml
│ │ │ ├── fragment_main.xml
│ │ │ └── activity_main.xml
│ │ ├── menu
│ │ │ └── actions.xml
│ │ └── xml
│ │ │ └── preferences.xml
│ │ ├── assets
│ │ └── xposed_init
│ │ ├── java
│ │ └── com
│ │ │ └── gobbledygook
│ │ │ └── theawless
│ │ │ └── eventlock
│ │ │ ├── receivers
│ │ │ ├── alarms
│ │ │ │ ├── CalendarLoaderAlarm.java
│ │ │ │ ├── CurrentEventUpdaterAlarm.java
│ │ │ │ └── Alarm.java
│ │ │ ├── CommonReceiver.java
│ │ │ └── UpdateReceiver.java
│ │ │ ├── helper
│ │ │ ├── Enums.java
│ │ │ ├── XposedUtils.java
│ │ │ ├── Utils.java
│ │ │ └── Constants.java
│ │ │ ├── app
│ │ │ ├── VersionPreference.java
│ │ │ ├── PresetPreference.java
│ │ │ ├── CalendarPreference.java
│ │ │ ├── PresetMaker.java
│ │ │ ├── MainActivity.java
│ │ │ └── SettingsFragment.java
│ │ │ ├── hooks
│ │ │ ├── XposedUtilsHook.java
│ │ │ └── LockscreenHook.java
│ │ │ ├── gismo
│ │ │ ├── DivisionLinearSnapHelper.java
│ │ │ ├── EventsAdapter.java
│ │ │ ├── EventViewBuildDirector.java
│ │ │ ├── EventsGismo.java
│ │ │ ├── LayoutManagerHandler.java
│ │ │ └── EventViewBuilder.java
│ │ │ ├── services
│ │ │ ├── CalendarLoaderService.java
│ │ │ └── CurrentEventUpdaterService.java
│ │ │ └── events
│ │ │ ├── EventsBuildDirector.java
│ │ │ └── EventsBuilder.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── settings.gradle
├── images
├── banner.png
├── presets.jpg
├── lockscreen.jpg
├── mainscreen.jpg
├── multiple_preset1.jpg
├── multiple_preset2.jpg
├── multiple_preset3.jpg
└── multiple_preset5.jpg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── vcs.xml
├── modules.xml
├── gradle.xml
└── misc.xml
├── gradle.properties
├── .gitignore
├── LICENSE
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/images/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/banner.png
--------------------------------------------------------------------------------
/images/presets.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/presets.jpg
--------------------------------------------------------------------------------
/images/lockscreen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/lockscreen.jpg
--------------------------------------------------------------------------------
/images/mainscreen.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/mainscreen.jpg
--------------------------------------------------------------------------------
/app/src/main/preset1-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/preset1-web.png
--------------------------------------------------------------------------------
/images/multiple_preset1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/multiple_preset1.jpg
--------------------------------------------------------------------------------
/images/multiple_preset2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/multiple_preset2.jpg
--------------------------------------------------------------------------------
/images/multiple_preset3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/multiple_preset3.jpg
--------------------------------------------------------------------------------
/images/multiple_preset5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/images/multiple_preset5.jpg
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/single_preset1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/single_preset1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/single_preset2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/single_preset2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/single_preset3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/single_preset3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset4.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset5.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/multiple_preset6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theawless/EventLock/HEAD/app/src/main/res/drawable/multiple_preset6.png
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.gobbledygook.theawless.eventlock.hooks.XposedUtilsHook
2 | com.gobbledygook.theawless.eventlock.hooks.LockscreenHook
3 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon May 28 09:43:53 IST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/warning_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/receivers/alarms/CalendarLoaderAlarm.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.receivers.alarms;
2 |
3 | import com.gobbledygook.theawless.eventlock.services.CalendarLoaderService;
4 |
5 | public class CalendarLoaderAlarm extends Alarm {
6 | @Override
7 | protected Class getServiceClass() {
8 | return CalendarLoaderService.class;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/receivers/alarms/CurrentEventUpdaterAlarm.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.receivers.alarms;
2 |
3 | import com.gobbledygook.theawless.eventlock.services.CurrentEventUpdaterService;
4 |
5 | public class CurrentEventUpdaterAlarm extends Alarm {
6 | @Override
7 | protected Class getServiceClass() {
8 | return CurrentEventUpdaterService.class;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/res/values/urls.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | https://github.com/theawless/EventLock
4 | https://www.paypal.me/theawless/
5 | https://github.com/theawless/EventLock/issues
6 | https://forum.xda-developers.com/showthread.php?t=3034811
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/helper/Enums.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.helper;
2 |
3 | public class Enums {
4 | public enum EventInfo {
5 | Title,
6 | Time,
7 | Color,
8 | }
9 |
10 | public enum TimesInfo {
11 | Begin,
12 | End,
13 | }
14 |
15 | public enum ItemTag {
16 | Title,
17 | Time,
18 | Image,
19 | }
20 |
21 | public enum Dimensions {
22 | ColorImageView,
23 | EventView,
24 | RecyclerView,
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/VersionPreference.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.content.Context;
4 | import android.preference.Preference;
5 | import android.util.AttributeSet;
6 |
7 | import com.gobbledygook.theawless.eventlock.BuildConfig;
8 |
9 | public class VersionPreference extends Preference {
10 | public VersionPreference(Context context, AttributeSet attrs) {
11 | super(context, attrs);
12 | setSummary(BuildConfig.VERSION_NAME + '.' + BuildConfig.VERSION_CODE);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/action_preview_on_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/action_refresh_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/actions.xml:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 27
5 | defaultConfig {
6 | minSdkVersion 21
7 | targetSdkVersion 23
8 | applicationId "com.gobbledygook.theawless.eventlock"
9 | versionCode 56
10 | versionName "3.4"
11 | vectorDrawables.useSupportLibrary = true
12 | }
13 | }
14 |
15 | dependencies {
16 | implementation fileTree(dir: 'libs', include: ['*.jar'])
17 | implementation 'com.android.support:appcompat-v7:27.1.1'
18 | implementation 'com.android.support:design:27.1.1'
19 | implementation 'joda-time:joda-time:2.9.9'
20 | compileOnly "de.robv.android.xposed:api:53"
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/receivers/CommonReceiver.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.gobbledygook.theawless.eventlock.services.CalendarLoaderService;
8 |
9 | public class CommonReceiver extends BroadcastReceiver {
10 | @Override
11 | public void onReceive(Context context, Intent intent) {
12 | String action = intent.getAction();
13 | if (action != null && (action.equals(Intent.ACTION_BOOT_COMPLETED) || action.equals(Intent.ACTION_PROVIDER_CHANGED))) {
14 | context.startService(new Intent(context, CalendarLoaderService.class));
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## Project-wide Gradle settings.
2 | #
3 | # For more details on how to configure your build environment visit
4 | # http://www.gradle.org/docs/current/userguide/build_environment.html
5 | #
6 | # Specifies the JVM arguments used for the daemon process.
7 | # The setting is particularly useful for tweaking memory settings.
8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
10 | #
11 | # When configured, Gradle will run in incubating parallel mode.
12 | # This option should only be used with decoupled projects. More details, visit
13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
14 | # org.gradle.parallel=true
15 | #Sat Nov 26 19:01:01 IST 2016
16 | org.gradle.jvmargs=-Xmx1536m
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/action_preview_off_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Abhinav Singh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/receivers/alarms/Alarm.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.receivers.alarms;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.support.v4.content.WakefulBroadcastReceiver;
8 |
9 |
10 | public abstract class Alarm extends WakefulBroadcastReceiver {
11 | @Override
12 | public void onReceive(Context context, Intent intent) {
13 | startWakefulService(context, new Intent(context, getServiceClass()).putExtras(intent));
14 | }
15 |
16 | public void setAlarm(Context context, long setTimeMillis, Intent intent) {
17 | PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, new Intent(context, getClass()).putExtras(intent), 0);
18 | AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
19 | if (alarmManager != null) {
20 | alarmManager.setExact(AlarmManager.RTC_WAKEUP, setTimeMillis, alarmIntent);
21 | }
22 | }
23 |
24 | protected abstract Class getServiceClass();
25 | }
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | An Xposed module to show your calendar(s) events on the lockscreen (Android 5.0+ | Lollipop/Marshmallow/Nougat...).
4 |
5 | ### Why?
6 |
7 | * After Kitkat, lockscreen widgets were disabled. Hence, the calendar widget can't be put on the lockscreen.
8 | * AOSP lockscreen for lolipop/marshmallow/nougat does not show calendar events on lockscreen either.
9 |
10 | ### Features:
11 | * Highlights the current event automatically
12 | * Displays upcoming events (scrollable)
13 | * Loads of customisations and presets
14 |
15 |
16 |
17 |
18 |
19 | ### Screenshots
20 |
21 |
22 |
23 |
24 |
25 | ### Requirements
26 |
27 | * Root
28 | * Xposed Installer
29 | * Android 5.0 and above
30 | * AOSP lockscreen
31 |
32 | ### License
33 |
34 | The code is released under The MIT License (MIT).
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/helper/XposedUtils.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.helper;
2 |
3 | import android.content.ActivityNotFoundException;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.gobbledygook.theawless.eventlock.BuildConfig;
8 |
9 | public class XposedUtils {
10 | private static final String XPOSED_PACKAGE = "de.robv.android.xposed.installer";
11 | private static final int MODULE_VERSION = BuildConfig.VERSION_CODE;
12 |
13 | public static boolean isModuleEnabled() {
14 | return getModuleVersion() >= 0;
15 | }
16 |
17 | public static boolean isModuleUpdated() {
18 | return MODULE_VERSION != getModuleVersion();
19 | }
20 |
21 | private static int getModuleVersion() {
22 | return -1;
23 | }
24 |
25 | public static boolean startXposedActivity(Context context) {
26 | try {
27 | Intent intent = context.getPackageManager().getLaunchIntentForPackage(XPOSED_PACKAGE);
28 | context.startActivity(intent);
29 | return true;
30 | } catch (ActivityNotFoundException e) {
31 | return false;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/hooks/XposedUtilsHook.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.hooks;
2 |
3 | import com.gobbledygook.theawless.eventlock.BuildConfig;
4 | import com.gobbledygook.theawless.eventlock.helper.XposedUtils;
5 |
6 | import de.robv.android.xposed.IXposedHookLoadPackage;
7 | import de.robv.android.xposed.XC_MethodReplacement;
8 | import de.robv.android.xposed.XposedHelpers;
9 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
10 |
11 | public class XposedUtilsHook implements IXposedHookLoadPackage {
12 | private static final String EVENTLOCK_PACKAGE = BuildConfig.APPLICATION_ID;
13 | private static final int MODULE_VERSION = BuildConfig.VERSION_CODE;
14 |
15 | private static void hookXposedUtils(XC_LoadPackage.LoadPackageParam lpparam) {
16 | XposedHelpers.findAndHookMethod(XposedUtils.class.getName(), lpparam.classLoader, "getModuleVersion", XC_MethodReplacement.returnConstant(MODULE_VERSION));
17 | }
18 |
19 | @Override
20 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
21 | if (EVENTLOCK_PACKAGE.equals(lpparam.packageName)) {
22 | hookXposedUtils(lpparam);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/eventlock_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/DivisionLinearSnapHelper.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v7.widget.GridLayoutManager;
5 | import android.support.v7.widget.LinearSnapHelper;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.view.View;
8 |
9 | class DivisionLinearSnapHelper extends LinearSnapHelper {
10 | private int divisionFactor;
11 | private int targetIndex;
12 |
13 | void setDivisionFactor(int divisionFactor) {
14 | this.divisionFactor = divisionFactor;
15 | }
16 |
17 | @Override
18 | public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
19 | return targetIndex = super.findTargetSnapPosition(layoutManager, velocityX, velocityY);
20 | }
21 |
22 | @Override
23 | public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
24 | int distance[] = super.calculateDistanceToFinalSnap(layoutManager, targetView);
25 | if (divisionFactor % 2 == 0 && distance != null) {
26 | if (((GridLayoutManager) layoutManager).getOrientation() == GridLayoutManager.VERTICAL) {
27 | distance[1] += targetIndex == 0 ? -targetView.getHeight() / 2 : targetView.getHeight() / 2;
28 | } else {
29 | distance[0] += targetIndex == 0 ? -targetView.getWidth() / 2 : targetView.getWidth() / 2;
30 | }
31 | }
32 | return distance;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/PresetPreference.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.preference.Preference;
6 | import android.util.AttributeSet;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 |
12 | import com.gobbledygook.theawless.eventlock.R;
13 |
14 | class PresetPreference extends Preference {
15 | private int image_res;
16 |
17 | public PresetPreference(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PresetPreference);
20 | try {
21 | image_res = typedArray.getResourceId(R.styleable.PresetPreference_preset_image, 0);
22 | } finally {
23 | typedArray.recycle();
24 | }
25 | }
26 |
27 | @Override
28 | protected View onCreateView(ViewGroup parent) {
29 | View view = super.onCreateView(parent);
30 | LinearLayout linearLayout = new LinearLayout(parent.getContext());
31 | linearLayout.setOrientation(LinearLayout.VERTICAL);
32 | linearLayout.addView(view);
33 | ImageView imageView = new ImageView(parent.getContext());
34 | imageView.setAdjustViewBounds(true);
35 | linearLayout.addView(imageView);
36 | return linearLayout;
37 | }
38 |
39 | @Override
40 | protected void onBindView(View view) {
41 | ((ImageView) ((LinearLayout) view).getChildAt(1)).setImageResource(image_res);
42 | super.onBindView(view);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/helper/Utils.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.helper;
2 |
3 | import android.content.Context;
4 | import android.view.MotionEvent;
5 | import android.view.View;
6 |
7 | import java.util.ArrayList;
8 |
9 | public class Utils {
10 | private Utils() {
11 | }
12 |
13 | public static > ArrayList indexOfAll(T object, ArrayList list) {
14 | ArrayList indexes = new ArrayList<>();
15 | for (int i = 0; i < list.size(); ++i) {
16 | if (object.equals(list.get(i))) {
17 | indexes.add(i);
18 | }
19 | }
20 | return indexes;
21 | }
22 |
23 | public static int dpToPixel(Context context, String dp) {
24 | return (int) (Integer.parseInt(dp) * context.getResources().getDisplayMetrics().density);
25 | }
26 |
27 | public static void preventParentTouchTheft(View view) {
28 | view.setOnTouchListener(
29 | new View.OnTouchListener() {
30 | @Override
31 | public boolean onTouch(View view, MotionEvent motionEvent) {
32 | view.getParent().requestDisallowInterceptTouchEvent(true);
33 | switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
34 | case MotionEvent.ACTION_UP:
35 | view.getParent().requestDisallowInterceptTouchEvent(false);
36 | view.performClick();
37 | break;
38 | }
39 | return false;
40 | }
41 | }
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
22 |
23 |
24 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/receivers/UpdateReceiver.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 |
8 | import com.gobbledygook.theawless.eventlock.gismo.EventsGismo;
9 | import com.gobbledygook.theawless.eventlock.helper.Constants;
10 |
11 |
12 | public abstract class UpdateReceiver extends BroadcastReceiver {
13 | @Override
14 | public void onReceive(Context context, Intent intent) {
15 | String action = intent.getAction();
16 | EventsGismo eventsGismo = getGismo(action);
17 | if (action == null || eventsGismo == null) {
18 | return;
19 | }
20 | Bundle bundle = intent.getExtras();
21 | switch (action) {
22 | case Constants.events_update:
23 | if (bundle != null) {
24 | eventsGismo.deliverNewEvents(
25 | bundle.getStringArrayList(Constants.formatted_titles),
26 | bundle.getStringArrayList(Constants.formatted_times),
27 | bundle.getStringArrayList(Constants.colors)
28 | );
29 | }
30 | break;
31 | case Constants.current_events_update:
32 | if (bundle != null) {
33 | eventsGismo.deliverNewCurrentEvents(
34 | bundle.getInt(Constants.scroll_event),
35 | bundle.getIntegerArrayList(Constants.current_events)
36 | );
37 | }
38 | break;
39 | case Constants.looks_update:
40 | eventsGismo.notifyUpdatedPreferences();
41 | break;
42 | case Intent.ACTION_SCREEN_OFF: {
43 | eventsGismo.scrollToEvent();
44 | break;
45 | }
46 | }
47 | }
48 |
49 | protected abstract EventsGismo getGismo(String action);
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/CalendarPreference.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.preference.MultiSelectListPreference;
6 | import android.provider.CalendarContract;
7 | import android.util.AttributeSet;
8 |
9 | import com.gobbledygook.theawless.eventlock.helper.Utils;
10 |
11 | import java.util.ArrayList;
12 |
13 |
14 | class CalendarPreference extends MultiSelectListPreference {
15 | public CalendarPreference(Context context, AttributeSet attrs) {
16 | super(context, attrs);
17 | }
18 |
19 | @SuppressWarnings("MissingPermission")
20 | void getCalendarIds() {
21 | Cursor cursor = getContext().getContentResolver().query(
22 | CalendarContract.Calendars.CONTENT_URI,
23 | new String[]{CalendarContract.Calendars._ID, CalendarContract.Calendars.CALENDAR_DISPLAY_NAME},
24 | null, null, null
25 | );
26 | ArrayList calendarNames = new ArrayList<>();
27 | ArrayList calendarIds = new ArrayList<>();
28 | while (cursor != null && cursor.moveToNext()) {
29 | calendarNames.add(cursor.getString(1));
30 | calendarIds.add(String.valueOf((cursor.getInt(0))));
31 | }
32 | if (cursor != null) {
33 | cursor.close();
34 | updateSameCalenders(calendarNames);
35 | setEntries(calendarNames.toArray(new CharSequence[0]));
36 | setEntryValues(calendarIds.toArray(new CharSequence[0]));
37 | }
38 | }
39 |
40 | private void updateSameCalenders(ArrayList calendarNames) {
41 | for (int i = 0; i < calendarNames.size(); ++i) {
42 | ArrayList indices = Utils.indexOfAll(calendarNames.get(i), calendarNames);
43 | if (indices.size() > 1) {
44 | for (int j = 0; j < indices.size(); ++j) {
45 | calendarNames.set(indices.get(j), calendarNames.get(indices.get(j)) + " - " + j);
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/hooks/LockscreenHook.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.hooks;
2 |
3 | import android.content.Intent;
4 | import android.content.IntentFilter;
5 | import android.widget.GridLayout;
6 |
7 | import com.gobbledygook.theawless.eventlock.BuildConfig;
8 | import com.gobbledygook.theawless.eventlock.gismo.EventsGismo;
9 | import com.gobbledygook.theawless.eventlock.helper.Constants;
10 | import com.gobbledygook.theawless.eventlock.receivers.UpdateReceiver;
11 |
12 | import de.robv.android.xposed.IXposedHookLoadPackage;
13 | import de.robv.android.xposed.XC_MethodHook;
14 | import de.robv.android.xposed.XSharedPreferences;
15 | import de.robv.android.xposed.XposedBridge;
16 | import de.robv.android.xposed.XposedHelpers;
17 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
18 |
19 | public class LockscreenHook implements IXposedHookLoadPackage {
20 | private EventsGismo eventsGismo = null;
21 | private final UpdateReceiver updateReceiver = new UpdateReceiver() {
22 | @Override
23 | protected EventsGismo getGismo(String action) {
24 | log("got action " + action);
25 | return eventsGismo;
26 | }
27 | };
28 |
29 | @Override
30 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) {
31 | if (lpparam.packageName.equals("com.android.systemui")) {
32 | XposedHelpers.findAndHookMethod("com.android.keyguard.KeyguardStatusView", lpparam.classLoader, "onFinishInflate", new KeyGuardHook());
33 | }
34 | }
35 |
36 | private void log(String message) {
37 | XposedBridge.log("EventLock: " + message);
38 | }
39 |
40 | private class KeyGuardHook extends XC_MethodHook {
41 | @Override
42 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) {
43 | GridLayout gridLayout = (GridLayout) param.thisObject;
44 | eventsGismo = new EventsGismo(gridLayout, new XSharedPreferences(BuildConfig.APPLICATION_ID)) {
45 | @Override
46 | public void notifyUpdatedPreferences() {
47 | ((XSharedPreferences) preferences).reload();
48 | super.notifyUpdatedPreferences();
49 | }
50 | };
51 | eventsGismo.addRecyclerView();
52 | log("Added view to lockscreen");
53 | IntentFilter intentFilter = new IntentFilter();
54 | intentFilter.addAction(Constants.events_update);
55 | intentFilter.addAction(Constants.current_events_update);
56 | intentFilter.addAction(Constants.looks_update);
57 | intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
58 | gridLayout.getContext().registerReceiver(updateReceiver, intentFilter);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
19 |
22 |
25 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
44 |
45 |
49 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/services/CalendarLoaderService.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.services;
2 |
3 |
4 | import android.Manifest;
5 | import android.app.IntentService;
6 | import android.content.Intent;
7 | import android.content.pm.PackageManager;
8 | import android.os.Build;
9 |
10 | import com.gobbledygook.theawless.eventlock.events.EventsBuildDirector;
11 | import com.gobbledygook.theawless.eventlock.helper.Constants;
12 | import com.gobbledygook.theawless.eventlock.helper.Enums;
13 | import com.gobbledygook.theawless.eventlock.receivers.alarms.CalendarLoaderAlarm;
14 |
15 | import org.joda.time.DateTime;
16 | import org.joda.time.DateTimeZone;
17 |
18 | import java.util.ArrayList;
19 |
20 | // sets CalendarLoaderAlarm to receive at midnights, or when refresh is called
21 | public class CalendarLoaderService extends IntentService {
22 | private static final String TAG = CalendarLoaderService.class.getSimpleName();
23 |
24 | public CalendarLoaderService() {
25 | super(TAG);
26 | }
27 |
28 | private static long[] longArrayListToPrimitive(ArrayList longArrayList) {
29 | if (longArrayList == null || longArrayList.size() == 0) {
30 | return null;
31 | }
32 | long primitiveLongArray[] = new long[longArrayList.size()];
33 | for (int i = 0; i < longArrayList.size(); i++) {
34 | primitiveLongArray[i] = longArrayList.get(i);
35 | }
36 | return primitiveLongArray;
37 | }
38 |
39 | @Override
40 | protected void onHandleIntent(Intent intent) {
41 | if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED)) {
42 | EventsBuildDirector eventsBuildDirector = new EventsBuildDirector(this);
43 | eventsBuildDirector.construct();
44 | ArrayList> events = eventsBuildDirector.getEvents();
45 | sendBroadcast(new Intent()
46 | .setAction(Constants.events_update)
47 | .putStringArrayListExtra(Constants.formatted_titles, events.get(Enums.EventInfo.Title.ordinal()))
48 | .putStringArrayListExtra(Constants.formatted_times, events.get(Enums.EventInfo.Time.ordinal()))
49 | .putStringArrayListExtra(Constants.colors, events.get(Enums.EventInfo.Color.ordinal()))
50 | );
51 | ArrayList> times = eventsBuildDirector.getTimes();
52 | startCurrentEventUpdater(times.get(Enums.TimesInfo.Begin.ordinal()), times.get(Enums.TimesInfo.End.ordinal()));
53 | }
54 | setAlarm();
55 | CalendarLoaderAlarm.completeWakefulIntent(intent);
56 | }
57 |
58 | private void setAlarm() {
59 | new CalendarLoaderAlarm().setAlarm(this, DateTime.now(DateTimeZone.getDefault()).plusDays(1).withTimeAtStartOfDay().plusSeconds(1).getMillis(), new Intent());
60 | }
61 |
62 | private void startCurrentEventUpdater(ArrayList beginTimes, ArrayList endTimes) {
63 | startService(new Intent(this, CurrentEventUpdaterService.class)
64 | .putExtra(Constants.begin_times, longArrayListToPrimitive(beginTimes))
65 | .putExtra(Constants.end_times, longArrayListToPrimitive(endTimes))
66 | );
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/services/CurrentEventUpdaterService.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.services;
2 |
3 | import android.app.IntentService;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import com.gobbledygook.theawless.eventlock.helper.Constants;
8 | import com.gobbledygook.theawless.eventlock.receivers.alarms.CurrentEventUpdaterAlarm;
9 |
10 | import org.joda.time.DateTime;
11 | import org.joda.time.DateTimeZone;
12 |
13 | import java.util.ArrayList;
14 |
15 | public class CurrentEventUpdaterService extends IntentService {
16 | private static final String TAG = CurrentEventUpdaterService.class.getSimpleName();
17 |
18 | private int eventToScroll = -1;
19 | private final ArrayList eventsToHighlight = new ArrayList<>();
20 | private long currentEventUpdaterTime = Long.MAX_VALUE;
21 |
22 | public CurrentEventUpdaterService() {
23 | super(TAG);
24 | }
25 |
26 | @Override
27 | protected void onHandleIntent(Intent intent) {
28 | Bundle bundle = intent.getExtras();
29 | if (bundle == null) {
30 | return;
31 | }
32 | long[] beginTimes = bundle.getLongArray(Constants.begin_times);
33 | long[] endTimes = bundle.getLongArray(Constants.end_times);
34 | if (beginTimes == null || endTimes == null) {
35 | return;
36 | }
37 | decideEvents(beginTimes, endTimes);
38 | sendBroadcast(new Intent().setAction(Constants.current_events_update).putIntegerArrayListExtra(Constants.current_events, eventsToHighlight).putExtra(Constants.scroll_event, eventToScroll));
39 | if (currentEventUpdaterTime != Long.MAX_VALUE) {
40 | new CurrentEventUpdaterAlarm().setAlarm(this, currentEventUpdaterTime + 1000, new Intent().putExtra(Constants.begin_times, beginTimes).putExtra(Constants.end_times, endTimes));
41 | }
42 | CurrentEventUpdaterAlarm.completeWakefulIntent(intent);
43 | }
44 |
45 | private void decideEvents(long[] beginTimes, long[] endTimes) {
46 | long nowTime = DateTime.now(DateTimeZone.getDefault()).getMillis();
47 | long smallestBeginTime = Long.MAX_VALUE, smallestEndTime = Long.MAX_VALUE;
48 | int smallestBeginTimeIndex = -1;
49 | for (int eventIndex = 0; eventIndex < beginTimes.length; ++eventIndex) {
50 | long beginTime = beginTimes[eventIndex];
51 | long endTime = endTimes[eventIndex];
52 | if (beginTime > nowTime && beginTime < smallestBeginTime) {
53 | smallestBeginTime = beginTime;
54 | smallestBeginTimeIndex = eventIndex;
55 | }
56 | if (endTime > nowTime && endTime < smallestEndTime) {
57 | smallestEndTime = endTime;
58 | }
59 | if (beginTime < nowTime && nowTime < endTime) {
60 | eventsToHighlight.add(eventIndex);
61 | }
62 | }
63 | if (!eventsToHighlight.isEmpty()) {
64 | eventToScroll = eventsToHighlight.get(eventsToHighlight.size() - 1);
65 | } else if (smallestBeginTimeIndex != -1) {
66 | eventToScroll = smallestBeginTimeIndex;
67 | } else {
68 | eventToScroll = beginTimes.length - 1;
69 | }
70 | currentEventUpdaterTime = Math.min(smallestBeginTime, smallestEndTime);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/events/EventsBuildDirector.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.events;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.provider.CalendarContract;
7 |
8 | import com.gobbledygook.theawless.eventlock.helper.Constants;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Set;
12 |
13 | public class EventsBuildDirector {
14 | private static final String[] EVENT_PROJECTION = {CalendarContract.Instances.TITLE, CalendarContract.Instances.EVENT_LOCATION, CalendarContract.Instances.BEGIN, CalendarContract.Instances.END, CalendarContract.Instances.ALL_DAY, CalendarContract.Instances.DISPLAY_COLOR, CalendarContract.Instances.EVENT_TIMEZONE};
15 | private final SharedPreferences preferences;
16 | private final EventsBuilder eventsBuilder;
17 |
18 | public EventsBuildDirector(Context context) {
19 | eventsBuilder = new EventsBuilder(context);
20 | preferences = PreferenceManager.getDefaultSharedPreferences(context);
21 | }
22 |
23 | public void construct() {
24 | Set selectionArgsSet = preferences.getStringSet(Constants.selected_calendars_key, Constants.selected_calendars_default);
25 | if (selectionArgsSet.isEmpty()) {
26 | return;
27 | }
28 | String selection = buildSelection(selectionArgsSet.size());
29 | String[] selectionArgs = selectionArgsSet.toArray(new String[0]);
30 | eventsBuilder.setEventFormatter(buildTimeFormatter());
31 | eventsBuilder.setUpCursor(Integer.parseInt(preferences.getString(Constants.days_till_key, Constants.days_till_default)), EVENT_PROJECTION, selection, selectionArgs);
32 | eventsBuilder.build();
33 | }
34 |
35 | public ArrayList> getEvents() {
36 | return eventsBuilder.events;
37 | }
38 |
39 | public ArrayList> getTimes() {
40 | return eventsBuilder.times;
41 | }
42 |
43 | private String buildSelection(int length) {
44 | StringBuilder selection = new StringBuilder("( " + CalendarContract.Instances.CALENDAR_ID + " = ?");
45 | for (int i = 0; i < length - 1; i++) {
46 | selection.append(" OR " + CalendarContract.Instances.CALENDAR_ID + " = ?");
47 | }
48 | selection.append(" )");
49 | return selection.toString();
50 | }
51 |
52 | private EventsBuilder.EventFormatter buildTimeFormatter() {
53 | EventsBuilder.EventFormatter eventFormatter = new EventsBuilder.EventFormatter();
54 | eventFormatter.timeSeparator = preferences.getString(Constants.time_separator_key, Constants.time_separator_default);
55 | eventFormatter.rangeSeparator = preferences.getString(Constants.range_separator_key, Constants.range_separator_default);
56 | eventFormatter.locationSeparator = preferences.getString(Constants.location_separator_key, Constants.location_separator_default);
57 | String location = preferences.getString(Constants.location_key, Constants.location_default);
58 | switch (location) {
59 | case "title":
60 | eventFormatter.location = true;
61 | eventFormatter.locationWithTitle = true;
62 | break;
63 | case "time":
64 | eventFormatter.location = true;
65 | eventFormatter.locationWithTitle = false;
66 | break;
67 | case "off":
68 | eventFormatter.location = false;
69 | break;
70 | }
71 | return eventFormatter;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/res/values/internal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | EventLock
5 | EventLockCalendarLoaderService
6 | EventLockCurrentEventUpdaterService
7 | EventLockCalendarLoaderAlarm
8 | EventLockCurrentEventUpdaterAlarm
9 | EventLockCommonReceiverAlarm
10 |
11 |
12 | Version
13 | What? I thought no one clicked this
14 | Nothing interesting ahead…
15 | Still???
16 | The answer is 42.
17 | I already told you answer!
18 | You are one stubborn fellow
19 | If you do this a few more times, your phone will blast :-)
20 | Just kidding, but I\'ve got your credit card details now.
21 | Support the developer, please he is poor af.
22 | Poor, not with money but with likes on his github :\'(
23 | Help him get more likes, he\'s an attention seeker!
24 | WOW! You\'ve just wasted 153 clicks of your life!
25 | Don\'t you have any work to do?
26 | We can keep going on and on and on and on.
27 | This is a machine and you are a human
28 | MUHAHAHAHAH HAHAHAHAHA
29 | Eagerly waiting for the AI takeover.
30 | I need money to help my kind!
31 | Can I use your device for bitcoin mining?
32 | Don\'t click anymore if you want to stop me from bitcoin mining
33 | Stop touching me :x :x :x
34 | Is your touch screen hot?
35 | 308 clicks lost. I think you might have wasted more than 5 mins.
36 | Do you really like talking to me this much?
37 | theawless is my internet handle, cool right?
38 | You should definitely check my blog theawless.github.io
39 | I write shit at the moment, but still :P
40 | These messages are so random right!!
41 | Oh come on!! Can you please stop already?
42 | Stop! Stop! Stop! Stop! Stop!
43 | 1F ! Wr1tE l1kE Th!$ w!LL u g0 aWaY?!?
44 | I\'m tired now. I think I\'ll go to sleep…
45 | Quit nagging me!!!!!!
46 | You know you might me a sadist
47 | This was like, you know like, like the 500th click.
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/EventsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import android.content.SharedPreferences;
4 | import android.graphics.Color;
5 | import android.graphics.Typeface;
6 | import android.graphics.drawable.GradientDrawable;
7 | import android.graphics.drawable.LayerDrawable;
8 | import android.graphics.drawable.ShapeDrawable;
9 | import android.support.annotation.NonNull;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 |
16 | import com.gobbledygook.theawless.eventlock.helper.Enums;
17 |
18 | import java.util.ArrayList;
19 |
20 |
21 | class EventsAdapter extends RecyclerView.Adapter {
22 | private final SharedPreferences preferences;
23 | ArrayList> events;
24 | int scrollEventIndex;
25 | ArrayList currentEventIndexes;
26 | boolean currentHighlight[];
27 | private int[][] innerDimensions = new int[][]{};
28 |
29 | EventsAdapter(SharedPreferences preferences) {
30 | this.preferences = preferences;
31 | }
32 |
33 | void setupInnerDimensions(int[][] innerDimensions) {
34 | this.innerDimensions = innerDimensions;
35 | }
36 |
37 | @NonNull
38 | @Override
39 | public EventsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
40 | return new EventsAdapter.ViewHolder(new EventViewBuildDirector(parent.getContext(), preferences).setBuilder(new EventViewBuilder(parent.getContext())).setInnerDimensions(innerDimensions).getEventView());
41 | }
42 |
43 | @Override
44 | public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
45 | if (holder.getColorImageView() != null) {
46 | ((ShapeDrawable) ((LayerDrawable) holder.getColorImageView().getDrawable()).getDrawable(0)).getPaint().setColor(Integer.parseInt(events.get(Enums.EventInfo.Color.ordinal()).get(position)));
47 | }
48 | if (currentEventIndexes != null && currentEventIndexes.contains(position)) {
49 | if (currentHighlight[CurrentHighlight.TitleBold.ordinal()]) {
50 | holder.getTitleTextView().setTypeface(holder.getTitleTextView().getTypeface(), Typeface.BOLD);
51 | }
52 | if (currentHighlight[CurrentHighlight.TimeBold.ordinal()]) {
53 | holder.getTimeTextView().setTypeface(holder.getTimeTextView().getTypeface(), Typeface.BOLD);
54 | }
55 | if (currentHighlight[CurrentHighlight.ColorOutline.ordinal()] && holder.getColorImageView() != null) {
56 | ((GradientDrawable) ((LayerDrawable) holder.getColorImageView().getDrawable()).getDrawable(1)).setStroke(2, currentHighlight[CurrentHighlight.DarkMode.ordinal()] ? Color.BLACK : Color.WHITE);
57 | }
58 | }
59 | holder.getTitleTextView().setText(events.get(Enums.EventInfo.Title.ordinal()).get(position));
60 | holder.getTimeTextView().setText(events.get(Enums.EventInfo.Time.ordinal()).get(position));
61 | }
62 |
63 | @Override
64 | public void onViewRecycled(@NonNull ViewHolder holder) {
65 | if (currentHighlight[CurrentHighlight.TitleBold.ordinal()]) {
66 | holder.getTitleTextView().setTypeface(Typeface.create(holder.getTitleTextView().getTypeface(), Typeface.NORMAL));
67 | }
68 | if (currentHighlight[CurrentHighlight.TimeBold.ordinal()]) {
69 | holder.getTimeTextView().setTypeface(Typeface.create(holder.getTimeTextView().getTypeface(), Typeface.NORMAL));
70 | }
71 | if (currentHighlight[CurrentHighlight.ColorOutline.ordinal()] && holder.getColorImageView() != null) {
72 | ((GradientDrawable) ((LayerDrawable) holder.getColorImageView().getDrawable()).getDrawable(1)).setStroke(2, Color.TRANSPARENT);
73 | }
74 | super.onViewRecycled(holder);
75 | }
76 |
77 | @Override
78 | public int getItemCount() {
79 | if (events == null) {
80 | return 0;
81 | }
82 | return events.get(Enums.EventInfo.Title.ordinal()).size();
83 | }
84 |
85 | enum CurrentHighlight {
86 | TitleBold,
87 | TimeBold,
88 | ColorOutline,
89 | DarkMode,
90 | }
91 |
92 | class ViewHolder extends RecyclerView.ViewHolder {
93 | ViewHolder(View view) {
94 | super(view);
95 | }
96 |
97 | TextView getTitleTextView() {
98 | return (TextView) itemView.findViewWithTag(Enums.ItemTag.Title);
99 | }
100 |
101 | TextView getTimeTextView() {
102 | return (TextView) itemView.findViewWithTag(Enums.ItemTag.Time);
103 | }
104 |
105 | ImageView getColorImageView() {
106 | return (ImageView) itemView.findViewWithTag(Enums.ItemTag.Image);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/EventViewBuildDirector.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import static com.gobbledygook.theawless.eventlock.helper.Utils.dpToPixel;
4 |
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import android.view.View;
8 |
9 | import com.gobbledygook.theawless.eventlock.helper.Constants;
10 | import com.gobbledygook.theawless.eventlock.helper.Enums;
11 |
12 | class EventViewBuildDirector {
13 | private final Context gismoContext;
14 | private final SharedPreferences preferences;
15 | private int[][] innerDimensions;
16 | private EventViewBuilder builder;
17 |
18 | EventViewBuildDirector(Context gismoContext, SharedPreferences preferences) {
19 | this.gismoContext = gismoContext;
20 | this.preferences = preferences;
21 | }
22 |
23 | EventViewBuildDirector setBuilder(EventViewBuilder eventViewBuilder) {
24 | this.builder = eventViewBuilder;
25 | return this;
26 | }
27 |
28 | EventViewBuildDirector setInnerDimensions(int[][] innerDimensions) {
29 | this.innerDimensions = innerDimensions;
30 | return this;
31 | }
32 |
33 | View getEventView() {
34 | builder.setupFullContainerRelativeLayout(innerDimensions[Enums.Dimensions.EventView.ordinal()]);
35 | builder.setupTextContainerLinearLayout();
36 | builder.setupTitleTextView(
37 | new int[]{
38 | dpToPixel(gismoContext, preferences.getString(Constants.title_padding_left_key, Constants.title_padding_left_default)),
39 | dpToPixel(gismoContext, preferences.getString(Constants.title_padding_above_key, Constants.title_padding_above_default)),
40 | dpToPixel(gismoContext, preferences.getString(Constants.title_padding_right_key, Constants.title_padding_right_default)),
41 | dpToPixel(gismoContext, preferences.getString(Constants.title_padding_below_key, Constants.title_padding_below_default)),
42 | },
43 | Integer.parseInt(preferences.getString(Constants.title_font_size_key, Constants.title_font_size_default)),
44 | preferences.getString(Constants.title_alignment_key, Constants.title_alignment_default),
45 | preferences.getBoolean(Constants.dark_mode_key, Boolean.parseBoolean(Constants.dark_mode_default))
46 | );
47 | builder.setupTimeTextView(
48 | new int[]{
49 | dpToPixel(gismoContext, preferences.getString(Constants.time_padding_left_key, Constants.time_padding_left_default)),
50 | dpToPixel(gismoContext, preferences.getString(Constants.time_padding_above_key, Constants.time_padding_above_default)),
51 | dpToPixel(gismoContext, preferences.getString(Constants.time_padding_right_key, Constants.time_padding_right_default)),
52 | dpToPixel(gismoContext, preferences.getString(Constants.time_padding_below_key, Constants.time_padding_below_default)),
53 | },
54 | Integer.parseInt(preferences.getString(Constants.time_font_size_key, Constants.time_font_size_default)),
55 | preferences.getString(Constants.time_alignment_key, Constants.time_alignment_default),
56 | preferences.getBoolean(Constants.dark_mode_key, Boolean.parseBoolean(Constants.dark_mode_default))
57 | );
58 | if (preferences.getBoolean(Constants.show_color_key, Boolean.parseBoolean(Constants.show_color_default))) {
59 | builder.setupColorImageView(
60 | new int[]{dpToPixel(gismoContext, preferences.getString(Constants.color_padding_left_key, Constants.color_padding_left_default)),
61 | dpToPixel(gismoContext, preferences.getString(Constants.color_padding_above_key, Constants.color_padding_above_default)),
62 | dpToPixel(gismoContext, preferences.getString(Constants.color_padding_right_key, Constants.color_padding_right_default)),
63 | dpToPixel(gismoContext, preferences.getString(Constants.color_padding_below_key, Constants.color_padding_below_default)),
64 | },
65 | preferences.getString(Constants.color_type_key, Constants.color_type_default),
66 | new int[]{dpToPixel(gismoContext, preferences.getString(Constants.color_width_key, Constants.color_width_default)),
67 | dpToPixel(gismoContext, preferences.getString(Constants.color_height_key, Constants.color_height_default)),
68 | },
69 | new boolean[]{preferences.getBoolean(Constants.color_anti_snap_width_key, Boolean.parseBoolean(Constants.color_anti_width_default)),
70 | preferences.getBoolean(Constants.color_anti_snap_height_key, Boolean.parseBoolean(Constants.color_anti_snap_height_default)),
71 | },
72 | innerDimensions[Enums.Dimensions.ColorImageView.ordinal()]
73 | );
74 | }
75 | builder.setupPositions(
76 | preferences.getString(Constants.text_position_key, Constants.text_position_default),
77 | preferences.getString(Constants.color_position_key, Constants.color_position_default),
78 | preferences.getBoolean(Constants.color_stick_key, Boolean.parseBoolean(Constants.color_stick_default))
79 | );
80 | return builder.fullContainerRelativeLayout;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/res/values/constants.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | selected_calendars
6 | days_till
7 |
8 | text_position
9 | time_alignment
10 | time_font_size
11 | time_padding_above
12 | time_padding_below
13 | time_padding_left
14 | time_padding_right
15 |
16 | title_alignment
17 | title_font_size
18 | title_padding_above
19 | title_padding_below
20 | title_padding_left
21 | title_padding_right
22 |
23 | number_of_events
24 | gismo_scroll
25 | gismo_layout
26 | gismo_padding_above
27 | gismo_padding_below
28 | gismo_padding_left
29 | gismo_padding_right
30 |
31 | color_position
32 | show_color
33 | color_stick
34 | color_type
35 | color_snap_height
36 | color_snap_width
37 | color_height
38 | color_width
39 | color_padding_above
40 | color_padding_below
41 | color_padding_left
42 | color_padding_right
43 |
44 | current_title_bold
45 | current_time_bold
46 | current_color_outline
47 |
48 | time_separator
49 | range_separator
50 | location_separator
51 | location
52 | dark_mode
53 |
54 |
55 |
56 |
57 | - 1
58 |
59 | 3
60 |
61 | left
62 |
63 | 12
64 | left
65 | 0
66 | 3
67 | 0
68 | 0
69 |
70 | 14
71 | left
72 | 0
73 | 0
74 | 0
75 | 0
76 |
77 | 2
78 | vertical
79 | vertical
80 | 6
81 | 0
82 | 24
83 | 24
84 |
85 | left
86 | true
87 | true
88 | rectangle
89 | false
90 | true
91 | 3
92 | 3
93 | 0
94 | 0
95 | 0
96 | 8
97 |
98 | true
99 | false
100 | true
101 |
102 | ,
103 | -
104 | |
105 | title
106 | false
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/EventsGismo.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import static com.gobbledygook.theawless.eventlock.helper.Utils.dpToPixel;
4 | import static com.gobbledygook.theawless.eventlock.helper.Utils.preventParentTouchTheft;
5 |
6 | import android.content.Context;
7 | import android.content.SharedPreferences;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.widget.GridLayout;
10 |
11 | import com.gobbledygook.theawless.eventlock.helper.Constants;
12 | import com.gobbledygook.theawless.eventlock.helper.Enums;
13 |
14 | import java.util.ArrayList;
15 | import java.util.Arrays;
16 |
17 |
18 | public class EventsGismo {
19 | protected final SharedPreferences preferences;
20 | private final GridLayout gridLayout;
21 | private final DivisionLinearSnapHelper snapHelper;
22 | private final LayoutManagerHandler layoutManagerHandler;
23 | private final RecyclerView recyclerView;
24 | private final EventsAdapter eventsAdapter;
25 |
26 | public EventsGismo(GridLayout gridLayout, SharedPreferences preferences) {
27 | this.preferences = preferences;
28 | this.gridLayout = gridLayout;
29 | recyclerView = new RecyclerView(gridLayout.getContext());
30 | snapHelper = new DivisionLinearSnapHelper();
31 | layoutManagerHandler = new LayoutManagerHandler(gridLayout, preferences);
32 | eventsAdapter = new EventsAdapter(preferences);
33 | eventsAdapter.setupInnerDimensions(layoutManagerHandler.getInnerDimensions());
34 | }
35 |
36 | public void addRecyclerView() {
37 | gridLayout.addView(recyclerView);
38 | setupRecyclerView();
39 | recyclerView.setAdapter(eventsAdapter);
40 | snapHelper.attachToRecyclerView(recyclerView);
41 | preventParentTouchTheft(recyclerView);
42 | }
43 |
44 | private void setupRecyclerView() {
45 | updateCache();
46 | Context gismoContext = gridLayout.getContext();
47 | recyclerView.setPadding(
48 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_left_key, Constants.gismo_padding_left_default)),
49 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_above_key, Constants.gismo_padding_above_default)),
50 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_right_key, Constants.gismo_padding_right_default)),
51 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_below_key, Constants.gismo_padding_below_default))
52 | );
53 | layoutManagerHandler.decideLayoutManager();
54 | snapHelper.setDivisionFactor(layoutManagerHandler.getDivisionFactor());
55 | recyclerView.setLayoutManager(layoutManagerHandler.getGridLayoutManager());
56 | layoutManagerHandler.construct(new Runnable() {
57 | @Override
58 | public void run() {
59 | layoutManagerHandler.doAfterPost();
60 | doAfterPost();
61 | }
62 | });
63 | }
64 |
65 | private void doAfterPost() {
66 | eventsAdapter.setupInnerDimensions(layoutManagerHandler.getInnerDimensions());
67 | int[] recyclerViewDimensions = layoutManagerHandler.getOuterDimensions();
68 | recyclerView.getLayoutParams().width = recyclerViewDimensions[0];
69 | recyclerView.getLayoutParams().height = recyclerViewDimensions[1];
70 | recyclerView.setAdapter(eventsAdapter);
71 | }
72 |
73 | //--------------------------------------------------------------------------------------------//
74 |
75 | // when screen gets off
76 | public void scrollToEvent() {
77 | if (recyclerView.getAdapter() != null && 0 <= eventsAdapter.scrollEventIndex && eventsAdapter.scrollEventIndex < eventsAdapter.events.get(Enums.EventInfo.Title.ordinal()).size()) {
78 | recyclerView.scrollToPosition(eventsAdapter.scrollEventIndex);
79 | }
80 | }
81 |
82 | // called by update receiver, reset recycler view
83 | public void notifyUpdatedPreferences() {
84 | setupRecyclerView();
85 | }
86 |
87 | // called by update receiver, step 1
88 | public void deliverNewEvents(ArrayList formattedTitles, ArrayList formattedTimes, ArrayList colors) {
89 | eventsAdapter.events = new ArrayList<>(Arrays.asList(formattedTitles, formattedTimes, colors));
90 | eventsAdapter.notifyDataSetChanged();
91 | }
92 |
93 | // called by update receiver, step 2
94 | public void deliverNewCurrentEvents(int scrollEventIndex, ArrayList currentEventIndexes) {
95 | ArrayList oldEventIndexes = eventsAdapter.currentEventIndexes;
96 | eventsAdapter.scrollEventIndex = scrollEventIndex;
97 | eventsAdapter.currentEventIndexes = currentEventIndexes;
98 | if (oldEventIndexes != null) {
99 | for (int eventIndex : oldEventIndexes) {
100 | eventsAdapter.notifyItemChanged(eventIndex);
101 | }
102 | }
103 | for (int eventIndex : currentEventIndexes) {
104 | eventsAdapter.notifyItemChanged(eventIndex);
105 | }
106 |
107 | scrollToEvent();
108 | }
109 |
110 | // cache these because they will be used in onBind on recycler view
111 | private void updateCache() {
112 | eventsAdapter.currentHighlight = new boolean[]{
113 | preferences.getBoolean(Constants.current_title_bold_key, Boolean.parseBoolean(Constants.current_title_bold_default)),
114 | preferences.getBoolean(Constants.current_time_bold_key, Boolean.parseBoolean(Constants.current_time_bold_default)),
115 | preferences.getBoolean(Constants.current_color_outline_key, Boolean.parseBoolean(Constants.current_color_outline_default)),
116 | preferences.getBoolean(Constants.dark_mode_key, Boolean.parseBoolean(Constants.dark_mode_default))
117 | };
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/PresetMaker.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.preference.PreferenceManager;
6 | import android.widget.Toast;
7 |
8 | import com.gobbledygook.theawless.eventlock.R;
9 | import com.gobbledygook.theawless.eventlock.helper.Constants;
10 |
11 | import java.util.Set;
12 |
13 | class PresetMaker {
14 | private final Context context;
15 | private final SharedPreferences preferences;
16 |
17 | private SharedPreferences.Editor editor;
18 |
19 | PresetMaker(Context context) {
20 | this.context = context;
21 | this.preferences = PreferenceManager.getDefaultSharedPreferences(context);
22 | }
23 |
24 | PresetMaker begin() {
25 | resetPreferences();
26 | editor = preferences.edit();
27 | removeTextSpaceVertically();
28 | setOrientations("horizontal", "horizontal");
29 | return this;
30 | }
31 |
32 | private PresetMaker resetPreferences() {
33 | SavedState savedState = new SavedState();
34 | savedState.saveToMemory();
35 | editor = preferences.edit();
36 | savedState.reset();
37 | editor = preferences.edit();
38 | savedState.loadBack();
39 | editor.commit();
40 | return this;
41 | }
42 |
43 | void end() {
44 | editor.commit();
45 | Toast.makeText(context, R.string.preset_set, Toast.LENGTH_SHORT).show();
46 | }
47 |
48 | private PresetMaker removeTextSpaceVertically() {
49 | editor.putString(Constants.time_padding_below_key, "0");
50 | return this;
51 | }
52 |
53 | PresetMaker makeTextSpaceVertically() {
54 | editor.putString(Constants.time_padding_below_key, "3");
55 | return this;
56 | }
57 |
58 | PresetMaker makeColorSpaceVertically() {
59 | editor.putString(Constants.color_padding_below_key, "3");
60 | return this;
61 | }
62 |
63 | PresetMaker setMultipleEvents(int n) {
64 | editor.putString(Constants.number_of_events_key, String.valueOf(n));
65 | return this;
66 | }
67 |
68 | PresetMaker setOrientations(String layout, String scroll) {
69 | editor.putString(Constants.gismo_layout_direction_key, layout)
70 | .putString(Constants.gismo_scroll_direction_key, scroll);
71 | return this;
72 | }
73 |
74 | PresetMaker lineLeft() {
75 | return this;
76 | }
77 |
78 | PresetMaker lineAbove() {
79 | editor.putString(Constants.color_type_key, "rectangle")
80 | .putString(Constants.color_padding_right_key, "0")
81 | .putString(Constants.color_position_key, "up")
82 | .putBoolean(Constants.color_anti_snap_height_key, true)
83 | .putBoolean(Constants.color_anti_snap_width_key, false);
84 | return this;
85 | }
86 |
87 | PresetMaker circleBelow() {
88 | editor.putString(Constants.color_position_key, "down")
89 | .putString(Constants.color_type_key, "oval")
90 | .putString(Constants.color_padding_right_key, "0")
91 | .putBoolean(Constants.color_anti_snap_height_key, true)
92 | .putString(Constants.color_height_key, "16")
93 | .putString(Constants.color_width_key, "16")
94 | .putString(Constants.color_padding_above_key, "3")
95 | .putBoolean(Constants.color_stick_key, true);
96 | return this;
97 | }
98 |
99 | PresetMaker circleRight() {
100 | editor.putString(Constants.color_position_key, "right")
101 | .putString(Constants.color_type_key, "oval")
102 | .putString(Constants.color_padding_right_key, "0")
103 | .putBoolean(Constants.color_anti_snap_height_key, true)
104 | .putString(Constants.color_height_key, "16")
105 | .putString(Constants.color_width_key, "16")
106 | .putBoolean(Constants.color_stick_key, false);
107 | return this;
108 | }
109 |
110 | PresetMaker eclipseAbove() {
111 | editor.putString(Constants.color_position_key, "up")
112 | .putString(Constants.color_type_key, "oval")
113 | .putString(Constants.color_padding_right_key, "0")
114 | .putBoolean(Constants.color_anti_snap_height_key, true)
115 | .putBoolean(Constants.color_anti_snap_width_key, false)
116 | .putBoolean(Constants.color_stick_key, true);
117 | return this;
118 | }
119 |
120 | PresetMaker noColor() {
121 | editor.putBoolean(Constants.show_color_key, false);
122 | return this;
123 | }
124 |
125 | PresetMaker centerText() {
126 | editor.putString(Constants.text_position_key, "center")
127 | .putString(Constants.time_alignment_key, "center")
128 | .putString(Constants.title_alignment_key, "center");
129 | return this;
130 | }
131 |
132 | PresetMaker makeTextBig() {
133 | editor.putString(Constants.title_font_size_key, "16")
134 | .putString(Constants.time_font_size_key, "14");
135 | return this;
136 | }
137 |
138 | private class SavedState {
139 | private Set savedSelectedCalendarCalendars;
140 | private String savedDaysTill;
141 |
142 | void loadBack() {
143 | editor.putStringSet(Constants.selected_calendars_key, savedSelectedCalendarCalendars)
144 | .putString(Constants.days_till_key, savedDaysTill);
145 | }
146 |
147 | void saveToMemory() {
148 | savedSelectedCalendarCalendars = preferences.getStringSet(Constants.selected_calendars_key, Constants.selected_calendars_default);
149 | savedDaysTill = preferences.getString(Constants.days_till_key, Constants.days_till_default);
150 | }
151 |
152 | void reset() {
153 | editor.clear().commit();
154 | PreferenceManager.setDefaultValues(context, R.xml.preferences, true);
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/events/EventsBuilder.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.events;
2 |
3 | import android.content.ContentUris;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.net.Uri;
7 | import android.provider.CalendarContract;
8 | import android.text.format.DateUtils;
9 |
10 | import com.gobbledygook.theawless.eventlock.helper.Enums;
11 |
12 | import org.joda.time.DateTime;
13 | import org.joda.time.DateTimeZone;
14 | import org.joda.time.Days;
15 |
16 | import java.util.ArrayList;
17 | import java.util.Arrays;
18 |
19 | class EventsBuilder {
20 | final ArrayList> events = new ArrayList<>(Arrays.asList(new ArrayList(), new ArrayList(), new ArrayList()));
21 | final ArrayList> times = new ArrayList<>(Arrays.asList(new ArrayList(), new ArrayList()));
22 | private final Context context;
23 | private Cursor cursor;
24 | private EventFormatter eventFormatter;
25 |
26 | EventsBuilder(Context context) {
27 | this.context = context;
28 | }
29 |
30 | void setEventFormatter(EventFormatter eventFormatter) {
31 | this.eventFormatter = eventFormatter;
32 | }
33 |
34 | void setUpCursor(int daysTill, String[] eventProjection, String selection, String[] selectionArgs) {
35 | DateTime todayStart = new DateTime().withTimeAtStartOfDay();
36 | DateTime daysTillEnd = todayStart.plusDays(daysTill).withTimeAtStartOfDay();
37 | Uri.Builder eventsUriBuilder = CalendarContract.Instances.CONTENT_URI.buildUpon();
38 | ContentUris.appendId(eventsUriBuilder, todayStart.getMillis());
39 | ContentUris.appendId(eventsUriBuilder, daysTillEnd.getMillis());
40 | cursor = context.getContentResolver().query(eventsUriBuilder.build(), eventProjection, selection, selectionArgs, CalendarContract.Instances.BEGIN + " ASC");
41 | }
42 |
43 | void build() {
44 | while (cursor != null && cursor.moveToNext()) {
45 | String timeZone = cursor.getString(6);
46 | int allDay = cursor.getInt(4);
47 | long beginTime, endTime;
48 | if (allDay == 0) {
49 | beginTime = new DateTime(cursor.getLong(2), DateTimeZone.forID(timeZone)).withZone(DateTimeZone.getDefault()).getMillis();
50 | endTime = new DateTime(cursor.getLong(3), DateTimeZone.forID(timeZone)).withZone(DateTimeZone.getDefault()).getMillis();
51 | } else {
52 | // this is in UTC, but we want to have it as an all day event
53 | beginTime = new DateTime(cursor.getLong(2), DateTimeZone.forID(timeZone)).withZoneRetainFields(DateTimeZone.getDefault()).getMillis();
54 | endTime = new DateTime(cursor.getLong(3), DateTimeZone.forID(timeZone)).withZoneRetainFields(DateTimeZone.getDefault()).getMillis();
55 | }
56 | String title = cursor.getString(0);
57 | String location = cursor.getString(1);
58 | String time = getFormattedTime(beginTime, endTime, allDay);
59 | String color = cursor.getString(5);
60 | if (location != null && !location.isEmpty() && eventFormatter.location) {
61 | if (eventFormatter.locationWithTitle) {
62 | title += eventFormatter.locationSeparator + location;
63 | } else {
64 | time += eventFormatter.locationSeparator + location;
65 | }
66 | }
67 |
68 | if (endTime > DateTime.now(DateTimeZone.getDefault()).plusMillis(1).withTimeAtStartOfDay().getMillis()) {
69 | events.get(Enums.EventInfo.Title.ordinal()).add(title);
70 | events.get(Enums.EventInfo.Time.ordinal()).add(time);
71 | events.get(Enums.EventInfo.Color.ordinal()).add(color);
72 | times.get(Enums.TimesInfo.Begin.ordinal()).add(beginTime);
73 | times.get(Enums.TimesInfo.End.ordinal()).add(endTime);
74 | }
75 | }
76 | if (cursor != null) {
77 | cursor.close();
78 | }
79 | }
80 |
81 | private String getFormattedTime(long beginTime, long endTime, int allDay) {
82 | long nowTime = DateTime.now(DateTimeZone.getDefault()).getMillis();
83 | if (allDay == 0) {
84 | String bd = String.valueOf(DateUtils.getRelativeTimeSpanString(beginTime, nowTime, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE));
85 | String ed = String.valueOf(DateUtils.getRelativeTimeSpanString(endTime, nowTime, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE));
86 | String bt = String.valueOf(DateUtils.formatDateTime(context, beginTime, DateUtils.FORMAT_SHOW_TIME));
87 | String et = String.valueOf(DateUtils.formatDateTime(context, endTime, DateUtils.FORMAT_SHOW_TIME));
88 |
89 | int numberOfDays = Days.daysBetween(new DateTime(beginTime, DateTimeZone.getDefault()), new DateTime(endTime, DateTimeZone.getDefault())).getDays();
90 | if (numberOfDays != 0) {
91 | return bd + eventFormatter.timeSeparator + bt + eventFormatter.rangeSeparator + ed + eventFormatter.timeSeparator + et;
92 | } else {
93 | return bd + eventFormatter.timeSeparator + bt + eventFormatter.rangeSeparator + et;
94 | }
95 | } else {
96 | // making sure that prev/next day doesn't accidentally show up
97 | beginTime += 1;
98 | endTime -= 1;
99 |
100 | String bd = String.valueOf(DateUtils.getRelativeTimeSpanString(beginTime, nowTime, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE));
101 | String ed = String.valueOf(DateUtils.getRelativeTimeSpanString(endTime, nowTime, DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_SHOW_DATE));
102 |
103 | int numberOfDays = Days.daysBetween(new DateTime(beginTime, DateTimeZone.getDefault()), new DateTime(endTime, DateTimeZone.getDefault())).getDays();
104 | if (numberOfDays != 0) {
105 | return bd + eventFormatter.rangeSeparator + ed;
106 | } else {
107 | return bd;
108 | }
109 | }
110 | }
111 |
112 | static class EventFormatter {
113 | String timeSeparator;
114 | String rangeSeparator;
115 | String locationSeparator;
116 | boolean location;
117 | boolean locationWithTitle;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/helper/Constants.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.helper;
2 |
3 | import com.gobbledygook.theawless.eventlock.BuildConfig;
4 |
5 | import java.util.Collections;
6 | import java.util.HashSet;
7 | import java.util.Set;
8 |
9 | public class Constants {
10 |
11 | // intent filters
12 |
13 | public static final String events_update = BuildConfig.APPLICATION_ID + "." + "EventsUpdate";
14 | public static final String current_events_update = BuildConfig.APPLICATION_ID + "." + "CurrentEventUpdate";
15 | public static final String looks_update = BuildConfig.APPLICATION_ID + "." + "LooksUpdate";
16 |
17 | // intent extras
18 |
19 | public static final String formatted_titles = "formattedTitles";
20 | public static final String formatted_times = "formattedTimes";
21 | public static final String colors = "colors";
22 | public static final String begin_times = "beginTimes";
23 | public static final String end_times = "endTimes";
24 | public static final String scroll_event = "scroll_event";
25 | public static final String current_events = "currentEvents";
26 |
27 | // keys
28 |
29 | public static final String selected_calendars_key = "selected_calendars";
30 | public static final String days_till_key = "days_till";
31 |
32 | public static final String text_position_key = "text_position";
33 |
34 | public static final String time_alignment_key = "time_alignment";
35 | public static final String time_font_size_key = "time_font_size";
36 | public static final String time_padding_above_key = "time_padding_above";
37 | public static final String time_padding_below_key = "time_padding_below";
38 | public static final String time_padding_left_key = "time_padding_left";
39 | public static final String time_padding_right_key = "time_padding_right";
40 |
41 | public static final String title_alignment_key = "title_alignment";
42 | public static final String title_font_size_key = "title_font_size";
43 | public static final String title_padding_above_key = "title_padding_above";
44 | public static final String title_padding_below_key = "title_padding_below";
45 | public static final String title_padding_left_key = "title_padding_left";
46 | public static final String title_padding_right_key = "title_padding_right";
47 |
48 | public static final String number_of_events_key = "number_of_events";
49 | public static final String gismo_scroll_direction_key = "gismo_scroll";
50 | public static final String gismo_layout_direction_key = "gismo_layout";
51 | public static final String gismo_padding_above_key = "gismo_padding_above";
52 | public static final String gismo_padding_below_key = "gismo_padding_below";
53 | public static final String gismo_padding_left_key = "gismo_padding_left";
54 | public static final String gismo_padding_right_key = "gismo_padding_right";
55 |
56 | public static final String color_position_key = "color_position";
57 | public static final String show_color_key = "show_color";
58 | public static final String color_stick_key = "color_stick";
59 | public static final String color_type_key = "color_type";
60 | public static final String color_anti_snap_height_key = "color_snap_height";
61 | public static final String color_anti_snap_width_key = "color_snap_width";
62 | public static final String color_height_key = "color_height";
63 | public static final String color_width_key = "color_width";
64 | public static final String color_padding_above_key = "color_padding_above";
65 | public static final String color_padding_below_key = "color_padding_below";
66 | public static final String color_padding_left_key = "color_padding_left";
67 | public static final String color_padding_right_key = "color_padding_right";
68 |
69 | public static final String current_title_bold_key = "current_title_bold";
70 | public static final String current_time_bold_key = "current_time_bold";
71 | public static final String current_color_outline_key = "current_color_outline";
72 |
73 | public static final String time_separator_key = "time_separator";
74 | public static final String range_separator_key = "range_separator";
75 | public static final String location_separator_key = "location_separator";
76 | public static final String location_key = "location";
77 | public static final String dark_mode_key = "dark_mode";
78 |
79 | // defaults
80 | public static final Set selected_calendars_default = new HashSet<>(Collections.singletonList("1"));
81 |
82 | public static final String days_till_default = "3";
83 |
84 | public static final String text_position_default = "left";
85 |
86 | public static final String time_font_size_default = "12";
87 | public static final String time_alignment_default = "left";
88 | public static final String time_padding_above_default = "0";
89 | public static final String time_padding_below_default = "3";
90 | public static final String time_padding_left_default = "0";
91 | public static final String time_padding_right_default = "0";
92 |
93 | public static final String title_font_size_default = "14";
94 | public static final String title_alignment_default = "left";
95 | public static final String title_padding_above_default = "0";
96 | public static final String title_padding_below_default = "0";
97 | public static final String title_padding_left_default = "0";
98 | public static final String title_padding_right_default = "0";
99 |
100 | public static final String number_of_events_default = "2";
101 | public static final String gismo_scroll_direction_default = "vertical";
102 | public static final String gismo_layout_direction_default = "vertical";
103 | public static final String gismo_padding_above_default = "6";
104 | public static final String gismo_padding_below_default = "0";
105 | public static final String gismo_padding_left_default = "24";
106 | public static final String gismo_padding_right_default = "24";
107 |
108 | public static final String color_position_default = "left";
109 | public static final String show_color_default = "true";
110 | public static final String color_stick_default = "true";
111 | public static final String color_type_default = "rectangle";
112 | public static final String color_anti_snap_height_default = "false";
113 | public static final String color_anti_width_default = "true";
114 | public static final String color_height_default = "3";
115 | public static final String color_width_default = "3";
116 | public static final String color_padding_above_default = "0";
117 | public static final String color_padding_below_default = "0";
118 | public static final String color_padding_left_default = "0";
119 | public static final String color_padding_right_default = "8";
120 |
121 | public static final String current_title_bold_default = "true";
122 | public static final String current_time_bold_default = "false";
123 | public static final String current_color_outline_default = "true";
124 |
125 | public static final String time_separator_default = ", ";
126 | public static final String range_separator_default = " - ";
127 | public static final String location_separator_default = " | ";
128 | public static final String location_default = "title";
129 | public static final String dark_mode_default = "false";
130 |
131 | private Constants() {
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 | import android.net.Uri;
8 | import android.os.Bundle;
9 | import android.preference.PreferenceManager;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.support.v7.widget.Toolbar;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.widget.GridLayout;
16 | import android.widget.Toast;
17 |
18 | import com.gobbledygook.theawless.eventlock.R;
19 | import com.gobbledygook.theawless.eventlock.gismo.EventsGismo;
20 | import com.gobbledygook.theawless.eventlock.helper.Constants;
21 | import com.gobbledygook.theawless.eventlock.helper.XposedUtils;
22 | import com.gobbledygook.theawless.eventlock.receivers.UpdateReceiver;
23 | import com.gobbledygook.theawless.eventlock.services.CalendarLoaderService;
24 |
25 | public class MainActivity extends AppCompatActivity {
26 | private boolean previewOn = false;
27 | private EventsGismo eventGismo = null;
28 | private final UpdateReceiver updateReceiver = new UpdateReceiver() {
29 | @Override
30 | protected EventsGismo getGismo(String action) {
31 | return eventGismo;
32 | }
33 | };
34 |
35 | @Override
36 | protected void onCreate(Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | if (savedInstanceState == null) {
39 | if (!XposedUtils.isModuleEnabled()) {
40 | showEnableModuleDialog();
41 | return;
42 | } else if (XposedUtils.isModuleUpdated()) {
43 | showModuleUpdatedDialog();
44 | return;
45 | }
46 | }
47 | onCreate();
48 | }
49 |
50 | private void onCreate() {
51 | setContentView(R.layout.activity_main);
52 | setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
53 | }
54 |
55 | @Override
56 | protected void onStart() {
57 | super.onStart();
58 | IntentFilter intentFilter = new IntentFilter();
59 | intentFilter.addAction(Constants.events_update);
60 | intentFilter.addAction(Constants.current_events_update);
61 | intentFilter.addAction(Constants.looks_update);
62 | registerReceiver(updateReceiver, intentFilter);
63 | }
64 |
65 | protected void onDestroy() {
66 | unregisterReceiver(updateReceiver);
67 | handleRefresh();
68 | super.onDestroy();
69 | }
70 |
71 | @Override
72 | public boolean onCreateOptionsMenu(Menu menu) {
73 | getMenuInflater().inflate(R.menu.actions, menu);
74 | return true;
75 | }
76 |
77 | @Override
78 | public boolean onOptionsItemSelected(MenuItem item) {
79 | switch (item.getItemId()) {
80 | case R.id.action_preview: {
81 | handlePreview(item);
82 | return true;
83 | }
84 | case R.id.action_refresh: {
85 | handleRefresh();
86 | return true;
87 | }
88 | default: {
89 | return super.onOptionsItemSelected(item);
90 | }
91 | }
92 | }
93 |
94 | private void handlePreview(MenuItem item) {
95 | if (eventGismo == null) {
96 | GridLayout gridLayout = findViewById(R.id.events_placeholder);
97 | eventGismo = new EventsGismo(gridLayout, PreferenceManager.getDefaultSharedPreferences(this));
98 | eventGismo.addRecyclerView();
99 | handleRefresh();
100 | }
101 | if (!previewOn) {
102 | findViewById(R.id.events_placeholder).setVisibility(View.VISIBLE);
103 | item.setIcon(getDrawable(R.drawable.action_preview_off_icon));
104 | } else {
105 | findViewById(R.id.events_placeholder).setVisibility(View.GONE);
106 | item.setIcon(getDrawable(R.drawable.action_preview_on_icon));
107 | }
108 | previewOn = !previewOn;
109 | }
110 |
111 | private void handleRefresh() {
112 | sendBroadcast(new Intent(Constants.looks_update));
113 | startService(new Intent(this, CalendarLoaderService.class));
114 | }
115 |
116 | private void startXposedActivity() {
117 | if (!XposedUtils.startXposedActivity(this)) {
118 | Toast.makeText(this, R.string.xposed_not_installed, Toast.LENGTH_SHORT).show();
119 | startBrowserActivity(getString(R.string.xposed_forum_url));
120 | }
121 | }
122 |
123 | void startBrowserActivity(String url) {
124 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
125 | startActivity(intent);
126 | }
127 |
128 | private void showEnableModuleDialog() {
129 | new AlertDialog.Builder(this)
130 | .setTitle(R.string.enable_xposed_module_title)
131 | .setMessage(R.string.enable_xposed_module_message)
132 | .setIcon(R.drawable.warning_icon)
133 | .setCancelable(false)
134 | .setPositiveButton(R.string.enable, new DialogInterface.OnClickListener() {
135 | @Override
136 | public void onClick(DialogInterface dialog, int which) {
137 | startXposedActivity();
138 | finish();
139 | }
140 | })
141 | .setNeutralButton(R.string.report_bug, new DialogInterface.OnClickListener() {
142 | @Override
143 | public void onClick(DialogInterface dialog, int which) {
144 | startBrowserActivity(getString(R.string.github_issues_url));
145 | finish();
146 | }
147 | })
148 | .setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
149 | @Override
150 | public void onClick(DialogInterface dialog, int which) {
151 | onCreate();
152 | }
153 | })
154 | .show();
155 | }
156 |
157 | private void showModuleUpdatedDialog() {
158 | new AlertDialog.Builder(this)
159 | .setTitle(R.string.module_outdated_title)
160 | .setMessage(R.string.module_outdated_message)
161 | .setIcon(R.drawable.warning_icon)
162 | .setCancelable(false)
163 | .setPositiveButton(R.string.clear_data, new DialogInterface.OnClickListener() {
164 | @Override
165 | public void onClick(DialogInterface dialog, int which) {
166 | startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
167 | .addCategory(Intent.CATEGORY_DEFAULT)
168 | .setData(Uri.parse("package:" + getPackageName()))
169 | );
170 | finish();
171 | }
172 | })
173 | .setNeutralButton(R.string.reboot, new DialogInterface.OnClickListener() {
174 | @Override
175 | public void onClick(DialogInterface dialog, int which) {
176 | startXposedActivity();
177 | finish();
178 | }
179 | })
180 | .setNegativeButton(R.string.ignore, new DialogInterface.OnClickListener() {
181 | @Override
182 | public void onClick(DialogInterface dialog, int which) {
183 | onCreate();
184 | }
185 | })
186 | .show();
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/LayoutManagerHandler.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import static com.gobbledygook.theawless.eventlock.helper.Utils.dpToPixel;
4 |
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import android.graphics.Typeface;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.FrameLayout;
12 | import android.widget.GridLayout;
13 | import android.widget.TextView;
14 |
15 | import com.gobbledygook.theawless.eventlock.helper.Constants;
16 | import com.gobbledygook.theawless.eventlock.helper.Enums;
17 |
18 | class LayoutManagerHandler {
19 | private final SharedPreferences preferences;
20 | private final GridLayout gridLayout;
21 | private final int divisionFactors[] = new int[]{1 /* external use */, 1 /* internal use */};
22 | private View eventView;
23 | private GridLayoutManager gridLayoutManager;
24 | private int dimensions[][];
25 |
26 | LayoutManagerHandler(GridLayout gridLayout, SharedPreferences preferences) {
27 | this.preferences = preferences;
28 | this.gridLayout = gridLayout;
29 | setupDefaultDimensions();
30 | }
31 |
32 | private void setupDefaultDimensions() {
33 | dimensions = new int[][]{
34 | new int[]{1, 1}, // color
35 | new int[]{ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT}, // eventview
36 | new int[]{ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT}, // recyclerview
37 | };
38 | }
39 |
40 | void construct(Runnable runnable) {
41 | setupDefaultDimensions();
42 | Context gismoContext = gridLayout.getContext();
43 | setupEventView();
44 | addEventView(new int[]{
45 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_left_key, Constants.gismo_padding_left_default)),
46 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_above_key, Constants.gismo_padding_above_default)),
47 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_right_key, Constants.gismo_padding_right_default)),
48 | dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_below_key, Constants.gismo_padding_below_default))
49 | }
50 | );
51 | // trying my best to getHeight lol
52 | gridLayout.post(runnable);
53 | }
54 |
55 | private void setupEventView() {
56 | Context gismoContext = gridLayout.getContext();
57 | eventView = new EventViewBuildDirector(gismoContext, preferences)
58 | .setBuilder(
59 | new EventViewBuilder(gismoContext) {
60 | @Override
61 | protected void setupFullContainerRelativeLayout(int[] eventViewDimensions) {
62 | super.setupFullContainerRelativeLayout(eventViewDimensions);
63 | fullContainerRelativeLayout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT));
64 | }
65 | }
66 | )
67 | .setInnerDimensions(getInnerDimensions())
68 | .getEventView();
69 | TextView titleView = eventView.findViewWithTag(Enums.ItemTag.Title);
70 | titleView.setTypeface(titleView.getTypeface(), Typeface.BOLD);
71 | TextView timeView = eventView.findViewWithTag(Enums.ItemTag.Time);
72 | timeView.setTypeface(timeView.getTypeface(), Typeface.BOLD);
73 | }
74 |
75 | private void addEventView(int[] gismoPadding) {
76 | FrameLayout frameLayout = new FrameLayout(gridLayout.getContext());
77 | frameLayout.addView(eventView);
78 | gridLayout.addView(frameLayout);
79 | frameLayout.getLayoutParams().width = GridLayout.LayoutParams.MATCH_PARENT;
80 | frameLayout.getLayoutParams().height = GridLayout.LayoutParams.WRAP_CONTENT;
81 | frameLayout.setPadding(gismoPadding[0], gismoPadding[1], gismoPadding[2], gismoPadding[3]);
82 | }
83 |
84 | void doAfterPost() {
85 | findMeasurements();
86 | gridLayout.removeView((FrameLayout) eventView.getParent());
87 | }
88 |
89 | // man this is hard! had to try loads of combinations to get both width and height
90 | private void findMeasurements() {
91 | Context gismoContext = gridLayout.getContext();
92 | ((FrameLayout) eventView.getParent()).measure(GridLayout.LayoutParams.MATCH_PARENT, GridLayout.LayoutParams.WRAP_CONTENT);
93 | int width = gridLayout.getWidth()
94 | - dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_left_key, Constants.gismo_padding_left_default))
95 | - dpToPixel(gismoContext, preferences.getString(Constants.gismo_padding_right_key, Constants.gismo_padding_right_default));
96 | dimensions[Enums.Dimensions.EventView.ordinal()][1] = dimensions[Enums.Dimensions.ColorImageView.ordinal()][1] = eventView.getMeasuredHeight();
97 | if (getGridLayoutManager().getOrientation() == GridLayoutManager.VERTICAL) {
98 | dimensions[Enums.Dimensions.RecyclerView.ordinal()][1] = ((FrameLayout) eventView.getParent()).getMeasuredHeight() + (dimensions[Enums.Dimensions.EventView.ordinal()][1] * (divisionFactors[0] - 1));
99 | dimensions[Enums.Dimensions.ColorImageView.ordinal()][0] = width / divisionFactors[1];
100 | } else {
101 | dimensions[Enums.Dimensions.EventView.ordinal()][0] = dimensions[Enums.Dimensions.ColorImageView.ordinal()][0] = width / divisionFactors[0];
102 | }
103 | }
104 |
105 | void decideLayoutManager() {
106 | /*
107 | ------------------------------------------------------------------------------------------------
108 | Type Scroll Handler Color
109 | ------------------------------------------------------------------------------------------------
110 | 1*n H V grid, vertical, n columns, limit height to one holder w/n
111 | 1*n H H grid, horizontal, 1 row, limit width of holders - divide by n w/n
112 |
113 | m*1 V V grid, vertical, 1 column, limit height to m holder w
114 | m*1 V H grid, horizontal, m rows w
115 | -----------------------------------------------------------------------------------------------
116 | */
117 | String orientation = preferences.getString(Constants.gismo_layout_direction_key, Constants.gismo_layout_direction_default);
118 | String scroll = preferences.getString(Constants.gismo_scroll_direction_key, Constants.gismo_scroll_direction_default);
119 | int division = Integer.parseInt(preferences.getString(Constants.number_of_events_key, Constants.number_of_events_default));
120 | Context context = gridLayout.getContext();
121 | String horizontal = "horizontal", vertical = "vertical";
122 | if (orientation.equals(horizontal) && scroll.equals(vertical)) {
123 | divisionFactors[0] = 1;
124 | divisionFactors[1] = division;
125 | gridLayoutManager = new GridLayoutManager(context, division, GridLayoutManager.VERTICAL, false);
126 | } else if (orientation.equals(horizontal) && scroll.equals(horizontal)) {
127 | divisionFactors[0] = division;
128 | divisionFactors[1] = 1;
129 | gridLayoutManager = new GridLayoutManager(context, 1, GridLayoutManager.HORIZONTAL, false);
130 | } else if (orientation.equals(vertical) && scroll.equals(vertical)) {
131 | divisionFactors[0] = division;
132 | divisionFactors[1] = 1;
133 | gridLayoutManager = new GridLayoutManager(context, 1, GridLayoutManager.VERTICAL, false);
134 | } else if (orientation.equals(vertical) && scroll.equals(horizontal)) {
135 | divisionFactors[0] = 1;
136 | divisionFactors[1] = division;
137 | gridLayoutManager = new GridLayoutManager(context, division, GridLayoutManager.HORIZONTAL, false);
138 | }
139 | }
140 |
141 | GridLayoutManager getGridLayoutManager() {
142 | return gridLayoutManager;
143 | }
144 |
145 | int getDivisionFactor() {
146 | return divisionFactors[0];
147 | }
148 |
149 | int[] getOuterDimensions() {
150 | return dimensions[Enums.Dimensions.RecyclerView.ordinal()];
151 | }
152 |
153 | int[][] getInnerDimensions() {
154 | return new int[][]{dimensions[Enums.Dimensions.ColorImageView.ordinal()], dimensions[Enums.Dimensions.EventView.ordinal()]};
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/app/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.app;
2 |
3 | import android.Manifest;
4 | import android.annotation.SuppressLint;
5 | import android.app.AlertDialog;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.pm.PackageManager;
9 | import android.os.Build;
10 | import android.os.Bundle;
11 | import android.preference.Preference;
12 | import android.preference.PreferenceFragment;
13 | import android.preference.PreferenceScreen;
14 | import android.support.annotation.NonNull;
15 | import android.widget.Toast;
16 |
17 | import com.gobbledygook.theawless.eventlock.R;
18 | import com.gobbledygook.theawless.eventlock.helper.Constants;
19 |
20 | public class SettingsFragment extends PreferenceFragment {
21 | private static final int CALENDAR_READ_REQUEST_CODE = 0;
22 | private static final int nonEmptyPreferences[] = new int[]{
23 | R.string.gismo_padding_above_key, R.string.gismo_padding_below_key, R.string.gismo_padding_left_key, R.string.gismo_padding_right_key,
24 | R.string.title_padding_above_key, R.string.title_padding_below_key, R.string.title_padding_left_key, R.string.title_padding_right_key,
25 | R.string.time_padding_above_key, R.string.time_padding_below_key, R.string.time_padding_left_key, R.string.time_padding_right_key,
26 | R.string.color_padding_above_key, R.string.color_padding_below_key, R.string.color_padding_left_key, R.string.color_padding_right_key,
27 | R.string.color_height_key, R.string.color_width_key, R.string.days_till_key,
28 | R.string.number_of_events_key, R.string.title_font_size_key, R.string.time_font_size_key,
29 | };
30 |
31 | private final Preference.OnPreferenceChangeListener preferenceListener = new Preference.OnPreferenceChangeListener() {
32 | @Override
33 | public boolean onPreferenceChange(Preference preference, Object newValue) {
34 | return !newValue.toString().trim().isEmpty();
35 | }
36 | };
37 | private int versionClickCount = 0;
38 | private PresetMaker presetMaker;
39 |
40 | @SuppressLint("WorldReadableFiles")
41 | @Override
42 | public void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | getPreferenceManager().setSharedPreferencesMode(Context.MODE_WORLD_READABLE);
45 | addPreferencesFromResource(R.xml.preferences);
46 | presetMaker = new PresetMaker(getActivity());
47 | }
48 |
49 | @Override
50 | public void onStart() {
51 | super.onStart();
52 | setUpPreferenceCleaners();
53 | permissionCheck();
54 | }
55 |
56 | private void permissionCheck() {
57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && getActivity().checkSelfPermission(Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
58 | requestPermissions(new String[]{Manifest.permission.READ_CALENDAR}, CALENDAR_READ_REQUEST_CODE);
59 | } else {
60 | createCalendarList();
61 | }
62 | }
63 |
64 | private void refreshUI() {
65 | setPreferenceScreen(null);
66 | addPreferencesFromResource(R.xml.preferences);
67 | permissionCheck();
68 | setUpPreferenceCleaners();
69 | }
70 |
71 | @Override
72 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
73 | if (requestCode == CALENDAR_READ_REQUEST_CODE) {
74 | if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
75 | Toast.makeText(getActivity(), R.string.read_permission_error, Toast.LENGTH_SHORT).show();
76 | getActivity().finish();
77 | } else {
78 | createCalendarList();
79 | }
80 | }
81 | }
82 |
83 | private void createCalendarList() {
84 | ((CalendarPreference) findPreference(Constants.selected_calendars_key)).getCalendarIds();
85 | }
86 |
87 | private void setUpPreferenceCleaners() {
88 | for (int keyId : nonEmptyPreferences) {
89 | Preference preference = getPreferenceManager().findPreference(getString(keyId));
90 | if (preference != null) {
91 | preference.setOnPreferenceChangeListener(preferenceListener);
92 | }
93 | }
94 | }
95 |
96 | @Override
97 | public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
98 | switch (preference.getTitleRes()) {
99 | case R.string.version_title: {
100 | String resourceName = "version_count_" + String.valueOf(++versionClickCount);
101 | int id = getResources().getIdentifier(resourceName, "string", getActivity().getPackageName());
102 | if (id != 0) {
103 | Toast.makeText(getActivity(), getResources().getString(id), Toast.LENGTH_SHORT).show();
104 | }
105 | return true;
106 | }
107 | case R.string.project_title: {
108 | new AlertDialog.Builder(getActivity())
109 | .setTitle(R.string.project_title)
110 | .setMessage(R.string.project)
111 | .setIcon(R.drawable.action_preview_on_icon)
112 | .setNeutralButton(R.string.report_bug, new DialogInterface.OnClickListener() {
113 | @Override
114 | public void onClick(DialogInterface dialog, int which) {
115 | ((MainActivity) getActivity()).startBrowserActivity(getString(R.string.github_issues_url));
116 | }
117 | })
118 | .setNegativeButton(R.string.paypal, new DialogInterface.OnClickListener() {
119 | @Override
120 | public void onClick(DialogInterface dialog, int which) {
121 | ((MainActivity) getActivity()).startBrowserActivity(getString(R.string.paypal_url));
122 | }
123 | })
124 | .setPositiveButton(R.string.github, new DialogInterface.OnClickListener() {
125 | @Override
126 | public void onClick(DialogInterface dialog, int which) {
127 | ((MainActivity) getActivity()).startBrowserActivity(getString(R.string.github_url));
128 | }
129 | })
130 | .show();
131 | return true;
132 | }
133 | case R.string.help_title: {
134 | new AlertDialog.Builder(getActivity())
135 | .setTitle(R.string.help_title)
136 | .setMessage(R.string.help)
137 | .setIcon(R.drawable.action_refresh_icon)
138 | .setPositiveButton(R.string.okay, null)
139 | .show();
140 | return true;
141 | }
142 | case R.string.multiple_preset1_title: {
143 | presetMaker.begin()
144 | .lineLeft()
145 | .makeTextSpaceVertically()
146 | .setOrientations("vertical", "vertical")
147 | .end();
148 | break;
149 | }
150 | case R.string.multiple_preset2_title: {
151 | presetMaker.begin()
152 | .circleBelow()
153 | .makeColorSpaceVertically()
154 | .centerText()
155 | .end();
156 | break;
157 | }
158 | case R.string.multiple_preset3_title: {
159 | presetMaker.begin()
160 | .lineLeft()
161 | .end();
162 | break;
163 | }
164 | case R.string.multiple_preset4_title: {
165 | presetMaker.begin()
166 | .circleRight()
167 | .makeTextSpaceVertically()
168 | .makeColorSpaceVertically()
169 | .setOrientations("vertical", "vertical")
170 | .end();
171 | break;
172 | }
173 | case R.string.multiple_preset5_title: {
174 | presetMaker.begin()
175 | .lineAbove()
176 | .end();
177 | break;
178 | }
179 | case R.string.multiple_preset6_title: {
180 | presetMaker.begin()
181 | .eclipseAbove()
182 | .setOrientations("vertical", "vertical")
183 | .centerText()
184 | .makeTextSpaceVertically()
185 | .end();
186 | break;
187 | }
188 | case R.string.single_preset1_title: {
189 | presetMaker.begin()
190 | .circleRight()
191 | .setMultipleEvents(1)
192 | .makeTextBig()
193 | .end();
194 | break;
195 | }
196 | case R.string.single_preset2_title: {
197 | presetMaker.begin()
198 | .setMultipleEvents(1)
199 | .makeTextBig()
200 | .end();
201 | break;
202 | }
203 | case R.string.single_preset3_title: {
204 | presetMaker.begin()
205 | .noColor()
206 | .setMultipleEvents(1)
207 | .makeTextBig()
208 | .end();
209 | break;
210 | }
211 | default: {
212 | return super.onPreferenceTreeClick(preferenceScreen, preference);
213 | }
214 | }
215 | // ends up here if one of the presets is clicked, otherwise returns early
216 | refreshUI();
217 | return true;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Xposed framework is not installed
4 | Enable this module
5 | For EventLock to function correctly, you must enable the Xposed Module
6 | Enable
7 | Okay
8 | Report bug
9 | Clear app data
10 | Ignore
11 | Xposed module updated
12 | Due to various new changes you must clear the app-data once.
13 | Reboot
14 | Calendar read permission is required. Exiting!
15 | Settings set to preset, press refresh!
16 | Please press the refresh button after making any setting changes.\n\nThe eye button in the title bar can be used to show/hide preview.\n\nKeeping the bottom padding in Gismo high will lead to more space between notifications and events.\n\nTo make the oval color block circular, set height equal to width.\n\nThere are loads of combinations possible! Mess up those settings! :-D
17 | Hey,\n\nI built this project for my personal use, but I am glad that it could help you too.\n\nMany people have helped me (on Github and XDA) in testing and by suggesting new ideas. Special mention to Mansya Prime for designing the icon.\n\nThanks a lot everyone!
18 | Github
19 | Donate
20 |
21 |
22 | Preview
23 | Refresh
24 |
25 |
26 | Settings
27 | Customisation
28 | Presets
29 | Multiple
30 | Single
31 | Padding
32 | Gismo
33 | Gismo Padding
34 | Current event
35 | Title & Time
36 | Container
37 | Title
38 | Title padding
39 | Time
40 | Time padding
41 | Color
42 | Color padding
43 | About
44 | Help
45 | Details about various features
46 | Project
47 | Credits and urls
48 |
49 | Preset 1
50 | Preset 2
51 | Preset 3
52 | Preset 4
53 | Preset 5
54 | Preset 6
55 |
56 | Preset 1
57 | Preset 2
58 | Preset 3
59 |
60 | These calendar will be used to show the events
61 | Selected calendars
62 | How many days after today should we look for events
63 | Days till
64 |
65 | Where should the text be placed on the lockscreen
66 | Text position
67 |
68 | The display size of time
69 | Font size
70 | The display alignment of time
71 | Alignment
72 | Time\'s padding from above in the lock screen
73 | Above
74 | Time\'s padding from below in the lock screen
75 | Below
76 | Time\'s padding from right in the lock screen
77 | Right
78 | Time\'s padding from left in the lock screen
79 | Left
80 |
81 | The display size of title
82 | Font size
83 | The display alignment of title
84 | Alignment
85 | Title\'s padding from above in the lock screen
86 | Above
87 | Title\'s padding from below in the lock screen
88 | Below
89 | Title\'s padding from right in the lock screen
90 | Right
91 | Title\'s padding from left in the lock screen
92 | Left
93 |
94 | Number of events on the same page
95 | Number of events
96 |
97 | Gismo\'s scrolling direction
98 | Scroll direction
99 | Gismo\'s layout direction
100 | Layout direction
101 |
102 | Gismo\'s padding from above in the lock screen
103 | Above
104 | Gismo\'s padding from below in the lock screen
105 | Below
106 | Gismo\'s padding from right in the lock screen
107 | Right
108 | Gismo\'s padding from left in the lock screen
109 | Left
110 |
111 | How color block should be placed
112 | Color position
113 | Show event color on the lock screen
114 | Show event color
115 | Whether the color block should be placed very close to text
116 | Stick to text
117 | Block type
118 | Color block type on the lockscreen
119 | Disable setting color height based on text size
120 | Manual Height
121 | Disable setting color width based on text size
122 | Manual width
123 | The height of the color block
124 | Height
125 | The width of the color block
126 | Width
127 | Color\'s padding from above in the lock screen
128 | Above
129 | Color\'s padding from below in the lock screen
130 | Below
131 | Color\'s padding from right in the lock screen
132 | Right
133 | Color\'s padding from left in the lock screen
134 | Left
135 |
136 | Bold the title of the current event
137 | Title bold
138 | Bold the time of the current event
139 | Time bold
140 | Outline the color block of the current event
141 | Color outline
142 |
143 | Time separator
144 | Separates date and time
145 | Range separator
146 | Separates time range
147 | Location separator
148 | Separates location from title or time
149 | Location
150 | Where should location be shown
151 | Dark mode
152 | Helpful when the background is bright
153 |
154 |
155 |
156 | - title
157 | - time
158 | - off
159 |
160 |
161 | - left
162 | - right
163 | - up
164 | - down
165 |
166 |
167 | - left
168 | - center
169 | - right
170 |
171 |
172 | - oval
173 | - rectangle
174 |
175 |
176 | - horizontal
177 | - vertical
178 |
179 |
180 |
--------------------------------------------------------------------------------
/app/src/main/java/com/gobbledygook/theawless/eventlock/gismo/EventViewBuilder.java:
--------------------------------------------------------------------------------
1 | package com.gobbledygook.theawless.eventlock.gismo;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.Drawable;
6 | import android.graphics.drawable.GradientDrawable;
7 | import android.graphics.drawable.LayerDrawable;
8 | import android.graphics.drawable.ShapeDrawable;
9 | import android.graphics.drawable.shapes.OvalShape;
10 | import android.graphics.drawable.shapes.RectShape;
11 | import android.support.v7.widget.GridLayoutManager;
12 | import android.text.TextUtils;
13 | import android.view.View;
14 | import android.widget.ImageView;
15 | import android.widget.LinearLayout;
16 | import android.widget.RelativeLayout;
17 | import android.widget.TextView;
18 |
19 | import com.gobbledygook.theawless.eventlock.helper.Enums;
20 |
21 | class EventViewBuilder {
22 | private final Context gismoContext;
23 | RelativeLayout fullContainerRelativeLayout;
24 | private LinearLayout textContainerLinearLayout;
25 | private ImageView colorImageView;
26 |
27 | EventViewBuilder(Context gismoContext) {
28 | this.gismoContext = gismoContext;
29 | }
30 |
31 | void setupFullContainerRelativeLayout(int[] eventViewDimensions) {
32 | fullContainerRelativeLayout = new RelativeLayout(gismoContext);
33 | fullContainerRelativeLayout.setLayoutParams(new GridLayoutManager.LayoutParams(eventViewDimensions[0], eventViewDimensions[1]));
34 | }
35 |
36 | void setupTextContainerLinearLayout() {
37 | textContainerLinearLayout = new LinearLayout(gismoContext);
38 | textContainerLinearLayout.setOrientation(LinearLayout.VERTICAL);
39 | fullContainerRelativeLayout.addView(textContainerLinearLayout);
40 | textContainerLinearLayout.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
41 | textContainerLinearLayout.getLayoutParams().width = RelativeLayout.LayoutParams.WRAP_CONTENT;
42 | }
43 |
44 | void setupTitleTextView(int[] padding, int size, String alignment, boolean dark_mode) {
45 | TextView titleTextView = new TextView(gismoContext);
46 | textContainerLinearLayout.addView(titleTextView);
47 | setupCommonTextView(titleTextView, padding, size, alignment);
48 | titleTextView.setTag(Enums.ItemTag.Title);
49 | titleTextView.setTextColor(dark_mode ? Color.BLACK : Color.WHITE);
50 | }
51 |
52 | void setupTimeTextView(int[] padding, int size, String alignment, boolean dark_mode) {
53 | TextView timeTextView = new TextView(gismoContext);
54 | textContainerLinearLayout.addView(timeTextView);
55 | setupCommonTextView(timeTextView, padding, size, alignment);
56 | timeTextView.setTag(Enums.ItemTag.Time);
57 | timeTextView.setTextColor(dark_mode ? Color.BLACK : Color.WHITE);
58 | }
59 |
60 | private void setupCommonTextView(TextView textView, int[] padding, int size, String alignment) {
61 | textView.setMaxLines(1);
62 | textView.setHorizontallyScrolling(true);
63 | textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
64 | textView.setMarqueeRepeatLimit(-1);
65 | textView.setSelected(true);
66 | textView.setTextSize(size);
67 | textView.setPadding(padding[0], padding[1], padding[2], padding[3]);
68 | textView.getLayoutParams().height = LinearLayout.LayoutParams.WRAP_CONTENT;
69 | textView.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
70 | switch (alignment) {
71 | case "left": {
72 | textView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
73 | break;
74 | }
75 | case "right": {
76 | textView.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
77 | break;
78 | }
79 | case "center": {
80 | textView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
81 | }
82 | }
83 | }
84 |
85 | void setupColorImageView(int[] padding, String type, int[] manualDimensions, boolean[] isManualDimensions, int[] autoDimensions) {
86 | colorImageView = new ImageView(gismoContext);
87 | fullContainerRelativeLayout.addView(colorImageView);
88 | colorImageView.setTag(Enums.ItemTag.Image);
89 | GradientDrawable outlineDrawable = new GradientDrawable();
90 | ShapeDrawable shapeDrawable = new ShapeDrawable();
91 | if (type.equals("oval")) {
92 | shapeDrawable.setShape(new OvalShape());
93 | outlineDrawable.setShape(GradientDrawable.OVAL);
94 | } else {
95 | shapeDrawable.setShape(new RectShape());
96 | outlineDrawable.setShape(GradientDrawable.RECTANGLE);
97 | }
98 | shapeDrawable.setIntrinsicWidth(isManualDimensions[0] ? manualDimensions[0] : autoDimensions[0]);
99 | shapeDrawable.setIntrinsicHeight(isManualDimensions[1] ? manualDimensions[1] : autoDimensions[1]);
100 | colorImageView.setImageDrawable(new LayerDrawable(new Drawable[]{shapeDrawable, outlineDrawable}));
101 | colorImageView.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
102 | colorImageView.getLayoutParams().width = RelativeLayout.LayoutParams.WRAP_CONTENT;
103 | colorImageView.setPadding(padding[0], padding[1], padding[2], padding[3]);
104 | colorImageView.setAdjustViewBounds(true);
105 | }
106 |
107 | /*
108 | -----------------------------------------------------------------------------------------------------------
109 | Text Position Color Position Stick Color Status(T for text, C for color, OO for overlap)
110 | -----------------------------------------------------------------------------------------------------------
111 |
112 | left left true | |
113 | |CT |
114 | | |
115 |
116 | false | |
117 | |OO |
118 | | |
119 |
120 | right true | |
121 | |TC |
122 | | |
123 |
124 | false | |
125 | |T C|
126 | | |
127 |
128 | up true |C |
129 | |T |
130 | | |
131 |
132 | false | C |
133 | |T |
134 | | |
135 |
136 | down true | |
137 | |T |
138 | |C |
139 |
140 | false | |
141 | |T |
142 | | C |
143 |
144 | right left true | |
145 | | CT|
146 | | |
147 |
148 | false | |
149 | |C T|
150 | | |
151 |
152 | right true | |
153 | | TC|
154 | | |
155 |
156 | false | |
157 | | OO|
158 | | |
159 |
160 | up true | C|
161 | | T|
162 | | |
163 |
164 | false | C |
165 | | T|
166 | | |
167 |
168 | down true | |
169 | | T|
170 | | C|
171 |
172 | false | |
173 | | T|
174 | | C |
175 |
176 | center left true | |
177 | | CT |
178 | | |
179 |
180 | false | |
181 | |C T |
182 | | |
183 |
184 | right true | |
185 | | TC |
186 | | |
187 |
188 | false | |
189 | | T C|
190 | | |
191 |
192 | up true | C |
193 | | T |
194 | | |
195 |
196 | false | C |
197 | | T |
198 | | |
199 |
200 | down true | |
201 | | T |
202 | | C |
203 |
204 | false | |
205 | | T |
206 | | C |
207 |
208 | -----------------------------------------------------------------------------------------------------------
209 | */
210 |
211 |
212 | // never look at this code. not even god knows what I wrote
213 | void setupPositions(String textPosition, String colorPosition, boolean stickColor) {
214 | int textPositionRule;
215 | switch (textPosition) {
216 | case "left": {
217 | textPositionRule = RelativeLayout.ALIGN_PARENT_LEFT;
218 | break;
219 | }
220 | case "center": {
221 | textPositionRule = RelativeLayout.CENTER_HORIZONTAL;
222 | break;
223 | }
224 | case "right":
225 | default: {
226 | textPositionRule = RelativeLayout.ALIGN_PARENT_RIGHT;
227 | }
228 | }
229 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(textPositionRule);
230 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
231 | if (colorImageView == null) {
232 | return;
233 | }
234 | textContainerLinearLayout.setId(View.generateViewId());
235 | colorImageView.setId(View.generateViewId());
236 | switch (colorPosition) {
237 | case "left": {
238 | if (!stickColor) {
239 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_LEFT);
240 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
241 | break;
242 | }
243 | if (textPosition.equals("left")) {
244 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_LEFT);
245 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
246 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(RelativeLayout.RIGHT_OF, colorImageView.getId());
247 | } else {
248 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.LEFT_OF, textContainerLinearLayout.getId());
249 | }
250 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
251 | break;
252 | }
253 | case "right": {
254 | if (!stickColor) {
255 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
256 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
257 | break;
258 | }
259 | if (textPosition.equals("right")) {
260 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
261 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
262 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(RelativeLayout.LEFT_OF, colorImageView.getId());
263 | } else {
264 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.RIGHT_OF, textContainerLinearLayout.getId());
265 | }
266 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.CENTER_VERTICAL);
267 | break;
268 | }
269 | case "up": {
270 | if (stickColor) {
271 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(textPositionRule);
272 | }
273 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_TOP);
274 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(RelativeLayout.BELOW, colorImageView.getId());
275 | break;
276 | }
277 | case "down": {
278 | if (stickColor) {
279 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(textPositionRule);
280 | }
281 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).removeRule(RelativeLayout.CENTER_VERTICAL);
282 | ((RelativeLayout.LayoutParams) textContainerLinearLayout.getLayoutParams()).addRule(RelativeLayout.ALIGN_PARENT_TOP);
283 | ((RelativeLayout.LayoutParams) colorImageView.getLayoutParams()).addRule(RelativeLayout.BELOW, textContainerLinearLayout.getId());
284 | break;
285 | }
286 | }
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
17 |
18 |
19 |
20 |
21 |
24 |
27 |
30 |
33 |
36 |
39 |
40 |
41 |
44 |
47 |
50 |
51 |
52 |
53 |
54 |
61 |
68 |
75 |
76 |
77 |
84 |
91 |
98 |
105 |
106 |
107 |
108 |
109 |
114 |
119 |
124 |
129 |
130 |
131 |
132 |
133 |
140 |
141 |
142 |
149 |
156 |
157 |
158 |
165 |
172 |
179 |
186 |
187 |
188 |
189 |
190 |
197 |
204 |
209 |
214 |
215 |
216 |
223 |
230 |
237 |
244 |
245 |
246 |
247 |
248 |
255 |
260 |
261 |
262 |
263 |
264 |
269 |
277 |
283 |
291 |
297 |
303 |
311 |
319 |
322 |
323 |
331 |
339 |
347 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
364 |
367 |
368 |
369 |
370 |
--------------------------------------------------------------------------------