Skip to content

Commit

Permalink
feat: altstore news + copy dl links + disregard some errors
Browse files Browse the repository at this point in the history
  • Loading branch information
khcrysalis committed Feb 4, 2025
1 parent 7aa3c4f commit 95acb5d
Show file tree
Hide file tree
Showing 10 changed files with 305 additions and 4 deletions.
12 changes: 12 additions & 0 deletions Shared/Data/CoreData/Models/SourcesModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import Foundation
public struct SourcesData: Codable, Hashable {
public var name: String?
public var identifier: String
public var tintColor: String?

public var sourceURL: URL?
public var iconURL: URL?
public var news: [NewsData]?
public var apps: [StoreAppsData]

public static func == (lhs: SourcesData, rhs: SourcesData) -> Bool {
Expand All @@ -26,6 +28,16 @@ public struct SourcesData: Codable, Hashable {
}
}

public struct NewsData: Codable, Hashable {
public let title: String
public let identifier: String
public let caption: String?
public let tintColor: String?
public let imageURL: String?
public let url: URL?
public let date: String
public let appID: String?
}

public struct StoreAppsData: Codable {
public var name: String
Expand Down
15 changes: 15 additions & 0 deletions Shared/Design/VariableBlurView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import UIKit
import SwiftUI

class UIVariableBlurView: UIView {
// MARK: - Private Properties
Expand Down Expand Up @@ -128,6 +129,20 @@ class UIVariableBlurView: UIView {
}
}

/// A variable blur view.
struct VariableBlurView: UIViewRepresentable {
func makeUIView(context: Context) -> UIVariableBlurView {
var view = UIVariableBlurView()

let gradientMask = VariableBlurViewConstants.defaultGradientMask
view = UIVariableBlurView(frame: .zero)
view.gradientMask = gradientMask
return view
}

func updateUIView(_ uiView: UIVariableBlurView, context: Context) {}
}

public enum VariableBlurViewConstants {

/// A gradient mask image (top is opaque, bottom is clear). The gradient includes easing.
Expand Down
20 changes: 20 additions & 0 deletions feather.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
33089A2A2D51F117006E1068 /* NewsCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33089A292D51F117006E1068 /* NewsCardView.swift */; };
33089A2C2D51F2CE006E1068 /* NewsCardsScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33089A2B2D51F2CE006E1068 /* NewsCardsScrollView.swift */; };
331616912C786B9B00894427 /* TransferPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331616902C786B9B00894427 /* TransferPreview.swift */; };
331616952C78D55100894427 /* Asspp.md in Resources */ = {isa = PBXBuildFile; fileRef = 331616942C78D55100894427 /* Asspp.md */; };
33163FF02C3D224C0038E1EC /* DownloadTaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33163FEF2C3D224C0038E1EC /* DownloadTaskManager.swift */; };
Expand Down Expand Up @@ -34,6 +36,7 @@
335F0C2E2C5E0FFF00A4F0AE /* CoreDataManager+Certificates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335F0C2D2C5E0FFF00A4F0AE /* CoreDataManager+Certificates.swift */; };
335F0C302C5E175B00A4F0AE /* CertData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335F0C2F2C5E175B00A4F0AE /* CertData.swift */; };
336EEE812C32367C0011188D /* ZIPFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 336EEE802C32367C0011188D /* ZIPFoundation */; };
3386515B2D52343500A85670 /* CardContextMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3386515A2D52343500A85670 /* CardContextMenuView.swift */; };
338FFCD92C682469006C3BE0 /* PopupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 338FFCD82C682469006C3BE0 /* PopupViewController.swift */; };
338FFCDB2C6870E2006C3BE0 /* LibraryViewController+Import.swift in Sources */ = {isa = PBXBuildFile; fileRef = 338FFCDA2C6870E2006C3BE0 /* LibraryViewController+Import.swift */; };
338FFCE42C695118006C3BE0 /* IconsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 338FFCE32C695118006C3BE0 /* IconsListViewController.swift */; };
Expand Down Expand Up @@ -148,6 +151,8 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
33089A292D51F117006E1068 /* NewsCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsCardView.swift; sourceTree = "<group>"; };
33089A2B2D51F2CE006E1068 /* NewsCardsScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsCardsScrollView.swift; sourceTree = "<group>"; };
331616902C786B9B00894427 /* TransferPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferPreview.swift; sourceTree = "<group>"; };
331616942C78D55100894427 /* Asspp.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Asspp.md; sourceTree = "<group>"; };
33163FE82C3D09980038E1EC /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
Expand Down Expand Up @@ -175,6 +180,7 @@
335F0C2B2C5DC3AE00A4F0AE /* CoreDataManager+SignedApps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoreDataManager+SignedApps.swift"; sourceTree = "<group>"; };
335F0C2D2C5E0FFF00A4F0AE /* CoreDataManager+Certificates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CoreDataManager+Certificates.swift"; sourceTree = "<group>"; };
335F0C2F2C5E175B00A4F0AE /* CertData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CertData.swift; sourceTree = "<group>"; };
3386515A2D52343500A85670 /* CardContextMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardContextMenuView.swift; sourceTree = "<group>"; };
338B0F0C2D0C0E8200C5EA11 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
338FFCD82C682469006C3BE0 /* PopupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupViewController.swift; sourceTree = "<group>"; };
338FFCDA2C6870E2006C3BE0 /* LibraryViewController+Import.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LibraryViewController+Import.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -328,9 +334,20 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
33089A282D51F0F3006E1068 /* News */ = {
isa = PBXGroup;
children = (
3386515A2D52343500A85670 /* CardContextMenuView.swift */,
33089A292D51F117006E1068 /* NewsCardView.swift */,
33089A2B2D51F2CE006E1068 /* NewsCardsScrollView.swift */,
);
path = News;
sourceTree = "<group>";
};
3322FF4A2BFEDAE8001768D8 /* SourceAppViews */ = {
isa = PBXGroup;
children = (
33089A282D51F0F3006E1068 /* News */,
3322FF482BFEC97F001768D8 /* SourceAppViewController.swift */,
3322FF4B2BFEDB01001768D8 /* SourceAppTableViewCell.swift */,
332476D72C3E4CF7008C8EF0 /* SourceAppActions.swift */,
Expand Down Expand Up @@ -1037,13 +1054,15 @@
3322FF4C2BFEDB01001768D8 /* SourceAppTableViewCell.swift in Sources */,
339CE2872C5850BA00B58502 /* CoreDataManager.swift in Sources */,
33BDD09B2C76BE3500AF6169 /* Decompression.swift in Sources */,
33089A2A2D51F117006E1068 /* NewsCardView.swift in Sources */,
332476ED2C3E92BC008C8EF0 /* DisplayCollectionTableViewCell.swift in Sources */,
339BDAE02BF953EE007009D9 /* BasicLayoutAnchorsHolding.swift in Sources */,
338FFCE42C695118006C3BE0 /* IconsListViewController.swift in Sources */,
339FE33B2CCE01F000C297BA /* IdentifiersViewController.swift in Sources */,
3A39AC782D030064002F54B0 /* BundleIdChecker.swift in Sources */,
3A39AC792D030064002F54B0 /* iTunesLookup.swift in Sources */,
D0651C112BFEE93C00D40829 /* zsign.mm in Sources */,
33089A2C2D51F2CE006E1068 /* NewsCardsScrollView.swift in Sources */,
332476DA2C3E4D35008C8EF0 /* SourceAppDownload.swift in Sources */,
33BE87632C6F17870044D245 /* SigningsInputViewController.swift in Sources */,
3322FF492BFEC97F001768D8 /* SourceAppViewController.swift in Sources */,
Expand All @@ -1066,6 +1085,7 @@
AFAC50952C48DF9300EDEAB6 /* AppSigner.swift in Sources */,
339FE33E2CCE06A100C297BA /* AddIdentifierViewController.swift in Sources */,
33BA37AB2BF8196000FF530A /* Preferences.swift in Sources */,
3386515B2D52343500A85670 /* CardContextMenuView.swift in Sources */,
D0651C392BFEEA4B00D40829 /* signing.cpp in Sources */,
33C0409B2C30B4A100243D90 /* AppDownload.swift in Sources */,
33BA37BA2BF9426100FF530A /* Sources.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion iOS/Delegates/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UIOnboardingViewControlle
try BGTaskScheduler.shared.submit(request)
Debug.shared.log(message: "Background refresh scheduled successfully", type: .info)
} catch {
Debug.shared.log(message: "Could not schedule app refresh: \(error.localizedDescription)", type: .error)
Debug.shared.log(message: "Could not schedule app refresh: \(error.localizedDescription)", type: .info)
}
}

Expand Down
6 changes: 3 additions & 3 deletions iOS/Operations/SourceRefreshOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import Foundation
allSourceData.append((data: sourceData, url: url))
}
case let .failure(error):
Debug.shared.log(message: "Source refresh error: \(error)", type: .error)
Debug.shared.log(message: "Source refresh error: \(error)", type: .info)
}
dispatchGroup.leave()
}
Expand Down Expand Up @@ -155,7 +155,7 @@ import Foundation
Debug.shared.log(message: "Source URL: \(firstApp.originalSourceURL?.absoluteString ?? "missing")", type: .info)

guard let bundleId = firstApp.bundleidentifier else {
Debug.shared.log(message: "Debug mode: Missing bundle identifier", type: .error)
Debug.shared.log(message: "Debug mode: Missing bundle identifier", type: .info)
completion(nil)
return
}
Expand Down Expand Up @@ -206,7 +206,7 @@ import Foundation
Debug.shared.log(message: "Debug mode: Successfully created mock source", type: .info)
completion(mockSource)
} else {
Debug.shared.log(message: "Debug mode: Failed to create mock source", type: .error)
Debug.shared.log(message: "Debug mode: Failed to create mock source", type: .info)
completion(nil)
}
} else {
Expand Down
63 changes: 63 additions & 0 deletions iOS/Views/Sources/SourceAppViews/News/CardContextMenuView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// CardContextMenuView.swift
// feather
//
// Created by samara on 4.02.2025.
//

import SwiftUI

struct CardContextMenuView: View {
let news: NewsData

var formattedDate: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
if let date = dateFormatter.date(from: news.date) {
return date.formatted(.relative(presentation: .named))
}
return news.date
}

var body: some View {
VStack(alignment: .leading, spacing: 12) {
AsyncImage(url: URL(string: news.imageURL ?? "")) { image in
image.resizable()
.aspectRatio(contentMode: .fill)
} placeholder: {
Color.gray
}
.frame(width: 280, height: 160)
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
.overlay(
LinearGradient(
gradient: Gradient(colors: [.clear, .black.opacity(0.2)]),
startPoint: .top,
endPoint: .bottom
)
)

VStack(alignment: .leading, spacing: 8) {
Text(news.title)
.font(.title3)
.fontWeight(.bold)
.lineLimit(2)

if let caption = news.caption {
Text(caption)
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
}

Text(formattedDate)
.font(.caption)
.foregroundColor(.secondary)
}
}
.frame(width: 280)
.padding()
.background(Color(uiColor: .systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
}
}
85 changes: 85 additions & 0 deletions iOS/Views/Sources/SourceAppViews/News/NewsCardView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// NewsCardView.swift
// feather
//
// Created by samara on 3.02.2025.
//

import SwiftUI

struct NewsCardView: View {
let news: NewsData

var body: some View {
ZStack(alignment: .bottomLeading) {
if (news.imageURL != nil) {
AsyncImage(url: URL(string: news.imageURL!)) { image in
Color.clear.overlay(
image
.resizable()
.aspectRatio(contentMode: .fill)
)
} placeholder: {
Color.black.opacity(0.2)
}

LinearGradient(
gradient: Gradient(colors: [.clear, .black.opacity(0.7)]),
startPoint: .top,
endPoint: .bottom
)
}
VariableBlurView()
.opacity(0.97)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.rotationEffect(.degrees(180))
.padding(.top, 95)

VStack {
Spacer()
Text(news.title)
.font(.headline)
.fontWeight(.bold)
.foregroundColor(.white)
.lineLimit(2)
.padding()
}
}
.frame(width: 250, height: 150)
.background(Color(uiColor: UIColor(hex: news.tintColor ?? "000000")))
.clipShape(
RoundedRectangle(cornerRadius: 12, style: .continuous)
)
.overlay(
RoundedRectangle(cornerRadius: 12, style: .continuous)
.stroke(Color.white.opacity(0.15), lineWidth: 2)
)
.compactContentMenuPreview(news: news)
}
}

extension View {
func compactContentMenuPreview(news: NewsData) -> some View {
if #available(iOS 16.0, *) {
return self.contextMenu {
if (news.url != nil) {
Button(action: {
UIApplication.shared.open(news.url!)
}) {
Label("Open URL", systemImage: "arrow.up.right")
}
} else {
Button(action: {
UIApplication.shared.open(URL(string: "https://github.com/khcrysalis/feather")!)
}) {
Label("Give us a star!", systemImage: "star")
}
}
} preview: {
CardContextMenuView(news: news)
}
} else {
return self
}
}
}
28 changes: 28 additions & 0 deletions iOS/Views/Sources/SourceAppViews/News/NewsCardsScrollView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// NewsCardsScrollView.swift
// feather
//
// Created by samara on 3.02.2025.
//

import SwiftUI

struct NewsCardsScrollView: View {
@State private var newsData: [NewsData]

init(newsData: [NewsData]) {
_newsData = State(initialValue: newsData)
}

var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(newsData.reversed(), id: \.self) { new in
NewsCardView(news: new)
}
}
.padding()
}
.frame(maxWidth: .infinity)
}
}
17 changes: 17 additions & 0 deletions iOS/Views/Sources/SourceAppViews/SourceAppTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,23 @@ class AppTableViewCell: UITableViewCell {

let appVersion = (app.versions?.first?.version ?? app.version) ?? "1.0"
var displayText = appVersion

let appDate = (app.versions?.first?.date ?? app.versionDate) ?? ""
if appDate != "" {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"

if let date = dateFormatter.date(from: appDate) {
let formattedDate = date.formatted(date: .numeric, time: .omitted)
displayText += "" + formattedDate
} else {
dateFormatter.dateFormat = "yyyy-MM-dd"
if let date = dateFormatter.date(from: appDate) {
let formattedDate = date.formatted(date: .numeric, time: .omitted)
displayText += "" + formattedDate
}
}
}
var descText = ""

if Preferences.appDescriptionAppearence == 0 {
Expand Down
Loading

0 comments on commit 95acb5d

Please sign in to comment.