├── .github └── FUNDING.yml ├── .gitignore ├── .gitmodules ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── output-metadata.json │ └── output.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ ├── com │ │ └── google │ │ │ └── android │ │ │ ├── a │ │ │ ├── LauncherOverlayBinder.java │ │ │ ├── a.java │ │ │ └── c.java │ │ │ ├── apps │ │ │ └── gsa │ │ │ │ └── nowoverlayservice │ │ │ │ └── ConfigurationOverlayController.kt │ │ │ └── libraries │ │ │ ├── gsa │ │ │ └── d │ │ │ │ └── a │ │ │ │ ├── BaseCallback.java │ │ │ │ ├── ByteBundleHolder.java │ │ │ │ ├── DialogListeners.java │ │ │ │ ├── DialogOverlayController.java │ │ │ │ ├── MinusOneOverlayCallback.java │ │ │ │ ├── OverlayController.java │ │ │ │ ├── OverlayControllerBinder.java │ │ │ │ ├── OverlayControllerCallback.java │ │ │ │ ├── OverlayControllerLayoutChangeListener.java │ │ │ │ ├── OverlayControllerSlidingPanelLayout.java │ │ │ │ ├── OverlayControllerStateChanger.java │ │ │ │ ├── OverlaysController.java │ │ │ │ ├── PanelState.java │ │ │ │ ├── SlidingPanelLayout.java │ │ │ │ ├── SlidingPanelLayoutInterpolator.java │ │ │ │ ├── SlidingPanelLayoutProperty.java │ │ │ │ ├── TransparentOverlayController.java │ │ │ │ ├── t.java │ │ │ │ └── v.java │ │ │ └── i │ │ │ ├── LauncherOverlayInterfaceBinder.java │ │ │ ├── a.java │ │ │ ├── d.java │ │ │ └── f.java │ └── ua │ │ └── itaysonlab │ │ ├── homefeeder │ │ ├── HFApplication.kt │ │ ├── activites │ │ │ └── MainActivity.kt │ │ ├── fragments │ │ │ ├── AboutFragment.kt │ │ │ ├── PluginsFragment.kt │ │ │ ├── PreferenceFragment.kt │ │ │ └── base │ │ │ │ └── FixedPreferencesFragment.kt │ │ ├── kt │ │ │ └── KtExtensions.kt │ │ ├── overlay │ │ │ ├── DrawerOverlayService.kt │ │ │ ├── OverlayKt.kt │ │ │ ├── feed │ │ │ │ ├── FeedAdapter.kt │ │ │ │ └── binders │ │ │ │ │ ├── FeedBinder.kt │ │ │ │ │ ├── StoryCardBinder.kt │ │ │ │ │ ├── TextCardBinder.kt │ │ │ │ │ └── TextCardWithActionsBinder.kt │ │ │ ├── launcherapi │ │ │ │ ├── LauncherAPI.kt │ │ │ │ └── OverlayThemeHolder.kt │ │ │ └── rvutils │ │ │ │ └── StackBlur.java │ │ ├── pluginsystem │ │ │ ├── PluginConnector.kt │ │ │ └── PluginFetcher.kt │ │ ├── preferences │ │ │ ├── HFPluginPreferences.kt │ │ │ └── HFPreferences.kt │ │ ├── prefui │ │ │ └── HFElementPreview.kt │ │ ├── theming │ │ │ └── Theming.kt │ │ └── utils │ │ │ ├── Logger.kt │ │ │ ├── OverlayBridge.kt │ │ │ ├── PreferenceHelper.kt │ │ │ └── RelativeTimeHelper.kt │ │ └── replica │ │ └── vkpopup │ │ ├── ActionAdapter.kt │ │ ├── ActionDivider.kt │ │ ├── ActionStyle.kt │ │ ├── ActionVh.kt │ │ ├── DialogActionsVcByPopup.kt │ │ ├── DividerStyle.kt │ │ ├── PopupContentAnimator.kt │ │ ├── PopupItem.kt │ │ ├── PopupWindowImpl.kt │ │ └── VkLibActionsListView.kt │ └── res │ ├── drawable-hdpi │ └── vkim_bg_overlay.9.png │ ├── drawable-mdpi │ └── vkim_bg_overlay.9.png │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable-xhdpi │ └── vkim_bg_overlay.9.png │ ├── drawable-xxhdpi │ └── vkim_bg_overlay.9.png │ ├── drawable-xxxhdpi │ └── vkim_bg_overlay.9.png │ ├── drawable │ ├── gradient.xml │ ├── ic_delete_24.xml │ ├── ic_info_24.xml │ ├── ic_info_outline_28.xml │ ├── ic_launcher_background.xml │ ├── ic_more_vertical_24.xml │ ├── ic_notifications_24.xml │ ├── ic_replay_24.xml │ ├── ic_report_outline_28.xml │ ├── ic_services_outline_28.xml │ ├── ic_settings_24.xml │ ├── ic_settings_outline_28.xml │ ├── ic_warning_24.xml │ ├── remove_bg.xml │ └── v2_dialog.xml │ ├── layout │ ├── activity_main.xml │ ├── feed_card_action.xml │ ├── feed_card_story_large.xml │ ├── feed_card_text.xml │ ├── notification_generic_content.xml │ ├── notification_simple.xml │ ├── overlay_header.xml │ ├── overlay_layout.xml │ ├── plugin_manager_empty.xml │ ├── plugin_manager_entry.xml │ ├── plugin_manager_ui.xml │ ├── preview.xml │ ├── replica_popup.xml │ └── vklib_actionslistview_entry.xml │ ├── menu │ └── bottom_nav_menu.xml │ ├── mipmap-anydpi-v26 │ └── ic_launcher.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── navigation │ └── mobile_navigation.xml │ ├── values-night │ ├── bools.xml │ └── colors.xml │ ├── values-ru │ ├── arrays.xml │ ├── plurals.xml │ └── strings.xml │ ├── values-v23 │ └── styles.xml │ ├── values-v27 │ └── styles.xml │ ├── values │ ├── arrays.xml │ ├── attrs.xml │ ├── bools.xml │ ├── colors.xml │ ├── dimens.xml │ ├── plurals.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── pref_about.xml │ └── pref_general.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | custom: ['https://qiwi.me/itaysonlab'] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Split plugins into seperate repos 2 | hf-rss-datasource 3 | hf-vkplugin 4 | 5 | # SDK as submodule 6 | hf-vkplugin 7 | 8 | # Built application files 9 | *.apk 10 | *.ap_ 11 | *.aab 12 | 13 | # Files for the ART/Dalvik VM 14 | *.dex 15 | 16 | # Java class files 17 | *.class 18 | 19 | # Generated files 20 | bin/ 21 | gen/ 22 | out/ 23 | 24 | # Gradle files 25 | .gradle/ 26 | build/ 27 | 28 | # Local configuration file (sdk path, etc) 29 | local.properties 30 | 31 | # Proguard folder generated by Eclipse 32 | proguard/ 33 | 34 | # Log Files 35 | *.log 36 | 37 | # Android Studio Navigation editor temp files 38 | .navigation/ 39 | 40 | # Android Studio captures folder 41 | captures/ 42 | 43 | # IntelliJ 44 | *.iml 45 | .idea/ 46 | 47 | # Keystore files 48 | # Uncomment the following lines if you do not want to check your keystore files in. 49 | #*.jks 50 | #*.keystore 51 | 52 | # External native build folder generated in Android Studio 2.2 and later 53 | .externalNativeBuild 54 | 55 | # Google Services (e.g. APIs or Firebase) 56 | google-services.json 57 | 58 | # Freeline 59 | freeline.py 60 | freeline/ 61 | freeline_project_description.json 62 | 63 | # fastlane 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | fastlane/readme.md 69 | 70 | # Obviously we don't need caches from macOS and other OS'es 71 | .DS_Store 72 | .DS_Store? 73 | ._* 74 | .Spotlight-V100 75 | .Trashes 76 | settings.gradle 77 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "homefeeder-sdk"] 2 | path = homefeeder-sdk 3 | url = https://github.com/iTaysonLab/homefeeder-sdk/ 4 | [submodule "homefeeder-rss"] 5 | path = homefeeder-rss 6 | url = https://github.com/iTaysonLab/homefeeder-rss 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | xmlns:android 17 | 18 | ^$ 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | xmlns:.* 28 | 29 | ^$ 30 | 31 | 32 | BY_NAME 33 | 34 |
35 |
36 | 37 | 38 | 39 | .*:id 40 | 41 | http://schemas.android.com/apk/res/android 42 | 43 | 44 | 45 |
46 |
47 | 48 | 49 | 50 | .*:name 51 | 52 | http://schemas.android.com/apk/res/android 53 | 54 | 55 | 56 |
57 |
58 | 59 | 60 | 61 | name 62 | 63 | ^$ 64 | 65 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | style 73 | 74 | ^$ 75 | 76 | 77 | 78 |
79 |
80 | 81 | 82 | 83 | .* 84 | 85 | ^$ 86 | 87 | 88 | BY_NAME 89 | 90 |
91 |
92 | 93 | 94 | 95 | .* 96 | 97 | http://schemas.android.com/apk/res/android 98 | 99 | 100 | ANDROID_ATTRIBUTE_ORDER 101 | 102 |
103 |
104 | 105 | 106 | 107 | .* 108 | 109 | .* 110 | 111 | 112 | BY_NAME 113 | 114 |
115 |
116 |
117 |
118 | 119 | 121 |
122 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HomeFeeder 2 | Custom Google Now Feed replacement for launchers. 3 | 4 | ## Supported launchers 5 | - Librechair 6 | - Shade Launcher 7 | - Mostly anything with custom feed provider support 8 | 9 | ## Credits 10 | https://github.com/FabianTerhorst/DrawerOverlayService as base for overlay service -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | apply plugin: 'kotlin-kapt' 5 | apply plugin: 'kotlin-parcelize' 6 | 7 | android { 8 | compileSdkVersion 31 9 | 10 | defaultConfig { 11 | applicationId "ua.itaysonlab.homefeeder" 12 | minSdkVersion 21 13 | targetSdkVersion 31 14 | versionCode 11 15 | versionName "alpha 1" 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled true 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | kotlinOptions { 26 | jvmTarget = '1.8' 27 | } 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_1_8 31 | targetCompatibility JavaVersion.VERSION_1_8 32 | } 33 | 34 | buildFeatures { 35 | viewBinding true 36 | } 37 | } 38 | 39 | dependencies { 40 | implementation fileTree(dir: 'libs', include: ['*.jar']) 41 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 42 | implementation 'androidx.appcompat:appcompat:1.4.1' 43 | implementation 'androidx.core:core-ktx:1.7.0' 44 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 45 | implementation 'com.google.android.material:material:1.6.0-alpha02' 46 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' 47 | implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' 48 | implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' 49 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' 50 | implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' 51 | implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' 52 | implementation 'androidx.preference:preference-ktx:1.2.0' 53 | implementation("io.coil-kt:coil:1.3.0") 54 | 55 | implementation project(':homefeeder-sdk') 56 | } 57 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | #-keep class com.google.android.libraries.launcherclient.** {*;} 23 | 24 | -keep class ua.itaysonlab.hfsdk.** { 25 | *; 26 | } 27 | 28 | -repackageclasses "hfcore" -------------------------------------------------------------------------------- /app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "ua.itaysonlab.homefeeder", 8 | "variantName": "processReleaseResources", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "versionCode": 10, 14 | "versionName": "pre-alpha 10", 15 | "outputFile": "app-release.apk" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "ua.itaysonlab.homefeeder", 8 | "variantName": "release", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "properties": [], 14 | "versionCode": 8, 15 | "versionName": "8", 16 | "enabled": true, 17 | "outputFile": "app-release.apk" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/a/LauncherOverlayBinder.java: -------------------------------------------------------------------------------- 1 | package com.google.android.a; 2 | 3 | import android.os.Binder; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.Parcel; 7 | import android.os.RemoteException; 8 | 9 | public class LauncherOverlayBinder extends Binder implements IInterface { 10 | public IBinder asBinder() { 11 | return this; 12 | } 13 | 14 | protected final boolean a(int i, Parcel parcel, Parcel parcel2, int i2) throws RemoteException {//Todo: throws is new 15 | if (i > 16777215) { 16 | return super.onTransact(i, parcel, parcel2, i2); 17 | } 18 | parcel.enforceInterface(getInterfaceDescriptor()); 19 | return false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/a/a.java: -------------------------------------------------------------------------------- 1 | package com.google.android.a; 2 | 3 | import android.os.IBinder; 4 | import android.os.IInterface; 5 | import android.os.Parcel; 6 | import android.os.RemoteException; 7 | 8 | public class a implements IInterface { 9 | private final String bHh; 10 | private final IBinder binder; 11 | 12 | protected a(IBinder iBinder, String str) { 13 | this.binder = iBinder; 14 | this.bHh = str; 15 | } 16 | 17 | public IBinder asBinder() { 18 | return this.binder; 19 | } 20 | 21 | protected final Parcel pg() { 22 | Parcel obtain = Parcel.obtain(); 23 | obtain.writeInterfaceToken(this.bHh); 24 | return obtain; 25 | } 26 | 27 | //Todo: different from source 28 | public final Parcel a(int i, Parcel parcel) { 29 | IBinder iBinder; 30 | Parcel obtain = Parcel.obtain(); 31 | try { 32 | iBinder = this.binder; 33 | iBinder.transact(i, parcel, obtain, 0); 34 | obtain.readException(); 35 | } catch (RuntimeException | RemoteException e) { 36 | parcel = null; 37 | //throw e; 38 | } finally { 39 | obtain.recycle(); 40 | } 41 | return parcel; 42 | } 43 | 44 | //Todo: different from source 45 | protected final void c(int i, Parcel parcel) { 46 | try { 47 | this.binder.transact(i, parcel, null, 1); 48 | } catch (RemoteException e) { 49 | e.printStackTrace(); 50 | } finally { 51 | parcel.recycle(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/a/c.java: -------------------------------------------------------------------------------- 1 | package com.google.android.a; 2 | 3 | import android.os.IInterface; 4 | import android.os.Parcel; 5 | import android.os.Parcelable; 6 | import android.os.Parcelable.Creator; 7 | import java.util.HashMap; 8 | 9 | public class c { 10 | private c() { 11 | } 12 | 13 | public static boolean a(Parcel parcel) { 14 | return parcel.readInt() == 1; 15 | } 16 | 17 | public static void a(Parcel parcel, boolean z) { 18 | parcel.writeInt(z ? 1 : 0); 19 | } 20 | 21 | public static Parcelable a(Parcel parcel, Creator creator) { 22 | if (parcel.readInt() == 0) { 23 | return null; 24 | } 25 | return (Parcelable) creator.createFromParcel(parcel); 26 | } 27 | 28 | public static void a(Parcel parcel, Parcelable parcelable) { 29 | if (parcelable == null) { 30 | parcel.writeInt(0); 31 | return; 32 | } 33 | parcel.writeInt(1); 34 | parcelable.writeToParcel(parcel, 0); 35 | } 36 | 37 | public static void a(Parcel parcel, IInterface iInterface) { 38 | if (iInterface == null) { 39 | parcel.writeStrongBinder(null); 40 | } else { 41 | parcel.writeStrongBinder(iInterface.asBinder()); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/apps/gsa/nowoverlayservice/ConfigurationOverlayController.kt: -------------------------------------------------------------------------------- 1 | package com.google.android.apps.gsa.nowoverlayservice 2 | 3 | import android.app.Service 4 | import android.content.Context 5 | import android.content.res.Configuration 6 | 7 | import com.google.android.libraries.gsa.d.a.OverlayController 8 | import com.google.android.libraries.gsa.d.a.OverlaysController 9 | import com.google.android.libraries.gsa.d.a.v 10 | 11 | import ua.itaysonlab.homefeeder.overlay.OverlayKt 12 | 13 | class ConfigurationOverlayController(private val service: Service) : OverlaysController(service) { 14 | override fun Hx() = 24 15 | 16 | override fun createController( 17 | configuration: Configuration?, 18 | i: Int, 19 | i2: Int 20 | ): OverlayController = OverlayKt(if (configuration != null) service.createConfigurationContext(configuration) else service) 21 | 22 | override fun HA() = v() 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/BaseCallback.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.os.Handler.Callback; 4 | import android.os.Message; 5 | import java.io.PrintWriter; 6 | 7 | class BaseCallback implements Callback { 8 | 9 | BaseCallback() { 10 | } 11 | 12 | public boolean handleMessage(Message message) { 13 | return true; 14 | } 15 | 16 | public void dump(PrintWriter printWriter, String str) { 17 | printWriter.println(String.valueOf(str).concat("BaseCallback: nothing to dump")); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/ByteBundleHolder.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.os.Bundle; 4 | 5 | final class ByteBundleHolder { 6 | 7 | private final Bundle extras; 8 | private final byte[] bytes; 9 | 10 | public ByteBundleHolder(byte[] bArr, Bundle bundle) { 11 | this.bytes = bArr; 12 | this.extras = bundle; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/DialogListeners.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.content.DialogInterface.OnDismissListener; 4 | import android.content.DialogInterface.OnShowListener; 5 | 6 | interface DialogListeners extends OnDismissListener, OnShowListener { 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/DialogOverlayController.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.os.Build.VERSION; 8 | import android.os.Bundle; 9 | import android.view.ActionMode; 10 | import android.view.ContextThemeWrapper; 11 | import android.view.KeyEvent; 12 | import android.view.Menu; 13 | import android.view.MenuItem; 14 | import android.view.MotionEvent; 15 | import android.view.SearchEvent; 16 | import android.view.View; 17 | import android.view.Window; 18 | import android.view.Window.Callback; 19 | import android.view.WindowManager; 20 | import android.view.WindowManager.LayoutParams; 21 | import android.view.accessibility.AccessibilityEvent; 22 | 23 | import java.util.HashSet; 24 | 25 | class DialogOverlayController extends ContextThemeWrapper implements Callback, DialogListeners { 26 | 27 | public WindowManager windowManager; 28 | public final Window window; 29 | private final HashSet dialogs = new HashSet<>(); 30 | public View windowView; 31 | 32 | DialogOverlayController(Context context, int theme, int dialogTheme) { 33 | super(context, theme); 34 | Dialog dialog = new Dialog(context, dialogTheme); 35 | this.window = dialog.getWindow(); 36 | this.window.setCallback(this); 37 | Window window = this.window; 38 | if (VERSION.SDK_INT >= 21) { 39 | //window.setStatusBarColor(0); 40 | //window.setNavigationBarColor(0); 41 | window.addFlags(Integer.MIN_VALUE); 42 | } else if (VERSION.SDK_INT >= 19) { 43 | window.addFlags(201326592); 44 | } 45 | } 46 | 47 | void onBackPressed() { 48 | } 49 | 50 | public boolean dispatchKeyEvent(KeyEvent keyEvent) { 51 | if (keyEvent.getKeyCode() != 4 || keyEvent.getAction() != 1 || keyEvent.isCanceled()) { 52 | return this.window.superDispatchKeyEvent(keyEvent); 53 | } 54 | onBackPressed(); 55 | return true; 56 | } 57 | 58 | public boolean dispatchKeyShortcutEvent(KeyEvent keyEvent) { 59 | return this.window.superDispatchKeyShortcutEvent(keyEvent); 60 | } 61 | 62 | public boolean dispatchTouchEvent(MotionEvent motionEvent) { 63 | return this.window.superDispatchTouchEvent(motionEvent); 64 | } 65 | 66 | public boolean dispatchTrackballEvent(MotionEvent motionEvent) { 67 | return this.window.superDispatchTrackballEvent(motionEvent); 68 | } 69 | 70 | public boolean dispatchGenericMotionEvent(MotionEvent motionEvent) { 71 | return this.window.superDispatchGenericMotionEvent(motionEvent); 72 | } 73 | 74 | public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 75 | return false; 76 | } 77 | 78 | public View onCreatePanelView(int i) { 79 | return null; 80 | } 81 | 82 | public boolean onCreatePanelMenu(int i, Menu menu) { 83 | return false; 84 | } 85 | 86 | public boolean onPreparePanel(int i, View view, Menu menu) { 87 | return true; 88 | } 89 | 90 | public boolean onMenuOpened(int i, Menu menu) { 91 | return true; 92 | } 93 | 94 | public boolean onMenuItemSelected(int i, MenuItem menuItem) { 95 | return false; 96 | } 97 | 98 | public void onWindowAttributesChanged(LayoutParams layoutParams) { 99 | if (this.windowView != null) { 100 | this.windowManager.updateViewLayout(this.windowView, layoutParams); 101 | } 102 | } 103 | 104 | public void onContentChanged() { 105 | } 106 | 107 | public void onWindowFocusChanged(boolean z) { 108 | } 109 | 110 | public void onAttachedToWindow() { 111 | } 112 | 113 | public void onDetachedFromWindow() { 114 | } 115 | 116 | public void onPanelClosed(int i, Menu menu) { 117 | } 118 | 119 | public boolean onSearchRequested() { 120 | return false; 121 | } 122 | 123 | public boolean onSearchRequested(SearchEvent searchEvent) { 124 | return false; 125 | } 126 | 127 | public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { 128 | return null; 129 | } 130 | 131 | public ActionMode onWindowStartingActionMode(ActionMode.Callback callback, int i) { 132 | return null; 133 | } 134 | 135 | public void onActionModeStarted(ActionMode actionMode) { 136 | } 137 | 138 | public void onActionModeFinished(ActionMode actionMode) { 139 | } 140 | 141 | public void startActivity(Intent intent) { 142 | super.startActivity(intent.addFlags(268435456)); 143 | } 144 | 145 | public void startActivity(Intent intent, Bundle bundle) { 146 | super.startActivity(intent.addFlags(268435456), bundle); 147 | } 148 | 149 | public void onShow(DialogInterface dialogInterface) { 150 | this.dialogs.add(dialogInterface); 151 | } 152 | 153 | public void onDismiss(DialogInterface dialogInterface) { 154 | this.dialogs.remove(dialogInterface); 155 | } 156 | 157 | final void cnB() { 158 | if (!this.dialogs.isEmpty()) { 159 | Dialog[] dialogArr = this.dialogs.toArray(new Dialog[this.dialogs.size()]); 160 | this.dialogs.clear(); 161 | for (Dialog dismiss : dialogArr) { 162 | dismiss.dismiss(); 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/MinusOneOverlayCallback.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.content.res.Configuration; 4 | import android.os.Message; 5 | 6 | import java.io.PrintWriter; 7 | 8 | public final class MinusOneOverlayCallback extends OverlayControllerCallback { 9 | 10 | private final OverlaysController overlaysController; 11 | 12 | public MinusOneOverlayCallback(OverlaysController overlaysControllerVar, OverlayControllerBinder overlayControllerBinderVar) { 13 | super(overlayControllerBinderVar, 3); 14 | this.overlaysController = overlaysControllerVar; 15 | } 16 | 17 | final OverlayController createController(Configuration configuration) { 18 | return this.overlaysController.createController(configuration, this.overlayControllerBinder.mServerVersion, this.overlayControllerBinder.mClientVersion); 19 | } 20 | 21 | public final void dump(PrintWriter printWriter, String str) { 22 | printWriter.println(String.valueOf(str).concat("MinusOneOverlayCallback")); 23 | super.dump(printWriter, str); 24 | } 25 | 26 | public final boolean handleMessage(Message message) { 27 | if (super.handleMessage(message)) { 28 | return true; 29 | } 30 | OverlayController overlayControllerVar; 31 | long when; 32 | switch (message.what) { 33 | case 3: 34 | if (this.overlayController != null) { 35 | overlayControllerVar = this.overlayController; 36 | when = message.getWhen(); 37 | if (!overlayControllerVar.cnD()) { 38 | SlidingPanelLayout slidingPanelLayoutVar = overlayControllerVar.slidingPanelLayout; 39 | if (slidingPanelLayoutVar.uoC < slidingPanelLayoutVar.mTouchSlop) { 40 | overlayControllerVar.slidingPanelLayout.BM(0); 41 | overlayControllerVar.mAcceptExternalMove = true; 42 | overlayControllerVar.unX = 0; 43 | overlayControllerVar.slidingPanelLayout.mForceDrag = true; 44 | overlayControllerVar.obZ = when - 30; 45 | overlayControllerVar.b(0, overlayControllerVar.unX, overlayControllerVar.obZ); 46 | overlayControllerVar.b(2, overlayControllerVar.unX, when); 47 | } 48 | } 49 | } 50 | return true; 51 | case 4: 52 | if (this.overlayController != null) { 53 | overlayControllerVar = this.overlayController; 54 | float floatValue = (float) message.obj; 55 | when = message.getWhen(); 56 | if (overlayControllerVar.mAcceptExternalMove) { 57 | overlayControllerVar.unX = (int) (floatValue * ((float) overlayControllerVar.slidingPanelLayout.getMeasuredWidth())); 58 | overlayControllerVar.b(2, overlayControllerVar.unX, when); 59 | } 60 | } 61 | return true; 62 | case 5: 63 | if (this.overlayController != null) { 64 | overlayControllerVar = this.overlayController; 65 | when = message.getWhen(); 66 | if (overlayControllerVar.mAcceptExternalMove) { 67 | overlayControllerVar.b(1, overlayControllerVar.unX, when); 68 | } 69 | overlayControllerVar.mAcceptExternalMove = false; 70 | } 71 | return true; 72 | default: 73 | return false; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/OverlayControllerLayoutChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.os.Build; 4 | import android.view.View; 5 | import android.view.View.OnLayoutChangeListener; 6 | import android.view.WindowManager.LayoutParams; 7 | 8 | final class OverlayControllerLayoutChangeListener implements OnLayoutChangeListener { 9 | 10 | private final OverlayController overlayController; 11 | 12 | OverlayControllerLayoutChangeListener(OverlayController overlayControllerVar) { 13 | this.overlayController = overlayControllerVar; 14 | } 15 | 16 | public final void onLayoutChange(View view, int i, int i2, int i3, int i4, int i5, int i6, int i7, int i8) { 17 | this.overlayController.window.getDecorView().removeOnLayoutChangeListener(this); 18 | if (this.overlayController.panelState == PanelState.CLOSED) {//Todo: PanelState.uoe was default 19 | OverlayController overlayControllerVar = this.overlayController; 20 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 21 | if (Build.VERSION.SDK_INT >= 26) { 22 | float f = attributes.alpha; 23 | attributes.alpha = 0.0f; 24 | if (f != attributes.alpha) { 25 | overlayControllerVar.window.setAttributes(attributes); 26 | return; 27 | } 28 | return; 29 | } 30 | attributes.x = overlayControllerVar.mWindowShift; 31 | attributes.flags |= 512; 32 | overlayControllerVar.unZ = false; 33 | overlayControllerVar.window.setAttributes(attributes); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/OverlayControllerSlidingPanelLayout.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.graphics.Rect; 4 | import android.view.MotionEvent; 5 | 6 | public final class OverlayControllerSlidingPanelLayout extends SlidingPanelLayout { 7 | 8 | private final OverlayController overlayController; 9 | 10 | public OverlayControllerSlidingPanelLayout(OverlayController overlayControllerVar) { 11 | super(overlayControllerVar); 12 | this.overlayController = overlayControllerVar; 13 | } 14 | 15 | protected final void determineScrollingStart(MotionEvent motionEvent, float f) { 16 | Object obj = 1; 17 | if (motionEvent.findPointerIndex(this.mActivePointerId) != -1) { 18 | float x = motionEvent.getX() - this.mDownX; 19 | float abs = Math.abs(x); 20 | float abs2 = Math.abs(motionEvent.getY() - this.mDownY); 21 | if (Float.compare(abs, 0.0f) != 0) { 22 | abs = (float) Math.atan((double) (abs2 / abs)); 23 | Object obj2; 24 | if (this.mIsRtl) { 25 | obj2 = x < 0.0f ? 1 : null; 26 | } else if (x > 0.0f) { 27 | obj2 = 1;//TODO: different from source 28 | } else { 29 | obj2 = null; 30 | } 31 | if (!this.mIsPanelOpen || this.mIsPageMoving) { 32 | obj = null; 33 | } 34 | if (obj != null && obj2 != null) {//TODO: different from source 35 | return; 36 | } 37 | if ((obj != null && this.uoH.cnI()) || abs > 1.0471976f) { 38 | return; 39 | } 40 | if (abs > 0.5235988f) { 41 | super.determineScrollingStart(motionEvent, (((float) Math.sqrt((double) ((abs - 0.5235988f) / 0.5235988f))) * 4.0f) + 1.0f); 42 | } else { 43 | super.determineScrollingStart(motionEvent, f); 44 | } 45 | } 46 | } 47 | } 48 | 49 | protected final boolean fitSystemWindows(Rect rect) { 50 | return !this.overlayController.unZ || super.fitSystemWindows(rect); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/OverlayControllerStateChanger.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.os.Build; 4 | import android.view.WindowManager.LayoutParams; 5 | 6 | final class OverlayControllerStateChanger implements t { 7 | 8 | private final OverlayController overlayController; 9 | 10 | OverlayControllerStateChanger(OverlayController overlayControllerVar) { 11 | this.overlayController = overlayControllerVar; 12 | } 13 | 14 | public final void drag() { 15 | OverlayController overlayControllerVar = this.overlayController; 16 | PanelState panelStateVar = PanelState.DRAGGING;//Todo: PanelState.uof was default 17 | if (overlayControllerVar.panelState != panelStateVar) { 18 | overlayControllerVar.panelState = panelStateVar; 19 | overlayControllerVar.setState(overlayControllerVar.panelState); 20 | } 21 | overlayControllerVar = this.overlayController; 22 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 23 | if (Build.VERSION.SDK_INT >= 26) { 24 | float f = attributes.alpha; 25 | attributes.alpha = 1.0f; 26 | if (f != attributes.alpha) { 27 | overlayControllerVar.window.setAttributes(attributes); 28 | return; 29 | } 30 | return; 31 | } 32 | attributes.x = 0; 33 | attributes.flags &= -513; 34 | overlayControllerVar.unZ = true; 35 | overlayControllerVar.window.setAttributes(attributes); 36 | } 37 | 38 | public final void cnF() { 39 | OverlayController overlayControllerVar = this.overlayController; 40 | PanelState panelStateVar = PanelState.DRAGGING;//Todo: PanelState.uof was default 41 | if (overlayControllerVar.panelState != panelStateVar) { 42 | overlayControllerVar.panelState = panelStateVar; 43 | overlayControllerVar.setState(overlayControllerVar.panelState); 44 | } 45 | this.overlayController.setVisible(true); 46 | overlayControllerVar = this.overlayController; 47 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 48 | if (Build.VERSION.SDK_INT >= 26) { 49 | float f = attributes.alpha; 50 | attributes.alpha = 1.0f; 51 | if (f != attributes.alpha) { 52 | overlayControllerVar.window.setAttributes(attributes); 53 | return; 54 | } 55 | return; 56 | } 57 | attributes.x = 0; 58 | attributes.flags &= -513; 59 | overlayControllerVar.unZ = true; 60 | overlayControllerVar.window.setAttributes(attributes); 61 | } 62 | 63 | public final void oc(boolean z) { 64 | if (z) { 65 | this.overlayController.Hn(); 66 | } 67 | OverlayController overlayControllerVar = this.overlayController; 68 | PanelState panelStateVar = PanelState.DRAGGING;//Todo: PanelState.uof was default 69 | if (overlayControllerVar.panelState != panelStateVar) { 70 | overlayControllerVar.panelState = panelStateVar; 71 | overlayControllerVar.setState(overlayControllerVar.panelState); 72 | } 73 | this.overlayController.setVisible(false); 74 | } 75 | 76 | public final void open() { 77 | OverlayController overlayControllerVar = this.overlayController; 78 | PanelState panelStateVar = PanelState.OPEN_AS_DRAWER;//Todo: PanelState.uog was default 79 | if (overlayControllerVar.panelState != panelStateVar) { 80 | overlayControllerVar.panelState = panelStateVar; 81 | overlayControllerVar.setState(overlayControllerVar.panelState); 82 | } 83 | } 84 | 85 | public final void D(float f) { 86 | if (this.overlayController.uoa != null && !Float.isNaN(f)) { 87 | try { 88 | this.overlayController.uoa.aK(f); 89 | this.overlayController.onScroll(f); 90 | } catch (Throwable ignored) { 91 | 92 | } 93 | } 94 | } 95 | 96 | public final void close() { 97 | OverlayController overlayControllerVar = this.overlayController; 98 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 99 | if (Build.VERSION.SDK_INT >= 26) { 100 | float f = attributes.alpha; 101 | attributes.alpha = 0.0f; 102 | if (f != attributes.alpha) { 103 | overlayControllerVar.window.setAttributes(attributes); 104 | } 105 | } else { 106 | attributes.x = overlayControllerVar.mWindowShift; 107 | attributes.flags |= 512; 108 | overlayControllerVar.unZ = false; 109 | overlayControllerVar.window.setAttributes(attributes); 110 | } 111 | overlayControllerVar = this.overlayController; 112 | PanelState panelStateVar = PanelState.CLOSED;//Todo: PanelState.uoe was default 113 | if (overlayControllerVar.panelState != panelStateVar) { 114 | overlayControllerVar.panelState = panelStateVar; 115 | overlayControllerVar.setState(overlayControllerVar.panelState); 116 | } 117 | } 118 | 119 | public final boolean cnI() { 120 | return this.overlayController.Ho(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/PanelState.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | public enum PanelState { 4 | CLOSED,//Todo: PanelState.uoe was default 5 | DRAGGING,//Todo: PanelState.uof was default 6 | OPEN_AS_DRAWER,//Todo: PanelState.uog was default 7 | OPEN_AS_LAYER//Todo: PanelState.uoh was default 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/SlidingPanelLayoutInterpolator.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.view.animation.Interpolator; 7 | 8 | final class SlidingPanelLayoutInterpolator extends AnimatorListenerAdapter implements Interpolator { 9 | 10 | private ObjectAnimator mAnimator; 11 | int mFinalX; 12 | private final SlidingPanelLayout slidingPanelLayout; 13 | 14 | public SlidingPanelLayoutInterpolator(SlidingPanelLayout slidingPanelLayoutVar) { 15 | this.slidingPanelLayout = slidingPanelLayoutVar; 16 | } 17 | 18 | public final void cnP() { 19 | if (this.mAnimator != null) { 20 | this.mAnimator.removeAllListeners(); 21 | this.mAnimator.cancel(); 22 | } 23 | } 24 | 25 | public final void dt(int i, int i2) { 26 | cnP(); 27 | this.mFinalX = i; 28 | if (i2 > 0) { 29 | this.mAnimator = ObjectAnimator.ofInt(this.slidingPanelLayout, SlidingPanelLayout.PANEL_X, i).setDuration((long) i2); 30 | this.mAnimator.setInterpolator(this); 31 | this.mAnimator.addListener(this); 32 | this.mAnimator.start(); 33 | return; 34 | } 35 | onAnimationEnd(null); 36 | } 37 | 38 | public final boolean isFinished() { 39 | return this.mAnimator == null; 40 | } 41 | 42 | public final void onAnimationEnd(Animator animator) { 43 | this.mAnimator = null; 44 | this.slidingPanelLayout.BM(this.mFinalX); 45 | SlidingPanelLayout slidingPanelLayoutVar = this.slidingPanelLayout; 46 | if (slidingPanelLayoutVar.mSettling) { 47 | slidingPanelLayoutVar.mSettling = false; 48 | if (slidingPanelLayoutVar.uoC == 0) { 49 | slidingPanelLayoutVar.cnO(); 50 | slidingPanelLayoutVar.mIsPanelOpen = false; 51 | slidingPanelLayoutVar.mIsPageMoving = false; 52 | if (slidingPanelLayoutVar.uoH != null) { 53 | slidingPanelLayoutVar.uoH.close(); 54 | } 55 | } else if (slidingPanelLayoutVar.uoC == slidingPanelLayoutVar.getMeasuredWidth()) { 56 | slidingPanelLayoutVar.cnG(); 57 | } 58 | } 59 | } 60 | 61 | public final float getInterpolation(float f) { 62 | float f2 = f - 1.0f; 63 | return (f2 * (((f2 * f2) * f2) * f2)) + 1.0f; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/SlidingPanelLayoutProperty.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.util.Property; 4 | 5 | final class SlidingPanelLayoutProperty extends Property { 6 | 7 | SlidingPanelLayoutProperty(Class cls, String str) { 8 | super(cls, str); 9 | } 10 | 11 | public final /* synthetic */ Object get(Object obj) { 12 | return ((SlidingPanelLayout) obj).uoC; 13 | } 14 | 15 | public final /* synthetic */ void set(Object obj, Object obj2) { 16 | ((SlidingPanelLayout) obj).BM((Integer) obj2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/TransparentOverlayController.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | import android.os.Build; 4 | import android.view.WindowManager.LayoutParams; 5 | 6 | final class TransparentOverlayController implements t { 7 | 8 | private final OverlayController overlayController; 9 | 10 | TransparentOverlayController(OverlayController overlayControllerVar) { 11 | this.overlayController = overlayControllerVar; 12 | } 13 | 14 | public final void drag() { 15 | 16 | } 17 | 18 | public final void cnF() { 19 | } 20 | 21 | public final void oc(boolean z) { 22 | } 23 | 24 | public final void open() { 25 | this.overlayController.setVisible(true); 26 | OverlayController overlayControllerVar = this.overlayController; 27 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 28 | if (Build.VERSION.SDK_INT >= 26) { 29 | float f = attributes.alpha; 30 | attributes.alpha = 1.0f; 31 | if (f != attributes.alpha) { 32 | overlayControllerVar.window.setAttributes(attributes); 33 | } 34 | } else { 35 | attributes.x = 0; 36 | attributes.flags &= -513; 37 | overlayControllerVar.unZ = true; 38 | overlayControllerVar.window.setAttributes(attributes); 39 | } 40 | overlayControllerVar = this.overlayController; 41 | PanelState panelStateVar = PanelState.OPEN_AS_LAYER;//Todo: PanelState.uoh was default 42 | if (overlayControllerVar.panelState != panelStateVar) { 43 | overlayControllerVar.panelState = panelStateVar; 44 | overlayControllerVar.setState(overlayControllerVar.panelState); 45 | } 46 | } 47 | 48 | public final void close() { 49 | OverlayController overlayControllerVar = this.overlayController; 50 | LayoutParams attributes = overlayControllerVar.window.getAttributes(); 51 | if (Build.VERSION.SDK_INT >= 26) { 52 | float f = attributes.alpha; 53 | attributes.alpha = 0.0f; 54 | if (f != attributes.alpha) { 55 | overlayControllerVar.window.setAttributes(attributes); 56 | } 57 | } else { 58 | attributes.x = overlayControllerVar.mWindowShift; 59 | attributes.flags |= 512; 60 | overlayControllerVar.unZ = false; 61 | overlayControllerVar.window.setAttributes(attributes); 62 | } 63 | this.overlayController.setVisible(false); 64 | overlayControllerVar = this.overlayController; 65 | PanelState panelStateVar = PanelState.CLOSED;//Todo: PanelState.uoe was default 66 | if (overlayControllerVar.panelState != panelStateVar) { 67 | overlayControllerVar.panelState = panelStateVar; 68 | overlayControllerVar.setState(overlayControllerVar.panelState); 69 | } 70 | this.overlayController.slidingPanelLayout.uoH = this.overlayController.overlayControllerStateChanger; 71 | } 72 | 73 | public final void D(float f) { 74 | } 75 | 76 | public final boolean cnI() { 77 | return true; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/t.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | interface t { 4 | void D(float f); 5 | 6 | void drag(); 7 | 8 | void cnF(); 9 | 10 | void open(); 11 | 12 | void close(); 13 | 14 | boolean cnI(); 15 | 16 | void oc(boolean z); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/gsa/d/a/v.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.gsa.d.a; 2 | 3 | public class v { 4 | public String HB() { 5 | return null; 6 | } 7 | 8 | public boolean HC() { 9 | return false; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/i/LauncherOverlayInterfaceBinder.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.i; 2 | 3 | import android.os.Bundle; 4 | import android.os.IBinder; 5 | import android.os.IInterface; 6 | import android.os.Parcel; 7 | import android.os.RemoteException; 8 | import android.view.WindowManager.LayoutParams; 9 | 10 | import com.google.android.a.LauncherOverlayBinder; 11 | import com.google.android.a.c; 12 | //import com.google.android.gms.dynamite.descriptors.com.google.android.gms.ads.dynamite.ModuleDescriptor; 13 | 14 | 15 | public abstract class LauncherOverlayInterfaceBinder extends LauncherOverlayBinder implements a { 16 | 17 | protected LauncherOverlayInterfaceBinder() { 18 | attachInterface(this, "com.google.android.libraries.launcherclient.ILauncherOverlay"); 19 | } 20 | 21 | public boolean onTransact(int i, Parcel parcel, Parcel parcel2, int i2) throws RemoteException {//Todo: throws is new 22 | d dVar = null; 23 | if (a(i, parcel, parcel2, i2)) { 24 | return true; 25 | } 26 | IBinder readStrongBinder; 27 | IInterface queryLocalInterface; 28 | boolean HC; 29 | switch (i) { 30 | case 1: 31 | cnK(); 32 | break; 33 | case 2: 34 | aL(parcel.readFloat()); 35 | break; 36 | case 3: 37 | cnL(); 38 | break; 39 | case 4: 40 | LayoutParams layoutParams = (LayoutParams) c.a(parcel, LayoutParams.CREATOR); 41 | readStrongBinder = parcel.readStrongBinder(); 42 | if (readStrongBinder != null) { 43 | queryLocalInterface = readStrongBinder.queryLocalInterface("com.google.android.libraries.launcherclient.ILauncherOverlayCallback"); 44 | if (queryLocalInterface instanceof d) { 45 | dVar = (d) queryLocalInterface; 46 | } else { 47 | dVar = new f(readStrongBinder); 48 | } 49 | } 50 | a(layoutParams, dVar, parcel.readInt()); 51 | break; 52 | case 5: 53 | od(c.a(parcel)); 54 | break; 55 | case 6: 56 | fI(parcel.readInt()); 57 | break; 58 | case 7: 59 | onPause(); 60 | break; 61 | case 8: 62 | onResume(); 63 | break; 64 | case 9: 65 | BK(parcel.readInt()); 66 | break; 67 | case 10: 68 | oe(c.a(parcel)); 69 | break; 70 | case 11: 71 | String HB = HB(); 72 | parcel2.writeNoException(); 73 | parcel2.writeString(HB); 74 | break; 75 | case /*ModuleDescriptor.MODULE_VERSION*/12 /*12*/://Todo: modified, 12 was always there but the constant was there before 76 | HC = HC(); 77 | parcel2.writeNoException(); 78 | c.a(parcel2, HC); 79 | break; 80 | case 13: 81 | parcel2.writeNoException(); 82 | c.a(parcel2, true); 83 | break; 84 | case 14: 85 | Bundle bundle = (Bundle) c.a(parcel, Bundle.CREATOR); 86 | readStrongBinder = parcel.readStrongBinder(); 87 | if (readStrongBinder != null) { 88 | queryLocalInterface = readStrongBinder.queryLocalInterface("com.google.android.libraries.launcherclient.ILauncherOverlayCallback"); 89 | if (queryLocalInterface instanceof d) { 90 | dVar = (d) queryLocalInterface; 91 | } else { 92 | dVar = new f(readStrongBinder); 93 | } 94 | } 95 | a(bundle, dVar); 96 | break; 97 | case 16: 98 | BJ(parcel.readInt()); 99 | break; 100 | case 17: 101 | HC = a(parcel.createByteArray(), (Bundle) c.a(parcel, Bundle.CREATOR)); 102 | parcel2.writeNoException(); 103 | c.a(parcel2, HC); 104 | break; 105 | default: 106 | return false; 107 | } 108 | return true; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/i/a.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.i; 2 | 3 | import android.os.Bundle; 4 | import android.os.IInterface; 5 | import android.view.WindowManager.LayoutParams; 6 | 7 | public interface a extends IInterface { 8 | void BJ(int i); 9 | 10 | void BK(int i); 11 | 12 | String HB(); 13 | 14 | boolean HC(); 15 | 16 | void a(Bundle bundle, d dVar); 17 | 18 | void a(LayoutParams layoutParams, d dVar, int i); 19 | 20 | boolean a(byte[] bArr, Bundle bundle); 21 | 22 | void aL(float f); 23 | 24 | void cnK(); 25 | 26 | void cnL(); 27 | 28 | void fI(int i); 29 | 30 | void od(boolean z); 31 | 32 | void oe(boolean z); 33 | 34 | void onPause(); 35 | 36 | void onResume(); 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/i/d.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.i; 2 | 3 | import android.os.IInterface; 4 | 5 | public interface d extends IInterface { 6 | void BI(int i); 7 | 8 | void aK(float f); 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/google/android/libraries/i/f.java: -------------------------------------------------------------------------------- 1 | package com.google.android.libraries.i; 2 | 3 | import android.os.IBinder; 4 | import android.os.Parcel; 5 | import com.google.android.a.a; 6 | 7 | public final class f extends a implements d { 8 | 9 | f(IBinder iBinder) { 10 | super(iBinder, "com.google.android.libraries.launcherclient.ILauncherOverlayCallback"); 11 | } 12 | 13 | public final void aK(float f) { 14 | Parcel pg = pg(); 15 | pg.writeFloat(f); 16 | c(1, pg); 17 | } 18 | 19 | public final void BI(int i) { 20 | Parcel pg = pg(); 21 | pg.writeInt(i); 22 | c(2, pg); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/HFApplication.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder 2 | 3 | import android.app.Application 4 | import android.app.Notification 5 | import ua.itaysonlab.homefeeder.utils.Logger 6 | import android.content.pm.PackageManager 7 | import android.graphics.drawable.BitmapDrawable 8 | import android.graphics.drawable.Drawable 9 | import android.os.Build 10 | import androidx.core.graphics.drawable.toDrawable 11 | import ua.itaysonlab.homefeeder.pluginsystem.PluginFetcher 12 | import ua.itaysonlab.homefeeder.utils.OverlayBridge 13 | 14 | class HFApplication: Application() { 15 | companion object { 16 | const val ACTION_MANAGE_LISTENERS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS" 17 | 18 | lateinit var instance: HFApplication 19 | val bridge = OverlayBridge() 20 | 21 | fun getAppNameByPkg(pkg: String): CharSequence { 22 | val ai = try { 23 | instance.packageManager.getApplicationInfo(pkg, 0) 24 | } catch (e: PackageManager.NameNotFoundException) { 25 | null 26 | } 27 | return if (ai != null) instance.packageManager.getApplicationLabel(ai) else "Unknown" 28 | } 29 | 30 | fun getSmallIcon(notification: Notification, pkg: String): Drawable { 31 | return try { 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 33 | notification.smallIcon.loadDrawable(instance) 34 | } else { 35 | instance.packageManager.getResourcesForApplication(pkg).getDrawable(notification.icon, null) 36 | } 37 | } catch (e: Exception) { 38 | instance.packageManager.getApplicationIcon(pkg) 39 | } 40 | } 41 | 42 | fun getSmallIcon(pkg: String): Drawable { 43 | return instance.packageManager.getApplicationIcon(pkg) 44 | } 45 | 46 | fun getLargeIcon(notification: Notification): BitmapDrawable? { 47 | return try { 48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 49 | notification.getLargeIcon().loadDrawable(instance) as? BitmapDrawable 50 | } else { 51 | notification.largeIcon.toDrawable(instance.resources) 52 | } 53 | } catch (e: Exception) { 54 | null 55 | } 56 | } 57 | } 58 | 59 | override fun onCreate() { 60 | super.onCreate() 61 | Logger.log("Application", "Starting HomeFeeder ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})...") 62 | instance = this 63 | PluginFetcher.init(instance) 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/activites/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.activites 2 | 3 | import android.Manifest 4 | import android.content.pm.PackageManager 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.core.app.ActivityCompat 8 | import androidx.core.content.ContextCompat 9 | import androidx.navigation.findNavController 10 | import androidx.navigation.ui.AppBarConfiguration 11 | import androidx.navigation.ui.setupActionBarWithNavController 12 | import androidx.navigation.ui.setupWithNavController 13 | import com.google.android.material.bottomnavigation.BottomNavigationView 14 | import com.google.android.material.dialog.MaterialAlertDialogBuilder 15 | import ua.itaysonlab.homefeeder.R 16 | 17 | class MainActivity : AppCompatActivity() { 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_main) 21 | setSupportActionBar(findViewById(R.id.toolbar)) 22 | val navView: BottomNavigationView = findViewById(R.id.nav_view) 23 | 24 | val navController = findNavController(R.id.nav_host_fragment) 25 | val appBarConfiguration = AppBarConfiguration( 26 | setOf( 27 | R.id.navigation_plugins, R.id.navigation_settings, R.id.navigation_about 28 | ) 29 | ) 30 | 31 | setupActionBarWithNavController(navController, appBarConfiguration) 32 | navView.setupWithNavController(navController) 33 | 34 | checkStoragePermission() 35 | } 36 | 37 | private fun checkStoragePermission() { 38 | if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 39 | showStorageAlert() 40 | } 41 | } 42 | 43 | override fun onRequestPermissionsResult( 44 | requestCode: Int, 45 | permissions: Array, 46 | grantResults: IntArray 47 | ) { 48 | super.onRequestPermissionsResult(requestCode, permissions, grantResults) 49 | if (requestCode == 1) { 50 | if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 51 | findNavController(R.id.nav_host_fragment).navigate(R.id.navigation_settings) 52 | } else { 53 | showStorageAlert() 54 | } 55 | } 56 | } 57 | 58 | private fun showStorageAlert() { 59 | MaterialAlertDialogBuilder(this).apply { 60 | setTitle(R.string.storage_alert) 61 | setMessage(R.string.storage_desc) 62 | setPositiveButton(R.string.storage_action) { _, _ -> 63 | ActivityCompat.requestPermissions(this@MainActivity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 1) 64 | } 65 | setNeutralButton(R.string.cancel, null) 66 | }.show() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/fragments/AboutFragment.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.fragments 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Bundle 7 | import androidx.preference.Preference 8 | import ua.itaysonlab.homefeeder.BuildConfig 9 | import ua.itaysonlab.homefeeder.R 10 | import ua.itaysonlab.homefeeder.fragments.base.FixedPreferencesFragment 11 | 12 | class AboutFragment : FixedPreferencesFragment() { 13 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 14 | setPreferencesFromResource(R.xml.pref_about, rootKey) 15 | 16 | findPreference("about_app")!!.summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" 17 | 18 | val tg = findPreference("about_tg")!! 19 | val tgdev = findPreference("about_tg_dev")!! 20 | val git = findPreference("about_source")!! 21 | 22 | tg.summary = "@homefeeder" 23 | tg.setOnPreferenceClickListener { 24 | openLink(requireActivity(), "https://t.me/homefeeder") 25 | true 26 | } 27 | tgdev.summary = "@itaysonlab" 28 | tgdev.setOnPreferenceClickListener { 29 | openLink(requireActivity(), "https://t.me/itaysonlab") 30 | true 31 | } 32 | git.setOnPreferenceClickListener { 33 | openLink(requireActivity(), "https://github.com/iTaysonLab/HomeFeeder/") 34 | true 35 | } 36 | } 37 | 38 | private fun openLink(context: Context, url: String) { 39 | context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url))) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/fragments/PreferenceFragment.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.fragments 2 | 3 | import android.os.Build 4 | import android.os.Bundle 5 | import android.widget.Toast 6 | import androidx.preference.* 7 | import ua.itaysonlab.homefeeder.BuildConfig 8 | import ua.itaysonlab.homefeeder.HFApplication 9 | import ua.itaysonlab.homefeeder.R 10 | import ua.itaysonlab.homefeeder.activites.MainActivity 11 | import ua.itaysonlab.homefeeder.fragments.base.FixedPreferencesFragment 12 | import ua.itaysonlab.homefeeder.prefui.HFElementPreview 13 | 14 | class PreferenceFragment : FixedPreferencesFragment() { 15 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 16 | setPreferencesFromResource(R.xml.pref_general, rootKey) 17 | 18 | bindAppearance() 19 | if (BuildConfig.DEBUG) bindDebug() 20 | } 21 | 22 | private fun bindAppearance() { 23 | val summaryProviderInstance = ListPreference.SimpleSummaryProvider.getInstance() 24 | 25 | val theme = findPreference("ovr_theme")!! 26 | val transparency = findPreference("ovr_transparency")!! 27 | val overlayBackground = findPreference("ovr_bg")!! 28 | val cardBackground = findPreference("ovr_card_bg")!! 29 | 30 | val compact = findPreference("ovr_compact")!! 31 | val sysColors = findPreference("ovr_syscolors")!! 32 | 33 | val preview = findPreference("preview")!! 34 | 35 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) { 36 | sysColors.apply { 37 | isEnabled = false 38 | setSummary(R.string.pref_syscolors_disabled) 39 | } 40 | } 41 | 42 | theme.summaryProvider = summaryProviderInstance 43 | transparency.summaryProvider = summaryProviderInstance 44 | cardBackground.summaryProvider = summaryProviderInstance 45 | overlayBackground.summaryProvider = summaryProviderInstance 46 | 47 | theme.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 48 | preview.applyNewTheme(newValue as String) 49 | HFApplication.bridge.getCallback()?.applyNewTheme(newValue) 50 | true 51 | } 52 | 53 | transparency.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 54 | preview.applyNewTransparency(newValue as String) 55 | HFApplication.bridge.getCallback()?.applyNewTransparency(newValue) 56 | true 57 | } 58 | 59 | compact.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 60 | preview.applyCompact(newValue as Boolean) 61 | HFApplication.bridge.getCallback()?.applyCompactCard(newValue) 62 | true 63 | } 64 | 65 | sysColors.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 66 | HFApplication.bridge.getCallback()?.applySysColors(newValue as Boolean) 67 | true 68 | } 69 | 70 | overlayBackground.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 71 | preview.applyNewOverlayBg(newValue as String) 72 | HFApplication.bridge.getCallback()?.applyNewOverlayBg(newValue) 73 | true 74 | } 75 | 76 | cardBackground.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> 77 | preview.applyNewCardBg(newValue as String) 78 | HFApplication.bridge.getCallback()?.applyNewCardBg(newValue) 79 | true 80 | } 81 | } 82 | 83 | private fun bindDebug() { 84 | val debugCategory = PreferenceCategory(preferenceManager.context).apply { 85 | title = "Debug" 86 | isIconSpaceReserved = false 87 | } 88 | val loggingSwitch = SwitchPreference(preferenceManager.context).apply { 89 | key = "HFDebugging" 90 | title = "Extensive logcat printing" 91 | setDefaultValue(false) 92 | isIconSpaceReserved = false 93 | } 94 | val contentLoggingSwitch = SwitchPreference(preferenceManager.context).apply { 95 | key = "HFContentDebugging" 96 | title = "Log notification content" 97 | setDefaultValue(false) 98 | isIconSpaceReserved = false 99 | } 100 | val sendToBridge = Preference(preferenceManager.context).apply { 101 | key = "HFBridgeTest" 102 | title = "Test OverlayBridge" 103 | summary = "Send message \"uiBridgeTest\" to Overlay" 104 | isIconSpaceReserved = false 105 | } 106 | sendToBridge.setOnPreferenceClickListener { 107 | if (HFApplication.bridge.isBridgeAlive()) { 108 | HFApplication.bridge.callServer("uiBridgeTest") 109 | } else { 110 | Toast.makeText(activity, "Bridge is not connected!", Toast.LENGTH_LONG).show() 111 | } 112 | true 113 | } 114 | preferenceScreen.addPreference(debugCategory) 115 | debugCategory.addPreference(loggingSwitch) 116 | debugCategory.addPreference(contentLoggingSwitch) 117 | debugCategory.addPreference(sendToBridge) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/fragments/base/FixedPreferencesFragment.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.fragments.base 2 | 3 | import android.view.MenuItem 4 | import androidx.preference.* 5 | 6 | abstract class FixedPreferencesFragment : PreferenceFragmentCompat() { 7 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 8 | if (item.itemId == android.R.id.home) { 9 | activity!!.onBackPressed() 10 | return true 11 | } 12 | return super.onOptionsItemSelected(item) 13 | } 14 | 15 | override fun setPreferenceScreen(preferenceScreen: PreferenceScreen?) { 16 | super.setPreferenceScreen(preferenceScreen) 17 | if (preferenceScreen != null) { 18 | val count = preferenceScreen.preferenceCount 19 | for (i in 0 until count) { 20 | val pref = preferenceScreen.getPreference(i)!! 21 | pref.isIconSpaceReserved = false 22 | if (pref is PreferenceCategory) { 23 | val pcount = pref.preferenceCount 24 | for (pi in 0 until pcount) { 25 | pref.getPreference(pi).isIconSpaceReserved = false 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/kt/KtExtensions.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.kt 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.os.Build 6 | import android.os.Bundle 7 | import android.provider.Settings 8 | import android.view.View 9 | import androidx.annotation.ColorInt 10 | import androidx.core.graphics.ColorUtils 11 | import ua.itaysonlab.homefeeder.utils.Logger 12 | 13 | const val LIGHT_BORDER = 0.5f 14 | 15 | fun Int.isLight() = ColorUtils.calculateLuminance(this) > LIGHT_BORDER 16 | fun Int.isDark() = ColorUtils.calculateLuminance(this) < LIGHT_BORDER 17 | 18 | fun Bundle.dump(tag: String) { 19 | keySet().forEach { 20 | val item = get(it) 21 | item ?: return@forEach 22 | Logger.log(tag, "[$it] $item") 23 | } 24 | } 25 | 26 | fun View.setLightFlags() { 27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 28 | var flags = systemUiVisibility 29 | flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 30 | systemUiVisibility = flags 31 | } 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 33 | var flags = systemUiVisibility 34 | flags = flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR 35 | systemUiVisibility = flags 36 | } 37 | } 38 | 39 | fun View.clearLightFlags() { 40 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 41 | var flags = systemUiVisibility 42 | flags = flags xor View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 43 | systemUiVisibility = flags 44 | } 45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 46 | var flags = systemUiVisibility 47 | flags = flags xor View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR 48 | systemUiVisibility = flags 49 | } 50 | } 51 | 52 | @ColorInt 53 | fun Color?.toInt(): Int { 54 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return Color.BLACK 55 | this ?: Color.BLACK 56 | return Color.rgb(this!!.red(), this.green(), this.blue()) 57 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/DrawerOverlayService.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay 2 | 3 | import android.app.Service 4 | import android.content.Intent 5 | import android.os.IBinder 6 | 7 | import com.google.android.apps.gsa.nowoverlayservice.ConfigurationOverlayController 8 | import com.google.android.libraries.gsa.d.a.OverlaysController 9 | 10 | import java.io.FileDescriptor 11 | import java.io.PrintWriter 12 | 13 | class DrawerOverlayService : Service() { 14 | private lateinit var overlaysController: OverlaysController 15 | 16 | override fun onCreate() { 17 | super.onCreate() 18 | this.overlaysController = ConfigurationOverlayController(this) 19 | } 20 | 21 | override fun onDestroy() { 22 | this.overlaysController.onDestroy() 23 | super.onDestroy() 24 | } 25 | 26 | override fun onBind(intent: Intent): IBinder? = this.overlaysController.onBind(intent) 27 | 28 | override fun onUnbind(intent: Intent): Boolean { 29 | this.overlaysController.unUnbind(intent) 30 | return false 31 | } 32 | 33 | /*override fun dump( 34 | fileDescriptor: FileDescriptor, 35 | printWriter: PrintWriter, 36 | strArr: Array 37 | ) { 38 | //this.overlaysController.dump(printWriter) 39 | }*/ 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/feed/FeedAdapter.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.feed 2 | 3 | import android.util.SparseIntArray 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.recyclerview.widget.RecyclerView 8 | import ua.itaysonlab.hfsdk.FeedItem 9 | import ua.itaysonlab.hfsdk.FeedItemType 10 | import ua.itaysonlab.homefeeder.R 11 | import ua.itaysonlab.homefeeder.overlay.feed.binders.StoryCardBinder 12 | import ua.itaysonlab.homefeeder.overlay.feed.binders.TextCardBinder 13 | import ua.itaysonlab.homefeeder.overlay.feed.binders.TextCardWithActionsBinder 14 | import ua.itaysonlab.homefeeder.utils.Logger 15 | 16 | class FeedAdapter: RecyclerView.Adapter() { 17 | private var list = listOf() 18 | private lateinit var layoutInflater: LayoutInflater 19 | private var theme: SparseIntArray? = null 20 | 21 | fun replace(new: List) { 22 | list = new 23 | notifyDataSetChanged() 24 | } 25 | 26 | fun append(new: List) { 27 | list = mutableListOf().apply { 28 | addAll(list) 29 | addAll(new) 30 | } 31 | 32 | notifyDataSetChanged() 33 | } 34 | 35 | fun setTheme(theme: SparseIntArray) { 36 | this.theme = theme 37 | notifyDataSetChanged() 38 | } 39 | 40 | override fun getItemCount(): Int { 41 | return list.size 42 | } 43 | 44 | override fun getItemViewType(position: Int): Int { 45 | return (list[position].type.ordinal) 46 | } 47 | 48 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeedViewHolder { 49 | if (!::layoutInflater.isInitialized) layoutInflater = LayoutInflater.from(parent.context) 50 | 51 | val layoutResource = when (FeedItemType.values()[viewType]) { 52 | FeedItemType.TEXT_CARD -> R.layout.notification_simple 53 | FeedItemType.TEXT_CARD_ACTIONS -> R.layout.feed_card_text 54 | FeedItemType.STORY_CARD -> R.layout.feed_card_story_large 55 | } 56 | 57 | return FeedViewHolder(viewType, layoutInflater.inflate(layoutResource, parent, false)) 58 | } 59 | 60 | override fun onBindViewHolder(holder: FeedViewHolder, position: Int) { 61 | val item = list[position] 62 | when (FeedItemType.values()[holder.type]) { 63 | FeedItemType.TEXT_CARD -> TextCardBinder.bind(theme, item, holder.itemView) 64 | FeedItemType.TEXT_CARD_ACTIONS -> TextCardWithActionsBinder.bind(theme, item, holder.itemView) 65 | FeedItemType.STORY_CARD -> StoryCardBinder.bind(theme, item, holder.itemView) 66 | } 67 | } 68 | 69 | inner class FeedViewHolder(val type: Int, itemView: View): RecyclerView.ViewHolder(itemView) 70 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/feed/binders/FeedBinder.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.feed.binders 2 | 3 | import android.util.SparseIntArray 4 | import android.view.View 5 | import ua.itaysonlab.hfsdk.FeedItem 6 | 7 | interface FeedBinder { 8 | fun bind(theme: SparseIntArray?, item: FeedItem, view: View) 9 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/feed/binders/StoryCardBinder.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.feed.binders 2 | 3 | import android.content.Intent 4 | import android.net.Uri 5 | import android.text.Html 6 | import android.util.SparseIntArray 7 | import android.view.View 8 | import coil.load 9 | import ua.itaysonlab.hfsdk.FeedItem 10 | import ua.itaysonlab.hfsdk.content.StoryCardContent 11 | import ua.itaysonlab.homefeeder.databinding.FeedCardStoryLargeBinding 12 | import ua.itaysonlab.homefeeder.kt.isDark 13 | import ua.itaysonlab.homefeeder.theming.Theming 14 | 15 | object StoryCardBinder: FeedBinder { 16 | override fun bind(theme: SparseIntArray?, item: FeedItem, view: View) { 17 | val content = item.content as StoryCardContent 18 | val binding = FeedCardStoryLargeBinding.bind(view) 19 | 20 | binding.storyTitle.text = content.title 21 | binding.storySource.text = content.source.title 22 | 23 | if (content.text.isEmpty()) { 24 | binding.storyDesc.visibility = View.GONE 25 | } else { 26 | binding.storyDesc.text = Html.fromHtml(content.text).toString() 27 | } 28 | 29 | binding.storyPic.load(content.background_url) 30 | 31 | theme ?: return 32 | binding.storyDimmer.setBackgroundColor(theme.get(Theming.Colors.CARD_BG.ordinal)) 33 | val themeCard = if (theme.get(Theming.Colors.CARD_BG.ordinal).isDark()) Theming.defaultDarkThemeColors else Theming.defaultLightThemeColors 34 | binding.storyTitle.setTextColor(themeCard.get(Theming.Colors.TEXT_COLOR_PRIMARY.ordinal)) 35 | binding.storySource.setTextColor(themeCard.get(Theming.Colors.TEXT_COLOR_SECONDARY.ordinal)) 36 | binding.storyDesc.setTextColor(themeCard.get(Theming.Colors.TEXT_COLOR_SECONDARY.ordinal)) 37 | 38 | binding.root.setOnClickListener { 39 | view.context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(content.link))) 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/feed/binders/TextCardBinder.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.feed.binders 2 | 3 | import android.util.SparseIntArray 4 | import android.view.View 5 | import ua.itaysonlab.hfsdk.FeedItem 6 | import ua.itaysonlab.hfsdk.content.TextCardContent 7 | import ua.itaysonlab.homefeeder.HFApplication 8 | import ua.itaysonlab.homefeeder.databinding.NotificationGenericContentBinding 9 | import ua.itaysonlab.homefeeder.utils.RelativeTimeHelper 10 | 11 | object TextCardBinder: FeedBinder { 12 | override fun bind(theme: SparseIntArray?, item: FeedItem, view: View) { 13 | val content = item.content as TextCardContent 14 | val binding = NotificationGenericContentBinding.bind(view) 15 | 16 | binding.notTitle.text = content.title 17 | binding.notTitle.visibility = if (content.title.isEmpty()) { 18 | View.GONE 19 | } else View.VISIBLE 20 | 21 | binding.notText.text = content.text 22 | binding.notText.visibility = if (content.text.isEmpty()) { 23 | View.GONE 24 | } else View.VISIBLE 25 | 26 | binding.notAppSubtitle.text = content.subtitle 27 | binding.notAppSubtitle.visibility = if (content.subtitle == null) { 28 | View.GONE 29 | } else View.VISIBLE 30 | 31 | binding.notAppName.text = item.title 32 | binding.notAppIcon.visibility = View.GONE 33 | binding.notAppDate.text = RelativeTimeHelper.getDateFormattedRelative(HFApplication.instance, (item.time/1000) - 1000) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/feed/binders/TextCardWithActionsBinder.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.feed.binders 2 | 3 | import android.util.SparseIntArray 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import ua.itaysonlab.hfsdk.FeedItem 9 | import ua.itaysonlab.hfsdk.content.TextCardContent 10 | import ua.itaysonlab.homefeeder.R 11 | 12 | object TextCardWithActionsBinder: FeedBinder { 13 | override fun bind(theme: SparseIntArray?, item: FeedItem, view: View) { 14 | TextCardBinder.bind(theme, item, view) 15 | val valley = view.findViewById(R.id.button_valley_2) 16 | valley.removeAllViews() 17 | (item.content as TextCardContent).actions?.forEach { 18 | valley.addView(LayoutInflater.from(view.context).inflate(R.layout.feed_card_action, view as ViewGroup, false).apply { 19 | (this as TextView).text = it.title 20 | }) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/launcherapi/LauncherAPI.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.launcherapi 2 | 3 | import android.graphics.Color 4 | import android.os.Bundle 5 | import androidx.annotation.ColorInt 6 | import ua.itaysonlab.homefeeder.kt.dump 7 | import ua.itaysonlab.homefeeder.preferences.HFPreferences 8 | 9 | /** 10 | * A class which parses data from launcher's options [android.os.Bundle]. 11 | * */ 12 | class LauncherAPI(bundle: Bundle = Bundle()) { 13 | companion object { 14 | const val LOG_TAG = "LauncherAPI" 15 | 16 | const val DARK_THEME_KEY = "is_background_dark" 17 | const val BG_HINT_KEY = "background_color_hint" 18 | const val BG_SECONDARY_HINT_KEY = "background_secondary_color_hint" 19 | const val BG_TERTIARY_HINT_KEY = "background_tertiary_color_hint" 20 | } 21 | 22 | /** 23 | * If the wallpaper is dark enough. 24 | * Available on almost every launcher 25 | */ 26 | var darkTheme = false 27 | 28 | /** 29 | * Primary wallpaper color. 30 | * Seems like it's available only on Lawnchair. 31 | * On Shade, it returns applied theme color. 32 | */ 33 | @ColorInt 34 | var backgroundColorHint = Color.BLACK 35 | 36 | /** 37 | * Secondary wallpaper color. 38 | * Only on Lawnchair (and Librechair too). 39 | */ 40 | @ColorInt 41 | var backgroundColorHintSecondary = Color.BLACK 42 | 43 | /** 44 | * Tertiary wallpaper color. 45 | * Available only on Librechair. 46 | */ 47 | @ColorInt 48 | var backgroundColorHintTertiary = Color.BLACK 49 | 50 | init { 51 | if (HFPreferences.contentDebugging) { 52 | bundle.dump(LOG_TAG) 53 | } 54 | 55 | darkTheme = bundle.getBoolean(DARK_THEME_KEY, true) 56 | backgroundColorHint = bundle.getInt(BG_HINT_KEY, Color.BLACK) 57 | backgroundColorHintSecondary = bundle.getInt(BG_SECONDARY_HINT_KEY, Color.BLACK) 58 | backgroundColorHintTertiary = bundle.getInt(BG_TERTIARY_HINT_KEY, Color.BLACK) 59 | } 60 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/overlay/launcherapi/OverlayThemeHolder.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.overlay.launcherapi 2 | 3 | import android.annotation.TargetApi 4 | import android.app.WallpaperManager 5 | import android.content.Context 6 | import android.graphics.Color 7 | import android.os.Build 8 | import android.util.SparseIntArray 9 | import androidx.annotation.ColorInt 10 | import androidx.core.content.ContextCompat 11 | import ua.itaysonlab.homefeeder.HFApplication 12 | import ua.itaysonlab.homefeeder.R 13 | import ua.itaysonlab.homefeeder.kt.clearLightFlags 14 | import ua.itaysonlab.homefeeder.kt.isLight 15 | import ua.itaysonlab.homefeeder.kt.toInt 16 | import ua.itaysonlab.homefeeder.overlay.OverlayKt 17 | import ua.itaysonlab.homefeeder.preferences.HFPreferences 18 | import ua.itaysonlab.homefeeder.theming.Theming 19 | import ua.itaysonlab.homefeeder.utils.Logger 20 | 21 | /** 22 | * A class which manages overlay styling. 23 | * */ 24 | class OverlayThemeHolder(private val context: Context, private val overlay: OverlayKt) { 25 | /** 26 | * Current theme colors mapping 27 | */ 28 | var currentTheme = Theming.defaultDarkThemeColors 29 | 30 | /** 31 | * Card background 32 | */ 33 | var cardBgPref = HFPreferences.cardBackground 34 | 35 | /** 36 | * Overlay background 37 | */ 38 | var overlayBgPref = HFPreferences.overlayBackground 39 | 40 | /** 41 | * Overlay transparency 42 | */ 43 | var transparencyBgPref = HFPreferences.overlayTransparency 44 | 45 | /** 46 | * If we should apply light statusbar/navbar 47 | */ 48 | var shouldUseSN = false 49 | 50 | /** 51 | * If we are applied light statusbar/navbar 52 | */ 53 | var isSNApplied = false 54 | 55 | /** 56 | * If we are using system colors instead of [LauncherAPI] 57 | */ 58 | var systemColors = false 59 | 60 | /** 61 | * Parses [cardBgPref] into color integer 62 | */ 63 | private val cardBackground: Int get() = when (cardBgPref) { 64 | "white" -> ContextCompat.getColor(context, R.color.card_bg) 65 | "dark" -> ContextCompat.getColor(context, R.color.card_bg_dark) 66 | "launcher_primary" -> if (HFPreferences.systemColors) primaryWallColor() else overlay.apiInstance.backgroundColorHint 67 | "launcher_secondary" -> if (HFPreferences.systemColors) secondaryWallColor() else overlay.apiInstance.backgroundColorHintSecondary 68 | "launcher_tertiary" -> if (HFPreferences.systemColors) tertiaryWallColor() else overlay.apiInstance.backgroundColorHintTertiary 69 | else -> Color.BLACK 70 | } 71 | 72 | /** 73 | * Parses [overlayBgPref] into color integer 74 | */ 75 | private val overlayBackground: Int get() = when (overlayBgPref) { 76 | "white" -> Color.WHITE 77 | "dark" -> ContextCompat.getColor(context, R.color.bg_dark) 78 | "launcher_primary" -> if (HFPreferences.systemColors) primaryWallColor() else overlay.apiInstance.backgroundColorHint 79 | "launcher_secondary" -> if (HFPreferences.systemColors) secondaryWallColor() else overlay.apiInstance.backgroundColorHintSecondary 80 | "launcher_tertiary" -> if (HFPreferences.systemColors) tertiaryWallColor() else overlay.apiInstance.backgroundColorHintTertiary 81 | else -> Color.BLACK 82 | } 83 | 84 | /** 85 | * If [transparencyBgPref] is fully transparent 86 | */ 87 | val isTransparentBg get() = transparencyBgPref == "transparent" 88 | 89 | /** 90 | * Parses scroll alpha to match theme 91 | */ 92 | fun getScrollAlpha(alpha: Float): Float { 93 | return if (transparencyBgPref == "half" && alpha > 0.5f) { 94 | 0.5f 95 | } else if (transparencyBgPref == "less_half" && alpha > 0.25f) { 96 | 0.25f 97 | } else if (transparencyBgPref == "more_half" && alpha > 0.75f) { 98 | 0.75f 99 | } else alpha 100 | } 101 | 102 | /** 103 | * Replaces the color mapping ([currentTheme]) with config-specified values 104 | */ 105 | fun setTheme(theme: SparseIntArray) { 106 | currentTheme = theme 107 | 108 | shouldUseSN = if (overlayBgPref != "theme") { 109 | currentTheme.put(Theming.Colors.OVERLAY_BG.ordinal, overlayBackground) 110 | overlayBackground.isLight() 111 | } else { 112 | currentTheme.get(Theming.Colors.IS_LIGHT.ordinal) == 1 113 | } 114 | 115 | if (!shouldUseSN && isSNApplied) { 116 | isSNApplied = false 117 | overlay.window.decorView.clearLightFlags() 118 | } 119 | 120 | if (cardBgPref != "theme") { 121 | currentTheme.put(Theming.Colors.CARD_BG.ordinal, cardBackground) 122 | } 123 | 124 | Logger.log("OTH", currentTheme.toString()) 125 | } 126 | 127 | companion object { 128 | @ColorInt 129 | @TargetApi(Build.VERSION_CODES.O_MR1) 130 | fun primaryWallColor(): Int { 131 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return Color.BLACK 132 | val wc = WallpaperManager.getInstance(HFApplication.instance).getWallpaperColors(WallpaperManager.FLAG_SYSTEM) 133 | wc ?: Color.BLACK 134 | return wc!!.primaryColor.toInt() 135 | } 136 | 137 | @ColorInt 138 | @TargetApi(Build.VERSION_CODES.O_MR1) 139 | fun secondaryWallColor(): Int { 140 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return Color.BLACK 141 | val wc = WallpaperManager.getInstance(HFApplication.instance).getWallpaperColors(WallpaperManager.FLAG_SYSTEM) 142 | wc ?: Color.BLACK 143 | return wc!!.secondaryColor.toInt() 144 | } 145 | 146 | @ColorInt 147 | @TargetApi(Build.VERSION_CODES.O_MR1) 148 | fun tertiaryWallColor(): Int { 149 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return Color.BLACK 150 | val wc = WallpaperManager.getInstance(HFApplication.instance).getWallpaperColors(WallpaperManager.FLAG_SYSTEM) 151 | wc ?: Color.BLACK 152 | wc?.tertiaryColor ?: Color.BLACK 153 | return wc!!.tertiaryColor.toInt() 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/pluginsystem/PluginConnector.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.pluginsystem 2 | 3 | import android.app.Service 4 | import android.content.ComponentName 5 | import android.content.Intent 6 | import android.content.ServiceConnection 7 | import android.os.Handler 8 | import android.os.IBinder 9 | import android.os.Looper 10 | import androidx.core.os.bundleOf 11 | import androidx.recyclerview.widget.RecyclerView 12 | import ua.itaysonlab.hfsdk.FeedCategory 13 | import ua.itaysonlab.hfsdk.FeedItem 14 | import ua.itaysonlab.hfsdk.IFeedInterface 15 | import ua.itaysonlab.hfsdk.IFeedInterfaceCallback 16 | import ua.itaysonlab.homefeeder.HFApplication 17 | import ua.itaysonlab.homefeeder.preferences.HFPluginPreferences 18 | import ua.itaysonlab.homefeeder.utils.Logger 19 | 20 | object PluginConnector { 21 | const val TAG = "PluginConnector" 22 | private var hasInitialized = false 23 | 24 | private var interfaces = hashMapOf() 25 | private var callbacks = hashMapOf() 26 | 27 | private var index = 0 28 | private var serviceSize = 0 29 | 30 | private val handler = Handler(Looper.getMainLooper()) 31 | 32 | private val serviceConnection: ServiceConnection = object : ServiceConnection { 33 | override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) { 34 | Logger.log(TAG, "Connected to service ${componentName.packageName} / ${componentName.className}") 35 | interfaces[componentName.packageName] = IFeedInterface.Stub.asInterface(iBinder) 36 | interfaces[componentName.packageName]!!.getFeed(callbacks[componentName.packageName], 0, "default", null) 37 | } 38 | 39 | override fun onServiceDisconnected(componentName: ComponentName) { 40 | Logger.log(TAG, "Disconnected from service ${componentName.packageName} / ${componentName.className}") 41 | interfaces[componentName.packageName] = null 42 | } 43 | } 44 | 45 | private fun connectTo(pkg: String) { 46 | Logger.log(TAG, "Connecting to: $pkg") 47 | val intent = Intent("$pkg.HFPluginService") 48 | intent.action = PluginFetcher.INTENT_ACTION_SERVICE 49 | intent.setPackage(pkg) 50 | HFApplication.instance.bindService(intent, serviceConnection, Service.BIND_AUTO_CREATE) 51 | } 52 | 53 | fun clear() { 54 | index = 0 55 | serviceSize = 0 56 | interfaces.clear() 57 | callbacks.clear() 58 | hasInitialized = false 59 | } 60 | 61 | fun getFeedAsItLoads(page: Int, onNewFeed: (List) -> Unit, onLoadFinished: () -> Unit) { 62 | Logger.log(TAG, "getFeedAsItLoads") 63 | 64 | val stub = object: IFeedInterfaceCallback.Stub() { 65 | override fun onCategoriesReceive(categories: MutableList?) { 66 | 67 | } 68 | 69 | override fun onFeedReceive(feed: MutableList?) { 70 | feed ?: return 71 | 72 | Logger.log(TAG, "Received feed: $feed") 73 | 74 | onNewFeed(feed) 75 | 76 | index++ 77 | if (index >= serviceSize) { 78 | Logger.log(TAG, "Finished chain!") 79 | handler.post { 80 | onLoadFinished() 81 | } 82 | } 83 | } 84 | } 85 | 86 | if (hasInitialized) { 87 | index = 0 88 | interfaces.forEach { 89 | it.value?.getFeed(stub, page, "default", null) 90 | } 91 | return 92 | } 93 | 94 | chainLoad(stub) 95 | hasInitialized = true 96 | } 97 | 98 | private fun chainLoad(cb: IFeedInterfaceCallback) { 99 | index = 0 100 | serviceSize = HFPluginPreferences.enabledList.size 101 | HFPluginPreferences.enabledList.forEach { 102 | callbacks[it] = cb 103 | connectTo(it) 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/pluginsystem/PluginFetcher.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.pluginsystem 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.content.pm.PackageManager 6 | import ua.itaysonlab.homefeeder.preferences.HFPreferences 7 | import ua.itaysonlab.homefeeder.utils.Logger 8 | 9 | object PluginFetcher { 10 | // List of available packages. 11 | val availablePlugins = hashMapOf() 12 | 13 | // Required part for AIDL connection. 14 | const val INTENT_ACTION_SERVICE = "ua.itaysonlab.hfsdk.HOMEFEEDER_PLUGIN_SERVICE" 15 | 16 | // Plugin settings action 17 | const val INTENT_ACTION_SETTINGS = "ua.itaysonlab.hfsdk.HOMEFEEDER_PLUGIN_ENTRYPOINT" 18 | 19 | // Metadata value acting for SDK version. 20 | private const val METADATA_SDK_VERSION = "HF_PluginSDK_Version" 21 | 22 | private const val METADATA_NAME = "HF_Plugin_Name" 23 | private const val METADATA_DESCRIPTION = "HF_Plugin_Description" 24 | private const val METADATA_AUTHOR = "HF_Plugin_Author" 25 | private const val METADATA_HAS_SETTINGS = "HF_Plugin_HasSettingsActivity" 26 | 27 | fun init(ctx: Context) { 28 | fillListBy(ctx.packageManager) 29 | } 30 | 31 | // Fill list of suitable packages. 32 | private fun fillListBy(packageManager: PackageManager) { 33 | availablePlugins.clear() 34 | 35 | val hasService = packageManager.queryIntentServices( 36 | Intent(INTENT_ACTION_SERVICE), 37 | PackageManager.GET_META_DATA 38 | ).map { 39 | Pair(it.serviceInfo.packageName, it.serviceInfo.metaData) 40 | } 41 | 42 | if (HFPreferences.debugging) { 43 | Logger.log("PluginFetcher", "Packages that has service: $hasService") 44 | } 45 | 46 | hasService.forEach { 47 | //Logger.log("PluginFetcher", "$it") 48 | availablePlugins[it.first] = SlimPluginInfo( 49 | it.first, 50 | hasPluginSettings = it.second.getBoolean(METADATA_HAS_SETTINGS), 51 | sdkVersion = it.second.getInt(METADATA_SDK_VERSION), 52 | title = it.second.getString(METADATA_NAME, ""), 53 | description = it.second.getString(METADATA_DESCRIPTION, ""), 54 | author = it.second.getString(METADATA_AUTHOR, "") 55 | ) 56 | } 57 | } 58 | 59 | data class SlimPluginInfo( 60 | val pkg: String, 61 | val hasPluginSettings: Boolean, 62 | val sdkVersion: Int, 63 | val title: String, 64 | val description: String, 65 | val author: String 66 | ) 67 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/preferences/HFPluginPreferences.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.preferences 2 | 3 | import ua.itaysonlab.homefeeder.utils.PreferenceHelper 4 | 5 | object HFPluginPreferences { 6 | private const val KEY = "HFEnabledPlugins" 7 | 8 | val enabledList get() = PreferenceHelper.getSet(KEY) 9 | 10 | fun add(pkg: String) { 11 | PreferenceHelper.setSet(KEY, enabledList.apply { 12 | add(pkg) 13 | }) 14 | } 15 | 16 | fun remove(pkg: String) { 17 | PreferenceHelper.setSet(KEY, enabledList.apply { 18 | remove(pkg) 19 | }) 20 | } 21 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/preferences/HFPreferences.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.preferences 2 | 3 | import ua.itaysonlab.homefeeder.utils.PreferenceHelper 4 | 5 | object HFPreferences { 6 | val debugging get() = PreferenceHelper.get("HFDebugging", false) 7 | val contentDebugging get() = PreferenceHelper.get("HFContentDebugging", false) 8 | val overlayCompact get() = PreferenceHelper.get("ovr_compact", false) 9 | val systemColors get() = PreferenceHelper.get("ovr_syscolors", false) 10 | val overlayTheme get() = PreferenceHelper.get("ovr_theme", "auto_launcher") 11 | val overlayTransparency get() = PreferenceHelper.get("ovr_transparency", "non_transparent") 12 | val overlayBackground get() = PreferenceHelper.get("ovr_bg", "theme") 13 | val cardBackground get() = PreferenceHelper.get("ovr_card_bg", "theme") 14 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/theming/Theming.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.theming 2 | 3 | import android.content.Context 4 | import android.content.res.Configuration 5 | import android.util.SparseIntArray 6 | import androidx.core.content.ContextCompat 7 | import ua.itaysonlab.homefeeder.HFApplication 8 | import ua.itaysonlab.homefeeder.R 9 | 10 | object Theming { 11 | val defaultLightThemeColors = createLightTheme() 12 | val defaultDarkThemeColors = createDarkTheme() 13 | 14 | private fun createLightTheme(): SparseIntArray { 15 | return SparseIntArray().apply { 16 | addBasicThings(this) 17 | put(Colors.CARD_BG.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.card_bg)) 18 | put(Colors.TEXT_COLOR_PRIMARY.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.text_color_primary)) 19 | put(Colors.TEXT_COLOR_SECONDARY.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.text_color_secondary)) 20 | put(Colors.OVERLAY_BG.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.bg_overlay)) 21 | put(Colors.IS_LIGHT.ordinal, 1) 22 | } 23 | } 24 | 25 | private fun createDarkTheme(): SparseIntArray { 26 | return SparseIntArray().apply { 27 | addBasicThings(this) 28 | put(Colors.CARD_BG.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.card_bg_dark)) 29 | put(Colors.TEXT_COLOR_PRIMARY.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.text_color_primary_dark)) 30 | put(Colors.TEXT_COLOR_SECONDARY.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.text_color_secondary_dark)) 31 | put(Colors.OVERLAY_BG.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.bg_dark)) 32 | put(Colors.IS_LIGHT.ordinal, 0) 33 | } 34 | } 35 | 36 | private fun addBasicThings(array: SparseIntArray): SparseIntArray { 37 | return array.apply { 38 | put(Colors.ACCENT_COLOR.ordinal, ContextCompat.getColor(HFApplication.instance, R.color.globalAccent)) 39 | } 40 | } 41 | 42 | fun getThemeBySystem(ctx: Context): SparseIntArray { 43 | return if (ctx.resources.configuration.uiMode.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES) createDarkTheme() else createLightTheme() 44 | } 45 | 46 | enum class Colors { 47 | CARD_BG, 48 | TEXT_COLOR_PRIMARY, 49 | TEXT_COLOR_SECONDARY, 50 | ACCENT_COLOR, 51 | OVERLAY_BG, 52 | IS_LIGHT 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/utils/Logger.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.utils 2 | 3 | import android.util.Log 4 | import ua.itaysonlab.homefeeder.BuildConfig 5 | 6 | /** 7 | * This class wraps [android.util.Log]. 8 | */ 9 | object Logger { 10 | fun log(tag: String, msg: String) { 11 | if (BuildConfig.DEBUG) Log.d("HF:$tag", msg) 12 | } 13 | 14 | fun w(tag: String, msg: String) { 15 | Log.w(tag, msg) 16 | } 17 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/utils/OverlayBridge.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.utils 2 | 3 | class OverlayBridge { 4 | private var callback: OverlayBridgeCallback? = null 5 | 6 | fun callServer(action: String) { 7 | if (isBridgeAlive()) callback!!.onClientMessage(action) 8 | } 9 | 10 | fun getCallback(): OverlayBridgeCallback? { 11 | return callback 12 | } 13 | 14 | fun setCallback(callback: OverlayBridgeCallback?) { 15 | this.callback = callback 16 | } 17 | 18 | fun isBridgeAlive() = callback !== null 19 | 20 | interface OverlayBridgeCallback { 21 | fun applyNewTheme(value: String) 22 | fun applyNewCardBg(value: String) 23 | fun applyNewOverlayBg(value: String) 24 | fun applyCompactCard(value: Boolean) 25 | fun applySysColors(value: Boolean) 26 | fun applyNewTransparency(value: String) 27 | 28 | fun onClientMessage(action: String) 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/utils/PreferenceHelper.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.utils 2 | 3 | import android.content.SharedPreferences 4 | import androidx.preference.PreferenceManager 5 | import ua.itaysonlab.homefeeder.HFApplication 6 | 7 | object PreferenceHelper { 8 | private val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(HFApplication.instance) 9 | 10 | fun get(key: String, default: Boolean): Boolean { 11 | return prefs.getBoolean(key, default) 12 | } 13 | 14 | fun get(key: String, default: String): String { 15 | return prefs.getString(key, default)!! 16 | } 17 | 18 | fun getSet(key: String): MutableSet { 19 | return prefs.getStringSet(key, mutableSetOf())!! 20 | } 21 | 22 | fun setSet(key: String, set: MutableSet) { 23 | Logger.log("PH", "Putting $set to $key") 24 | prefs.edit().apply { 25 | remove(key) 26 | commit() 27 | putStringSet(key, set) 28 | commit() 29 | } 30 | } 31 | 32 | fun get(key: String, default: Int): Int { 33 | return prefs.getInt(key, default) 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/homefeeder/utils/RelativeTimeHelper.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.homefeeder.utils 2 | 3 | import android.content.Context 4 | import ua.itaysonlab.homefeeder.R 5 | import java.util.Calendar 6 | import java.util.Locale 7 | import kotlin.math.min 8 | 9 | object RelativeTimeHelper { 10 | private val calendar: Calendar 11 | get() = Calendar.getInstance() 12 | 13 | private val currentTime: Long 14 | get() = System.currentTimeMillis() / 1000 15 | 16 | private fun getAbsoluteDate(context: Context, i: Long): String { 17 | val resources = context.resources 18 | val j = i * 1000 19 | val calendar = calendar 20 | val i2 = calendar.get(Calendar.YEAR) 21 | calendar.set(Calendar.MINUTE, 0) 22 | calendar.set(Calendar.HOUR_OF_DAY, 0) 23 | calendar.set(Calendar.SECOND, 0) 24 | calendar.set(Calendar.MILLISECOND, 0) 25 | val timeInMillis = calendar.timeInMillis 26 | var j2 = 86400000.toLong() 27 | var j3 = timeInMillis + j2 28 | var j4 = j3 + j2 29 | j2 = timeInMillis - j2 30 | calendar.timeInMillis = j 31 | j4-- 32 | val locale: Locale 33 | val str: String 34 | var format: String 35 | if (j in j3..j4) { 36 | locale = Locale.ENGLISH 37 | str = "%s %s %d:%02d" 38 | val tomorrow = resources.getString(R.string.tomorrow) 39 | val at = resources.getString(if (calendar.get(Calendar.HOUR_OF_DAY) == 1) R.string.date_at_1am else R.string.date_at) 40 | val hourOfDay = calendar.get(Calendar.HOUR_OF_DAY) 41 | val minute = calendar.get(Calendar.MINUTE) 42 | format = String.format(locale, str, tomorrow, at, hourOfDay, minute) 43 | return format 44 | } 45 | j3-- 46 | if (j in timeInMillis..j3) { 47 | locale = Locale.ENGLISH 48 | str = "%s %s %d:%02d" 49 | val today = resources.getString(R.string.today) 50 | val at = resources.getString(if (calendar.get(Calendar.HOUR_OF_DAY) == 1) R.string.date_at_1am else R.string.date_at) 51 | val hourOfDay = calendar.get(Calendar.HOUR_OF_DAY) 52 | val minute = calendar.get(Calendar.MINUTE) 53 | format = String.format(locale, str, today, at, hourOfDay, minute) 54 | return format 55 | } else if (j < j2 || j >= timeInMillis) { 56 | val string: String = if (calendar.get(Calendar.YEAR) != i2) { 57 | resources.getString(R.string.date_format_day_month_year, calendar.get(Calendar.DAY_OF_MONTH), resources.getStringArray(R.array.date_shortmonths)[min(calendar.get(2), Calendar.HOUR_OF_DAY)], calendar.get(Calendar.YEAR)) 58 | } else { 59 | resources.getString(R.string.date_format_day_month, calendar.get(Calendar.DAY_OF_MONTH), resources.getStringArray(R.array.date_shortmonths)[min(calendar.get(2), Calendar.HOUR_OF_DAY)]) 60 | } 61 | val stringBuilder = StringBuilder() 62 | stringBuilder.append(string) 63 | locale = Locale.ENGLISH 64 | val str2 = " %s %d:%02d" 65 | val at = resources.getString(if (calendar.get(Calendar.HOUR_OF_DAY) == 1) R.string.date_at_1am else R.string.date_at) 66 | val hourOfDay = calendar.get(Calendar.HOUR_OF_DAY) 67 | val minute = calendar.get(Calendar.MINUTE) 68 | format = String.format(locale, str2, at, hourOfDay, minute) 69 | stringBuilder.append(format) 70 | format = stringBuilder.toString() 71 | return format 72 | } else { 73 | locale = Locale.ENGLISH 74 | str = "%s %s %d:%02d" 75 | val yesterday = resources.getString(R.string.yesterday) 76 | val at = resources.getString(if (calendar.get(Calendar.HOUR_OF_DAY) == 1) R.string.date_at_1am else R.string.date_at) 77 | val hourOfDay = calendar.get(Calendar.HOUR_OF_DAY) 78 | val minute = calendar.get(Calendar.MINUTE) 79 | format = String.format(locale, str, yesterday, at, hourOfDay, minute) 80 | return format 81 | } 82 | } 83 | 84 | /** 85 | * @param context - Context to use with resources 86 | * @param i - Time in seconds (Unix timestamp) 87 | * @return Time relative to this 88 | */ 89 | fun getDateFormattedRelative(context: Context, i: Long): String { 90 | val resources = context.resources 91 | val currentTime = currentTime - i 92 | if (currentTime >= 14400 || currentTime < 0) { 93 | return getAbsoluteDate(context, i) 94 | } 95 | return when { 96 | currentTime >= 10800 -> { 97 | resources.getStringArray(R.array.date_ago_hrs)[2] 98 | } 99 | currentTime >= 7200 -> { 100 | resources.getStringArray(R.array.date_ago_hrs)[1] 101 | } 102 | currentTime >= 3600 -> { 103 | resources.getStringArray(R.array.date_ago_hrs)[0] 104 | } 105 | currentTime >= 60 -> { 106 | resources.getQuantityString(R.plurals.date_ago_mins, (currentTime / 60).toInt(), (currentTime / 60).toInt()) 107 | } 108 | currentTime <= 10 -> { 109 | resources.getString(R.string.date_ago_now) 110 | } 111 | else -> { 112 | resources.getQuantityString(R.plurals.date_ago_secs, currentTime.toInt(), currentTime.toInt()) 113 | } 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/ActionAdapter.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.recyclerview.widget.RecyclerView 7 | import ua.itaysonlab.homefeeder.R 8 | 9 | class ActionAdapter(private val e: Context, private val f: ActionStyle): RecyclerView.Adapter() { 10 | private val f2972a = LayoutInflater.from(this.e) 11 | private var c: List = listOf() 12 | private var d: ((PopupItem) -> Unit)? = null 13 | 14 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActionVh { 15 | return ActionVh(f2972a.inflate(R.layout.vklib_actionslistview_entry, parent, false), this.f) 16 | } 17 | 18 | override fun getItemCount(): Int { 19 | return this.c.size 20 | } 21 | 22 | fun a(i: Int): PopupItem { 23 | return this.c[i] 24 | } 25 | 26 | override fun onBindViewHolder(holder: ActionVh, position: Int) { 27 | holder.a(d!!) 28 | holder.a(this.c[position]) 29 | } 30 | 31 | override fun onViewRecycled(holder: ActionVh) { 32 | super.onViewRecycled(holder) 33 | holder.a(null) 34 | } 35 | 36 | fun a(): ((PopupItem) -> Unit)? { 37 | return this.d 38 | } 39 | 40 | fun a(cVar: (PopupItem) -> Unit) { 41 | this.d = cVar 42 | } 43 | 44 | fun a(list: List) { 45 | this.c = list 46 | notifyDataSetChanged() 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/ActionDivider.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.graphics.Canvas 4 | import android.graphics.Paint 5 | import android.graphics.Rect 6 | import android.view.View 7 | import androidx.recyclerview.widget.RecyclerView 8 | 9 | class ActionDivider(private val style: DividerStyle): RecyclerView.ItemDecoration() { 10 | private val f2974a = Paint() 11 | private val b = Rect() 12 | 13 | init { 14 | this.f2974a.color = style.dividerColor 15 | this.f2974a.isAntiAlias = false 16 | this.f2974a.isDither = false 17 | } 18 | 19 | override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { 20 | if (a(parent, view)) { 21 | outRect.bottom = style.dividerHeight 22 | } 23 | } 24 | 25 | override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { 26 | super.onDraw(c, parent, state) 27 | if (parent.childCount != 0) { 28 | val paddingLeft = parent.paddingLeft 29 | val measuredWidth = parent.measuredWidth - parent.paddingRight 30 | 31 | for (i in 0 until parent.childCount) { 32 | val childAt = parent.getChildAt(i) 33 | if (a(parent, childAt)) { 34 | val bottom = childAt.bottom + ((this.style.dividerHeight / 2) - (this.style.dividerSize / 2)) 35 | this.b.set(paddingLeft, bottom, measuredWidth, this.style.dividerSize + bottom) 36 | c.drawRect(this.b, this.f2974a) 37 | } 38 | } 39 | } 40 | } 41 | 42 | companion object { 43 | fun a(recyclerView: RecyclerView, view: View): Boolean { 44 | val cap = recyclerView.getChildAdapterPosition(view) 45 | if (cap == -1) return false 46 | val adapter = recyclerView.adapter as ActionAdapter 47 | if (cap == adapter.itemCount - 1) return false 48 | if (adapter.a(cap).group != adapter.a(cap + 1).group) return true 49 | return false 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/ActionStyle.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.graphics.drawable.Drawable 4 | import androidx.annotation.UiThread 5 | 6 | @UiThread 7 | data class ActionStyle( 8 | var optionBackground: Drawable?, 9 | var paddingStart: Int, 10 | var paddingEnd: Int, 11 | var iconSpace: Int, 12 | var iconTint: Int?, 13 | var textSize: Int, 14 | var textColor: Int 15 | ) -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/ActionVh.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.graphics.PorterDuff 4 | import android.graphics.PorterDuffColorFilter 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.ImageView 8 | import android.widget.TextView 9 | import androidx.recyclerview.widget.RecyclerView 10 | import ua.itaysonlab.homefeeder.R 11 | 12 | class ActionVh(private val f: View, private val g: ActionStyle): RecyclerView.ViewHolder(f) { 13 | private val b: ImageView = this.f.findViewById(R.id.icon) 14 | private val c: TextView = this.f.findViewById(R.id.label) 15 | private var d: PopupItem? = null 16 | private var e: ((PopupItem) -> Unit)? = null 17 | 18 | init { 19 | //this.f.background = this.g.optionBackground 20 | this.f.setPaddingRelative(this.g.paddingStart, 0, this.g.paddingEnd, 0) 21 | this.f.setOnClickListener { 22 | if (d != null && e != null) { 23 | e?.invoke(d!!) 24 | } 25 | } 26 | if (this.g.iconTint != null) { 27 | this.b.colorFilter = PorterDuffColorFilter(this.g.iconTint!!, PorterDuff.Mode.SRC_IN) 28 | } 29 | this.c.setTextSize(0, this.g.textSize.toFloat()) 30 | this.c.setTextColor(this.g.textColor) 31 | this.c.layoutParams = (this.c.layoutParams as ViewGroup.MarginLayoutParams).apply { 32 | marginStart = g.iconSpace 33 | } 34 | } 35 | 36 | fun a(): ((PopupItem) -> Unit)? { 37 | return this.e 38 | } 39 | 40 | fun a(cVar: ((PopupItem) -> Unit)?) { 41 | this.e = cVar 42 | } 43 | 44 | fun a(aVar: PopupItem) { 45 | this.d = aVar 46 | this.b.setImageResource(aVar.icon) 47 | this.c.setText(aVar.title) 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/DialogActionsVcByPopup.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.res.Resources 5 | import android.graphics.Rect 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import androidx.annotation.UiThread 9 | import ua.itaysonlab.homefeeder.R 10 | import kotlin.math.ceil 11 | 12 | @UiThread 13 | class DialogActionsVcByPopup(private val d: View) { 14 | private var b: (() -> Unit)? = null 15 | private var c: PopupWindowImpl? = null 16 | private fun a(): Boolean = this.c != null 17 | 18 | private fun intToDp(dp: Int): Int { 19 | return ceil((dp * Resources.getSystem().displayMetrics.density).toDouble()).toInt() 20 | } 21 | 22 | fun d(view: View): Rect { 23 | val iArr = IntArray(2) 24 | view.getLocationOnScreen(iArr) 25 | return Rect(iArr[0], iArr[1], iArr[0] + view.measuredWidth, iArr[1] + view.measuredHeight) 26 | } 27 | 28 | @SuppressLint("InflateParams") 29 | fun a(list: List, setListViewParams: ((Pair) -> Unit)? = null, onClick: (PopupItem) -> Unit) { 30 | if (!a()) { 31 | val context = this.d.context 32 | val inflate = LayoutInflater.from(context).inflate(R.layout.replica_popup, null, false) 33 | val dialogActionsListView = inflate.findViewById(R.id.dialog_actions_list_content) 34 | setListViewParams?.invoke(Pair(inflate.findViewById(R.id.dialog_actions_list_container), dialogActionsListView)) 35 | dialogActionsListView.setActions(list) 36 | dialogActionsListView.setActionClickListener(onClick) 37 | 38 | inflate.measure(View.MeasureSpec.makeMeasureSpec(this.d.rootView.measuredWidth, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(this.d.rootView.measuredHeight - intToDp(64), View.MeasureSpec.AT_MOST)) 39 | inflate.layout(0, 0, inflate.measuredWidth, inflate.measuredHeight) 40 | 41 | val d2 = d(this.d) 42 | val measuredWidth = (d2.right - inflate.measuredWidth) + intToDp(8) 43 | val b2 = d2.top - intToDp(8) 44 | val rect = Rect(measuredWidth, b2, inflate.measuredWidth + measuredWidth, inflate.measuredHeight + b2) 45 | 46 | this.c = PopupWindowImpl(context).apply { 47 | contentView = inflate 48 | width = rect.width() 49 | height = rect.height() 50 | setOnDismissListener { c = null } 51 | showAtLocation(d, 0, rect.left, rect.top) 52 | } 53 | } 54 | } 55 | 56 | fun dismiss() { 57 | if (a()) { 58 | b?.invoke() 59 | c?.dismiss() 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/DividerStyle.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import androidx.annotation.UiThread 4 | 5 | @UiThread 6 | data class DividerStyle( 7 | var dividerHeight: Int, 8 | var dividerSize: Int, 9 | var dividerColor: Int 10 | ) -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/PopupContentAnimator.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.animation.* 4 | import android.content.res.Resources 5 | import android.graphics.Rect 6 | import android.os.Handler 7 | import android.os.Looper 8 | import android.view.View 9 | import androidx.annotation.UiThread 10 | import androidx.core.os.postDelayed 11 | import androidx.interpolator.view.animation.FastOutLinearInInterpolator 12 | import androidx.interpolator.view.animation.LinearOutSlowInInterpolator 13 | import kotlin.math.ceil 14 | 15 | @UiThread 16 | class PopupContentAnimator(private val g: View) { 17 | companion object { 18 | private fun intToDp(dp: Int): Int { 19 | return ceil((dp * Resources.getSystem().displayMetrics.density).toDouble()).toInt() 20 | } 21 | 22 | val h = (-(intToDp(4))).toFloat() 23 | val j = (-(intToDp(4))).toFloat() 24 | 25 | val i = LinearOutSlowInInterpolator() 26 | val k = FastOutLinearInInterpolator() 27 | } 28 | 29 | var b: Animator? = null 30 | var c: Animator? = null 31 | private val d = Handler(Looper.getMainLooper()) 32 | private var e: (() -> Unit)? = null 33 | private var f: (() -> Unit)? = null 34 | 35 | fun a(action: () -> Unit) { 36 | this.f = action 37 | } 38 | 39 | private fun b() { 40 | val rect = Rect(0, 0, this.g.measuredWidth, 0) 41 | val rect2 = Rect(0, 0, this.g.measuredWidth, this.g.measuredHeight) 42 | this.g.apply { 43 | clipBounds = rect 44 | alpha = 0.0f 45 | translationY = h 46 | visibility = View.VISIBLE 47 | } 48 | 49 | val ofObject = ObjectAnimator.ofObject(this.g, "clipBounds", RectEvaluator(), rect, rect2) 50 | val ofFloat = ObjectAnimator.ofFloat(this.g, View.ALPHA, 0.0f, 1.0f) 51 | val ofFloat2 = ObjectAnimator.ofFloat(this.g, View.TRANSLATION_Y, h, 0.0f) 52 | this.b = AnimatorSet().apply { 53 | addListener(object: AnimatorListenerAdapter() { 54 | override fun onAnimationEnd(animation: Animator?) { 55 | b = null 56 | c = null 57 | g.visibility = View.VISIBLE 58 | } 59 | }) 60 | addListener(object: AnimatorListenerAdapter() { 61 | override fun onAnimationEnd(animation: Animator?) { 62 | b = null 63 | c = null 64 | e?.invoke() 65 | } 66 | }) 67 | duration = 225 68 | interpolator = i 69 | playTogether(ofObject, ofFloat, ofFloat2) 70 | start() 71 | } 72 | } 73 | 74 | fun a(z: Boolean) { 75 | if (!a()) { 76 | e() 77 | if (d()) { 78 | b() 79 | } else { 80 | b { b() } 81 | } 82 | } 83 | } 84 | 85 | fun b(z: Boolean) { 86 | if (a()) { 87 | if (z) { 88 | e() 89 | if (d()) { 90 | c() 91 | } else { 92 | b { c() } 93 | } 94 | } else { 95 | e() 96 | this.g.visibility = View.INVISIBLE 97 | this.f?.invoke() 98 | } 99 | } 100 | } 101 | 102 | private fun c() { 103 | this.g.apply { 104 | clipBounds = null 105 | alpha = 1.0f 106 | translationY = 0.0f 107 | visibility = View.VISIBLE 108 | } 109 | val ofFloat = ObjectAnimator.ofFloat(this.g, View.ALPHA, 1.0f, 0.0f) 110 | val ofFloat2 = ObjectAnimator.ofFloat(this.g, View.TRANSLATION_Y, 0.0f, j) 111 | this.c = AnimatorSet().apply { 112 | addListener(object: AnimatorListenerAdapter() { 113 | override fun onAnimationEnd(animation: Animator?) { 114 | b = null 115 | c = null 116 | g.visibility = View.INVISIBLE 117 | } 118 | }) 119 | addListener(object: AnimatorListenerAdapter() { 120 | override fun onAnimationEnd(animation: Animator?) { 121 | b = null 122 | c = null 123 | f?.invoke() 124 | } 125 | }) 126 | duration = 150 127 | interpolator = k 128 | playTogether(ofFloat, ofFloat2) 129 | start() 130 | } 131 | } 132 | 133 | private fun d(): Boolean { 134 | return this.g.measuredHeight > 0 135 | } 136 | 137 | private fun b(aVar: () -> Unit) { 138 | this.g.visibility = View.INVISIBLE 139 | this.d.postDelayed(50) { 140 | aVar.invoke() 141 | } 142 | } 143 | 144 | private fun e() { 145 | this.b?.cancel() 146 | this.b = null 147 | this.c?.cancel() 148 | this.c = null 149 | this.d.removeCallbacksAndMessages(null) 150 | } 151 | 152 | private fun a(): Boolean { 153 | if (this.b == null) { 154 | if (this.g.visibility == View.VISIBLE) { 155 | if (this.c == null) { 156 | return true 157 | } 158 | } 159 | return false 160 | } 161 | return true 162 | } 163 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/PopupItem.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import androidx.annotation.DrawableRes 4 | import androidx.annotation.StringRes 5 | 6 | data class PopupItem( 7 | @DrawableRes val icon: Int, 8 | @StringRes val title: Int, 9 | val group: Int, 10 | val id: String 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/PopupWindowImpl.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.content.Context 4 | import android.graphics.Canvas 5 | import android.graphics.ColorFilter 6 | import android.graphics.PixelFormat 7 | import android.graphics.drawable.Drawable 8 | import android.os.Handler 9 | import android.view.View 10 | import android.widget.PopupWindow 11 | import androidx.annotation.UiThread 12 | 13 | @UiThread 14 | class PopupWindowImpl(context: Context): PopupWindow(context) { 15 | private val f1304a = Handler() 16 | private var b: PopupContentAnimator? = null 17 | 18 | init { 19 | isClippingEnabled = false 20 | isFocusable = true 21 | animationStyle = 0 22 | setBackgroundDrawable(object: Drawable() { 23 | override fun draw(canvas: Canvas) { 24 | 25 | } 26 | 27 | override fun setAlpha(alpha: Int) { 28 | 29 | } 30 | 31 | override fun getOpacity(): Int { 32 | return PixelFormat.TRANSPARENT 33 | } 34 | 35 | override fun setColorFilter(colorFilter: ColorFilter?) { 36 | 37 | } 38 | 39 | }) 40 | } 41 | 42 | override fun showAsDropDown(view: View?) { 43 | run { 44 | super.showAsDropDown(view) 45 | } 46 | } 47 | 48 | override fun showAsDropDown(view: View?, i: Int, i2: Int) { 49 | run { 50 | super.showAsDropDown(view, i, i2) 51 | } 52 | } 53 | 54 | override fun showAsDropDown(view: View?, i: Int, i2: Int, i3: Int) { 55 | run { 56 | super.showAsDropDown(view, i, i2, i3) 57 | } 58 | } 59 | 60 | override fun showAtLocation(view: View?, i: Int, i2: Int, i3: Int) { 61 | run { 62 | super.showAtLocation(view, i, i2, i3) 63 | } 64 | } 65 | 66 | private fun run(aVar: () -> Unit) { 67 | this.b = PopupContentAnimator(contentView) 68 | this.b?.b(false) 69 | aVar.invoke() 70 | this.f1304a.post { 71 | this.b?.a(true) 72 | } 73 | } 74 | 75 | override fun dismiss() { 76 | this.f1304a.removeCallbacksAndMessages(null) 77 | this.b?.a { 78 | b = null 79 | super.dismiss() 80 | } 81 | this.b?.b(true) 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/ua/itaysonlab/replica/vkpopup/VkLibActionsListView.kt: -------------------------------------------------------------------------------- 1 | package ua.itaysonlab.replica.vkpopup 2 | 3 | import android.content.Context 4 | import android.content.res.Resources 5 | import android.graphics.drawable.Drawable 6 | import android.util.AttributeSet 7 | import android.util.DisplayMetrics 8 | import androidx.annotation.ColorInt 9 | import androidx.annotation.DrawableRes 10 | import androidx.annotation.Px 11 | import androidx.annotation.UiThread 12 | import androidx.core.content.ContextCompat 13 | import androidx.recyclerview.widget.LinearLayoutManager 14 | import androidx.recyclerview.widget.RecyclerView 15 | import ua.itaysonlab.homefeeder.R 16 | import kotlin.math.ceil 17 | 18 | @UiThread 19 | open class VkLibActionsListView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0): RecyclerView(context, attrs, defStyleAttr) { 20 | private val f2979a: DividerStyle 21 | private val b: ActionStyle 22 | private var c: ActionDivider 23 | private var d: ActionAdapter 24 | 25 | init { 26 | val attr = context.obtainStyledAttributes(attrs, R.styleable.VkLibActionsListView, defStyleAttr, 0) 27 | val dHeight = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_dividerHeight, a(1)) 28 | val dSize = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_dividerSize, a(1)) 29 | val dColor = attr.getColor(R.styleable.VkLibActionsListView_vklib_alv_dividerColor, -16777216) 30 | this.f2979a = DividerStyle(dHeight, dSize, dColor) 31 | 32 | val oBg = attr.getDrawable(R.styleable.VkLibActionsListView_vklib_alv_optionBackground) 33 | val paddingStart = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_optionPaddingStart, 0) 34 | val paddingEnd = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_optionPaddingEnd, 0) 35 | val iconSpace = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_optionIconLabelSpace, 0) 36 | val iconTint = Integer.valueOf(attr.getColor(R.styleable.VkLibActionsListView_vklib_alv_optionIconTint, -16777216)) 37 | val textSize = attr.getDimensionPixelSize(R.styleable.VkLibActionsListView_vklib_alv_optionLabelTextSize, (((getDisplayMetrics().scaledDensity * 16.0f) + 0.5f).toInt())) 38 | val textColor = attr.getColor(R.styleable.VkLibActionsListView_vklib_alv_optionLabelTextColor, -16777216) 39 | this.b = ActionStyle(oBg, paddingStart, paddingEnd, iconSpace, iconTint, textSize, textColor) 40 | attr.recycle() 41 | 42 | this.c = ActionDivider(this.f2979a) 43 | this.d = ActionAdapter(context, this.b) 44 | this.layoutManager = LinearLayoutManager(context, VERTICAL, false) 45 | this.addItemDecoration(this.c) 46 | this.adapter = this.d 47 | } 48 | 49 | fun setDividerHeight(@Px i: Int) { 50 | this.f2979a.dividerHeight = i 51 | a() 52 | } 53 | 54 | fun setDividerSize(@Px i: Int) { 55 | this.f2979a.dividerSize = i 56 | a() 57 | } 58 | 59 | fun setDividerColor(@ColorInt i: Int) { 60 | this.f2979a.dividerColor = i 61 | a() 62 | } 63 | 64 | fun setActionBackground(@DrawableRes i: Int) { 65 | if (i != 0) { 66 | setActionBackground(ContextCompat.getDrawable(context, i)) 67 | } else { 68 | setActionBackground(null) 69 | } 70 | } 71 | 72 | fun setActionBackground(drawable: Drawable?) { 73 | this.b.optionBackground = drawable 74 | b() 75 | } 76 | 77 | fun setActionPaddingStart(@Px i: Int) { 78 | this.b.paddingStart = i 79 | b() 80 | } 81 | 82 | fun setActionIconTint(@ColorInt i: Int) { 83 | this.b.iconTint = i 84 | b() 85 | } 86 | 87 | fun setActionPaddingEnd(@Px i: Int) { 88 | this.b.paddingEnd = i 89 | b() 90 | } 91 | 92 | fun setActionIconLabelSpace(@Px i: Int) { 93 | this.b.iconSpace = i 94 | b() 95 | } 96 | 97 | fun setActionLabelTextSize(@Px i: Int) { 98 | this.b.textSize = i 99 | b() 100 | } 101 | 102 | fun setActionLabelTextColor(@ColorInt i: Int) { 103 | this.b.textColor = i 104 | b() 105 | } 106 | 107 | fun setActionClickListener(cVar: (PopupItem) -> Unit) { 108 | this.d.a(cVar) 109 | } 110 | 111 | fun setActions(list: List) { 112 | this.d.a(list) 113 | if (list.isNotEmpty()) layoutManager?.scrollToPosition(0) 114 | } 115 | 116 | private fun a() { 117 | this.c = ActionDivider(this.f2979a) 118 | adapter?.notifyDataSetChanged() 119 | } 120 | 121 | private fun b() { 122 | this.d = ActionAdapter(context, this.b) 123 | adapter = this.d 124 | } 125 | 126 | private fun getDisplayMetrics(): DisplayMetrics { 127 | return Resources.getSystem().displayMetrics 128 | } 129 | 130 | private fun a(i: Int): Int { 131 | return ceil((getDisplayMetrics().density * 1.0f)).toInt() 132 | } 133 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/vkim_bg_overlay.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/drawable-hdpi/vkim_bg_overlay.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/vkim_bg_overlay.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/drawable-mdpi/vkim_bg_overlay.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 9 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 38 | 44 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/vkim_bg_overlay.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/drawable-xhdpi/vkim_bg_overlay.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/vkim_bg_overlay.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/drawable-xxhdpi/vkim_bg_overlay.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/vkim_bg_overlay.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/drawable-xxxhdpi/vkim_bg_overlay.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info_outline_28.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 6 | 8 | 14 | 22 | 30 | 38 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_more_vertical_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_replay_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_report_outline_28.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_services_outline_28.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings_outline_28.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_warning_24.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/remove_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/v2_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 29 | 30 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/feed_card_action.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/feed_card_story_large.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 17 | 18 | 28 | 29 | 39 | 40 | 53 | 54 | 62 | 63 | 70 | 71 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/layout/feed_card_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 18 | 19 | 26 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notification_generic_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 14 | 15 | 19 | 26 | 27 | 34 | 35 | 45 | 46 | 47 | 57 | 58 | 59 | 69 | 70 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/layout/notification_simple.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/overlay_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 22 | 23 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/overlay_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 22 | 23 | 27 | 28 | 33 | 34 | 35 | 36 | 42 | 43 | 50 | 51 | 56 | 57 | 65 | 66 | 73 | 74 | 80 | 81 | 82 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /app/src/main/res/layout/plugin_manager_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 14 | 24 | 25 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/plugin_manager_entry.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 29 | 30 | 34 | 35 | 41 | 42 | 48 | 49 | 56 | 57 | 62 | 63 | 64 | 72 | 73 | 78 | 79 | 80 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/res/layout/plugin_manager_ui.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preview.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/replica_popup.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/vklib_actionslistview_entry.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/menu/bottom_nav_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/navigation/mobile_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | -------------------------------------------------------------------------------- /app/src/main/res/values-night/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4285f4 4 | #80000000 5 | #121212 6 | #212121 7 | #ffffff 8 | #a0a0a0 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Автоматически (из лаунчера) 5 | Автоматически (из системы) 6 | Светлая 7 | Темная 8 | 9 | 10 | 11 | Непрозрачный 12 | 75\uff05 13 | 50\uff05 14 | 25\uff05 15 | Прозрачный 16 | 17 | 18 | 19 | Из темы 20 | Светлый 21 | Темный 22 | AMOLED 23 | Из лаунчера: Основной цвет 24 | Из лаунчера: Вторичный цвет 25 | Из лаунчера: Третичный цвет 26 | 27 | 28 | 29 | час назад 30 | два часа назад 31 | три часа назад 32 | 33 | 34 | 35 | Январь 36 | Февраль 37 | Март 38 | Апрель 39 | Май 40 | Июнь 41 | Июль 42 | Август 43 | Сентябрь 44 | Октябрь 45 | Ноябрь 46 | Декабрь 47 | 48 | 49 | 50 | Янв 51 | Фев 52 | Мар 53 | Апр 54 | Мая 55 | Июн 56 | Июл 57 | Авг 58 | Сен 59 | Окт 60 | Ноя 61 | Дек 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/plurals.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %,d минут назад 5 | %,d минуту назад 6 | %,d минуты назад 7 | 8 | 9 | %,d секунд назад 10 | %,d секунду назад 11 | %,d секунды назад 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values-ru/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Настройки 3 | О приложении 4 | Источники данных 5 | 6 | сейчас 7 | в 8 | @string/date_at 9 | сегодня 10 | завтра 11 | вчера 12 | 13 | Контакты 14 | Официальный канал в Telegram 15 | Разработчик 16 | Исходный код 17 | 18 | Внешний вид 19 | Прозрачность фона 20 | Тема 21 | Компактные элементы списка 22 | 23 | Фон карточек 24 | Фон ленты 25 | 26 | Категория ленты \"Уведомления\" 27 | Доступ к уведомлениям 28 | Есть 29 | Нету, нажмите сюда для подробной информации 30 | HomeFeeder нужно разрешение \"Доступ к уведомлениям\" для показа уведомлений в ленте. Данные обрабатываются на устройстве и только на нем.\n\nВозможно, некоторые функции HomeFeeder могут быть недоступными до выдачи разрешения. 31 | Настройки 32 | Отменить 33 | 34 | Доступ к памяти 35 | HomeFeeder нужно разрешение \"Память\" для точного предпросмотра и сохранения данных.\n\nДанное разрешение необязательно, но рекомендуется для нормального использования. 36 | Запросить 37 | 38 | Разрешение не выдано 39 | Нажмите для перезагрузки 40 | HomeFeeder нужно разрешение \"Доступ к уведомлениям\" для показа уведомлений в ленте. 41 | Проверьте что вы выдали разрешение \"Доступ к уведомлениям\" 42 | 43 | Уведомления 44 | Погода 45 | 46 | Использовать системные цвета обоев 47 | вместо опций \"Из лаунчера:\" 48 | Требуется Android 8.1 или новее 49 | 50 | Перезагрузить 51 | 52 | Источники не обнаружены 53 | HomeFeeder использует их для получения данных 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/values-v23/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values-v27/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Automatically (from launcher) 5 | Automatically (from system) 6 | Light 7 | Dark 8 | 9 | 10 | 11 | Non-transparent 12 | 75\uff05 13 | 50\uff05 14 | 25\uff05 15 | Transparent 16 | 17 | 18 | 19 | non_transparent 20 | more_half 21 | half 22 | less_half 23 | transparent 24 | 25 | 26 | 27 | Theme-based 28 | White 29 | Dark 30 | AMOLED 31 | Launcher: Primary color 32 | Launcher: Secondary color 33 | Launcher: Tertiary color 34 | 35 | 36 | 37 | theme 38 | white 39 | dark 40 | amoled 41 | launcher_primary 42 | launcher_secondary 43 | launcher_tertiary 44 | 45 | 46 | 47 | auto_launcher 48 | auto_system 49 | light 50 | dark 51 | 52 | 53 | 54 | an hour ago 55 | two hours ago 56 | three hours ago 57 | 58 | 59 | 60 | January 61 | February 62 | March 63 | April 64 | May 65 | June 66 | July 67 | August 68 | September 69 | October 70 | November 71 | December 72 | 73 | 74 | 75 | Jan 76 | Feb 77 | Mar 78 | Apr 79 | May 80 | Jun 81 | Jul 82 | Aug 83 | Sep 84 | Oct 85 | Nov 86 | Dec 87 | 88 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #4285f4 4 | 5 | #A0FFFFFF 6 | #ffffff 7 | 8 | #ffffff 9 | #121212 10 | #f0f0f0 11 | 12 | #000000 13 | #707070 14 | 15 | #f0f0f0 16 | #212121 17 | #000000 18 | #ffffff 19 | #a0000000 20 | #a0FFFFFF 21 | 22 | #ff453a 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 14dp 5 | 6 | 16dp 7 | 16dp 8 | 9 | 4dp 10 | 8dp 11 | 140dp 12 | 13 | 12dp 14 | 12dp 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/plurals.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %,d minutes ago 5 | %,d minute ago 6 | %,d minutes ago 7 | 8 | 9 | %,d seconds ago 10 | %,d second ago 11 | %,d seconds ago 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | HomeFeeder 3 | 4 | Settings 5 | About 6 | Data sources 7 | 8 | %1$d %2$s 9 | %1$d %2$s %3$d 10 | now 11 | at 12 | @string/date_at 13 | today 14 | tomorrow 15 | yesterday 16 | 17 | Contacts 18 | Official Telegram channel 19 | Developer 20 | Source code 21 | 22 | Appearance 23 | Overlay background transparency 24 | Overlay theme 25 | Compact item layout 26 | 27 | Card background 28 | Overlay background 29 | 30 | Notification feed category 31 | Notification permission 32 | Granted 33 | Not granted, click here to allow 34 | HomeFeeder needs \"Notification access\" permission to show your notifications in a overlay. Data is processed only on-device and won\'t be sent from it.\n\nPlease note that some features of HomeFeeder might be unavailable until you grant the permission. 35 | Open settings 36 | Cancel 37 | 38 | Storage permission 39 | HomeFeeder needs \"Read external storage\" permission to save various data and show accurate previews.\n\nThis permission is not needed, but recommended for using. 40 | Request 41 | 42 | No permission granted 43 | Click here to reload 44 | HomeFeeder needs \"Notification access\" permission to show your notifications in a overlay. 45 | Please verify you have allowed \"Notification access\" permission and try again. 46 | 47 | Notifications 48 | Weather 49 | 50 | Use system wallpaper colors 51 | instead of \"Launcher:\" options 52 | Requires Android 8.1 or newer 53 | 54 | Reload 55 | 56 | No sources installed 57 | HomeFeeder uses them to display data 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 17 | 18 | 21 | 22 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 11 | 14 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/xml/pref_general.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 24 | 29 | 35 | 41 | 42 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.6.10' 5 | 6 | repositories { 7 | google() 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:7.1.1' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | google() 22 | mavenCentral() 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iTaysonLab/HomeFeeder/ec36735b596a0af3f3c0cf79f03d9ab42b7d1e14/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jul 10 12:40:05 EEST 2020 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-7.2-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 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 Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':homefeeder-sdk', ':homefeeder-rss' 2 | rootProject.name='HomeFeeder' 3 | --------------------------------------------------------------------------------