From b275437353b5428434b2cff004e9b6e51561ef2a Mon Sep 17 00:00:00 2001 From: Zryte Date: Thu, 19 Sep 2024 17:04:41 +0700 Subject: [PATCH] AmityUIKit v4.0.0-beta21 --- .../AmityUIKit.xcodeproj/project.pbxproj | 30 +-- .../AmityUIKit4.xcodeproj/project.pbxproj | 152 +++++++++++- .../contents.xcworkspacedata | 4 + .../AmityUIKit4/Ads/Engine/AdEngine.swift | 4 +- .../AmityUIKit4/Ads/Supplier/AdSupplier.swift | 4 +- .../AmityUIKit4/AmityUIKitConfig.json | 13 + .../categoriesPlaceholder.imageset/Avatar.svg | 4 + .../Contents.json | 12 + .../Contents.json | 12 + .../noCommunitiesIcon.svg | 3 + .../Contents.json | 12 + .../Placeholder Image.svg | 10 + .../communityThumbnail.imageset/Contents.json | 12 + .../communityThumbnail.imageset/Thumbnail.svg | 21 ++ .../emptyStateExplore.imageset/Contents.json | 15 ++ .../Frame 481016.svg | 4 + .../tickIcon.imageset/Contents.json | 12 + .../tickIcon.imageset/tickIcon.svg | 3 + .../EmptyStates/AmityEmptyStateView.swift | 6 +- .../Core/CustomViews/AmityNavigationBar.swift | 141 +++++++++++ .../Localization/AmityLocalizable.strings | 11 + .../Core/Utilities/AccessibilityID.swift | 24 ++ .../Core/Utilities/AmityIcon.swift | 7 + .../Utilities/AmityLocalizedStringSet.swift | 11 + .../Utilities/Constants/AmityViewId.swift | 7 + .../Components/Ads/AmityAdInfoView.swift | 2 + .../PostDetail/PostContentSkeletonView.swift | 1 + .../Components/Search/CommunityCellView.swift | 5 +- .../Explore/AmityExplorePageContainer.swift | 126 ++++++++++ .../AmityCommunityCategoriesComponent.swift | 140 +++++++++++ .../CommunityCategoriesViewModel.swift | 117 +++++++++ .../CommunityCategoryModel.swift | 24 ++ ...AmityRecommendedCommunitiesComponent.swift | 106 +++++++++ .../RecommendedCommunityViewModel.swift | 94 ++++++++ .../AmityTrendingCommunitiesComponent.swift | 85 +++++++ .../TrendingCommunityViewModel.swift | 107 +++++++++ .../ExploreComponentEmptyStateView.swift | 88 +++++++ .../ExploreComponentSkeletonView.swift | 162 +++++++++++++ .../ExploreComponentsStateManager.swift | 66 ++++++ .../Categories/AmityAllCategoriesPage.swift | 104 ++++++++ .../AmityCommunitiesByCategoryPage.swift | 41 ++++ .../Views/CommunityListItemView.swift | 224 ++++++++++++++++++ .../Views/CommunityListView.swift | 117 +++++++++ .../AmityCommunityProfilePage.swift | 1 - .../AmityCommunitySetupPage.swift | 12 +- .../SocialHome/AmitySocialHomePage.swift | 2 +- .../ChildViews/SocialHomeContainerView.swift | 12 +- .../ChildViews/CommentSkeletonView.swift | 2 + .../Story/Models/AmityCommunityModel.swift | 7 +- .../project.pbxproj | 8 +- .../SampleApp.xcodeproj/project.pbxproj | 14 +- .../Endpoint Settings/EndpointsView.swift | 1 - .../SampleApp/Feature/LiveChatListView.swift | 2 + .../SampleApp/Manager/AppManager.swift | 6 +- UpstraUIKit/SharedFrameworks/Package.swift | 20 +- 55 files changed, 2148 insertions(+), 82 deletions(-) create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Avatar.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/noCommunitiesIcon.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Placeholder Image.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Thumbnail.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Frame 481016.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/Contents.json create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/tickIcon.svg create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/CustomViews/AmityNavigationBar.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/AmityExplorePageContainer.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/AmityCommunityCategoriesComponent.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoriesViewModel.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoryModel.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/AmityRecommendedCommunitiesComponent.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/RecommendedCommunityViewModel.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/AmityTrendingCommunitiesComponent.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/TrendingCommunityViewModel.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentEmptyStateView.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentSkeletonView.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentsStateManager.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/Categories/AmityAllCategoriesPage.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/AmityCommunitiesByCategoryPage.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListItemView.swift create mode 100644 UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListView.swift diff --git a/UpstraUIKit/AmityUIKit.xcodeproj/project.pbxproj b/UpstraUIKit/AmityUIKit.xcodeproj/project.pbxproj index f948f1e..b376c56 100644 --- a/UpstraUIKit/AmityUIKit.xcodeproj/project.pbxproj +++ b/UpstraUIKit/AmityUIKit.xcodeproj/project.pbxproj @@ -90,6 +90,7 @@ 68B30A7D2B70E38B006A4102 /* AmityStoryCommentSettingsScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68B30A762B70E38B006A4102 /* AmityStoryCommentSettingsScreenViewModel.swift */; }; 68B30A7E2B70E38B006A4102 /* AmityStoryCommentSettingsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68B30A782B70E38B006A4102 /* AmityStoryCommentSettingsItem.swift */; }; 68F0EE062BC6BBDF004B3AA4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 68F0EE052BC6BBDF004B3AA4 /* PrivacyInfo.xcprivacy */; }; + 68F5D9FA2B481E4000A9FA0D /* AmityUIKit4.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68F5D9F92B481E4000A9FA0D /* AmityUIKit4.framework */; }; 720D599A2525BDB1009734EF /* DispatchGroupWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 720D59992525BDB1009734EF /* DispatchGroupWrapper.swift */; }; 7211553E25505D180081CC23 /* AmityCategoryPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7211553C25505D180081CC23 /* AmityCategoryPickerViewController.swift */; }; 7211553F25505D180081CC23 /* AmityCategoryPickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7211553D25505D180081CC23 /* AmityCategoryPickerViewController.xib */; }; @@ -370,6 +371,7 @@ 78DA0324263C715C007C11CE /* AmityMyCommunityPreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 78DA0320263C715C007C11CE /* AmityMyCommunityPreviewViewController.xib */; }; 78DA0325263C715C007C11CE /* AmityMyCommunityPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78DA0321263C715C007C11CE /* AmityMyCommunityPreviewViewController.swift */; }; 921C3FCB2C379FDB00BF403E /* AmitySocialV4Compatible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921C3FCA2C379FDB00BF403E /* AmitySocialV4Compatible.swift */; }; + 925522522C9C2DF900AD85B5 /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = 925522512C9C2DF900AD85B5 /* SharedFrameworks */; }; 970E784726429FA500E5FCEE /* ChatSettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970E784526429FA500E5FCEE /* ChatSettingsTableViewCell.swift */; }; 970E784826429FA500E5FCEE /* ChatSettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 970E784626429FA500E5FCEE /* ChatSettingsTableViewCell.xib */; }; 970E784E26429FB300E5FCEE /* AmityChatSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970E784C26429FB300E5FCEE /* AmityChatSettingsViewController.swift */; }; @@ -503,9 +505,6 @@ A9E8910B29FBB1B200A22B35 /* AmityReactionUserSkeletonCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9E8910929FBB1B200A22B35 /* AmityReactionUserSkeletonCell.xib */; }; A9E891102A00CC0E00A22B35 /* AmityReactionPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E8910E2A00CC0E00A22B35 /* AmityReactionPageViewController.swift */; }; A9E891112A00CC0E00A22B35 /* AmityReactionPageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9E8910F2A00CC0E00A22B35 /* AmityReactionPageViewController.xib */; }; - A9F9272F2C94635C00AC8E9C /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = A9F9272E2C94635C00AC8E9C /* SharedFrameworks */; }; - A9F927312C9463C900AC8E9C /* AmityUIKit4.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9F927302C9463C900AC8E9C /* AmityUIKit4.framework */; }; - A9F927322C9463C900AC8E9C /* AmityUIKit4.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A9F927302C9463C900AC8E9C /* AmityUIKit4.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; B704D1432578CB2F0038BA78 /* AmityPulseAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B704D1422578CB2F0038BA78 /* AmityPulseAnimation.swift */; }; B704D1492578E23A0038BA78 /* AmityAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B704D1482578E23A0038BA78 /* AmityAudioPlayer.swift */; }; B704D14E2578E2570038BA78 /* AmityAudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B704D14D2578E2570038BA78 /* AmityAudioRecorder.swift */; }; @@ -673,20 +672,6 @@ }; /* End PBXContainerItemProxy section */ -/* Begin PBXCopyFilesBuildPhase section */ - A9F927332C9463CA00AC8E9C /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - A9F927322C9463C900AC8E9C /* AmityUIKit4.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ 0A7682C327B16D2200F6BA41 /* AmityMediaConverter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityMediaConverter.swift; sourceTree = ""; }; 0D123ECD25DA85DD009171D8 /* AmityCommentCreateController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityCommentCreateController.swift; sourceTree = ""; }; @@ -1192,7 +1177,6 @@ A9E8910929FBB1B200A22B35 /* AmityReactionUserSkeletonCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AmityReactionUserSkeletonCell.xib; sourceTree = ""; }; A9E8910E2A00CC0E00A22B35 /* AmityReactionPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityReactionPageViewController.swift; sourceTree = ""; }; A9E8910F2A00CC0E00A22B35 /* AmityReactionPageViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AmityReactionPageViewController.xib; sourceTree = ""; }; - A9F927302C9463C900AC8E9C /* AmityUIKit4.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AmityUIKit4.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B704D1422578CB2F0038BA78 /* AmityPulseAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityPulseAnimation.swift; sourceTree = ""; }; B704D1482578E23A0038BA78 /* AmityAudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityAudioPlayer.swift; sourceTree = ""; }; B704D14D2578E2570038BA78 /* AmityAudioRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityAudioRecorder.swift; sourceTree = ""; }; @@ -1356,8 +1340,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9F9272F2C94635C00AC8E9C /* SharedFrameworks in Frameworks */, - A9F927312C9463C900AC8E9C /* AmityUIKit4.framework in Frameworks */, + 925522522C9C2DF900AD85B5 /* SharedFrameworks in Frameworks */, + 68F5D9FA2B481E4000A9FA0D /* AmityUIKit4.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2085,7 +2069,6 @@ 72928FA524EA834A00BF566D /* Frameworks */ = { isa = PBXGroup; children = ( - A9F927302C9463C900AC8E9C /* AmityUIKit4.framework */, 68F5D9F92B481E4000A9FA0D /* AmityUIKit4.framework */, 6857F6C82B2AE15C00AC2914 /* AmityUIKit4.framework */, 68EF84A529B077CF00C7EDEC /* RealmSwift.xcframework */, @@ -4517,7 +4500,6 @@ 72A3502C24EA811500DA9D46 /* Sources */, 72A3502D24EA811500DA9D46 /* Frameworks */, 72A3502E24EA811500DA9D46 /* Resources */, - A9F927332C9463CA00AC8E9C /* Embed Frameworks */, ); buildRules = ( ); @@ -4525,7 +4507,7 @@ ); name = AmityUIKit; packageProductDependencies = ( - A9F9272E2C94635C00AC8E9C /* SharedFrameworks */, + 925522512C9C2DF900AD85B5 /* SharedFrameworks */, ); productName = UpstraUIKit; productReference = 72A3503024EA811500DA9D46 /* AmityUIKit.framework */; @@ -5541,7 +5523,7 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - A9F9272E2C94635C00AC8E9C /* SharedFrameworks */ = { + 925522512C9C2DF900AD85B5 /* SharedFrameworks */ = { isa = XCSwiftPackageProductDependency; productName = SharedFrameworks; }; diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.pbxproj b/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.pbxproj index dc0cd2a..3bb738b 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.pbxproj +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.pbxproj @@ -300,6 +300,7 @@ 68FF77DB2B81DEC900B8F561 /* AmityStoryTargetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68FF77DA2B81DEC900B8F561 /* AmityStoryTargetModel.swift */; }; 921C3FC92C379F3E00BF403E /* AmityPostContentComponentBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 921C3FC82C379F3E00BF403E /* AmityPostContentComponentBehavior.swift */; }; 9250CA2D2C2D55E9007551ED /* MultiSelectionMediaPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9250CA2C2C2D55E9007551ED /* MultiSelectionMediaPicker.swift */; }; + 925522502C9C2DF200AD85B5 /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = 9255224F2C9C2DF200AD85B5 /* SharedFrameworks */; }; 926894402C474A49004CECF8 /* AmityCommunityPinnedPostComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9268943F2C474A49004CECF8 /* AmityCommunityPinnedPostComponent.swift */; }; 926894422C474A6A004CECF8 /* EmptyCommunityFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 926894412C474A6A004CECF8 /* EmptyCommunityFeedView.swift */; }; 926F079C2BB4DDB9000806CB /* Shimmer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 926F079B2BB4DDB9000806CB /* Shimmer.swift */; }; @@ -420,9 +421,24 @@ A97A44422C3257770017327D /* AmityAdInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97A44412C3257770017327D /* AmityAdInfoView.swift */; }; A9AD73B32B8759F3009D6C19 /* ExpandableTextEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9AD73B22B8759F3009D6C19 /* ExpandableTextEditorView.swift */; }; A9AD73B52B886265009D6C19 /* AmityTextMessageEditPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9AD73B42B886265009D6C19 /* AmityTextMessageEditPreview.swift */; }; + A9CEB8102C7D993D0062823A /* AmityExplorePageContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB80F2C7D993D0062823A /* AmityExplorePageContainer.swift */; }; + A9CEB8132C7EDB930062823A /* AmityCommunityCategoriesComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8122C7EDB930062823A /* AmityCommunityCategoriesComponent.swift */; }; + A9CEB8152C7EE5AC0062823A /* CommunityCategoriesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8142C7EE5AB0062823A /* CommunityCategoriesViewModel.swift */; }; + A9CEB8172C7EE8AE0062823A /* AmityAllCategoriesPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8162C7EE8AE0062823A /* AmityAllCategoriesPage.swift */; }; + A9CEB8192C7EECF30062823A /* CommunityCategoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8182C7EECF30062823A /* CommunityCategoryModel.swift */; }; + A9CEB81B2C7F01CF0062823A /* CommunityListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB81A2C7F01CF0062823A /* CommunityListView.swift */; }; + A9CEB81E2C7F0BAB0062823A /* AmityRecommendedCommunitiesComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB81D2C7F0BAB0062823A /* AmityRecommendedCommunitiesComponent.swift */; }; + A9CEB8212C7F19A10062823A /* AmityTrendingCommunitiesComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8202C7F19A10062823A /* AmityTrendingCommunitiesComponent.swift */; }; + A9CEB8232C804EF20062823A /* ExploreComponentEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8222C804EF20062823A /* ExploreComponentEmptyStateView.swift */; }; + A9CEB8252C805BF80062823A /* ExploreComponentSkeletonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8242C805BF80062823A /* ExploreComponentSkeletonView.swift */; }; + A9CEB8272C85774F0062823A /* ExploreComponentsStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8262C85774F0062823A /* ExploreComponentsStateManager.swift */; }; + A9CEB82E2C885AC50062823A /* TrendingCommunityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB82D2C885AC50062823A /* TrendingCommunityViewModel.swift */; }; + A9CEB8302C885AE90062823A /* RecommendedCommunityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB82F2C885AE90062823A /* RecommendedCommunityViewModel.swift */; }; + A9CEB8362C88650D0062823A /* AmityCommunitiesByCategoryPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9CEB8352C88650D0062823A /* AmityCommunitiesByCategoryPage.swift */; }; + A9D034D32C8EC04B00909915 /* CommunityListItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D034D22C8EC04B00909915 /* CommunityListItemView.swift */; }; + A9D034D52C8ED3E200909915 /* AmityNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D034D42C8ED3E200909915 /* AmityNavigationBar.swift */; }; A9E286642BFF2C85007C5825 /* AmityLiveChatMessageQuickReaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E286632BFF2C85007C5825 /* AmityLiveChatMessageQuickReaction.swift */; }; A9F4EC102BB42FC5005FDDEA /* MentionTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9F4EC0F2BB42FC5005FDDEA /* MentionTextEditor.swift */; }; - A9F9272D2C94634A00AC8E9C /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = A9F9272C2C94634A00AC8E9C /* SharedFrameworks */; }; A9FF80E82BBD14660088A317 /* AmityLiveChatPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FF80E72BBD14660088A317 /* AmityLiveChatPageViewModel.swift */; }; A9FF80EB2BBD49C20088A317 /* AmityMessageListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FF80EA2BBD49C20088A317 /* AmityMessageListViewModel.swift */; }; ED08DC482BA2E8B4000DA797 /* AmityEmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED08DC472BA2E8B4000DA797 /* AmityEmptyStateView.swift */; }; @@ -867,6 +883,22 @@ A97A44412C3257770017327D /* AmityAdInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityAdInfoView.swift; sourceTree = ""; }; A9AD73B22B8759F3009D6C19 /* ExpandableTextEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableTextEditorView.swift; sourceTree = ""; }; A9AD73B42B886265009D6C19 /* AmityTextMessageEditPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityTextMessageEditPreview.swift; sourceTree = ""; }; + A9CEB80F2C7D993D0062823A /* AmityExplorePageContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityExplorePageContainer.swift; sourceTree = ""; }; + A9CEB8122C7EDB930062823A /* AmityCommunityCategoriesComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityCommunityCategoriesComponent.swift; sourceTree = ""; }; + A9CEB8142C7EE5AB0062823A /* CommunityCategoriesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityCategoriesViewModel.swift; sourceTree = ""; }; + A9CEB8162C7EE8AE0062823A /* AmityAllCategoriesPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityAllCategoriesPage.swift; sourceTree = ""; }; + A9CEB8182C7EECF30062823A /* CommunityCategoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityCategoryModel.swift; sourceTree = ""; }; + A9CEB81A2C7F01CF0062823A /* CommunityListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityListView.swift; sourceTree = ""; }; + A9CEB81D2C7F0BAB0062823A /* AmityRecommendedCommunitiesComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityRecommendedCommunitiesComponent.swift; sourceTree = ""; }; + A9CEB8202C7F19A10062823A /* AmityTrendingCommunitiesComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityTrendingCommunitiesComponent.swift; sourceTree = ""; }; + A9CEB8222C804EF20062823A /* ExploreComponentEmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreComponentEmptyStateView.swift; sourceTree = ""; }; + A9CEB8242C805BF80062823A /* ExploreComponentSkeletonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreComponentSkeletonView.swift; sourceTree = ""; }; + A9CEB8262C85774F0062823A /* ExploreComponentsStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreComponentsStateManager.swift; sourceTree = ""; }; + A9CEB82D2C885AC50062823A /* TrendingCommunityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingCommunityViewModel.swift; sourceTree = ""; }; + A9CEB82F2C885AE90062823A /* RecommendedCommunityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendedCommunityViewModel.swift; sourceTree = ""; }; + A9CEB8352C88650D0062823A /* AmityCommunitiesByCategoryPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityCommunitiesByCategoryPage.swift; sourceTree = ""; }; + A9D034D22C8EC04B00909915 /* CommunityListItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityListItemView.swift; sourceTree = ""; }; + A9D034D42C8ED3E200909915 /* AmityNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityNavigationBar.swift; sourceTree = ""; }; A9E286632BFF2C85007C5825 /* AmityLiveChatMessageQuickReaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AmityLiveChatMessageQuickReaction.swift; sourceTree = ""; }; A9F4EC0F2BB42FC5005FDDEA /* MentionTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionTextEditor.swift; sourceTree = ""; }; A9FF80E72BBD14660088A317 /* AmityLiveChatPageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmityLiveChatPageViewModel.swift; sourceTree = ""; }; @@ -881,7 +913,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9F9272D2C94634A00AC8E9C /* SharedFrameworks in Frameworks */, + 925522502C9C2DF200AD85B5 /* SharedFrameworks in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1690,6 +1722,7 @@ 68D4358E2B984889004482D7 /* AmityTextEditorView.swift */, 689EE6B92BF372E000927D51 /* AVPlayerView.swift */, 9250CA2C2C2D55E9007551ED /* MultiSelectionMediaPicker.swift */, + A9D034D42C8ED3E200909915 /* AmityNavigationBar.swift */, ); path = CustomViews; sourceTree = ""; @@ -1860,6 +1893,7 @@ 686198482C10490100BA81BE /* AmityPostMenuComponent.swift */, 689EE6B12BF1EA8900927D51 /* NewsFeed */, 689EE6B32BF1EAF100927D51 /* MyCommunities */, + A9CEB80E2C7D99240062823A /* Explore */, ); path = SocialHome; sourceTree = ""; @@ -2362,6 +2396,100 @@ path = Elements; sourceTree = ""; }; + A9CEB80E2C7D99240062823A /* Explore */ = { + isa = PBXGroup; + children = ( + A9CEB80F2C7D993D0062823A /* AmityExplorePageContainer.swift */, + A9CEB8262C85774F0062823A /* ExploreComponentsStateManager.swift */, + A9CEB8222C804EF20062823A /* ExploreComponentEmptyStateView.swift */, + A9CEB8242C805BF80062823A /* ExploreComponentSkeletonView.swift */, + A9D034CE2C8EBF6100909915 /* Pages */, + A9CEB8312C885B300062823A /* Components */, + A9CEB82C2C885A8A0062823A /* Elements */, + ); + path = Explore; + sourceTree = ""; + }; + A9CEB8112C7EDB700062823A /* CommunityCategories */ = { + isa = PBXGroup; + children = ( + A9CEB8122C7EDB930062823A /* AmityCommunityCategoriesComponent.swift */, + A9CEB8142C7EE5AB0062823A /* CommunityCategoriesViewModel.swift */, + A9CEB8182C7EECF30062823A /* CommunityCategoryModel.swift */, + ); + path = CommunityCategories; + sourceTree = ""; + }; + A9CEB81C2C7F0B860062823A /* RecommendedCommunities */ = { + isa = PBXGroup; + children = ( + A9CEB81D2C7F0BAB0062823A /* AmityRecommendedCommunitiesComponent.swift */, + A9CEB82F2C885AE90062823A /* RecommendedCommunityViewModel.swift */, + ); + path = RecommendedCommunities; + sourceTree = ""; + }; + A9CEB81F2C7F19950062823A /* TrendingCommunities */ = { + isa = PBXGroup; + children = ( + A9CEB8202C7F19A10062823A /* AmityTrendingCommunitiesComponent.swift */, + A9CEB82D2C885AC50062823A /* TrendingCommunityViewModel.swift */, + ); + path = TrendingCommunities; + sourceTree = ""; + }; + A9CEB82C2C885A8A0062823A /* Elements */ = { + isa = PBXGroup; + children = ( + ); + path = Elements; + sourceTree = ""; + }; + A9CEB8312C885B300062823A /* Components */ = { + isa = PBXGroup; + children = ( + A9CEB81F2C7F19950062823A /* TrendingCommunities */, + A9CEB81C2C7F0B860062823A /* RecommendedCommunities */, + A9CEB8112C7EDB700062823A /* CommunityCategories */, + ); + path = Components; + sourceTree = ""; + }; + A9D034CE2C8EBF6100909915 /* Pages */ = { + isa = PBXGroup; + children = ( + A9D034D02C8EBF6F00909915 /* CommunitiesByCategory */, + A9D034CF2C8EBF6A00909915 /* Categories */, + ); + path = Pages; + sourceTree = ""; + }; + A9D034CF2C8EBF6A00909915 /* Categories */ = { + isa = PBXGroup; + children = ( + A9CEB8162C7EE8AE0062823A /* AmityAllCategoriesPage.swift */, + ); + path = Categories; + sourceTree = ""; + }; + A9D034D02C8EBF6F00909915 /* CommunitiesByCategory */ = { + isa = PBXGroup; + children = ( + A9D034D12C8EC03D00909915 /* Views */, + A9CEB8352C88650D0062823A /* AmityCommunitiesByCategoryPage.swift */, + ); + path = CommunitiesByCategory; + sourceTree = ""; + }; + A9D034D12C8EC03D00909915 /* Views */ = { + isa = PBXGroup; + children = ( + A9CEB81A2C7F01CF0062823A /* CommunityListView.swift */, + A9D034D22C8EC04B00909915 /* CommunityListItemView.swift */, + ); + path = Views; + sourceTree = ""; + }; A9FF80E92BBD49AC0088A317 /* MessageList */ = { isa = PBXGroup; children = ( @@ -2428,7 +2556,7 @@ ); name = AmityUIKit4; packageProductDependencies = ( - A9F9272C2C94634A00AC8E9C /* SharedFrameworks */, + 9255224F2C9C2DF200AD85B5 /* SharedFrameworks */, ); productName = AmityUIKit4; productReference = 684AE0F12B0C5B0200FD7270 /* AmityUIKit4.framework */; @@ -2533,6 +2661,7 @@ 6861984C2C116AF900BA81BE /* AmityPostComposerPage.swift in Sources */, 689EE6A22BEDCB4E00927D51 /* PostManager.swift in Sources */, 68EE70C42C1AD40B005A7002 /* AmityMediaAttachmentViewModel.swift in Sources */, + A9CEB8212C7F19A10062823A /* AmityTrendingCommunitiesComponent.swift in Sources */, 68FF77CD2B81C4A300B8F561 /* SwipeDirection.swift in Sources */, 684AE1662B0F42C700FD7270 /* AmityTheme.swift in Sources */, 68EE70C62C1ADD77005A7002 /* FileRepositoryManager.swift in Sources */, @@ -2564,6 +2693,7 @@ A97A440D2C2D2D4D0017327D /* Resource.swift in Sources */, 685F16B92BFC84420016685F /* AmityCommunitySearchResultComponent.swift in Sources */, 689EE6A42BEDD07D00927D51 /* AmityGlobalFeedComponentBehavior.swift in Sources */, + A9CEB8252C805BF80062823A /* ExploreComponentSkeletonView.swift in Sources */, 68EB58A52B2C2CBD00F6F250 /* AmityCreateStoryPage.swift in Sources */, 685F16B12BFC722E0016685F /* AnimationViewModifiers.swift in Sources */, A91476EE2BB131300095BF50 /* AmityMessageTextEditorView.swift in Sources */, @@ -2576,6 +2706,7 @@ 6859F2282B3DE052004AEB8C /* GestureView.swift in Sources */, 68EE70C22C1816C2005A7002 /* AmityMyCommunitiesSearchPage.swift in Sources */, 684097DF2B30942F00697E1B /* PlainDatabase.swift in Sources */, + A9CEB8362C88650D0062823A /* AmityCommunitiesByCategoryPage.swift in Sources */, 6874B9562C3E7B8D0021D8D0 /* AmityUserSearchResultComponentBehavior.swift in Sources */, A97A441C2C2D2D4D0017327D /* ImageProgressive.swift in Sources */, 689EE6B72BF21A2500927D51 /* MediaViewer.swift in Sources */, @@ -2641,6 +2772,7 @@ 685CE26B2B62775D00AF8F54 /* ImpactFeedbackGenerator.swift in Sources */, 92EF987F2BC5F7D60029B420 /* AmityLiveChatMessageSenderView.swift in Sources */, 92F2B11A2BE4883C004CF86B /* AmityLiveChatMessageReactionPicker.swift in Sources */, + A9CEB8152C7EE5AC0062823A /* CommunityCategoriesViewModel.swift in Sources */, 683DF10A2C6B1CAD005BF06C /* AmityCommunityAddUserPage.swift in Sources */, 684097E52B30942F00697E1B /* Database.swift in Sources */, 684097E72B30942F00697E1B /* FileManager+Extensions.swift in Sources */, @@ -2681,6 +2813,7 @@ 684097B22B30942F00697E1B /* RemoteImage.swift in Sources */, 6840981B2B313A6F00697E1B /* AVPlayerItem+Extensions.swift in Sources */, 685F16BD2BFC96B30016685F /* AmityGlobalSearchViewModel.swift in Sources */, + A9CEB82E2C885AC50062823A /* TrendingCommunityViewModel.swift in Sources */, 684AE1212B0C5F2C00FD7270 /* AmityMessageMediaService.swift in Sources */, 68FF77CC2B81C4A300B8F561 /* SwipeInteractionArea.swift in Sources */, 684AE1592B0DEBC900FD7270 /* AmityPageView.swift in Sources */, @@ -2689,6 +2822,7 @@ 6877D3772C75C08F008B3598 /* NotificationManager.swift in Sources */, 6880E6BA2B28110600F25C75 /* AmityStoryModel.swift in Sources */, 688051E72B56962A00C9BBCB /* AmityLocalizedStringSet.swift in Sources */, + A9CEB81E2C7F0BAB0062823A /* AmityRecommendedCommunitiesComponent.swift in Sources */, 684097BB2B30942F00697E1B /* URLImageService+Decode.swift in Sources */, A97A44032C2D2D4D0017327D /* Storage.swift in Sources */, 6840981A2B313A6F00697E1B /* AVAssetResourceLoadingRequest+Extensions.swift in Sources */, @@ -2721,11 +2855,13 @@ 684097D42B30942F00697E1B /* Bundle+Extensions.swift in Sources */, 92891DE32BACE17100B5111E /* LiveChatMessageBubbleView.swift in Sources */, A97A44102C2D2D4D0017327D /* KFOptionsSetter.swift in Sources */, + A9CEB8192C7EECF30062823A /* CommunityCategoryModel.swift in Sources */, A97A441B2C2D2D4D0017327D /* ImageProcessor.swift in Sources */, A97A44202C2D2D4D0017327D /* ImageDataProcessor.swift in Sources */, 6877D39B2C7C3E6B008B3598 /* AmityCommunityPostPermissionPage.swift in Sources */, A97A44172C2D2D4D0017327D /* GraphicsContext.swift in Sources */, A97A44292C2D2D4D0017327D /* SessionDelegate.swift in Sources */, + A9CEB8132C7EDB930062823A /* AmityCommunityCategoriesComponent.swift in Sources */, A97A442B2C2D2D4D0017327D /* ImageContext.swift in Sources */, 680204662B88527D00CC0CD0 /* AccessibilityID.swift in Sources */, 68FF77C72B81C4A300B8F561 /* Pager.swift in Sources */, @@ -2779,6 +2915,7 @@ 6861984F2C11AA3B00BA81BE /* AmityMediaAttatchmentComponent.swift in Sources */, 685CE2892B68D08800AF8F54 /* AmityCommunityMember+Extension.swift in Sources */, 686D17402B149F63007AEF59 /* AmityIcon.swift in Sources */, + A9CEB8102C7D993D0062823A /* AmityExplorePageContainer.swift in Sources */, 685F16B42BFC76BD0016685F /* AmitySocialGlobalSearchPage.swift in Sources */, A96F20AA2BEB65290020D9C0 /* AmityReactionListViewModel.swift in Sources */, 684AE15B2B0DEC2900FD7270 /* AmityComponentView.swift in Sources */, @@ -2795,6 +2932,7 @@ 685F16CC2BFCD4970016685F /* BottomSheetViewModifier.swift in Sources */, 683DF10C2C6B27A4005BF06C /* AmityUserModel.swift in Sources */, 689EE6972BEB7F7500927D51 /* AmityMyCommunitiesComponent.swift in Sources */, + A9CEB8302C885AE90062823A /* RecommendedCommunityViewModel.swift in Sources */, 685F16AD2BFB20900016685F /* CommentBottomSheetView.swift in Sources */, 684AE1292B0C609000FD7270 /* UIApplication+Extension.swift in Sources */, 684097BE2B30942F00697E1B /* URLImageActivityIndicator.swift in Sources */, @@ -2842,6 +2980,7 @@ A93396DB2C1AB88600FC064E /* AdSupplier.swift in Sources */, 6840981D2B313A6F00697E1B /* Double+Extensions.swift in Sources */, A97A44332C2D2D4D0017327D /* Delegate.swift in Sources */, + A9D034D52C8ED3E200909915 /* AmityNavigationBar.swift in Sources */, 684097DE2B30942F00697E1B /* DownloadManager.swift in Sources */, A97A44362C2D2D4D0017327D /* Result.swift in Sources */, 6880E6BD2B2811A600F25C75 /* StoryManager.swift in Sources */, @@ -2879,6 +3018,8 @@ 685CE2692B625D7700AF8F54 /* ReactionManager.swift in Sources */, 684097BC2B30942F00697E1B /* URLImageService+RemoteImage.swift in Sources */, 6840982D2B313A6F00697E1B /* VideoFullscreenTransitioner.swift in Sources */, + A9D034D32C8EC04B00909915 /* CommunityListItemView.swift in Sources */, + A9CEB81B2C7F01CF0062823A /* CommunityListView.swift in Sources */, 685CE28D2B68EFB900AF8F54 /* Date+Extension.swift in Sources */, A93396D72C1AB84200FC064E /* AdEngine.swift in Sources */, 92CC82702C332C4B0000B523 /* AmityCommentAdComponent.swift in Sources */, @@ -2910,13 +3051,16 @@ A97A44192C2D2D4D0017327D /* ImageDrawing.swift in Sources */, 685CE2832B68B17F00AF8F54 /* CommentCoreView.swift in Sources */, A97A440F2C2D2D4D0017327D /* KF.swift in Sources */, + A9CEB8272C85774F0062823A /* ExploreComponentsStateManager.swift in Sources */, 68FF77D12B81C4A300B8F561 /* PagerContent+Helper.swift in Sources */, 684098192B313A6F00697E1B /* AVPlayer+Extensions.swift in Sources */, A97A442F2C2D2D4D0017327D /* KFImageProtocol.swift in Sources */, A955BA842C228B9300585C59 /* AdAsset.swift in Sources */, + A9CEB8172C7EE8AE0062823A /* AmityAllCategoriesPage.swift in Sources */, A97A44382C2D2D4D0017327D /* SizeExtensions.swift in Sources */, 68F0A1F62C7EFC020006B549 /* AmityCommunityCommentsNotificationSettingPage.swift in Sources */, 6840982B2B313A6F00697E1B /* VideoLoader.swift in Sources */, + A9CEB8232C804EF20062823A /* ExploreComponentEmptyStateView.swift in Sources */, A97188582B834F0500B1BCA2 /* MessageAvatarView.swift in Sources */, 68FB40912C3D5F16006C97CC /* AmitySocialHomePageBehavior.swift in Sources */, 684097D92B30942F00697E1B /* Utils.swift in Sources */, @@ -3215,7 +3359,7 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - A9F9272C2C94634A00AC8E9C /* SharedFrameworks */ = { + 9255224F2C9C2DF200AD85B5 /* SharedFrameworks */ = { isa = XCSwiftPackageProductDependency; productName = SharedFrameworks; }; diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..94b2795 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Engine/AdEngine.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Engine/AdEngine.swift index 500abe5..8ba5492 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Engine/AdEngine.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Engine/AdEngine.swift @@ -195,7 +195,7 @@ class AdEngine { let asset = realm.object(ofType: AdAsset.self, forPrimaryKey: assetId) if let asset { - Log.adAssets.debug("Is Asset Downloaded: \(assetId) \(asset.isDownloaded)") + // Log.adAssets.debug("Is Asset Downloaded: \(assetId) \(asset.isDownloaded)") return asset.isDownloaded } else { Log.adAssets.debug("Is Asset Downloaded: Error - Asset not found") @@ -211,7 +211,7 @@ class AdEngine { if let asset = realm.object(ofType: AdAsset.self, forPrimaryKey: id) { asset.isDownloaded = true - Log.adAssets.debug("Asset is ready: \(id)") + // Log.adAssets.debug("Asset is ready: \(id)") } else { Log.adAssets.debug("Asset is ready: \(id) Error - Asset not found") } diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Supplier/AdSupplier.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Supplier/AdSupplier.swift index 70c01e4..4efc7f1 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Supplier/AdSupplier.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Ads/Supplier/AdSupplier.swift @@ -91,8 +91,8 @@ class AdSupplier { let weightSum = weights.reduce(0, { $0 + $1 }) // Normalize Weights - var likelihoods = weights.map { $0 / weightSum } - var selectedAdIndex = weightedRandomChoice(weights: likelihoods) + let likelihoods = weights.map { $0 / weightSum } + let selectedAdIndex = weightedRandomChoice(weights: likelihoods) selectedAds.append(relevantAds[selectedAdIndex]) relevantAds.remove(at: selectedAdIndex) diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/AmityUIKitConfig.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/AmityUIKitConfig.json index 2f356ea..6c8b24f 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/AmityUIKitConfig.json +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/AmityUIKitConfig.json @@ -430,5 +430,18 @@ "text": "Attachment", "image": "attatchmentIcon" }, + "social_home_page/community_categories/*": {}, + "social_home_page/recommended_communities/*": {}, + "social_home_page/*/explore_empty_image": { + "image": "emptyExploreIcon" + }, + "social_home_page/*/explore_empty_title": { + }, + "social_home_page/*/explore_empty_description": { + }, + "social_home_page/*/explore_create_community": {}, + "social_home_page/trending_communities/*": {}, + "all_categories_page/*/*": {}, + "communities_by_category_page/*/*": {} } } diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Avatar.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Avatar.svg new file mode 100644 index 0000000..0a1a94e --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Avatar.svg @@ -0,0 +1,4 @@ + + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Contents.json new file mode 100644 index 0000000..e5ed0d7 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/categoriesPlaceholder.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Avatar.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/Contents.json new file mode 100644 index 0000000..7b9fb63 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "noCommunitiesIcon.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/noCommunitiesIcon.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/noCommunitiesIcon.svg new file mode 100644 index 0000000..31f1f35 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityNotFoundIcon.imageset/noCommunitiesIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Contents.json new file mode 100644 index 0000000..09dcb98 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Placeholder Image.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Placeholder Image.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Placeholder Image.svg new file mode 100644 index 0000000..f7ad05c --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityPlaceholder.imageset/Placeholder Image.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Contents.json new file mode 100644 index 0000000..877982a --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Thumbnail.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Thumbnail.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Thumbnail.svg new file mode 100644 index 0000000..8fc68fb --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/communityThumbnail.imageset/Thumbnail.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Contents.json new file mode 100644 index 0000000..6b35e9b --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Frame 481016.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Frame 481016.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Frame 481016.svg new file mode 100644 index 0000000..670f29d --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/emptyStateExplore.imageset/Frame 481016.svg @@ -0,0 +1,4 @@ + + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/Contents.json b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/Contents.json new file mode 100644 index 0000000..faf4a71 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tickIcon.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/tickIcon.svg b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/tickIcon.svg new file mode 100644 index 0000000..7f41317 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Assets.xcassets/tickIcon.imageset/tickIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Chat/Compnents/EmptyStates/AmityEmptyStateView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Chat/Compnents/EmptyStates/AmityEmptyStateView.swift index ce7dd26..7df935b 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Chat/Compnents/EmptyStates/AmityEmptyStateView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Chat/Compnents/EmptyStates/AmityEmptyStateView.swift @@ -21,7 +21,7 @@ public struct AmityEmptyStateView: View { VStack(spacing: 0) { if let icon = configuration.image { Image(ImageResource(name: icon, bundle: AmityUIKit4Manager.bundle)) - .renderingMode(.template) + .renderingMode(configuration.renderingMode) .resizable() .scaledToFit() .frame(size: configuration.iconSize) @@ -58,13 +58,15 @@ public struct AmityEmptyStateView: View { public let subtitle: String? public let tapAction: DefaultTapAction? public let iconSize: CGSize + public let renderingMode: Image.TemplateRenderingMode - public init(image: String?, title: String?, subtitle: String?, iconSize: CGSize = CGSize(width: 28, height: 24), tapAction: DefaultTapAction?) { + public init(image: String?, title: String?, subtitle: String?, iconSize: CGSize = CGSize(width: 28, height: 24), renderingMode: Image.TemplateRenderingMode = .template, tapAction: DefaultTapAction?) { self.image = image self.title = title self.subtitle = subtitle self.tapAction = tapAction self.iconSize = iconSize + self.renderingMode = renderingMode } internal static let previewWithoutTitle = Configuration(image: AmityIcon.Chat.emptyStateMessage.rawValue, title: nil, subtitle: "Couldn't load chat", tapAction: nil) diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/CustomViews/AmityNavigationBar.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/CustomViews/AmityNavigationBar.swift new file mode 100644 index 0000000..9b02129 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/CustomViews/AmityNavigationBar.swift @@ -0,0 +1,141 @@ +// +// AmityNavigationBar.swift +// AmityUIKit4 +// +// Created by Nishan on 9/9/2567 BE. +// + +import SwiftUI + +struct AmityNavigationBar: View { + + // Inherited from parent + @EnvironmentObject var host: AmitySwiftUIHostWrapper + @EnvironmentObject var viewConfig: AmityViewConfigController + + let title: String + let isBackButtonEnabled: Bool + let trailingView: AnyView? + let leadingView: AnyView? + + init(title: String) { + self.title = title + self.trailingView = nil + self.leadingView = nil + self.isBackButtonEnabled = false + } + + init(title: String, showBackButton: Bool) { + self.title = title + self.isBackButtonEnabled = showBackButton + self.leadingView = nil + self.trailingView = nil + } + + init(title: String, showBackButton: Bool, @ViewBuilder trailing: () -> TrailingView) { + self.title = title + self.isBackButtonEnabled = showBackButton + self.leadingView = nil + self.trailingView = AnyView(trailing()) + } + + init(title: String, @ViewBuilder leading: () -> LeadingView, @ViewBuilder trailing: () -> TrailingView) { + self.title = title + self.leadingView = AnyView(leading()) + self.trailingView = AnyView(trailing()) + self.isBackButtonEnabled = false + } + + var body: some View { + HStack(spacing: 0) { + HStack { + if let leadingView { + leadingView + } else if isBackButtonEnabled { + BackButton() + } + + Spacer() + } + .layoutPriority(1) + .frame(maxWidth: .infinity) + + Text(title) + .font(.system(size: 17, weight: .semibold)) + .padding(.horizontal, 8) + .lineLimit(1) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .layoutPriority(2) + + HStack { + Spacer() + + if let trailingView { + trailingView + .padding(.trailing, 8) + } + } + .layoutPriority(1) + .frame(maxWidth: .infinity) + } + .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)) + .frame(minHeight: 55) // Investigate why existing nav bar is of height 55 instead of 44 + .background(Color(viewConfig.theme.backgroundColor)) + } + + struct BackButton: View { + + @EnvironmentObject var host: AmitySwiftUIHostWrapper + @EnvironmentObject var viewConfig: AmityViewConfigController + + var body: some View { + let backIcon = AmityIcon.getImageResource(named: viewConfig.getConfig(elementId: .backButtonElement, key: "icon", of: String.self) ?? "backIcon") + Image(backIcon) + .resizable() + .renderingMode(.template) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .aspectRatio(contentMode: .fit) + .frame(width: 24, height: 20) + .onTapGesture { + host.controller?.navigationController?.popViewController(animated: true) + } + .isHidden(viewConfig.isHidden(elementId: .backButtonElement)) + .padding(.horizontal, 8) // We add padding here to increase tappable area + .padding(.vertical, 8) + } + } +} + +#if DEBUG +#Preview { + ZStack(alignment: .top) { + Color.green.opacity(0.1) + + VStack { + AmityNavigationBar(title: "My Page") + + AmityNavigationBar(title: "My Page", showBackButton: true) + + AmityNavigationBar(title: "My Page", showBackButton: true) { + HStack { + Image(systemName: "leaf.fill") + + Image(systemName: "cloud.fill") + } + } + + AmityNavigationBar(title: "My Page") { + Image(systemName: "leaf.fill") + .padding(6) + } trailing: { + HStack { + Image(systemName: "leaf.fill") + + Image(systemName: "cloud.fill") + } + } + } + } + .environmentObject(AmityViewConfigController(pageId: .socialHomePage)) +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Localization/AmityLocalizable.strings b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Localization/AmityLocalizable.strings index 1a45b22..0f2466a 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Localization/AmityLocalizable.strings +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Localization/AmityLocalizable.strings @@ -118,6 +118,7 @@ "create_post_bottom_sheet_title" = "Post"; "create_story_bottom_sheet_title" = "Story"; "community_page_join_title" = "Join"; +"community_page_joined_title" = "Joined"; "community_page_pending_post_title" = "Pending post"; "non_member_react_post_message" = "Join community to interact with all posts"; @@ -188,3 +189,13 @@ "community_notification_setting_story_reaction_Description" = "Receive notifications when someone reacts to your story in this community."; "community_notification_setting_story_comment_title" = "Story comments"; "community_notification_setting_story_comment_description" = "Receive notifications when someone comments on your story in this community."; + +"community_member_count_singular" = "%@ member"; +"community_member_count_plural" = "%@ members"; + +"explore_categories_see_more" = "See More"; +"explore_trending_now_component_title" = "Trending Now"; +"explore_recommended_communities_component_title" = "Recommended for you"; + +"community_all_categories_title" = "All Categories"; +"community_list_empty_state_title" = "No community yet"; diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AccessibilityID.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AccessibilityID.swift index ea054c1..78aeb3a 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AccessibilityID.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AccessibilityID.swift @@ -186,6 +186,30 @@ struct AccessibilityID { static let reactionImageView = "reaction_list/reaction_image_view" } } + + struct Social { + + struct CategoryList { + static let categoryImage = "community_row_image" + static let communityName = "community_row_name" + } + + struct Explore { + static let emptyStateImage = "explore_empty_image" + static let emptyStateText = "explore_empty_text" + static let emptyStateCreateCommunity = "explore_create_community" + + + static let recommendedSection = "recommended_communities" + static let categoriesSection = "community_categories" + static let trendingSection = "trending_communities" + + static let communityJoinButton = "community_card_join_button" + static let communityMemberCount = "community_card_member_count" + static let communityCategories = "community_card_categories" + static let communityImage = "community_card_image" + } + } } diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityIcon.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityIcon.swift index 0f5e92b..ab3eb37 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityIcon.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityIcon.swift @@ -129,6 +129,13 @@ enum AmityIcon: String, ImageResourceProvider { case communityPinBadge = "communityPinBadge" case communityProfileEmptyPostIcon = "communityProfileEmptyPostIcon" case communityPendingPostIcon = "communityPendingPostIcon" + case tickIcon = "tickIcon" + case communityCategoryPlaceholder = "categoriesPlaceholder" + case communityPlaceholder = "communityPlaceholder" + case communityThumbnail = "communityThumbnail" + case emptyStateExplore = "emptyStateExplore" + case communityNotFoundIcon = "communityNotFoundIcon" + case brandBadge = "brandBadgeIcon" case globeIcon = "globeIcon" case checkboxIcon = "checkBoxIcon" diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityLocalizedStringSet.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityLocalizedStringSet.swift index c9e87d7..253991f 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityLocalizedStringSet.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/AmityLocalizedStringSet.swift @@ -136,6 +136,7 @@ public struct AmityLocalizedStringSet { static let createPostBottomSheetTitle = "create_post_bottom_sheet_title" static let createStoryBottomSheetTitle = "create_story_bottom_sheet_title" static let communityPageJoinTitle = "community_page_join_title" + static let communityPageJoinedTitle = "community_page_joined_title" static let communityPagePendingPostTitle = "community_page_pending_post_title" static let nonMemberReactPostMessage = "non_member_react_post_message" static let communitySetupAlertTitle = "community_setup_alert_title" @@ -196,6 +197,16 @@ public struct AmityLocalizedStringSet { static let communityNotificationSettingStoryReactionDescription = "community_notification_setting_story_reaction_Description" static let communityNotificationSettingStoryCommentTitle = "community_notification_setting_story_comment_title" static let communityNotificationSettingStoryCommentDescription = "community_notification_setting_story_comment_description" + + static let communityMemberCountSingular = "community_member_count_singular" + static let communityMemberCountPlural = "community_member_count_plural" + + static let exploreCategoriesSeeMore = "explore_categories_see_more" + static let exploreTrendingComponentTitle = "explore_trending_now_component_title" + static let exploreRecommendedComponentTitle = "explore_recommended_communities_component_title" + + static let communityAllCategoriesPageTitle = "community_all_categories_title" + static let communityEmptyStateTitle = "community_list_empty_state_title" } } diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/Constants/AmityViewId.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/Constants/AmityViewId.swift index 40b24d8..254f6f0 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/Constants/AmityViewId.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Core/Utilities/Constants/AmityViewId.swift @@ -26,6 +26,7 @@ public enum PageId: String { case myCommunitiesSearchPage = "my_communities_search_page" case communityProfilePage = "community_profile_page" + case communitySetupPage = "community_setup_page" case communityAddCategoryPage = "community_add_category_page" case communityAddUserPage = "community_add_user_page" @@ -37,6 +38,9 @@ public enum PageId: String { case communityPostsNotificationSettingPage = "community_posts_notification_page" case communityCommentsNotificationSettingPage = "community_comments_notification_page" case communityPendingPostPage = "pending_posts_page" + + case communitiesByCategoryPage = "communities_by_category_page" + case allCategories = "all_categories_page" } public enum ComponentId: String { @@ -69,6 +73,9 @@ public enum ComponentId: String { case mediaAttachment = "media_attachment" case detailedMediaAttachment = "detailed_media_attachment" + case recommendedCommunities = "recommended_communities" + case trendingCommunities = "trending_communities" + case communityCategories = "community_categories" } public enum ElementId: String { diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Ads/AmityAdInfoView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Ads/AmityAdInfoView.swift index d2f31f9..8d1af22 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Ads/AmityAdInfoView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Ads/AmityAdInfoView.swift @@ -76,7 +76,9 @@ struct AmityAdInfoView: View { } } +#if DEBUG #Preview { AmityAdInfoView(advertiserName: "Nishan") .environmentObject(AmityViewConfigController(pageId: nil, componentId: .postContentComponent)) } +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/PostDetail/PostContentSkeletonView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/PostDetail/PostContentSkeletonView.swift index bcac157..e4d2786 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/PostDetail/PostContentSkeletonView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/PostDetail/PostContentSkeletonView.swift @@ -80,5 +80,6 @@ struct PostContentSkeletonView: View { #if DEBUG #Preview { PostContentSkeletonView() + .environmentObject(AmityViewConfigController(pageId: .communityProfilePage)) } #endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Search/CommunityCellView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Search/CommunityCellView.swift index e2fe9cb..5bd6e69 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Search/CommunityCellView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/Search/CommunityCellView.swift @@ -28,9 +28,10 @@ struct CommunityCellView: View { private func getCommunityView(_ model: AmityCommunityModel) -> some View { HStack(spacing: 16) { - AsyncImage(placeholder: AmityIcon.defaultCommunity.getImageResource(), url: URL(string: model.avatarURL)) + AsyncImage(placeholder: AmityIcon.communityThumbnail.imageResource, url: URL(string: model.avatarURL)) .frame(size: CGSize(width: 64, height: 64)) - .clipShape(Circle()) + .clipped() + .cornerRadius(8, corners: .allCorners) .isHidden(viewConfig.isHidden(elementId: .communityAvatar)) VStack(alignment: .leading, spacing: 8) { diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/AmityExplorePageContainer.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/AmityExplorePageContainer.swift new file mode 100644 index 0000000..6d07152 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/AmityExplorePageContainer.swift @@ -0,0 +1,126 @@ +// +// AmityExplorePageContainer.swift +// AmityUIKit4 +// +// Created by Nishan on 27/8/2567 BE. +// + +import SwiftUI +import AmitySDK + +// This page acts as a container & is not public by default. +struct AmityExplorePageContainer: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + @EnvironmentObject private var host: AmitySwiftUIHostWrapper + + @State private var isRefreshing = false + let pullToRefreshThreshold: CGFloat = 70 + + @StateObject var stateManager = ExploreComponentsStateManager.shared + + var body: some View { + ScrollView(.vertical, showsIndicators: false) { + ZStack(alignment: .top) { + GeometryReader { geometry in + + Color.clear + .frame(height: UIScreen.main.bounds.height * 0.5) + .onChange(of: geometry.frame(in: .named("scrollview")).origin.y) { newValue in + + // Amount scrollview is scrolled, + let scrollViewOffset = newValue + if scrollViewOffset > pullToRefreshThreshold && !isRefreshing { + isRefreshing = true + + Task { @MainActor in + // Refresh here + await refreshData() + + isRefreshing = false + } + } + } + } + + ProgressView() + .frame(width: isRefreshing ? 20 : 0, height: isRefreshing ? 20 : 0) + .scaleEffect(isRefreshing ? 1 : 0) + .padding(.bottom, isRefreshing ? 8 : 0) + .opacity(isRefreshing ? 1 : 0) + .animation(.easeIn, value: isRefreshing) + + VStack(alignment: .center, spacing: 0) { + Rectangle() + .fill(Color(viewConfig.theme.baseColorShade4)) + .frame(height: 8) + + if stateManager.isCategoriesVisible { + AmityCommunityCategoriesComponent() + .padding(.vertical, 14) + .accessibilityIdentifier(AccessibilityID.Social.Explore.categoriesSection) + } + + if stateManager.isRecommendedCommunitiesVisible { + AmityRecommendedCommunitiesComponent() + .accessibilityIdentifier(AccessibilityID.Social.Explore.recommendedSection) + .padding(.top, stateManager.isCategoriesVisible ? 0 : 16) + } + + if stateManager.isTrendingCommunitiesVisible { + AmityTrendingCommunitiesComponent() + .accessibilityIdentifier(AccessibilityID.Social.Explore.trendingSection) + .padding(.top, stateManager.isRecommendedCommunitiesVisible || !stateManager.isCategoriesVisible ? 16 : 0) + .padding(.bottom, 8) + } + } + .padding(.top, isRefreshing ? 36 : 0) + .animation(.linear, value: isRefreshing) + + emptyState + .opacity(stateManager.isNoCommunitiesAvailable || stateManager.isErrorInFetchingCommunities ? 1 : 0) + } + } + .coordinateSpace(name: "scrollview") + } + + private func openCommunitySetupPage() { + let page = AmityCommunitySetupPage(mode: .create) + let vc = AmitySwiftUIHostingController(rootView: page) + host.controller?.navigationController?.pushViewController(vc, animation: .presentation) + } + + @ViewBuilder + var emptyState: some View { + ZStack { + Color.clear + .frame(height: UIScreen.main.bounds.height * 0.7) + + VStack { + Spacer() + + let emptyStateType: ExploreComponentEmptyStateView.StateType = stateManager.isNoCommunitiesAvailable ? .communitiesNotAvailable : .unableToLoad + ExploreComponentEmptyStateView(type: emptyStateType, action: { + openCommunitySetupPage() + }) + + Spacer() + Spacer() + } + } + } + + func refreshData() async { + ExploreComponentsStateManager.shared.refreshAllComponents() + + let minRefreshSeconds: UInt64 = 3 * 1_000_000_000 + try? await Task.sleep(nanoseconds: minRefreshSeconds) + } +} + +#if DEBUG +#Preview { + AmityExplorePageContainer() + .environmentObject(AmityViewConfigController(pageId: .socialHomePage)) +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/AmityCommunityCategoriesComponent.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/AmityCommunityCategoriesComponent.swift new file mode 100644 index 0000000..4702dd1 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/AmityCommunityCategoriesComponent.swift @@ -0,0 +1,140 @@ +// +// AmityCommunityCategoriesComponent.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI + +public struct AmityCommunityCategoriesComponent: AmityComponentView { + + public var pageId: PageId? + + public var id: ComponentId { + return .communityCategories + } + + @EnvironmentObject public var host: AmitySwiftUIHostWrapper + @StateObject private var viewConfig: AmityViewConfigController + @StateObject private var viewModel = CommunityCategoriesViewModel(limit: 5) + + private let maxCategoriesCount: Int = 5 + + public init(pageId: PageId? = .socialHomePage) { + self.pageId = pageId + self._viewConfig = StateObject(wrappedValue: AmityViewConfigController(pageId: pageId, componentId: .communityCategories)) + } + + public var body: some View { + ZStack(alignment: .top) { + ExploreCategorySkeletonView() + .opacity(viewModel.categories.isEmpty && viewModel.queryState == .loading ? 1 : 0) + + content + .opacity(viewModel.categories.isEmpty ? 0 : 1) + } + .onAppear { + viewModel.observeState() + viewModel.fetchCategories(limit: 5) + } + .onDisappear { + viewModel.unObserveState() + } + .updateTheme(with: viewConfig) + } + + @ViewBuilder + var content: some View { + ScrollView(.horizontal, showsIndicators: false) { + HStack { + ForEach(viewModel.categories) { item in + CategoryLabel(category: item) { + let communityListView = AmityCommunitiesByCategoryPage(categoryId: item.id) + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: communityListView), animated: true) + } + } + + if viewModel.loadedCategoriesCount > maxCategoriesCount { + MoreLabel { + let allCategoriesView = AmityAllCategoriesPage() + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: allCategoriesView), animated: true) + } + } + } + .padding(.top, 4) + } + .padding(.horizontal) + } +} + +struct CategoryLabel: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + let category: CommunityCategoryModel + let tapAction: DefaultTapAction + + var body: some View { + Button(action: { + tapAction() + }, label: { + HStack(spacing: 0) { + AsyncImage(placeholder: AmityIcon.communityCategoryPlaceholder.imageResource, url: category.avatarURL) + .scaledToFill() + .clipped() + .frame(width: 28, height: 28) + .cornerRadius(14, corners: .allCorners) + + Text(category.name) + .font(.system(size: 15, weight: .medium)) + .padding(.horizontal, 8) + } + .padding(4) + .frame(minHeight: 36) + .overlay( + RoundedCorner() + .stroke(Color(viewConfig.theme.baseColorShade4), lineWidth: 1) + ) + }) + .buttonStyle(.plain) + } +} + +struct MoreLabel: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + let tapAction: DefaultTapAction + + var body: some View { + Button(action: { + tapAction() + }, label: { + HStack(spacing: 0) { + Text(AmityLocalizedStringSet.Social.exploreCategoriesSeeMore.localizedString) + .font(.system(size: 15, weight: .medium)) + .padding(.horizontal, 8) + + Image(systemName: "chevron.right") + .resizable() + .scaledToFit() + .frame(width: 12, height: 12) + .padding(.trailing, 8) + } + .padding(4) + .frame(minHeight: 36) + .overlay( + RoundedCorner() + .stroke(Color(viewConfig.theme.baseColorShade4), lineWidth: 1) + ) + }) + .buttonStyle(.plain) + } +} + +#if DEBUG +#Preview { + AmityCommunityCategoriesComponent() +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoriesViewModel.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoriesViewModel.swift new file mode 100644 index 0000000..ef783a6 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoriesViewModel.swift @@ -0,0 +1,117 @@ +// +// CommunityCategoriesViewModel.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI +import AmitySDK +import Combine + +enum QueryState { + case idle + case loading + case loaded + case error +} + +class CommunityCategoriesViewModel: ObservableObject { + + private let commRepo: AmityCommunityRepository = .init(client: AmityUIKitManagerInternal.shared.client) + + private var token: AmityNotificationToken? + private var categoryCollection: AmityCollection? + + @Published var categories: [CommunityCategoryModel] = [] + @Published var queryState: QueryState = .idle + + var queryStateObserver: AnyCancellable? + var refreshStateObserver: AnyCancellable? + var limit: Int? + + init(limit: Int? = nil) { + self.limit = limit + } + + var loadedCategoriesCount: Int { + return categoryCollection?.count() ?? 0 + } + + func fetchCategories(limit: Int? = nil) { + Log.add(event: .info, "Fetch categories called...") + guard queryState != .loading else { return } + + queryState = .loading + + categoryCollection = commRepo.getCategories(sortBy: .displayName, includeDeleted: false) + token = categoryCollection?.observe { [weak self] liveCollection, _, error in + guard let self else { return } + + if let error { + self.queryState = .error + self.token?.invalidate() + self.categoryCollection = nil + self.unObserveState() + return + } + + if let limit, limit > 0 { + let items = Array(liveCollection.snapshots.prefix(limit)).map { CommunityCategoryModel(model: $0) } + self.categories = items + } else { + let items = liveCollection.snapshots.map { CommunityCategoryModel(model: $0) } + self.categories = items + } + + self.queryState = .loaded + } + } + + func loadNextPage() { + guard let categoryCollection, categoryCollection.hasNext, queryState != .loading else { return } + + queryState = .loading + + categoryCollection.nextPage() + } + + func observeState() { + refreshStateObserver = ExploreComponentsStateManager.shared.$categoriesState + .receive(on: DispatchQueue.main) + .sink { [weak self] state in + guard let self else { return } + + switch state { + case .refreshing: + self.fetchCategories(limit: self.limit) + default: + break + } + } + + queryStateObserver = $queryState + .receive(on: DispatchQueue.main) + .sink { state in + switch state { + case .error: + ExploreComponentsStateManager.shared.categoriesState = .error + case .idle: + ExploreComponentsStateManager.shared.categoriesState = .initial + case .loaded: + if self.categories.isEmpty { + ExploreComponentsStateManager.shared.categoriesState = .dataEmpty + } else { + ExploreComponentsStateManager.shared.categoriesState = .dataAvailable + } + case .loading: + ExploreComponentsStateManager.shared.categoriesState = .loading + } + } + } + + func unObserveState() { + queryStateObserver = nil + refreshStateObserver = nil + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoryModel.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoryModel.swift new file mode 100644 index 0000000..60649ba --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/CommunityCategories/CommunityCategoryModel.swift @@ -0,0 +1,24 @@ +// +// CommunityCategoryModel.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI +import AmitySDK + +struct CommunityCategoryModel: Identifiable { + + let id: String + let name: String + let avatar: AmityImageData? + let avatarURL: URL? + + init(model: AmityCommunityCategory) { + self.id = model.categoryId + self.name = model.name + self.avatar = model.avatar + self.avatarURL = URL(string: model.avatar?.fileURL ?? "") + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/AmityRecommendedCommunitiesComponent.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/AmityRecommendedCommunitiesComponent.swift new file mode 100644 index 0000000..b3cef5a --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/AmityRecommendedCommunitiesComponent.swift @@ -0,0 +1,106 @@ +// +// AmityRecommendedCommunitiesComponent.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI +import AmitySDK +import Combine + +public struct AmityRecommendedCommunitiesComponent: AmityComponentView { + + public var pageId: PageId? + + public var id: ComponentId { + return .recommendedCommunities + } + + @EnvironmentObject public var host: AmitySwiftUIHostWrapper + + @StateObject private var viewConfig: AmityViewConfigController + @StateObject private var viewModel = RecommendedCommunityViewModel() + + public init(pageId: PageId? = .socialHomePage) { + self.pageId = pageId + self._viewConfig = StateObject(wrappedValue: AmityViewConfigController(pageId: pageId, componentId: .recommendedCommunities)) + } + + public var body: some View { + ZStack(alignment: .top) { + if viewModel.communities.isEmpty && viewModel.queryState == .loading { + ExploreRecommendedSkeletonView() + } + + content + .opacity(viewModel.communities.isEmpty ? 0 : 1) + } + .onAppear { + viewModel.observeState() + viewModel.fetchCommunities(limit: 4) + } + .onDisappear { + viewModel.unObserveState() + } + .updateTheme(with: viewConfig) + } + + @ViewBuilder + var content: some View { + VStack(alignment: .leading, spacing: 0) { + Text(AmityLocalizedStringSet.Social.exploreRecommendedComponentTitle.localizedString) + .font(.system(size: 17, weight: .semibold)) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .padding(.bottom, 16) + + ScrollView(.horizontal, showsIndicators: false) { + VStack(spacing: 0) { + LazyHStack(spacing: 0) { + ForEach(viewModel.communities) { community in + RecommendedCommunityView(community: community) + .onTapGesture { + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: AmityCommunityProfilePage(communityId: community.communityId)), animated: true) + } + .padding(.leading, 8) + } + } + .frame(height: 222) + } + } + } + .padding(.horizontal) + } +} + +struct RecommendedCommunityView: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + let community: AmityCommunityModel + + var body: some View { + VStack(alignment: .leading, spacing: 0) { + AsyncImage(placeholder: AmityIcon.communityPlaceholder.imageResource, url: URL(string: community.avatarURL), contentMode: .fill) + .frame(height: 125) + + CommunityInfoView(community: community) + .padding(10) + + Spacer() + } + .frame(width: 270) + .frame(height: 220) + .overlay( + RoundedRectangle(cornerRadius: 8, style: .continuous) + .stroke(Color(viewConfig.theme.baseColorShade4), lineWidth: 1) + ) + .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous)) + } +} + +#if DEBUG +#Preview { + AmityRecommendedCommunitiesComponent() +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/RecommendedCommunityViewModel.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/RecommendedCommunityViewModel.swift new file mode 100644 index 0000000..63c3eb3 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/RecommendedCommunities/RecommendedCommunityViewModel.swift @@ -0,0 +1,94 @@ +// +// RecommendedCommunityViewModel.swift +// AmityUIKit4 +// +// Created by Nishan on 4/9/2567 BE. +// + +import SwiftUI +import AmitySDK +import Combine + +class RecommendedCommunityViewModel: ObservableObject { + + private let repository: AmityCommunityRepository = .init(client: AmityUIKit4Manager.client) + private var token: AmityNotificationToken? + private var communityCollection: AmityCollection? + + @Published var communities: [AmityCommunityModel] = [] + @Published var queryState: QueryState = .idle + + var queryStateObserver: AnyCancellable? + var refreshStateObserver: AnyCancellable? + + func fetchCommunities(limit: Int? = 4) { + guard queryState != .loading else { return } + + queryState = .loading + + communityCollection = repository.getRecommendedCommunities() + token = communityCollection?.observe { [weak self] liveCollection, _, error in + guard let self else { return } + + if let error { + self.queryState = .error + self.token?.invalidate() + self.communityCollection = nil + self.unObserveState() + return + } + + if let limit, limit > 0 { + let notJoinedCommunities = liveCollection.snapshots.filter { !$0.isJoined } + let items = Array(notJoinedCommunities.prefix(limit).map { AmityCommunityModel(object: $0)} ) + self.communities = items + } else { + let items = liveCollection.snapshots.map { + AmityCommunityModel(object: $0) + } + self.communities = items + } + + self.queryState = .loaded + } + } + + func observeState() { + refreshStateObserver = ExploreComponentsStateManager.shared.$recommendedCommunitiesState + .receive(on: DispatchQueue.main) + .sink { [weak self] state in + guard let self else { return } + + switch state { + case .refreshing: + self.fetchCommunities() + default: + break + } + } + + queryStateObserver = $queryState + .receive(on: DispatchQueue.main) + .sink { state in + switch state { + case .error: + ExploreComponentsStateManager.shared.recommendedCommunitiesState = .error + case .idle: + ExploreComponentsStateManager.shared.recommendedCommunitiesState = .initial + case .loaded: + if self.communities.isEmpty { + ExploreComponentsStateManager.shared.recommendedCommunitiesState = .dataEmpty + } else { + ExploreComponentsStateManager.shared.recommendedCommunitiesState = .dataAvailable + } + case .loading: + ExploreComponentsStateManager.shared.recommendedCommunitiesState = .loading + } + } + } + + func unObserveState() { + queryStateObserver = nil + refreshStateObserver = nil + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/AmityTrendingCommunitiesComponent.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/AmityTrendingCommunitiesComponent.swift new file mode 100644 index 0000000..1342a5d --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/AmityTrendingCommunitiesComponent.swift @@ -0,0 +1,85 @@ +// +// TrendingCommunitiesComponent.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI +import AmitySDK +import Combine + +public struct AmityTrendingCommunitiesComponent: AmityComponentView { + + @EnvironmentObject public var host: AmitySwiftUIHostWrapper + + @StateObject var viewConfig: AmityViewConfigController + @StateObject var viewModel = TrendingCommunityViewModel() + + public var pageId: PageId? + public var id: ComponentId { + return .trendingCommunities + } + + public init(pageId: PageId? = .socialHomePage) { + self.pageId = pageId + self._viewConfig = StateObject(wrappedValue: AmityViewConfigController(pageId: pageId, componentId: .trendingCommunities)) + } + + public var body: some View { + ZStack(alignment: .top) { + ExploreTrendingSkeletonView() + .opacity(viewModel.communities.isEmpty && viewModel.queryState == .loading ? 1 : 0) + + content + .opacity(viewModel.communities.isEmpty ? 0 : 1) + + } + .onAppear(perform: { + viewModel.observeState() + viewModel.fetchCommunities(limit: 5) + }) + .updateTheme(with: viewConfig) + .onDisappear { + viewModel.unObserveState() + } + } + + @ViewBuilder + var content: some View { + LazyVStack(alignment: .leading, spacing: 0) { + Text(AmityLocalizedStringSet.Social.exploreTrendingComponentTitle.localizedString) + .font(.system(size: 17, weight: .semibold)) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .padding(.bottom, 16) + + ForEach(Array(viewModel.communities.enumerated()), id: \.element.id) { index, community in + VStack(spacing: 0) { + CommunityListItemView(community: community, shouldOverlayImage: true) + .onTapGesture { + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: AmityCommunityProfilePage(communityId: community.communityId)), animated: true) + } + .overlay( + Text(viewModel.digitFormatter.string(from: NSNumber(value: index + 1)) ?? "") + .font(.body) + .fontWeight(.bold) + .foregroundColor(.white) + .offset(x: 8, y: -8) + .shadow(radius: 2, x: 0, y: 0) + , alignment: .bottomLeading) + + Divider() + .opacity(viewModel.isLastCommunity(community: community) ? 0 : 1) + .padding(.vertical, 12) + } + } + } + .padding(.horizontal) + } +} + +#if DEBUG +#Preview { + AmityTrendingCommunitiesComponent() +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/TrendingCommunityViewModel.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/TrendingCommunityViewModel.swift new file mode 100644 index 0000000..c1bf9a5 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Components/TrendingCommunities/TrendingCommunityViewModel.swift @@ -0,0 +1,107 @@ +// +// TrendingCommunityViewModel.swift +// AmityUIKit4 +// +// Created by Nishan on 4/9/2567 BE. +// + +import SwiftUI +import AmitySDK +import Combine + +class TrendingCommunityViewModel: ObservableObject { + + private let repository: AmityCommunityRepository = .init(client: AmityUIKit4Manager.client) + private var token: AmityNotificationToken? + private var communityCollection: AmityCollection? + + @Published var communities: [AmityCommunityModel] = [] + @Published var queryState: QueryState = .idle + + lazy var digitFormatter: NumberFormatter = { + let formatter = NumberFormatter() + formatter.minimumIntegerDigits = 2 + return formatter + }() + + var queryStateObserver: AnyCancellable? + var refreshStateObserver: AnyCancellable? + + func fetchCommunities(limit: Int? = 5) { + guard queryState != .loading else { return } + + queryState = .loading + + communityCollection = repository.getTrendingCommunities() + token = communityCollection?.observe { [weak self] liveCollection, _, error in + guard let self else { return } + + if let error { + self.queryState = .error + self.token?.invalidate() + self.communityCollection = nil + self.unObserveState() + return + } + + if let limit, limit > 0 { + let items = Array(liveCollection.snapshots.prefix(limit).map { AmityCommunityModel(object: $0)} ) + self.communities = items + } else { + let items = liveCollection.snapshots.map { + AmityCommunityModel(object: $0) + } + self.communities = items + } + + self.queryState = .loaded + } + } + + func isLastCommunity(community: AmityCommunityModel) -> Bool { + if let lastCommunity = communities.last, lastCommunity.communityId == community.communityId { + return true + } + return false + } + + func observeState() { + refreshStateObserver = ExploreComponentsStateManager.shared.$trendingCommunitiesState + .receive(on: DispatchQueue.main) + .sink { [weak self] state in + guard let self else { return } + + switch state { + case .refreshing: + Log.add(event: .info, "Refreshing trending communities") + self.fetchCommunities(limit: 5) + default: + break + } + } + + queryStateObserver = $queryState + .receive(on: DispatchQueue.main) + .sink { state in + switch state { + case .error: + ExploreComponentsStateManager.shared.trendingCommunitiesState = .error + case .idle: + ExploreComponentsStateManager.shared.trendingCommunitiesState = .initial + case .loaded: + if self.communities.isEmpty { + ExploreComponentsStateManager.shared.trendingCommunitiesState = .dataEmpty + } else { + ExploreComponentsStateManager.shared.trendingCommunitiesState = .dataAvailable + } + case .loading: + ExploreComponentsStateManager.shared.trendingCommunitiesState = .loading + } + } + } + + func unObserveState() { + queryStateObserver = nil + refreshStateObserver = nil + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentEmptyStateView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentEmptyStateView.swift new file mode 100644 index 0000000..0f53f43 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentEmptyStateView.swift @@ -0,0 +1,88 @@ +// +// ExploreComponentEmptyStateView.swift +// AmityUIKit4 +// +// Created by Nishan on 29/8/2567 BE. +// + +import SwiftUI + +struct ExploreComponentEmptyStateView: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + enum StateType { + case unableToLoad + case communitiesNotAvailable + } + + let emptyStateType: StateType + let action: DefaultTapAction? + + init(type: StateType, action: DefaultTapAction?) { + self.emptyStateType = type + self.action = action + } + + var body: some View { + + if emptyStateType == .unableToLoad { + AmityEmptyStateView(configuration: .init(image: AmityIcon.emptyStateExplore.rawValue, title: "Something went wrong", subtitle: "Please try again", iconSize: CGSize(width: 80, height: 80), renderingMode: .original, tapAction: nil)) + } else { + VStack(alignment: .center, spacing: 0) { + // emptyNewsFeedIcon + Image(AmityIcon.emptyNewsFeedIcon.imageResource) + .resizable() + .scaledToFit() + .frame(width: 160, height: 160) + + Text("No community yet") + .font(.system(size: 17, weight: .semibold)) + .foregroundColor(Color(viewConfig.theme.baseColorShade2)) + .padding(.top, 24) + + Text("Let's create your own communities") + .font(.system(size: 15)) + .foregroundColor(Color(viewConfig.theme.baseColorShade2)) + .multilineTextAlignment(.center) + .padding(.top, 4) + + Button { + ImpactFeedbackGenerator.impactFeedback(style: .medium) + + action?() + } label: { + HStack(spacing: 0) { + Image(AmityIcon.plusIcon.imageResource) + .resizable() + .renderingMode(.template) + .scaledToFit() + .frame(width: 16, height: 16) + .foregroundColor(Color(.white)) + + Text("Create Community") + .font(.body) + .fontWeight(.semibold) + .foregroundColor(Color(.white)) + .padding(.horizontal, 4) + } + .padding(.horizontal, 24) + .padding(.vertical, 6) + .contentShape(Rectangle()) + } + .buttonStyle(.plain) + .frame(height: 40) + .background(Color(viewConfig.theme.primaryColor)) + .cornerRadius(8, corners: .allCorners) + .padding(.top, 16) + } + } + } +} + +#if DEBUG +#Preview { + ExploreComponentEmptyStateView(type: .unableToLoad, action: nil) + .environmentObject(AmityViewConfigController(pageId: .socialHomePage)) +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentSkeletonView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentSkeletonView.swift new file mode 100644 index 0000000..274308f --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/ExploreComponentSkeletonView.swift @@ -0,0 +1,162 @@ +// +// ExploreComponentSkeletonView.swift +// AmityUIKit4 +// +// Created by Nishan on 29/8/2567 BE. +// + +import SwiftUI + +struct ExploreComponentSkeletonView: View { + + @EnvironmentObject var viewConfig: AmityViewConfigController + + var body: some View { + ScrollView(.vertical, showsIndicators: false) { + VStack(alignment: .leading) { + ExploreCategorySkeletonView() + + ExploreRecommendedSkeletonView() + + ExploreTrendingSkeletonView() + } + } + } +} + +struct SkeletonRectangle: View { + + @EnvironmentObject var viewConfig: AmityViewConfigController + + let height: CGFloat + let width: CGFloat + let cornerRadius: CGFloat + + init(height: CGFloat = 12, width: CGFloat = 200, cornerRadius: CGFloat = 12) { + self.height = height + self.width = width + self.cornerRadius = cornerRadius + } + + var body: some View { + Rectangle() + .fill(Color(viewConfig.theme.baseColorShade4)) + .frame(width: width, height: height) + .cornerRadius(cornerRadius, corners: .allCorners) + } +} + + +#if DEBUG +#Preview { + ExploreComponentSkeletonView() + .environmentObject(AmityViewConfigController(pageId: .socialHomePage)) +} +#endif + +struct ExploreCategorySkeletonView: View { + + @EnvironmentObject var viewConfig: AmityViewConfigController + + let count: Int = 7 + + var body: some View { + VStack(alignment: .leading) { + ScrollView(.horizontal, showsIndicators: false) { + HStack { + ForEach(0.. some View { + VStack(spacing: 0) { + HStack(spacing: 0) { + AsyncImage(placeholder: AmityIcon.communityCategoryPlaceholder.imageResource, url: item.avatarURL) + .frame(width: 40, height: 40) + .clipped() + .clipShape(Circle()) + .accessibilityIdentifier("category_row_image") + + Text(item.name) + .font(.body) + .fontWeight(.semibold) + .padding(.leading, 12) + .lineLimit(1) + .accessibilityIdentifier("category_row_name") + + Spacer() + + Image(systemName: "chevron.right") + .resizable() + .scaledToFit() + .frame(width: 12, height: 12) + } + + if let lastItemId = viewModel.categories.last?.id, lastItemId != item.id { + Divider() + .overlay(Color(viewConfig.theme.baseColorShade4)) + .padding(.vertical, 8) + + } + } + .contentShape(Rectangle()) + .listRowBackground(Color(viewConfig.theme.backgroundColor)) + .listRowInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16)) + .onTapGesture { + let communityListView = AmityCommunitiesByCategoryPage(categoryId: item.id) + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: communityListView), animated: true) + } + .onAppear { + if let lastCategoryId = viewModel.categories.last?.id, lastCategoryId == item.id { + viewModel.loadNextPage() + } + } + .onDisappear { + viewModel.unObserveState() + } + } +} + +#if DEBUG +#Preview { + AmityAllCategoriesPage() +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/AmityCommunitiesByCategoryPage.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/AmityCommunitiesByCategoryPage.swift new file mode 100644 index 0000000..e32a2d1 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/AmityCommunitiesByCategoryPage.swift @@ -0,0 +1,41 @@ +// +// AmityCommunitiesByCategoryPage.swift +// AmityUIKit4 +// +// Created by Nishan on 4/9/2567 BE. +// + +import SwiftUI + +public struct AmityCommunitiesByCategoryPage: AmityPageView { + + public var id: PageId { + return .communitiesByCategoryPage + } + + @EnvironmentObject public var host: AmitySwiftUIHostWrapper + @StateObject var viewConfig: AmityViewConfigController + @StateObject var viewModel: CommunityListViewModel + + public init(categoryId: String) { + self._viewModel = StateObject(wrappedValue: CommunityListViewModel(categoryId: categoryId)) + self._viewConfig = StateObject(wrappedValue: .init(pageId: .communitiesByCategoryPage)) + } + + public var body: some View { + VStack(spacing: 0) { + AmityNavigationBar(title: viewModel.categoryName, showBackButton: true) + + CommunityListView(viewModel: viewModel) + .padding(.top, 16) + } + .background(Color(viewConfig.theme.backgroundColor).ignoresSafeArea()) + .updateTheme(with: viewConfig) + } +} + +#if DEBUG +#Preview { + AmityCommunitiesByCategoryPage(categoryId: "1234") +} +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListItemView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListItemView.swift new file mode 100644 index 0000000..08449b9 --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListItemView.swift @@ -0,0 +1,224 @@ +// +// CommunityListItemView.swift +// AmityUIKit4 +// +// Created by Nishan on 9/9/2567 BE. +// + +import SwiftUI +import AmitySDK + +struct CommunityListItemView: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + var community: AmityCommunityModel + var shouldOverlayImage: Bool = false + + var body: some View { + HStack { + AsyncImage(placeholder: AmityIcon.communityThumbnail.imageResource, url: URL(string: community.avatarURL), contentMode: .fill) + .accessibilityLabel(AccessibilityID.Social.Explore.communityImage) + .frame(width: 80, height: 80) + .clipped() + .cornerRadius(8, corners: .allCorners) + .overlay( + LinearGradient(colors: [Color.black.opacity(0.4), Color.black.opacity(0)], startPoint: .bottom, endPoint: .top) + .cornerRadius(8, corners: .allCorners).opacity(shouldOverlayImage ? 1 : 0) + , alignment: .center) + + CommunityInfoView(community: community) + .padding(.horizontal, 8) + .padding(.vertical, 8) + } + .contentShape(Rectangle()) + } +} + +struct SmallCommunityCategoryLabel: View { + + @EnvironmentObject var viewConfig: AmityViewConfigController + + let title: String + + var body: some View { + Text(title) + .font(.caption) + .padding(.horizontal, 10) + .padding(.vertical, 2) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .lineLimit(1) + .background(Color(viewConfig.theme.baseColorShade4)) + .clipShape(Capsule()) + } +} + +struct CommunityJoinButton: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + + let community: AmityCommunityModel + let tapAction: DefaultTapAction + + @State private var isJoined = false + + init(community: AmityCommunityModel, tapAction: @escaping DefaultTapAction) { + self.community = community + self.tapAction = tapAction + } + + var body: some View { + Button { + ImpactFeedbackGenerator.impactFeedback(style: .medium) + + tapAction() + } label: { + HStack(spacing: 0) { + Image(isJoined ? AmityIcon.tickIcon.imageResource : AmityIcon.plusIcon.imageResource) + .resizable() + .renderingMode(.template) + .scaledToFit() + .frame(width: 16, height: 16) + .foregroundColor(Color(isJoined ? viewConfig.theme.baseColor : .white)) + + Text(isJoined ? AmityLocalizedStringSet.Social.communityPageJoinedTitle.localizedString : AmityLocalizedStringSet.Social.communityPageJoinTitle.localizedString) + .font(.caption) + .fontWeight(.bold) + .foregroundColor(Color(isJoined ? viewConfig.theme.baseColor : .white)) + .padding(.horizontal, 4) + } + .padding(.horizontal, 8) + .padding(.vertical, 6) + } + .buttonStyle(.plain) + .background(Color(isJoined ? viewConfig.theme.backgroundColor : viewConfig.theme.primaryColor)) + .cornerRadius(4, corners: .allCorners) + .overlay( + RoundedRectangle(cornerRadius: 4, style: .continuous) + .stroke(Color(isJoined ? viewConfig.theme.baseColorShade4 : viewConfig.theme.primaryColor), lineWidth: 1) + ) + .onChange(of: community.isJoined, perform: { value in + withAnimation { + self.isJoined = value + } + }) + .accessibilityIdentifier(AccessibilityID.Social.Explore.communityJoinButton) + } +} + +struct CommunityInfoView: View { + + @EnvironmentObject private var viewConfig: AmityViewConfigController + @StateObject var viewModel = CommunityInfoViewModel() + + let community: AmityCommunityModel + + var body: some View { + VStack(alignment: .leading, spacing: 5) { + HStack(spacing: 0) { + if !community.isPublic { + Image(AmityIcon.lockBlackIcon.imageResource) + .renderingMode(.template) + .frame(width: 20, height: 12) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .isHidden(viewConfig.isHidden(elementId: .communityPrivateBadge)) + .padding(.trailing, 4) + } + + Text(community.displayName) + .font(.body) + .fontWeight(.semibold) + .foregroundColor(Color(viewConfig.theme.baseColor)) + .lineLimit(1) + + Image(AmityIcon.verifiedBadge.imageResource) + .resizable() + .scaledToFill() + .frame(width: 20, height: 20) + .padding(.leading, 4) + .opacity(community.isOfficial ? 1 : 0) + } + + HStack(alignment: community.categories.isEmpty ? .bottom : .bottom, spacing: 0) { + VStack(alignment: .leading, spacing: 0) { + + if !community.categories.isEmpty { + CategoryList(community: community) + .padding(.bottom, 5) + } + + let memberCountInfo = community.membersCount > 1 ? AmityLocalizedStringSet.Social.communityMemberCountPlural.localized(arguments: "\(community.membersCount.formattedCountString)") : AmityLocalizedStringSet.Social.communityMemberCountSingular.localized(arguments: "\(community.membersCount.formattedCountString)") + Text(memberCountInfo) + .font(.system(size: 13, weight: .regular)) + .foregroundColor(Color(viewConfig.theme.baseColorShade1)) + .accessibilityLabel(AccessibilityID.Social.Explore.communityMemberCount) + + Spacer() + } + + Spacer() + + CommunityJoinButton(community: community, tapAction: { + let communityId = community.communityId + let isJoined = community.isJoined + Task { @MainActor in + if isJoined { + let isSuccess = try await viewModel.leaveCommunity(communityId: communityId) + Log.add(event: .info, "Leaving Community Status: \(isSuccess)") + } else { + let isSuccess = try await viewModel.joinCommunity(communityId: communityId) + Log.add(event: .info, "Joining Community Status: \(isSuccess)") + } + } + }) + } + .frame(height: 48) + } + } + + struct CategoryList: View { + + let community: AmityCommunityModel + let shownCategories: [String] + let notShownCategories: Int + + init(community: AmityCommunityModel) { + self.community = community + + let maxCategoriesToShow = 2 + let categories = community.categories + self.shownCategories = Array(categories.prefix(maxCategoriesToShow)) + + let totalCount = community.categories.count + let remainingCategories = totalCount - maxCategoriesToShow + self.notShownCategories = max(remainingCategories, 0) + } + + var body: some View { + HStack { + ForEach(shownCategories, id: \.self) { item in + SmallCommunityCategoryLabel(title: item) + } + + if notShownCategories > 0 { + SmallCommunityCategoryLabel(title: "+ \(notShownCategories)") + .layoutPriority(1) + } + } + .accessibilityLabel(AccessibilityID.Social.Explore.communityCategories) + } + } +} + +class CommunityInfoViewModel: ObservableObject { + + let repository = AmityCommunityRepository(client: AmityUIKit4Manager.client) + + func joinCommunity(communityId: String) async throws -> Bool { + try await repository.joinCommunity(withId: communityId) + } + + func leaveCommunity(communityId: String) async throws -> Bool { + try await repository.leaveCommunity(withId: communityId) + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListView.swift new file mode 100644 index 0000000..5e6de5a --- /dev/null +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Components/SocialHome/Explore/Pages/CommunitiesByCategory/Views/CommunityListView.swift @@ -0,0 +1,117 @@ +// +// CommunityListView.swift +// AmityUIKit4 +// +// Created by Nishan on 28/8/2567 BE. +// + +import SwiftUI +import AmitySDK + +struct CommunityListView: View { + + @EnvironmentObject public var host: AmitySwiftUIHostWrapper + @EnvironmentObject public var viewConfig: AmityViewConfigController + @StateObject var viewModel: CommunityListViewModel + + var body: some View { + ZStack { + ScrollView(.vertical, showsIndicators: false) { + LazyVStack { + ForEach(viewModel.communities) { community in + VStack(spacing: 0) { + CommunityListItemView(community: community) + .onTapGesture { + host.controller?.navigationController?.pushViewController(AmitySwiftUIHostingController(rootView: AmityCommunityProfilePage(communityId: community.communityId)), animated: true) + } + .onAppear { + if let lastCommunityId = viewModel.communities.last?.communityId, lastCommunityId == community.communityId { + viewModel.loadMore() + } + } + + Divider() + .opacity(viewModel.isLastCommunity(community: community) ? 0 : 1) + .padding(.vertical, 12) + } + } + } + } + + AmityEmptyStateView(configuration: .init(image: "communityNotFoundIcon", title: AmityLocalizedStringSet.Social.communityEmptyStateTitle.localizedString, subtitle: nil, iconSize: CGSize(width: 60, height: 60), renderingMode: .original, tapAction: nil)) + .opacity(viewModel.queryState == .loaded && viewModel.communities.isEmpty ? 1 : 0) + + } + .padding(.horizontal) + .background(Color(viewConfig.theme.backgroundColor).ignoresSafeArea()) + .onAppear { + viewModel.fetchCommunities() + } + } +} + +class CommunityListViewModel: ObservableObject { + + private let repository: AmityCommunityRepository = .init(client: AmityUIKit4Manager.client) + private var token: AmityNotificationToken? + private var communityCollection: AmityCollection? + private let categoryId: String + + private let categoryRepository: AmityCommunityRepository = .init(client: AmityUIKit4Manager.client) + private var categoryToken: AmityNotificationToken? + + @Published var communities: [AmityCommunityModel] = [] + @Published var queryState: QueryState = .idle + @Published var categoryName: String = "" + + init(categoryId: String) { + self.categoryId = categoryId + self.categoryToken = categoryRepository.getCategory(withId: categoryId).observe({ [weak self] liveObject, error in + guard let self else { return } + + if let category = liveObject.snapshot { + self.categoryName = category.name + + // Invalidate token + self.categoryToken?.invalidate() + } + }) + } + + func fetchCommunities() { + guard queryState != .loading else { return } + + queryState = .loading + + let queryOptions = AmityCommunityQueryOptions(filter: .all, sortBy: .lastCreated, categoryId: categoryId, includeDeleted: false) + communityCollection = repository.getCommunities(with: queryOptions) + token = communityCollection?.observe { [weak self] liveCollection, _, error in + guard let self else { return } + + if let _ = error { + self.queryState = .error + return + } + + let items = liveCollection.snapshots.map { + AmityCommunityModel(object: $0) + } + self.communities = items + + self.queryState = .loaded + } + } + + func isLastCommunity(community: AmityCommunityModel) -> Bool { + if let lastCommunity = communities.last, lastCommunity.communityId == community.communityId { + return true + } + return false + } + + func loadMore() { + if let communityCollection, communityCollection.hasNext { + communityCollection.nextPage() + } + } +} diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunityProfilePage.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunityProfilePage.swift index c8d49cf..a6e8fab 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunityProfilePage.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunityProfilePage.swift @@ -23,7 +23,6 @@ public struct AmityCommunityProfilePage: AmityPageView { public var id: PageId { return .communityProfilePage - } public init(communityId: String) { diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunitySetupPage.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunitySetupPage.swift index 44844d3..c04a10e 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunitySetupPage.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/CommunityProfile/AmityCommunitySetupPage.swift @@ -168,14 +168,14 @@ public struct AmityCommunitySetupPage: AmityPageView { .padding([.leading, .trailing], 16) } } - .gesture( - DragGesture() - .onChanged { _ in - hideKeyboard() - } - ) } } + .simultaneousGesture( + DragGesture() + .onChanged { _ in + hideKeyboard() + } + ) if case .edit(let community) = pageMode { diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/AmitySocialHomePage.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/AmitySocialHomePage.swift index 6c3ac75..051425f 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/AmitySocialHomePage.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/AmitySocialHomePage.swift @@ -25,7 +25,7 @@ public struct AmitySocialHomePage: AmityPageView { public var body: some View { VStack(alignment: .leading, spacing: 0) { AmitySocialHomeTopNavigationComponent(pageId: id, selectedTab: viewModel.selectedTab, searchButtonAction: { - if viewModel.selectedTab == .newsFeed { + if viewModel.selectedTab == .newsFeed || viewModel.selectedTab == .explore { let context = AmitySocialHomePageBehavior.Context(page: self) AmityUIKitManagerInternal.shared.behavior.socialHomePageBehavior?.goToGlobalSearchPage(context: context) diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/ChildViews/SocialHomeContainerView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/ChildViews/SocialHomeContainerView.swift index 37230d9..4e84b96 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/ChildViews/SocialHomeContainerView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Social/Pages/SocialHome/ChildViews/SocialHomeContainerView.swift @@ -26,7 +26,7 @@ struct SocialHomeContainerView: View { case .newsFeed: AmityNewsFeedComponent(pageId: pageId) case .explore: - ComponentA() + AmityExplorePageContainer() case .myCommunities: AmityMyCommunitiesComponent(pageId: pageId) } @@ -45,13 +45,3 @@ struct SocialHomeContainerView: View { .padding(.top, 8) } } - - -struct ComponentA: View { - var body: some View { - VStack { - Text("Explore Component") - } - } -} - diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Components/StoryComment/ChildViews/CommentSkeletonView.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Components/StoryComment/ChildViews/CommentSkeletonView.swift index 9a54f2e..b7652bb 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Components/StoryComment/ChildViews/CommentSkeletonView.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Components/StoryComment/ChildViews/CommentSkeletonView.swift @@ -55,6 +55,8 @@ struct TestSkeletonView: View { } } +#if DEBUG #Preview { TestSkeletonView() } +#endif diff --git a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Models/AmityCommunityModel.swift b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Models/AmityCommunityModel.swift index 88a7a07..73ab109 100644 --- a/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Models/AmityCommunityModel.swift +++ b/UpstraUIKit/AmityUIKit4/AmityUIKit4/Story/Models/AmityCommunityModel.swift @@ -8,7 +8,12 @@ import UIKit import AmitySDK -public struct AmityCommunityModel { +public struct AmityCommunityModel: Identifiable { + + public var id: String { + return communityId + } + let communityId: String let description: String let displayName: String diff --git a/UpstraUIKit/AmityUIKitLiveStream/AmityUIKitLiveStream.xcodeproj/project.pbxproj b/UpstraUIKit/AmityUIKitLiveStream/AmityUIKitLiveStream.xcodeproj/project.pbxproj index 5a6d5c2..b060df0 100644 --- a/UpstraUIKit/AmityUIKitLiveStream/AmityUIKitLiveStream.xcodeproj/project.pbxproj +++ b/UpstraUIKit/AmityUIKitLiveStream/AmityUIKitLiveStream.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 925522542C9C2E0100AD85B5 /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = 925522532C9C2E0100AD85B5 /* SharedFrameworks */; }; A0B68B3026E07278007D7B5B /* LiveStreamViewController+GoLive.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0B68B2F26E07278007D7B5B /* LiveStreamViewController+GoLive.swift */; }; A0B68B3626E07824007D7B5B /* AsyncOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0B68B3526E07824007D7B5B /* AsyncOperation.swift */; }; A0B68B3F26E07912007D7B5B /* CreatePost.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0B68B3E26E07912007D7B5B /* CreatePost.swift */; }; @@ -29,7 +30,6 @@ A0BD0B5E26DF37160054088B /* LiveStreamBroadcastVC+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BD0B5D26DF37160054088B /* LiveStreamBroadcastVC+Keyboard.swift */; }; A0BD0B6026DF377A0054088B /* LiveStreamBroadcastVC+CoverImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BD0B5F26DF377A0054088B /* LiveStreamBroadcastVC+CoverImagePicker.swift */; }; A0BD0B6226DF3A3F0054088B /* LiveStreamBroadcast+UIContainerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BD0B6126DF3A3F0054088B /* LiveStreamBroadcast+UIContainerState.swift */; }; - A9F927352C9463DB00AC8E9C /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = A9F927342C9463DB00AC8E9C /* SharedFrameworks */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -69,7 +69,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9F927352C9463DB00AC8E9C /* SharedFrameworks in Frameworks */, + 925522542C9C2E0100AD85B5 /* SharedFrameworks in Frameworks */, A0BD0B3426DDD9820054088B /* AmityUIKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -245,7 +245,7 @@ ); name = AmityUIKitLiveStream; packageProductDependencies = ( - A9F927342C9463DB00AC8E9C /* SharedFrameworks */, + 925522532C9C2E0100AD85B5 /* SharedFrameworks */, ); productName = AmityUIKitLiveStream; productReference = A0BD0B1526DCE4F50054088B /* AmityUIKitLiveStream.framework */; @@ -529,7 +529,7 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - A9F927342C9463DB00AC8E9C /* SharedFrameworks */ = { + 925522532C9C2E0100AD85B5 /* SharedFrameworks */ = { isa = XCSwiftPackageProductDependency; productName = SharedFrameworks; }; diff --git a/UpstraUIKit/SampleApp/SampleApp.xcodeproj/project.pbxproj b/UpstraUIKit/SampleApp/SampleApp.xcodeproj/project.pbxproj index b557e36..2f20362 100644 --- a/UpstraUIKit/SampleApp/SampleApp.xcodeproj/project.pbxproj +++ b/UpstraUIKit/SampleApp/SampleApp.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 729CAF3E273CC8ED000AE162 /* Binding+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 729CAF3D273CC8ED000AE162 /* Binding+Extension.swift */; }; 729CAF42273CC95B000AE162 /* EndpointManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 729CAF41273CC95B000AE162 /* EndpointManager.swift */; }; 72AACE0B273931F100E59D55 /* EndpointsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72AACE0A273931F100E59D55 /* EndpointsView.swift */; }; + 925522562C9C2E0D00AD85B5 /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = 925522552C9C2E0D00AD85B5 /* SharedFrameworks */; }; 92DBE8A62ACA98CF007D873C /* DataListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D495077325E637C1005C033F /* DataListViewController.swift */; }; 92DBE8A72ACA98CF007D873C /* SamplePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 724C25F3274CE38B0058B066 /* SamplePageViewController.swift */; }; 92DBE8A82ACA98CF007D873C /* PostCreatorSettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A03190A6272169C1008A85DC /* PostCreatorSettingsPage.swift */; }; @@ -100,7 +101,6 @@ A03190A7272169C1008A85DC /* PostCreatorSettingsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A03190A6272169C1008A85DC /* PostCreatorSettingsPage.swift */; }; A0BD0B4826DDE0E30054088B /* AmityUIKitLiveStream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0BD0B4726DDE0E30054088B /* AmityUIKitLiveStream.framework */; }; A0BD0B4926DDE0E30054088B /* AmityUIKitLiveStream.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A0BD0B4726DDE0E30054088B /* AmityUIKitLiveStream.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - A9F927372C9463F500AC8E9C /* SharedFrameworks in Frameworks */ = {isa = PBXBuildFile; productRef = A9F927362C9463F500AC8E9C /* SharedFrameworks */; }; A9FF80E62BBD10010088A317 /* LiveChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FF80E52BBD10010088A317 /* LiveChatListView.swift */; }; A9FF80ED2BBD55870088A317 /* LiveChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FF80E52BBD10010088A317 /* LiveChatListView.swift */; }; B72861D924C573B100ECC563 /* TabbarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72861D824C573B100ECC563 /* TabbarViewController.swift */; }; @@ -279,7 +279,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A9F927372C9463F500AC8E9C /* SharedFrameworks in Frameworks */, + 925522562C9C2E0D00AD85B5 /* SharedFrameworks in Frameworks */, A0BD0B4826DDE0E30054088B /* AmityUIKitLiveStream.framework in Frameworks */, 68F5D9FE2B481E4700A9FA0D /* AmityUIKit4.framework in Frameworks */, D478D16926240A5E006EA140 /* AmityUIKit.framework in Frameworks */, @@ -605,7 +605,7 @@ ); name = SampleApp; packageProductDependencies = ( - A9F927362C9463F500AC8E9C /* SharedFrameworks */, + 925522552C9C2E0D00AD85B5 /* SharedFrameworks */, ); productName = SampleApp; productReference = B78DA47524BED7D300EE902B /* SampleApp.app */; @@ -1288,15 +1288,15 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 925522552C9C2E0D00AD85B5 /* SharedFrameworks */ = { + isa = XCSwiftPackageProductDependency; + productName = SharedFrameworks; + }; 92DBE8A32ACA98CF007D873C /* FirebaseCrashlytics */ = { isa = XCSwiftPackageProductDependency; package = 92DBE8A42ACA98CF007D873C /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; productName = FirebaseCrashlytics; }; - A9F927362C9463F500AC8E9C /* SharedFrameworks */ = { - isa = XCSwiftPackageProductDependency; - productName = SharedFrameworks; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = B78DA46D24BED7D300EE902B /* Project object */; diff --git a/UpstraUIKit/SampleApp/SampleApp/Feature/Endpoint Settings/EndpointsView.swift b/UpstraUIKit/SampleApp/SampleApp/Feature/Endpoint Settings/EndpointsView.swift index 83b4c42..64335bd 100644 --- a/UpstraUIKit/SampleApp/SampleApp/Feature/Endpoint Settings/EndpointsView.swift +++ b/UpstraUIKit/SampleApp/SampleApp/Feature/Endpoint Settings/EndpointsView.swift @@ -27,7 +27,6 @@ struct EndpointsView: View { _uploadURL = .init(initialValue: config.uploadURL) } - @State private var favoriteColor = 0 var body: some View { Picker(selection: $selectedEnv.onChange(valueChange), label: /*@START_MENU_TOKEN@*/Text("Picker")/*@END_MENU_TOKEN@*/) { diff --git a/UpstraUIKit/SampleApp/SampleApp/Feature/LiveChatListView.swift b/UpstraUIKit/SampleApp/SampleApp/Feature/LiveChatListView.swift index d02455c..38f0173 100644 --- a/UpstraUIKit/SampleApp/SampleApp/Feature/LiveChatListView.swift +++ b/UpstraUIKit/SampleApp/SampleApp/Feature/LiveChatListView.swift @@ -63,9 +63,11 @@ struct LiveChatListView: View { } } +#if DEBUG #Preview { LiveChatListView() } +#endif class TestLiveChatListViewModel: ObservableObject { let channelRepo = AmityChannelRepository(client: AmityUIKit4Manager.client) diff --git a/UpstraUIKit/SampleApp/SampleApp/Manager/AppManager.swift b/UpstraUIKit/SampleApp/SampleApp/Manager/AppManager.swift index 61f9130..81de438 100644 --- a/UpstraUIKit/SampleApp/SampleApp/Manager/AppManager.swift +++ b/UpstraUIKit/SampleApp/SampleApp/Manager/AppManager.swift @@ -88,13 +88,11 @@ class AppManager { AmityUIKitManager.registerDeviceForPushNotification(deviceToken) { success, error in if success { - AmityHUD.show(.success(message: "Success with id \(deviceToken)")) + AmityHUD.show(.success(message: "Successfully registered push notification for device \(deviceToken)")) } else { - AmityHUD.show(.error(message: "Failed with error \(error?.localizedDescription)")) + AmityHUD.show(.error(message: "Failed to register push notification. Error: \(error?.localizedDescription ?? "")")) } - } - } func unregister() { diff --git a/UpstraUIKit/SharedFrameworks/Package.swift b/UpstraUIKit/SharedFrameworks/Package.swift index ba3178e..126b5d7 100644 --- a/UpstraUIKit/SharedFrameworks/Package.swift +++ b/UpstraUIKit/SharedFrameworks/Package.swift @@ -23,28 +23,28 @@ let package = Package( dependencies: []), .binaryTarget( name: "AmitySDK", - url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta20/AmitySDK.xcframework.zip", - checksum: "956c787e0cc9711c6c717cc1074e4b416b5a4e347fff831063b75984dbcdbc7b" + url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta21/AmitySDK.xcframework.zip", + checksum: "b95582d90256610bb4cbe393fb158ae97b2f2ba36dbf2fa1fd14410ec794c69b" ), .binaryTarget( name: "Realm", - url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta20/Realm.xcframework.zip", - checksum: "e7c23f25fbcd2dc944d11a6eb647e6e6d1ff3da4d3cc3f2507f07785c93098e0" + url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta21/Realm.xcframework.zip", + checksum: "fe727567d51b301a7b5c315a4821e2cf926bb26e72a4441eb88491ccfd827635" ), .binaryTarget( name: "RealmSwift", - url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta20/RealmSwift.xcframework.zip", - checksum: "41699cdf7edc36f800ac3487931f7ef74c8eebcda8342c079ed041f74011a39a" + url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta21/RealmSwift.xcframework.zip", + checksum: "898c21448d9bd54bc531a2b98235bd85d022563356d4224829ccd8a0598e6808" ), .binaryTarget( name: "AmityLiveVideoBroadcastKit", - url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta20/AmityLiveVideoBroadcastKit.xcframework.zip", - checksum: "2afdc3a8d4abfccb872ca9db9e2b2e11af20e22664d007da185b5045f4843fba" + url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta21/AmityLiveVideoBroadcastKit.xcframework.zip", + checksum: "517f68b1bc856e856d4a4b1fd8be588801631d142624082eadb1525e639852d1" ), .binaryTarget( name: "AmityVideoPlayerKit", - url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta20/AmityVideoPlayerKit.xcframework.zip", - checksum: "b57446618d695706f938992a7a3267bc50890e644fd703a3af5a5e7a6f4ebdb9" + url: "https://sdk.amity.co/sdk-release/ios-uikit-frameworks/4.0.0-beta21/AmityVideoPlayerKit.xcframework.zip", + checksum: "3d5af83b23c20434f73e4e61e56c2af9496053a79b6fa402d62fa569e1fcd295" ), .binaryTarget( name: "MobileVLCKit",