mirror of
https://github.com/faroukbmiled/RyukGram.git
synced 2026-04-22 04:06:10 +02:00
feat: Story audio mute/unmute toggle — button on story overlay and 3-dot menu
feat: Multi-select in excluded chats/story users lists with batch actions feat: Dynamic count refresh on manage list buttons imp: Opening tweak settings pauses any playing video/audio (toggleable in advanced settings) imp: Tweak settings quick-access (hold feed tab) now on by default imp: Disable auto-unmuting reels now off by default imp: Excluding a chat or story now immediately marks as seen
This commit is contained in:
@@ -101,6 +101,7 @@ A feature-rich iOS tweak for Instagram, forked from [SCInsta](https://github.com
|
||||
- Manual mark story as seen — button on story overlay to selectively mark stories as seen (button or toggle mode) **\***
|
||||
- Long-press the story seen button for quick actions **\***
|
||||
- Per-user story seen-receipt exclusions — exclude specific users so their stories behave normally. Manage via 3-dot menu, eye button long-press, or settings list **\***
|
||||
- Story audio mute/unmute toggle — button on the story overlay and 3-dot menu to toggle audio **\***
|
||||
- Stop story auto-advance — stories won't auto-skip when the timer ends **\***
|
||||
- Story download button — download directly from the story overlay **\***
|
||||
- Download disappearing DM media (photos + videos) **\***
|
||||
@@ -132,6 +133,8 @@ A feature-rich iOS tweak for Instagram, forked from [SCInsta](https://github.com
|
||||
|
||||
### Tweak settings **\***
|
||||
- Search bar in the main settings page — recursively finds any setting across nested pages with a breadcrumb to its location
|
||||
- Pause playback when opening settings (toggleable) **\***
|
||||
- Quick-access via long-press on feed tab **\***
|
||||
|
||||
### Backup & Restore **\***
|
||||
- Export RyukGram settings as a JSON file
|
||||
|
||||
@@ -67,15 +67,16 @@
|
||||
}
|
||||
}
|
||||
- (void)_muteSwitchStateChanged:(id)changed {
|
||||
if (![SCIUtils getBoolPref:@"disable_auto_unmuting_reels"]) {
|
||||
extern BOOL sciStoryAudioBypass;
|
||||
if (sciStoryAudioBypass || ![SCIUtils getBoolPref:@"disable_auto_unmuting_reels"]) {
|
||||
%orig(changed);
|
||||
}
|
||||
}
|
||||
// Block the announcer from broadcasting "audio enabled" state changes
|
||||
- (void)_announceForDeviceStateChangesIfNeededForAudioEnabled:(BOOL)enabled reason:(NSInteger)reason {
|
||||
// When pause/play mode is on, allow unmute (our force-unmute needs this path)
|
||||
extern BOOL sciStoryAudioBypass;
|
||||
BOOL pausePlayMode = [[SCIUtils getStringPref:@"reels_tap_control"] isEqualToString:@"pause"];
|
||||
if ([SCIUtils getBoolPref:@"disable_auto_unmuting_reels"] && enabled && !pausePlayMode) {
|
||||
if ([SCIUtils getBoolPref:@"disable_auto_unmuting_reels"] && enabled && !pausePlayMode && !sciStoryAudioBypass) {
|
||||
return;
|
||||
}
|
||||
%orig;
|
||||
|
||||
@@ -174,11 +174,15 @@ void sciRefreshAllVisibleOverlays(UIViewController *storyVC) {
|
||||
if (!overlayCls) overlayCls = NSClassFromString(@"IGStoryFullscreenOverlayMetalLayerView");
|
||||
if (!overlayCls) return;
|
||||
SEL refreshSel = @selector(sciRefreshSeenButton);
|
||||
SEL audioSel = @selector(sciRefreshAudioButton);
|
||||
NSMutableArray *stack = [NSMutableArray arrayWithObject:storyVC.view];
|
||||
while (stack.count) {
|
||||
UIView *v = stack.lastObject; [stack removeLastObject];
|
||||
if ([v isKindOfClass:overlayCls] && [v respondsToSelector:refreshSel]) {
|
||||
((void(*)(id, SEL))objc_msgSend)(v, refreshSel);
|
||||
if ([v isKindOfClass:overlayCls]) {
|
||||
if ([v respondsToSelector:refreshSel])
|
||||
((void(*)(id, SEL))objc_msgSend)(v, refreshSel);
|
||||
if ([v respondsToSelector:audioSel])
|
||||
((void(*)(id, SEL))objc_msgSend)(v, audioSel);
|
||||
}
|
||||
for (UIView *sub in v.subviews) [stack addObject:sub];
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ extern "C" BOOL sciStorySeenToggleEnabled;
|
||||
extern "C" void sciRefreshAllVisibleOverlays(UIViewController *storyVC);
|
||||
extern "C" void sciTriggerStoryMarkSeen(UIViewController *storyVC);
|
||||
extern "C" __weak UIViewController *sciActiveStoryViewerVC;
|
||||
extern "C" void sciToggleStoryAudio(void);
|
||||
extern "C" BOOL sciIsStoryAudioEnabled(void);
|
||||
extern "C" void sciInitStoryAudioState(void);
|
||||
extern "C" void sciResetStoryAudioState(void);
|
||||
|
||||
static SCIDownloadDelegate *sciStoryVideoDl = nil;
|
||||
static SCIDownloadDelegate *sciStoryImageDl = nil;
|
||||
@@ -131,6 +135,29 @@ static void sciDownloadDMVisualMessage(UIViewController *dmVC) {
|
||||
]];
|
||||
}
|
||||
|
||||
// Audio toggle button (left side, small)
|
||||
sciInitStoryAudioState();
|
||||
if ([SCIUtils getBoolPref:@"story_audio_toggle"] && ![self viewWithTag:1341]) {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
btn.tag = 1341;
|
||||
UIImageSymbolConfiguration *cfg = [UIImageSymbolConfiguration configurationWithPointSize:14 weight:UIImageSymbolWeightSemibold];
|
||||
NSString *icon = sciIsStoryAudioEnabled() ? @"speaker.wave.2" : @"speaker.slash";
|
||||
[btn setImage:[UIImage systemImageNamed:icon withConfiguration:cfg] forState:UIControlStateNormal];
|
||||
btn.tintColor = [UIColor whiteColor];
|
||||
btn.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.4];
|
||||
btn.layer.cornerRadius = 14;
|
||||
btn.clipsToBounds = YES;
|
||||
btn.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[btn addTarget:self action:@selector(sciAudioToggleTapped:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:btn];
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[btn.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor constant:-100],
|
||||
[btn.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:12],
|
||||
[btn.widthAnchor constraintEqualToConstant:28],
|
||||
[btn.heightAnchor constraintEqualToConstant:28]
|
||||
]];
|
||||
}
|
||||
|
||||
// Seen button — deferred so the responder chain is wired up
|
||||
__weak UIView *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -141,6 +168,15 @@ static void sciDownloadDMVisualMessage(UIViewController *dmVC) {
|
||||
|
||||
// ============ Seen button lifecycle ============
|
||||
|
||||
// Refresh the audio toggle icon (tag 1341) to match current state.
|
||||
%new - (void)sciRefreshAudioButton {
|
||||
UIButton *btn = (UIButton *)[self viewWithTag:1341];
|
||||
if (!btn) return;
|
||||
UIImageSymbolConfiguration *cfg = [UIImageSymbolConfiguration configurationWithPointSize:14 weight:UIImageSymbolWeightSemibold];
|
||||
NSString *icon = sciIsStoryAudioEnabled() ? @"speaker.wave.2" : @"speaker.slash";
|
||||
[btn setImage:[UIImage systemImageNamed:icon withConfiguration:cfg] forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
// Rebuilds the eye button (tag 1339) based on current owner + prefs. Idempotent.
|
||||
%new - (void)sciRefreshSeenButton {
|
||||
if (![SCIUtils getBoolPref:@"no_seen_receipt"]) return;
|
||||
@@ -192,11 +228,11 @@ static void sciDownloadDMVisualMessage(UIViewController *dmVC) {
|
||||
lp.minimumPressDuration = 0.4;
|
||||
[btn addGestureRecognizer:lp];
|
||||
[self addSubview:btn];
|
||||
UIView *dlBtn = [self viewWithTag:1340];
|
||||
if (dlBtn) {
|
||||
UIView *anchor = [self viewWithTag:1340];
|
||||
if (anchor) {
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[btn.centerYAnchor constraintEqualToAnchor:dlBtn.centerYAnchor],
|
||||
[btn.trailingAnchor constraintEqualToAnchor:dlBtn.leadingAnchor constant:-10],
|
||||
[btn.centerYAnchor constraintEqualToAnchor:anchor.centerYAnchor],
|
||||
[btn.trailingAnchor constraintEqualToAnchor:anchor.leadingAnchor constant:-10],
|
||||
[btn.widthAnchor constraintEqualToConstant:36],
|
||||
[btn.heightAnchor constraintEqualToConstant:36]
|
||||
]];
|
||||
@@ -210,12 +246,26 @@ static void sciDownloadDMVisualMessage(UIViewController *dmVC) {
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh when story owner changes (overlay reuse across reels)
|
||||
// Refresh when story owner changes or audio state changes
|
||||
- (void)layoutSubviews {
|
||||
%orig;
|
||||
if (![SCIUtils getBoolPref:@"no_seen_receipt"]) return;
|
||||
static char kLastPKKey;
|
||||
static char kLastExclKey;
|
||||
static char kLastAudioKey;
|
||||
|
||||
// Audio button: check if state changed
|
||||
UIButton *audioBtn = (UIButton *)[self viewWithTag:1341];
|
||||
if (audioBtn) {
|
||||
BOOL audioOn = sciIsStoryAudioEnabled();
|
||||
NSNumber *prevAudio = objc_getAssociatedObject(self, &kLastAudioKey);
|
||||
if (!prevAudio || [prevAudio boolValue] != audioOn) {
|
||||
objc_setAssociatedObject(self, &kLastAudioKey, @(audioOn), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
((void(*)(id, SEL))objc_msgSend)(self, @selector(sciRefreshAudioButton));
|
||||
}
|
||||
}
|
||||
|
||||
// Seen button: check if owner/exclusion changed
|
||||
if (![SCIUtils getBoolPref:@"no_seen_receipt"]) return;
|
||||
NSDictionary *info = sciOwnerInfoForView(self);
|
||||
NSString *pk = info[@"pk"] ?: @"";
|
||||
BOOL excluded = pk.length && [SCIExcludedStoryUsers isUserPKExcluded:pk];
|
||||
@@ -228,6 +278,17 @@ static void sciDownloadDMVisualMessage(UIViewController *dmVC) {
|
||||
((void(*)(id, SEL))objc_msgSend)(self, @selector(sciRefreshSeenButton));
|
||||
}
|
||||
|
||||
// ============ Audio toggle handler ============
|
||||
|
||||
%new - (void)sciAudioToggleTapped:(UIButton *)sender {
|
||||
UIImpactFeedbackGenerator *haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
||||
[haptic impactOccurred];
|
||||
sciToggleStoryAudio();
|
||||
UIImageSymbolConfiguration *cfg = [UIImageSymbolConfiguration configurationWithPointSize:14 weight:UIImageSymbolWeightSemibold];
|
||||
NSString *icon = sciIsStoryAudioEnabled() ? @"speaker.wave.2" : @"speaker.slash";
|
||||
[sender setImage:[UIImage systemImageNamed:icon withConfiguration:cfg] forState:UIControlStateNormal];
|
||||
}
|
||||
|
||||
// ============ Download handler ============
|
||||
|
||||
%new - (void)sciDownloadTapped:(UIButton *)sender {
|
||||
@@ -471,10 +532,12 @@ static void sciSyncStoryButtonsAlpha(UIView *self_, CGFloat alpha) {
|
||||
while (cur) {
|
||||
for (UIView *sib in cur.superview.subviews) {
|
||||
if (![sib isKindOfClass:overlayCls]) continue;
|
||||
UIView *seen = [sib viewWithTag:1339];
|
||||
UIView *dl = [sib viewWithTag:1340];
|
||||
if (seen) seen.alpha = alpha;
|
||||
if (dl) dl.alpha = alpha;
|
||||
UIView *seen = [sib viewWithTag:1339];
|
||||
UIView *dl = [sib viewWithTag:1340];
|
||||
UIView *audio = [sib viewWithTag:1341];
|
||||
if (seen) seen.alpha = alpha;
|
||||
if (dl) dl.alpha = alpha;
|
||||
if (audio) audio.alpha = alpha;
|
||||
return;
|
||||
}
|
||||
cur = cur.superview;
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
// Story audio mute/unmute toggle. Posts mute-switch-state-changed to toggle
|
||||
// IG's audio. Reads _audioEnabled on IGAudioStatusAnnouncer for icon state.
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "StoryHelpers.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#import <substrate.h>
|
||||
|
||||
extern "C" __weak UIViewController *sciActiveStoryViewerVC;
|
||||
extern "C" void sciRefreshAllVisibleOverlays(UIViewController *);
|
||||
|
||||
static id sciAudioAnnouncer = nil;
|
||||
|
||||
static BOOL sciIGAudioEnabled(void) {
|
||||
if (!sciAudioAnnouncer) return NO;
|
||||
Ivar ivar = class_getInstanceVariable([sciAudioAnnouncer class], "_audioEnabled");
|
||||
if (!ivar) return NO;
|
||||
ptrdiff_t offset = ivar_getOffset(ivar);
|
||||
return *(BOOL *)((char *)(__bridge void *)sciAudioAnnouncer + offset);
|
||||
}
|
||||
|
||||
// ============ Volume KVO ============
|
||||
|
||||
@interface _SciVolumeObserver : NSObject
|
||||
@end
|
||||
@implementation _SciVolumeObserver
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
|
||||
change:(NSDictionary *)change context:(void *)context {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (sciActiveStoryViewerVC) sciRefreshAllVisibleOverlays(sciActiveStoryViewerVC);
|
||||
});
|
||||
}
|
||||
@end
|
||||
static _SciVolumeObserver *sciVolumeObserver = nil;
|
||||
|
||||
// ============ Public API ============
|
||||
|
||||
extern "C" {
|
||||
|
||||
BOOL sciStoryAudioBypass = NO;
|
||||
|
||||
void sciToggleStoryAudio(void) {
|
||||
BOOL on = sciIGAudioEnabled();
|
||||
sciStoryAudioBypass = YES;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"mute-switch-state-changed"
|
||||
object:nil
|
||||
userInfo:@{@"mute-state": @(on ? 0 : 1)}];
|
||||
sciStoryAudioBypass = NO;
|
||||
if (sciActiveStoryViewerVC) sciRefreshAllVisibleOverlays(sciActiveStoryViewerVC);
|
||||
}
|
||||
|
||||
BOOL sciIsStoryAudioEnabled(void) {
|
||||
return sciIGAudioEnabled();
|
||||
}
|
||||
|
||||
void sciInitStoryAudioState(void) {
|
||||
if (!sciVolumeObserver) sciVolumeObserver = [_SciVolumeObserver new];
|
||||
@try {
|
||||
[[AVAudioSession sharedInstance] addObserver:sciVolumeObserver
|
||||
forKeyPath:@"outputVolume"
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:NULL];
|
||||
} @catch (__unused id e) {}
|
||||
}
|
||||
|
||||
void sciResetStoryAudioState(void) {
|
||||
@try {
|
||||
[[AVAudioSession sharedInstance] removeObserver:sciVolumeObserver forKeyPath:@"outputVolume"];
|
||||
} @catch (__unused id e) {}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// ============ Announcer hooks ============
|
||||
|
||||
static id (*orig_announcerInit)(id, SEL);
|
||||
static id new_announcerInit(id self, SEL _cmd) {
|
||||
id r = orig_announcerInit(self, _cmd);
|
||||
sciAudioAnnouncer = self;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void (*orig_announce)(id, SEL, BOOL, NSInteger);
|
||||
static void new_announce(id self, SEL _cmd, BOOL enabled, NSInteger reason) {
|
||||
orig_announce(self, _cmd, enabled, reason);
|
||||
if (sciActiveStoryViewerVC) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (sciActiveStoryViewerVC) sciRefreshAllVisibleOverlays(sciActiveStoryViewerVC);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ============ 3-dot menu item ============
|
||||
|
||||
extern "C" NSArray *sciMaybeAppendStoryAudioMenuItem(NSArray *items) {
|
||||
if (!sciActiveStoryViewerVC) return items;
|
||||
|
||||
BOOL looksLikeStoryHeader = NO;
|
||||
for (id it in items) {
|
||||
@try {
|
||||
NSString *t = [NSString stringWithFormat:@"%@", [it valueForKey:@"title"] ?: @""];
|
||||
if ([t isEqualToString:@"Report"] || [t isEqualToString:@"Mute"] ||
|
||||
[t isEqualToString:@"Unfollow"] || [t isEqualToString:@"Follow"] ||
|
||||
[t isEqualToString:@"Hide"]) { looksLikeStoryHeader = YES; break; }
|
||||
} @catch (__unused id e) {}
|
||||
}
|
||||
if (!looksLikeStoryHeader) return items;
|
||||
|
||||
Class menuItemCls = NSClassFromString(@"IGDSMenuItem");
|
||||
if (!menuItemCls) return items;
|
||||
|
||||
BOOL on = sciIGAudioEnabled();
|
||||
NSString *title = on ? @"Mute story audio" : @"Unmute story audio";
|
||||
void (^handler)(void) = ^{ sciToggleStoryAudio(); };
|
||||
|
||||
id newItem = nil;
|
||||
@try {
|
||||
typedef id (*Init)(id, SEL, id, id, id);
|
||||
newItem = ((Init)objc_msgSend)([menuItemCls alloc],
|
||||
@selector(initWithTitle:image:handler:), title, nil, handler);
|
||||
} @catch (__unused id e) {}
|
||||
|
||||
if (!newItem) return items;
|
||||
NSMutableArray *newItems = [items mutableCopy];
|
||||
[newItems addObject:newItem];
|
||||
return [newItems copy];
|
||||
}
|
||||
|
||||
// ============ Ringer listener ============
|
||||
|
||||
static void sciRingerChanged(CFNotificationCenterRef center, void *observer,
|
||||
CFNotificationName name, const void *object,
|
||||
CFDictionaryRef userInfo) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (sciActiveStoryViewerVC) sciRefreshAllVisibleOverlays(sciActiveStoryViewerVC);
|
||||
});
|
||||
}
|
||||
|
||||
// ============ Init ============
|
||||
|
||||
__attribute__((constructor)) static void _storyAudioInit(void) {
|
||||
CFNotificationCenterAddObserver(
|
||||
CFNotificationCenterGetDarwinNotifyCenter(), NULL,
|
||||
sciRingerChanged, CFSTR("com.apple.springboard.ringerstate"),
|
||||
NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
|
||||
|
||||
Class cls = NSClassFromString(@"IGAudioStatusAnnouncer");
|
||||
if (!cls) return;
|
||||
MSHookMessageEx(cls, @selector(init), (IMP)new_announcerInit, (IMP *)&orig_announcerInit);
|
||||
SEL s = NSSelectorFromString(@"_announceForDeviceStateChangesIfNeededForAudioEnabled:reason:");
|
||||
if (class_getInstanceMethod(cls, s))
|
||||
MSHookMessageEx(cls, s, (IMP)new_announce, (IMP *)&orig_announce);
|
||||
}
|
||||
@@ -78,9 +78,17 @@ static char rowStaticRef[] = "row";
|
||||
self.navigationItem.searchController = sc;
|
||||
self.navigationItem.hidesSearchBarWhenScrolling = NO;
|
||||
self.searchController = sc;
|
||||
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
|
||||
initWithBarButtonSystemItem:UIBarButtonSystemItemClose
|
||||
target:self action:@selector(sciDismissSettings)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sciDismissSettings {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
[self.tableView reloadData];
|
||||
|
||||
@@ -187,6 +187,12 @@
|
||||
}),
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Audio",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Story audio toggle" subtitle:@"Adds a speaker button to the story overlay to unmute/mute audio. Also available in the 3-dot menu" defaultsKey:@"story_audio_toggle"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Other",
|
||||
@"rows": @[
|
||||
@@ -361,33 +367,38 @@
|
||||
// }
|
||||
// ]
|
||||
// ],
|
||||
[SCISetting navigationCellWithTitle:@"Advanced"
|
||||
subtitle:@""
|
||||
icon:[SCISymbol symbolWithName:@"gearshape.2"]
|
||||
navSections:@[@{
|
||||
@"header": @"Settings",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Enable tweak settings quick-access" subtitle:@"Hold on the home tab to open RyukGram settings" defaultsKey:@"settings_shortcut" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Show tweak settings on app launch" subtitle:@"Automatically opens settings when the app launches" defaultsKey:@"tweak_settings_app_launch"],
|
||||
[SCISetting switchCellWithTitle:@"Pause playback when opening settings" subtitle:@"Pauses any playing video/audio when settings opens" defaultsKey:@"settings_pause_playback"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Instagram",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Disable safe mode" subtitle:@"Prevents Instagram from resetting settings after crashes (at your own risk)" defaultsKey:@"disable_safe_mode"],
|
||||
[SCISetting buttonCellWithTitle:@"Reset onboarding state"
|
||||
subtitle:@""
|
||||
icon:nil
|
||||
action:^(void) { [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"SCInstaFirstRun"]; [SCIUtils showRestartConfirmation];}
|
||||
],
|
||||
]
|
||||
}]
|
||||
],
|
||||
[SCISetting navigationCellWithTitle:@"Debug"
|
||||
subtitle:@""
|
||||
icon:[SCISymbol symbolWithName:@"ladybug"]
|
||||
navSections:@[@{
|
||||
@"header": @"FLEX",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Enable FLEX gesture" subtitle:@"Allows you to hold 5 fingers on the screen to open the FLEX explorer" defaultsKey:@"flex_instagram"],
|
||||
[SCISetting switchCellWithTitle:@"Open FLEX on app launch" subtitle:@"Automatically opens the FLEX explorer when the app launches" defaultsKey:@"flex_app_launch"],
|
||||
[SCISetting switchCellWithTitle:@"Open FLEX on app focus" subtitle:@"Automatically opens the FLEX explorer when the app is focused" defaultsKey:@"flex_app_start"]
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"RyukGram",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Enable tweak settings quick-access" subtitle:@"Allows you to hold on the home tab to open the RyukGram settings" defaultsKey:@"settings_shortcut" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Show tweak settings on app launch" subtitle:@"Automatically opens the RyukGram settings when the app launches" defaultsKey:@"tweak_settings_app_launch"],
|
||||
[SCISetting buttonCellWithTitle:@"Reset onboarding completion state"
|
||||
subtitle:@""
|
||||
icon:nil
|
||||
action:^(void) { [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"SCInstaFirstRun"]; [SCIUtils showRestartConfirmation];}
|
||||
],
|
||||
]
|
||||
},
|
||||
@{
|
||||
@"header": @"Instagram",
|
||||
@"rows": @[
|
||||
[SCISetting switchCellWithTitle:@"Disable safe mode" subtitle:@"Makes Instagram not reset settings after subsequent crashes (at your own risk)" defaultsKey:@"disable_safe_mode"]
|
||||
[SCISetting switchCellWithTitle:@"Enable FLEX gesture" subtitle:@"Hold 5 fingers on the screen to open FLEX" defaultsKey:@"flex_instagram"],
|
||||
[SCISetting switchCellWithTitle:@"Open FLEX on app launch" subtitle:@"Opens FLEX when the app launches" defaultsKey:@"flex_app_launch"],
|
||||
[SCISetting switchCellWithTitle:@"Open FLEX on app focus" subtitle:@"Opens FLEX when the app is focused" defaultsKey:@"flex_app_start"]
|
||||
]
|
||||
},
|
||||
@{
|
||||
|
||||
+7
-2
@@ -44,7 +44,8 @@ BOOL dmVisualMsgsViewedButtonEnabled = false;
|
||||
@"swipe_nav_tabs": @"default",
|
||||
@"enable_notes_customization": @(YES),
|
||||
@"custom_note_themes": @(YES),
|
||||
@"disable_auto_unmuting_reels": @(YES),
|
||||
@"disable_auto_unmuting_reels": @(NO),
|
||||
@"settings_shortcut": @(YES),
|
||||
@"doom_scrolling_reel_count": @(1),
|
||||
@"no_seen_visual": @(YES),
|
||||
@"send_audio_as_file": @(YES),
|
||||
@@ -64,7 +65,9 @@ BOOL dmVisualMsgsViewedButtonEnabled = false;
|
||||
@"unexclude_inbox_button": @(YES),
|
||||
@"enable_story_user_exclusions": @(YES),
|
||||
@"story_excluded_show_unexclude_eye": @(YES),
|
||||
@"story_seen_mode": @"button"
|
||||
@"story_seen_mode": @"button",
|
||||
@"story_audio_toggle": @(NO),
|
||||
@"settings_pause_playback": @(YES)
|
||||
};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:sciDefaults];
|
||||
|
||||
@@ -615,7 +618,9 @@ shouldPersistLastBugReportId:(id)arg6
|
||||
}
|
||||
|
||||
extern NSArray *sciMaybeAppendStoryExcludeMenuItem(NSArray *);
|
||||
extern NSArray *sciMaybeAppendStoryAudioMenuItem(NSArray *);
|
||||
NSArray *finalObjs = sciMaybeAppendStoryExcludeMenuItem([filteredObjs copy]);
|
||||
finalObjs = sciMaybeAppendStoryAudioMenuItem(finalObjs);
|
||||
return %orig(finalObjs, edr, headerLabelText);
|
||||
}
|
||||
%end
|
||||
|
||||
@@ -114,6 +114,8 @@
|
||||
UIViewController *rootController = [window rootViewController];
|
||||
SCISettingsViewController *settingsViewController = [SCISettingsViewController new];
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:settingsViewController];
|
||||
if ([SCIUtils getBoolPref:@"settings_pause_playback"])
|
||||
navigationController.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
|
||||
[rootController presentViewController:navigationController animated:YES completion:nil];
|
||||
}
|
||||
@@ -124,6 +126,8 @@
|
||||
while (rootController.presentedViewController) rootController = rootController.presentedViewController;
|
||||
SCISettingsViewController *root = [SCISettingsViewController new];
|
||||
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:root];
|
||||
if ([SCIUtils getBoolPref:@"settings_pause_playback"])
|
||||
nav.modalPresentationStyle = UIModalPresentationFullScreen;
|
||||
|
||||
NSArray *targetNavSections = nil;
|
||||
for (NSDictionary *section in [SCITweakSettings sections]) {
|
||||
|
||||
Reference in New Issue
Block a user