Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StringCatalog対応やSwinftLint修正など #15

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions .gitignore
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最新の https://github.com/github/gitignore/blob/main/Swift.gitignore を参考にしつつ、Swift Package Manager、CocoaPods、Carthage、fastlane のいずれも、コメントアウトだけでなくて記述自体を削除してしまって良いかなと思います

Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,6 @@
## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Obj-C/Swift specific
*.hmap

Expand Down Expand Up @@ -66,10 +49,6 @@ playground.xcworkspace

Carthage/Build/

# Accio dependency management
Dependencies/
.accio/

# fastlane
#
# It is recommended to not store the screenshots in the git repo.
Expand All @@ -81,11 +60,3 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/
.DS_Store
18 changes: 18 additions & 0 deletions Osushi.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
3F91F1682BBA88E1008EC967 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3F91F1672BBA88E1008EC967 /* Preview Assets.xcassets */; };
3F91F17C2BBA88E1008EC967 /* OsushiUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F91F17B2BBA88E1008EC967 /* OsushiUITests.swift */; };
3F91F17E2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F91F17D2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift */; };
3FC7CE6F2CA80AF90058BFB0 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */; };
3FC7CE722CA80B590058BFB0 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC7CE712CA80B590058BFB0 /* Strings.swift */; };
3FF9231D2BBA8AF000092F07 /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF9231C2BBA8AF000092F07 /* MarkdownUI */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -89,6 +91,8 @@
3F91F1772BBA88E1008EC967 /* OsushiUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OsushiUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3F91F17B2BBA88E1008EC967 /* OsushiUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsushiUITests.swift; sourceTree = "<group>"; };
3F91F17D2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsushiUITestsLaunchTests.swift; sourceTree = "<group>"; };
3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
3FC7CE712CA80B590058BFB0 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -211,6 +215,7 @@
3F6891292BBAF473003E7982 /* Model */,
3F91F1642BBA88E1008EC967 /* Assets.xcassets */,
3F91F1662BBA88E1008EC967 /* Preview Content */,
3FC7CE702CA80B480058BFB0 /* Resources */,
);
path = Osushi;
sourceTree = "<group>";
Expand Down Expand Up @@ -241,6 +246,15 @@
path = OsushiUITests;
sourceTree = "<group>";
};
3FC7CE702CA80B480058BFB0 /* Resources */ = {
isa = PBXGroup;
children = (
3FC7CE712CA80B590058BFB0 /* Strings.swift */,
3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */,
);
path = Resources;
sourceTree = "<group>";
};
3FF9231B2BBA8AF000092F07 /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -373,6 +387,7 @@
files = (
3F91F1682BBA88E1008EC967 /* Preview Assets.xcassets in Resources */,
3F91F1652BBA88E1008EC967 /* Assets.xcassets in Resources */,
3FC7CE6F2CA80AF90058BFB0 /* Localizable.xcstrings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -429,6 +444,7 @@
3F68911D2BBAF45A003E7982 /* ProfileDetailView.swift in Sources */,
3F6891392BBAF516003E7982 /* PostRowView.swift in Sources */,
3F91F1632BBA88DE008EC967 /* ContentView.swift in Sources */,
3FC7CE722CA80B590058BFB0 /* Strings.swift in Sources */,
3F91F1612BBA88DE008EC967 /* OsushiApp.swift in Sources */,
3F68912D2BBAF473003E7982 /* Profile.swift in Sources */,
3F68911F2BBAF45A003E7982 /* StaffListView.swift in Sources */,
Expand Down Expand Up @@ -539,6 +555,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
Expand Down Expand Up @@ -596,6 +613,7 @@
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
VALIDATE_PRODUCT = YES;
};
name = Release;
Expand Down
77 changes: 33 additions & 44 deletions Osushi/Model/APIModelData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation

final class APIModelData: ObservableObject {
@Published var markdownContent: [String] = []
@Published var errorMessage: String = "不明なエラー"
@Published var errorMessage: String = Strings.Other.unknown

private var lastFetchDate: Date?
private let fetchThresholdSeconds: TimeInterval = 3600 // 1hour
Expand All @@ -17,76 +17,65 @@ final class APIModelData: ObservableObject {
]

func fetchPostsIfNeeded() {
let now: Date = .now
if let lastFetchDate {
guard now.timeIntervalSince(lastFetchDate) > fetchThresholdSeconds else {
print("取得できませんでした。:\(now.timeIntervalSince(lastFetchDate))")
return
Task {
let now: Date = .now
if let lastFetchDate {
guard now.timeIntervalSince(lastFetchDate) > fetchThresholdSeconds else {
print("取得できませんでした。:\(now.timeIntervalSince(lastFetchDate))")
return
}
}
await fetchPosts()
lastFetchDate = now
}
fetchPosts()
lastFetchDate = now
}

private func fetchPosts() {
@MainActor
private func fetchPosts() async {
markdownContent.removeAll()
guard var url = URL(string: Url.osushiApi) else { return }
url.append(queryItems: APIModelData.githubApiQuery)

URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
guard let data, let self else { return }
if let error {
// TODO: エラー処理をここに記述
DispatchQueue.main.async {
self.errorMessage = "API Request Failed: \(error.localizedDescription)"
}
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)

// APIエラーレスポンスのハンドリング
if let rateLimitError = try? self.decoder.decode(RateLimitError.self, from: data) {
DispatchQueue.main.async {
self.errorMessage = rateLimitError.message
}
if let rateLimitError = try? decoder.decode(RateLimitError.self, from: data) {
errorMessage = rateLimitError.message
return
}

if let response = try? self.decoder.decode([Post].self, from: data) {
DispatchQueue.main.async {
if let response = try? decoder.decode([Post].self, from: data) {
// TaskGroupを使用して並列処理する
await withTaskGroup(of: Void.self) { group in
Comment on lines +49 to +50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

将来的に、PostListViewModel.sortedPosts で sort せずとも withTaskGroup(of:returning:isolation:body:) の戻り値が sort 済みである状態にしたいですね

for post in response {
self.fetchDownloadUrl(post.downloadUrl)
group.addTask {
await self.fetchDownloadUrl(post.downloadUrl)
}
}
}
return
}
} catch {
errorMessage = "API Request Failed: \(error.localizedDescription)"
}
.resume()
}

private func fetchDownloadUrl(_ downloadUrl: String) {
@MainActor
private func fetchDownloadUrl(_ downloadUrl: String) async {
if downloadUrl == Url.indexDownload { return }
guard let url = URL(string: downloadUrl) else {
fatalError("Invalid Url")
}

URLSession.shared.dataTask(with: url) { data, response, error in
guard let data else { return }
if let error {
fatalError("API Request Failed: \(error.localizedDescription)")
}

if let markdownString = String(data: data, encoding: .utf8) {
DispatchQueue.main.async {
if markdownString.starts(with: " ") { return }
self.markdownContent.append(markdownString)
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
let markdownString = String(decoding: data, as: UTF8.self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちら、今まで使っていた init(data:encoding:) から init(decoding:as:) を使うように変更されていますが、意図した変更ですか?

guard markdownString.starts(with: " ") else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

もし guard を使い続ける場合、https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/ と照らし合わせて、else 句のところには処理の脱出を強制させるべきであることを示してそのための処理を書く方が良いと思うので、!markdownString.starts(with: " ") にして else 句では return だけ行いたいです。

markdownContent.append(markdownString)
return
} else {
self.markdownContent.append("**エラー**")
// TODO: アラートを表示
print("Error fetching markdown content: \(error?.localizedDescription ?? "Unknown error")")
}
} catch {
fatalError("API Request Failed: \(error.localizedDescription)")
}
.resume()
}
}
2 changes: 1 addition & 1 deletion Osushi/Model/Favorite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import SwiftData

@Model
final class Favorite {
let post: String
var post: String

init(post: String) {
self.post = post
Expand Down
85 changes: 85 additions & 0 deletions Osushi/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"sourceLanguage" : "ja",
"strings" : {
"GitHub" : {

},
"iOS Osushi" : {

},
"iOS Osushi🍣" : {

},
"MarkdownUI" : {

},
"X" : {

},
"お気に入り" : {

},
"お気に入りボタン" : {

},
"お気に入りボタンの説明" : {
"extractionState" : "manual",
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "この記事をお気に入りすることができます🍣\nお気に入りした記事は下のタブから確認することができます!"
}
}
}
},
"お気に入りリストが空の場合のメッセージ" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "お気に入りボタンをタップして追加してみよう🍣"
}
}
}
},
"お気に入り一覧" : {

},
"コミュニティの説明" : {
"localizations" : {
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "iOS Osushi は、iOS 関連のニュースを定期的に配信するサイトです。"
}
}
}
},
"バージョン" : {

},
"ホーム" : {

},
"ライセンス" : {

},
"不明" : {

},
"投稿一覧" : {

},
"詳細情報" : {

},
"運営" : {

},
"運営メンバー" : {

}
},
"version" : "1.0"
}
36 changes: 36 additions & 0 deletions Osushi/Resources/Strings.swift
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct から enum に変更して、うっかり Strings 等のインスタンスが internal から作られないようにしませんか?

namespace 的な使い方をしたいということだと思うので

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
struct Strings {
struct Home {
static let home = String(localized: "ホーム")
static let favorite = String(localized: "お気に入り")
static let iosOsushi = String(localized: "iOS Osushi")
}

struct PostList {
static let title = String(localized: "投稿一覧")
static let tipsTitle = String(localized: "お気に入りボタン")
static let tipsMessage = String(localized: "お気に入りボタンの説明")
static let errorMessage = String(localized: "詳細情報")
}


struct FavoriteList {
static let title = String(localized: "お気に入り一覧")
static let emptyListTitle = String(localized: "お気に入り一覧")
static let emptyListMessage = String(localized: "お気に入りリストが空の場合のメッセージ")
}

struct Infomation {
static let title = String(localized: "iOS Osushi🍣")
static let management = String(localized: "運営")
static let license = String(localized: "ライセンス")
static let version = String(localized: "バージョン")
static let description = String(localized: "コミュニティの説明")
static let staffListTitle = String(localized: "運営メンバー")
static let x = String(localized: "X")
static let gitHub = String(localized: "GitHub")
}

struct Other {
static let unknown = String(localized: "不明")
}
}
6 changes: 3 additions & 3 deletions Osushi/View/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ struct ContentView: View {
TabView(selection: $selection) {
PostListView()
.tabItem {
Label("ホーム", systemImage: "house")
Label(Strings.Home.home, systemImage: "house")
}
.tag(Tab.top)

FavoriteListView()
.modelContainer(for: Favorite.self)
.tabItem {
Label("お気に入り", systemImage: "star")
Label(Strings.Home.favorite, systemImage: "star")
}
.tag(Tab.favorite)

InfoListView()
.tabItem {
Label("iOS Osushi", image: .tabOsushi)
Label(Strings.Home.iosOsushi, image: .tabOsushi)
}.tag(Tab.setting)
}
}
Expand Down
Loading