Skip to content

Commit

Permalink
1.1
Browse files Browse the repository at this point in the history
- added Download ability for BeReals
- completely rewritten the tweak
- show comment button by default
  • Loading branch information
yandevelop committed Apr 17, 2023
1 parent 735663f commit 2b156c5
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 45 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
TARGET := iphone:clang:latest:15.0
INSTALL_TARGET_PROCESSES = BeReal
ARCHS = arm64 arm64e

THEOS_PACKAGE_SCHEME = rootless
THEOS_DEVICE_IP = 192.168.102.61

export SYSROOT = $(THEOS)/sdks/iPhoneOS15.5.sdk

Expand Down
14 changes: 14 additions & 0 deletions Tweak.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

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
206 changes: 163 additions & 43 deletions Tweak.x
Original file line number Diff line number Diff line change
@@ -1,7 +1,93 @@
#include <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "Tweak.h"

static NSString *lateBeReal;
@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
Expand Down Expand Up @@ -35,53 +121,87 @@ static NSString *lateBeReal;
}
%end

%hook UIView
- (void)layoutSubviews {
%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;
}

// Get the current View Controller
UIResponder *responder = self;
while (responder && ![responder isKindOfClass:[UIViewController class]]) {
responder = [responder nextResponder];
}
UIViewController *vc = (UIViewController *)responder;

// Remove the "Post to view" View
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:objc_getClass("_TtC6BeReal20FeedPostCellBlurView")]) {
[subview removeFromSuperview];
break;
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

for (UIView *view in self.subviews) {
if ([view isKindOfClass:objc_getClass("UIImageView")] && [view.superview isKindOfClass:objc_getClass("BeReal.DoublePhotoView")]) {
for (UIButton *button in view.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
return;
%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];
}

// Adding the "Post a Late BeReal." button but only for the Feed Friends View
if (![vc isKindOfClass:objc_getClass("_TtC6BeReal25FeedFriendsViewController")] || (vc == nil)) return;
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.backgroundColor = [UIColor colorWithWhite: 1.0 alpha: 0.9];
button.layer.cornerRadius = 8;
button.layer.masksToBounds = YES;
button.tintColor = [UIColor blackColor];
NSString *title = lateBeReal ?: @"Post a Late BeReal.";
[button setTitle:title forState:UIControlStateNormal];
button.titleLabel.font = [UIFont systemFontOfSize:13.0 weight:UIFontWeightBold];
[button sizeToFit];
CGRect frame = button.frame;
frame.size.width += 20;
button.frame = CGRectMake(view.frame.size.width - frame.size.width - 10, 11.7, frame.size.width, 36);
[button addTarget:vc action:@selector(emptyViewTakeBeReal) forControlEvents:UIControlEventTouchUpInside];
[view addSubview:button];
break;
}
}
}
}

%end

// Bypass screenshot detection?
Expand All @@ -102,6 +222,6 @@ static NSString *lateBeReal;

%ctor {
NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.bereal.BRAssets"];
lateBeReal = [bundle localizedStringForKey:@"timelineCell_blurredView_button" value:@"" table:@"Localizable"];
%init(CameraViewController = objc_getClass("_TtC6BeReal20CameraViewController"));
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"));
}
2 changes: 1 addition & 1 deletion control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: com.yan.bea
Name: Bea
Version: 1.0
Version: 1.1
Architecture: iphoneos-arm64
Description: Lightweight BeReal. enhancement tweak.
Maintainer: yan
Expand Down

0 comments on commit 2b156c5

Please sign in to comment.