: View {
14 |
15 | @ObservedObject var presenter: GetListPresenter<
16 | AnimeRankingRequest,
17 | AnimeDomainModel,
18 | Interactor<
19 | AnimeRankingRequest,
20 | [AnimeDomainModel],
21 | GetAnimeRankingRepository<
22 | GetAnimeRankingLocaleDataSource,
23 | GetAnimeRankingRemoteDataSource,
24 | AnimesTransformer>>>
25 | @State var scrollOffset: CGFloat
26 | let rankingType: RankingTypeRequest
27 | let navigationTitle: String
28 | let detailDestination: ((_ anime: AnimeDomainModel) -> DetailDestination)
29 |
30 | public init(
31 | presenter: GetListPresenter<
32 | AnimeRankingRequest,
33 | AnimeDomainModel,
34 | Interactor<
35 | AnimeRankingRequest,
36 | [AnimeDomainModel],
37 | GetAnimeRankingRepository<
38 | GetAnimeRankingLocaleDataSource,
39 | GetAnimeRankingRemoteDataSource,
40 | AnimesTransformer>>>,
41 | scrollOffset: CGFloat = CGFloat.zero,
42 | rankingType: RankingTypeRequest,
43 | navigationTitle: String,
44 | detailDestination: @escaping (_ anime: AnimeDomainModel) -> DetailDestination
45 | ) {
46 | self.presenter = presenter
47 | self.scrollOffset = scrollOffset
48 | self.rankingType = rankingType
49 | self.navigationTitle = navigationTitle
50 | self.detailDestination = detailDestination
51 | }
52 |
53 | public var body: some View {
54 | ZStack {
55 | if presenter.isLoading {
56 | ProgressIndicator()
57 | .background(YumeColor.background)
58 | } else if presenter.isError {
59 | CustomEmptyView(label: presenter.errorMessage)
60 | } else {
61 | content
62 | }
63 | }
64 | .toolbar(.hidden)
65 | .onAppear {
66 | if presenter.list.isEmpty {
67 | presenter.getList(request: AnimeRankingRequest(type: rankingType))
68 | }
69 | }
70 | }
71 | }
72 |
73 | extension SeeAllAnimeView {
74 | var content: some View {
75 | ZStack(alignment: .top) {
76 | ObservableScrollView(scrollOffset: $scrollOffset, showsIndicators: false) { _ in
77 | LazyVStack(spacing: Space.small) {
78 | ForEach(presenter.list.prefix(20)) { anime in
79 | NavigationLink(destination: detailDestination(anime)) {
80 | AnimeCardItem(anime: anime)
81 | }.buttonStyle(.plain)
82 | }
83 | }
84 | .padding(
85 | EdgeInsets(
86 | top: 56,
87 | leading: Space.medium,
88 | bottom: Space.medium,
89 | trailing: Space.medium)
90 | )
91 | }.background(YumeColor.background)
92 |
93 | BackAppBar(scrollOffset: scrollOffset, label: navigationTitle.localized(bundle: .common), alwaysShowLabel: true)
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Modules/SeeAllAnime/Tests/SeeAllAnimeTests/SeeAllAnimeTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import SeeAllAnime
3 |
4 | final class SeeAllAnimeTests: XCTestCase {
5 | func testExample() throws {
6 | // This is an example of a functional test case.
7 | // Use XCTAssert and related functions to verify your tests produce the correct
8 | // results.
9 | XCTAssertEqual(SeeAllAnime().text, "Hello, World!")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Yume
4 | Discover anime anytime, anywhere
5 |
6 | Get to know various information about anime such as season, score, rank, adaptation source, synopsis, and more. Find any anime by title using either English or Rōmaji. Create your own favorite list for easy access.
7 |
8 | Yume is available in English and Bahasa Indonesia.
9 | > Support for Bahasa Indonesia is limited to some features and can only be used by changing device's system language
10 |
11 | ## Features
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ### Home
21 | - Top airing anime
22 | - Top upcoming anime
23 | - Most popular anime
24 | - Top rated anime
25 |
26 | ### Search
27 | - Top favorite anime
28 | - Search anime by title using either English or Rōmaji
29 |
30 | ### Favorite
31 | - List of anime added to favorite
32 |
33 | ### Profile
34 |
35 | ## Dependency Diagram
36 | 
37 |
38 | ## Getting Started
39 | ### Prerequisites
40 | #### OS & Software
41 | > Requirements might be lower, the app is developed using the system listed below
42 | * macOS Ventura 13.1
43 | * Xcode 14.2
44 | * iOS 16.2
45 |
46 | #### App
47 | * Client ID (API token) from [MyAnimeList](https://myanimelist.net/apiconfig)
48 |
49 | ### Installation
50 | 1. Download the repository
51 | 2. Open the project by using Xcode
52 | 3. Build the project and a `Keys.plist` file should be created automatically at `Yume/Supporting Files/`
53 | > If it isn't created automatically, copy `Keys-Example.plist` at `Yume/Supporting Files/` and paste it as `Keys.plist` at `Yume/Supporting Files/`
54 | 4. Replace the value of key `API_KEY` with your Client ID (API token) at Keys.plist
55 |
56 | ## License
57 | This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/bryanless/Yume-Swift/blob/main/LICENSE) file for details
58 |
59 | ## Acknowledgments
60 | * [MyAnimeList API](https://myanimelist.net/apiconfig/references/api/v2) by [MyAnimeList](https://myanimelist.net)
61 |
--------------------------------------------------------------------------------
/Yume.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Yume.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Yume.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "alamofire",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/Alamofire/Alamofire",
7 | "state" : {
8 | "revision" : "78424be314842833c04bc3bef5b72e85fff99204",
9 | "version" : "5.6.4"
10 | }
11 | },
12 | {
13 | "identity" : "realm-cocoa",
14 | "kind" : "remoteSourceControl",
15 | "location" : "https://github.com/realm/realm-cocoa",
16 | "state" : {
17 | "revision" : "b1072f3ef733108dfcc62c2001781e5d65605fbf",
18 | "version" : "10.34.1"
19 | }
20 | },
21 | {
22 | "identity" : "realm-core",
23 | "kind" : "remoteSourceControl",
24 | "location" : "https://github.com/realm/realm-core.git",
25 | "state" : {
26 | "revision" : "b77443ca7fa25407869ca537bf3ae912b1427bff",
27 | "version" : "12.13.0"
28 | }
29 | },
30 | {
31 | "identity" : "sdwebimage",
32 | "kind" : "remoteSourceControl",
33 | "location" : "https://github.com/SDWebImage/SDWebImage.git",
34 | "state" : {
35 | "revision" : "6c6b951845a520fa7e8356e28adb5339c0f008d3",
36 | "version" : "5.15.0"
37 | }
38 | },
39 | {
40 | "identity" : "sdwebimageswiftui",
41 | "kind" : "remoteSourceControl",
42 | "location" : "https://github.com/SDWebImage/SDWebImageSwiftUI",
43 | "state" : {
44 | "revision" : "61fefe9c284fd41ddef77d02749e88f00c305196",
45 | "version" : "2.2.2"
46 | }
47 | },
48 | {
49 | "identity" : "yume-core-module",
50 | "kind" : "remoteSourceControl",
51 | "location" : "https://github.com/bryanless/Yume-Core-Module",
52 | "state" : {
53 | "revision" : "2f56655a87143cc20add17c293f7503c0a3d6728",
54 | "version" : "1.3.6"
55 | }
56 | }
57 | ],
58 | "version" : 2
59 | }
60 |
--------------------------------------------------------------------------------
/Yume.xcodeproj/xcshareddata/xcschemes/Yume - ID.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
44 |
46 |
52 |
53 |
54 |
55 |
61 |
63 |
69 |
70 |
71 |
72 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Yume.xcodeproj/xcshareddata/xcschemes/Yume.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
34 |
40 |
41 |
42 |
45 |
51 |
52 |
53 |
54 |
55 |
65 |
67 |
73 |
74 |
75 |
76 |
82 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/Yume/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/.DS_Store
--------------------------------------------------------------------------------
/Yume/App/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 25/12/22.
6 | //
7 |
8 | import Anime
9 | import AnimeDetail
10 | import Core
11 | import Common
12 | import Favorite
13 | import Home
14 | import Profile
15 | import Search
16 | import SeeAllAnime
17 | import SwiftUI
18 |
19 | struct ContentView: View {
20 | @EnvironmentObject var homePresenter: HomePresenter<
21 | Interactor<
22 | AnimeRankingRequest,
23 | [AnimeDomainModel],
24 | GetAnimeRankingRepository<
25 | GetAnimeRankingLocaleDataSource,
26 | GetAnimeRankingRemoteDataSource,
27 | AnimesTransformer>>,
28 | Interactor<
29 | AnimeRankingRequest,
30 | [AnimeDomainModel],
31 | GetAnimeRankingRepository<
32 | GetAnimeRankingLocaleDataSource,
33 | GetAnimeRankingRemoteDataSource,
34 | AnimesTransformer>>,
35 | Interactor<
36 | AnimeRankingRequest,
37 | [AnimeDomainModel],
38 | GetAnimeRankingRepository<
39 | GetAnimeRankingLocaleDataSource,
40 | GetAnimeRankingRemoteDataSource,
41 | AnimesTransformer>>,
42 | Interactor<
43 | AnimeRankingRequest,
44 | [AnimeDomainModel],
45 | GetAnimeRankingRepository<
46 | GetAnimeRankingLocaleDataSource,
47 | GetAnimeRankingRemoteDataSource,
48 | AnimesTransformer>>>
49 | @EnvironmentObject var searchPresenter: SearchPresenter<
50 | Interactor<
51 | AnimeListRequest,
52 | [AnimeDomainModel],
53 | SearchAnimeRepository<
54 | GetAnimeListLocaleDataSource,
55 | GetAnimeListRemoteDataSource,
56 | AnimesTransformer>>,
57 | Interactor<
58 | AnimeRankingRequest,
59 | [AnimeDomainModel],
60 | GetAnimeRankingRepository<
61 | GetAnimeRankingLocaleDataSource,
62 | GetAnimeRankingRemoteDataSource,
63 | AnimesTransformer>>>
64 | @EnvironmentObject var favoritePresenter: GetListPresenter<
65 | Int,
66 | AnimeDomainModel,
67 | Interactor<
68 | Int,
69 | [AnimeDomainModel],
70 | GetFavoriteAnimesRepository<
71 | GetFavoriteAnimeLocaleDataSource,
72 | AnimesTransformer>>>
73 | @State private var selection: Tab = .home
74 |
75 | init() {
76 | NetworkMonitor.shared.startMonitoring()
77 |
78 | UITabBar.appearance().isHidden = true
79 | }
80 |
81 | var body: some View {
82 | VStack(spacing: 0) {
83 | TabView(selection: $selection) {
84 | NavigationStack {
85 | HomeView<
86 | SeeAllAnimeView,
87 | AnimeDetailView>(presenter: homePresenter) { rankingType in
88 | Router().makeSeeAllAnimeView(for: rankingType) { anime in
89 | Router().makeAnimeDetailView(for: anime)
90 | }
91 | } detailDestination: { anime in
92 | Router().makeAnimeDetailView(for: anime)
93 | }
94 | }.tag(Tab.home)
95 | NavigationStack {
96 | SearchView(presenter: searchPresenter) { anime in
97 | Router().makeAnimeDetailView(for: anime)
98 | }
99 | }.tag(Tab.search)
100 | NavigationStack {
101 | FavoriteView(presenter: favoritePresenter) { anime in
102 | Router().makeAnimeDetailView(for: anime)
103 | }
104 | }.tag(Tab.favorite)
105 | NavigationStack {
106 | ProfileView()
107 | }.tag(Tab.profile)
108 | }
109 | TabBar(selection: $selection)
110 | }.ignoresSafeArea(.keyboard)
111 | }
112 |
113 | }
114 |
115 | struct ContentView_Previews: PreviewProvider {
116 | static var previews: some View {
117 | ContentView()
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Yume/App/Router.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Router.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 08/01/23.
6 | //
7 |
8 | import Anime
9 | import AnimeDetail
10 | import Core
11 | import SeeAllAnime
12 | import SwiftUI
13 |
14 | class Router {
15 | func makeAnimeDetailView(for anime: AnimeDomainModel) -> AnimeDetailView {
16 |
17 | let animeUseCase: Interactor<
18 | AnimeRequest,
19 | AnimeDomainModel,
20 | GetAnimeRepository<
21 | GetAnimeLocaleDataSource,
22 | GetAnimeRemoteDataSource,
23 | AnimeTransformer>> = Injection.init().provideAnime()
24 |
25 | let favoriteUseCase: Interactor<
26 | Int,
27 | AnimeDomainModel,
28 | UpdateFavoriteAnimeRepository<
29 | GetFavoriteAnimeLocaleDataSource,
30 | AnimeDataTransformer>> = Injection.init().provideUpdateFavoriteAnime()
31 |
32 | let presenter = AnimePresenter(animeUseCase: animeUseCase, favoriteUseCase: favoriteUseCase)
33 |
34 | return AnimeDetailView(presenter: presenter, anime: anime)
35 |
36 | }
37 |
38 | func makeSeeAllAnimeView(
39 | for rankingType: RankingTypeRequest,
40 | detailDestination: @escaping ((_ anime: AnimeDomainModel) -> AnimeDetailView)) -> SeeAllAnimeView {
41 | var navigationTitle: String
42 |
43 | switch rankingType {
44 | case .airing:
45 | navigationTitle = "now_airing_title"
46 | case .upcoming:
47 | navigationTitle = "upcoming_title"
48 | case .byPopularity:
49 | navigationTitle = "most_popular_title"
50 | default:
51 | // All
52 | navigationTitle = "top_rated_title"
53 | }
54 |
55 | let seeAllAnimeUseCase: Interactor<
56 | AnimeRankingRequest,
57 | [AnimeDomainModel],
58 | GetAnimeRankingRepository<
59 | GetAnimeRankingLocaleDataSource,
60 | GetAnimeRankingRemoteDataSource,
61 | AnimesTransformer>> = Injection.init().provideAnimeRanking()
62 |
63 | let presenter = GetListPresenter(useCase: seeAllAnimeUseCase)
64 |
65 | return SeeAllAnimeView(
66 | presenter: presenter,
67 | rankingType: rankingType,
68 | navigationTitle: navigationTitle,
69 | detailDestination: detailDestination
70 | )
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Yume/App/YumeApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YumeApp.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 25/12/22.
6 | //
7 |
8 | import Anime
9 | import Core
10 | import Home
11 | import Search
12 | import SwiftUI
13 |
14 | let injection = Injection.init()
15 |
16 | // Home
17 | let topAiringAnimeUseCase: Interactor<
18 | AnimeRankingRequest,
19 | [AnimeDomainModel],
20 | GetAnimeRankingRepository<
21 | GetAnimeRankingLocaleDataSource,
22 | GetAnimeRankingRemoteDataSource,
23 | AnimesTransformer>> = injection.provideAnimeRanking()
24 | let topUpcomingAnimeUseCase: Interactor<
25 | AnimeRankingRequest,
26 | [AnimeDomainModel],
27 | GetAnimeRankingRepository<
28 | GetAnimeRankingLocaleDataSource,
29 | GetAnimeRankingRemoteDataSource,
30 | AnimesTransformer>> = injection.provideAnimeRanking()
31 | let popularAnimeUseCase: Interactor<
32 | AnimeRankingRequest,
33 | [AnimeDomainModel],
34 | GetAnimeRankingRepository<
35 | GetAnimeRankingLocaleDataSource,
36 | GetAnimeRankingRemoteDataSource,
37 | AnimesTransformer>> = injection.provideAnimeRanking()
38 | let topAllAnimeUseCase: Interactor<
39 | AnimeRankingRequest,
40 | [AnimeDomainModel],
41 | GetAnimeRankingRepository<
42 | GetAnimeRankingLocaleDataSource,
43 | GetAnimeRankingRemoteDataSource,
44 | AnimesTransformer>> = injection.provideAnimeRanking()
45 |
46 | // Search
47 | let searchAnimeUseCase: Interactor<
48 | AnimeListRequest,
49 | [AnimeDomainModel],
50 | SearchAnimeRepository<
51 | GetAnimeListLocaleDataSource,
52 | GetAnimeListRemoteDataSource,
53 | AnimesTransformer>> = injection.provideSearchAnime()
54 | let topFavoriteAnimeUseCase: Interactor<
55 | AnimeRankingRequest,
56 | [AnimeDomainModel],
57 | GetAnimeRankingRepository<
58 | GetAnimeRankingLocaleDataSource,
59 | GetAnimeRankingRemoteDataSource,
60 | AnimesTransformer>> = injection.provideAnimeRanking()
61 |
62 | // Favorite
63 | let favoriteAnimeUseCase: Interactor<
64 | Int,
65 | [AnimeDomainModel],
66 | GetFavoriteAnimesRepository<
67 | GetFavoriteAnimeLocaleDataSource,
68 | AnimesTransformer>> = injection.provideFavoriteAnime()
69 |
70 | @main
71 | struct YumeApp: App {
72 |
73 | let homePresenter = HomePresenter(
74 | topAiringAnimeUseCase: topAiringAnimeUseCase,
75 | topUpcomingAnimeUseCase: topUpcomingAnimeUseCase,
76 | popularAnimeUseCase: popularAnimeUseCase,
77 | topAllAnimeUseCase: topAllAnimeUseCase)
78 | let searchPresenter = SearchPresenter(
79 | searchAnimeUseCase: searchAnimeUseCase,
80 | topFavoriteAnimeUseCase: topFavoriteAnimeUseCase)
81 | let favoritePresenter = GetListPresenter(useCase: favoriteAnimeUseCase)
82 |
83 | var body: some Scene {
84 | WindowGroup {
85 | ContentView()
86 | .environmentObject(homePresenter)
87 | .environmentObject(searchPresenter)
88 | .environmentObject(favoritePresenter)
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Yume/Core/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Core/.DS_Store
--------------------------------------------------------------------------------
/Yume/Core/DI/Injection.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Injection.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 28/12/22.
6 | //
7 |
8 | import Anime
9 | import Core
10 |
11 | import Foundation
12 | import RealmSwift
13 |
14 | final class Injection: NSObject {
15 |
16 | private let realm = try? Realm()
17 |
18 | func provideAnimeRanking() -> U
19 | where
20 | U.Request == AnimeRankingRequest,
21 | U.Response == [AnimeDomainModel] {
22 | let locale = GetAnimeRankingLocaleDataSource(realm: realm!)
23 |
24 | let remote = GetAnimeRankingRemoteDataSource(
25 | endpoint: Endpoints.Gets.ranking.url,
26 | encoder: API.encoder,
27 | headers: API.headers
28 | )
29 |
30 | let mapper = AnimesTransformer()
31 |
32 | let repository = GetAnimeRankingRepository(
33 | localeDataSource: locale,
34 | remoteDataSource: remote,
35 | mapper: mapper)
36 |
37 | return Interactor(repository: repository) as! U
38 | }
39 |
40 | func provideSearchAnime() -> U
41 | where
42 | U.Request == AnimeListRequest,
43 | U.Response == [AnimeDomainModel] {
44 | let locale = GetAnimeListLocaleDataSource(realm: realm!)
45 |
46 | let remote = GetAnimeListRemoteDataSource(
47 | endpoint: Endpoints.Gets.search.url,
48 | encoder: API.encoder,
49 | headers: API.headers
50 | )
51 |
52 | let mapper = AnimesTransformer()
53 |
54 | let repository = SearchAnimeRepository(
55 | localeDataSource: locale,
56 | remoteDataSource: remote,
57 | mapper: mapper)
58 |
59 | return Interactor(repository: repository) as! U
60 | }
61 |
62 | func provideAnime() -> U
63 | where
64 | U.Request == AnimeRequest,
65 | U.Response == AnimeDomainModel {
66 | let locale = GetAnimeLocaleDataSource(realm: realm!)
67 |
68 | let remote = GetAnimeRemoteDataSource(
69 | endpoint: Endpoints.Gets.detail.url,
70 | encoder: API.encoder,
71 | headers: API.headers
72 | )
73 |
74 | let mapper = AnimeTransformer()
75 |
76 | let repository = GetAnimeRepository(
77 | localeDataSource: locale,
78 | remoteDataSource: remote,
79 | mapper: mapper
80 | )
81 |
82 | return Interactor(repository: repository) as! U
83 | }
84 |
85 | func provideUpdateFavoriteAnime() -> U
86 | where
87 | U.Request == Int,
88 | U.Response == AnimeDomainModel {
89 | let locale = GetFavoriteAnimeLocaleDataSource(realm: realm!)
90 |
91 | let mapper = AnimeDataTransformer()
92 |
93 | let repository = UpdateFavoriteAnimeRepository(
94 | localeDataSource: locale,
95 | mapper: mapper
96 | )
97 |
98 | return Interactor(repository: repository) as! U
99 | }
100 |
101 | func provideFavoriteAnime() -> U
102 | where
103 | U.Request == Int,
104 | U.Response == [AnimeDomainModel] {
105 | let locale = GetFavoriteAnimeLocaleDataSource(realm: realm!)
106 |
107 | let mapper = AnimesTransformer()
108 |
109 | let repository = GetFavoriteAnimesRepository(
110 | localeDataSource: locale,
111 | mapper: mapper
112 | )
113 |
114 | return Interactor(repository: repository) as! U
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/Yume/Core/Utils/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Core/Utils/.DS_Store
--------------------------------------------------------------------------------
/Yume/Core/Utils/Extensions/File+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // File+Ext.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 06/02/23.
6 | //
7 |
8 | import Foundation
9 |
10 | struct File {
11 | static func loadFile(
12 | forResource resource: String,
13 | ofType type: String) -> String {
14 | guard let filePath = Bundle.main.path(forResource: resource, ofType: type) else {
15 | fatalError("Couldn't find file '\(resource).\(type)'.")
16 | }
17 |
18 | return filePath
19 | }
20 |
21 | static func loadDictionaryKey(
22 | forKey key: String,
23 | forResource resource: String,
24 | ofType type: String) -> Any {
25 | let filePath = loadFile(forResource: resource, ofType: type)
26 |
27 | let plist = NSDictionary(contentsOfFile: filePath)
28 | guard let value = plist?.object(forKey: "API_KEY") else {
29 | fatalError("Couldn't find key '\(key)' in '\(resource).\(type)'.")
30 | }
31 |
32 | return value
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Yume/Core/Utils/Extensions/UINavigationController+Ext.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UINavigationController+Ext.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 30/12/22.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UINavigationController {
11 | open override func viewDidLoad() {
12 | super.viewDidLoad()
13 | interactivePopGestureRecognizer?.delegate = nil
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Yume/Core/Utils/Network/APICall.swift:
--------------------------------------------------------------------------------
1 | //
2 | // APICall.swift
3 | // Yume
4 | //
5 | // Created by Bryan on 28/12/22.
6 | //
7 |
8 | import Foundation
9 | import Alamofire
10 |
11 | struct API {
12 |
13 | static let baseUrl = "https://api.myanimelist.net/v2/"
14 | static let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(keyEncoding: .convertToSnakeCase))
15 | static var headers: HTTPHeaders {
16 | guard let apiKey = File.loadDictionaryKey(forKey: "API_KEY", forResource: "Keys", ofType: "plist") as? String else {
17 | fatalError("Value of 'API_KEY' in 'Keys.plist' is not a String")
18 | }
19 |
20 | if apiKey.starts(with: "_") {
21 | debugPrint("Create a MyAnimeList account and get a Client ID (API key) at https://myanimelist.net/apiconfig.")
22 | }
23 |
24 | return ["X-MAL-CLIENT-ID": apiKey]
25 | }
26 |
27 | }
28 |
29 | protocol Endpoint {
30 |
31 | var url: String { get }
32 |
33 | }
34 |
35 | enum Endpoints {
36 |
37 | enum Gets: Endpoint {
38 | case detail
39 | case ranking
40 | case search
41 |
42 | public var url: String {
43 | switch self {
44 | case .detail: return "\(API.baseUrl)anime"
45 | case .ranking: return "\(API.baseUrl)anime/ranking"
46 | case .search: return "\(API.baseUrl)anime"
47 | }
48 | }
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/Yume/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Yume/Preview Content/PreviewData copy.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PreviewData.swift
3 | // Rawg
4 | //
5 | // Created by Bryan on 21/10/22.
6 | //
7 |
8 | import Foundation
9 |
10 | class PreviewData {
11 | static func load(_ file: String) -> T {
12 | guard let path = Bundle.main.path(forResource: file, ofType: "json") else {
13 | fatalError("Failed to locate \(file) in bundle.")
14 | }
15 |
16 | guard let data = try? Data(contentsOf: URL(filePath: path)) else {
17 | fatalError("Failed to load \(file) from bundle.")
18 | }
19 |
20 | let decoder = JSONDecoder()
21 |
22 | guard let result = try? decoder.decode(T.self, from: data) else {
23 | fatalError("Failed to decode \(file) from bundle.")
24 | }
25 |
26 | return result as T
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/.DS_Store
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/.DS_Store
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/100.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/114.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/128.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/144.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/16.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/172.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/172.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/196.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/216.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/216.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/256.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/32.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/48.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/50.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/512.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/55.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/57.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/64.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/66.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/66.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/72.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/88.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/88.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/92.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Assets.xcassets/AppIcon.appiconset/92.png
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFF",
9 | "green" : "0xFB",
10 | "red" : "0xFF"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorInverseOnSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xF4",
9 | "green" : "0xEF",
10 | "red" : "0xF3"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorInversePrimary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFF",
9 | "green" : "0xC1",
10 | "red" : "0xC1"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorInverseSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x34",
9 | "green" : "0x30",
10 | "red" : "0x31"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOnBackground.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x1F",
9 | "green" : "0x1B",
10 | "red" : "0x1C"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOnPrimary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFF",
9 | "green" : "0xFF",
10 | "red" : "0xFF"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOnSecondaryContainer.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x2C",
9 | "green" : "0x1A",
10 | "red" : "0x1A"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOnSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x1F",
9 | "green" : "0x1B",
10 | "red" : "0x1C"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOnSurfaceVariant.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x4F",
9 | "green" : "0x46",
10 | "red" : "0x47"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOutline.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0x80",
9 | "green" : "0x76",
10 | "red" : "0x77"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorOutlineVariant.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xD0",
9 | "green" : "0xC5",
10 | "red" : "0xC8"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorPrimary.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xC2",
9 | "green" : "0x50",
10 | "red" : "0x4F"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorSecondaryContainer.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xF9",
9 | "green" : "0xE0",
10 | "red" : "0xE2"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorSurface.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFF",
9 | "green" : "0xFB",
10 | "red" : "0xFF"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorSurface2.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xFA",
9 | "green" : "0xED",
10 | "red" : "0xF1"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/ColorSurfaceVariant.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xEC",
9 | "green" : "0xE1",
10 | "red" : "0xE4"
11 | }
12 | },
13 | "idiom" : "universal"
14 | }
15 | ],
16 | "info" : {
17 | "author" : "xcode",
18 | "version" : 1
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Black.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-BlackItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Bold.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-BoldItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-ExtraBold.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-ExtraBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-ExtraBoldItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-ExtraLight.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Italic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Light.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-LightItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Medium.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-MediumItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-Regular.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-SemiBold.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Font/Nunito-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/Yume/Supporting Files/Font/Nunito-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/Yume/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIAppFonts
6 |
7 | Nunito-Regular.ttf
8 | Nunito-SemiBold.ttf
9 |
10 | UIApplicationSceneManifest
11 |
12 | UIApplicationSupportsMultipleScenes
13 |
14 | UISceneConfigurations
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/Keys-Example.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | API_KEY
6 | _MyAnimeList_Client_ID
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | Yume
4 |
5 | Created by Bryan on 09/01/23.
6 |
7 | */
8 |
--------------------------------------------------------------------------------
/Yume/Supporting Files/id.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | Yume
4 |
5 | Created by Bryan on 09/01/23.
6 |
7 | */
8 |
--------------------------------------------------------------------------------
/YumeTests/YumeTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YumeTests.swift
3 | // YumeTests
4 | //
5 | // Created by Bryan on 25/12/22.
6 | //
7 |
8 | import XCTest
9 | @testable import Yume
10 |
11 | final class YumeTests: XCTestCase {
12 |
13 | override func setUpWithError() throws {
14 | // Put setup code here. This method is called before the invocation of each test method in the class.
15 | }
16 |
17 | override func tearDownWithError() throws {
18 | // Put teardown code here. This method is called after the invocation of each test method in the class.
19 | }
20 |
21 | func testExample() throws {
22 | // This is an example of a functional test case.
23 | // Use XCTAssert and related functions to verify your tests produce the correct results.
24 | // Any test you write for XCTest can be annotated as throws and async.
25 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
26 | // Mark your test async to allow awaiting for asynchronous code to complete.
27 | // Check the results with assertions afterwards.
28 | }
29 |
30 | func testPerformanceExample() throws {
31 | // This is an example of a performance test case.
32 | self.measure {
33 | // Put the code you want to measure the time of here.
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/YumeUITests/YumeUITests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YumeUITests.swift
3 | // YumeUITests
4 | //
5 | // Created by Bryan on 25/12/22.
6 | //
7 |
8 | import XCTest
9 |
10 | final class YumeUITests: XCTestCase {
11 |
12 | override func setUpWithError() throws {
13 | // Put setup code here. This method is called before the invocation of each test method in the class.
14 |
15 | // In UI tests it is usually best to stop immediately when a failure occurs.
16 | continueAfterFailure = false
17 |
18 | // In UI tests it’s important to set the initial state - such as interface orientation - required
19 | // for your tests before they run. The setUp method is a good place to do this.
20 | }
21 |
22 | override func tearDownWithError() throws {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | }
25 |
26 | func testExample() throws {
27 | // UI tests must launch the application that they test.
28 | let app = XCUIApplication()
29 | app.launch()
30 |
31 | // Use XCTAssert and related functions to verify your tests produce the correct results.
32 | }
33 |
34 | func testLaunchPerformance() throws {
35 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
36 | // This measures how long it takes to launch your application.
37 | measure(metrics: [XCTApplicationLaunchMetric()]) {
38 | XCUIApplication().launch()
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/YumeUITests/YumeUITestsLaunchTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YumeUITestsLaunchTests.swift
3 | // YumeUITests
4 | //
5 | // Created by Bryan on 25/12/22.
6 | //
7 |
8 | import XCTest
9 |
10 | final class YumeUITestsLaunchTests: XCTestCase {
11 |
12 | override class var runsForEachTargetApplicationUIConfiguration: Bool {
13 | true
14 | }
15 |
16 | override func setUpWithError() throws {
17 | continueAfterFailure = false
18 | }
19 |
20 | func testLaunch() throws {
21 | let app = XCUIApplication()
22 | app.launch()
23 |
24 | // Insert steps here to perform after app launch but before taking a screenshot,
25 | // such as logging into a test account or navigating somewhere in the app
26 |
27 | let attachment = XCTAttachment(screenshot: app.screenshot())
28 | attachment.name = "Launch Screen"
29 | attachment.lifetime = .keepAlways
30 | add(attachment)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/codemagic.yaml:
--------------------------------------------------------------------------------
1 | workflows:
2 | ios-project-debug: # workflow ID
3 | name: iOS debug # workflow name
4 | environment:
5 | xcode: latest
6 | cocoapods: default
7 | vars:
8 | XCODE_PROJECT: "Yume.xcodeproj" # Project name
9 | XCODE_SCHEME: "Yume" # Scheme name
10 | scripts:
11 | - name: Run tests
12 | script: |
13 | xcodebuild \
14 | -project "$XCODE_PROJECT" \
15 | -scheme "$XCODE_SCHEME" \
16 | -sdk iphonesimulator \
17 | -destination 'platform=iOS Simulator,name=iPhone 14 Pro,OS=16.4' \
18 | clean build test CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
19 | - name: Build debug app
20 | script: |
21 | xcodebuild build -project "$XCODE_PROJECT" \
22 | -scheme "$XCODE_SCHEME" \
23 | CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
24 | artifacts:
25 | - $HOME/Library/Developer/Xcode/DerivedData/**/Build/**/*.app
26 | publishing:
27 | email:
28 | recipients:
29 | - bryanmuliawan@yahoo.co.id # Notification email
30 |
--------------------------------------------------------------------------------
/readme/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/.DS_Store
--------------------------------------------------------------------------------
/readme/dependency-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/dependency-diagram.png
--------------------------------------------------------------------------------
/readme/feature-graphic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/feature-graphic.jpg
--------------------------------------------------------------------------------
/readme/screen-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/screen-1.jpg
--------------------------------------------------------------------------------
/readme/screen-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/screen-2.jpg
--------------------------------------------------------------------------------
/readme/screen-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/screen-3.jpg
--------------------------------------------------------------------------------
/readme/screen-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/screen-4.jpg
--------------------------------------------------------------------------------
/readme/screen-5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bryanless/Yume-Swift/fdce1064d8107a8f1001d223492d5c7f367145e1/readme/screen-5.jpg
--------------------------------------------------------------------------------