Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]

### Added
- Clean up nav bar: move music to settings, conditional play/pause (#34)
- Replace isIPad device checks with size classes and trait collections (#24)
- Replace deprecated UITableViewCellAccessoryDetailDisclosureButton in SSWorldCell (#19)
- Replace hardcoded 320pt popover widths with adaptive sizing (#18)
Expand All @@ -29,6 +30,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add Swift model classes for World, Alias, Trigger, Gag, Ticker (#76)

### Fixed
- Fix MSSP Server Status button not receiving taps in title view (#35)
- Fix world select button on iPhone (toggleSidebar collapsed) (#33)
- Fix crash in itemWithAttributedString: on empty string (#57)
- Fix libtelnet missing HAVE_ZLIB define causing MCCP2 gibberish (#56)

Expand Down
4 changes: 4 additions & 0 deletions src/Mudrammer/Controllers/Client/ClientContainer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ class ClientContainer: UISplitViewController {
}

@objc func toggleSidebar() {
if isCollapsed {
show(.primary)
return
}
#if os(visionOS)
let shouldHide = displayMode == .oneBesideSecondary
#else
Expand Down
69 changes: 66 additions & 3 deletions src/Mudrammer/Controllers/Client/SSClientViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ - (void) appendTextToLog:(NSString *)cleanText;
@property (nonatomic, strong) UIBarButtonItem *editWorldButton;
@property (nonatomic, strong) UIBarButtonItem *musicButton;
@property (nonatomic, strong) UIBarButtonItem *playPauseButton;
@property (nonatomic, strong) UIBarButtonItem *serverStatusButton;

@property (nonatomic, strong) UIViewController *SSPopoverController;

Expand Down Expand Up @@ -167,6 +168,7 @@ - (SSClientViewController *) init {
[client sendNAWS];
}];
}

}

return self;
Expand All @@ -189,13 +191,14 @@ + (SSClientViewController *)clientWithWorld:(NSString *)worldIdentifier {
}

- (UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeBottom;
return UIRectEdgeAll;
}

- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];

[self setNavVisible:YES];
[self updateWorldToolbar];

// Hacks around initial welcome on iPhone
if ([self isConnected]) {
Expand All @@ -211,6 +214,7 @@ - (void)viewDidAppear:(BOOL)animated {
}
}


- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];

Expand Down Expand Up @@ -307,14 +311,26 @@ - (void)updateWorldToolbar {
self.connectButton.connectDelegate = self;
}

BOOL isRegularWidth = self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular;

// On regular width, MSSP is shown as a bar button instead of a title subtitle
self.titleView.hidesMSSPSubtitle = isRegularWidth;
[self.titleView setMSSPData:self.titleView.MSSPData];

NSMutableArray *leftItems = [NSMutableArray array];

[leftItems addObject:self.settingsButton];

if (currentWorldIdentifier) {
[leftItems addObject:self.editWorldButton];
[leftItems addObject:self.musicButton];
[leftItems addObject:self.playPauseButton];

if (isRegularWidth) {
[leftItems addObject:self.musicButton];
}

if (self.gmcpHandler.isMusicPlaying || self.gmcpHandler.isMusicPaused) {
[leftItems addObject:self.playPauseButton];
}
}

self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
Expand All @@ -330,6 +346,16 @@ - (void)updateWorldToolbar {

[rightItems addObject:[self.worldSelectButton wrappedBarButtonItem]];

if (isRegularWidth && self.titleView.MSSPData.count > 0) {
if (!self.serverStatusButton) {
_serverStatusButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"SERVER_STATUS", nil)
style:UIBarButtonItemStylePlain
target:self
action:@selector(tappedServerStatus:)];
}
[rightItems addObject:self.serverStatusButton];
}

[self.navigationItem setRightBarButtonItems:rightItems
animated:NO];
}
Expand All @@ -352,6 +378,10 @@ - (void)viewDidLoad {

// setup navbar
[self updateWorldToolbar];

// rebuild toolbar when horizontal size class changes (e.g. rotation, multitasking)
[self registerForTraitChanges:@[UITraitHorizontalSizeClass.class]
withAction:@selector(updateWorldToolbar)];
}

#pragma clang diagnostic push
Expand Down Expand Up @@ -608,6 +638,20 @@ - (void)tappedPlayPause:(id)sender {

- (void)musicStateDidChange:(NSNotification *)note {
[self updateMusicButtons];
[self updateWorldToolbar];
}

- (void)tappedServerStatus:(id)sender {
NSDictionary *data = self.titleView.MSSPData;
if (!data || data.count == 0) return;

SPLMSSPViewController *MSSPVC = [[SPLMSSPViewController alloc] initWithMSSPData:data];
MSSPVC.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(dismissMSSPViewController:)];
UINavigationController *nav = [MSSPVC wrappedNavigationController];
nav.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:nav animated:YES completion:nil];
}

- (void)tappedWorldSelect:(id)sender {
Expand Down Expand Up @@ -722,6 +766,24 @@ - (void)settingsViewShouldOpenContact:(SSSettingsViewController *)settingsViewCo
[self closeSettingsWithCompletion:nil];
}

- (void)settingsViewShouldOpenMusicPicker:(SSSettingsViewController *)settingsViewController
navigationController:(UINavigationController *)navigationController {
SSMusicPickerViewController *picker = [[SSMusicPickerViewController alloc] init];
picker.gmcpHandler = self.gmcpHandler;
picker.currentWorldIdentifier = currentWorldIdentifier;

if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact) {
// On compact width, push onto the settings nav stack
picker.navigationItem.leftBarButtonItem = nil;
[navigationController pushViewController:picker animated:YES];
} else {
// On regular width (popover), dismiss settings then present music picker
[self closeSettingsWithCompletion:^{
[self tappedMusic:nil];
}];
}
}

- (void)settingsViewShouldSendSessionLog:(SSSettingsViewController *)settingsViewController {
@weakify(self);

Expand Down Expand Up @@ -1262,6 +1324,7 @@ - (BOOL)mudsocketShouldAttemptSSL:(SSMUDSocket *)socket {

- (void)mudsocket:(SSMUDSocket *)socket receivedMSSPData:(NSDictionary *)MSSPData {
[self.titleView setMSSPData:MSSPData];
[self updateWorldToolbar];
}

- (void)mudsocket:(SSMUDSocket *)socket receivedGMCPModule:(NSString *)module data:(NSDictionary *)data {
Expand Down
21 changes: 14 additions & 7 deletions src/Mudrammer/Controllers/Client/SSMusicPickerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,22 @@ class SSMusicPickerViewController: UITableViewController {
SSThemes.configureTable(tableView)
tracks = MusicLibrary.shared.musicTrackDictionaries

navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .close,
target: self,
action: #selector(dismissPicker)
)
// Only show close button when presented modally (not pushed onto a nav stack)
if navigationController?.viewControllers.first === self || navigationController == nil {
navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .close,
target: self,
action: #selector(dismissPicker)
)
}
}

@objc private func dismissPicker() {
dismiss(animated: true)
if navigationController?.viewControllers.first !== self {
navigationController?.popViewController(animated: true)
} else {
dismiss(animated: true)
}
}

// MARK: - UITableViewDataSource
Expand Down Expand Up @@ -77,6 +84,6 @@ class SSMusicPickerViewController: UITableViewController {
world.ambientMusicPath = path
WorldStoreBridge.updateMUDWorld(world)
}
dismiss(animated: true)
dismissPicker()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@ - (void)addClientWithWorld:(NSString *)worldIdentifier {
newClient.delegate = self;
UINavigationController *nav = [newClient wrappedNavigationController];
nav.delegate = newClient;
nav.navigationBar.translucent = NO;

BOOL isFirstWorld = [self numberOfClients] == 0;

Expand Down
4 changes: 4 additions & 0 deletions src/Mudrammer/Controllers/Settings/SSSettingsViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ typedef NS_ENUM( NSUInteger, SettingsSection ) {
typedef NS_ENUM( NSUInteger, SettingsTopSectionRow ) {
SettingsRowWorlds = 0,
SettingsRowThemes,
SettingsRowMusic,
SettingsTopNumRows
};

Expand Down Expand Up @@ -63,4 +64,7 @@ typedef NS_ENUM( NSUInteger, SettingsAboutHelpRow ) {

- (void) settingsViewShouldOpenContact:(SSSettingsViewController *)settingsViewController;

- (void) settingsViewShouldOpenMusicPicker:(SSSettingsViewController *)settingsViewController
navigationController:(UINavigationController *)navigationController;

@end
12 changes: 12 additions & 0 deletions src/Mudrammer/Controllers/Settings/SSSettingsViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ - (void)viewDidLoad {
cell.textLabel.text = NSLocalizedString(@"THEMES", @"Themes");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

break;
case SettingsRowMusic:

cell.textLabel.text = NSLocalizedString(@"BACKGROUND_MUSIC", @"Background Music");
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

break;
default:
break;
Expand Down Expand Up @@ -451,6 +457,12 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
case SettingsRowThemes:
nextVC = [SSThemePickerController themePickerController];

break;
case SettingsRowMusic:
if ([del respondsToSelector:@selector(settingsViewShouldOpenMusicPicker:navigationController:)]) {
[del settingsViewShouldOpenMusicPicker:self
navigationController:self.navigationController];
}
break;
default:
break;
Expand Down
6 changes: 6 additions & 0 deletions src/Mudrammer/Views/SPLMUDTitleView.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
*/
- (void) setTitle:(NSString *)title;

/**
* When YES, hides the MSSP subtitle button even if MSSPData is set.
* Use when MSSP is accessible via a separate bar button item.
*/
@property (nonatomic, assign) BOOL hidesMSSPSubtitle;

/**
* Block called when there is MSSP data available and the button has been tapped.
*/
Expand Down
25 changes: 24 additions & 1 deletion src/Mudrammer/Views/SPLMUDTitleView.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ @implementation SPLMUDTitleView

- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
self.clipsToBounds = NO;

_titleLabel = [UILabel new];
self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
Expand All @@ -41,6 +42,8 @@ - (instancetype)initWithFrame:(CGRect)frame {
forState:UIControlStateNormal];
[self.MSSPButton.titleLabel setFont:[UIFont systemFontOfSize:13.f]];

self.MSSPButton.tintColor = [UIColor whiteColor];
[self.MSSPButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.MSSPButton addTarget:self
action:@selector(MSSPButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
Expand All @@ -55,6 +58,25 @@ - (void)MSSPButtonTapped:(id)sender {
}
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// The MSSP button may render outside our bounds (nav bar can shrink the title view).
// Extend hit testing to include it.
if (self.MSSPButton.superview == self) {
CGPoint buttonPoint = [self convertPoint:point toView:self.MSSPButton];
if ([self.MSSPButton pointInside:buttonPoint withEvent:event]) {
return self.MSSPButton;
}
}
return [super hitTest:point withEvent:event];
}

- (CGSize)intrinsicContentSize {
if (self.MSSPData && self.MSSPData.count > 0) {
return CGSizeMake(UIViewNoIntrinsicMetric, 36);
}
return CGSizeMake(UIViewNoIntrinsicMetric, 22);
}

- (void)setTitle:(NSString *)title {
self.titleLabel.text = title;
[self setNeedsDisplay];
Expand All @@ -63,7 +85,7 @@ - (void)setTitle:(NSString *)title {
- (void)setMSSPData:(NSDictionary *)MSSPData {
_MSSPData = MSSPData;

if (MSSPData && [MSSPData count] > 0) {
if (MSSPData && [MSSPData count] > 0 && !self.hidesMSSPSubtitle) {
[self.titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.and.right.and.top.equalTo(self);
make.height.equalTo(@18);
Expand All @@ -83,6 +105,7 @@ - (void)setMSSPData:(NSDictionary *)MSSPData {
[self.MSSPButton removeFromSuperview];
}

[self invalidateIntrinsicContentSize];
[self setNeedsLayout];

[UIView animateWithDuration:0.3f
Expand Down
5 changes: 3 additions & 2 deletions src/Mudrammer/WorldStore/MusicLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,11 @@ final class MusicLibrary: NSObject {
// MARK: - Path Building

/// Build the relative path within GMCPMedia/ for a track.
/// Mirrors the logic in GMCPMediaManager.cachePath(baseURL:name:).
/// Must mirror GMCPMediaManager.cachePath(baseURL:name:) exactly.
static func buildRelativePath(hostname: String, name: String, baseURL: URL) -> String {
var components: [String] = []
components.append(hostname)
// Use baseURL.host (not the hostname parameter) to match cachePath behavior.
if let host = baseURL.host { components.append(host) }
let basePath = baseURL.path.trimmingCharacters(in: CharacterSet(charactersIn: "/"))
if !basePath.isEmpty { components.append(basePath) }
components.append(name)
Expand Down
Loading