Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS] Add local search to Playlist #26933

Merged
merged 1 commit into from
Dec 12, 2024
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
81 changes: 81 additions & 0 deletions ios/brave-ios/Sources/BraveUI/SwiftUI/SearchBar.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2024 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

import SwiftUI
import UIKit

/// A representable around `UISearchBar` using the minimal style
public struct SearchBar: UIViewRepresentable {
@Binding var text: String
var placeholder: String?
var isFocused: Binding<Bool>?
var onSubmit: (() -> Void)?

public init(
text: Binding<String>,
placeholder: String? = nil,
isFocused: Binding<Bool>? = nil,
onSubmit: (() -> Void)? = nil
) {
self._text = text
self.placeholder = placeholder
self.isFocused = isFocused
self.onSubmit = onSubmit
}

public func makeUIView(context: Context) -> UISearchBar {
let searchBar = UISearchBar(frame: .zero)
searchBar.text = text
searchBar.placeholder = placeholder
searchBar.searchBarStyle = .minimal
return searchBar
}

public func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
uiView.placeholder = placeholder
uiView.delegate = context.coordinator
if let isFocused {
if isFocused.wrappedValue {
uiView.becomeFirstResponder()
} else {
uiView.resignFirstResponder()
}
}
}

public func makeCoordinator() -> Coordinator {
Coordinator(text: $text, isFocused: isFocused, onSubmit: onSubmit)
}

public class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
var isFocused: Binding<Bool>?
var onSubmit: (() -> Void)?

init(text: Binding<String>, isFocused: Binding<Bool>?, onSubmit: (() -> Void)?) {
self._text = text
self.isFocused = isFocused
self.onSubmit = onSubmit
}

public func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}

public func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
isFocused?.wrappedValue = true
}

public func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
isFocused?.wrappedValue = false
}

public func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
onSubmit?()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

import BraveCore
import BraveUI
import SwiftUI

struct TransactionSection: Equatable, Identifiable {
Expand Down
50 changes: 0 additions & 50 deletions ios/brave-ios/Sources/BraveWallet/SearchBar.swift

This file was deleted.

2 changes: 1 addition & 1 deletion ios/brave-ios/Sources/PlaylistUI/PlayerModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ public final class PlayerModel: ObservableObject {

@MainActor @Published var selectedItemID: PlaylistItem.ID? {
willSet {
if let selectedItem {
if selectedItem != nil {
let currentTime = currentTime
let duration = duration.seconds ?? 0
// Reset the current item's last played time if you changed videos in the last 10s
Expand Down
80 changes: 51 additions & 29 deletions ios/brave-ios/Sources/PlaylistUI/PlaylistContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct PlaylistContentView: View {
@State private var isEditModePresented: Bool = false
@State private var newPlaylistName: String = ""
@State private var isPopulatingNewPlaylist: Bool = false
@State private var isPresentingSearch: Bool = false

private var selectedItemID: PlaylistItem.ID? {
playerModel.selectedItemID
Expand All @@ -48,37 +49,41 @@ struct PlaylistContentView: View {
playerModel.selectedItemID.flatMap { PlaylistItem.getItem(id: $0) }
}

private var selectedItemIDBinding: Binding<PlaylistItem.ID?> {
Binding(
get: {
selectedItemID
},
set: { newValue in
// Make the item queue prior to setting the `selectedItemID`, which will start playing
// said item
withAnimation(.snappy) {
selectedDetent = .anchor(.mediaControls)
}
// FIXME: Move this into PlayerModel
playerModel.makeItemQueue(selectedItemID: newValue)
if selectedItemID == newValue {
// Already selected, restart it (based on prior behaviour)
Task {
await playerModel.seek(to: 0, accurately: true)
playerModel.play()
}
return
}
playerModel.selectedItemID = newValue
Task {
await playerModel.prepareToPlaySelectedItem(initialOffset: nil, playImmediately: true)
}
}
)
}

public var body: some View {
PlaylistSplitView(selectedDetent: $selectedDetent) {
PlaylistSidebarList(
folders: Array(folders),
folderID: selectedFolderID,
selectedItemID: Binding(
get: {
selectedItemID
},
set: { newValue in
// Make the item queue prior to setting the `selectedItemID`, which will start playing
// said item
withAnimation(.snappy) {
selectedDetent = .anchor(.mediaControls)
}
// FIXME: Move this into PlayerModel
playerModel.makeItemQueue(selectedItemID: newValue)
if selectedItemID == newValue {
// Already selected, restart it (based on prior behaviour)
Task {
await playerModel.seek(to: 0, accurately: true)
playerModel.play()
}
return
}
playerModel.selectedItemID = newValue
Task {
await playerModel.prepareToPlaySelectedItem(initialOffset: nil, playImmediately: true)
}
}
),
selectedItemID: selectedItemIDBinding,
isPlaying: playerModel.isPlaying,
onPlaylistUpdated: {
// Update the queue to reflect updated playlist
Expand Down Expand Up @@ -150,6 +155,12 @@ struct PlaylistContentView: View {
.labelStyle(.iconOnly)
.transition(.opacity.animation(.default))
}
Button {
isPresentingSearch = true
} label: {
Label(Strings.Playlist.searchTitle, braveSystemImage: "leo.search")
}
.labelStyle(.iconOnly)
}
.task {
await playerModel.prepareItemQueue()
Expand All @@ -160,9 +171,7 @@ struct PlaylistContentView: View {
}
}
.onDisappear {
if let selectedItem {
playerModel.persistPlaybackTimeForSelectedItem(playerModel.currentTime)
}
playerModel.persistPlaybackTimeForSelectedItem(playerModel.currentTime)
}
.sheet(isPresented: $isEditModePresented) {
if let selectedFolder {
Expand Down Expand Up @@ -225,6 +234,19 @@ struct PlaylistContentView: View {
.environment(\.colorScheme, .dark)
.preferredColorScheme(.dark)
}
.sheet(isPresented: $isPresentingSearch) {
SearchView(
folders: Array(folders),
selectedItemID: selectedItemIDBinding,
selectedFolderID: $playerModel.selectedFolderID,
isPlaying: playerModel.isPlaying,
onPlaylistUpdated: {
playerModel.makeItemQueue(selectedItemID: playerModel.selectedItemID)
}
)
.environment(\.colorScheme, .dark)
.preferredColorScheme(.dark)
}
.onChange(of: selectedItemID) { newValue in
if newValue == nil {
withAnimation(.snappy) {
Expand Down
Loading
Loading