Skip to content

Commit

Permalink
update 4.1
Browse files Browse the repository at this point in the history
- Fix downloading video without sound using FFmpeg.
- Add app icon changer (works just for JB and Trollstore)
- Remove unnecessarily features.
  • Loading branch information
BandarHL committed Dec 8, 2023
1 parent 0c8aea8 commit 92ed4dc
Show file tree
Hide file tree
Showing 17 changed files with 436 additions and 74 deletions.
Binary file modified 1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified 2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified 3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified 4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
192 changes: 192 additions & 0 deletions BHTwitter/AppIcon/BHAppIconViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
//
// BHAppIconViewController.swift
// BHTwitter
//
// Created by Bandar Alruwaili
//

import UIKit

struct AppIconItem: Hashable, Codable {
internal init(id: UUID = UUID(), imageName: String, settingsImageName: String, isPrimaryIcon: Bool) {
self.id = id
self.imageName = imageName
self.settingsImageName = settingsImageName
self.isPrimaryIcon = isPrimaryIcon
}

let id: UUID
let imageName: String
let settingsImageName: String
let isPrimaryIcon: Bool
}

class AppIconCell: UICollectionViewCell {
static let reuseIdentifier = "appicon"

var imageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 22
return imageView
}()
let checkIMG: UIImageView = {
let imageView = UIImageView()
imageView.image = .init(systemName: "circle")
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()

override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(imageView)
self.addSubview(checkIMG)

NSLayoutConstraint.activate([
imageView.topAnchor.constraint(equalTo: self.topAnchor),
imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
imageView.heightAnchor.constraint(equalToConstant: 98),
imageView.widthAnchor.constraint(equalToConstant: 98),

checkIMG.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 12),
checkIMG.centerXAnchor.constraint(equalTo: self.centerXAnchor),
checkIMG.widthAnchor.constraint(equalToConstant: 24),
checkIMG.heightAnchor.constraint(equalToConstant: 24),
])
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class BHAppIconViewController: UIViewController {

lazy var appIconCollectionView: UICollectionView = {
let collection = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collection.contentInsetAdjustmentBehavior = .always
collection.register(AppIconCell.self, forCellWithReuseIdentifier: AppIconCell.reuseIdentifier)
collection.delegate = self
collection.dataSource = self
collection.translatesAutoresizingMaskIntoConstraints = false
return collection
}()

var headerLabel: UILabel = {
let label = UILabel()
label.text = BHTBundle.shared().localizedString(forKey: "APP_ICON_HEADER_TITLE")
label.textColor = .secondaryLabel
label.numberOfLines = 0
label.font = .systemFont(ofSize: 15)
label.textAlignment = .justified
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()

var icons = [AppIconItem]() {
didSet {
appIconCollectionView.reloadData()
}
}

override func viewDidLoad() {
super.viewDidLoad()
setupAppIcons()
self.navigationController?.navigationBar.prefersLargeTitles = false
self.view.backgroundColor = .systemBackground
self.view.addSubview(headerLabel)
self.view.addSubview(appIconCollectionView)

NSLayoutConstraint.activate([
headerLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
headerLabel.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16),
headerLabel.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16),

appIconCollectionView.topAnchor.constraint(equalTo: self.headerLabel.bottomAnchor),
appIconCollectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
appIconCollectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
appIconCollectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
}

func setupAppIcons() {
let appBundle = Bundle.main
let CFBundleIcons = appBundle.object(forInfoDictionaryKey: "CFBundleIcons") as! Dictionary<String, Any>
let CFBundlePrimaryIcon = CFBundleIcons["CFBundlePrimaryIcon"] as! Dictionary<String, Any>
let primaryIcon = CFBundlePrimaryIcon["CFBundleIconName"] as! String
let CFBundleAlternateIcons = CFBundleIcons["CFBundleAlternateIcons"] as! Dictionary<String, Any>

icons.append(AppIconItem(imageName: primaryIcon, settingsImageName: "Icon-Production-settings", isPrimaryIcon: true))

for (key, _) in CFBundleAlternateIcons {
icons.append(AppIconItem(imageName: key, settingsImageName: "\(key)-settings", isPrimaryIcon: false))
}
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
appIconCollectionView.collectionViewLayout.invalidateLayout()
super.viewWillTransition(to: size, with: coordinator)
}
}

extension BHAppIconViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return icons.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AppIconCell.reuseIdentifier, for: indexPath) as! AppIconCell
let currCell = self.icons[indexPath.row]
cell.imageView.image = UIImage(named: currCell.settingsImageName)

if let alternateIconName = UIApplication.shared.alternateIconName {
if currCell.imageName == alternateIconName {
collectionView.visibleCells.forEach { cell in
guard let iconCell = cell as? AppIconCell else {return}
iconCell.checkIMG.image = .init(systemName: "circle")
}
cell.checkIMG.image = .init(systemName: "checkmark.circle")
}
} else if currCell.isPrimaryIcon {
collectionView.visibleCells.forEach { cell in
guard let iconCell = cell as? AppIconCell else {return}
iconCell.checkIMG.image = .init(systemName: "circle")
}
cell.checkIMG.image = .init(systemName: "checkmark.circle")
}

return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let iconItem = self.icons[indexPath.row]
collectionView.visibleCells.forEach { cell in
guard let iconCell = cell as? AppIconCell else {return}
iconCell.checkIMG.image = .init(systemName: "circle")
}
guard let currCell = collectionView.cellForItem(at: indexPath) as? AppIconCell else {return}
UIApplication.shared.setAlternateIconName(iconItem.isPrimaryIcon ? nil : iconItem.imageName) { err in
if err == nil {
currCell.checkIMG.image = .init(systemName: "checkmark.circle")
}
}
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 10
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 98, height: 136)
}
}
51 changes: 42 additions & 9 deletions BHTwitter/BHDownloadInlineButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#import "BHDownloadInlineButton.h"
#import "Colours.h"
#import "BHTBundle.h"
#import <ffmpegkit/FFmpegKit.h>

@interface BHDownloadInlineButton () <BHDownloadDelegate>
@property (nonatomic, strong) JGProgressHUD *hud;
Expand All @@ -29,6 +30,8 @@ - (void)statusDidUpdate:(id)arg1 options:(NSUInteger)arg2 displayTextOptions:(NS
[self setTintColor:UIColor.whiteColor];
} else if ([self.delegate.delegate isKindOfClass:objc_getClass("T1ImmersiveExploreCardView")]) {
[self setTintColor:UIColor.whiteColor];
} else if ([self.delegate.delegate isKindOfClass:objc_getClass("T1TwitterSwift.ImmersiveExploreCardViewHelper")]) {
[self setTintColor:UIColor.whiteColor];
} else {
[self setTintColor:[UIColor colorFromHexString:@"6D6E70"]];
}
Expand Down Expand Up @@ -67,26 +70,35 @@ - (void)DownloadHandler:(UIButton *)sender {
[actions addObject:title];
NSMutableArray *innerActions = [[NSMutableArray alloc] init];
[innerActions addObject:title];


if ([self.delegate.delegate isKindOfClass:objc_getClass("T1SlideshowStatusView")]) {
T1SlideshowStatusView *selectedMedia = self.delegate.delegate;

for (TFSTwitterEntityMediaVideoVariant *video in selectedMedia.media.videoInfo.variants) {
if ([video.contentType isEqualToString:@"video/mp4"]) {

TFNActionItem *option = [objc_getClass("TFNActionItem") actionItemWithTitle:[BHTManager getVideoQuality:video.url] imageName:@"arrow_down_circle_stroke" action:^{
BHDownload *dwManager = [[BHDownload alloc] init];
[dwManager downloadFileWithURL:[NSURL URLWithString:video.url]];
[dwManager setDelegate:self];

if (![BHTManager DirectSave]) {
self.hud = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
self.hud.textLabel.text = [[BHTBundle sharedBundle] localizedStringForKey:@"PROGRESS_DOWNLOADING_STATUS_TITLE"];
[self.hud showInView:topMostController().view];
}
}];


[actions addObject:option];
}

if ([video.contentType isEqualToString:@"application/x-mpegURL"]) {
TFNActionItem *option = [objc_getClass("TFNActionItem") actionItemWithTitle:[[BHTBundle sharedBundle] localizedStringForKey:@"FFMPEG_DOWNLOAD_OPTION_TITLE"] imageName:@"arrow_down_circle_stroke" action:^{
self.hud = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
TFNMenuSheetViewController *alert2 = [BHTManager newFFmpegDownloadSheet:[NSURL URLWithString:video.url] withProgressView:self.hud];
[alert2 tfnPresentedCustomPresentFromViewController:topMostController() animated:YES completion:nil];
}];

[actions addObject:option];
}
}
Expand Down Expand Up @@ -115,12 +127,22 @@ - (void)DownloadHandler:(UIButton *)sender {

[innerActions addObject:innerOption];
}

if ([video.contentType isEqualToString:@"application/x-mpegURL"]) {
TFNActionItem *option = [objc_getClass("TFNActionItem") actionItemWithTitle:[[BHTBundle sharedBundle] localizedStringForKey:@"FFMPEG_DOWNLOAD_OPTION_TITLE"] imageName:@"arrow_down_circle_stroke" action:^{
self.hud = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
TFNMenuSheetViewController *alert2 = [BHTManager newFFmpegDownloadSheet:[NSURL URLWithString:video.url] withProgressView:self.hud];
[alert2 tfnPresentedCustomPresentFromViewController:topMostController() animated:YES completion:nil];
}];

[innerActions addObject:option];
}
}

TFNMenuSheetViewController *innerAlert = [[objc_getClass("TFNMenuSheetViewController") alloc] initWithActionItems:[NSArray arrayWithArray:innerActions]];
[innerAlert tfnPresentedCustomPresentFromViewController:topMostController() animated:YES completion:nil];
}];

[actions addObject:option];
}
}];
Expand All @@ -132,14 +154,23 @@ - (void)DownloadHandler:(UIButton *)sender {
BHDownload *dwManager = [[BHDownload alloc] init];
[dwManager downloadFileWithURL:[NSURL URLWithString:video.url]];
[dwManager setDelegate:self];

if (![BHTManager DirectSave]) {
self.hud = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
self.hud.textLabel.text = [[BHTBundle sharedBundle] localizedStringForKey:@"PROGRESS_DOWNLOADING_STATUS_TITLE"];
[self.hud showInView:topMostController().view];
}
}];


[actions addObject:option];
}
if ([video.contentType isEqualToString:@"application/x-mpegURL"]) {
TFNActionItem *option = [objc_getClass("TFNActionItem") actionItemWithTitle:[[BHTBundle sharedBundle] localizedStringForKey:@"FFMPEG_DOWNLOAD_OPTION_TITLE"] imageName:@"arrow_down_circle_stroke" action:^{
self.hud = [JGProgressHUD progressHUDWithStyle:JGProgressHUDStyleDark];
TFNMenuSheetViewController *alert2 = [BHTManager newFFmpegDownloadSheet:[NSURL URLWithString:video.url] withProgressView:self.hud];
[alert2 tfnPresentedCustomPresentFromViewController:topMostController() animated:YES completion:nil];
}];

[actions addObject:option];
}
}
Expand All @@ -150,6 +181,8 @@ - (void)DownloadHandler:(UIButton *)sender {
[alert tfnPresentedCustomPresentFromViewController:topMostController() animated:YES completion:nil];
}



- (void)setTouchInsets:(UIEdgeInsets)arg1 {
if ([self.delegate.delegate isKindOfClass:objc_getClass("T1StandardStatusInlineActionsViewAdapter")]) {
[self setImageEdgeInsets:arg1];
Expand Down Expand Up @@ -232,10 +265,10 @@ - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) {
return [super pointInside:point withEvent:event];
}

CGRect relativeFrame = self.bounds;
CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);

return CGRectContainsPoint(hitFrame, point);
}

Expand Down
3 changes: 1 addition & 2 deletions BHTwitter/BHTManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
+ (UIViewController *)BHTSettingsWithAccount:(TFNTwitterAccount *)twAccount;
+ (void)showSaveVC:(NSURL *)url;
+ (void)save:(NSURL *)url;
+ (TFNMenuSheetViewController *)newFFmpegDownloadSheet:(NSURL *)downloadingURL withProgressView:(JGProgressHUD *)hud;

+ (BOOL)DownloadingVideos;
+ (BOOL)DirectSave;
+ (BOOL)UndoTweet;
+ (BOOL)VideoZoom;
+ (BOOL)NoHistory;
+ (BOOL)BioTranslate;
+ (BOOL)LikeConfirm;
Expand All @@ -49,7 +49,6 @@
+ (BOOL)hideViewCount;
+ (BOOL)forceTweetFullFrame;
+ (BOOL)stripTrackingParams;
+ (BOOL)disableImmersive;
+ (BOOL)alwaysFollowingPage;
+ (BOOL)stopHidingTabBar;
+ (BOOL)advancedSearch;
Expand Down
Loading

0 comments on commit 92ed4dc

Please sign in to comment.