Skip to content
Open
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
6 changes: 4 additions & 2 deletions Feather/Backend/Observable/OptionsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct Options: Codable, Equatable {
var ppqProtection: Bool
/// (Better) protection against PPQ
var dynamicProtection: Bool
/// Automatically select certificate that matches target bundle identifier
var autoSelectMatchingCertificate: Bool = false
/// App identifiers list which matches and replaces
var identifiers: [String: String]
/// App name list which matches and replaces
Expand Down Expand Up @@ -130,6 +132,7 @@ struct Options: Codable, Equatable {
ppqString: randomString(),
ppqProtection: false,
dynamicProtection: false,
autoSelectMatchingCertificate: false,
identifiers: [:],
displayNames: [:],
injectionFiles: [],
Expand All @@ -155,8 +158,6 @@ struct Options: Codable, Equatable {
post_deleteAppAfterSigned: false
)

// MARK: duplicate values are not recommended!

enum AppAppearance: String, Codable, CaseIterable, LocalizedDescribable {
case `default`
case light = "Light"
Expand Down Expand Up @@ -233,3 +234,4 @@ extension LocalizedDescribable where Self: RawRepresentable, RawValue == String
return localized == self.rawValue ? self.rawValue : localized
}
}

12 changes: 12 additions & 0 deletions Feather/Resources/Assets.xcassets/discord.symbolset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"symbols" : [
{
"filename" : "discord.svg",
"idiom" : "universal"
}
]
}
199 changes: 199 additions & 0 deletions Feather/Resources/Assets.xcassets/discord.symbolset/discord.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions Feather/Resources/Assets.xcassets/github.symbolset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"symbols" : [
{
"filename" : "github.svg",
"idiom" : "universal"
}
]
}
167 changes: 167 additions & 0 deletions Feather/Resources/Assets.xcassets/github.symbolset/github.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 105 additions & 13 deletions Feather/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -1504,6 +1504,23 @@
}
}
},
"Auto-select Matching Certificate" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Auto-select Matching Certificate"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Automatyczny wybór pasującego certyfikatu"
}
}
}
},
"Bad Password" : {
"comment" : "Bad certificate password",
"extractionState" : "manual",
Expand Down Expand Up @@ -2541,6 +2558,23 @@
}
}
},
"Connect to LocalDevVPN" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Connect to LocalDevVPN"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Połącz do LocalDevVPN"
}
}
}
},
"Copy" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -3622,6 +3656,23 @@
}
}
},
"Download LocalDevVPN" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Download LocalDevVPN"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Pobierz LocalDevVPN"
}
}
}
},
"Download StosVPN" : {
"comment" : "Don't translate StosVPN, this is for linking the download to the required VPN for idevice",
"extractionState" : "manual",
Expand Down Expand Up @@ -6943,6 +6994,12 @@
"value" : "Install After Signing"
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Zainstaluj po podpisaniu"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
Expand Down Expand Up @@ -7244,10 +7301,16 @@
"value" : "Join Us on Discord"
}
},
"vi": {
"stringUnit": {
"state": "translated",
"value": "Hãy tham gia cùng chúng tôi trên Discord!"
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Dołącz do nas na Discordzie"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hãy tham gia cùng chúng tôi trên Discord!"
}
}
}
Expand Down Expand Up @@ -8430,10 +8493,16 @@
"value" : "No sources to copy"
}
},
"vi": {
"stringUnit": {
"state": "translated",
"value": "Không có nguồn để sao chép"
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Brak źródeł do skopiowania"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Không có nguồn để sao chép"
}
}
}
Expand Down Expand Up @@ -12800,10 +12869,16 @@
"value" : "Sources copied to clipboard"
}
},
"vi": {
"stringUnit": {
"state": "translated",
"value": "Nguồn đã được sao chép vào bộ nhớ tạm"
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Źródła skopiowane do schowka"
}
},
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nguồn đã được sao chép vào bộ nhớ tạm"
}
}
}
Expand Down Expand Up @@ -14687,6 +14762,23 @@
}
}
},
"When enabled, Feather will automatically select the certificate whose application-identifier exactly matches the target bundle identifier." : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "When enabled, Feather will automatically select the certificate whose application-identifier exactly matches the target bundle identifier."
}
},
"pl" : {
"stringUnit" : {
"state" : "translated",
"value" : "Gdy włączone, Feather automatycznie wybierze certyfikat, którego application-identifier dokładnie odpowiada docelowemu identyfikatorowi pakietu (bundle identifier)."
}
}
}
},
"You cannot update ‘%@‘ with itself, please use an alternative tool to update it." : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -14789,4 +14881,4 @@
}
},
"version" : "1.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct ArchiveView: View {
var body: some View {
NBList(.localized("Archive & Compression")) {
Section {
Picker(.localized("Compression Level"), systemImage: "archivebox", selection: $_compressionLevel) {
Picker(.localized("Compression Level"), systemImage: "doc.zipper", selection: $_compressionLevel) {
ForEach(ZipCompression.allCases, id: \.rawValue) { level in
Text(level.label).tag(level)
}
Expand Down
35 changes: 30 additions & 5 deletions Feather/Views/Settings/Certificates/CertificatesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct CertificatesView: View {

@State private var _isAddingPresenting = false
@State private var _isSelectedInfoPresenting: CertificatePair?
@State private var _searchText: String = ""

// MARK: Fetch
@FetchRequest(
Expand All @@ -27,6 +28,22 @@ struct CertificatesView: View {
private var _selectedCertBinding: Binding<Int> {
_bindingSelectedCert ?? $_storedSelectedCert
}

// Filtered certificates based on search
private var _filteredCertificates: [CertificatePair] {
let items = Array(_certificates)
let query = _searchText.trimmingCharacters(in: .whitespacesAndNewlines)
guard !query.isEmpty else { return items }
let q = query.lowercased()
return items.filter { cert in
let nickname = (cert.nickname ?? "").lowercased()
let decoded = Storage.shared.getProvisionFileDecoded(for: cert)
let name = (decoded?.Name ?? "").lowercased()
let appIDName = (decoded?.AppIDName ?? "").lowercased()
let haystack = "\(nickname) \(name) \(appIDName)"
return haystack.contains(q)
}
}

init(selectedCert: Binding<Int>? = nil) {
self._bindingSelectedCert = selectedCert
Expand All @@ -35,13 +52,17 @@ struct CertificatesView: View {
// MARK: Body
var body: some View {
NBGrid {
ForEach(Array(_certificates.enumerated()), id: \.element.uuid) { index, cert in
_cellButton(for: cert, at: index)
}
ForEach(_filteredCertificates, id: \.uuid) { cert in
if let originalIndex = _originalIndex(for: cert) {
_cellButton(for: cert, originalIndex: originalIndex)
}
}
}
.navigationTitle(.localized("Certificates"))
.searchable(text: $_searchText, placement: .platform())
.scrollDismissesKeyboard(.interactively)
.overlay {
if _certificates.isEmpty {
if _filteredCertificates.isEmpty {
if #available(iOS 17, *) {
ContentUnavailableView {
Label(.localized("No Certificates"), systemImage: "questionmark.folder.fill")
Expand Down Expand Up @@ -81,7 +102,7 @@ struct CertificatesView: View {
// MARK: - View extension
extension CertificatesView {
@ViewBuilder
private func _cellButton(for cert: CertificatePair, at index: Int) -> some View {
private func _cellButton(for cert: CertificatePair, originalIndex index: Int) -> some View {
Button {
_selectedCertBinding.wrappedValue = index
} label: {
Expand Down Expand Up @@ -114,6 +135,10 @@ extension CertificatesView {
.buttonStyle(.plain)
}

private func _originalIndex(for cert: CertificatePair) -> Int? {
return _certificates.firstIndex(where: { $0.objectID == cert.objectID })
}

@ViewBuilder
private func _actions(for cert: CertificatePair) -> some View {
Button(.localized("Delete"), systemImage: "trash", role: .destructive) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct TunnelView: View {
UIApplication.open("localdevvpn://enable?scheme=feather")
}
} else {
Button(.localized("Download LocalDevVPN"), systemImage: "arrow.down.app") {
Button(.localized("Download LocalDevVPN"), systemImage: "link.badge.plus") {
UIApplication.open("https://apps.apple.com/us/app/localdevvpn/id6755608044")
}
}
Expand Down Expand Up @@ -103,4 +103,4 @@ struct TunnelView: View {
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
}
}
}
}
22 changes: 17 additions & 5 deletions Feather/Views/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ struct SettingsView: View {
Label(.localized("Signing Options"), systemImage: "signature")
}
NavigationLink(destination: ArchiveView()) {
Label(.localized("Archive & Compression"), systemImage: "archivebox")
Label(.localized("Archive & Compression"), systemImage: "doc.zipper")
}
NavigationLink(destination: InstallationView()) {
Label(.localized("Installation"), systemImage: "arrow.down.circle")
Label(.localized("Installation"), systemImage: "plus.app")
}
} footer: {
Text(.localized("Configure the apps way of installing, its zip compression levels, and custom modifications to apps."))
Expand Down Expand Up @@ -83,7 +83,7 @@ extension SettingsView {
}
}

Button(.localized("Submit Feedback"), systemImage: "safari") {
Button(.localized("Submit Feedback"), systemImage: "square.text.square") {
let bugAction: UIAlertAction = .init(title: .localized("Bug Report"), style: .default) { _ in
UIApplication.open(_makeGitHubIssueURL(url: _githubUrl))
}
Expand All @@ -98,11 +98,23 @@ extension SettingsView {
actions: [bugAction, chooseAction]
)
}
Button(.localized("GitHub Repository"), systemImage: "safari") {
Button {
UIApplication.open(_githubUrl)
} label: {
Label {
Text(.localized("GitHub Repository"))
} icon: {
Image("github")
}
}
Button(.localized("Join Us on Discord"), systemImage: "safari") {
Button {
UIApplication.open(_discordServer)
} label: {
Label {
Text(.localized("Join Us on Discord"))
} icon: {
Image("discord")
}
}
} footer: {
Text(.localized("If any issues occur within the app please report it via the GitHub repository. When submitting an issue, make sure to submit detailed information."))
Expand Down
Loading