From d0f36dc4eed0edc1074d4c689c4518cec10401e4 Mon Sep 17 00:00:00 2001 From: KaitoMuraoka Date: Sat, 28 Sep 2024 19:29:02 +0900 Subject: [PATCH 1/5] =?UTF-8?q?StringsCatalog=20=E3=81=AB=E7=A7=BB?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #5 --- Osushi.xcodeproj/project.pbxproj | 18 ++++ Osushi/Model/APIModelData.swift | 2 +- Osushi/Resources/Localizable.xcstrings | 85 +++++++++++++++++++ Osushi/Resources/Strings.swift | 36 ++++++++ Osushi/View/ContentView.swift | 6 +- .../View/FavoriteList/FavoriteListView.swift | 6 +- .../View/InfomationList/CommunityView.swift | 2 +- Osushi/View/InfomationList/InfoListView.swift | 8 +- .../InformationListViewModel.swift | 2 +- .../Lisence/LisenceListView.swift | 2 +- Osushi/View/InfomationList/SNSView.swift | 4 +- .../Staff/ProfileDetailView.swift | 4 +- .../InfomationList/Staff/StaffListView.swift | 2 +- Osushi/View/PostList/DetailPostView.swift | 4 +- Osushi/View/PostList/PostListView.swift | 2 +- Osushi/View/PostList/PostListViewModel.swift | 2 +- 16 files changed, 162 insertions(+), 23 deletions(-) create mode 100644 Osushi/Resources/Localizable.xcstrings create mode 100644 Osushi/Resources/Strings.swift diff --git a/Osushi.xcodeproj/project.pbxproj b/Osushi.xcodeproj/project.pbxproj index 9b63195..1ab1e31 100644 --- a/Osushi.xcodeproj/project.pbxproj +++ b/Osushi.xcodeproj/project.pbxproj @@ -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 */ @@ -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 = ""; }; 3F91F17D2BBA88E1008EC967 /* OsushiUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OsushiUITestsLaunchTests.swift; sourceTree = ""; }; + 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + 3FC7CE712CA80B590058BFB0 /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -211,6 +215,7 @@ 3F6891292BBAF473003E7982 /* Model */, 3F91F1642BBA88E1008EC967 /* Assets.xcassets */, 3F91F1662BBA88E1008EC967 /* Preview Content */, + 3FC7CE702CA80B480058BFB0 /* Resources */, ); path = Osushi; sourceTree = ""; @@ -241,6 +246,15 @@ path = OsushiUITests; sourceTree = ""; }; + 3FC7CE702CA80B480058BFB0 /* Resources */ = { + isa = PBXGroup; + children = ( + 3FC7CE712CA80B590058BFB0 /* Strings.swift */, + 3FC7CE6E2CA80AF90058BFB0 /* Localizable.xcstrings */, + ); + path = Resources; + sourceTree = ""; + }; 3FF9231B2BBA8AF000092F07 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -373,6 +387,7 @@ files = ( 3F91F1682BBA88E1008EC967 /* Preview Assets.xcassets in Resources */, 3F91F1652BBA88E1008EC967 /* Assets.xcassets in Resources */, + 3FC7CE6F2CA80AF90058BFB0 /* Localizable.xcstrings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -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 */, @@ -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; @@ -596,6 +613,7 @@ MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/Osushi/Model/APIModelData.swift b/Osushi/Model/APIModelData.swift index 523ea52..d7f8348 100644 --- a/Osushi/Model/APIModelData.swift +++ b/Osushi/Model/APIModelData.swift @@ -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 diff --git a/Osushi/Resources/Localizable.xcstrings b/Osushi/Resources/Localizable.xcstrings new file mode 100644 index 0000000..078198a --- /dev/null +++ b/Osushi/Resources/Localizable.xcstrings @@ -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" +} \ No newline at end of file diff --git a/Osushi/Resources/Strings.swift b/Osushi/Resources/Strings.swift new file mode 100644 index 0000000..b976a50 --- /dev/null +++ b/Osushi/Resources/Strings.swift @@ -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: "不明") + } +} diff --git a/Osushi/View/ContentView.swift b/Osushi/View/ContentView.swift index f09f1b3..e3981d0 100644 --- a/Osushi/View/ContentView.swift +++ b/Osushi/View/ContentView.swift @@ -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, image: "star") } .tag(Tab.favorite) InfoListView() .tabItem { - Label("iOS Osushi", image: .tabOsushi) + Label(Strings.Home.iosOsushi, image: .tabOsushi) }.tag(Tab.setting) } } diff --git a/Osushi/View/FavoriteList/FavoriteListView.swift b/Osushi/View/FavoriteList/FavoriteListView.swift index 895f76c..f4c3ff2 100644 --- a/Osushi/View/FavoriteList/FavoriteListView.swift +++ b/Osushi/View/FavoriteList/FavoriteListView.swift @@ -22,13 +22,13 @@ struct FavoriteListView: View { } } } - .navigationTitle("お気に入り一覧") + .navigationTitle(Strings.FavoriteList.title) .overlay { if favoritePosts.isEmpty { ContentUnavailableView { - Label("お気に入りがありません", systemImage: "tray.fill") + Label(Strings.FavoriteList.emptyListTitle, systemImage: "tray.fill") } description: { - Text("お気に入りボタンをタップして追加してみよう🍣") + Text(Strings.FavoriteList.emptyListMessage) } } } diff --git a/Osushi/View/InfomationList/CommunityView.swift b/Osushi/View/InfomationList/CommunityView.swift index b9d9582..38dd6cb 100644 --- a/Osushi/View/InfomationList/CommunityView.swift +++ b/Osushi/View/InfomationList/CommunityView.swift @@ -22,7 +22,7 @@ struct CommunityView: View { Spacer() } - Text("iOS Osushiは、iOS関連のニュースを定期的に配信するサイトです。") + Text(Strings.Infomation.description) } } diff --git a/Osushi/View/InfomationList/InfoListView.swift b/Osushi/View/InfomationList/InfoListView.swift index c42cfa8..3c5eeb5 100644 --- a/Osushi/View/InfomationList/InfoListView.swift +++ b/Osushi/View/InfomationList/InfoListView.swift @@ -18,19 +18,19 @@ struct InfoListView: View { } Section { - NavigationLink("運営") { + NavigationLink(Strings.Infomation.management) { StaffListView(profiles: InformationListViewModel.profiles) } - NavigationLink("ライセンス") { + NavigationLink(Strings.Infomation.license) { LisenceListView() } } Section { - LabeledContent("バージョン", value: viewModel.versionString) + LabeledContent(Strings.Infomation.version, value: viewModel.versionString) } } - .navigationTitle("iOS Osushi🍣") + .navigationTitle(Strings.Infomation.title) } } } diff --git a/Osushi/View/InfomationList/InformationListViewModel.swift b/Osushi/View/InfomationList/InformationListViewModel.swift index a47602f..ad19dba 100644 --- a/Osushi/View/InfomationList/InformationListViewModel.swift +++ b/Osushi/View/InfomationList/InformationListViewModel.swift @@ -20,6 +20,6 @@ final class InformationListViewModel { } private func makeVersionString(forInfoDictionaryKey key: String) -> String { - Bundle.main.object(forInfoDictionaryKey: key) as? String ?? "不明" + Bundle.main.object(forInfoDictionaryKey: key) as? String ?? Strings.Other.unknown } } diff --git a/Osushi/View/InfomationList/Lisence/LisenceListView.swift b/Osushi/View/InfomationList/Lisence/LisenceListView.swift index da899a2..1b5d043 100644 --- a/Osushi/View/InfomationList/Lisence/LisenceListView.swift +++ b/Osushi/View/InfomationList/Lisence/LisenceListView.swift @@ -36,7 +36,7 @@ SOFTWARE. ) ) } - .navigationTitle("ライセンス") + .navigationTitle(Strings.Infomation.license) } } } diff --git a/Osushi/View/InfomationList/SNSView.swift b/Osushi/View/InfomationList/SNSView.swift index a5bf08a..d396a15 100644 --- a/Osushi/View/InfomationList/SNSView.swift +++ b/Osushi/View/InfomationList/SNSView.swift @@ -5,7 +5,7 @@ struct SNSView: View { let gitHubUrlString: String var body: some View { - Link("X", destination: URL(string: xUrlString)!) - Link("GitHub", destination: URL(string: gitHubUrlString)!) + Link(Strings.Infomation.x, destination: URL(string: xUrlString)!) + Link(Strings.Infomation.gitHub, destination: URL(string: gitHubUrlString)!) } } diff --git a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift index 73dd02d..ba650ff 100644 --- a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift +++ b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift @@ -15,14 +15,14 @@ struct ProfileDetailView: View { HStack { Link( - "X", + Strings.Infomation.x, destination: URL( string: "https://twitter.com/\(profile.x)" )! ) Link( - "GitHub", + Strings.Infomation.gitHub, destination: URL( string: "https://github.com/\(profile.gitHub)" )! diff --git a/Osushi/View/InfomationList/Staff/StaffListView.swift b/Osushi/View/InfomationList/Staff/StaffListView.swift index 68588cf..0bff38c 100644 --- a/Osushi/View/InfomationList/Staff/StaffListView.swift +++ b/Osushi/View/InfomationList/Staff/StaffListView.swift @@ -14,7 +14,7 @@ struct StaffListView: View { } } } - .navigationTitle("運営メンバー") + .navigationTitle(Strings.Infomation.staffListTitle) } } } diff --git a/Osushi/View/PostList/DetailPostView.swift b/Osushi/View/PostList/DetailPostView.swift index 14a2063..611a971 100644 --- a/Osushi/View/PostList/DetailPostView.swift +++ b/Osushi/View/PostList/DetailPostView.swift @@ -5,10 +5,10 @@ import TipKit struct FavoriteButtonTip: Tip { var title: Text { - Text("お気に入りボタン") + Text(Strings.PostList.tipsTitle) } var message: Text? { - Text("この記事をお気に入りすることができます🍣\nお気に入りした記事は下のタブから確認することができます!") + Text(Strings.PostList.tipsMessage) } } diff --git a/Osushi/View/PostList/PostListView.swift b/Osushi/View/PostList/PostListView.swift index 646988e..879de97 100644 --- a/Osushi/View/PostList/PostListView.swift +++ b/Osushi/View/PostList/PostListView.swift @@ -16,7 +16,7 @@ struct PostListView: View { } } } - .navigationTitle("投稿一覧") + .navigationTitle(Strings.PostList.title) .refreshable { viewModel.fetchPosts() } diff --git a/Osushi/View/PostList/PostListViewModel.swift b/Osushi/View/PostList/PostListViewModel.swift index d777659..7c3b58a 100644 --- a/Osushi/View/PostList/PostListViewModel.swift +++ b/Osushi/View/PostList/PostListViewModel.swift @@ -29,6 +29,6 @@ final class PostListViewModel: ObservableObject { .trimmingCharacters(in: .whitespaces) } } - return "詳細情報が見つかりません。" + return Strings.PostList.errorMessage } } From e29e1fdce9cb5a6785b08fef91c35937a9646722 Mon Sep 17 00:00:00 2001 From: KaitoMuraoka Date: Sat, 28 Sep 2024 19:51:15 +0900 Subject: [PATCH 2/5] =?UTF-8?q?gitignore=E3=82=92=E7=B7=A8=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #8 --- .gitignore | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/.gitignore b/.gitignore index 4f20167..52fe2f7 100644 --- a/.gitignore +++ b/.gitignore @@ -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 @@ -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. @@ -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 From 8dfef40aa773579457283bbcbf524cd23b02281b Mon Sep 17 00:00:00 2001 From: KaitoMuraoka Date: Sun, 29 Sep 2024 23:01:11 +0900 Subject: [PATCH 3/5] =?UTF-8?q?SwiftLint=20=E3=81=AEwarning=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Osushi/Model/Favorite.swift | 2 +- Osushi/View/InfomationList/Lisence/LisenceView.swift | 2 +- Osushi/View/InfomationList/SNSView.swift | 2 ++ .../View/InfomationList/Staff/ProfileDetailView.swift | 4 ++-- Osushi/View/PostList/DetailPostView.swift | 6 ++---- Osushi/View/PostList/PostListViewModel.swift | 10 ++++------ Osushi/View/PostList/PostRowView.swift | 6 ++---- 7 files changed, 14 insertions(+), 18 deletions(-) diff --git a/Osushi/Model/Favorite.swift b/Osushi/Model/Favorite.swift index 96d50a8..4f8f3cd 100644 --- a/Osushi/Model/Favorite.swift +++ b/Osushi/Model/Favorite.swift @@ -2,7 +2,7 @@ import SwiftData @Model final class Favorite { - let post: String + var post: String init(post: String) { self.post = post diff --git a/Osushi/View/InfomationList/Lisence/LisenceView.swift b/Osushi/View/InfomationList/Lisence/LisenceView.swift index 614f90b..2b454ff 100644 --- a/Osushi/View/InfomationList/Lisence/LisenceView.swift +++ b/Osushi/View/InfomationList/Lisence/LisenceView.swift @@ -17,6 +17,6 @@ struct LisenceView: View { } private var url: URL { - URL(string: urlString)! + URL(string: urlString)! // swiftlint:disable:this force_unwrapping } } diff --git a/Osushi/View/InfomationList/SNSView.swift b/Osushi/View/InfomationList/SNSView.swift index d396a15..7b7c4d7 100644 --- a/Osushi/View/InfomationList/SNSView.swift +++ b/Osushi/View/InfomationList/SNSView.swift @@ -5,7 +5,9 @@ struct SNSView: View { let gitHubUrlString: String var body: some View { + // swiftlint:disable force_unwrapping Link(Strings.Infomation.x, destination: URL(string: xUrlString)!) Link(Strings.Infomation.gitHub, destination: URL(string: gitHubUrlString)!) + // swiftlint:enable force_unwrapping } } diff --git a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift index ba650ff..fbd4cc0 100644 --- a/Osushi/View/InfomationList/Staff/ProfileDetailView.swift +++ b/Osushi/View/InfomationList/Staff/ProfileDetailView.swift @@ -18,14 +18,14 @@ struct ProfileDetailView: View { Strings.Infomation.x, destination: URL( string: "https://twitter.com/\(profile.x)" - )! + )!// swiftlint:disable:this force_unwrapping ) Link( Strings.Infomation.gitHub, destination: URL( string: "https://github.com/\(profile.gitHub)" - )! + )!// swiftlint:disable:this force_unwrapping ) } } diff --git a/Osushi/View/PostList/DetailPostView.swift b/Osushi/View/PostList/DetailPostView.swift index 611a971..6165346 100644 --- a/Osushi/View/PostList/DetailPostView.swift +++ b/Osushi/View/PostList/DetailPostView.swift @@ -63,10 +63,8 @@ struct DetailPostView: View { } private func setupData() { - for favoritePost in favoritePosts { - if favoritePost.post == markdownContent { - isFavorited = true - } + for favoritePost in favoritePosts where favoritePost.post == markdownContent { + isFavorited = true } } diff --git a/Osushi/View/PostList/PostListViewModel.swift b/Osushi/View/PostList/PostListViewModel.swift index 7c3b58a..9586ac3 100644 --- a/Osushi/View/PostList/PostListViewModel.swift +++ b/Osushi/View/PostList/PostListViewModel.swift @@ -22,12 +22,10 @@ final class PostListViewModel: ObservableObject { func descriptText(_ content: String) -> String { let lines = content.components(separatedBy: "\n") - for line in lines { - if line.starts(with: "description:") { - return line - .replacingOccurrences(of: "description:", with: "") - .trimmingCharacters(in: .whitespaces) - } + for line in lines where line.starts(with: "description:") { + return line + .replacingOccurrences(of: "description:", with: "") + .trimmingCharacters(in: .whitespaces) } return Strings.PostList.errorMessage } diff --git a/Osushi/View/PostList/PostRowView.swift b/Osushi/View/PostList/PostRowView.swift index 16db81d..05f1a92 100644 --- a/Osushi/View/PostList/PostRowView.swift +++ b/Osushi/View/PostList/PostRowView.swift @@ -7,10 +7,8 @@ struct PostRowView: View { var heading1Text: String { let lines = markdownContent.components(separatedBy: "\n") - for line in lines { - if line.starts(with: "# ") { - return line.replacingOccurrences(of: "# ", with: "").trimmingCharacters(in: .whitespaces) - } + for line in lines where line.starts(with: "# ") { + return line.replacingOccurrences(of: "# ", with: "").trimmingCharacters(in: .whitespaces) } return "" } From 5374bb47d5757b7dfb96fdf7872b58c819128ef5 Mon Sep 17 00:00:00 2001 From: KaitoMuraoka Date: Mon, 30 Sep 2024 00:03:23 +0900 Subject: [PATCH 4/5] =?UTF-8?q?API=E5=87=A6=E7=90=86=E3=82=92Concurrency?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Osushi/Model/APIModelData.swift | 75 ++++++++++++++------------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/Osushi/Model/APIModelData.swift b/Osushi/Model/APIModelData.swift index d7f8348..a77e7dc 100644 --- a/Osushi/Model/APIModelData.swift +++ b/Osushi/Model/APIModelData.swift @@ -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 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) + guard markdownString.starts(with: " ") else { + 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() } } From ee0a12ede32c8cc3df01a0d4bcb02fc99c5392c5 Mon Sep 17 00:00:00 2001 From: KaitoMuraoka Date: Mon, 30 Sep 2024 00:09:28 +0900 Subject: [PATCH 5/5] =?UTF-8?q?systemImage=20=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Osushi/View/ContentView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Osushi/View/ContentView.swift b/Osushi/View/ContentView.swift index e3981d0..8e5bf67 100644 --- a/Osushi/View/ContentView.swift +++ b/Osushi/View/ContentView.swift @@ -20,7 +20,7 @@ struct ContentView: View { FavoriteListView() .modelContainer(for: Favorite.self) .tabItem { - Label(Strings.Home.favorite, image: "star") + Label(Strings.Home.favorite, systemImage: "star") } .tag(Tab.favorite)