mirror of
https://github.com/yattee/yattee.git
synced 2025-12-13 11:38:15 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b34c7e72b | ||
|
|
0dd7943849 | ||
|
|
6745934a78 | ||
|
|
76801a34ee | ||
|
|
4d0318d4b0 | ||
|
|
9d4446a6ef | ||
|
|
b74017894c | ||
|
|
9fef6c0276 | ||
|
|
fcbeb45d1e | ||
|
|
66f7286cdc | ||
|
|
e1e068ba11 | ||
|
|
524c99dd54 | ||
|
|
b57ed7055c | ||
|
|
d84d701b07 | ||
|
|
bcfd4126b6 | ||
|
|
97b16cfd04 | ||
|
|
d5b81ceba1 | ||
|
|
f3ba61a168 | ||
|
|
c68aa1d30c | ||
|
|
d187fc322c | ||
|
|
e616022278 | ||
|
|
1b0486df05 | ||
|
|
e6deb9ef26 | ||
|
|
0216c17b95 | ||
|
|
1eff757caf | ||
|
|
4cfd00b307 | ||
|
|
8075db3ac8 | ||
|
|
2cd867e344 | ||
|
|
b5b2e7f13d | ||
|
|
cbd7c417d2 | ||
|
|
ed7a233c9b | ||
|
|
d75e3e9a61 |
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
# lane: ['mac beta', 'ios beta', 'tvos beta']
|
||||
lane: ['ios beta', 'tvos beta']
|
||||
name: Releasing ${{ matrix.lane }} version to TestFlight
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
@@ -38,6 +38,9 @@ jobs:
|
||||
run: |
|
||||
sed -i '' 's/match Development/match AppStore/' Yattee.xcodeproj/project.pbxproj
|
||||
sed -i '' 's/iPhone Developer/iPhone Distribution/' Yattee.xcodeproj/project.pbxproj
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '14.3.1'
|
||||
- uses: maierj/fastlane-action@v3.0.0
|
||||
with:
|
||||
lane: ${{ matrix.lane }}
|
||||
@@ -48,7 +51,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
mac_notarized:
|
||||
name: Build and notarize macOS app
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
@@ -59,6 +62,9 @@ jobs:
|
||||
run: |
|
||||
sed -i '' 's/match AppStore/match Direct/' Yattee.xcodeproj/project.pbxproj
|
||||
sed -i '' 's/3rd Party Mac Developer Application/Developer ID Application/' Yattee.xcodeproj/project.pbxproj
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: '14.3.1'
|
||||
- uses: maierj/fastlane-action@v3.0.0
|
||||
with:
|
||||
lane: mac build_and_notarize
|
||||
|
||||
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,11 +1,18 @@
|
||||
## Build 177
|
||||
* Added Settings Import/Export (iOS, macOS)
|
||||
## Build 179
|
||||
* Add skip, play/pause, and fullscreen shortcuts to macOS player (by @rickykresslein)
|
||||
* Updated localizations
|
||||
* Updated dependencies
|
||||
|
||||
## Previous builds
|
||||
* Added Settings Import/Export
|
||||
* Export all settings, instances and accounts
|
||||
* Import selected elements from the file
|
||||
* Include unencrypted passwords in the export or provide them during the import
|
||||
* Import via URL for tvOS
|
||||
* Added Controls setting "Action button labels" icon or icon and text
|
||||
* Added Advanced setting for MPV: "deinterlace"
|
||||
* Updated dependencies
|
||||
* Updated dependencies (mpvkit 0.37.0)
|
||||
* Localization fixes
|
||||
* Updated localizations
|
||||
* Fixed reported crash
|
||||
* Other minor changes and improvements
|
||||
|
||||
17
Gemfile.lock
17
Gemfile.lock
@@ -48,15 +48,17 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
CFPropertyList (3.0.6)
|
||||
CFPropertyList (3.0.7)
|
||||
base64
|
||||
nkf
|
||||
rexml
|
||||
addressable (2.8.6)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
artifactory (3.0.15)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.886.0)
|
||||
aws-sdk-core (3.191.0)
|
||||
aws-partitions (1.894.0)
|
||||
aws-sdk-core (3.191.3)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-sigv4 (~> 1.8)
|
||||
@@ -71,6 +73,7 @@ GEM
|
||||
aws-sigv4 (1.8.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
babosa (1.0.4)
|
||||
base64 (0.2.0)
|
||||
claide (1.1.0)
|
||||
colored (1.2)
|
||||
colored2 (3.1.2)
|
||||
@@ -155,13 +158,15 @@ GEM
|
||||
httpclient (2.8.3)
|
||||
jmespath (1.6.2)
|
||||
json (2.7.1)
|
||||
jwt (2.7.1)
|
||||
jwt (2.8.0)
|
||||
base64
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.3.0)
|
||||
multipart-post (2.4.0)
|
||||
nanaimo (0.3.0)
|
||||
naturally (2.2.1)
|
||||
nkf (0.2.0)
|
||||
optparse (0.4.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.1)
|
||||
@@ -177,7 +182,7 @@ GEM
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.3.2)
|
||||
security (0.1.3)
|
||||
signet (0.18.0)
|
||||
signet (0.19.0)
|
||||
addressable (~> 2.8)
|
||||
faraday (>= 0.17.5, < 3.a)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
|
||||
@@ -2,15 +2,11 @@ import Defaults
|
||||
import Foundation
|
||||
import SwiftyJSON
|
||||
|
||||
struct ImportSettingsFileModel {
|
||||
let url: URL
|
||||
|
||||
var filename: String {
|
||||
String(url.lastPathComponent.dropLast(ImportExportSettingsModel.settingsExtension.count + 1))
|
||||
}
|
||||
final class ImportSettingsFileModel: ObservableObject {
|
||||
static let shared = ImportSettingsFileModel()
|
||||
|
||||
var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
|
||||
if let locationsSettings = json?.dictionaryValue["locationsSettings"] {
|
||||
if let locationsSettings = json.dictionaryValue["locationsSettings"] {
|
||||
return LocationsSettingsGroupImporter(
|
||||
json: locationsSettings,
|
||||
includePublicLocations: importExportModel.isGroupEnabled(.locationsSettings),
|
||||
@@ -25,6 +21,8 @@ struct ImportSettingsFileModel {
|
||||
var importExportModel = ImportExportSettingsModel.shared
|
||||
var sheetViewModel = ImportSettingsSheetViewModel.shared
|
||||
|
||||
var loadTask: URLSessionTask?
|
||||
|
||||
func isGroupIncludedInFile(_ group: ImportExportSettingsModel.ExportGroup) -> Bool {
|
||||
switch group {
|
||||
case .locationsSettings:
|
||||
@@ -48,7 +46,7 @@ struct ImportSettingsFileModel {
|
||||
}
|
||||
|
||||
func groupJSON(_ group: ImportExportSettingsModel.ExportGroup) -> JSON {
|
||||
json?.dictionaryValue[group.rawValue] ?? .init()
|
||||
json.dictionaryValue[group.rawValue] ?? .init()
|
||||
}
|
||||
|
||||
func performImport() {
|
||||
@@ -91,17 +89,34 @@ struct ImportSettingsFileModel {
|
||||
}
|
||||
}
|
||||
|
||||
var json: JSON? {
|
||||
if let fileContents = try? Data(contentsOf: url),
|
||||
let json = try? JSON(data: fileContents)
|
||||
{
|
||||
return json
|
||||
@Published var json = JSON()
|
||||
|
||||
func loadData(_ url: URL) {
|
||||
json = JSON()
|
||||
loadTask?.cancel()
|
||||
|
||||
loadTask = URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
|
||||
guard let data else { return }
|
||||
|
||||
if let json = try? JSON(data: data) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
self.json = json
|
||||
|
||||
self.sheetViewModel.reset(locationsSettingsGroupImporter)
|
||||
self.importExportModel.reset(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
loadTask?.resume()
|
||||
}
|
||||
|
||||
func filename(_ url: URL) -> String {
|
||||
String(url.lastPathComponent.dropLast(ImportExportSettingsModel.settingsExtension.count + 1))
|
||||
}
|
||||
|
||||
var metadataBuild: String? {
|
||||
if let build = json?.dictionaryValue["metadata"]?.dictionaryValue["build"]?.string {
|
||||
if let build = json.dictionaryValue["metadata"]?.dictionaryValue["build"]?.string {
|
||||
return build
|
||||
}
|
||||
|
||||
@@ -109,7 +124,7 @@ struct ImportSettingsFileModel {
|
||||
}
|
||||
|
||||
var metadataPlatform: String? {
|
||||
if let platform = json?.dictionaryValue["metadata"]?.dictionaryValue["platform"]?.string {
|
||||
if let platform = json.dictionaryValue["metadata"]?.dictionaryValue["platform"]?.string {
|
||||
return platform
|
||||
}
|
||||
|
||||
@@ -117,7 +132,7 @@ struct ImportSettingsFileModel {
|
||||
}
|
||||
|
||||
var metadataDate: String? {
|
||||
if let timestamp = json?.dictionaryValue["metadata"]?.dictionaryValue["timestamp"]?.doubleValue {
|
||||
if let timestamp = json.dictionaryValue["metadata"]?.dictionaryValue["timestamp"]?.doubleValue {
|
||||
let date = Date(timeIntervalSince1970: timestamp)
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
|
||||
@@ -176,6 +176,11 @@ final class PlayerModel: ObservableObject {
|
||||
@Default(.resetWatchedStatusOnPlaying) var resetWatchedStatusOnPlaying
|
||||
@Default(.playerRate) var playerRate
|
||||
@Default(.systemControlsSeekDuration) var systemControlsSeekDuration
|
||||
|
||||
#if os(macOS)
|
||||
@Default(.buttonBackwardSeekDuration) private var buttonBackwardSeekDuration
|
||||
@Default(.buttonForwardSeekDuration) private var buttonForwardSeekDuration
|
||||
#endif
|
||||
|
||||
#if !os(macOS)
|
||||
@Default(.closePiPAndOpenPlayerOnEnteringForeground) var closePiPAndOpenPlayerOnEnteringForeground
|
||||
@@ -187,6 +192,10 @@ final class PlayerModel: ObservableObject {
|
||||
var onPlayStream = [(Stream) -> Void]()
|
||||
var rateToRestore: Float?
|
||||
private var remoteCommandCenterConfigured = false
|
||||
|
||||
#if os(macOS)
|
||||
var keyPressMonitor: Any?
|
||||
#endif
|
||||
|
||||
init() {
|
||||
#if !os(macOS)
|
||||
@@ -212,6 +221,7 @@ final class PlayerModel: ObservableObject {
|
||||
#if os(macOS)
|
||||
if presentingPlayer {
|
||||
Windows.player.focus()
|
||||
assignKeyPressMonitor()
|
||||
return
|
||||
}
|
||||
#endif
|
||||
@@ -227,6 +237,7 @@ final class PlayerModel: ObservableObject {
|
||||
#if os(macOS)
|
||||
Windows.player.open()
|
||||
Windows.player.focus()
|
||||
assignKeyPressMonitor()
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -246,6 +257,7 @@ final class PlayerModel: ObservableObject {
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
destroyKeyPressMonitor()
|
||||
Windows.player.hide()
|
||||
#endif
|
||||
}
|
||||
@@ -1146,4 +1158,46 @@ final class PlayerModel: ObservableObject {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private func assignKeyPressMonitor() {
|
||||
keyPressMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { keyEvent -> NSEvent? in
|
||||
switch keyEvent.keyCode {
|
||||
case 124:
|
||||
if !self.liveStreamInAVPlayer {
|
||||
let interval = TimeInterval(self.buttonForwardSeekDuration) ?? 10
|
||||
self.backend.seek(
|
||||
relative: .secondsInDefaultTimescale(interval),
|
||||
seekType: .userInteracted
|
||||
)
|
||||
}
|
||||
case 123:
|
||||
if !self.liveStreamInAVPlayer {
|
||||
let interval = TimeInterval(self.buttonBackwardSeekDuration) ?? 10
|
||||
self.backend.seek(
|
||||
relative: .secondsInDefaultTimescale(-interval),
|
||||
seekType: .userInteracted
|
||||
)
|
||||
}
|
||||
case 3:
|
||||
self.toggleFullscreen(
|
||||
self.playingFullScreen,
|
||||
showControls: false
|
||||
)
|
||||
case 49:
|
||||
if !self.controls.isLoadingVideo {
|
||||
self.backend.togglePlay()
|
||||
}
|
||||
default: return keyEvent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func destroyKeyPressMonitor() {
|
||||
if let keyPressMonitor = keyPressMonitor {
|
||||
NSEvent.removeMonitor(keyPressMonitor)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -436,9 +436,9 @@ enum ButtonLabelStyle: String, CaseIterable, Defaults.Serializable {
|
||||
var description: String {
|
||||
switch self {
|
||||
case .iconOnly:
|
||||
return "Icon only"
|
||||
return "Icon only".localized()
|
||||
case .iconAndText:
|
||||
return "Icon and text"
|
||||
return "Icon and text".localized()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,6 @@ struct OpenURLHandler {
|
||||
var navigationStyle: NavigationStyle
|
||||
|
||||
func handle(_ url: URL) {
|
||||
if url.isFileURL, url.standardizedFileURL.absoluteString.hasSuffix(".\(ImportExportSettingsModel.settingsExtension)") {
|
||||
navigation.presentSettingsImportSheet(url)
|
||||
return
|
||||
}
|
||||
|
||||
if Self.firstHandle {
|
||||
Self.firstHandle = false
|
||||
|
||||
@@ -26,6 +21,11 @@ struct OpenURLHandler {
|
||||
return
|
||||
}
|
||||
|
||||
if url.isFileURL, url.standardizedFileURL.absoluteString.hasSuffix(".\(ImportExportSettingsModel.settingsExtension)") {
|
||||
navigation.presentSettingsImportSheet(url)
|
||||
return
|
||||
}
|
||||
|
||||
if accounts.current.isNil {
|
||||
accounts.setCurrent(accounts.any)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,13 @@ struct ExportSettings: View {
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#if os(iOS)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
exportButton
|
||||
}
|
||||
}
|
||||
#endif
|
||||
.navigationTitle("Export Settings")
|
||||
}
|
||||
|
||||
@@ -70,7 +77,7 @@ struct ExportSettings: View {
|
||||
var body: some View {
|
||||
Button(action: { model.toggleExportGroupSelection(group) }) {
|
||||
HStack {
|
||||
Text(group.label)
|
||||
Text(group.label.localized())
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.accentColor)
|
||||
@@ -106,12 +113,6 @@ struct ExportSettings: View {
|
||||
ExportGroupRow(group: group)
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(macOS)
|
||||
Section {
|
||||
exportButton
|
||||
}
|
||||
#endif
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(model.isExportInProgress)
|
||||
@@ -119,7 +120,7 @@ struct ExportSettings: View {
|
||||
|
||||
var exportButton: some View {
|
||||
Button(action: exportSettings) {
|
||||
Label(model.isExportInProgress ? "Export in progress..." : "Export...", systemImage: model.isExportInProgress ? "fireworks" : "square.and.arrow.up")
|
||||
Text(model.isExportInProgress ? "In progress..." : "Export")
|
||||
.animation(nil, value: model.isExportInProgress)
|
||||
#if !os(macOS)
|
||||
.foregroundColor(.accentColor)
|
||||
|
||||
34
Shared/Settings/Import/ImportSettings.swift
Normal file
34
Shared/Settings/Import/ImportSettings.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ImportSettings: View {
|
||||
@State private var fileURL = ""
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 100) {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text("1. Export settings from Yattee for iOS or macOS")
|
||||
Text("2. Upload it to a file hosting (e. g. Pastebin or GitHub Gist)")
|
||||
Text("3. Enter file URL in the field below. You can use iOS remote to paste.")
|
||||
}
|
||||
|
||||
TextField("URL", text: $fileURL)
|
||||
|
||||
Button {
|
||||
if let url = URL(string: fileURL) {
|
||||
NavigationModel.shared.presentSettingsImportSheet(url)
|
||||
}
|
||||
} label: {
|
||||
Text("Import")
|
||||
}
|
||||
}
|
||||
.padding(20)
|
||||
.navigationTitle("Import Settings")
|
||||
}
|
||||
}
|
||||
|
||||
struct ImportSettings_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ImportSettings()
|
||||
}
|
||||
}
|
||||
@@ -27,102 +27,110 @@ struct ImportSettingsAccountRow: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Button(action: { model.toggleAccount(account, accounts: accounts) }) {
|
||||
let accountExists = AccountsModel.shared.find(account.id) != nil
|
||||
#if os(tvOS)
|
||||
row
|
||||
#else
|
||||
Button(action: { model.toggleAccount(account, accounts: accounts) }) {
|
||||
row
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
}
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(account.username)
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.accentColor)
|
||||
.opacity(isChecked ? 1 : 0)
|
||||
}
|
||||
Text(account.instance?.description ?? "")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
var row: some View {
|
||||
let accountExists = AccountsModel.shared.find(account.id) != nil
|
||||
|
||||
Group {
|
||||
if let instanceID = account.instanceID {
|
||||
if accountExists {
|
||||
HStack {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
Text("Account already exists")
|
||||
}
|
||||
} else {
|
||||
Group {
|
||||
if InstancesModel.shared.find(instanceID) != nil {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Custom Location already exists")
|
||||
}
|
||||
} else if model.selectedInstances.contains(instanceID) {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Custom Location selected for import")
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(.red)
|
||||
Text("Custom Location not selected for import")
|
||||
}
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 20)
|
||||
return VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(account.username)
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.accentColor)
|
||||
.opacity(isChecked ? 1 : 0)
|
||||
}
|
||||
Text(account.instance?.description ?? "")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
if account.password.isNil || account.password!.isEmpty {
|
||||
Group {
|
||||
if password.isEmpty {
|
||||
HStack {
|
||||
Image(systemName: "key")
|
||||
Text("Password required to import")
|
||||
}
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
} else {
|
||||
AccountValidationStatus(
|
||||
app: .constant(instance.app),
|
||||
isValid: $isValid,
|
||||
isValidated: $isValidated,
|
||||
isValidating: $isValidating,
|
||||
error: $validationError
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 20)
|
||||
} else {
|
||||
Group {
|
||||
if let instanceID = account.instanceID {
|
||||
if accountExists {
|
||||
HStack {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
Text("Account already exists")
|
||||
}
|
||||
} else {
|
||||
Group {
|
||||
if InstancesModel.shared.find(instanceID) != nil {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
|
||||
Text("Password saved in import file")
|
||||
Text("Custom Location already exists")
|
||||
}
|
||||
} else if model.selectedInstances.contains(instanceID) {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
Text("Custom Location selected for import")
|
||||
}
|
||||
} else {
|
||||
HStack {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(.red)
|
||||
Text("Custom Location not selected for import")
|
||||
}
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 20)
|
||||
|
||||
if account.password.isNil || account.password!.isEmpty {
|
||||
Group {
|
||||
if password.isEmpty {
|
||||
HStack {
|
||||
Image(systemName: "key")
|
||||
Text("Password required to import")
|
||||
}
|
||||
.foregroundColor(Color("AppRedColor"))
|
||||
} else {
|
||||
AccountValidationStatus(
|
||||
app: .constant(instance.app),
|
||||
isValid: $isValid,
|
||||
isValidated: $isValidated,
|
||||
isValidating: $isValidating,
|
||||
error: $validationError
|
||||
)
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 20)
|
||||
} else {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundColor(.green)
|
||||
|
||||
Text("Password saved in import file")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
.font(.caption)
|
||||
.padding(.vertical, 2)
|
||||
|
||||
if !accountExists && (account.password.isNil || account.password!.isEmpty) {
|
||||
SecureField("Password", text: $password)
|
||||
.onChange(of: password) { _ in validate() }
|
||||
#if !os(tvOS)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
.onChange(of: isValid) { _ in afterValidation() }
|
||||
.animation(nil, value: isChecked)
|
||||
.foregroundColor(.primary)
|
||||
.font(.caption)
|
||||
.padding(.vertical, 2)
|
||||
|
||||
if !accountExists && (account.password.isNil || account.password!.isEmpty) {
|
||||
SecureField("Password", text: $password)
|
||||
.onChange(of: password) { _ in validate() }
|
||||
#if !os(tvOS)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
.onChange(of: isValid) { _ in afterValidation() }
|
||||
.animation(nil, value: isChecked)
|
||||
}
|
||||
|
||||
var isChecked: Bool {
|
||||
@@ -173,7 +181,8 @@ struct ImportSettingsAccountRow: View {
|
||||
|
||||
struct ImportSettingsAccountRow_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let fileModel = ImportSettingsFileModel(url: URL(string: "https://gist.githubusercontent.com/arekf/578668969c9fdef1b3828bea864c3956/raw/f794a95a20261bcb1145e656c8dda00bea339e2a/yattee-recents.yatteesettings")!)
|
||||
let fileModel = ImportSettingsFileModel()
|
||||
fileModel.loadData(URL(string: "https://gist.githubusercontent.com/arekf/578668969c9fdef1b3828bea864c3956/raw/f794a95a20261bcb1145e656c8dda00bea339e2a/yattee-recents.yatteesettings")!)
|
||||
|
||||
return List {
|
||||
ImportSettingsAccountRow(
|
||||
|
||||
@@ -4,6 +4,7 @@ struct ImportSettingsSheetView: View {
|
||||
@Binding var settingsFile: URL?
|
||||
@StateObject private var model = ImportSettingsSheetViewModel.shared
|
||||
@StateObject private var importExportModel = ImportExportSettingsModel.shared
|
||||
@StateObject private var fileModel = ImportSettingsFileModel.shared
|
||||
|
||||
@Environment(\.presentationMode) private var presentationMode
|
||||
|
||||
@@ -23,12 +24,12 @@ struct ImportSettingsSheetView: View {
|
||||
#endif
|
||||
}
|
||||
.onAppear {
|
||||
guard let fileModel else { return }
|
||||
model.reset(fileModel.locationsSettingsGroupImporter)
|
||||
importExportModel.reset(fileModel)
|
||||
guard let settingsFile else { return }
|
||||
fileModel.loadData(settingsFile)
|
||||
}
|
||||
.onChange(of: settingsFile) { _ in
|
||||
importExportModel.reset(fileModel)
|
||||
guard let settingsFile else { return }
|
||||
fileModel.loadData(settingsFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +57,7 @@ struct ImportSettingsSheetView: View {
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(action: {
|
||||
fileModel?.performImport()
|
||||
fileModel.performImport()
|
||||
presentingCompletedAlert = true
|
||||
ImportExportSettingsModel.shared.reset()
|
||||
}) {
|
||||
@@ -85,16 +86,8 @@ struct ImportSettingsSheetView: View {
|
||||
return !model.selectedAccounts.isEmpty || !model.selectedInstances.isEmpty || !importExportModel.selectedExportGroups.isEmpty
|
||||
}
|
||||
|
||||
var fileModel: ImportSettingsFileModel? {
|
||||
guard let settingsFile else { return nil }
|
||||
|
||||
return ImportSettingsFileModel(url: settingsFile)
|
||||
}
|
||||
|
||||
var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
|
||||
guard let fileModel else { return nil }
|
||||
|
||||
return fileModel.locationsSettingsGroupImporter
|
||||
fileModel.locationsSettingsGroupImporter
|
||||
}
|
||||
|
||||
struct ExportGroupRow: View {
|
||||
@@ -105,7 +98,7 @@ struct ImportSettingsSheetView: View {
|
||||
var body: some View {
|
||||
Button(action: { model.toggleExportGroupSelection(group) }) {
|
||||
HStack {
|
||||
Text(group.label)
|
||||
Text(group.label.localized())
|
||||
Spacer()
|
||||
Image(systemName: "checkmark")
|
||||
.foregroundColor(.accentColor)
|
||||
@@ -128,34 +121,43 @@ struct ImportSettingsSheetView: View {
|
||||
Section(header: Text("Settings")) {
|
||||
ForEach(ImportExportSettingsModel.ExportGroup.settingsGroups) { group in
|
||||
ExportGroupRow(group: group)
|
||||
.disabled(!fileModel!.isGroupIncludedInFile(group))
|
||||
.disabled(!fileModel.isGroupIncludedInFile(group))
|
||||
}
|
||||
}
|
||||
|
||||
Section(header: Text("Other")) {
|
||||
ForEach(ImportExportSettingsModel.ExportGroup.otherGroups) { group in
|
||||
ExportGroupRow(group: group)
|
||||
.disabled(!fileModel!.isGroupIncludedInFile(group))
|
||||
.disabled(!fileModel.isGroupIncludedInFile(group))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder var metadata: some View {
|
||||
if let fileModel {
|
||||
if let settingsFile {
|
||||
Section(header: Text("File information")) {
|
||||
MetadataRow(name: Text("Name"), value: Text(fileModel.filename))
|
||||
MetadataRow(name: Text("Name"), value: Text(fileModel.filename(settingsFile)))
|
||||
|
||||
if let date = fileModel.metadataDate {
|
||||
MetadataRow(name: Text("Date"), value: Text(date))
|
||||
#if os(tvOS)
|
||||
.focusable()
|
||||
#endif
|
||||
}
|
||||
|
||||
if let build = fileModel.metadataBuild {
|
||||
MetadataRow(name: Text("Build"), value: Text(build))
|
||||
#if os(tvOS)
|
||||
.focusable()
|
||||
#endif
|
||||
}
|
||||
|
||||
if let platform = fileModel.metadataPlatform {
|
||||
MetadataRow(name: Text("Platform"), value: Text(platform))
|
||||
#if os(tvOS)
|
||||
.focusable()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,24 +233,22 @@ struct ImportSettingsSheetView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder var importOptions: some View {
|
||||
if let fileModel {
|
||||
if fileModel.isPublicInstancesSettingsGroupInFile || !instances.isEmpty {
|
||||
Section(header: Text("Locations")) {
|
||||
if fileModel.isPublicInstancesSettingsGroupInFile {
|
||||
ExportGroupRow(group: .locationsSettings)
|
||||
}
|
||||
if fileModel.isPublicInstancesSettingsGroupInFile || !instances.isEmpty {
|
||||
Section(header: Text("Locations")) {
|
||||
if fileModel.isPublicInstancesSettingsGroupInFile {
|
||||
ExportGroupRow(group: .locationsSettings)
|
||||
}
|
||||
|
||||
ForEach(instances) { instance in
|
||||
ImportInstanceRow(instance: instance, accounts: accounts)
|
||||
}
|
||||
ForEach(instances) { instance in
|
||||
ImportInstanceRow(instance: instance, accounts: accounts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !accounts.isEmpty {
|
||||
Section(header: Text("Accounts")) {
|
||||
ForEach(accounts) { account in
|
||||
ImportSettingsAccountRow(account: account, fileModel: fileModel)
|
||||
}
|
||||
if !accounts.isEmpty {
|
||||
Section(header: Text("Accounts")) {
|
||||
ForEach(accounts) { account in
|
||||
ImportSettingsAccountRow(account: account, fileModel: fileModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ struct SettingsView: View {
|
||||
|
||||
var body: some View {
|
||||
settings
|
||||
.modifier(ImportSettingsSheetViewModifier(isPresented: $settingsModel.presentingSettingsImportSheet, settingsFile: $settingsModel.settingsImportURL))
|
||||
#if !os(tvOS)
|
||||
.modifier(ImportSettingsFileImporterViewModifier(isPresented: $navigation.presentingSettingsFileImporter))
|
||||
.modifier(ImportSettingsSheetViewModifier(isPresented: $settingsModel.presentingSettingsImportSheet, settingsFile: $settingsModel.settingsImportURL))
|
||||
.modifier(ImportSettingsFileImporterViewModifier(isPresented: $navigation.presentingSettingsFileImporter))
|
||||
#endif
|
||||
#if os(iOS)
|
||||
.backport
|
||||
@@ -281,19 +281,27 @@ struct SettingsView: View {
|
||||
|
||||
var importView: some View {
|
||||
Section {
|
||||
Button(action: importSettings) {
|
||||
Label("Import Settings...", systemImage: "square.and.arrow.down")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.foregroundColor(.accentColor)
|
||||
.buttonStyle(.plain)
|
||||
#if os(tvOS)
|
||||
NavigationLink(destination: LazyView(ImportSettings())) {
|
||||
Label("Import Settings", systemImage: "square.and.arrow.down")
|
||||
.labelStyle(SettingsLabel())
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
#else
|
||||
Button(action: importSettings) {
|
||||
Label("Import Settings...", systemImage: "square.and.arrow.down")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.foregroundColor(.accentColor)
|
||||
.buttonStyle(.plain)
|
||||
|
||||
NavigationLink(destination: LazyView(ExportSettings())) {
|
||||
Label("Export Settings", systemImage: "square.and.arrow.up")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
NavigationLink(destination: LazyView(ExportSettings())) {
|
||||
Label("Export Settings", systemImage: "square.and.arrow.up")
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"Podcasts" = "بودكاست";
|
||||
"Releases" = "الإصدارات";
|
||||
"Add %@" = "إضافة %@";
|
||||
"Import Settings..." = "إستيراد الإعدادات...";
|
||||
"Accounts passwords (unencrypted)" = "كلمات مرور الحسابات (غير مشفرة)";
|
||||
"Other data" = "بيانات أخرى";
|
||||
"Export..." = "تصدير…";
|
||||
"Export" = "تصدير";
|
||||
"File information" = "معلومات الملف";
|
||||
"Build" = "بناء";
|
||||
"Platform" = "المنصة";
|
||||
"Import" = "إستيراد";
|
||||
"Action button labels" = "تسميات زر الإجراء";
|
||||
"Icon only" = "أيقونة فقط";
|
||||
"Icon and text" = "أيقونة و نص";
|
||||
"Custom Location not selected for import" = "لم يتم تحديد الموقع المخصّص للإستيراد";
|
||||
"Account already exists" = "الحساب موجود بالفعل";
|
||||
"Export Settings" = "تصدير الإعدادات";
|
||||
"Other" = "أخرى";
|
||||
"Other data include last used playback preferences and listing options" = "بيانات أخرى تتضمن آخر تفضيلات التشغيل المستخدمة وخيارات القائمة";
|
||||
"Are you sure you want to export unencrypted passwords?" = "هل أنت متأكد من أنك تريد تصدير كلمات المرور غير المشفرة؟";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "لا تشارك هذا الملف مع أي شخص وإلا قد تفقد إمكانية الوصول إلى حساباتك. إذا لم تحدّد تصدير كلمات المرور، فسوف يُطلب منك تقديمها أثناء الإستيراد";
|
||||
"Custom Location selected for import" = "حدّد الموقع المخصّص للإستيراد";
|
||||
"Custom Location already exists" = "الموقع المخصّص موجود بالفعل";
|
||||
"Password required to import" = "كلمة المرور مطلوبة للإستيراد";
|
||||
"Password saved in import file" = "كلمة المرور محفوظة في ملف الإستيراد";
|
||||
"Export in progress..." = "جارِ التصدير...";
|
||||
"In progress..." = "في تَقَدم…";
|
||||
|
||||
@@ -602,3 +602,28 @@
|
||||
"No preview" = "No preview";
|
||||
"Open vertical chapters expanded" = "Open vertical chapters expanded";
|
||||
"Chapters (if available)" = "Chapters (if available)";
|
||||
"Import Settings..." = "Import Settings...";
|
||||
"Export Settings" = "Export Settings";
|
||||
"Accounts passwords (unencrypted)" = "Accounts passwords (unencrypted)";
|
||||
"Other" = "Other";
|
||||
"Other data" = "Other data";
|
||||
"Export..." = "Export…";
|
||||
"Other data include last used playback preferences and listing options" = "Other data include last used playback preferences and listing options";
|
||||
"Are you sure you want to export unencrypted passwords?" = "Are you sure you want to export unencrypted passwords?";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import";
|
||||
"Icon only" = "Icon only";
|
||||
"Export" = "Export";
|
||||
"File information" = "File information";
|
||||
"Build" = "Build";
|
||||
"Import" = "Import";
|
||||
"Platform" = "Platform";
|
||||
"Action button labels" = "Action button labels";
|
||||
"Icon and text" = "Icon and text";
|
||||
"Password required to import" = "Password required to import";
|
||||
"Custom Location already exists" = "Custom Location already exists";
|
||||
"Custom Location selected for import" = "Custom Location selected for import";
|
||||
"Custom Location not selected for import" = "Custom Location not selected for import";
|
||||
"Account already exists" = "Account already exists";
|
||||
"Password saved in import file" = "Password saved in import file";
|
||||
"Export in progress..." = "Export in progress...";
|
||||
"In progress..." = "In progress…";
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"No preview" = "Sin vista previa";
|
||||
"Open vertical chapters expanded" = "Abrir capítulos verticales ampliados";
|
||||
"Chapters (if available)" = "Capítulos (si están disponibles)";
|
||||
"Password required to import" = "Se requiere contraseña para importar";
|
||||
"Export Settings" = "Ajustes de exportación";
|
||||
"Other" = "Otro";
|
||||
"Other data" = "Información adicional";
|
||||
"Export..." = "Exportar…";
|
||||
"Are you sure you want to export unencrypted passwords?" = "¿Estás seguro de que quieres exportar las contraseñas sin cifrar?";
|
||||
"Export" = "Exportar";
|
||||
"Build" = "Compilación";
|
||||
"Platform" = "Plataforma";
|
||||
"Import" = "Importar";
|
||||
"Action button labels" = "Etiquetas para los botones de acción";
|
||||
"Icon only" = "Solo icono";
|
||||
"Icon and text" = "Icono y texto";
|
||||
"Custom Location already exists" = "Ya existe una ubicación personalizada";
|
||||
"Custom Location selected for import" = "Ubicación personalizada seleccionada para la importación";
|
||||
"Custom Location not selected for import" = "Ubicación personalizada no seleccionada para la importación";
|
||||
"Password saved in import file" = "Contraseña guardada en el archivo de importación";
|
||||
"Export in progress..." = "Exportación en curso...";
|
||||
"In progress..." = "En proceso…";
|
||||
"Import Settings..." = "Importar configuración...";
|
||||
"Accounts passwords (unencrypted)" = "Contraseñas de las cuentas (no cifradas)";
|
||||
"Other data include last used playback preferences and listing options" = "Información adicional incluye las últimas preferencias de reproducción utilizadas y las opciones de listado";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "No compartas este archivo con nadie o puedes perder el acceso a tus cuentas. Si no selecciona exportar contraseñas se le pedirá que las proporcione durante la importación";
|
||||
"File information" = "Información del archivo";
|
||||
"Account already exists" = "La cuenta ya existe";
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"No preview" = "Aucun aperçu";
|
||||
"Open vertical chapters expanded" = "Ouvrir les chapitres verticaux étendus";
|
||||
"Chapters (if available)" = "Chapitres (si disponibles)";
|
||||
"Accounts passwords (unencrypted)" = "Mots de passe des comptes (non chiffrés)";
|
||||
"Export..." = "Exporter…";
|
||||
"Export" = "Exporter";
|
||||
"Build" = "Build";
|
||||
"Import" = "Importer";
|
||||
"Action button labels" = "Textes des boutons d'action";
|
||||
"File information" = "Informations sur le fichier";
|
||||
"Export Settings" = "Paramètres d'exportation";
|
||||
"Import Settings..." = "Importer des paramètres...";
|
||||
"Other" = "Autres";
|
||||
"Other data" = "Autres données";
|
||||
"Other data include last used playback preferences and listing options" = "Les autres données incluent les dernières préférences de lecture et de liste utilisées";
|
||||
"Are you sure you want to export unencrypted passwords?" = "Êtes-vous sûr de vouloir exporter les mots de passe non chiffrés ?";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "Ne partagez pas ce fichier avec qui que ce soit, sinon vous risquez de perdre l'accès à vos comptes. Si vous ne choisissez pas d'exporter les mots de passe, il vous sera demandé de les fournir lors de l'importation";
|
||||
"Platform" = "Plateforme";
|
||||
"Icon only" = "Icône uniquement";
|
||||
"Icon and text" = "Icône et texte";
|
||||
"Custom Location already exists" = "L'emplacement personnalisé existe déjà";
|
||||
"Custom Location selected for import" = "Emplacement personnalisé sélectionné pour l'importation";
|
||||
"Custom Location not selected for import" = "Emplacement personnalisé non sélectionné pour l'importation";
|
||||
"Password required to import" = "Mot de passe requis pour l'importation";
|
||||
"Account already exists" = "Le compte existe déjà";
|
||||
"Password saved in import file" = "Mot de passe enregistré dans le fichier d'importation";
|
||||
"Export in progress..." = "Exportation en cours...";
|
||||
"In progress..." = "En cours…";
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"No preview" = "プレビューなし";
|
||||
"Open vertical chapters expanded" = "チャプターを縦方向に開く";
|
||||
"Chapters (if available)" = "チャプター (あれば)";
|
||||
"Password required to import" = "取り込むにはパスワードが必要です";
|
||||
"Export..." = "出力…";
|
||||
"Other data include last used playback preferences and listing options" = "ほかのデータには、最後に使った再生設定と一覧オプションを含む";
|
||||
"File information" = "ファイル情報";
|
||||
"Platform" = "プラットフォーム";
|
||||
"Icon and text" = "アイコンと文字";
|
||||
"Custom Location not selected for import" = "指定の場所は取り込み用に選択されていません";
|
||||
"Import Settings..." = "設定の取り込み...";
|
||||
"Export Settings" = "設定を出力";
|
||||
"Accounts passwords (unencrypted)" = "アカウントのパスワード (暗号化なし)";
|
||||
"Other" = "ほか";
|
||||
"Other data" = "ほかのデータ";
|
||||
"Are you sure you want to export unencrypted passwords?" = "暗号化のないパスワードを本当に出力しますか?";
|
||||
"Custom Location selected for import" = "指定の場所は取り込み用に選択済み";
|
||||
"Export" = "出力";
|
||||
"Build" = "ビルド";
|
||||
"Import" = "取り込み";
|
||||
"Icon only" = "アイコンのみ";
|
||||
"Action button labels" = "操作ボタンの表示";
|
||||
"Export in progress..." = "エクスポート中...";
|
||||
"In progress..." = "実行中…";
|
||||
"Password saved in import file" = "取り込みファイルにパスワードを保存しました";
|
||||
"Account already exists" = "アカウントは既に存在します";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "このファイルを他の人と共有しないでください。パスワードを出力していなければ、取り込み時にパスワードが求められます";
|
||||
"Custom Location already exists" = "指定の場所は既に存在します";
|
||||
|
||||
@@ -605,3 +605,28 @@
|
||||
"No preview" = "Brak podglądu";
|
||||
"Open vertical chapters expanded" = "Otwórz pionowe rozdziały rozwinięte";
|
||||
"Chapters (if available)" = "Rozdziały (jeśli dostępne)";
|
||||
"Import Settings..." = "Importuj Ustawienia…";
|
||||
"Export Settings" = "Eksportuj Ustawienia";
|
||||
"Export" = "Eksportuj";
|
||||
"Accounts passwords (unencrypted)" = "Hasła kont (nieszyfrowane)";
|
||||
"Other" = "Inne";
|
||||
"Other data" = "Inne dane";
|
||||
"Export..." = "Eksportuj…";
|
||||
"Other data include last used playback preferences and listing options" = "Inne dane obejmują ostatnie preferencje odtwarzania i opcje listowania";
|
||||
"Are you sure you want to export unencrypted passwords?" = "Czy na pewno eksportować nieszyfrowane hasła?";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "Nie dziel się z nikim tym plikiem albo możesz stracić dostęp do swoich kont. Jeśli nie wybierzesz eksportu haseł, zostaniesz o nie zapytany podczas importu";
|
||||
"File information" = "Informacje o pliku";
|
||||
"Build" = "Wersja";
|
||||
"Platform" = "Platforma";
|
||||
"Import" = "Importuj";
|
||||
"Action button labels" = "Etykiety przycisków akcji";
|
||||
"Icon only" = "Tylko ikony";
|
||||
"Icon and text" = "Ikony i tekst";
|
||||
"Custom Location already exists" = "Własna Lokalizacja już istnieje";
|
||||
"Custom Location selected for import" = "Lokalizacja wybrana do zaimportowania";
|
||||
"Custom Location not selected for import" = "Lokalizacji nie wybrano do zaimportowania";
|
||||
"Password required to import" = "Hasło wymagane do zaimportowania";
|
||||
"Password saved in import file" = "Hasło zapisane w importowanym pliku";
|
||||
"Account already exists" = "Konto już istnieje";
|
||||
"Export in progress..." = "Eksport w toku…";
|
||||
"In progress..." = "W trakcie…";
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"No preview" = "Sem prévia";
|
||||
"Open vertical chapters expanded" = "Abrir capítulos verticais expandidos";
|
||||
"Chapters (if available)" = "Capítulos (se disponível)";
|
||||
"Password required to import" = "Senha necessária para importar";
|
||||
"Export Settings" = "Exportar Ajustes";
|
||||
"Accounts passwords (unencrypted)" = "Senhas das contas (não encriptadas)";
|
||||
"Other" = "Outro";
|
||||
"Export" = "Exportar";
|
||||
"Build" = "Compilação";
|
||||
"Action button labels" = "Rótulos dos botões de ação";
|
||||
"Icon and text" = "Ícone e texto";
|
||||
"Password saved in import file" = "Senha salva em arquivo de importação";
|
||||
"Export in progress..." = "Exportação em progresso…";
|
||||
"In progress..." = "Em progresso…";
|
||||
"Import Settings..." = "Importar Ajustes…";
|
||||
"Other data" = "Outros dados";
|
||||
"Other data include last used playback preferences and listing options" = "Outros dados incluem as preferências de playback usadas pela última vez e opções de listagem";
|
||||
"Export..." = "Exportar…";
|
||||
"Platform" = "Plataforma";
|
||||
"Are you sure you want to export unencrypted passwords?" = "Tem certeza que deseja exportar senhas sem criptografia?";
|
||||
"Icon only" = "Apenas ícone";
|
||||
"Custom Location already exists" = "Localização Personalizada já existe";
|
||||
"Custom Location selected for import" = "Localização Personalizada selecionada para importação";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "Não compartilhe este arquivo com ninguém, ou você poderá perder acesso às suas contas. Se você não selecionar a exportação de senhas, será perguntado por elas durante a importação";
|
||||
"File information" = "Informação do arquivo";
|
||||
"Import" = "Importar";
|
||||
"Custom Location not selected for import" = "Localização Personalizada não selecionada para importação";
|
||||
"Account already exists" = "Conta já existe";
|
||||
|
||||
@@ -604,3 +604,28 @@
|
||||
"Description preview" = "Descriere preview";
|
||||
"No preview" = "Fără previzualizare";
|
||||
"Chapters (if available)" = "Capitole (dacă există)";
|
||||
"Password required to import" = "Parolă necesară pentru a importa";
|
||||
"Import Settings..." = "Importă Setări...";
|
||||
"Export Settings" = "Exportă Setări";
|
||||
"Other" = "Alte";
|
||||
"Other data" = "Alte date";
|
||||
"Export..." = "Exportă…";
|
||||
"Other data include last used playback preferences and listing options" = "Alte date includ ultimele preferințe de redare utilizate și opțiunile de listare";
|
||||
"Are you sure you want to export unencrypted passwords?" = "Sigur doriți să exportați parole necriptate?";
|
||||
"Export" = "Exportă";
|
||||
"File information" = "Informații despre fișier";
|
||||
"Build" = "Build";
|
||||
"Platform" = "Platformă";
|
||||
"Import" = "Importă";
|
||||
"Action button labels" = "Etichete pentru butoanele de acțiune";
|
||||
"Icon only" = "Doar pictogramă";
|
||||
"Icon and text" = "Pictogramă și text";
|
||||
"Custom Location already exists" = "Locația customizată există deja";
|
||||
"Custom Location not selected for import" = "Locația customizată nu este selectată pentru importare";
|
||||
"Account already exists" = "Există deja un cont";
|
||||
"Password saved in import file" = "Parolă salvată în fișierul de import";
|
||||
"Export in progress..." = "Export în curs...";
|
||||
"In progress..." = "În curs…";
|
||||
"Custom Location selected for import" = "Locație customizată selectată pentru importare";
|
||||
"Accounts passwords (unencrypted)" = "Parolele conturilor (necriptate)";
|
||||
"Do not share this file with anyone or you can lose access to your accounts. If you don't select to export passwords you will be asked to provide them during import" = "Nu partajați acest fișier cu nimeni, altfel puteți pierde accesul la conturile tale. Dacă nu selectați să exportați parolele, vi se va cere să le furnizați în timpul importului";
|
||||
|
||||
@@ -662,6 +662,7 @@
|
||||
37A5DBC8285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; };
|
||||
37A5DBC9285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; };
|
||||
37A5DBCA285E371400CA4DD1 /* ControlBackgroundModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */; };
|
||||
37A6D4ED2B6E372700B26299 /* ImportSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A6D4EC2B6E372700B26299 /* ImportSettings.swift */; };
|
||||
37A7D6E32B67E303009CB1ED /* ImportSettingsFileModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 372C74692B67098A00BE179B /* ImportSettingsFileModel.swift */; };
|
||||
37A7D6E52B67E315009CB1ED /* SettingsGroupExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A7D6E42B67E315009CB1ED /* SettingsGroupExporter.swift */; };
|
||||
37A7D6E62B67E315009CB1ED /* SettingsGroupExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A7D6E42B67E315009CB1ED /* SettingsGroupExporter.swift */; };
|
||||
@@ -1360,6 +1361,7 @@
|
||||
37A362BD29537AAA00BDF328 /* PlaybackSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSettings.swift; sourceTree = "<group>"; };
|
||||
37A362C129537FED00BDF328 /* PlaybackSettingsPresentationDetents+Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PlaybackSettingsPresentationDetents+Backport.swift"; sourceTree = "<group>"; };
|
||||
37A5DBC7285E371400CA4DD1 /* ControlBackgroundModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlBackgroundModifier.swift; sourceTree = "<group>"; };
|
||||
37A6D4EC2B6E372700B26299 /* ImportSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportSettings.swift; sourceTree = "<group>"; };
|
||||
37A7D6E42B67E315009CB1ED /* SettingsGroupExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsGroupExporter.swift; sourceTree = "<group>"; };
|
||||
37A7D6E82B67E334009CB1ED /* BrowsingSettingsGroupExporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingSettingsGroupExporter.swift; sourceTree = "<group>"; };
|
||||
37A7D6EC2B67E3BF009CB1ED /* BrowsingSettingsGroupImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingSettingsGroupImporter.swift; sourceTree = "<group>"; };
|
||||
@@ -2162,6 +2164,7 @@
|
||||
37BBB33D2B6B9C80001C4845 /* Import */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37A6D4EC2B6E372700B26299 /* ImportSettings.swift */,
|
||||
37BBB3422B6BB88F001C4845 /* ImportSettingsAccountRow.swift */,
|
||||
372C74622B66FFFC00BE179B /* ImportSettingsFileImporterViewModifier.swift */,
|
||||
37BBB33E2B6B9D52001C4845 /* ImportSettingsSheetView.swift */,
|
||||
@@ -3840,6 +3843,7 @@
|
||||
37E80F45287B7AC000561799 /* ControlsBar.swift in Sources */,
|
||||
3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
|
||||
376BE50827347B57009AD608 /* SettingsHeader.swift in Sources */,
|
||||
37A6D4ED2B6E372700B26299 /* ImportSettings.swift in Sources */,
|
||||
37A9966026D6F9B9006E3224 /* HomeView.swift in Sources */,
|
||||
372820402945E4A8009A0E2D /* SubscriptionsPageButton.swift in Sources */,
|
||||
37001565271B1F250049C794 /* AccountsModel.swift in Sources */,
|
||||
@@ -4055,7 +4059,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
||||
@@ -4086,7 +4090,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||
@@ -4117,7 +4121,7 @@
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
@@ -4137,7 +4141,7 @@
|
||||
buildSettings = {
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
@@ -4301,7 +4305,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
@@ -4354,7 +4358,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
||||
@@ -4406,7 +4410,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -4445,7 +4449,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
@@ -4480,7 +4484,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -4504,7 +4508,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -4530,7 +4534,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -4555,7 +4559,7 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@@ -4581,7 +4585,7 @@
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -4621,7 +4625,7 @@
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -4662,7 +4666,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -4686,7 +4690,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 177;
|
||||
CURRENT_PROJECT_VERSION = 179;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
@@ -4996,8 +5000,8 @@
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/cxfksword/MPVKit.git";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 0.36.0;
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.36.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"location" : "https://github.com/hyperoslo/Cache.git",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "d048bf404a5c8362c6cf840c2096d5777975cd27"
|
||||
"revision" : "a73f7d09534c35a509d2914849a75c15c12fbbbd"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -60,8 +60,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/cxfksword/MPVKit.git",
|
||||
"state" : {
|
||||
"revision" : "96825b3dc2b38e5550268156148d47798ce6aa74",
|
||||
"version" : "0.36.0"
|
||||
"revision" : "645f430ff0b99ccc2c61062727ad7e8bf32ca72a",
|
||||
"version" : "0.37.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -106,7 +106,7 @@
|
||||
"location" : "https://github.com/SDWebImage/SDWebImage",
|
||||
"state" : {
|
||||
"branch" : "master",
|
||||
"revision" : "a41be90abd89b125cd7588f20b9788108254091a"
|
||||
"revision" : "80c8b2023a5efb4415a2c615acfec075e5c243d2"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -132,8 +132,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/SDWebImage/SDWebImageWebPCoder.git",
|
||||
"state" : {
|
||||
"revision" : "acfb824ca5cd9dbde2c43dc6b5a008c6757dee85",
|
||||
"version" : "0.14.3"
|
||||
"revision" : "8a33fb3ca75a01267f775f891f7d61f675e95072",
|
||||
"version" : "0.14.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user