Skip to content

Commit 03914dd

Browse files
committed
Minor fixes.
1 parent 2a57a19 commit 03914dd

File tree

11 files changed

+116
-83
lines changed

11 files changed

+116
-83
lines changed

Hanami.xcodeproj/project.pbxproj

+8-4
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
0859979C28F6DBE50095422C /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0859979B28F6DBE50095422C /* Logger.swift */; };
3232
085DB65F28E11BD100AF5323 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 085DB65E28E11BD100AF5323 /* NukeUI */; };
3333
086A3DDA296F6BCB00CF434C /* PopupView in Frameworks */ = {isa = PBXBuildFile; productRef = 086A3DD9296F6BCB00CF434C /* PopupView */; };
34+
086A3DDC297029C700CF434C /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 086A3DDB297029C700CF434C /* Collection.swift */; };
3435
08700EF3295769A90019E615 /* LiveTextHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08700EF2295769A90019E615 /* LiveTextHandler.swift */; };
3536
08700EF629576A390019E615 /* LiveText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08700EF529576A390019E615 /* LiveText.swift */; };
3637
08700EFA29578C2B0019E615 /* Shimmering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08700EF929578C2B0019E615 /* Shimmering.swift */; };
@@ -185,6 +186,7 @@
185186
0859979428F4C4170095422C /* SettingsFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFeature.swift; sourceTree = "<group>"; };
186187
0859979628F4C4230095422C /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
187188
0859979B28F6DBE50095422C /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
189+
086A3DDB297029C700CF434C /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
188190
08700EF2295769A90019E615 /* LiveTextHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveTextHandler.swift; sourceTree = "<group>"; };
189191
08700EF529576A390019E615 /* LiveText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveText.swift; sourceTree = "<group>"; };
190192
08700EF929578C2B0019E615 /* Shimmering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shimmering.swift; sourceTree = "<group>"; };
@@ -347,6 +349,7 @@
347349
080D1DBA294FDEE8008B813C /* DataType */ = {
348350
isa = PBXGroup;
349351
children = (
352+
086A3DDB297029C700CF434C /* Collection.swift */,
350353
22DA241E2839752800150C23 /* Double.swift */,
351354
226DF7962865C08D007CF96A /* String.swift */,
352355
22655331287EFED400D61873 /* Array.swift */,
@@ -1049,6 +1052,7 @@
10491052
229F9A3128BB0A290015BC8B /* URL.swift in Sources */,
10501053
0829E20828F896C30009A907 /* AuthClient.swift in Sources */,
10511054
22DA241F2839752800150C23 /* Double.swift in Sources */,
1055+
086A3DDC297029C700CF434C /* Collection.swift in Sources */,
10521056
22E057E12843F201004CD4C3 /* UIApplication.swift in Sources */,
10531057
224E671B282EAA50001D214C /* AppError.swift in Sources */,
10541058
22F4A85428AB29C9008C11A7 /* VolumeTabView.swift in Sources */,
@@ -1210,7 +1214,7 @@
12101214
CODE_SIGN_ENTITLEMENTS = Hanami/Hanami.entitlements;
12111215
CODE_SIGN_IDENTITY = "Apple Development";
12121216
CODE_SIGN_STYLE = Automatic;
1213-
CURRENT_PROJECT_VERSION = 9;
1217+
CURRENT_PROJECT_VERSION = 10;
12141218
DEVELOPMENT_ASSET_PATHS = "\"Hanami/Preview Content\"";
12151219
DEVELOPMENT_TEAM = HJ9678T652;
12161220
ENABLE_PREVIEWS = YES;
@@ -1231,7 +1235,7 @@
12311235
"$(inherited)",
12321236
"@executable_path/Frameworks",
12331237
);
1234-
MARKETING_VERSION = 0.23;
1238+
MARKETING_VERSION = 0.23.1;
12351239
PRODUCT_BUNDLE_IDENTIFIER = moe.mkpwnz.Hanami;
12361240
PRODUCT_NAME = "Hanami - Manga Reader";
12371241
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1251,7 +1255,7 @@
12511255
CODE_SIGN_ENTITLEMENTS = Hanami/Hanami.entitlements;
12521256
CODE_SIGN_IDENTITY = "Apple Development";
12531257
CODE_SIGN_STYLE = Automatic;
1254-
CURRENT_PROJECT_VERSION = 9;
1258+
CURRENT_PROJECT_VERSION = 10;
12551259
DEVELOPMENT_ASSET_PATHS = "\"Hanami/Preview Content\"";
12561260
DEVELOPMENT_TEAM = HJ9678T652;
12571261
ENABLE_PREVIEWS = YES;
@@ -1272,7 +1276,7 @@
12721276
"$(inherited)",
12731277
"@executable_path/Frameworks",
12741278
);
1275-
MARKETING_VERSION = 0.23;
1279+
MARKETING_VERSION = 0.23.1;
12761280
PRODUCT_BUNDLE_IDENTIFIER = moe.mkpwnz.Hanami;
12771281
PRODUCT_NAME = "Hanami - Manga Reader";
12781282
PROVISIONING_PROFILE_SPECIFIER = "";

Hanami/App/Core/Downloads/DownloadsFeature.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ struct DownloadsFeature: ReducerProtocol {
4343
case .cachedMangaFetched(let result):
4444
switch result {
4545
case .success(let retrievedMangaEntries):
46-
let cachedMangaIDsSet = Set(state.cachedMangaThumbnailStates.map(\.id))
47-
let retrievedMangaIDs = Set(retrievedMangaEntries.map(\.manga.id))
46+
let cachedMangaIDsSet = state.cachedMangaThumbnailStates.ids
47+
let retrievedMangaIDs = retrievedMangaEntries.idsSet
4848
let stateIDsToLeave = cachedMangaIDsSet.intersection(retrievedMangaIDs)
4949
let newMangaIDs = retrievedMangaIDs.subtracting(stateIDsToLeave)
5050

Hanami/App/Core/Manga/MangaReadingView/Offline/OfflineMangaReadingView.swift

+6-7
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,19 @@ struct OfflineMangaReadingView: View {
5858
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
5959
mainBlockOpacity = 1
6060
}
61+
62+
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
63+
withAnimation(.linear) {
64+
showNavBar = false
65+
}
66+
}
6167
}
6268
}
6369
.background(Color.theme.background)
6470
.overlay(navigationBlock)
6571
.navigationBarHidden(true)
6672
.gesture(tapGesture)
6773
.autoBlur(radius: blurRadius)
68-
.onAppear {
69-
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
70-
withAnimation(.linear) {
71-
showNavBar = false
72-
}
73-
}
74-
}
7574
}
7675
}
7776

Hanami/App/Core/Manga/MangaReadingView/Online/OnlineMangaReadingView.swift

+7-7
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,18 @@ struct OnlineMangaReadingView: View {
5555
.tint(.theme.accent)
5656
}
5757
}
58+
.onChange(of: viewStore.chapterIndex) { _ in
59+
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
60+
withAnimation(.linear) {
61+
showNavBar = false
62+
}
63+
}
64+
}
5865
}
5966
.gesture(tapGesture)
6067
.overlay(navigationBlock)
6168
.navigationBarHidden(true)
6269
.autoBlur(radius: blurRadius)
63-
.onAppear {
64-
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
65-
withAnimation(.linear) {
66-
showNavBar = false
67-
}
68-
}
69-
}
7070
}
7171
}
7272

Hanami/App/Core/Manga/Online/OnlineMangaFeature.swift

+26-4
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct OnlineMangaFeature: ReducerProtocol {
116116
var body: some ReducerProtocol<State, Action> {
117117
BindingReducer()
118118
Reduce { state, action in
119+
struct FirstChapterCancel: Hashable { let chpaterID: UUID }
119120
switch action {
120121
case .onAppear:
121122
var effects = [
@@ -257,11 +258,18 @@ struct OnlineMangaFeature: ReducerProtocol {
257258
hapticClient.generateFeedback(.medium).fireAndForget()
258259
)
259260

261+
// user wants to start reading manga from first chapter, have to retrieve preffered lang for reading
260262
case .startReadingButtonTapped:
263+
if let chapterLang = state.firstChapterOptions?.first?.attributes.translatedLanguage,
264+
chapterLang == state.prefferedLanguage?.rawValue {
265+
return .none
266+
}
267+
261268
return settingsClient.retireveSettingsConfig()
262269
.receive(on: mainQueue)
263270
.catchToEffect(Action.settingsConfigRetrieved)
264-
271+
272+
// after we retrieved preffered lang, have to find `first` chapters
265273
case .settingsConfigRetrieved(let result):
266274
switch result {
267275
case .success(let config):
@@ -274,6 +282,7 @@ struct OnlineMangaFeature: ReducerProtocol {
274282
return .merge(
275283
firstChapterOptionsIDs.map { chapterID in
276284
mangaClient.fetchChapterDetails(chapterID)
285+
.cancellable(id: FirstChapterCancel(chpaterID: chapterID), cancelInFlight: true)
277286
.receive(on: mainQueue)
278287
.catchToEffect(Action.firstChapterOptionRetrieved)
279288
}
@@ -301,18 +310,31 @@ struct OnlineMangaFeature: ReducerProtocol {
301310
return .none
302311
}
303312

313+
// when all first chapters fetched, have to filter only with matched preffered lang
314+
// if nothing found, show all (maximum 12, because of screen size).
315+
// if there's only one chapter with preffered lang, automatically send user to manga reading view
304316
case .allFirstChaptersRetrieved:
317+
let prefferedLang = state.prefferedLanguage!.rawValue
305318
let chaptersWithSamePrefferedLang = state._firstChapterOptions!.filter {
306-
$0.attributes.translatedLanguage == state.prefferedLanguage!.rawValue
319+
$0.attributes.translatedLanguage == prefferedLang
307320
}
308321

309322
if !chaptersWithSamePrefferedLang.isEmpty {
310-
state.firstChapterOptions = chaptersWithSamePrefferedLang
323+
if chaptersWithSamePrefferedLang.idsSet != state.firstChapterOptions?.idsSet {
324+
state.firstChapterOptions = chaptersWithSamePrefferedLang
325+
}
311326
} else {
312327
state.firstChapterOptions = state._firstChapterOptions
313328
}
314329

315-
if state.firstChapterOptions!.count == 1 {
330+
state.firstChapterOptions = Array(state.firstChapterOptions!.prefix(12))
331+
332+
let onlyOneChapterAndLangMatches = state.firstChapterOptions?.count == 1 &&
333+
state.firstChapterOptions!.first!.attributes.translatedLanguage == prefferedLang &&
334+
state.firstChapterOptions!.first!.attributes.externalURL == nil
335+
336+
337+
if onlyOneChapterAndLangMatches {
316338
let chapter = state.firstChapterOptions!.first!
317339
state.mangaReadingViewState = OnlineMangaReadingFeature.State(
318340
mangaID: state.manga.id,

Hanami/App/Core/Manga/Online/OnlineMangaView.swift

+43-50
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ struct OnlineMangaView: View {
3737
let lastReadChapterAvailable: Bool
3838
let areChaptersFetched: Bool
3939
let firstChapterOptions: [ChapterDetails]?
40+
let userReadsManga: Bool
4041

4142
init(state: OnlineMangaFeature.State) {
4243
manga = state.manga
@@ -50,6 +51,7 @@ struct OnlineMangaView: View {
5051
lastReadChapterAvailable = state.lastReadChapterID.hasValue && state.pagesState.hasValue
5152
areChaptersFetched = state.pagesState.hasValue
5253
firstChapterOptions = state.firstChapterOptions
54+
userReadsManga = state.isUserOnReadingView
5355
}
5456
}
5557

@@ -125,61 +127,54 @@ extension OnlineMangaView {
125127
.font(.title3)
126128
.padding(.bottom, 10)
127129

128-
if let firstChapterOptions = viewStore.firstChapterOptions {
129-
VStack(alignment: .leading, spacing: 12) {
130-
ForEach(firstChapterOptions) { chapter in
131-
VStack(alignment: .leading) {
132-
HStack(alignment: .bottom) {
133-
Text(chapter.chapterName)
134-
135-
Spacer()
136-
137-
if chapter.attributes.externalURL != nil {
138-
Image("ExternalLinkIcon")
139-
.resizable()
140-
.frame(width: 20, height: 20)
141-
}
142-
}
130+
ForEach(viewStore.firstChapterOptions ?? []) { chapter in
131+
LazyVStack(alignment: .leading) {
132+
HStack(alignment: .bottom) {
133+
Text(chapter.chapterName)
134+
135+
Spacer()
136+
137+
if chapter.attributes.externalURL != nil {
138+
Image("ExternalLinkIcon")
139+
.resizable()
140+
.frame(width: 20, height: 20)
141+
}
142+
}
143+
144+
if let scanlationGroup = chapter.scanlationGroup {
145+
HStack {
146+
Text(scanlationGroup.name)
147+
.fontWeight(.bold)
148+
.lineLimit(1)
149+
.font(.caption)
150+
.foregroundColor(.theme.secondaryText)
143151

144-
if let scanlationGroup = chapter.scanlationGroup {
145-
HStack {
146-
Text(scanlationGroup.name)
147-
.fontWeight(.bold)
148-
.lineLimit(1)
149-
.font(.caption)
150-
.foregroundColor(.theme.secondaryText)
151-
152-
if scanlationGroup.attributes.isOfficial {
153-
Image(systemName: "person.badge.shield.checkmark")
154-
.resizable()
155-
.scaledToFit()
156-
.foregroundColor(.green)
157-
.frame(height: 15)
158-
}
159-
}
152+
if scanlationGroup.attributes.isOfficial {
153+
Image(systemName: "person.badge.shield.checkmark")
154+
.resizable()
155+
.scaledToFit()
156+
.foregroundColor(.green)
157+
.frame(height: 15)
160158
}
161-
162-
Divider()
163-
}
164-
.onTapGesture {
165-
showFirstChaptersPopup = false
166-
viewStore.send(.userTappedOnFirstChapterOption(chapter))
167159
}
168160
}
169-
.frame(maxWidth: .infinity, alignment: .leading)
161+
162+
Divider()
163+
}
164+
.onTapGesture {
165+
showFirstChaptersPopup = false
166+
viewStore.send(.userTappedOnFirstChapterOption(chapter))
170167
}
171-
} else {
172-
ProgressView()
173168
}
169+
.frame(maxWidth: .infinity, alignment: .leading)
174170
}
175-
.animation(.linear, value: viewStore.firstChapterOptions?.count)
176-
.padding(25)
177-
.background(Color.theme.background.cornerRadius(20))
178-
.frame(maxWidth: .infinity)
179-
.padding(.horizontal, 40)
180171
}
172+
.padding(25)
173+
.background(Color.theme.background.cornerRadius(20))
174+
.frame(maxWidth: .infinity)
175+
.padding(.horizontal, 40)
181176
}
182-
177+
183178
private var footer: some View {
184179
HStack(spacing: 0) {
185180
Text("All information on this page provided by ")
@@ -574,10 +569,8 @@ extension OnlineMangaView {
574569
}
575570
}
576571
.padding(.horizontal, 5)
577-
.onChange(of: viewStore.firstChapterOptions) { newValue in
578-
if newValue.hasValue && newValue!.count > 1 {
579-
showFirstChaptersPopup = true
580-
}
572+
.onChange(of: viewStore.firstChapterOptions.hasValue) { _ in
573+
showFirstChaptersPopup = !viewStore.userReadsManga
581574
}
582575
}
583576
}

Hanami/App/Core/Manga/Pages/PagesFeature.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ struct PagesFeature: ReducerProtocol {
164164
var firstChapterOptionsIDs: [UUID] {
165165
var firstChapter: Chapter?
166166

167-
for page in splitIntoPagesVolumeTabStates.reversed() {
168-
for volumeState in page.reversed() {
169-
for chapterState in volumeState.chapterStates.reversed() {
170-
if firstChapter == nil {
167+
for page in splitIntoPagesVolumeTabStates {
168+
for volumeState in page {
169+
for chapterState in volumeState.chapterStates where (chapterState.chapter.index ?? .infinity) > 0 {
170+
if firstChapter.isNil {
171171
firstChapter = chapterState.chapter
172172
} else if (firstChapter!.index ?? .infinity) > (chapterState.chapter.index ?? .infinity) {
173173
firstChapter = chapterState.chapter

Hanami/App/Core/Search/SearchFeature.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ struct SearchFeature: ReducerProtocol {
111111

112112
case .cancelSearchButtonTapped:
113113
// cancelling all subscriptions to clear cache for manga(because all instance will be destroyed)
114-
let mangaIDs = state.foundManga.map(\.id)
114+
let mangaIDs = state.foundManga.idsSet
115115

116116
state.searchText = ""
117117
state.foundManga.removeAll()

Hanami/App/Core/Settings/Categories/LocalizationSettingsView.swift

+5-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ struct LocalizationSettingsView: View {
2121
ForEach(allLanguages) { lang in
2222
HStack {
2323
Text(lang.language)
24-
.onTapGesture {
25-
selectedLanugauge = lang
26-
dismiss()
27-
}
2824

2925
Spacer()
3026

@@ -33,6 +29,11 @@ struct LocalizationSettingsView: View {
3329
.foregroundColor(.theme.accent)
3430
}
3531
}
32+
.contentShape(Rectangle())
33+
.onTapGesture {
34+
selectedLanugauge = lang
35+
dismiss()
36+
}
3637
}
3738
}
3839
.listStyle(.plain)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// Collection.swift
3+
// Hanami
4+
//
5+
// Created by Oleg on 12.01.23.
6+
//
7+
8+
import Foundation
9+
10+
extension Collection where Element: Identifiable {
11+
var idsSet: Set<Element.ID> {
12+
Set(map(\.id))
13+
}
14+
}

0 commit comments

Comments
 (0)