diff --git a/Makefile b/Makefile index c0371da..c2b3f97 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -TARGET := iphone:clang:latest:15.0 +TARGET := iphone:clang:latest:14.0 INSTALL_TARGET_PROCESSES = BeReal ARCHS = arm64 arm64e - -THEOS_PACKAGE_SCHEME = rootless +FINALPACKAGE = 1 +PACKAGE_VERSION = 1.1.2 export SYSROOT = $(THEOS)/sdks/iPhoneOS15.5.sdk @@ -10,7 +10,7 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = Bea -Bea_FILES = Tweak.x +Bea_FILES = Tweak/Tweak.x Bea_CFLAGS = -fobjc-arc Bea_FRAMEWORKS = UIKit diff --git a/Tweak.x b/Tweak.x deleted file mode 100644 index 3c728f4..0000000 --- a/Tweak.x +++ /dev/null @@ -1,227 +0,0 @@ -#import "Tweak.h" - -@implementation BeaDownloader -+ (void)downloadImage:(id)sender { - UIButton *button = (UIButton *)sender; - UIView *tableContentView = button.superview.superview; - UIImageView *imageView = nil; - for (UIView *view in tableContentView.subviews) { - if ([NSStringFromClass([view class]) isEqualToString:@"BeReal.DoublePhotoView"]) { - imageView = view.subviews.firstObject; - break; - } - } - if (imageView) { - UIImage *imageToSave = imageView.image; - UIImageWriteToSavedPhotosAlbum(imageToSave, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)button); - } -} - -+ (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { - if (error) { - NSLog(@"Error saving image: %@", error.localizedDescription); - } else { - UIButton *button = (__bridge UIButton *)contextInfo; - UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:22]; - UIImage *checkmarkImage = [UIImage systemImageNamed:@"checkmark.circle.fill" withConfiguration:config]; - [UIView transitionWithView:button duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ - [button setImage:checkmarkImage forState:UIControlStateNormal]; - [button setEnabled:NO]; - [button.imageView setTintColor:[UIColor colorWithRed:122.0/255.0 green:255.0/255.0 blue:108.0/255.0 alpha:1.0]];} completion:nil]; - - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - UIImage *downloadImage = [UIImage systemImageNamed:@"arrow.down.circle.fill" withConfiguration:config]; - [UIView transitionWithView:button duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ - [button setImage:downloadImage forState:UIControlStateNormal]; - [button.imageView setTintColor:[UIColor whiteColor]]; - [button setEnabled:YES]; - } completion:nil]; - }); - } -} -@end - -@implementation BeaButton -+ (instancetype)downloadButton { - BeaButton *downloadButton = [BeaButton buttonWithType:UIButtonTypeRoundedRect]; - [downloadButton setTitle:@"" forState:UIControlStateNormal]; - - UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:22]; - UIImage *downloadImage = [UIImage systemImageNamed:@"arrow.down.circle.fill" withConfiguration:config]; - downloadImage = [downloadImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - - downloadButton.layer.shadowColor = [[UIColor blackColor] CGColor]; - downloadButton.layer.shadowOffset = CGSizeMake(0, 0); - downloadButton.layer.shadowRadius = 3; - downloadButton.layer.shadowOpacity = 0.7; - - [downloadButton setImage:downloadImage forState:UIControlStateNormal]; - [downloadButton setTintColor:[UIColor whiteColor]]; - [downloadButton sizeToFit]; - downloadButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; - downloadButton.translatesAutoresizingMaskIntoConstraints = NO; - [downloadButton addTarget:[BeaDownloader class] action:@selector(downloadImage:) forControlEvents:UIControlEventTouchUpInside]; - - return downloadButton; -} - -+ (instancetype)lateBeRealButton:(id)target { - BeaButton *lateBeRealButton = [BeaButton buttonWithType:UIButtonTypeSystem]; - NSString *title = lateBeRealTitle ?: @"Post a Late BeReal."; - [lateBeRealButton setTitle:title forState:UIControlStateNormal]; - lateBeRealButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent: 0.9]; - lateBeRealButton.layer.cornerRadius = 8; - lateBeRealButton.layer.masksToBounds = YES; - lateBeRealButton.tintColor = [UIColor blackColor]; - lateBeRealButton.titleLabel.font = [UIFont systemFontOfSize:13.0 weight:UIFontWeightBold]; - [lateBeRealButton sizeToFit]; - - [NSLayoutConstraint activateConstraints:@[[lateBeRealButton.titleLabel.leadingAnchor constraintEqualToAnchor:lateBeRealButton.leadingAnchor constant: 12], - [lateBeRealButton.titleLabel.topAnchor constraintEqualToAnchor:lateBeRealButton.topAnchor constant:10], - [lateBeRealButton.titleLabel.bottomAnchor constraintEqualToAnchor:lateBeRealButton.bottomAnchor constant:-10], - [lateBeRealButton.heightAnchor constraintEqualToAnchor:lateBeRealButton.titleLabel.heightAnchor constant:20]]]; - - [lateBeRealButton addTarget:target action:@selector(emptyViewTakeBeReal) forControlEvents:UIControlEventTouchUpInside]; - - lateBeRealButton.translatesAutoresizingMaskIntoConstraints = NO; - - return lateBeRealButton; -} -@end - -%hook CameraViewController -// Display the close button even if not finished taking a photo -- (void)viewDidLoad { - %orig; - UIViewController *viewController = (UIViewController *)self; - for (UIView *subview in viewController.view.subviews) { - if ([subview isKindOfClass:[UIButton class]]) { - if (subview.hidden == YES) { - subview.hidden = NO; - break; - } - } - } -} - -// Don't dismiss if the countdown of 2 minutes finishes -- (void)countdownFinished { - UIViewController *viewController = (UIViewController *)self; - for (UILabel *countdownLabel in viewController.view.subviews) { - if ([countdownLabel isKindOfClass:objc_getClass("_TtC14CountdownLabel14CountdownLabel")]) { - countdownLabel.text = @"Take your time."; - countdownLabel.textColor = [UIColor whiteColor]; - [UIView animateWithDuration:0.4 delay:10.0 options:UIViewAnimationOptionCurveEaseOut animations:^{ - countdownLabel.alpha = 0.0; - } completion:^(BOOL finished) { - [countdownLabel removeFromSuperview]; - }]; - } - } -} -%end - -%hook FriendsViewController -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { - %orig; - if ([cell isKindOfClass:NSClassFromString(@"BeReal.FeedPostCell")]) { - for (UIView *subview in cell.contentView.subviews) { - if ([subview isKindOfClass:objc_getClass("_TtC6BeReal20FeedPostCellBlurView")]) { - if ([subview.superview.subviews[2] isKindOfClass:objc_getClass("_TtC6BeReal15DoublePhotoView")]) { - // This gets set to hidden if the user already has taken a BeReal, so we won't display a button if that is the case. - if (subview.hidden == YES) continue; - UIView *photoView = subview.superview.subviews[2]; - BeaButton *lateBeRealButton = [BeaButton lateBeRealButton:self]; - [photoView addSubview:lateBeRealButton]; - [NSLayoutConstraint activateConstraints:@[[lateBeRealButton.trailingAnchor constraintEqualToAnchor:photoView.trailingAnchor constant:-11.6], - [lateBeRealButton.bottomAnchor constraintEqualToAnchor:photoView.topAnchor constant:47.333] - ]]; - [subview removeFromSuperview]; - } - continue; - } - - if ([subview isKindOfClass:[UIStackView class]]) { - // Unhide the comment button - if (subview.subviews[1].hidden == YES) subview.subviews[1].hidden = NO; - for (UIButton *button in subview.subviews) { - if ([button isKindOfClass:[BeaButton class]]) return; - } - BeaButton *downloadButton = [BeaButton downloadButton]; - [(UIStackView *)subview insertArrangedSubview:downloadButton atIndex:0]; - } - } - } -} -%end - -%hook DoublePhotoView -// Hide the buttons on long press -// (somehow i can not get an instance of these in viewDidLoad, since declaring an interface does not work with swift classes) -- (void)onMainImagePressed:(UILongPressGestureRecognizer *)gestureRecognizer { - %orig; - UIView *view = (UIView *)self; - // since DoublePhotoView is reused, the superviews subviews can sometimes only have one entry and this will crash the app - // we thus have to check if the views superview is UITableViewCellContentView to ensure that we are in Discovery or FeedFriends Controller - if (![view.superview isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) return; - //if (![view.superview.subviews[3].subviews.lastObject isKindOfClass:[BeaButton class]]) return; - - BeaButton *lateBeRealButton = view.subviews.lastObject; - BeaButton *downloadButton = view.superview.subviews[3].subviews.lastObject; - if (gestureRecognizer.state == 1) { - [UIView animateWithDuration:0.2 animations:^{ - lateBeRealButton.alpha = 0; - downloadButton.alpha = 0; - }]; - } else if (gestureRecognizer.state == 3) { - [UIView animateWithDuration:0.2 animations:^{ - lateBeRealButton.alpha = 1; - downloadButton.alpha = 1; - }]; - } -} -%end - -%hook DiscoveryViewController -- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { - if ([cell isKindOfClass:NSClassFromString(@"BeReal.FeedPostCell")]) { - for (UIView *subview in cell.contentView.subviews) { - if ([subview isKindOfClass:objc_getClass("_TtC6BeReal20FeedPostCellBlurView")]) { - [subview removeFromSuperview]; - continue; - } - if ([subview isKindOfClass:[UIStackView class]]) { - if (subview.subviews[1].hidden == YES) subview.subviews[1].hidden = NO; - for (UIButton *button in subview.subviews) { - if ([button isKindOfClass:[BeaButton class]]) return; - } - BeaButton *downloadButton = [BeaButton downloadButton]; - [(UIStackView *)subview insertArrangedSubview:downloadButton atIndex:0]; - } - } - } -} - -%end - -// Bypass screenshot detection? -%hook UIScreen -- (BOOL)isCaptured { - return NO; -} -%end - -%hook NSNotificationCenter -- (void)addObserver:(id)arg0 selector:(SEL)arg1 name:(NSNotificationName)arg2 object:(id)arg3 { - if (arg2 == UIApplicationUserDidTakeScreenshotNotification) { - return; - } - %orig; -} -%end - -%ctor { - NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.bereal.BRAssets"]; - lateBeRealTitle = [bundle localizedStringForKey:@"timelineCell_blurredView_button" value:@"" table:@"Localizable"]; - %init(CameraViewController = objc_getClass("_TtC6BeReal20CameraViewController"), FriendsViewController = objc_getClass("_TtC6BeReal25FeedFriendsViewController"), DiscoveryViewController = objc_getClass("_TtC6BeReal18FeedViewController"), DoublePhotoView = objc_getClass("BeReal.DoublePhotoView")); -} \ No newline at end of file diff --git a/Tweak/Tweak.h b/Tweak/Tweak.h new file mode 100644 index 0000000..77638ff --- /dev/null +++ b/Tweak/Tweak.h @@ -0,0 +1,5 @@ +#import +#import +#import "../Utilities/BeaUtilities.m" + +BOOL isUnblurred = NO; \ No newline at end of file diff --git a/Tweak/Tweak.x b/Tweak/Tweak.x new file mode 100644 index 0000000..05f4544 --- /dev/null +++ b/Tweak/Tweak.x @@ -0,0 +1,148 @@ +#import "Tweak.h" + +%hook DoublePhotoView +- (void)layoutSubviews { + %orig; + + UIView *doublePhotoView = (UIView *)self; + if ([doublePhotoView.subviews.lastObject isKindOfClass:[BeaButton class]] || doublePhotoView.frame.size.width < 180) return; + + UIResponder *responder = self; + while (responder && ![responder isKindOfClass:[UIViewController class]]) { + responder = [responder nextResponder]; + } + UIViewController *vc = (UIViewController *)responder; + + if (![vc isKindOfClass:objc_getClass("BeReal.SUIFeedViewController")]) return; + + BeaButton *downloadButton = [BeaButton downloadButton]; + [doublePhotoView addSubview:downloadButton]; + downloadButton.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [downloadButton.trailingAnchor constraintEqualToAnchor:doublePhotoView.trailingAnchor constant:-11.6], + [downloadButton.bottomAnchor constraintEqualToAnchor:doublePhotoView.topAnchor constant:47.333] + ]]; +} +%end + +%hook UIAlertController +- (void)viewDidLoad { + UIAlertController *alertController = (UIAlertController *)self; + %orig; + + if (![alertController.presentingViewController isKindOfClass:objc_getClass("BeReal.NavigationController")]) return %orig; + UIAlertAction *thirdAction = alertController.actions[2]; + id block = [thirdAction valueForKey:@"_handler"]; + if (block) { + void (^handler)(UIAlertAction *) = block; + handler(thirdAction); + isUnblurred = YES; + } +} + +- (void)viewWillAppear:(id)arg1 { + %orig; + if ([self.presentingViewController isKindOfClass:objc_getClass("BeReal.NavigationController")] || [self.presentingViewController isKindOfClass:[UINavigationController class]]) { + // Set the whole view to hidden + self.view.superview.hidden = YES; + + // Dismiss the UIAlertController automatically + [self dismissViewControllerAnimated:NO completion:nil]; + } +} +%end + +%hook HomeViewController +- (void)viewDidLoad { + %orig; + UIViewController *homeViewController = (UIViewController *)self; + + if (!isUnblurred && [homeViewController respondsToSelector:@selector(openDebugMenu)] && [homeViewController.childViewControllers.lastObject isKindOfClass:objc_getClass("BeReal.SUIFeedViewController")]) { + [homeViewController performSelector:@selector(openDebugMenu)]; + + NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + NSComparisonResult result = [version compare:@"1.1.2" options:NSNumericSearch]; + if (result == NSOrderedAscending) { + BeaAlertView *alertView = [[BeaAlertView alloc] init]; + [homeViewController.view addSubview:alertView]; + } + } +} +%end + +%hook SwiftView +- (void)layoutSubviews { + %orig; + UIView *s = (UIView *)self; + // removes the eye view and the post late button from the blurred view + for (UIView *v in s.subviews) { + if (v.frame.size.width <= 48 && v.frame.size.width > 32) { + v.hidden = YES; + } + if (([v isKindOfClass:objc_getClass("SwiftUI._UIGraphicsView")] || [v isKindOfClass:[UIView class]]) && v.frame.size.width > 350 && v.subviews.count == 0) { + v.hidden = YES; + } + } +} +%end + +%hook CALayer +- (void)setFilters:(NSArray *)filter { + return; +} +%end + +%hook SettingsViewController +- (void)viewDidLoad { + %orig; + + UIViewController *vc = (UIViewController *)self; + UITableView *labelView = vc.view.subviews.firstObject; + + UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, labelView.frame.size.width, 50)]; + headerLabel.text = @"Bea 1.1.2\nmade with ❤️ by yan"; + headerLabel.numberOfLines = 0; + headerLabel.font = [UIFont fontWithName:@"Inter" size:10]; + headerLabel.textAlignment = NSTextAlignmentCenter; + labelView.tableHeaderView = headerLabel; +} +%end + +%hook UIScreen +- (BOOL)isCaptured { + return NO; +} +%end + +%hook NSNotificationCenter +- (void)addObserver:(id)arg0 selector:(SEL)arg1 name:(NSNotificationName)arg2 object:(id)arg3 { + if (arg2 == UIApplicationUserDidTakeScreenshotNotification) { + return; + } + %orig; +} +%end + +// return a nil string so the BeReal photo view is clear :) +%hook NSBundle +- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName { + if ([self.bundleIdentifier isEqualToString:@"com.bereal.BRAssets"]) { + if ([key isEqualToString:@"timelineCell_blurredView_button"] || [key isEqualToString:@"timelineCell_blurredView_description_myFriends"] || [key isEqualToString:@"timelineCell_blurredView_title"]) { + return nil; + } + } + return %orig; +} +%end + + +%ctor { + %init(HomeViewController = objc_getClass("_TtC6BeReal18HomeViewController"), + DoublePhotoView = objc_getClass("RealComponents.DoublePhotoView"), + SettingsViewController = objc_getClass("_TtC6BeReal22SettingsViewController"), + SwiftView = objc_getClass("_TtCC7SwiftUI17HostingScrollView22PlatformGroupContainer")); + + // Enable dualCamera? + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"debug_dualCameraPreviewEnabled"]; + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"debug_developerModeEnabled"]; +} \ No newline at end of file diff --git a/Tweak.h b/Utilities/BeaUtilities.h similarity index 64% rename from Tweak.h rename to Utilities/BeaUtilities.h index 7cbad4d..3b713bf 100644 --- a/Tweak.h +++ b/Utilities/BeaUtilities.h @@ -1,14 +1,13 @@ -#import -#import - -static NSString *lateBeRealTitle; - @interface BeaButton : UIButton + (instancetype)downloadButton; -+ (instancetype)lateBeRealButton:(id)target; @end @interface BeaDownloader : NSObject + (void)downloadImage:(id)sender; + (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo; +@end + +@interface BeaAlertView : UIView +- (void)updateButtonTapped; +- (void)closeButtonTapped; @end \ No newline at end of file diff --git a/Utilities/BeaUtilities.m b/Utilities/BeaUtilities.m new file mode 100644 index 0000000..7833618 --- /dev/null +++ b/Utilities/BeaUtilities.m @@ -0,0 +1,144 @@ +#import "BeaUtilities.h" + +@implementation BeaDownloader ++ (void)downloadImage:(id)sender { + UIButton *button = (UIButton *)sender; + UIView *tableContentView = button.superview.superview; + UIImageView *imageView = nil; + for (UIView *view in tableContentView.subviews) { + if ([NSStringFromClass([view class]) isEqualToString:@"RealComponents.DoublePhotoView"]) { + imageView = view.subviews.firstObject; + break; + } + } + if (imageView) { + UIImage *imageToSave = imageView.image; + UIImageWriteToSavedPhotosAlbum(imageToSave, self, @selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)button); + } +} + ++ (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { + if (error) { + NSLog(@"Error saving image: %@", error.localizedDescription); + } else { + UIButton *button = (__bridge UIButton *)contextInfo; + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:19]; + UIImage *checkmarkImage = [UIImage systemImageNamed:@"checkmark.circle.fill" withConfiguration:config]; + [UIView transitionWithView:button duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ + [button setImage:checkmarkImage forState:UIControlStateNormal]; + [button setEnabled:NO]; + [button.imageView setTintColor:[UIColor colorWithRed:122.0/255.0 green:255.0/255.0 blue:108.0/255.0 alpha:1.0]];} completion:nil]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + UIImage *downloadImage = [UIImage systemImageNamed:@"arrow.down.circle.fill" withConfiguration:config]; + [UIView transitionWithView:button duration:0.2 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ + [button setImage:downloadImage forState:UIControlStateNormal]; + [button.imageView setTintColor:[UIColor whiteColor]]; + [button setEnabled:YES]; + } completion:nil]; + }); + } +} +@end + +@implementation BeaButton ++ (instancetype)downloadButton { + BeaButton *downloadButton = [BeaButton buttonWithType:UIButtonTypeRoundedRect]; + [downloadButton setTitle:@"" forState:UIControlStateNormal]; + + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:19]; + UIImage *downloadImage = [UIImage systemImageNamed:@"arrow.down.circle.fill" withConfiguration:config]; + downloadImage = [downloadImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + + downloadButton.layer.shadowColor = [[UIColor blackColor] CGColor]; + downloadButton.layer.shadowOffset = CGSizeMake(0, 0); + downloadButton.layer.shadowRadius = 3; + downloadButton.layer.shadowOpacity = 0.5; + + [downloadButton setImage:downloadImage forState:UIControlStateNormal]; + [downloadButton setTintColor:[UIColor whiteColor]]; + [downloadButton sizeToFit]; + downloadButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; + downloadButton.translatesAutoresizingMaskIntoConstraints = NO; + [downloadButton addTarget:[BeaDownloader class] action:@selector(downloadImage:) forControlEvents:UIControlEventTouchUpInside]; + + return downloadButton; +} +@end + +@implementation BeaAlertView +- (instancetype)init { + self = [super init]; + if (self) { + [self setupAlertView]; + } + return self; +} + +- (void)setupAlertView { + self.frame = [UIScreen mainScreen].bounds; + + UIView *shadeView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)]; + shadeView.backgroundColor = [UIColor colorWithWhite:0.0 alpha: 0.5]; + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeButtonTapped)]; + [shadeView addGestureRecognizer:tapGesture]; + [self addSubview:shadeView]; + + UIView *box = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 340, 240)]; + box.backgroundColor = [UIColor blackColor]; + box.center = CGPointMake(CGRectGetMidX([UIScreen mainScreen].bounds), CGRectGetMidY([UIScreen mainScreen].bounds)); + box.layer.cornerRadius = 8.0; + [self addSubview:box]; + + UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 30, CGRectGetWidth(box.frame), 30)]; + titleLabel.text = @"Version unsupported"; + titleLabel.textColor = [UIColor whiteColor]; + titleLabel.font = [UIFont fontWithName:@"Inter" size:24]; + titleLabel.textAlignment = NSTextAlignmentCenter; + + UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, CGRectGetMaxY(titleLabel.frame) + 5, CGRectGetWidth(box.frame) - 60, 85)]; + messageLabel.text = @"The current app version is no longer supported.\nUpdate the app or downgrade the tweak to continue using it."; + messageLabel.textAlignment = NSTextAlignmentCenter; + messageLabel.numberOfLines = 0; + messageLabel.font = [UIFont fontWithName:@"Inter" size:15]; + + UIButton *updateButton = [UIButton buttonWithType:UIButtonTypeSystem]; + updateButton.frame = CGRectMake(40, CGRectGetMaxY(messageLabel.frame) + 20, box.frame.size.width - 80, 40); + updateButton.layer.cornerRadius = 6.0; + updateButton.titleLabel.font = [UIFont fontWithName:@"Inter" size:16]; + updateButton.backgroundColor = [UIColor whiteColor]; + [updateButton setTitle:@"Update" forState:UIControlStateNormal]; + [updateButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [updateButton addTarget:self action:@selector(updateButtonTapped) forControlEvents:UIControlEventTouchUpInside]; + + UIButton *closeButton = [UIButton buttonWithType:UIButtonTypeSystem]; + closeButton.frame = CGRectMake(box.frame.size.width - 44, 6, 40, 40); + closeButton.titleLabel.font = [UIFont fontWithName:@"Inter" size:16]; + [closeButton setTitle:@"✕" forState:UIControlStateNormal]; + [closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [closeButton addTarget:self action:@selector(closeButtonTapped) forControlEvents:UIControlEventTouchUpInside]; + + [box addSubview:closeButton]; + [box addSubview:updateButton]; + [box addSubview:titleLabel]; + [box addSubview:messageLabel]; +} + +- (void)updateButtonTapped { + NSString *appStoreLink = @"https://apps.apple.com/de/app/id1459645446"; + NSURL *appStoreURL = [NSURL URLWithString:appStoreLink]; + + if ([[UIApplication sharedApplication] canOpenURL:appStoreURL]) { + [[UIApplication sharedApplication] openURL:appStoreURL options:@{} completionHandler:nil]; + } +} + +- (void)closeButtonTapped { + [UIView animateWithDuration:0.3 animations:^{ + self.alpha = 0.0; + } completion:^(BOOL finished) { + [self removeFromSuperview]; + }]; +} + +@end \ No newline at end of file diff --git a/control b/control index 5bdd301..0c91688 100644 --- a/control +++ b/control @@ -1,7 +1,7 @@ Package: com.yan.bea Name: Bea -Version: 1.1 -Architecture: iphoneos-arm64 +Version: 1.1.2 +Architecture: iphoneos-arm Description: Lightweight BeReal. enhancement tweak. Maintainer: yan Author: yan