Files
SideStore/AltStore/Views/Browse/BrowseView.swift
2023-02-06 00:44:03 -05:00

166 lines
5.7 KiB
Swift

//
// BrowseView.swift
// SideStoreUI
//
// Created by Fabian Thies on 18.11.22.
// Copyright © 2022 Fabian Thies. All rights reserved.
//
import SwiftUI
import SFSafeSymbols
import AltStoreCore
struct BrowseView: View {
@SwiftUI.FetchRequest(sortDescriptors: [
NSSortDescriptor(keyPath: \StoreApp.sourceIdentifier, ascending: true),
NSSortDescriptor(keyPath: \StoreApp.sortIndex, ascending: true),
NSSortDescriptor(keyPath: \StoreApp.name, ascending: true),
NSSortDescriptor(keyPath: \StoreApp.bundleIdentifier, ascending: true)
], predicate: NSPredicate(format: "%K != %@", #keyPath(StoreApp.bundleIdentifier), StoreApp.altstoreAppID))
var apps: FetchedResults<StoreApp>
var filteredApps: [StoreApp] {
apps.items(matching: self.searchText)
}
@State
var selectedStoreApp: StoreApp?
@State var searchText = ""
@State var isShowingSourcesView = false
var body: some View {
ScrollView {
VStack(alignment: .leading) {
if searchText.isEmpty {
VStack(alignment: .leading, spacing: 32) {
promotedCategoriesView
Text(L10n.BrowseView.Section.AllApps.title)
.font(.title2)
.bold()
}
}
if searchText.isEmpty, filteredApps.count == 0 {
HintView {
Text("You don't have any apps yet.")
.bold()
Text("Apps are provided by \"sources\". The specification for them is an open standard, so everyone can create their own source. To get you started, we have compiled a list of \"Trusted Sources\" which you can check out by tapping the button below.")
.font(.callout)
.foregroundColor(.secondary)
SwiftUI.Button {
self.isShowingSourcesView = true
} label: {
Label("Add Source", systemSymbol: .plus)
}
.buttonStyle(FilledButtonStyle())
.padding(.top, 8)
}
} else {
LazyVStack(spacing: 32) {
ForEach(filteredApps, id: \.bundleIdentifier) { app in
NavigationLink {
AppDetailView(storeApp: app)
} label: {
BrowseAppPreviewView(storeApp: app)
}
.buttonStyle(PlainButtonStyle())
}
}
}
}
.padding()
.searchable(text: self.$searchText, placeholder: L10n.BrowseView.search)
}
.background(Color(UIColor.systemGroupedBackground).ignoresSafeArea())
.navigationTitle(L10n.BrowseView.title)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
SwiftUI.Button {
self.isShowingSourcesView = true
} label: {
Text(L10n.BrowseView.Actions.sources)
}
.sheet(isPresented: self.$isShowingSourcesView) {
NavigationView {
SourcesView()
}
}
}
ToolbarItem(placement: .navigationBarTrailing) {
SwiftUI.Button {
} label: {
Image(systemSymbol: .lineHorizontal3DecreaseCircle)
.imageScale(.large)
}
}
}
}
var promotedCategoriesView: some View {
VStack {
HStack {
Text(L10n.BrowseView.Section.PromotedCategories.title)
.font(.title2)
.bold()
Spacer()
SwiftUI.Button(action: {}, label: {
Text(L10n.BrowseView.Section.PromotedCategories.showAll)
})
.font(.callout)
}
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible())]) {
PromotedCategoryView()
.shadow(color: .black.opacity(0.1), radius: 8, y: 5)
PromotedCategoryView()
.shadow(color: .black.opacity(0.1), radius: 8, y: 5)
}
}
}
}
struct BrowseView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
BrowseView()
}
}
}
struct PromotedCategoryView: View {
var body: some View {
ZStack {
GeometryReader { proxy in
RadialGradient(colors: [
Color(UIColor(hexString: "477E84")!),
Color(UIColor.secondarySystemBackground),
Color(UIColor.secondarySystemBackground),
Color(UIColor(hexString: "C38FF5")!)
], center: .bottomLeading, startRadius: 0, endRadius: proxy.size.width)
}
HStack {
Image(systemSymbol: .dpadRightFill)
Text(L10n.BrowseView.Categories.gamesAndEmulators)
.multilineTextAlignment(.leading)
}
.foregroundColor(.accentColor)
.padding()
}
.aspectRatio(21/9, contentMode: .fill)
.frame(maxWidth: .infinity)
.clipShape(RoundedRectangle(cornerRadius: 12))
}
}