diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..310b10c --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# gitignore for Theos + +*.deb +_/ +theos/ +theos +.theos +packages/ +./packages/ +obj/ +./obj/ +obj +.DS_Store diff --git a/FolderFinder.h b/FolderFinder.h new file mode 100644 index 0000000..f191627 --- /dev/null +++ b/FolderFinder.h @@ -0,0 +1,4 @@ +@interface FolderFinder : NSObject + +(NSString*) findSharedFolder:(NSString*) appName; + +(NSString*) findFolder:(NSString*) appName folder:(NSString*) dir; +@end diff --git a/FolderFinder.m b/FolderFinder.m new file mode 100644 index 0000000..f697c3a --- /dev/null +++ b/FolderFinder.m @@ -0,0 +1,40 @@ +// Credit: u/Mordred666 +// Source: https://reddit.com/r/jailbreakdevelopers/comments/5wb3tv/application_appgroup_path/ + +#import "FolderFinder.h" + +@implementation FolderFinder : NSObject + +(NSString*) findSharedFolder:(NSString*) appName { + NSString *dir = @"/var/mobile/Containers/Shared/AppGroup/"; + NSString* result = [self findFolder:appName folder:dir]; + return result; + } + + +(NSString*) findFolder:(NSString*) appName folder:(NSString*) dir { + NSFileManager *manager = [NSFileManager defaultManager]; + + NSError *error = nil; + NSArray *folders = [manager contentsOfDirectoryAtPath:dir error:&error]; + + if (!error) { + for (NSString *folder in folders) { + NSString *folderPath = [dir stringByAppendingString:folder]; + NSArray *items = [manager contentsOfDirectoryAtPath:folderPath error:&error]; + + for(NSString* itemPath in items) { + if([itemPath rangeOfString:@".com.apple.mobile_container_manager.metadata.plist"].location != NSNotFound) { + NSString* fullpath = [NSString stringWithFormat:@"%@/%@",folderPath, itemPath]; + NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:fullpath]; + + NSString* mcmmetadata = dict[@"MCMMetadataIdentifier"]; + if(mcmmetadata && [mcmmetadata.lowercaseString isEqualToString:appName.lowercaseString]) { + return folderPath; + } + } + } + + } + } + return nil; + } +@end diff --git a/Info.plist b/Info.plist new file mode 100755 index 0000000..cfac928 --- /dev/null +++ b/Info.plist @@ -0,0 +1,15 @@ + + + + + CFBundleDisplayName + Viber + DDNotificationExternalProviderClasses + + ViberContactPhotoProvider + com.viber + + DDNotificationExternalProviderAPIVersion + 1 + + diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..add6066 --- /dev/null +++ b/Makefile @@ -0,0 +1,21 @@ +ARCHS = armv7 arm64 + +include $(THEOS)/makefiles/common.mk + +BUNDLE_NAME = ShortLook-Viber +$(BUNDLE_NAME)_CFLAGS = -fobjc-arc +$(BUNDLE_NAME)_FILES = $(wildcard *.m) +$(BUNDLE_NAME)_FRAMEWORKS = UIKit +$(BUNDLE_NAME)_INSTALL_PATH = /Library/Dynastic/ShortLook/Plugins/ContactPhotoProviders +$(BUNDLE_NAME)_LDFLAGS = -lsqlite3 + +include $(THEOS_MAKE_PATH)/bundle.mk + +BUNDLE_PATH = $($(BUNDLE_NAME)_INSTALL_PATH)/$(BUNDLE_NAME).bundle + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)$(BUNDLE_PATH)$(ECHO_END) + $(ECHO_NOTHING)cp Info.plist $(THEOS_STAGING_DIR)$(BUNDLE_PATH)/Info.plist$(ECHO_END) + +after-install:: + install.exec "killall -9 SpringBoard" diff --git a/README.md b/README.md new file mode 100755 index 0000000..f016939 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Viber Contact Photo Provider for ShortLook + +Show Viber users' profile pictures in ShortLook when you receive a Viber notification! + +(This is not ShortLook itself, but a plugin for it) diff --git a/ShortLook-API.h b/ShortLook-API.h new file mode 100755 index 0000000..2c5cc07 --- /dev/null +++ b/ShortLook-API.h @@ -0,0 +1,107 @@ +// +// WARNING: +// This file contains the required headers to compile a tweak that +// interacts with ShortLook's contact photo API. Do not modify the +// headers within, or it could lead to unexpected behaviour. +// +// --- +// +// ShortLook-API.h +// +// Created by AppleBetas on 2018-05-18. +// Copyright © 2018 Dynastic Development. All rights reserved. +// + +#import +@class NCNotificationRequest, UNNotificationContent; + +/// A ShortLook-displayable notification representing a real user notification sent by an application to the system. +@interface DDUserNotification : NSObject +/// A custom notification title, separate from the application's title. +@property (nonatomic, retain, readonly) NSString *notificationTitle; + +/// A dictionary of any extra information included by ShortLook. +@property (nonatomic, retain) NSDictionary *userInfo; + +/// The system notification request that created this notification. +@property (nonatomic, readonly, retain) NCNotificationRequest *request; + +/// The user notification's content, sent by the application. +- (UNNotificationContent *)content; + +/// A dictionary of any extra information provided by the application sending the notification. +- (NSDictionary *)applicationUserInfo; + +/// The bundle identifier of the application this notification represents. +- (NSString *)senderIdentifier; +@end + +/// An object representing settings for the photo to be provided by a promise. +@interface DDNotificationContactPhotoSettings: NSObject +/// The background colour to show for the contact photo view if the provided image contains any transparency. +@property (nonatomic, retain) UIColor *backgroundColor; + +/// Whether or not ShortLook should automatically cache the returned image from your provider and use it for all future notifications with the same photo identifier and application. +@property (nonatomic, assign) BOOL usesCaching; +@end + +/// A promise representing a commitment to providing a contact icon for a notification. +@interface DDNotificationContactPhotoPromise: NSObject +/// An object holding the settings pertaining to the photo to be displayed. +@property (nonatomic, retain) DDNotificationContactPhotoSettings *settings; + +/// Whether or not this promise has already been resolved or rejected. +@property (nonatomic, readonly, assign) BOOL isComplete; + +// MARK: - Provider methods + +/// Resolve this promise with the provided image, notifying ShortLook that you have received your image. +/// - NOTE: This method should only be ran from within `addResolver:`. +- (void)resolveWithImage:(UIImage *)image; + +/// Reject this promise, notifying ShortLook that you failed to receive an image. +/// - NOTE: This method should only be ran from within `addResolver:`. +- (void)reject; +@end + +/// An offer to fulfill a promise representing a commitment to providing a contact icon for a notification. +@interface DDNotificationContactPhotoPromiseOffer: NSObject +/// A unique identifier for the photo that will be provided by this promise. +@property (nonatomic, readonly, retain) NSString *photoIdentifier; + +/// A string to replace the notification's title with, if it is required for your provider's context. Set to "" to remove the provided notification's title. +@property (nonatomic, retain) NSString *titleOverride; + +/// A string to replace the notification's subtitle with, if it is required for your provider's context. Set to "" to remove the provided notification's subtitle. +@property (nonatomic, retain) NSString *subtitleOverride; + +/// A string to replace the notification's body with, if it is required for your provider's context. Set to "" to remove the provided notification's body. +@property (nonatomic, retain) NSString *bodyOverride; + +/// Initialize a promise with the provided photo identifier. +- (instancetype)initWithPhotoIdentifier:(NSString *)photoIdentifier; + +/// Create a promise offer that will return the image at the provided URL, if needed. ++ (instancetype)offerDownloadingPromiseWithPhotoIdentifier:(NSString *)photoIdentifier fromURL:(NSURL *)url; + +/// Create a promise offer that will return the image at the provided URL, if needed, with custom settings. ++ (instancetype)offerDownloadingPromiseWithPhotoIdentifier:(NSString *)photoIdentifier fromURL:(NSURL *)url withSettings:(DDNotificationContactPhotoSettings *)settings; + +/// Create a promise offer that will instantly return the provided image. ++ (instancetype)offerInstantlyResolvingPromiseWithPhotoIdentifier:(NSString *)photoIdentifier image:(UIImage *)image; + +/// Create a promise offer that will instantly return the provided image with custom settings. ++ (instancetype)offerInstantlyResolvingPromiseWithPhotoIdentifier:(NSString *)photoIdentifier image:(UIImage *)image withSettings:(DDNotificationContactPhotoSettings *)settings; + +/// Add the block that will run if your image is needed (as it will not be in some cases, such as if your image is already cached by ShortLook). +/// If your provider does any long-running or asynchronous operations, they should be done using this method. +/// Any code run inside the provider block will be performed on a background thread. +- (void)fulfillWithBlock:(void (^)(DDNotificationContactPhotoPromise *promise))block; +@end + +/// An object that can provide contact photos for ShortLook notifications. +@protocol DDNotificationContactPhotoProviding +@required +/// Returns an offer to fulfill a promise to provide a contact photo for a notification. +- (DDNotificationContactPhotoPromiseOffer *)contactPhotoPromiseOfferForNotification:(DDUserNotification *)notification; +@end diff --git a/ViberContactPhotoProvider.h b/ViberContactPhotoProvider.h new file mode 100755 index 0000000..b729732 --- /dev/null +++ b/ViberContactPhotoProvider.h @@ -0,0 +1,5 @@ +#import "ShortLook-API.h" + +@interface ViberContactPhotoProvider : NSObject +- (DDNotificationContactPhotoPromiseOffer *)contactPhotoPromiseOfferForNotification:(DDUserNotification *)notification; +@end diff --git a/ViberContactPhotoProvider.m b/ViberContactPhotoProvider.m new file mode 100755 index 0000000..70543ce --- /dev/null +++ b/ViberContactPhotoProvider.m @@ -0,0 +1,36 @@ +#import +#import "FolderFinder.h" +#import "ViberContactPhotoProvider.h" + +@implementation ViberContactPhotoProvider + - (DDNotificationContactPhotoPromiseOffer *)contactPhotoPromiseOfferForNotification:(DDUserNotification *)notification { + NSString *containerPath = [FolderFinder findSharedFolder:@"group.viber.share.container"]; + NSString *databasePath = [NSString stringWithFormat:@"%@/com.viber/database/Contacts.data", containerPath]; + NSString *iconsPath = [NSString stringWithFormat:@"%@/com.viber/ViberIcons", containerPath]; + + NSString *senderMemberId = [notification.applicationUserInfo valueForKey:@"senderMemberId"]; + + const char *dbpath = [databasePath UTF8String]; + sqlite3 *_viberdb; + + if (sqlite3_open(dbpath, &_viberdb) == SQLITE_OK) { + const char *stmt = [[NSString stringWithFormat:@"SELECT ZICONID FROM ZMEMBER WHERE ZMEMBERID = '%@' AND ZICONSTATE = 'iconExist';", senderMemberId] UTF8String]; + sqlite3_stmt *statement; + + if (sqlite3_prepare_v2(_viberdb, stmt, -1, &statement, NULL) == SQLITE_OK) { + if (sqlite3_step(statement) == SQLITE_ROW) { + const unsigned char *result = sqlite3_column_text(statement, 0); + NSString *imageName = [NSString stringWithUTF8String:(char *)result]; + NSString *imageURL = [NSString stringWithFormat:@"%@/%@.jpg", iconsPath, imageName]; + UIImage *image = [UIImage imageWithContentsOfFile:imageURL]; + + return [NSClassFromString(@"DDNotificationContactPhotoPromiseOffer") offerInstantlyResolvingPromiseWithPhotoIdentifier:imageURL image:image]; + } + sqlite3_finalize(statement); + } + sqlite3_close(_viberdb); + } + + return nil; + } +@end diff --git a/control b/control new file mode 100755 index 0000000..ba74d70 --- /dev/null +++ b/control @@ -0,0 +1,9 @@ +Package: ch.marcoroth.shortlook.plugin.contact-photo.viber +Name: Viber Profile Pictures for ShortLook +Depends: mobilesubstrate, co.dynastic.ios.tweak.shortlook +Version: 1.0.0 +Architecture: iphoneos-arm +Description: Show Viber users' profile pictures in ShortLook when you receive a Viber notification! +Maintainer: Marco Roth +Author: Marco Roth +Section: Tweaks (ShortLook)