mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
Merge branch 'dev'
This commit is contained in:
commit
cf5451599b
12 changed files with 43 additions and 49 deletions
|
|
@ -183,7 +183,8 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
watchNextButton,
|
watchNextButton,
|
||||||
volumeSliderHostingView,
|
volumeSliderHostingView,
|
||||||
pipButton,
|
pipButton,
|
||||||
airplayButton
|
airplayButton,
|
||||||
|
timeBatteryContainer
|
||||||
].compactMap { $0 }
|
].compactMap { $0 }
|
||||||
|
|
||||||
private var originalHiddenStates: [UIView: Bool] = [:]
|
private var originalHiddenStates: [UIView: Bool] = [:]
|
||||||
|
|
@ -237,13 +238,9 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
let asset: AVURLAsset
|
let asset: AVURLAsset
|
||||||
|
|
||||||
// Check if this is a local file URL
|
|
||||||
if url.scheme == "file" {
|
if url.scheme == "file" {
|
||||||
// For local files, don't add HTTP headers
|
|
||||||
Logger.shared.log("Loading local file: \(url.absoluteString)", type: "Debug")
|
Logger.shared.log("Loading local file: \(url.absoluteString)", type: "Debug")
|
||||||
|
|
||||||
// Check if file exists
|
|
||||||
if FileManager.default.fileExists(atPath: url.path) {
|
if FileManager.default.fileExists(atPath: url.path) {
|
||||||
Logger.shared.log("Local file exists at path: \(url.path)", type: "Debug")
|
Logger.shared.log("Local file exists at path: \(url.path)", type: "Debug")
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -252,7 +249,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
|
|
||||||
asset = AVURLAsset(url: url)
|
asset = AVURLAsset(url: url)
|
||||||
} else {
|
} else {
|
||||||
// For remote URLs, add HTTP headers
|
|
||||||
Logger.shared.log("Loading remote URL: \(url.absoluteString)", type: "Debug")
|
Logger.shared.log("Loading remote URL: \(url.absoluteString)", type: "Debug")
|
||||||
var request = URLRequest(url: url)
|
var request = URLRequest(url: url)
|
||||||
if let mydict = headers, !mydict.isEmpty {
|
if let mydict = headers, !mydict.isEmpty {
|
||||||
|
|
@ -271,8 +267,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
|
|
||||||
let playerItem = AVPlayerItem(asset: asset)
|
let playerItem = AVPlayerItem(asset: asset)
|
||||||
self.player = AVPlayer(playerItem: playerItem)
|
self.player = AVPlayer(playerItem: playerItem)
|
||||||
|
|
||||||
// Add error observation
|
|
||||||
playerItem.addObserver(self, forKeyPath: "status", options: [.new], context: &playerItemKVOContext)
|
playerItem.addObserver(self, forKeyPath: "status", options: [.new], context: &playerItemKVOContext)
|
||||||
|
|
||||||
Logger.shared.log("Created AVPlayerItem with status: \(playerItem.status.rawValue)", type: "Debug")
|
Logger.shared.log("Created AVPlayerItem with status: \(playerItem.status.rawValue)", type: "Debug")
|
||||||
|
|
@ -1357,6 +1351,12 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
airplayButton.setContentCompressionResistancePriority(.required, for: .horizontal)
|
airplayButton.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
controlsContainerView.addSubview(airplayButton)
|
controlsContainerView.addSubview(airplayButton)
|
||||||
|
|
||||||
|
airplayButton.layer.shadowColor = UIColor.black.cgColor
|
||||||
|
airplayButton.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||||
|
airplayButton.layer.shadowOpacity = 0.6
|
||||||
|
airplayButton.layer.shadowRadius = 4
|
||||||
|
airplayButton.layer.masksToBounds = false
|
||||||
|
|
||||||
guard AVPictureInPictureController.isPictureInPictureSupported() else {
|
guard AVPictureInPictureController.isPictureInPictureSupported() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1368,7 +1368,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
pipController = AVPictureInPictureController(playerLayer: pipPlayerLayer)
|
pipController = AVPictureInPictureController(playerLayer: pipPlayerLayer)
|
||||||
pipController?.delegate = self
|
pipController?.delegate = self
|
||||||
|
|
||||||
|
|
||||||
let config = UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)
|
let config = UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)
|
||||||
let Image = UIImage(systemName: "pip", withConfiguration: config)
|
let Image = UIImage(systemName: "pip", withConfiguration: config)
|
||||||
pipButton = UIButton(type: .system)
|
pipButton = UIButton(type: .system)
|
||||||
|
|
@ -1391,7 +1390,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
pipButton.widthAnchor.constraint(equalToConstant: 44),
|
pipButton.widthAnchor.constraint(equalToConstant: 44),
|
||||||
pipButton.heightAnchor.constraint(equalToConstant: 44),
|
pipButton.heightAnchor.constraint(equalToConstant: 44),
|
||||||
airplayButton.centerYAnchor.constraint(equalTo: pipButton.centerYAnchor),
|
airplayButton.centerYAnchor.constraint(equalTo: pipButton.centerYAnchor),
|
||||||
airplayButton.trailingAnchor.constraint(equalTo: pipButton.leadingAnchor, constant: -6),
|
airplayButton.trailingAnchor.constraint(equalTo: pipButton.leadingAnchor, constant: -4),
|
||||||
airplayButton.widthAnchor.constraint(equalToConstant: 44),
|
airplayButton.widthAnchor.constraint(equalToConstant: 44),
|
||||||
airplayButton.heightAnchor.constraint(equalToConstant: 44)
|
airplayButton.heightAnchor.constraint(equalToConstant: 44)
|
||||||
])
|
])
|
||||||
|
|
@ -1416,11 +1415,11 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
menuButton.isHidden = true
|
menuButton.isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissButton.layer.shadowColor = UIColor.black.cgColor
|
menuButton.layer.shadowColor = UIColor.black.cgColor
|
||||||
dismissButton.layer.shadowOffset = CGSize(width: 0, height: 2)
|
menuButton.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||||
dismissButton.layer.shadowOpacity = 0.6
|
menuButton.layer.shadowOpacity = 0.6
|
||||||
dismissButton.layer.shadowRadius = 4
|
menuButton.layer.shadowRadius = 4
|
||||||
dismissButton.layer.masksToBounds = false
|
menuButton.layer.masksToBounds = false
|
||||||
|
|
||||||
controlsContainerView.addSubview(menuButton)
|
controlsContainerView.addSubview(menuButton)
|
||||||
menuButton.translatesAutoresizingMaskIntoConstraints = false
|
menuButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
@ -2831,7 +2830,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setupTimeBatteryIndicator() {
|
private func setupTimeBatteryIndicator() {
|
||||||
// Create container
|
|
||||||
let container = UIView()
|
let container = UIView()
|
||||||
container.translatesAutoresizingMaskIntoConstraints = false
|
container.translatesAutoresizingMaskIntoConstraints = false
|
||||||
container.backgroundColor = .clear
|
container.backgroundColor = .clear
|
||||||
|
|
@ -2839,7 +2837,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
controlsContainerView.addSubview(container)
|
controlsContainerView.addSubview(container)
|
||||||
self.timeBatteryContainer = container
|
self.timeBatteryContainer = container
|
||||||
|
|
||||||
// Create time label
|
|
||||||
let timeLabel = UILabel()
|
let timeLabel = UILabel()
|
||||||
timeLabel.translatesAutoresizingMaskIntoConstraints = false
|
timeLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
timeLabel.textColor = .white
|
timeLabel.textColor = .white
|
||||||
|
|
@ -2848,13 +2845,11 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
container.addSubview(timeLabel)
|
container.addSubview(timeLabel)
|
||||||
self.timeLabel = timeLabel
|
self.timeLabel = timeLabel
|
||||||
|
|
||||||
// Create separator
|
|
||||||
let separator = UIView()
|
let separator = UIView()
|
||||||
separator.translatesAutoresizingMaskIntoConstraints = false
|
separator.translatesAutoresizingMaskIntoConstraints = false
|
||||||
separator.backgroundColor = .white.withAlphaComponent(0.5)
|
separator.backgroundColor = .white.withAlphaComponent(0.5)
|
||||||
container.addSubview(separator)
|
container.addSubview(separator)
|
||||||
|
|
||||||
// Create battery label
|
|
||||||
let batteryLabel = UILabel()
|
let batteryLabel = UILabel()
|
||||||
batteryLabel.translatesAutoresizingMaskIntoConstraints = false
|
batteryLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
batteryLabel.textColor = .white
|
batteryLabel.textColor = .white
|
||||||
|
|
@ -2863,7 +2858,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
container.addSubview(batteryLabel)
|
container.addSubview(batteryLabel)
|
||||||
self.batteryLabel = batteryLabel
|
self.batteryLabel = batteryLabel
|
||||||
|
|
||||||
// Setup constraints
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
container.centerXAnchor.constraint(equalTo: controlsContainerView.centerXAnchor),
|
container.centerXAnchor.constraint(equalTo: controlsContainerView.centerXAnchor),
|
||||||
container.topAnchor.constraint(equalTo: sliderHostingController?.view.bottomAnchor ?? controlsContainerView.bottomAnchor, constant: 2),
|
container.topAnchor.constraint(equalTo: sliderHostingController?.view.bottomAnchor ?? controlsContainerView.bottomAnchor, constant: 2),
|
||||||
|
|
@ -2884,19 +2878,14 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
batteryLabel.widthAnchor.constraint(equalToConstant: 50)
|
batteryLabel.widthAnchor.constraint(equalToConstant: 50)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Start time updates
|
|
||||||
updateTime()
|
updateTime()
|
||||||
timeUpdateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
timeUpdateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
self?.updateTime()
|
self?.updateTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup battery monitoring
|
|
||||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||||
updateBatteryLevel()
|
updateBatteryLevel()
|
||||||
NotificationCenter.default.addObserver(self,
|
NotificationCenter.default.addObserver(self, selector: #selector(batteryLevelDidChange), name: UIDevice.batteryLevelDidChangeNotification, object: nil)
|
||||||
selector: #selector(batteryLevelDidChange),
|
|
||||||
name: UIDevice.batteryLevelDidChangeNotification,
|
|
||||||
object: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateTime() {
|
private func updateTime() {
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,6 @@ class VideoPlayerViewController: UIViewController {
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
// Only start normal playback if not launched from SharePlay
|
|
||||||
if !isLaunchedFromSharePlay {
|
if !isLaunchedFromSharePlay {
|
||||||
player?.play()
|
player?.play()
|
||||||
setInitialPlayerRate()
|
setInitialPlayerRate()
|
||||||
|
|
@ -217,7 +216,6 @@ class VideoPlayerViewController: UIViewController {
|
||||||
await checkForFaceTimeAndPromptSharePlay()
|
await checkForFaceTimeAndPromptSharePlay()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For SharePlay launches, the playback will be coordinated
|
|
||||||
setInitialPlayerRate()
|
setInitialPlayerRate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
// Created by Francesco on 05/01/25.
|
// Created by Francesco on 05/01/25.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Network
|
import Network
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class FetchDelegate: NSObject, URLSessionTaskDelegate {
|
class FetchDelegate: NSObject, URLSessionTaskDelegate {
|
||||||
private let allowRedirects: Bool
|
private let allowRedirects: Bool
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ struct ModuleAdditionSettingsView: View {
|
||||||
@State private var errorMessage: String?
|
@State private var errorMessage: String?
|
||||||
var moduleUrl: String
|
var moduleUrl: String
|
||||||
|
|
||||||
|
private var moduleAlreadyExists: Bool {
|
||||||
|
if let metadata = moduleMetadata {
|
||||||
|
return moduleManager.modules.contains(where: { $0.metadata.sourceName == metadata.sourceName })
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
|
|
@ -87,7 +94,7 @@ struct ModuleAdditionSettingsView: View {
|
||||||
.fill(Color(.systemGray5))
|
.fill(Color(.systemGray5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(width: 32, height: 32)
|
.frame(width: 40, height: 40)
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
.shadow(
|
.shadow(
|
||||||
color: colorScheme == .dark
|
color: colorScheme == .dark
|
||||||
|
|
@ -194,10 +201,11 @@ struct ModuleAdditionSettingsView: View {
|
||||||
Button(action: addModule) {
|
Button(action: addModule) {
|
||||||
HStack {
|
HStack {
|
||||||
Image(systemName: "plus.circle.fill")
|
Image(systemName: "plus.circle.fill")
|
||||||
Text("Add Module")
|
.foregroundColor(colorScheme == .dark ? .black : .white)
|
||||||
|
Text(moduleAlreadyExists ? "Module already added" : "Add Module")
|
||||||
}
|
}
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(Color.accentColor)
|
.foregroundColor(colorScheme == .dark ? .black : .white)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.padding(.vertical, 14)
|
.padding(.vertical, 14)
|
||||||
.background(
|
.background(
|
||||||
|
|
@ -219,8 +227,8 @@ struct ModuleAdditionSettingsView: View {
|
||||||
)
|
)
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
}
|
}
|
||||||
.disabled(isLoading || moduleMetadata == nil)
|
.disabled(isLoading || moduleMetadata == nil || moduleAlreadyExists)
|
||||||
.opacity(isLoading ? 0.6 : 1)
|
.opacity(isLoading || moduleAlreadyExists ? 0.6 : 1)
|
||||||
|
|
||||||
Button(action: { presentationMode.wrappedValue.dismiss() }) {
|
Button(action: { presentationMode.wrappedValue.dismiss() }) {
|
||||||
Text("Cancel")
|
Text("Cancel")
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,6 @@ struct AllBookmarks: View {
|
||||||
}
|
}
|
||||||
Button(action: {
|
Button(action: {
|
||||||
if isSelecting {
|
if isSelecting {
|
||||||
// If trash icon tapped
|
|
||||||
if !selectedBookmarks.isEmpty {
|
if !selectedBookmarks.isEmpty {
|
||||||
for id in selectedBookmarks {
|
for id in selectedBookmarks {
|
||||||
if let item = libraryManager.bookmarks.first(where: { $0.id == id }) {
|
if let item = libraryManager.bookmarks.first(where: { $0.id == id }) {
|
||||||
|
|
|
||||||
|
|
@ -266,12 +266,17 @@ struct AllWatchingView: View {
|
||||||
UserDefaults.standard.set(99999999.0, forKey: key)
|
UserDefaults.standard.set(99999999.0, forKey: key)
|
||||||
UserDefaults.standard.set(99999999.0, forKey: totalKey)
|
UserDefaults.standard.set(99999999.0, forKey: totalKey)
|
||||||
ContinueWatchingManager.shared.remove(item: item)
|
ContinueWatchingManager.shared.remove(item: item)
|
||||||
loadContinueWatchingItems()
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
loadContinueWatchingItems()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeItem(item: ContinueWatchingItem) {
|
private func removeItem(item: ContinueWatchingItem) {
|
||||||
ContinueWatchingManager.shared.remove(item: item)
|
ContinueWatchingManager.shared.remove(item: item)
|
||||||
loadContinueWatchingItems()
|
DispatchQueue.main.async {
|
||||||
|
loadContinueWatchingItems()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1508,7 +1508,7 @@ struct MediaInfoView: View {
|
||||||
|
|
||||||
alert.addAction(UIAlertAction(title: title, style: .default) { _ in
|
alert.addAction(UIAlertAction(title: title, style: .default) { _ in
|
||||||
guard self.activeFetchID == fetchID else { return }
|
guard self.activeFetchID == fetchID else { return }
|
||||||
self.playStream(url: streamUrl, fullURL: href, subtitles: subtitles, headers: headers, fetchID: fetchID)
|
self.playStream(url: streamUrl, fullURL: fullURL, subtitles: subtitles, headers: headers, fetchID: fetchID)
|
||||||
})
|
})
|
||||||
|
|
||||||
streamIndex += 1
|
streamIndex += 1
|
||||||
|
|
|
||||||
|
|
@ -275,9 +275,6 @@ struct SettingsViewGeneral: View {
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
|
|
||||||
Divider()
|
|
||||||
.padding(.horizontal, 16)
|
|
||||||
|
|
||||||
List {
|
List {
|
||||||
ForEach(Array(metadataProvidersOrder.enumerated()), id: \.element) { index, provider in
|
ForEach(Array(metadataProvidersOrder.enumerated()), id: \.element) { index, provider in
|
||||||
HStack {
|
HStack {
|
||||||
|
|
@ -358,8 +355,6 @@ struct SettingsViewGeneral: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.vertical, 20)
|
.padding(.vertical, 20)
|
||||||
.scrollViewBottomPadding()
|
|
||||||
.navigationTitle("General")
|
|
||||||
}
|
}
|
||||||
.navigationTitle(NSLocalizedString("General", comment: ""))
|
.navigationTitle(NSLocalizedString("General", comment: ""))
|
||||||
.scrollViewBottomPadding()
|
.scrollViewBottomPadding()
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ struct SubtitleSettingsSection: View {
|
||||||
icon: "captions.bubble",
|
icon: "captions.bubble",
|
||||||
title: NSLocalizedString("Enable Subtitles", comment: ""),
|
title: NSLocalizedString("Enable Subtitles", comment: ""),
|
||||||
isOn: $subtitlesEnabled,
|
isOn: $subtitlesEnabled,
|
||||||
showDivider: false
|
showDivider: true
|
||||||
)
|
)
|
||||||
.onChange(of: subtitlesEnabled) { newValue in
|
.onChange(of: subtitlesEnabled) { newValue in
|
||||||
SubtitleSettingsManager.shared.update { settings in
|
SubtitleSettingsManager.shared.update { settings in
|
||||||
|
|
@ -454,4 +454,4 @@ struct SubtitleSettingsSection: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ struct SplashScreenView: View {
|
||||||
isAnimating = true
|
isAnimating = true
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||||
withAnimation(.easeOut(duration: 0.5)) {
|
withAnimation(.easeOut(duration: 0.5)) {
|
||||||
showMainApp = true
|
showMainApp = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -247,12 +247,12 @@
|
||||||
path = SearchView;
|
path = SearchView;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
0409FE832DFF0870000DB00C /* cz.lproj */ = {
|
0409FE832DFF0870000DB00C /* cs.lproj */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0409FE822DFF0870000DB00C /* Localizable.strings */,
|
0409FE822DFF0870000DB00C /* Localizable.strings */,
|
||||||
);
|
);
|
||||||
path = cz.lproj;
|
path = cs.lproj;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
0409FE862DFF0870000DB00C /* es.lproj */ = {
|
0409FE862DFF0870000DB00C /* es.lproj */ = {
|
||||||
|
|
@ -632,7 +632,7 @@
|
||||||
0410697D2E00ABE900A157BB /* sk.lproj */,
|
0410697D2E00ABE900A157BB /* sk.lproj */,
|
||||||
04A1B73B2DFF39EB0064688A /* nn.lproj */,
|
04A1B73B2DFF39EB0064688A /* nn.lproj */,
|
||||||
0409FE8B2DFF2886000DB00C /* ru.lproj */,
|
0409FE8B2DFF2886000DB00C /* ru.lproj */,
|
||||||
0409FE832DFF0870000DB00C /* cz.lproj */,
|
0409FE832DFF0870000DB00C /* cs.lproj */,
|
||||||
0409FE862DFF0870000DB00C /* es.lproj */,
|
0409FE862DFF0870000DB00C /* es.lproj */,
|
||||||
0488FA9B2DFDF385007575E1 /* ar.lproj */,
|
0488FA9B2DFDF385007575E1 /* ar.lproj */,
|
||||||
0488FA972DFDF334007575E1 /* fr.lproj */,
|
0488FA972DFDF334007575E1 /* fr.lproj */,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue