diff options
| author | Bobby <[email protected]> | 2024-10-30 19:16:59 -0400 |
|---|---|---|
| committer | Bobby <[email protected]> | 2024-10-30 19:16:59 -0400 |
| commit | 3ec482112c06ad0c54d4f7b9f957219d044e330c (patch) | |
| tree | ed328b22bce0fa9eb03f8fbc1c81aa98f330ef8c | |
| parent | b1e1bea7e2005fc199d668a9a064b1c194cf2563 (diff) | |
| download | aki-3ec482112c06ad0c54d4f7b9f957219d044e330c.tar.xz aki-3ec482112c06ad0c54d4f7b9f957219d044e330c.zip | |
| -rw-r--r-- | aki.xcodeproj/project.pbxproj | 14 | ||||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/1024-mac.png | bin | 0 -> 70212 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/128-mac.png | bin | 0 -> 4430 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/16-mac.png | bin | 0 -> 288 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/256-mac 1.png | bin | 0 -> 11888 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/256-mac.png | bin | 0 -> 11888 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/32-mac 1.png | bin | 0 -> 796 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/32-mac.png | bin | 0 -> 796 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/512-mac 1.png | bin | 0 -> 32112 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/512-mac.png | bin | 0 -> 32112 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/64-mac.png | bin | 0 -> 1728 bytes | |||
| -rw-r--r-- | aki/Assets.xcassets/AppIcon.appiconset/Contents.json | 10 | ||||
| -rw-r--r-- | aki/ContentView.swift | 24 | ||||
| -rw-r--r-- | aki/Views/MainView.swift | 486 | ||||
| -rw-r--r-- | aki/akiApp.swift | 4 |
15 files changed, 511 insertions, 27 deletions
diff --git a/aki.xcodeproj/project.pbxproj b/aki.xcodeproj/project.pbxproj index 4c17ca1..54ef414 100644 --- a/aki.xcodeproj/project.pbxproj +++ b/aki.xcodeproj/project.pbxproj @@ -249,18 +249,23 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = aki/aki.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"aki/Preview Content\""; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = Aki; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; + MARKETING_VERSION = 0.1; PRODUCT_BUNDLE_IDENTIFIER = foo.shi.aki; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -274,18 +279,23 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = aki/aki.entitlements; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"aki/Preview Content\""; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = Aki; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment"; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); - MARKETING_VERSION = 1.0; + MACOSX_DEPLOYMENT_TARGET = 14.6; + MARKETING_VERSION = 0.1; PRODUCT_BUNDLE_IDENTIFIER = foo.shi.aki; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/aki/Assets.xcassets/AppIcon.appiconset/1024-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/1024-mac.png Binary files differnew file mode 100644 index 0000000..a340c14 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/1024-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/128-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/128-mac.png Binary files differnew file mode 100644 index 0000000..c68ced9 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/128-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/16-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/16-mac.png Binary files differnew file mode 100644 index 0000000..00f87f2 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/16-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/256-mac 1.png b/aki/Assets.xcassets/AppIcon.appiconset/256-mac 1.png Binary files differnew file mode 100644 index 0000000..339800e --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/256-mac 1.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/256-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/256-mac.png Binary files differnew file mode 100644 index 0000000..339800e --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/256-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/32-mac 1.png b/aki/Assets.xcassets/AppIcon.appiconset/32-mac 1.png Binary files differnew file mode 100644 index 0000000..9aeab40 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/32-mac 1.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/32-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/32-mac.png Binary files differnew file mode 100644 index 0000000..9aeab40 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/32-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/512-mac 1.png b/aki/Assets.xcassets/AppIcon.appiconset/512-mac 1.png Binary files differnew file mode 100644 index 0000000..a784339 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/512-mac 1.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/512-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/512-mac.png Binary files differnew file mode 100644 index 0000000..a784339 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/512-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/64-mac.png b/aki/Assets.xcassets/AppIcon.appiconset/64-mac.png Binary files differnew file mode 100644 index 0000000..be069f7 --- /dev/null +++ b/aki/Assets.xcassets/AppIcon.appiconset/64-mac.png diff --git a/aki/Assets.xcassets/AppIcon.appiconset/Contents.json b/aki/Assets.xcassets/AppIcon.appiconset/Contents.json index 3f00db4..2c976ad 100644 --- a/aki/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/aki/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,51 +1,61 @@ { "images" : [ { + "filename" : "16-mac.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { + "filename" : "32-mac.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { + "filename" : "32-mac 1.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { + "filename" : "64-mac.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { + "filename" : "128-mac.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { + "filename" : "256-mac.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { + "filename" : "256-mac 1.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { + "filename" : "512-mac.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { + "filename" : "512-mac 1.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { + "filename" : "1024-mac.png", "idiom" : "mac", "scale" : "2x", "size" : "512x512" diff --git a/aki/ContentView.swift b/aki/ContentView.swift deleted file mode 100644 index a09e7e8..0000000 --- a/aki/ContentView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentView.swift -// aki -// -// Created by Conrad Reeves on 10/30/24. -// - -import SwiftUI - -struct ContentView: View { - var body: some View { - VStack { - Image(systemName: "globe") - .imageScale(.large) - .foregroundStyle(.tint) - Text("Hello, world!") - } - .padding() - } -} - -#Preview { - ContentView() -} diff --git a/aki/Views/MainView.swift b/aki/Views/MainView.swift new file mode 100644 index 0000000..c634af8 --- /dev/null +++ b/aki/Views/MainView.swift @@ -0,0 +1,486 @@ +// +// MainView.swift +// aki +// +// Created by Conrad Reeves on 10/30/24. +// + +import SwiftUI + +// MARK: - Main Navigation Enums +enum NavigationItem: Hashable, Identifiable { + case home + case trending + case genres + case schedule + case search + case animeDetails + case animeWatch + case settings + case libraryItem(LibraryItem) + case playlist(String) + + var id: String { + switch self { + case .libraryItem(let item): + return "library-\(item.rawValue)" + case .playlist(let name): + return "playlist-\(name)" + case .home: + return "home" + case .trending: + return "trending" + case .genres: + return "genres" + case .schedule: + return "schedule" + case .search: + return "search" + case .animeDetails: + return "anime-details" + case .animeWatch: + return "anime-watch" + case .settings: + return "settings" + } + } + + var icon: String { + switch self { + case .home: + return "house" + case .trending: + return "chart.line.uptrend.xyaxis" + case .genres: + return "list.bullet" + case .schedule: + return "calendar" + case .search: + return "magnifyingglass" + case .animeDetails: + return "info.circle" + case .animeWatch: + return "play.circle" + case .settings: + return "gear" + case .libraryItem(let item): + return item.icon + case .playlist: + return "star.fill" + } + } + + var title: String { + switch self { + case .home: + return "Home" + case .trending: + return "Trending" + case .genres: + return "Genres" + case .schedule: + return "Schedule" + case .search: + return "Search" + case .animeDetails: + return "Anime Details" + case .animeWatch: + return "Watch" + case .settings: + return "Settings" + case .libraryItem(let item): + return item.rawValue + case .playlist(let name): + return name + } + } +} + +enum LibraryItem: String, Identifiable, CaseIterable { + case recentlyWatched = "Recently Watched" + case movies = "Movies" + case tvSeries = "TV Series" + + var id: String { self.rawValue } + + var icon: String { + switch self { + case .recentlyWatched: return "clock" + case .movies: return "film" + case .tvSeries: return "tv" + } + } +} + +// MARK: - Main View +struct MainView: View { + @State private var selectedNavigation: NavigationItem? = .home + @State private var searchText: String = "" + @State private var isLibraryExpanded = true + @State private var isPlaylistsExpanded = true + @State private var navigationPath = NavigationPath() + + var body: some View { + NavigationSplitView { + Sidebar(selectedNavigation: $selectedNavigation, + searchText: $searchText, + isLibraryExpanded: $isLibraryExpanded, + isPlaylistsExpanded: $isPlaylistsExpanded, + navigationPath: $navigationPath) // Add this + } detail: { + NavigationStack(path: $navigationPath) { + ContentView(selectedNavigation: $selectedNavigation, navigationPath: $navigationPath) + } + } + .navigationSplitViewStyle(.balanced) + } +} + +// MARK: - Sidebar +struct Sidebar: View { + @Binding var selectedNavigation: NavigationItem? + @Binding var searchText: String + @Binding var isLibraryExpanded: Bool + @Binding var isPlaylistsExpanded: Bool + @Binding var navigationPath: NavigationPath // Add this + @FocusState private var isSearchFocused: Bool + + var body: some View { + List(selection: $selectedNavigation) { + HStack { + TextField("", text: $searchText, prompt: Text("Search")) + .focused($isSearchFocused) + .onChange(of: isSearchFocused) { _, isFocused in + if isFocused { + selectedNavigation = .search + } + } + .onSubmit { + print("Searched for: \(searchText)") + } + .textFieldStyle(.roundedBorder) + } +// .overlay( +// Image(systemName: "magnifyingglass") +// .foregroundColor(.secondary) +// .padding(.leading, 6), +// alignment: .leading +// ) + .onTapGesture { + selectedNavigation = .search + } + + mainNavigation + + librarySection + + playlistsSection + + Spacer() + } + .safeAreaInset(edge: .bottom) { + Button { + navigationPath.append(NavigationItem.settings) + selectedNavigation = .settings + } label: { + HStack { + Image(systemName: "person.circle.fill") + .font(.title2) + VStack(alignment: .leading) { + Text("John Doe") + Text("View Profile") + .font(.caption) + .foregroundColor(.secondary) + } + Spacer() + } + .padding() + } + .buttonStyle(.plain) + } + } + + private var mainNavigation: some View { + Section { + ForEach([NavigationItem.home, .trending, .genres, .schedule], id: \.self) { item in + Label(item.title, systemImage: item.icon) + .tag(item) + } + } + } + + private var librarySection: some View { + Section(isExpanded: $isLibraryExpanded) { + ForEach(LibraryItem.allCases) { item in + NavigationLink(value: NavigationItem.libraryItem(item)) { + Label(item.rawValue, systemImage: item.icon) + } + } + } header: { + Text("Library") + } + } + + private var playlistsSection: some View { + Section(isExpanded: $isPlaylistsExpanded) { + NavigationLink(value: NavigationItem.playlist("My Top 25 Rated")) { + Label("My Top 25 Rated", systemImage: "star.fill") + } + } header: { + Text("Playlists") + } + } +} + +// MARK: - Content View +struct ContentView: View { + @Binding var selectedNavigation: NavigationItem? + @Binding var navigationPath: NavigationPath + + var body: some View { + VStack { + if let navigation = selectedNavigation { + switch navigation { + case .home: + HomeView(navigationPath: $navigationPath) + case .trending: + TrendingView() + case .genres: + GenresView() + case .schedule: + ScheduleView() + case .search: + SearchView() + case .libraryItem(let item): + LibraryView(item: item) + case .playlist(let name): + PlaylistView(name: name) + case .settings: + SettingsView() + .navigationTitle("Settings") + case .animeDetails: + AnimeDetailsView(navigationPath: $navigationPath) + case .animeWatch: + AnimeWatchView() + } + } else { + HomeView(navigationPath: $navigationPath) + } + } + .navigationDestination(for: NavigationItem.self) { item in + switch item { + case .animeDetails: + AnimeDetailsView(navigationPath: $navigationPath) + case .animeWatch: + AnimeWatchView() + case .libraryItem(let libraryItem): + LibraryView(item: libraryItem) + case .playlist(let name): + PlaylistView(name: name) + case .settings: + SettingsView() + default: + EmptyView() + } + } + .toolbar { + if selectedNavigation == .search { + ToolbarItemGroup { + Menu { + Button("Action", action: {}) + Button("Comedy", action: {}) + Button("Drama", action: {}) + } label: { + Label("Genre", systemImage: "tag") + } + + Menu { + Button("TV", action: {}) + Button("Movie", action: {}) + Button("OVA", action: {}) + } label: { + Label("Type", systemImage: "tv") + } + + Picker("Rating", selection: .constant("All")) { + Text("All").tag("All") + Text("PG-13").tag("PG-13") + Text("R").tag("R") + } + + Menu { + Button("Currently Airing", action: {}) + Button("Finished Airing", action: {}) + Button("Not Yet Aired", action: {}) + } label: { + Label("Status", systemImage: "clock") + } + } + } + } + } +} + +// MARK: - Placeholder Views +struct HomeView: View { + @Binding var navigationPath: NavigationPath + + var body: some View { + VStack { + Text("Home View") + Button("Open Anime Details") { + navigationPath.append(NavigationItem.animeDetails) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct TrendingView: View { + var body: some View { + Text("Trending View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct GenresView: View { + var body: some View { + Text("Genres View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct ScheduleView: View { + var body: some View { + Text("Schedule View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct SearchView: View { + @State private var localSearchText: String = "" + @State private var selectedGenres: Set<String> = [] + @State private var selectedTypes: Set<String> = [] + + var body: some View { + VStack(spacing: 20) { + // Search field + HStack { + Image(systemName: "magnifyingglass") + .foregroundColor(.secondary) + TextField("Search anime...", text: $localSearchText) + .textFieldStyle(.plain) + .font(.title2) + + if !localSearchText.isEmpty { + Button(action: { localSearchText = "" }) { + Image(systemName: "xmark.circle.fill") + .foregroundColor(.secondary) + } + .buttonStyle(.plain) + } + } + .padding() + .background(RoundedRectangle(cornerRadius: 8) + .fill(Color(.textBackgroundColor))) + + // Content + VStack(alignment: .leading, spacing: 16) { + if localSearchText.isEmpty { + Text("Recent Searches") + .font(.headline) + + ForEach(["One Piece", "Naruto", "Death Note"], id: \.self) { search in + HStack { + Image(systemName: "clock") + .foregroundColor(.secondary) + Text(search) + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + localSearchText = search + } + } + } else { + searchResults + } + } + } + .padding() + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + + private var searchResults: some View { + ScrollView { + LazyVGrid(columns: [ + GridItem(.adaptive(minimum: 200), spacing: 16) + ], spacing: 16) { + ForEach(0..<20, id: \.self) { _ in + Rectangle() + .fill(Color.gray.opacity(0.2)) + .aspectRatio(16/9, contentMode: .fit) + .overlay(Text("Anime Title")) + } + } + .padding() + } + } +} + +struct AnimeDetailsView: View { + @Binding var navigationPath: NavigationPath + + var body: some View { + VStack { + Text("Anime Details") + + Button("Watch Now") { + navigationPath.append(NavigationItem.animeWatch) + } + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .navigationTitle("Anime Title") + } +} + +struct AnimeWatchView: View { + var body: some View { + Text("Anime Watch View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + .navigationTitle("Now Playing") + } +} + +struct SettingsView: View { + var body: some View { + Text("Settings") + .frame(maxWidth: .infinity, maxHeight: .infinity) + .navigationTitle("Settings") + } +} + +struct LibraryView: View { + let item: LibraryItem + + var body: some View { + Text("\(item.rawValue) View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + .navigationTitle(item.rawValue) + } +} + +struct PlaylistView: View { + let name: String + + var body: some View { + Text("\(name) View") + .frame(maxWidth: .infinity, maxHeight: .infinity) + .navigationTitle(name) + } +} + +// MARK: - Preview +#Preview { + MainView() +} diff --git a/aki/akiApp.swift b/aki/akiApp.swift index 4197e1d..68be104 100644 --- a/aki/akiApp.swift +++ b/aki/akiApp.swift @@ -11,7 +11,9 @@ import SwiftUI struct akiApp: App { var body: some Scene { WindowGroup { - ContentView() + MainView() + .frame(minWidth: 1024, maxWidth: .infinity, minHeight: 768, maxHeight: .infinity) } + .windowResizability(.contentSize) } } |
