Skip to content

Instantly share code, notes, and snippets.

@lint
Last active July 23, 2020 18:24
Show Gist options
  • Save lint/ebe27e92d9e1ed082279583570775d54 to your computer and use it in GitHub Desktop.
Save lint/ebe27e92d9e1ed082279583570775d54 to your computer and use it in GitHub Desktop.

How to enable/disable a section in Spotify settings

Create your custom section classes

@interface SettingsSection
- (id)initWithSettingsViewController:(id)arg1;
@end

@interface FirstSettingsSection : SettingsSection
@property(strong, nonatomic) SettingsSwitchTableViewCell *cell;
@end

@interface SecondSettingsSection : SettingsSection
@property(strong, nonatomic) SettingsSwitchTableViewCell *cell;
@end

%subclass FirstSettingsSection : SettingsSection
%property(strong, nonatomic) SettingsSwitchTableViewCell *cell;

- (id)initWithSettingsViewController:(id)arg1 {
   self = %orig;

   SettingsSwitchTableViewCell *cell = [[%c(SettingsSwitchTableViewCell) alloc] initWithTitle:@"Test Cell 1" switchValue:NO target:arg1 action:@selector(firstSwitchTapped:) reuseIdentifier:@"CustomSwitchCell"];
   self.cell = cell;
   
   return self;
}

- (NSInteger)numberOfRows {
   return 1;
}

- (NSString *)headerText {
   return @"First Custom Section";
}

- (NSString *)footerText {
   return @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus tempus viverra feugiat. Nam lorem diam, accumsan ac semper vel, porttitor.";
}

- (id)cellForRow:(NSInteger)arg1 {
   return self.cell;
}

%end


%subclass SecondSettingsSection : SettingsSection
%property(strong, nonatomic) SettingsSwitchTableViewCell *cell;

- (id)initWithSettingsViewController:(id)arg1 {
   self = %orig;

   SettingsSwitchTableViewCell *cell = [[%c(SettingsSwitchTableViewCell) alloc] initWithTitle:@"Test Cell 2" switchValue:NO target:arg1 action:@selector(secondSwitchTapped:) reuseIdentifier:@"CustomSwitchCell"];
   self.cell = cell;
   
   return self;
}

- (NSInteger)numberOfRows {
   return 1;
}

- (NSString *)headerText {
   return @"Second Custom Section";
}

- (NSString *)footerText {
   return @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus tempus viverra feugiat. Nam lorem diam, accumsan ac semper vel, porttitor.";
}

- (id)cellForRow:(NSInteger)arg1 {
   return self.cell;
}

%end

In the initWithSettingsViewController method, you setup the cell with it's attributes such as the title, starting switchValue (on/off), action (the method you want to call), and target (the object the method will be called on). The target here is arg1, or the SettingsViewController, so it will be handling when the switch is tapped. Here there are two separate subclasses of SettingsSection, which are mostly the same. If adding many custom sections, it would probably be better to create one subclass of SettingsSection for the initial setup, and then more subclasses of that one subclass where you only change what you need. In this case, since there are only two of them, it really doesn't matter.

Creating the cells

@interface SettingsViewController () // the "()" is so I didn't have to go and add it to the header file b/c I was lazy.
@property(strong, nonatomic) SecondSettingsSection *secondSection;
@end

%hook SettingsViewController
%property(strong, nonatomic) SecondSettingsSection *secondSection;

- (id)initWithDictionaryRepresentation:(id)arg1 navigationRouter:(id)arg2 context:(id)arg3 {
	
	id orig = %orig; 
	
	if ([self.viewURI isEqualToString:@"spotify:config:car"]) {
		NSMutableArray *sections = self.sections;
		
   		FirstSettingsSection *firstSection = [[%c(FirstSettingsSection) alloc] initWithSettingsViewController:self];
		[sections insertObject:firstSection atIndex:0];
    
    		SecondSettingsSection *secondSection = [[%c(SecondSettingsSection) alloc] initWithSettingsViewController:self];
		[self setSecondSection:secondSection];
	}
	
	return orig;
}

At the moment this is only adding the first custom section to the page. Note that I am creating a property to store a reference to the secondSection. This will be used later. The second section is currently not added to the page, if you want that when it loads, create an if statement checking the value of the first section with [firstSection.cell.switchControl isOn] or use the value from your prefs. Inside that if statement you should do the same thing as the first section, [sections insertObject:secondSection atIndex:1];

Enabling/Disabling the second section


// in SettingsViewController 

%new
- (void)firstSwitchTapped:(UISwitch *)sender {	
	
	if ([sender isOn]) {
		[self.sections insertObject:self.secondSection atIndex:1];
	} else {
		[self.sections removeObject:self.secondSection];
	}
	
	[self.tableView reloadData];
}

%end

This method is called when the first switch is tapped. It uses the sender, the SPTSwitch (inherits from UISwitch) to know if it is enabled or disabled. The secondSection is able to be accessed since a reference was stored in a property. If the first switch was enabled, then it adds the second section to self.sections, otherwise it will remove it from the array. Note that no new section is created here. It was created in the init so there is no need for a new one, it can just be reused. Then reloadData is called on the tableView to display the cell. In this method you should also do the updating of your preferences with the new switch value.

Wrapping up

First, the section subclasses are defined and implemented. Second, the section objects are created in the SettingsViewController init method. Third, the first switch tap is handled. That's all there is to it. This is scalable with more sections, but this should give you the basic idea. I hope that this clears it up for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment