Skip to content

Commit

Permalink
(finally!!) add favourites to homeview
Browse files Browse the repository at this point in the history
  • Loading branch information
vapidinfinity committed May 19, 2024
1 parent d4a8374 commit b167dd4
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 17 deletions.
4 changes: 4 additions & 0 deletions Mythic.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
6ADF5ABB2B98B9710041D04E /* UninstallGameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ADF5ABA2B98B9710041D04E /* UninstallGameView.swift */; };
6ADFD97B2B975B3300557086 /* GameCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6ADFD97A2B975B3300557086 /* GameCard.swift */; };
6AE4A9A32B44682E0060D483 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE4A9A22B44682E0060D483 /* Lock.swift */; };
6AE842122BF96D0400016A58 /* CompactGameCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE842112BF96D0400016A58 /* CompactGameCard.swift */; };
6AEF7BC62BA6D873002FFE26 /* Downloads.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AEF7BC52BA6D873002FFE26 /* Downloads.swift */; };
6AF0EB1F2AAD4E0A0044C09C /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF0EB1E2AAD4E0A0044C09C /* Onboarding.swift */; };
6AF0EB212AAD4F1E0044C09C /* NotImplemented.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AF0EB202AAD4F1E0044C09C /* NotImplemented.swift */; };
Expand Down Expand Up @@ -151,6 +152,7 @@
6ADF5ABA2B98B9710041D04E /* UninstallGameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UninstallGameView.swift; sourceTree = "<group>"; };
6ADFD97A2B975B3300557086 /* GameCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameCard.swift; sourceTree = "<group>"; };
6AE4A9A22B44682E0060D483 /* Lock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = "<group>"; };
6AE842112BF96D0400016A58 /* CompactGameCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompactGameCard.swift; sourceTree = "<group>"; };
6AEF7BC52BA6D873002FFE26 /* Downloads.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Downloads.swift; sourceTree = "<group>"; };
6AF0EB1E2AAD4E0A0044C09C /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = "<group>"; };
6AF0EB202AAD4F1E0044C09C /* NotImplemented.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotImplemented.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -520,6 +522,7 @@
6ADF5ABA2B98B9710041D04E /* UninstallGameView.swift */,
6A02BDE92B99FC2900B70656 /* InstallGameView.swift */,
6A6D03ED2B9EFBD30064CEBB /* GameSettingsView.swift */,
6AE842112BF96D0400016A58 /* CompactGameCard.swift */,
);
path = GameListEvo;
sourceTree = "<group>";
Expand Down Expand Up @@ -694,6 +697,7 @@
6AD506562AAFF671008A28C1 /* Home.swift in Sources */,
6A0BB7AB2B501A2200C8A693 /* LocalImport.swift in Sources */,
6A1C6F462AEFD9B100F89AE7 /* WineInterfaceExt.swift in Sources */,
6AE842122BF96D0400016A58 /* CompactGameCard.swift in Sources */,
6AA6CCE72AD571C500F664A5 /* LegendaryInterfaceExt.swift in Sources */,
6AD5065C2AAFF6F0008A28C1 /* Support.swift in Sources */,
6A1322382B1C98AE0049BB64 /* InstallStatus.swift in Sources */,
Expand Down
12 changes: 11 additions & 1 deletion Mythic/Extensions/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ let mainLock: NSRecursiveLock = .init()

let discordRPC: SwordRPC = .init(appId: "1191343317749870712") // Mythic's discord application ID

let unifiedGames = (LocalGames.library ?? []) + ((try? Legendary.getInstallable()) ?? [])

struct UnknownError: LocalizedError {
var errorDescription: String? = "An unknown error occurred."
}
Expand Down Expand Up @@ -70,16 +72,18 @@ class Game: ObservableObject, Hashable, Codable, Identifiable, Equatable {
hasher.combine(id)
hasher.combine(platform)
hasher.combine(imageURL)
hasher.combine(wideImageURL)
hasher.combine(path)
}

// MARK: Initializer
init(type: GameType, title: String, id: String? = nil, platform: GamePlatform? = nil, imageURL: URL? = nil, path: String? = nil) {
init(type: GameType, title: String, id: String? = nil, platform: GamePlatform? = nil, imageURL: URL? = nil, wideImageURL: URL? = nil, path: String? = nil) {
self.type = type
self.title = title
self.id = id ?? UUID().uuidString
self.platform = platform
self.imageURL = imageURL
self.wideImageURL = wideImageURL
self.path = path
}

Expand All @@ -99,6 +103,12 @@ class Game: ObservableObject, Hashable, Codable, Identifiable, Equatable {
get { _imageURL ?? (self.type == .epic ? .init(string: Legendary.getImage(of: self, type: .tall)) : nil) }
set { _imageURL = newValue }
}

private var _wideImageURL: URL?
var wideImageURL: URL? {
get { _imageURL ?? (self.type == .epic ? .init(string: Legendary.getImage(of: self, type: .normal)) : nil) }
set { _imageURL = newValue }
}

private var _path: String?
var path: String? {
Expand Down
4 changes: 4 additions & 0 deletions Mythic/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -12814,6 +12814,9 @@
}
}
}
},
"Enter New Thumbnail URL here..." : {

},
"Enter the 'authorisationCode' from the JSON response in the field below." : {
"localizations" : {
Expand Down Expand Up @@ -15673,6 +15676,7 @@
}
},
"Favourites (Not implemented yet)" : {
"extractionState" : "stale",
"localizations" : {
"af" : {
"stringUnit" : {
Expand Down
130 changes: 130 additions & 0 deletions Mythic/Views/GameListEvo/CompactGameCard.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//
// CompactGameCard.swift
// Mythic
//
// Created by Esiayo Alegbe on 19/5/2024.
//

import SwiftUI
import CachedAsyncImage

struct CompactGameCard: View {
@Binding var game: Game

@EnvironmentObject var networkMonitor: NetworkMonitor
@ObservedObject private var operation: GameOperation = .shared
@AppStorage("minimiseOnGameLaunch") private var minimizeOnGameLaunch: Bool = false

@State private var isLaunchErrorAlertPresented: Bool = false
@State private var launchError: Error?

var body: some View {
RoundedRectangle(cornerRadius: 20)
.fill(.background)
.aspectRatio(1, contentMode: .fit)
.overlay { // MARK: Image
CachedAsyncImage(url: game.wideImageURL ?? game.imageURL) { phase in
switch phase {
case .empty:
if case .local = game.type, game.imageURL == nil {
let image = Image(nsImage: workspace.icon(forFile: game.path ?? .init()))

image
.resizable()
.aspectRatio(1, contentMode: .fill)
.blur(radius: 20.0)
} else {
RoundedRectangle(cornerRadius: 20)
.fill(.windowBackground)
.shimmering(
animation: .easeInOut(duration: 1)
.repeatForever(autoreverses: false),
bandSize: 1
)
}
case .success(let image):
image
.resizable()
.aspectRatio(1, contentMode: .fill)
.clipShape(.rect(cornerRadius: 20))
.blur(radius: 20.0)
case .failure:
// fallthrough
RoundedRectangle(cornerRadius: 20)
.fill(.windowBackground)
@unknown default:
RoundedRectangle(cornerRadius: 20)
.fill(.windowBackground)
}
}
}
.overlay(alignment: .bottom) {
VStack {
// MARK: Game Title Stack
HStack {
Text(game.title)
.font(.bold(.title3)())

Spacer()

// ! Changes made here must also be reflected in GameCard's play button
if operation.launching == game {
ProgressView()
.controlSize(.small)
.padding(5)
.clipShape(.circle)

} else {
Button {
Task(priority: .userInitiated) {
do {
switch game.type {
case .epic:
try await Legendary.launch(
game: game,
online: networkMonitor.isEpicAccessible
)
case .local:
try await LocalGames.launch(game: game)
}

if minimizeOnGameLaunch { NSApp.windows.first?.miniaturize(nil) }
} catch {
launchError = error
isLaunchErrorAlertPresented = true
}
}
} label: {
Image(systemName: "play")
.padding(5)
}
.clipShape(.circle)
.help(game.path != nil ? "Play \"\(game.title)\"" : "Unable to locate \(game.title) at its specified path (\(game.path ?? "Unknown"))")
.disabled(game.path != nil ? !files.fileExists(atPath: game.path!) : false)
.disabled(operation.runningGames.contains(game))
.alert(isPresented: $isLaunchErrorAlertPresented) {
Alert(
title: .init("Error launching \"\(game.title)\"."),
message: .init(launchError?.localizedDescription ?? "Unknown Error.")
)
}
}
}
.padding(.horizontal)
}
.padding(.bottom)
.scaledToFit()
}
.overlay(alignment: .topLeading) {
if game.isFavourited {
Image(systemName: "star.fill")
.padding()
}
}
}
}

#Preview {
CompactGameCard(game: .constant(.init(type: .epic, title: "firtbite;", wideImageURL: .init(string: "https://i.imgur.com/CZt2F4s.png"))))
.padding()
}
3 changes: 2 additions & 1 deletion Mythic/Views/GameListEvo/GameCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ struct GameCard: View {
Text(game.title)
.font(.bold(.title3)())
// .foregroundStyle(.white)
.padding(.leading)

SubscriptedTextView(game.type.rawValue)

Expand All @@ -101,6 +100,7 @@ struct GameCard: View {

Spacer()
}
.padding(.leading)

// MARK: Button Stack
HStack {
Expand Down Expand Up @@ -156,6 +156,7 @@ struct GameCard: View {
.help("Game verification is required for \"\(game.title)\".")
} else {
// MARK: Play Button
// ! Changes made here must also be reflected in CompactGameCard's play button
if operation.launching == game {
ProgressView()
.controlSize(.small)
Expand Down
2 changes: 0 additions & 2 deletions Mythic/Views/GameListEvo/GameListEvo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ struct GameListEvo: View {

@State private var isGameImportViewPresented: Bool = false

private let unifiedGames = (LocalGames.library ?? []) + ((try? Legendary.getInstallable()) ?? [])

private var games: [Game] {
return unifiedGames
.filter {
Expand Down
26 changes: 13 additions & 13 deletions Mythic/Views/Navigation/Home.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ struct HomeView: View {
@State private var isAlertPresented: Bool = false
@State private var activeAlert: ActiveAlert = .launchError

@State private var animateStar: Bool = false
let animateStarTimer = Timer.publish(every: 2, on: .main, in: .common).autoconnect() // why on god's green earth is it so lengthy on swift to repeat something every 2 seconds
@Environment(\.colorScheme) var colorScheme

// MARK: - Body
Expand All @@ -67,18 +65,20 @@ struct HomeView: View {
VStack {
// MARK: View 1 (Top)
VStack {
Image(systemName: animateStar ? "star.fill" : "calendar.badge.clock")
.resizable()
.symbolRenderingMode(.palette)
.contentTransition(.symbolEffect(.replace.upUp.byLayer))
.foregroundStyle(animateStar ? .yellow : .yellow, (colorScheme == .light ? .black : .white))
.aspectRatio(contentMode: .fit)
.frame(width: 35, height: 35)
.onReceive(animateStarTimer) { _ in
animateStar.toggle()
if !unifiedGames.filter({ $0.isFavourited == true }).isEmpty {
ScrollView(.horizontal) {
LazyHStack {
ForEach(unifiedGames.filter({ $0.isFavourited == true }), id: \.self) { game in
CompactGameCard(game: .constant(game))
}
}
}

Text("Favourites (Not implemented yet)")
} else {
HStack {
Image(systemName: "star.fill")
Text("No games are favourited.")
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.background)
Expand Down

0 comments on commit b167dd4

Please sign in to comment.