Skip to content

feat: remember shuffle and repeat#49

Merged
sozercan merged 2 commits intomainfrom
remember-shuffle
Jan 7, 2026
Merged

feat: remember shuffle and repeat#49
sozercan merged 2 commits intomainfrom
remember-shuffle

Conversation

@sozercan
Copy link
Owner

@sozercan sozercan commented Jan 7, 2026

Description

fixes #45

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📚 Documentation update
  • 🎨 UI/UX improvement
  • ♻️ Refactoring (no functional changes)
  • 🧪 Test update
  • 🔧 Build/CI configuration

Related Issues

Changes Made

Testing

  • Unit tests pass (xcodebuild test -only-testing:KasetTests)
  • Manual testing performed
  • UI tested on macOS 26+

Checklist

  • My code follows the project's style guidelines
  • I have run swiftlint --strict && swiftformat .
  • I have added tests that prove my fix/feature works
  • New and existing unit tests pass locally
  • I have updated documentation if needed
  • I have checked for any performance implications
  • My changes generate no new warnings

Screenshots

Additional Notes

Signed-off-by: Sertac Ozercan <sozercan@gmail.com>
Copilot AI review requested due to automatic review settings January 7, 2026 16:35
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds functionality to remember shuffle and repeat mode settings across app restarts. The feature is controlled by a new user preference toggle "Remember Shuffle & Repeat" in the General Settings.

Key Changes:

  • Added a new rememberPlaybackSettings boolean property to SettingsManager that defaults to false
  • Modified PlayerService to persist and restore shuffle and repeat mode states when the setting is enabled
  • Added a UI toggle in GeneralSettingsView to control the feature

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
Core/Services/SettingsManager.swift Added rememberPlaybackSettings property with UserDefaults persistence
Core/Services/Player/PlayerService.swift Added restoration logic in init and persistence logic in toggleShuffle/cycleRepeatMode
Views/macOS/GeneralSettingsView.swift Added UI toggle for the new setting with helpful tooltip
Tests/KasetTests/SettingsManagerTests.swift Added test to verify default value of rememberPlaybackSettings is false

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +639 to +650
// Persist repeat mode to UserDefaults if setting is enabled
if SettingsManager.shared.rememberPlaybackSettings {
let modeString = switch self.repeatMode {
case .off:
"off"
case .all:
"all"
case .one:
"one"
}
UserDefaults.standard.set(modeString, forKey: Self.repeatModeKey)
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repeat mode is persisted using string values ("off", "all", "one") rather than leveraging Swift's Codable or a raw value enum. While this works, consider making RepeatMode conform to RawRepresentable with String raw values, which would provide type safety and make the serialization/deserialization more maintainable and less error-prone.

Copilot uses AI. Check for mistakes.
Comment on lines +164 to +174
if let savedRepeatMode = UserDefaults.standard.string(forKey: Self.repeatModeKey) {
switch savedRepeatMode {
case "all":
self.repeatMode = .all
case "one":
self.repeatMode = .one
default:
self.repeatMode = .off
}
self.logger.info("Restored repeat mode: \(String(describing: self.repeatMode))")
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The restoration logic uses string comparison for repeat mode but doesn't handle invalid or unexpected values gracefully. If a corrupted or unexpected value is stored in UserDefaults, it will silently default to 'off'. Consider adding a logging statement in the default case to help diagnose issues where saved settings might not be restored correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +157 to +175
// Restore shuffle and repeat settings if enabled in settings
if SettingsManager.shared.rememberPlaybackSettings {
if UserDefaults.standard.object(forKey: Self.shuffleEnabledKey) != nil {
self.shuffleEnabled = UserDefaults.standard.bool(forKey: Self.shuffleEnabledKey)
self.logger.info("Restored shuffle state: \(self.shuffleEnabled)")
}

if let savedRepeatMode = UserDefaults.standard.string(forKey: Self.repeatModeKey) {
switch savedRepeatMode {
case "all":
self.repeatMode = .all
case "one":
self.repeatMode = .one
default:
self.repeatMode = .off
}
self.logger.info("Restored repeat mode: \(String(describing: self.repeatMode))")
}
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's inconsistency between how shuffle state is restored (with a nil check using object(forKey:)) versus repeat mode (only checking if the string exists). The shuffle restoration checks if the object exists before reading the bool value, but repeat mode just checks if the string is non-nil. For consistency and to avoid potential issues with default boolean values, both should use the same pattern.

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +73
@Test("Default rememberPlaybackSettings is false")
func defaultRememberPlaybackSettings() {
let manager = SettingsManager.shared
#expect(manager.rememberPlaybackSettings == false)
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test only verifies the default value but doesn't test the persistence behavior. Consider adding a test that verifies the setting is properly persisted to UserDefaults when changed, and can be restored after reinitialization, similar to how other settings properties are tested.

Copilot uses AI. Check for mistakes.
Comment on lines +85 to +90
/// Whether to remember shuffle/repeat settings across app restarts.
var rememberPlaybackSettings: Bool {
didSet {
UserDefaults.standard.set(self.rememberPlaybackSettings, forKey: Keys.rememberPlaybackSettings)
}
}
Copy link

Copilot AI Jan 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When toggling shuffle or repeat mode while the remember setting is disabled, the old persisted values remain in UserDefaults. If a user later re-enables the remember setting, those stale values will be restored. Consider clearing the persisted shuffle and repeat values from UserDefaults when the rememberPlaybackSettings property is set to false in the didSet observer, to prevent unexpected restoration of old settings.

Copilot uses AI. Check for mistakes.
@sozercan sozercan merged commit 4f46969 into main Jan 7, 2026
6 checks passed
@sozercan sozercan deleted the remember-shuffle branch January 7, 2026 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Allow saving state for shuffle/repeat settings

2 participants