mirror of
https://github.com/Finb/Bark.git
synced 2025-12-08 21:36:01 +00:00
添加上传自定义铃声UI
This commit is contained in:
parent
e8f33bc384
commit
d2f134088c
@ -91,6 +91,7 @@
|
||||
0661A54D204FDA4100965E4E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0661A54B204FDA4100965E4E /* LaunchScreen.storyboard */; };
|
||||
0667D192247D162C005DE2ED /* MessageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0667D191247D162C005DE2ED /* MessageTableViewCell.swift */; };
|
||||
0667D194247D1BA0005DE2ED /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0667D193247D1BA0005DE2ED /* Date+Extension.swift */; };
|
||||
066E0C8C2BB6AC9A00873838 /* AddSoundCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 066E0C8B2BB6AC9A00873838 /* AddSoundCell.swift */; };
|
||||
0672CB06256903F700570C9D /* MessageListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0672CB05256903F700570C9D /* MessageListViewModel.swift */; };
|
||||
06787C392A710568008ABDD7 /* GesturePassTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06787C382A710568008ABDD7 /* GesturePassTextView.swift */; };
|
||||
06787C3B2AB82BDB008ABDD7 /* CrashReportViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06787C3A2AB82BDB008ABDD7 /* CrashReportViewController.swift */; };
|
||||
@ -267,6 +268,7 @@
|
||||
0661A54E204FDA4100965E4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
0667D191247D162C005DE2ED /* MessageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageTableViewCell.swift; sourceTree = "<group>"; };
|
||||
0667D193247D1BA0005DE2ED /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = "<group>"; };
|
||||
066E0C8B2BB6AC9A00873838 /* AddSoundCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSoundCell.swift; sourceTree = "<group>"; };
|
||||
0672CB05256903F700570C9D /* MessageListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListViewModel.swift; sourceTree = "<group>"; };
|
||||
06787C382A710568008ABDD7 /* GesturePassTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GesturePassTextView.swift; sourceTree = "<group>"; };
|
||||
06787C3A2AB82BDB008ABDD7 /* CrashReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportViewController.swift; sourceTree = "<group>"; };
|
||||
@ -405,6 +407,7 @@
|
||||
06BBB8BB2567B3AD0076F63E /* ArchiveSettingCellViewModel.swift */,
|
||||
060481EF250F51CA00BC9799 /* SoundCell.swift */,
|
||||
065BE44F2563D939002A8CA4 /* SoundCellViewModel.swift */,
|
||||
066E0C8B2BB6AC9A00873838 /* AddSoundCell.swift */,
|
||||
062B98C2251B2762004562E7 /* BKButton.swift */,
|
||||
06C595352481160F006B98F3 /* BKLabel.swift */,
|
||||
062B98C7251B27AE004562E7 /* UINavigationItem+Extension.swift */,
|
||||
@ -952,6 +955,7 @@
|
||||
068EC15A27ED99E700D5D11E /* ServerListViewModel.swift in Sources */,
|
||||
06172FDC27F6DB06002333A4 /* ServerListTableViewCellViewModel.swift in Sources */,
|
||||
061894C729A75BEA00E001C2 /* Algorithm.swift in Sources */,
|
||||
066E0C8C2BB6AC9A00873838 /* AddSoundCell.swift in Sources */,
|
||||
065BE4502563D939002A8CA4 /* SoundCellViewModel.swift in Sources */,
|
||||
06F08EA729B1DDFE006AB9CA /* Error+Extension.swift in Sources */,
|
||||
06B1158F247BB1FB006D91FB /* Message.swift in Sources */,
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"symbols" : [
|
||||
{
|
||||
"filename" : "music_note-music_note_symbol.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 11 KiB |
@ -169,3 +169,7 @@ Email: to@day.app
|
||||
Telegram: https://t.me/joinchat/OsCbLzovUAE0YjY1
|
||||
Github Issue: https://github.com/Finb/Bark/issues
|
||||
";
|
||||
|
||||
uploadSound = "Upload Sound";
|
||||
customSounds = "Custom Sounds";
|
||||
defaultSounds = "Default Sounds";
|
||||
|
||||
@ -169,3 +169,7 @@ Email: to@day.app
|
||||
Telegram: https://t.me/joinchat/OsCbLzovUAE0YjY1
|
||||
Github Issue: https://github.com/Finb/Bark/issues
|
||||
";
|
||||
|
||||
uploadSound = "Upload Sound";
|
||||
customSounds = "Custom Sounds";
|
||||
defaultSounds = "Default Sounds";
|
||||
|
||||
@ -169,3 +169,7 @@ https://bark.day.app/#/faq
|
||||
Telegram: https://t.me/joinchat/OsCbLzov
|
||||
Github Issue: https://github.com/Finb/Bark/issues
|
||||
";
|
||||
|
||||
uploadSound = "上传铃声";
|
||||
customSounds = "自定义铃声";
|
||||
defaultSounds = "默认铃声";
|
||||
|
||||
@ -17,9 +17,10 @@ import RxSwift
|
||||
|
||||
class SoundsViewController: BaseViewController<SoundsViewModel> {
|
||||
let tableView: UITableView = {
|
||||
let tableView = UITableView()
|
||||
let tableView = UITableView(frame: CGRect.zero, style: .insetGrouped)
|
||||
tableView.backgroundColor = BKColor.background.primary
|
||||
tableView.register(SoundCell.self, forCellReuseIdentifier: "\(SoundCell.self)")
|
||||
tableView.register(AddSoundCell.self, forCellReuseIdentifier: "\(AddSoundCell.self)")
|
||||
return tableView
|
||||
}()
|
||||
|
||||
@ -27,41 +28,44 @@ class SoundsViewController: BaseViewController<SoundsViewModel> {
|
||||
self.title = NSLocalizedString("notificationSound")
|
||||
|
||||
self.view.addSubview(self.tableView)
|
||||
self.tableView.delegate = self
|
||||
self.tableView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
self.tableView.tableHeaderView = {
|
||||
let header = UILabel()
|
||||
header.fontSize = 12
|
||||
header.text = " \(NSLocalizedString("previewSound"))"
|
||||
header.textColor = BKColor.grey.darken1
|
||||
header.frame = CGRect(x: 0, y: 0, width: 0, height: 40)
|
||||
return header
|
||||
}()
|
||||
}
|
||||
|
||||
override func bindViewModel() {
|
||||
let output = viewModel.transform(
|
||||
input: SoundsViewModel.Input(soundSelected: self.tableView.rx
|
||||
.modelSelected(SoundCellViewModel.self)
|
||||
.modelSelected(SoundItem.self)
|
||||
.asDriver()))
|
||||
|
||||
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, SoundCellViewModel>> { _, tableView, _, item -> UITableViewCell in
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(SoundCell.self)") as? SoundCell else {
|
||||
return UITableViewCell()
|
||||
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, SoundItem>> { _, tableView, _, item -> UITableViewCell in
|
||||
switch item {
|
||||
case .sound(let model):
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(SoundCell.self)") as? SoundCell else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
cell.bindViewModel(model: model)
|
||||
return cell
|
||||
case .addSound:
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(AddSoundCell.self)") else {
|
||||
return UITableViewCell()
|
||||
}
|
||||
return cell
|
||||
}
|
||||
cell.bindViewModel(model: item)
|
||||
return cell
|
||||
|
||||
} titleForHeaderInSection: { dataSource, section in
|
||||
return dataSource[section].model
|
||||
}
|
||||
|
||||
output.audios
|
||||
.bind(to: tableView.rx.items(dataSource: dataSource))
|
||||
.disposed(by: rx.disposeBag)
|
||||
|
||||
output.copyNameAction.drive(onNext: { [weak self] name in
|
||||
output.copyNameAction.drive(onNext: { [unowned self] name in
|
||||
UIPasteboard.general.string = name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
self?.navigationController?.showSnackbar(text: NSLocalizedString("Copy"))
|
||||
self.navigationController?.showSnackbar(text: NSLocalizedString("Copy"))
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
output.playAction.drive(onNext: { url in
|
||||
@ -71,5 +75,33 @@ class SoundsViewController: BaseViewController<SoundsViewModel> {
|
||||
AudioServicesDisposeSystemSoundID(soundID)
|
||||
}
|
||||
}).disposed(by: rx.disposeBag)
|
||||
|
||||
output.pickerFile.drive(onNext: { [unowned self] _ in
|
||||
|
||||
}).disposed(by: rx.disposeBag)
|
||||
}
|
||||
}
|
||||
|
||||
extension SoundsViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let sectionTitle = tableView.dataSource?.tableView?(tableView, titleForHeaderInSection: section) ?? ""
|
||||
|
||||
let view = UIView()
|
||||
|
||||
let label = UILabel()
|
||||
label.text = NSLocalizedString(sectionTitle)
|
||||
label.fontSize = 14
|
||||
label.textColor = BKColor.grey.darken3
|
||||
view.addSubview(label)
|
||||
label.snp.makeConstraints { make in
|
||||
make.left.equalTo(12)
|
||||
make.centerY.equalToSuperview()
|
||||
}
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
||||
return 40
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,24 +12,31 @@ import RxCocoa
|
||||
import RxDataSources
|
||||
import RxSwift
|
||||
|
||||
enum SoundItem {
|
||||
case sound(model: SoundCellViewModel)
|
||||
case addSound
|
||||
}
|
||||
|
||||
class SoundsViewModel: ViewModel, ViewModelType {
|
||||
struct Input {
|
||||
var soundSelected: Driver<SoundCellViewModel>
|
||||
var soundSelected: Driver<SoundItem>
|
||||
}
|
||||
|
||||
struct Output {
|
||||
var audios: Observable<[SectionModel<String, SoundCellViewModel>]>
|
||||
var audios: Observable<[SectionModel<String, SoundItem>]>
|
||||
var copyNameAction: Driver<String>
|
||||
var playAction: Driver<CFURL>
|
||||
var pickerFile: Driver<Void>
|
||||
}
|
||||
|
||||
func getSounds(urls: [URL]) -> [SoundCellViewModel] {
|
||||
func getSounds(urls: [URL]) -> [SoundItem] {
|
||||
let urls = urls.sorted { u1, u2 -> Bool in
|
||||
u1.lastPathComponent.localizedStandardCompare(u2.lastPathComponent) == ComparisonResult.orderedAscending
|
||||
}
|
||||
return urls
|
||||
.map { AVURLAsset(url: $0) }
|
||||
.map { SoundCellViewModel(model: $0) }
|
||||
.map { SoundItem.sound(model: $0) }
|
||||
}
|
||||
|
||||
/// 返回指定文件夹,指定后缀的文件列表数组
|
||||
@ -53,17 +60,22 @@ class SoundsViewModel: ViewModel, ViewModelType {
|
||||
urls: Bundle.main.urls(forResourcesWithExtension: "caf", subdirectory: nil) ?? []
|
||||
)
|
||||
|
||||
let customSounds: [SoundCellViewModel] = {
|
||||
let customSounds: [SoundItem] = {
|
||||
guard let soundsDirectoryUrl = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true).first?.appending("/Sounds") else {
|
||||
return []
|
||||
return [.addSound]
|
||||
}
|
||||
return getSounds(
|
||||
urls: getFilesInDirectory(directory: soundsDirectoryUrl, suffix: "caf")
|
||||
)
|
||||
) + [.addSound]
|
||||
}()
|
||||
|
||||
let copyAction = Driver.merge(
|
||||
(defaultSounds + customSounds).map { $0.copyNameAction.asDriver(onErrorDriveWith: .empty()) }
|
||||
(defaultSounds + customSounds).compactMap { item in
|
||||
if case SoundItem.sound(let model) = item {
|
||||
return model.copyNameAction.asDriver(onErrorDriveWith: .empty())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
).asDriver()
|
||||
|
||||
return Output(
|
||||
@ -72,7 +84,20 @@ class SoundsViewModel: ViewModel, ViewModelType {
|
||||
SectionModel(model: "defaultSounds", items: defaultSounds)
|
||||
]),
|
||||
copyNameAction: copyAction,
|
||||
playAction: input.soundSelected.map { $0.model.url as CFURL }
|
||||
)
|
||||
playAction: input.soundSelected
|
||||
.compactMap { item in
|
||||
if case SoundItem.sound(let model) = item {
|
||||
return model
|
||||
}
|
||||
return nil
|
||||
}
|
||||
.map { $0.model.url as CFURL },
|
||||
pickerFile: input.soundSelected
|
||||
.compactMap { item in
|
||||
if case SoundItem.addSound = item {
|
||||
return ()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
37
View/AddSoundCell.swift
Normal file
37
View/AddSoundCell.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// AddSoundCell.swift
|
||||
// Bark
|
||||
//
|
||||
// Created by Fin on 2024/3/29.
|
||||
// Copyright © 2024 Fin. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AddSoundCell: UITableViewCell {
|
||||
let button: UIButton = {
|
||||
let button = UIButton(type: .system)
|
||||
button.setTitle(NSLocalizedString("uploadSound"), for: .normal)
|
||||
button.setImage(UIImage(named: "music_note-music_note_symbol"), for: .normal)
|
||||
button.setTitleColor(BKColor.lightBlue.darken3, for: .normal)
|
||||
button.tintColor = BKColor.lightBlue.darken3
|
||||
button.titleLabel?.font = UIFont.systemFont(ofSize: 16)
|
||||
// 从 UITableView didSelectRowAt 那响应点击事件
|
||||
button.isUserInteractionEnabled = false
|
||||
return button
|
||||
}()
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
self.selectionStyle = .none
|
||||
contentView.addSubview(button)
|
||||
button.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
make.height.equalTo(44)
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user