refactor: 移除 Core Data 相关代码并添加新的消息列表视图控制器

主要变更:
1. 从 AppDelegate 中移除 Core Data 相关的属性和方法,简化应用结构。
2. 新增 EPBaseListViewController 作为消息列表的基础类,提供通用的表视图功能。
3. 添加 EPMessageListVC、EPFriendListVC、EPFollowingListVC 和 EPFansListVC,分别用于展示消息、朋友、关注和粉丝列表。
4. 引入 EPMessageSegmentView 以支持消息主界面的分段控制。

此更新旨在提升代码的可维护性,简化数据管理,并增强用户界面的功能性和交互性。
This commit is contained in:
edwinQQQ
2025-10-20 11:25:33 +08:00
parent 6f5ab10562
commit c8173bf034
21 changed files with 1076 additions and 752 deletions

View File

@@ -442,6 +442,11 @@
4C520D882D89A78C0051C784 /* VisitorListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C520D872D89A78C0051C784 /* VisitorListViewController.m */; }; 4C520D882D89A78C0051C784 /* VisitorListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C520D872D89A78C0051C784 /* VisitorListViewController.m */; };
4C5527BC2D1BDCDE00833FFD /* RoomLevelInfoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5527BB2D1BDCDE00833FFD /* RoomLevelInfoModel.m */; }; 4C5527BC2D1BDCDE00833FFD /* RoomLevelInfoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5527BB2D1BDCDE00833FFD /* RoomLevelInfoModel.m */; };
4C5527BF2D1C099500833FFD /* RoomResourceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5527BE2D1C099500833FFD /* RoomResourceManager.m */; }; 4C5527BF2D1C099500833FFD /* RoomResourceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5527BE2D1C099500833FFD /* RoomResourceManager.m */; };
4C59C0FD2EA2508F00D1F7BD /* EPFriendFollowingFans.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C59C0F82EA2508F00D1F7BD /* EPFriendFollowingFans.swift */; };
4C59C0FE2EA2508F00D1F7BD /* EPMessageSegmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C59C0FB2EA2508F00D1F7BD /* EPMessageSegmentView.swift */; };
4C59C0FF2EA2508F00D1F7BD /* EPMessageMainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C59C0FA2EA2508F00D1F7BD /* EPMessageMainViewController.swift */; };
4C59C1002EA2508F00D1F7BD /* EPBaseListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C59C0F72EA2508F00D1F7BD /* EPBaseListViewController.swift */; };
4C59C1012EA2508F00D1F7BD /* EPMessageListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C59C0F92EA2508F00D1F7BD /* EPMessageListVC.swift */; };
4C5C37232D0C1C7900BA9AB8 /* RegionListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C37222D0C1C7900BA9AB8 /* RegionListViewController.m */; }; 4C5C37232D0C1C7900BA9AB8 /* RegionListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5C37222D0C1C7900BA9AB8 /* RegionListViewController.m */; };
4C6C92C02D1172D9000A4693 /* RegionListInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6C92BF2D1172D9000A4693 /* RegionListInfo.m */; }; 4C6C92C02D1172D9000A4693 /* RegionListInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6C92BF2D1172D9000A4693 /* RegionListInfo.m */; };
4C6E1F752CEAEC3C0073D0A3 /* ShoppingMallTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F742CEAEC3C0073D0A3 /* ShoppingMallTagView.m */; }; 4C6E1F752CEAEC3C0073D0A3 /* ShoppingMallTagView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C6E1F742CEAEC3C0073D0A3 /* ShoppingMallTagView.m */; };
@@ -884,7 +889,7 @@
54FFD3832C9BD12600DE61E5 /* 5.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37F2C9BD12600DE61E5 /* 5.svga */; }; 54FFD3832C9BD12600DE61E5 /* 5.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37F2C9BD12600DE61E5 /* 5.svga */; };
54FFD3842C9BD12600DE61E5 /* 3.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37D2C9BD12600DE61E5 /* 3.svga */; }; 54FFD3842C9BD12600DE61E5 /* 3.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37D2C9BD12600DE61E5 /* 3.svga */; };
54FFD3852C9BD12600DE61E5 /* 2.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37C2C9BD12600DE61E5 /* 2.svga */; }; 54FFD3852C9BD12600DE61E5 /* 2.svga in Resources */ = {isa = PBXBuildFile; fileRef = 54FFD37C2C9BD12600DE61E5 /* 2.svga */; };
73FFADDC93E195344047A2EC /* Pods_YuMi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CACF623970097D653132D69A /* Pods_YuMi.framework */; }; 6996748A711C8E6931880AD0 /* Pods_YuMi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3148BBD005110C1B57D04595 /* Pods_YuMi.framework */; };
9B0086C627BA392B0032BD2B /* AnchorStageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0086C527BA392B0032BD2B /* AnchorStageView.m */; }; 9B0086C627BA392B0032BD2B /* AnchorStageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0086C527BA392B0032BD2B /* AnchorStageView.m */; };
9B0086CA27BA4F570032BD2B /* AnchorMicroView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0086C927BA4F570032BD2B /* AnchorMicroView.m */; }; 9B0086CA27BA4F570032BD2B /* AnchorMicroView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0086C927BA4F570032BD2B /* AnchorMicroView.m */; };
9B044DA0282D32F700DE4859 /* MicroInviteExtModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B044D9F282D32F700DE4859 /* MicroInviteExtModel.m */; }; 9B044DA0282D32F700DE4859 /* MicroInviteExtModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B044D9F282D32F700DE4859 /* MicroInviteExtModel.m */; };
@@ -2431,6 +2436,7 @@
23FF42782AA6E19C0055733C /* HomeMenuSourceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeMenuSourceModel.m; sourceTree = "<group>"; }; 23FF42782AA6E19C0055733C /* HomeMenuSourceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeMenuSourceModel.m; sourceTree = "<group>"; };
23FF428C2AAB2D3A0055733C /* XPCandyTreeBuyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPCandyTreeBuyView.h; sourceTree = "<group>"; }; 23FF428C2AAB2D3A0055733C /* XPCandyTreeBuyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPCandyTreeBuyView.h; sourceTree = "<group>"; };
23FF428D2AAB2D3A0055733C /* XPCandyTreeBuyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPCandyTreeBuyView.m; sourceTree = "<group>"; }; 23FF428D2AAB2D3A0055733C /* XPCandyTreeBuyView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPCandyTreeBuyView.m; sourceTree = "<group>"; };
3148BBD005110C1B57D04595 /* Pods_YuMi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_YuMi.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4C0642722E97BD6D00BAF413 /* EPMineHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineHeaderView.h; sourceTree = "<group>"; }; 4C0642722E97BD6D00BAF413 /* EPMineHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineHeaderView.h; sourceTree = "<group>"; };
4C0642732E97BD6D00BAF413 /* EPMineHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineHeaderView.m; sourceTree = "<group>"; }; 4C0642732E97BD6D00BAF413 /* EPMineHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineHeaderView.m; sourceTree = "<group>"; };
4C0642792E97BD6D00BAF413 /* EPMomentCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMomentCell.h; sourceTree = "<group>"; }; 4C0642792E97BD6D00BAF413 /* EPMomentCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMomentCell.h; sourceTree = "<group>"; };
@@ -2527,6 +2533,11 @@
4C5527BB2D1BDCDE00833FFD /* RoomLevelInfoModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomLevelInfoModel.m; sourceTree = "<group>"; }; 4C5527BB2D1BDCDE00833FFD /* RoomLevelInfoModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomLevelInfoModel.m; sourceTree = "<group>"; };
4C5527BD2D1C099500833FFD /* RoomResourceManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomResourceManager.h; sourceTree = "<group>"; }; 4C5527BD2D1C099500833FFD /* RoomResourceManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomResourceManager.h; sourceTree = "<group>"; };
4C5527BE2D1C099500833FFD /* RoomResourceManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomResourceManager.m; sourceTree = "<group>"; }; 4C5527BE2D1C099500833FFD /* RoomResourceManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomResourceManager.m; sourceTree = "<group>"; };
4C59C0F72EA2508F00D1F7BD /* EPBaseListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPBaseListViewController.swift; sourceTree = "<group>"; };
4C59C0F82EA2508F00D1F7BD /* EPFriendFollowingFans.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPFriendFollowingFans.swift; sourceTree = "<group>"; };
4C59C0F92EA2508F00D1F7BD /* EPMessageListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPMessageListVC.swift; sourceTree = "<group>"; };
4C59C0FA2EA2508F00D1F7BD /* EPMessageMainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPMessageMainViewController.swift; sourceTree = "<group>"; };
4C59C0FB2EA2508F00D1F7BD /* EPMessageSegmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPMessageSegmentView.swift; sourceTree = "<group>"; };
4C5C37212D0C1C7900BA9AB8 /* RegionListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegionListViewController.h; sourceTree = "<group>"; }; 4C5C37212D0C1C7900BA9AB8 /* RegionListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegionListViewController.h; sourceTree = "<group>"; };
4C5C37222D0C1C7900BA9AB8 /* RegionListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RegionListViewController.m; sourceTree = "<group>"; }; 4C5C37222D0C1C7900BA9AB8 /* RegionListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RegionListViewController.m; sourceTree = "<group>"; };
4C6C92BE2D1172D9000A4693 /* RegionListInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegionListInfo.h; sourceTree = "<group>"; }; 4C6C92BE2D1172D9000A4693 /* RegionListInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RegionListInfo.h; sourceTree = "<group>"; };
@@ -2982,8 +2993,8 @@
4CD19EAD2E9CDFC30069DAA0 /* EPLoginInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPLoginInputView.swift; sourceTree = "<group>"; }; 4CD19EAD2E9CDFC30069DAA0 /* EPLoginInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPLoginInputView.swift; sourceTree = "<group>"; };
4CD19EB02E9D12600069DAA0 /* EPEditSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPEditSettingViewController.swift; sourceTree = "<group>"; }; 4CD19EB02E9D12600069DAA0 /* EPEditSettingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPEditSettingViewController.swift; sourceTree = "<group>"; };
4CD19EB22E9D141A0069DAA0 /* EPMineViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineViewController.h; sourceTree = "<group>"; }; 4CD19EB22E9D141A0069DAA0 /* EPMineViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EPMineViewController.h; sourceTree = "<group>"; };
4CD19EB62E9D15000069DAA0 /* EPAboutUsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPAboutUsViewController.swift; sourceTree = "<group>"; };
4CD19EB32E9D141A0069DAA0 /* EPMineViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineViewController.m; sourceTree = "<group>"; }; 4CD19EB32E9D141A0069DAA0 /* EPMineViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EPMineViewController.m; sourceTree = "<group>"; };
4CD19EB62E9D15000069DAA0 /* EPAboutUsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EPAboutUsViewController.swift; sourceTree = "<group>"; };
4CD401452E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPPartyRoomItemCollectionViewCell.h; sourceTree = "<group>"; }; 4CD401452E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPPartyRoomItemCollectionViewCell.h; sourceTree = "<group>"; };
4CD401462E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPPartyRoomItemCollectionViewCell.m; sourceTree = "<group>"; }; 4CD401462E7183A8003F5009 /* XPPartyRoomItemCollectionViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPPartyRoomItemCollectionViewCell.m; sourceTree = "<group>"; };
4CD401482E718E36003F5009 /* XPBlankRoomModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPBlankRoomModel.h; sourceTree = "<group>"; }; 4CD401482E718E36003F5009 /* XPBlankRoomModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPBlankRoomModel.h; sourceTree = "<group>"; };
@@ -3209,7 +3220,7 @@
54FFD37D2C9BD12600DE61E5 /* 3.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 3.svga; sourceTree = "<group>"; }; 54FFD37D2C9BD12600DE61E5 /* 3.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 3.svga; sourceTree = "<group>"; };
54FFD37E2C9BD12600DE61E5 /* 4.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 4.svga; sourceTree = "<group>"; }; 54FFD37E2C9BD12600DE61E5 /* 4.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 4.svga; sourceTree = "<group>"; };
54FFD37F2C9BD12600DE61E5 /* 5.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 5.svga; sourceTree = "<group>"; }; 54FFD37F2C9BD12600DE61E5 /* 5.svga */ = {isa = PBXFileReference; lastKnownFileType = file; path = 5.svga; sourceTree = "<group>"; };
7DB00EC07F1D0ADFF900B38D /* Pods-YuMi.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YuMi.debug.xcconfig"; path = "Target Support Files/Pods-YuMi/Pods-YuMi.debug.xcconfig"; sourceTree = "<group>"; }; 56B26C27109C1DD2002D0624 /* Pods-YuMi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YuMi.release.xcconfig"; path = "Target Support Files/Pods-YuMi/Pods-YuMi.release.xcconfig"; sourceTree = "<group>"; };
9B0086C427BA392B0032BD2B /* AnchorStageView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnchorStageView.h; sourceTree = "<group>"; }; 9B0086C427BA392B0032BD2B /* AnchorStageView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnchorStageView.h; sourceTree = "<group>"; };
9B0086C527BA392B0032BD2B /* AnchorStageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AnchorStageView.m; sourceTree = "<group>"; }; 9B0086C527BA392B0032BD2B /* AnchorStageView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AnchorStageView.m; sourceTree = "<group>"; };
9B0086C827BA4F570032BD2B /* AnchorMicroView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnchorMicroView.h; sourceTree = "<group>"; }; 9B0086C827BA4F570032BD2B /* AnchorMicroView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnchorMicroView.h; sourceTree = "<group>"; };
@@ -3495,8 +3506,6 @@
9BFE0D912899042600F53C24 /* XPTaskCompleteTipView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPTaskCompleteTipView.m; sourceTree = "<group>"; }; 9BFE0D912899042600F53C24 /* XPTaskCompleteTipView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPTaskCompleteTipView.m; sourceTree = "<group>"; };
9BFE992C288142FD009DA429 /* RoomClassifyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomClassifyModel.h; sourceTree = "<group>"; }; 9BFE992C288142FD009DA429 /* RoomClassifyModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomClassifyModel.h; sourceTree = "<group>"; };
9BFE992D288142FD009DA429 /* RoomClassifyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomClassifyModel.m; sourceTree = "<group>"; }; 9BFE992D288142FD009DA429 /* RoomClassifyModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomClassifyModel.m; sourceTree = "<group>"; };
B66633E061B1B34177CD011C /* Pods-YuMi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YuMi.release.xcconfig"; path = "Target Support Files/Pods-YuMi/Pods-YuMi.release.xcconfig"; sourceTree = "<group>"; };
CACF623970097D653132D69A /* Pods_YuMi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_YuMi.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E801273E27E323C800BAC3F2 /* XPRoomPKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomPKViewController.h; sourceTree = "<group>"; }; E801273E27E323C800BAC3F2 /* XPRoomPKViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomPKViewController.h; sourceTree = "<group>"; };
E801273F27E323C800BAC3F2 /* XPRoomPKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPRoomPKViewController.m; sourceTree = "<group>"; }; E801273F27E323C800BAC3F2 /* XPRoomPKViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPRoomPKViewController.m; sourceTree = "<group>"; };
E801274127E323E500BAC3F2 /* XPRoomPKPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomPKPresenter.h; sourceTree = "<group>"; }; E801274127E323E500BAC3F2 /* XPRoomPKPresenter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomPKPresenter.h; sourceTree = "<group>"; };
@@ -4803,6 +4812,7 @@
E8F65C1E286998C9009BB5B9 /* XPMineShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPMineShareViewController.m; sourceTree = "<group>"; }; E8F65C1E286998C9009BB5B9 /* XPMineShareViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPMineShareViewController.m; sourceTree = "<group>"; };
E8F65C202869A36F009BB5B9 /* ContentShareMonentsModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentShareMonentsModel.h; sourceTree = "<group>"; }; E8F65C202869A36F009BB5B9 /* ContentShareMonentsModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ContentShareMonentsModel.h; sourceTree = "<group>"; };
E8F65C212869A36F009BB5B9 /* ContentShareMonentsModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContentShareMonentsModel.m; sourceTree = "<group>"; }; E8F65C212869A36F009BB5B9 /* ContentShareMonentsModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ContentShareMonentsModel.m; sourceTree = "<group>"; };
ECF5B2AAE493057A3DBCCFAF /* Pods-YuMi.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YuMi.debug.xcconfig"; path = "Target Support Files/Pods-YuMi/Pods-YuMi.debug.xcconfig"; sourceTree = "<group>"; };
F1D8556D2931FC86008C418F /* XPRoomYearActivityView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomYearActivityView.h; sourceTree = "<group>"; }; F1D8556D2931FC86008C418F /* XPRoomYearActivityView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XPRoomYearActivityView.h; sourceTree = "<group>"; };
F1D8556E2931FC86008C418F /* XPRoomYearActivityView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPRoomYearActivityView.m; sourceTree = "<group>"; }; F1D8556E2931FC86008C418F /* XPRoomYearActivityView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XPRoomYearActivityView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -4821,11 +4831,11 @@
237701082BCF73CE00D661F1 /* Security.framework in Frameworks */, 237701082BCF73CE00D661F1 /* Security.framework in Frameworks */,
4CD15D922D7EC2AC00D9279F /* CoreTelephony.framework in Frameworks */, 4CD15D922D7EC2AC00D9279F /* CoreTelephony.framework in Frameworks */,
234489082AC3C5DA0070E5D5 /* SudMGP.framework in Frameworks */, 234489082AC3C5DA0070E5D5 /* SudMGP.framework in Frameworks */,
73FFADDC93E195344047A2EC /* Pods_YuMi.framework in Frameworks */,
186A531926FC592100D67B2C /* libresolv.tbd in Frameworks */, 186A531926FC592100D67B2C /* libresolv.tbd in Frameworks */,
E87888F42738C30E00BF1D57 /* StoreKit.framework in Frameworks */, E87888F42738C30E00BF1D57 /* StoreKit.framework in Frameworks */,
9BA8A47727C60DF7000365A3 /* AVFoundation.framework in Frameworks */, 9BA8A47727C60DF7000365A3 /* AVFoundation.framework in Frameworks */,
9BA8A47527C60D9F000365A3 /* AudioToolbox.framework in Frameworks */, 9BA8A47527C60D9F000365A3 /* AudioToolbox.framework in Frameworks */,
6996748A711C8E6931880AD0 /* Pods_YuMi.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -6473,6 +6483,7 @@
4C0642922E98EF0A00BAF413 /* E-P */ = { 4C0642922E98EF0A00BAF413 /* E-P */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4C59C0FC2EA2508F00D1F7BD /* NewMessage */,
4CD19C852E9CB31C0069DAA0 /* NewLogin */, 4CD19C852E9CB31C0069DAA0 /* NewLogin */,
4C1E98C22E9A45160031AE79 /* Common */, 4C1E98C22E9A45160031AE79 /* Common */,
4C0642752E97BD6D00BAF413 /* NewMine */, 4C0642752E97BD6D00BAF413 /* NewMine */,
@@ -6532,6 +6543,18 @@
path = GZIP; path = GZIP;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4C59C0FC2EA2508F00D1F7BD /* NewMessage */ = {
isa = PBXGroup;
children = (
4C59C0F72EA2508F00D1F7BD /* EPBaseListViewController.swift */,
4C59C0F82EA2508F00D1F7BD /* EPFriendFollowingFans.swift */,
4C59C0F92EA2508F00D1F7BD /* EPMessageListVC.swift */,
4C59C0FA2EA2508F00D1F7BD /* EPMessageMainViewController.swift */,
4C59C0FB2EA2508F00D1F7BD /* EPMessageSegmentView.swift */,
);
path = NewMessage;
sourceTree = "<group>";
};
4C7989F02D195293006AE07B /* RoomMode */ = { 4C7989F02D195293006AE07B /* RoomMode */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -7965,7 +7988,7 @@
23E56B3B2B03564B00C8DAC9 /* CoreTelephony.framework */, 23E56B3B2B03564B00C8DAC9 /* CoreTelephony.framework */,
E87888F32738C30E00BF1D57 /* StoreKit.framework */, E87888F32738C30E00BF1D57 /* StoreKit.framework */,
186A531826FC591100D67B2C /* libresolv.tbd */, 186A531826FC591100D67B2C /* libresolv.tbd */,
CACF623970097D653132D69A /* Pods_YuMi.framework */, 3148BBD005110C1B57D04595 /* Pods_YuMi.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -7973,8 +7996,8 @@
D09C770DC30B9BAAEAFC7945 /* Pods */ = { D09C770DC30B9BAAEAFC7945 /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7DB00EC07F1D0ADFF900B38D /* Pods-YuMi.debug.xcconfig */, ECF5B2AAE493057A3DBCCFAF /* Pods-YuMi.debug.xcconfig */,
B66633E061B1B34177CD011C /* Pods-YuMi.release.xcconfig */, 56B26C27109C1DD2002D0624 /* Pods-YuMi.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -11634,14 +11657,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 189DD54226DE255600AB55B1 /* Build configuration list for PBXNativeTarget "YuMi" */; buildConfigurationList = 189DD54226DE255600AB55B1 /* Build configuration list for PBXNativeTarget "YuMi" */;
buildPhases = ( buildPhases = (
1865B406E358C680125F108D /* [CP] Check Pods Manifest.lock */, 1BE44CE1939801EC8D8A3B98 /* [CP] Check Pods Manifest.lock */,
189DD52526DE255300AB55B1 /* Sources */, 189DD52526DE255300AB55B1 /* Sources */,
189DD52626DE255300AB55B1 /* Frameworks */, 189DD52626DE255300AB55B1 /* Frameworks */,
189DD52726DE255300AB55B1 /* Resources */, 189DD52726DE255300AB55B1 /* Resources */,
8311720C3643AC2030B96510 /* [CP] Embed Pods Frameworks */,
4C25F8F9E2D1F501119C383D /* [CP] Copy Pods Resources */,
18E7B21326E8CD220064BC9B /* Embed Frameworks */, 18E7B21326E8CD220064BC9B /* Embed Frameworks */,
232C43E62AB0754700D4B2ED /* CopyFiles */, 232C43E62AB0754700D4B2ED /* CopyFiles */,
5D1CA1F69A65602D6A906867 /* [CP] Embed Pods Frameworks */,
86EC598DD301B1F442E90F99 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -11937,7 +11960,7 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
1865B406E358C680125F108D /* [CP] Check Pods Manifest.lock */ = { 1BE44CE1939801EC8D8A3B98 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@@ -11959,28 +11982,7 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
4C25F8F9E2D1F501119C383D /* [CP] Copy Pods Resources */ = { 5D1CA1F69A65602D6A906867 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources.sh\"\n";
showEnvVarsInLog = 0;
};
8311720C3643AC2030B96510 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@@ -12001,6 +12003,27 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
86EC598DD301B1F442E90F99 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-YuMi/Pods-YuMi-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -13068,6 +13091,11 @@
E87AE7FC277AAC450037823A /* XPRoomTagPresenter.m in Sources */, E87AE7FC277AAC450037823A /* XPRoomTagPresenter.m in Sources */,
E85E7B652A4EC35A00B6D00A /* XPExchangeDiamondsModel.m in Sources */, E85E7B652A4EC35A00B6D00A /* XPExchangeDiamondsModel.m in Sources */,
E878894C273A607C00BF1D57 /* XPGiftUserCollectionViewCell.m in Sources */, E878894C273A607C00BF1D57 /* XPGiftUserCollectionViewCell.m in Sources */,
4C59C0FD2EA2508F00D1F7BD /* EPFriendFollowingFans.swift in Sources */,
4C59C0FE2EA2508F00D1F7BD /* EPMessageSegmentView.swift in Sources */,
4C59C0FF2EA2508F00D1F7BD /* EPMessageMainViewController.swift in Sources */,
4C59C1002EA2508F00D1F7BD /* EPBaseListViewController.swift in Sources */,
4C59C1012EA2508F00D1F7BD /* EPMessageListVC.swift in Sources */,
23E9E9A72A80F1C300B792F2 /* XPNewMineHallIncomeVC.m in Sources */, 23E9E9A72A80F1C300B792F2 /* XPNewMineHallIncomeVC.m in Sources */,
2331C1712A5EB71000E1D940 /* XPNobleCenterTableHeadView.m in Sources */, 2331C1712A5EB71000E1D940 /* XPNobleCenterTableHeadView.m in Sources */,
181D7F212727D9DB00B7C059 /* SocialStageView.m in Sources */, 181D7F212727D9DB00B7C059 /* SocialStageView.m in Sources */,
@@ -13457,6 +13485,7 @@
189DD54026DE255600AB55B1 /* Debug */ = { 189DD54026DE255600AB55B1 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -13516,6 +13545,7 @@
189DD54126DE255600AB55B1 /* Release */ = { 189DD54126DE255600AB55B1 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -13568,7 +13598,7 @@
}; };
189DD54326DE255600AB55B1 /* Debug */ = { 189DD54326DE255600AB55B1 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7DB00EC07F1D0ADFF900B38D /* Pods-YuMi.debug.xcconfig */; baseConfigurationReference = ECF5B2AAE493057A3DBCCFAF /* Pods-YuMi.debug.xcconfig */;
buildSettings = { buildSettings = {
APP_DISPLAY_NAME = "E-Party DEBUG"; APP_DISPLAY_NAME = "E-Party DEBUG";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@@ -13583,12 +13613,8 @@
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/YuMi/Main/RTC/Library",
"$(PROJECT_DIR)/YuMi/Modules/YMRTC/Library",
"$(PROJECT_DIR)/YuMi/Resources/Client",
"$(PROJECT_DIR)/YuMi/Library", "$(PROJECT_DIR)/YuMi/Library",
"$(PROJECT_DIR)/YuMi/Tools", "$(PROJECT_DIR)/YuMi/Tools",
"$(PROJECT_DIR)/YuMi/Tools/TencentOpenApiSDK",
); );
GCC_PREFIX_HEADER = YuMi/Structure/PrefixHeader.pch; GCC_PREFIX_HEADER = YuMi/Structure/PrefixHeader.pch;
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
@@ -13830,7 +13856,7 @@
}; };
189DD54426DE255600AB55B1 /* Release */ = { 189DD54426DE255600AB55B1 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = B66633E061B1B34177CD011C /* Pods-YuMi.release.xcconfig */; baseConfigurationReference = 56B26C27109C1DD2002D0624 /* Pods-YuMi.release.xcconfig */;
buildSettings = { buildSettings = {
APP_DISPLAY_NAME = "E-Party"; APP_DISPLAY_NAME = "E-Party";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
@@ -13844,12 +13870,8 @@
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/YuMi/Main/RTC/Library",
"$(PROJECT_DIR)/YuMi/Modules/YMRTC/Library",
"$(PROJECT_DIR)/YuMi/Resources/Client",
"$(PROJECT_DIR)/YuMi/Library", "$(PROJECT_DIR)/YuMi/Library",
"$(PROJECT_DIR)/YuMi/Tools", "$(PROJECT_DIR)/YuMi/Tools",
"$(PROJECT_DIR)/YuMi/Tools/TencentOpenApiSDK",
); );
GCC_PREFIX_HEADER = YuMi/Structure/PrefixHeader.pch; GCC_PREFIX_HEADER = YuMi/Structure/PrefixHeader.pch;
INFOPLIST_FILE = YuMi/Info.plist; INFOPLIST_FILE = YuMi/Info.plist;

View File

@@ -6,15 +6,10 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate> @interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window; @property (strong, nonatomic) UIWindow *window;
@property(nonatomic,strong,readonly)NSManagedObjectContext *managedObjectContext;
@property(nonatomic,strong,readonly)NSManagedObjectModel *managedObjectModel;
@property(nonatomic,strong,readonly)NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end @end

View File

@@ -342,83 +342,4 @@ void qg_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const
// } // }
//} //}
#pragma mark - Core Data stack
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
-(NSURL *)applicationDocumentsDirectory{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"_1_______" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"_1_______.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
// NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
// NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
@end @end

View File

@@ -0,0 +1,54 @@
//
// EPBaseListViewController.swift
// YuMi
//
// A lightweight table-view base class used by EP Message subpages.
//
import UIKit
import SnapKit
class EPBaseListViewController<Cell: UITableViewCell>: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView(frame: .zero, style: .plain)
var itemsCount: Int = 0 { didSet { tableView.reloadData() } }
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(named: "ep.background.dark") ?? UIColor.black.withAlphaComponent(0.9)
tableView.backgroundColor = .clear
tableView.separatorStyle = .none
tableView.showsVerticalScrollIndicator = false
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = 72
tableView.contentInsetAdjustmentBehavior = .never
tableView.keyboardDismissMode = .onDrag
tableView.register(Cell.self, forCellReuseIdentifier: "cell")
view.addSubview(tableView)
tableView.snp.makeConstraints { make in
make.edges.equalTo(view.safeAreaLayoutGuide)
}
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemsCount
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
cell.backgroundColor = .clear
return cell
}
// MARK: - Helpers
func simulateItems(_ count: Int) {
itemsCount = count
}
}

View File

@@ -0,0 +1,126 @@
import UIKit
final class EPFriendListVC: EPBaseListViewController<EPUserBriefCell> {
override func viewDidLoad() { super.viewDidLoad(); simulateItems(6) }
}
final class EPFollowingListVC: EPBaseListViewController<EPUserBriefCell> {
override func viewDidLoad() { super.viewDidLoad(); simulateItems(10) }
}
final class EPFansListVC: EPBaseListViewController<EPUserBriefCell> {
override func viewDidLoad() { super.viewDidLoad(); simulateItems(12) }
}
final class EPUserBriefCell: UITableViewCell {
private let avatar = UIImageView()
private let nameLabel = UILabel()
private let subtitleLabel = UILabel()
private let followButton = EPFollowButton()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
required init?(coder: NSCoder) { super.init(coder: coder); setup() }
private func setup() {
selectionStyle = .none
backgroundColor = .clear
avatar.contentMode = .scaleAspectFill
avatar.layer.cornerRadius = 24
avatar.layer.masksToBounds = true
avatar.image = UIImage(named: "pi_login_new_logo")
nameLabel.font = .systemFont(ofSize: 20, weight: .semibold)
nameLabel.textColor = .white
nameLabel.text = "Momoyy"
subtitleLabel.font = .systemFont(ofSize: 16)
subtitleLabel.textColor = UIColor.white.withAlphaComponent(0.6)
subtitleLabel.text = "Welcome to play"
contentView.addSubview(avatar)
contentView.addSubview(nameLabel)
contentView.addSubview(subtitleLabel)
contentView.addSubview(followButton)
avatar.translatesAutoresizingMaskIntoConstraints = false
nameLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
followButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatar.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
avatar.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
avatar.widthAnchor.constraint(equalToConstant: 48),
avatar.heightAnchor.constraint(equalToConstant: 48),
nameLabel.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 12),
nameLabel.topAnchor.constraint(equalTo: avatar.topAnchor, constant: -2),
subtitleLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor),
subtitleLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 6),
followButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
followButton.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
followButton.widthAnchor.constraint(equalToConstant: 120),
followButton.heightAnchor.constraint(equalToConstant: 40)
])
followButton.setFollowed(false)
}
}
final class EPFollowButton: UIButton {
private var isFollowedState: Bool = false
override init(frame: CGRect) { super.init(frame: frame); setup() }
required init?(coder: NSCoder) { super.init(coder: coder); setup() }
private func setup() {
titleLabel?.font = .systemFont(ofSize: 18, weight: .semibold)
layer.cornerRadius = 20
layer.masksToBounds = true
addTarget(self, action: #selector(onTap), for: .touchUpInside)
}
func setFollowed(_ followed: Bool) {
isFollowedState = followed
if followed {
setTitle("Followed", for: .normal)
backgroundColor = .clear
layer.borderWidth = 1
layer.borderColor = UIColor.systemPurple.withAlphaComponent(0.6).cgColor
setTitleColor(UIColor.systemPurple.withAlphaComponent(0.9), for: .normal)
} else {
setTitle("Follow", for: .normal)
layer.borderWidth = 0
setTitleColor(.white, for: .normal)
setGradientBackground()
}
}
@objc private func onTap() { setFollowed(!isFollowedState) }
private func setGradientBackground() {
let gradient = CAGradientLayer()
gradient.colors = [UIColor.systemPink.cgColor, UIColor.systemPurple.cgColor]
gradient.startPoint = CGPoint(x: 0, y: 0.5)
gradient.endPoint = CGPoint(x: 1, y: 0.5)
gradient.frame = bounds
gradient.cornerRadius = layer.cornerRadius
layer.sublayers?.removeAll(where: { $0 is CAGradientLayer })
layer.insertSublayer(gradient, at: 0)
}
override func layoutSubviews() {
super.layoutSubviews()
if !isFollowedState { setGradientBackground() }
}
}

View File

@@ -0,0 +1,90 @@
import UIKit
final class EPMessageListVC: EPBaseListViewController<EPMessageCell> {
override func viewDidLoad() {
super.viewDidLoad()
simulateItems(8)
}
}
// MARK: - Cell
final class EPMessageCell: UITableViewCell {
private let avatar = UIImageView()
private let nameLabel = UILabel()
private let subtitleLabel = UILabel()
private let timeLabel = UILabel()
private let unreadView = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
required init?(coder: NSCoder) { super.init(coder: coder); setup() }
private func setup() {
selectionStyle = .none
backgroundColor = .clear
avatar.contentMode = .scaleAspectFill
avatar.layer.cornerRadius = 24
avatar.layer.masksToBounds = true
avatar.image = UIImage(named: "pi_login_new_logo")
nameLabel.font = .systemFont(ofSize: 20, weight: .semibold)
nameLabel.textColor = .white
nameLabel.text = "Momoyy"
subtitleLabel.font = .systemFont(ofSize: 16)
subtitleLabel.textColor = UIColor.white.withAlphaComponent(0.6)
subtitleLabel.text = "Nice to meet you"
timeLabel.font = .systemFont(ofSize: 14)
timeLabel.textColor = UIColor.white.withAlphaComponent(0.5)
timeLabel.text = "11:03"
unreadView.backgroundColor = UIColor.systemRed
unreadView.textColor = .white
unreadView.font = .systemFont(ofSize: 12, weight: .bold)
unreadView.textAlignment = .center
unreadView.layer.cornerRadius = 12
unreadView.layer.masksToBounds = true
unreadView.text = "99+"
contentView.addSubview(avatar)
contentView.addSubview(nameLabel)
contentView.addSubview(subtitleLabel)
contentView.addSubview(timeLabel)
contentView.addSubview(unreadView)
avatar.translatesAutoresizingMaskIntoConstraints = false
nameLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
timeLabel.translatesAutoresizingMaskIntoConstraints = false
unreadView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatar.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
avatar.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
avatar.widthAnchor.constraint(equalToConstant: 48),
avatar.heightAnchor.constraint(equalToConstant: 48),
nameLabel.leadingAnchor.constraint(equalTo: avatar.trailingAnchor, constant: 12),
nameLabel.topAnchor.constraint(equalTo: avatar.topAnchor, constant: -2),
subtitleLabel.leadingAnchor.constraint(equalTo: nameLabel.leadingAnchor),
subtitleLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor, constant: 6),
timeLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
timeLabel.topAnchor.constraint(equalTo: nameLabel.topAnchor),
unreadView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
unreadView.centerYAnchor.constraint(equalTo: subtitleLabel.centerYAnchor),
unreadView.widthAnchor.constraint(greaterThanOrEqualToConstant: 40),
unreadView.heightAnchor.constraint(equalToConstant: 24)
])
}
}

View File

@@ -0,0 +1,92 @@
import UIKit
import SnapKit
final class EPMessageMainViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
//
var unreadCountDidChange: ((Int)->Void)?
private let segment = EPMessageSegmentView()
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
private lazy var pages: [UIViewController] = {
return [
EPMessageListVC(),
EPFriendListVC(),
EPFollowingListVC(),
EPFansListVC()
]
}()
private var currentIndex: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black.withAlphaComponent(0.92)
title = YMLocalizedString("XPSessionMainViewController0")
setupSegment()
setupPageVC()
//
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
self?.unreadCountDidChange?(12)
}
}
private func setupSegment() {
view.addSubview(segment)
segment.snp.makeConstraints { make in
make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(8)
make.leading.trailing.equalToSuperview().inset(20)
make.height.equalTo(48)
}
segment.didSelect = { [weak self] index in
self?.setPage(index: index, animated: true)
}
}
private func setupPageVC() {
addChild(pageVC)
view.addSubview(pageVC.view)
pageVC.view.backgroundColor = .clear
pageVC.view.snp.makeConstraints { make in
make.top.equalTo(segment.snp.bottom).offset(8)
make.leading.trailing.bottom.equalTo(view.safeAreaLayoutGuide)
}
pageVC.didMove(toParent: self)
pageVC.dataSource = self
pageVC.delegate = self
pageVC.setViewControllers([pages[0]], direction: .forward, animated: false)
}
private func setPage(index: Int, animated: Bool) {
guard index != currentIndex, index >= 0, index < pages.count else { return }
let direction: UIPageViewController.NavigationDirection = index > currentIndex ? .forward : .reverse
pageVC.setViewControllers([pages[index]], direction: direction, animated: animated)
currentIndex = index
segment.select(index: index, animated: animated)
title = segment.titles[index]
}
// MARK: - UIPageViewControllerDataSource
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let idx = pages.firstIndex(of: viewController), idx > 0 else { return nil }
return pages[idx - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let idx = pages.firstIndex(of: viewController), idx < pages.count - 1 else { return nil }
return pages[idx + 1]
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard completed, let vc = pageViewController.viewControllers?.first, let idx = pages.firstIndex(of: vc) else { return }
currentIndex = idx
segment.select(index: idx, animated: true)
title = segment.titles[idx]
}
}

View File

@@ -0,0 +1,84 @@
// A simple segmented control with underline indicator for four tabs
import UIKit
import SnapKit
final class EPMessageSegmentView: UIView {
enum Segment: Int, CaseIterable { case message=0, friend, following, fans }
var titles: [String] = [
YMLocalizedString("XPSessionMainViewController0"),
YMLocalizedString("XPSessionMainViewController1"),
YMLocalizedString("XPSessionMainViewController2"),
YMLocalizedString("XPSessionMainViewController3")
]
var didSelect: ((Int)->Void)?
private var buttons: [UIButton] = []
private let indicator = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) { super.init(coder: coder); setup() }
private func setup() {
backgroundColor = .clear
let stack = UIStackView()
stack.axis = .horizontal
stack.alignment = .fill
stack.distribution = .fillEqually
stack.spacing = 0
addSubview(stack)
stack.snp.makeConstraints { $0.edges.equalToSuperview() }
for (idx, title) in titles.enumerated() {
let b = UIButton(type: .custom)
b.tag = idx
b.setTitle(title, for: .normal)
b.setTitleColor(UIColor.white.withAlphaComponent(0.6), for: .normal)
b.setTitleColor(.white, for: .selected)
b.titleLabel?.font = .systemFont(ofSize: 24, weight: idx == 0 ? .heavy : .regular)
b.addTarget(self, action: #selector(onTap(_:)), for: .touchUpInside)
buttons.append(b)
stack.addArrangedSubview(b)
}
indicator.backgroundColor = UIColor.systemPink
addSubview(indicator)
layoutIfNeeded()
select(index: 0, animated: false)
}
@objc private func onTap(_ sender: UIButton) {
select(index: sender.tag, animated: true)
didSelect?(sender.tag)
}
func select(index: Int, animated: Bool) {
guard index >= 0 && index < buttons.count else { return }
for (i,b) in buttons.enumerated() {
b.isSelected = (i == index)
b.titleLabel?.font = .systemFont(ofSize: 24, weight: b.isSelected ? .heavy : .regular)
}
let target = buttons[index]
let width = target.bounds.width
let y = bounds.height - 4
let frame = CGRect(x: CGFloat(index) * width + width*0.15, y: y, width: width*0.7, height: 3)
if animated {
UIView.animate(withDuration: 0.2) {
self.indicator.frame = frame
}
} else {
indicator.frame = frame
}
}
}

View File

@@ -1,14 +1,10 @@
//
// EPMomentPublishViewController.m
// YuMi
//
// Created by AI on 2025-10-10. // Created by AI on 2025-10-10.
//
// NOTE: // NOTE:
// XPMonentsPublishViewController UI (addTopicView)
// 使
// : YuMi/Modules/YMMonents/View/XPMonentsPublishTopicView
#import "EPMomentPublishViewController.h" #import "EPMomentPublishViewController.h"
#import <Masonry/Masonry.h> #import <Masonry/Masonry.h>
@@ -20,7 +16,7 @@
#import "EPEmotionColorStorage.h" #import "EPEmotionColorStorage.h"
#import "UIView+GradientLayer.h" #import "UIView+GradientLayer.h"
//
NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNotification"; NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNotification";
@interface EPMomentPublishViewController () <UICollectionViewDataSource, UICollectionViewDelegate, TZImagePickerControllerDelegate, UITextViewDelegate> @interface EPMomentPublishViewController () <UICollectionViewDataSource, UICollectionViewDelegate, TZImagePickerControllerDelegate, UITextViewDelegate>
@@ -37,10 +33,10 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
@property (nonatomic, strong) UIButton *emotionButton; @property (nonatomic, strong) UIButton *emotionButton;
@property (nonatomic, strong) UICollectionView *collectionView; @property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSMutableArray<UIImage *> *images; @property (nonatomic, strong) NSMutableArray<UIImage *> *images;
@property (nonatomic, strong) NSMutableArray *selectedAssets; // TZImagePicker @property (nonatomic, strong) NSMutableArray *selectedAssets;
@property (nonatomic, copy) NSString *selectedEmotionColor; // @property (nonatomic, copy) NSString *selectedEmotionColor;
@property (nonatomic, assign) BOOL hasAddedGradient; // @property (nonatomic, assign) BOOL hasAddedGradient;
@end @end
@@ -51,27 +47,27 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
self.view.backgroundColor = [UIColor colorWithRed:0x0C/255.0 green:0x05/255.0 blue:0x27/255.0 alpha:1.0]; self.view.backgroundColor = [UIColor colorWithRed:0x0C/255.0 green:0x05/255.0 blue:0x27/255.0 alpha:1.0];
[self setupUI]; [self setupUI];
//
[self loadUserSignatureColor]; [self loadUserSignatureColor];
} }
- (void)viewDidLayoutSubviews { - (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews]; [super viewDidLayoutSubviews];
//
if (!self.hasAddedGradient && self.publishButton.bounds.size.width > 0) { if (!self.hasAddedGradient && self.publishButton.bounds.size.width > 0) {
// 使EPLoginConfig.Colors
// gradientStart: #F854FC, gradientEnd: #500FFF
[self.publishButton addGradientBackgroundWithColors:@[ [self.publishButton addGradientBackgroundWithColors:@[
[UIColor colorWithRed:0xF8/255.0 green:0x54/255.0 blue:0xFC/255.0 alpha:1.0], // #F854FC [UIColor colorWithRed:0xF8/255.0 green:0x54/255.0 blue:0xFC/255.0 alpha:1.0],
[UIColor colorWithRed:0x50/255.0 green:0x0F/255.0 blue:0xFF/255.0 alpha:1.0] // #500FFF [UIColor colorWithRed:0x50/255.0 green:0x0F/255.0 blue:0xFF/255.0 alpha:1.0]
] startPoint:CGPointMake(0, 0.5) endPoint:CGPointMake(1, 0.5) cornerRadius:25]; ] startPoint:CGPointMake(0, 0.5) endPoint:CGPointMake(1, 0.5) cornerRadius:25];
self.hasAddedGradient = YES; self.hasAddedGradient = YES;
} }
} }
///
- (void)loadUserSignatureColor { - (void)loadUserSignatureColor {
NSString *signatureColor = [EPEmotionColorStorage userSignatureColor]; NSString *signatureColor = [EPEmotionColorStorage userSignatureColor];
if (signatureColor) { if (signatureColor) {
@@ -86,7 +82,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
[self.view addSubview:self.contentView]; [self.view addSubview:self.contentView];
[self.navView addSubview:self.backButton]; [self.navView addSubview:self.backButton];
[self.navView addSubview:self.titleLabel]; [self.navView addSubview:self.titleLabel];
//
[self.contentView addSubview:self.textView]; [self.contentView addSubview:self.textView];
[self.contentView addSubview:self.limitLabel]; [self.contentView addSubview:self.limitLabel];
[self.contentView addSubview:self.lineView]; [self.contentView addSubview:self.lineView];
@@ -107,7 +103,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
make.centerX.equalTo(self.navView); make.centerX.equalTo(self.navView);
make.centerY.equalTo(self.backButton); make.centerY.equalTo(self.backButton);
}]; }];
//
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) { [self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.view); make.leading.trailing.equalTo(self.view);
make.top.equalTo(self.navView.mas_bottom); make.top.equalTo(self.navView.mas_bottom);
@@ -128,16 +124,14 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
make.height.mas_equalTo(1); make.height.mas_equalTo(1);
}]; }];
//
[self.emotionButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.emotionButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.contentView).inset(15); make.leading.trailing.equalTo(self.contentView).inset(15);
make.top.equalTo(self.lineView.mas_bottom).offset(10); make.top.equalTo(self.lineView.mas_bottom).offset(10);
make.height.mas_equalTo(44); make.height.mas_equalTo(44);
}]; }];
// 3
// itemW = ( - 30 - 20) / 3
// = 3itemW + 2(10*2)
CGFloat itemW = (KScreenWidth - 15*2 - 10*2)/3.0; CGFloat itemW = (KScreenWidth - 15*2 - 10*2)/3.0;
CGFloat collectionHeight = itemW * 3 + 10 * 2; CGFloat collectionHeight = itemW * 3 + 10 * 2;
@@ -147,7 +141,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
make.height.mas_equalTo(collectionHeight); make.height.mas_equalTo(collectionHeight);
}]; }];
//
[self.publishButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.publishButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.view).inset(20); make.leading.trailing.equalTo(self.view).inset(20);
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-20); make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom).offset(-20);
@@ -164,7 +158,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
- (void)onEmotionButtonTapped { - (void)onEmotionButtonTapped {
EPEmotionColorPicker *picker = [[EPEmotionColorPicker alloc] init]; EPEmotionColorPicker *picker = [[EPEmotionColorPicker alloc] init];
//
picker.preselectedColor = self.selectedEmotionColor; picker.preselectedColor = self.selectedEmotionColor;
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
@@ -178,10 +172,10 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
- (void)updateEmotionButtonAppearance { - (void)updateEmotionButtonAppearance {
if (self.selectedEmotionColor) { if (self.selectedEmotionColor) {
//
UIColor *color = [self colorFromHex:self.selectedEmotionColor]; UIColor *color = [self colorFromHex:self.selectedEmotionColor];
//
UIView *colorDot = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; UIView *colorDot = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
colorDot.backgroundColor = color; colorDot.backgroundColor = color;
colorDot.layer.cornerRadius = 10; colorDot.layer.cornerRadius = 10;
@@ -189,7 +183,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
colorDot.layer.borderWidth = 2; colorDot.layer.borderWidth = 2;
colorDot.layer.borderColor = [UIColor whiteColor].CGColor; colorDot.layer.borderColor = [UIColor whiteColor].CGColor;
// UIImage
UIGraphicsBeginImageContextWithOptions(colorDot.bounds.size, NO, 0); UIGraphicsBeginImageContextWithOptions(colorDot.bounds.size, NO, 0);
[colorDot.layer renderInContext:UIGraphicsGetCurrentContext()]; [colorDot.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *colorDotImage = UIGraphicsGetImageFromCurrentImageContext(); UIImage *colorDotImage = UIGraphicsGetImageFromCurrentImageContext();
@@ -197,7 +191,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
[self.emotionButton setImage:colorDotImage forState:UIControlStateNormal]; [self.emotionButton setImage:colorDotImage forState:UIControlStateNormal];
//
NSString *emotionName = [EPEmotionColorStorage emotionNameForColor:self.selectedEmotionColor]; NSString *emotionName = [EPEmotionColorStorage emotionNameForColor:self.selectedEmotionColor];
NSString *title = emotionName NSString *title = emotionName
? [NSString stringWithFormat:@" Selected Emotion: %@", emotionName] ? [NSString stringWithFormat:@" Selected Emotion: %@", emotionName]
@@ -212,7 +206,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
unsigned rgbValue = 0; unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString]; NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // # [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue]; [scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0xFF00) >> 8)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0
@@ -223,20 +217,20 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
- (void)onPublish { - (void)onPublish {
[self.view endEditing:YES]; [self.view endEditing:YES];
//
if (self.textView.text.length == 0 && self.images.count == 0) { if (self.textView.text.length == 0 && self.images.count == 0) {
[EPProgressHUD showError:YMLocalizedString(@"publish.content_or_image_required")]; [EPProgressHUD showError:YMLocalizedString(@"publish.content_or_image_required")];
return; return;
} }
// Swift API Helper
EPMomentAPISwiftHelper *apiHelper = [[EPMomentAPISwiftHelper alloc] init]; EPMomentAPISwiftHelper *apiHelper = [[EPMomentAPISwiftHelper alloc] init];
//
NSString *emotionColorToSave = self.selectedEmotionColor; NSString *emotionColorToSave = self.selectedEmotionColor;
if (self.images.count > 0) { if (self.images.count > 0) {
//
[[EPSDKManager shared] uploadImages:self.images [[EPSDKManager shared] uploadImages:self.images
progress:^(NSInteger uploaded, NSInteger total) { progress:^(NSInteger uploaded, NSInteger total) {
[EPProgressHUD showProgress:uploaded total:total]; [EPProgressHUD showProgress:uploaded total:total];
@@ -247,11 +241,11 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
content:self.textView.text ?: @"" content:self.textView.text ?: @""
resList:resList resList:resList
completion:^{ completion:^{
//
if (emotionColorToSave) { if (emotionColorToSave) {
[self savePendingEmotionColor:emotionColorToSave]; [self savePendingEmotionColor:emotionColorToSave];
} }
//
[[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil];
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
} failure:^(NSInteger code, NSString *msg) { } failure:^(NSInteger code, NSString *msg) {
@@ -265,16 +259,16 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
NSLog(@"上传失败: %@", errorMsg); NSLog(@"上传失败: %@", errorMsg);
}]; }];
} else { } else {
//
[apiHelper publishMomentWithType:@"0" [apiHelper publishMomentWithType:@"0"
content:self.textView.text content:self.textView.text
resList:@[] resList:@[]
completion:^{ completion:^{
//
if (emotionColorToSave) { if (emotionColorToSave) {
[self savePendingEmotionColor:emotionColorToSave]; [self savePendingEmotionColor:emotionColorToSave];
} }
//
[[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:EPMomentPublishSuccessNotification object:nil];
[self dismissViewControllerAnimated:YES completion:nil]; [self dismissViewControllerAnimated:YES completion:nil];
} failure:^(NSInteger code, NSString *msg) { } failure:^(NSInteger code, NSString *msg) {
@@ -284,7 +278,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
} }
} }
///
- (void)savePendingEmotionColor:(NSString *)color { - (void)savePendingEmotionColor:(NSString *)color {
[[NSUserDefaults standardUserDefaults] setObject:color forKey:@"EP_Pending_Emotion_Color"]; [[NSUserDefaults standardUserDefaults] setObject:color forKey:@"EP_Pending_Emotion_Color"];
[[NSUserDefaults standardUserDefaults] setObject:@([[NSDate date] timeIntervalSince1970]) forKey:@"EP_Pending_Emotion_Timestamp"]; [[NSUserDefaults standardUserDefaults] setObject:@([[NSDate date] timeIntervalSince1970]) forKey:@"EP_Pending_Emotion_Timestamp"];
@@ -294,14 +288,14 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
#pragma mark - UICollectionView #pragma mark - UICollectionView
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.images.count + 1; // return self.images.count + 1;
} }
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ep.publish.cell" forIndexPath:indexPath]; UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ep.publish.cell" forIndexPath:indexPath];
cell.contentView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.06]; cell.contentView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.06];
cell.contentView.layer.cornerRadius = 12; cell.contentView.layer.cornerRadius = 12;
//
for (UIView *sub in cell.contentView.subviews) { [sub removeFromSuperview]; } for (UIView *sub in cell.contentView.subviews) { [sub removeFromSuperview]; }
BOOL showAdd = (self.images.count < 9) && (indexPath.item == self.images.count); BOOL showAdd = (self.images.count < 9) && (indexPath.item == self.images.count);
if (showAdd) { if (showAdd) {
@@ -327,15 +321,16 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
TZImagePickerController *picker = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self]; TZImagePickerController *picker = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self];
picker.allowPickingVideo = NO; picker.allowPickingVideo = NO;
picker.allowTakeVideo = NO; picker.allowTakeVideo = NO;
picker.selectedAssets = self.selectedAssets; // picker.allowCameraLocation = NO; //
picker.maxImagesCount = 9; // picker.selectedAssets = self.selectedAssets;
picker.maxImagesCount = 9;
[self presentViewController:picker animated:YES completion:nil]; [self presentViewController:picker animated:YES completion:nil];
} }
} }
#pragma mark - TZImagePickerControllerDelegate #pragma mark - TZImagePickerControllerDelegate
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos { - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos {
// 9
for (NSInteger i = 0; i < assets.count; i++) { for (NSInteger i = 0; i < assets.count; i++) {
id asset = assets[i]; id asset = assets[i];
UIImage *img = [photos xpSafeObjectAtIndex:i] ?: photos[i]; UIImage *img = [photos xpSafeObjectAtIndex:i] ?: photos[i];
@@ -358,12 +353,24 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
#pragma mark - Lazy #pragma mark - Lazy
- (UIView *)navView { if (!_navView) { _navView = [UIView new]; _navView.backgroundColor = [UIColor clearColor]; } return _navView; } - (UIView *)navView { if (!_navView) { _navView = [UIView new]; _navView.backgroundColor = [UIColor clearColor]; } return _navView; }
- (UIButton *)backButton { if (!_backButton) { _backButton = [UIButton buttonWithType:UIButtonTypeCustom]; [_backButton setImage:[UIImage imageNamed:@"common_nav_back"] forState:UIControlStateNormal]; [_backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside]; } return _backButton; } - (UIButton *)backButton {
if (!_backButton) {
_backButton = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *backImage = [UIImage systemImageNamed:@"chevron.left"];
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:20 weight:UIImageSymbolWeightMedium];
backImage = [backImage imageByApplyingSymbolConfiguration:config];
[_backButton setImage:backImage forState:UIControlStateNormal];
[_backButton setTintColor:[UIColor whiteColor]];
[_backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
}
return _backButton;
}
- (UILabel *)titleLabel { - (UILabel *)titleLabel {
if (!_titleLabel) { if (!_titleLabel) {
_titleLabel = [UILabel new]; _titleLabel = [UILabel new];
_titleLabel.text = YMLocalizedString(@"publish.title"); _titleLabel.text = YMLocalizedString(@"publish.title");
_titleLabel.textColor = [UIColor whiteColor]; // _titleLabel.textColor = [UIColor whiteColor];
_titleLabel.font = [UIFont systemFontOfSize:17]; _titleLabel.font = [UIFont systemFontOfSize:17];
} }
return _titleLabel; return _titleLabel;
@@ -375,8 +382,8 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
[_publishButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [_publishButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_publishButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium]; _publishButton.titleLabel.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];
_publishButton.layer.cornerRadius = 25; _publishButton.layer.cornerRadius = 25;
_publishButton.layer.masksToBounds = NO; // NO 便 _publishButton.layer.masksToBounds = NO;
// viewDidLayoutSubviews
[_publishButton addTarget:self action:@selector(onPublish) forControlEvents:UIControlEventTouchUpInside]; [_publishButton addTarget:self action:@selector(onPublish) forControlEvents:UIControlEventTouchUpInside];
} }
return _publishButton; return _publishButton;
@@ -386,9 +393,9 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
if (!_textView) { if (!_textView) {
_textView = [SZTextView new]; _textView = [SZTextView new];
_textView.placeholder = @"Enter Content"; _textView.placeholder = @"Enter Content";
_textView.textColor = [UIColor whiteColor]; // _textView.textColor = [UIColor whiteColor];
_textView.placeholderTextColor = [[UIColor whiteColor] colorWithAlphaComponent:0.4]; // _textView.placeholderTextColor = [[UIColor whiteColor] colorWithAlphaComponent:0.4];
_textView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.08]; // _textView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.08];
_textView.layer.cornerRadius = 12; _textView.layer.cornerRadius = 12;
_textView.layer.masksToBounds = YES; _textView.layer.masksToBounds = YES;
_textView.font = [UIFont systemFontOfSize:15]; _textView.font = [UIFont systemFontOfSize:15];
@@ -400,7 +407,7 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
if (!_limitLabel) { if (!_limitLabel) {
_limitLabel = [UILabel new]; _limitLabel = [UILabel new];
_limitLabel.text = @"0/500"; _limitLabel.text = @"0/500";
_limitLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6]; // _limitLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6];
_limitLabel.font = [UIFont systemFontOfSize:12]; _limitLabel.font = [UIFont systemFontOfSize:12];
} }
return _limitLabel; return _limitLabel;
@@ -410,11 +417,11 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
if (!_emotionButton) { if (!_emotionButton) {
_emotionButton = [UIButton buttonWithType:UIButtonTypeCustom]; _emotionButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_emotionButton setTitle:@"🎨 Add Emotion" forState:UIControlStateNormal]; [_emotionButton setTitle:@"🎨 Add Emotion" forState:UIControlStateNormal];
[_emotionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // [_emotionButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
_emotionButton.titleLabel.font = [UIFont systemFontOfSize:15]; _emotionButton.titleLabel.font = [UIFont systemFontOfSize:15];
_emotionButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; _emotionButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
_emotionButton.contentEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 0); _emotionButton.contentEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 0);
_emotionButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.08]; // _emotionButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.08];
_emotionButton.layer.cornerRadius = 8; _emotionButton.layer.cornerRadius = 8;
_emotionButton.layer.masksToBounds = YES; _emotionButton.layer.masksToBounds = YES;
[_emotionButton addTarget:self action:@selector(onEmotionButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_emotionButton addTarget:self action:@selector(onEmotionButtonTapped) forControlEvents:UIControlEventTouchUpInside];
@@ -426,5 +433,3 @@ NSString *const EPMomentPublishSuccessNotification = @"EPMomentPublishSuccessNot
- (NSMutableArray *)selectedAssets { if (!_selectedAssets) { _selectedAssets = [NSMutableArray array]; } return _selectedAssets; } - (NSMutableArray *)selectedAssets { if (!_selectedAssets) { _selectedAssets = [NSMutableArray array]; } return _selectedAssets; }
@end @end

View File

@@ -1,10 +1,8 @@
//
// EPMomentViewController.m
// YuMi
//
// Created by AI on 2025-10-09. // Created by AI on 2025-10-09.
// Copyright © 2025 YuMi. All rights reserved. // Copyright © 2025 YuMi. All rights reserved.
//
#import "EPMomentViewController.h" #import "EPMomentViewController.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@@ -18,13 +16,13 @@
// MARK: - UI Components // MARK: - UI Components
/// MVVMView
@property (nonatomic, strong) EPMomentListView *listView; @property (nonatomic, strong) EPMomentListView *listView;
///
@property (nonatomic, strong) UIImageView *topIconImageView; @property (nonatomic, strong) UIImageView *topIconImageView;
///
@property (nonatomic, strong) UILabel *topTipLabel; @property (nonatomic, strong) UILabel *topTipLabel;
@end @end
@@ -38,24 +36,33 @@
self.title = @"Enjoy your Life Time"; self.title = @"Enjoy your Life Time";
// title
[self.navigationController.navigationBar setTitleTextAttributes:@{ [self.navigationController.navigationBar setTitleTextAttributes:@{
NSForegroundColorAttributeName: [UIColor whiteColor] NSForegroundColorAttributeName: [UIColor whiteColor]
}]; }];
[self setupUI]; [self setupUI];
[self.listView reloadFirstPage];
//
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onMomentPublishSuccess:) selector:@selector(onMomentPublishSuccess:)
name:EPMomentPublishSuccessNotification name:EPMomentPublishSuccessNotification
object:nil]; object:nil];
// NSLog(@"[EPMomentViewController] 页面加载完成UI 已设置");
[self scheduleAutoRefreshIfNeeded]; }
NSLog(@"[EPMomentViewController] 页面加载完成"); - (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"[EPMomentViewController] 首次 viewDidAppear延迟 0.3s 后开始加载数据");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"[EPMomentViewController] 触发首次数据加载");
[self.listView reloadFirstPage];
});
});
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
@@ -73,7 +80,7 @@
make.edges.mas_equalTo(self.view); make.edges.mas_equalTo(self.view);
}]; }];
//
[self.view addSubview:self.topIconImageView]; [self.view addSubview:self.topIconImageView];
[self.topIconImageView mas_makeConstraints:^(MASConstraintMaker *make) { [self.topIconImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.view); make.centerX.equalTo(self.view);
@@ -81,21 +88,21 @@
make.size.mas_equalTo(CGSizeMake(56, 41)); make.size.mas_equalTo(CGSizeMake(56, 41));
}]; }];
//
[self.view addSubview:self.topTipLabel]; [self.view addSubview:self.topTipLabel];
[self.topTipLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.topTipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.topIconImageView.mas_bottom).offset(14); make.top.equalTo(self.topIconImageView.mas_bottom).offset(14);
make.leading.trailing.equalTo(self.view).inset(20); make.leading.trailing.equalTo(self.view).inset(20);
}]; }];
//
[self.view addSubview:self.listView]; [self.view addSubview:self.listView];
[self.listView mas_makeConstraints:^(MASConstraintMaker *make) { [self.listView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.bottom.equalTo(self.view); make.leading.trailing.bottom.equalTo(self.view);
make.top.equalTo(self.topTipLabel.mas_bottom).offset(8); make.top.equalTo(self.topTipLabel.mas_bottom).offset(8);
}]; }];
//
UIImage *addIcon = [UIImage imageNamed:@"icon_moment_add"]; UIImage *addIcon = [UIImage imageNamed:@"icon_moment_add"];
UIButton *publishButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *publishButton = [UIButton buttonWithType:UIButtonTypeCustom];
publishButton.contentMode = UIViewContentModeScaleAspectFit; publishButton.contentMode = UIViewContentModeScaleAspectFit;
@@ -108,26 +115,6 @@
NSLog(@"[EPMomentViewController] UI 设置完成"); NSLog(@"[EPMomentViewController] UI 设置完成");
} }
// VC /
// MARK: - Auto Refresh
///
- (void)scheduleAutoRefreshIfNeeded {
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) self = weakSelf;
if (!self) return;
//
if (self.listView.rawList.count == 0) {
NSLog(@"[EPMomentViewController] ⚠️ 冷启动 1 秒后检测到无数据,自动刷新一次");
[self.listView reloadFirstPage];
} else {
NSLog(@"[EPMomentViewController] ✅ 冷启动 1 秒后检测到已有 %lu 条数据,无需刷新", (unsigned long)self.listView.rawList.count);
}
});
}
// MARK: - Actions // MARK: - Actions
@@ -155,17 +142,16 @@
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
} }
// listView
// MARK: - Lazy Loading // MARK: - Lazy Loading
- (EPMomentListView *)listView { - (EPMomentListView *)listView {
if (!_listView) { if (!_listView) {
_listView = [[EPMomentListView alloc] initWithFrame:CGRectZero]; _listView = [[EPMomentListView alloc] initWithFrame:CGRectZero];
__weak typeof(self) weakSelf = self;
_listView.onSelectMoment = ^(NSInteger index) { _listView.onSelectMoment = ^(NSInteger index) {
__strong typeof(weakSelf) self = weakSelf;
// [self showAlertWithMessage:[NSString stringWithFormat:YMLocalizedString(@"moment.item_clicked"), (long)index]];
}; };
} }
return _listView; return _listView;
@@ -190,6 +176,5 @@
return _topTipLabel; return _topTipLabel;
} }
//
@end @end

View File

@@ -1,10 +1,7 @@
//
// EPEmotionColorStorage.h
// YuMi
//
// Created by AI on 2025-10-14. // Created by AI on 2025-10-14.
// 本地情绪颜色存储管理器(基于 UserDefaults
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@@ -12,47 +9,38 @@ NS_ASSUME_NONNULL_BEGIN
@interface EPEmotionColorStorage : NSObject @interface EPEmotionColorStorage : NSObject
/// 保存动态的情绪颜色
/// @param hexColor Hex 格式颜色值,如 #FF0000
/// @param dynamicId 动态 ID
+ (void)saveColor:(NSString *)hexColor forDynamicId:(NSString *)dynamicId; + (void)saveColor:(NSString *)hexColor forDynamicId:(NSString *)dynamicId;
/// 获取动态关联的情绪颜色
/// @param dynamicId 动态 ID
/// @return Hex 格式颜色值,若未设置则返回 nil
+ (nullable NSString *)colorForDynamicId:(NSString *)dynamicId; + (nullable NSString *)colorForDynamicId:(NSString *)dynamicId;
/// 删除动态的情绪颜色
/// @param dynamicId 动态 ID
+ (void)removeColorForDynamicId:(NSString *)dynamicId; + (void)removeColorForDynamicId:(NSString *)dynamicId;
/// 获取所有预设情绪颜色6种基础情绪
/// @return Hex 颜色数组
+ (NSArray<NSString *> *)allEmotionColors; + (NSArray<NSString *> *)allEmotionColors;
/// 获取随机情绪颜色(不持久化)
+ (NSString *)randomEmotionColor; + (NSString *)randomEmotionColor;
/// 根据颜色值获取情绪名称
/// @param hexColor Hex 格式颜色值,如 #FFD700
/// @return 情绪名称(如 "Joy"),若未匹配返回 nil
+ (nullable NSString *)emotionNameForColor:(NSString *)hexColor; + (nullable NSString *)emotionNameForColor:(NSString *)hexColor;
#pragma mark - User Signature Color #pragma mark - User Signature Color
/// 保存用户专属颜色
+ (void)saveUserSignatureColor:(NSString *)hexColor; + (void)saveUserSignatureColor:(NSString *)hexColor;
/// 获取用户专属颜色
+ (nullable NSString *)userSignatureColor; + (nullable NSString *)userSignatureColor;
/// 是否已设置专属颜色
+ (BOOL)hasUserSignatureColor; + (BOOL)hasUserSignatureColor;
/// 清除专属颜色(调试用)
+ (void)clearUserSignatureColor; + (void)clearUserSignatureColor;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -1,9 +1,7 @@
//
// EPEmotionColorStorage.m
// YuMi
//
// Created by AI on 2025-10-14. // Created by AI on 2025-10-14.
//
#import "EPEmotionColorStorage.h" #import "EPEmotionColorStorage.h"
@@ -44,14 +42,14 @@ static NSString *const kUserSignatureTimestampKey = @"EP_User_Signature_Timestam
+ (NSArray<NSString *> *)allEmotionColors { + (NSArray<NSString *> *)allEmotionColors {
return @[ return @[
@"#FFD700", // Joy- @"#FFD700",
@"#4A90E2", // Sadness- @"#4A90E2",
@"#E74C3C", // Anger- @"#E74C3C",
@"#9B59B6", // Fear- @"#9B59B6",
@"#FF9A3D", // Surprise- @"#FF9A3D",
@"#2ECC71", // Disgust绿- @"#2ECC71",
@"#3498DB", // Trust- @"#3498DB",
@"#F39C12" // Anticipation- @"#F39C12"
]; ];
} }
@@ -67,7 +65,7 @@ static NSString *const kUserSignatureTimestampKey = @"EP_User_Signature_Timestam
NSArray<NSString *> *colors = [self allEmotionColors]; NSArray<NSString *> *colors = [self allEmotionColors];
NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"]; NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"];
//
NSString *upperHex = [hexColor uppercaseString]; NSString *upperHex = [hexColor uppercaseString];
for (NSInteger i = 0; i < colors.count; i++) { for (NSInteger i = 0; i < colors.count; i++) {
if ([[colors[i] uppercaseString] isEqualToString:upperHex]) { if ([[colors[i] uppercaseString] isEqualToString:upperHex]) {
@@ -115,4 +113,3 @@ static NSString *const kUserSignatureTimestampKey = @"EP_User_Signature_Timestam
} }
@end @end

View File

@@ -1,55 +1,47 @@
//
// EPMomentAPISwiftHelper.swift
// YuMi
//
// Created by AI on 2025-10-11. // Created by AI on 2025-10-11.
//
import Foundation import Foundation
/// API Swift
/// OC
@objc class EPMomentAPISwiftHelper: NSObject { @objc class EPMomentAPISwiftHelper: NSObject {
///
/// - Parameters:
/// - nextID: ID
/// - completion: (, ID)
/// - failure: (, )
@objc func fetchLatestMomentsWithNextID( @objc func fetchLatestMomentsWithNextID(
_ nextID: String, _ nextID: String,
completion: @escaping ([MomentsInfoModel], String) -> Void, completion: @escaping ([MomentsInfoModel], String) -> Void,
failure: @escaping (Int, String) -> Void failure: @escaping (Int, String) -> Void
) { ) {
let pageSize = "20" let pageSize = "20"
let types = "0,2" // + let types = "0,2"
NSLog("[EPMomentAPISwiftHelper] 🔄 开始请求动态列表nextID=\(nextID.isEmpty ? "(首页)" : nextID)")
Api.momentsLatestList({ (data, code, msg) in Api.momentsLatestList({ (data, code, msg) in
NSLog("[EPMomentAPISwiftHelper] 📥 收到响应code=\(code)")
if code == 200, let dict = data?.data as? NSDictionary { if code == 200, let dict = data?.data as? NSDictionary {
// 使 MomentsListInfoModel NSLog("[EPMomentAPISwiftHelper] 📦 开始解析数据字典")
// : XPMomentsLatestPresenter.m line 25 / EPLoginService.swift line 34
// Swift 使 mj_object(withKeyValues:) model(withJSON:)
if let listInfo = MomentsListInfoModel.mj_object(withKeyValues: dict) { if let listInfo = MomentsListInfoModel.mj_object(withKeyValues: dict) {
let dynamicList = listInfo.dynamicList let dynamicList = listInfo.dynamicList
let nextDynamicId = listInfo.nextDynamicId let nextDynamicId = listInfo.nextDynamicId
NSLog("[EPMomentAPISwiftHelper] ✅ 解析成功dynamicList.count=\(dynamicList.count), nextDynamicId=\(nextDynamicId)")
completion(dynamicList, nextDynamicId) completion(dynamicList, nextDynamicId)
} else { } else {
// NSLog("[EPMomentAPISwiftHelper] ⚠️ 解析失败,返回空数组")
completion([], "") completion([], "")
} }
} else { } else {
NSLog("[EPMomentAPISwiftHelper] ❌ 请求失败code=\(code), msg=\(msg ?? "无错误信息")")
failure(Int(code), msg ?? YMLocalizedString("error.request_failed")) failure(Int(code), msg ?? YMLocalizedString("error.request_failed"))
} }
}, dynamicId: nextID, pageSize: pageSize, types: types) }, dynamicId: nextID, pageSize: pageSize, types: types)
} }
///
/// - Parameters:
/// - type: "0"=, "2"=
/// - content:
/// - resList:
/// - completion:
/// - failure: (, )
@objc func publishMoment( @objc func publishMoment(
type: String, type: String,
content: String, content: String,
@@ -62,10 +54,9 @@ import Foundation
return return
} }
// worldId
// NOTE: XPMonentsPublishViewController // NOTE: XPMonentsPublishViewController
// 使
// : YuMi/Modules/YMMonents/View/XPMonentsPublishTopicView
Api.momentsPublish({ (data, code, msg) in Api.momentsPublish({ (data, code, msg) in
if code == 200 { if code == 200 {
@@ -76,14 +67,7 @@ import Foundation
}, uid: uid, type: type, worldId: "", content: content, resList: resList) }, uid: uid, type: type, worldId: "", content: content, resList: resList)
} }
/// /
/// - Parameters:
/// - dynamicId: ID
/// - isLike: true=false=
/// - likedUid: UID
/// - worldId: ID
/// - completion:
/// - failure: (, )
@objc func likeMoment( @objc func likeMoment(
dynamicId: String, dynamicId: String,
isLike: Bool, isLike: Bool,
@@ -109,4 +93,3 @@ import Foundation
}, dynamicId: dynamicId, uid: uid, status: status, likedUid: likedUid, worldId: worldIdStr) }, dynamicId: dynamicId, uid: uid, status: status, likedUid: likedUid, worldId: worldIdStr)
} }
} }

View File

@@ -1,9 +1,7 @@
//
// EPEmotionColorPicker.m
// YuMi
//
// Created by AI on 2025-10-14. // Created by AI on 2025-10-14.
//
#import "EPEmotionColorPicker.h" #import "EPEmotionColorPicker.h"
#import "EPEmotionColorWheelView.h" #import "EPEmotionColorWheelView.h"
@@ -39,27 +37,27 @@
- (void)setupUI { - (void)setupUI {
self.backgroundColor = [UIColor clearColor]; self.backgroundColor = [UIColor clearColor];
//
[self addSubview:self.backgroundMask]; [self addSubview:self.backgroundMask];
[self.backgroundMask mas_makeConstraints:^(MASConstraintMaker *make) { [self.backgroundMask mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self); make.edges.equalTo(self);
}]; }];
//
[self addSubview:self.containerView]; [self addSubview:self.containerView];
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.bottom.equalTo(self); make.leading.trailing.bottom.equalTo(self);
make.height.mas_equalTo(450); // make.height.mas_equalTo(450);
}]; }];
//
[self.containerView addSubview:self.titleLabel]; [self.containerView addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.containerView).offset(20); make.top.equalTo(self.containerView).offset(20);
make.centerX.equalTo(self.containerView); make.centerX.equalTo(self.containerView);
}]; }];
// Info
[self.containerView addSubview:self.infoButton]; [self.containerView addSubview:self.infoButton];
[self.infoButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.infoButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.containerView).offset(16); make.leading.equalTo(self.containerView).offset(16);
@@ -67,7 +65,7 @@
make.size.mas_equalTo(CGSizeMake(28, 28)); make.size.mas_equalTo(CGSizeMake(28, 28));
}]; }];
// OK
[self.containerView addSubview:self.okButton]; [self.containerView addSubview:self.okButton];
[self.okButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.okButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.trailing.equalTo(self.containerView).offset(-16); make.trailing.equalTo(self.containerView).offset(-16);
@@ -75,7 +73,7 @@
make.size.mas_equalTo(CGSizeMake(60, 32)); make.size.mas_equalTo(CGSizeMake(60, 32));
}]; }];
//
[self.containerView addSubview:self.selectedColorView]; [self.containerView addSubview:self.selectedColorView];
[self.selectedColorView mas_makeConstraints:^(MASConstraintMaker *make) { [self.selectedColorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleLabel.mas_bottom).offset(20); make.top.equalTo(self.titleLabel.mas_bottom).offset(20);
@@ -84,12 +82,12 @@
make.leading.trailing.equalTo(self.containerView).inset(20); make.leading.trailing.equalTo(self.containerView).inset(20);
}]; }];
// 使
[self.containerView addSubview:self.colorWheelView]; [self.containerView addSubview:self.colorWheelView];
[self.colorWheelView mas_makeConstraints:^(MASConstraintMaker *make) { [self.colorWheelView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.containerView); make.centerX.equalTo(self.containerView);
make.top.equalTo(self.selectedColorView.mas_bottom).offset(20); make.top.equalTo(self.selectedColorView.mas_bottom).offset(20);
make.size.mas_equalTo(CGSizeMake(280, 280)); // make.size.mas_equalTo(CGSizeMake(280, 280));
}]; }];
} }
@@ -119,11 +117,11 @@
make.edges.equalTo(parentView); make.edges.equalTo(parentView);
}]; }];
//
self.backgroundMask.alpha = 0;
self.containerView.transform = CGAffineTransformMakeTranslation(0, 450); //
// self.backgroundMask.alpha = 0;
self.containerView.transform = CGAffineTransformMakeTranslation(0, 450);
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.backgroundMask.alpha = 1; self.backgroundMask.alpha = 1;
self.containerView.transform = CGAffineTransformIdentity; self.containerView.transform = CGAffineTransformIdentity;
@@ -133,7 +131,7 @@
- (void)dismiss { - (void)dismiss {
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.backgroundMask.alpha = 0; self.backgroundMask.alpha = 0;
self.containerView.transform = CGAffineTransformMakeTranslation(0, 450); // self.containerView.transform = CGAffineTransformMakeTranslation(0, 450);
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
[self removeFromSuperview]; [self removeFromSuperview];
}]; }];
@@ -177,12 +175,12 @@
if (!_infoButton) { if (!_infoButton) {
_infoButton = [UIButton buttonWithType:UIButtonTypeCustom]; _infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// 使 info.circle
UIImage *infoIcon = [UIImage systemImageNamed:@"info.circle"]; UIImage *infoIcon = [UIImage systemImageNamed:@"info.circle"];
[_infoButton setImage:infoIcon forState:UIControlStateNormal]; [_infoButton setImage:infoIcon forState:UIControlStateNormal];
_infoButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7]; _infoButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
//
[_infoButton addTarget:self action:@selector(onInfoButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_infoButton addTarget:self action:@selector(onInfoButtonTapped) forControlEvents:UIControlEventTouchUpInside];
} }
return _infoButton; return _infoButton;
@@ -194,11 +192,11 @@
_selectedColorView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1]; _selectedColorView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.1];
_selectedColorView.layer.cornerRadius = 25; _selectedColorView.layer.cornerRadius = 25;
_selectedColorView.layer.masksToBounds = YES; _selectedColorView.layer.masksToBounds = YES;
_selectedColorView.hidden = YES; // _selectedColorView.hidden = YES;
//
UIView *colorDot = [[UIView alloc] init]; UIView *colorDot = [[UIView alloc] init];
colorDot.tag = 100; // colorDot.tag = 100;
colorDot.layer.cornerRadius = 12; colorDot.layer.cornerRadius = 12;
colorDot.layer.masksToBounds = YES; colorDot.layer.masksToBounds = YES;
[_selectedColorView addSubview:colorDot]; [_selectedColorView addSubview:colorDot];
@@ -208,7 +206,7 @@
make.size.mas_equalTo(CGSizeMake(24, 24)); make.size.mas_equalTo(CGSizeMake(24, 24));
}]; }];
//
[_selectedColorView addSubview:self.selectedColorLabel]; [_selectedColorView addSubview:self.selectedColorLabel];
[self.selectedColorLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.selectedColorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(colorDot.mas_trailing).offset(12); make.leading.equalTo(colorDot.mas_trailing).offset(12);
@@ -238,7 +236,7 @@
_okButton.backgroundColor = [UIColor colorWithRed:0x9B/255.0 green:0x59/255.0 blue:0xB6/255.0 alpha:1.0]; _okButton.backgroundColor = [UIColor colorWithRed:0x9B/255.0 green:0x59/255.0 blue:0xB6/255.0 alpha:1.0];
_okButton.layer.cornerRadius = 16; _okButton.layer.cornerRadius = 16;
_okButton.layer.masksToBounds = YES; _okButton.layer.masksToBounds = YES;
_okButton.enabled = NO; // _okButton.enabled = NO;
_okButton.alpha = 0.5; _okButton.alpha = 0.5;
[_okButton addTarget:self action:@selector(onOkButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_okButton addTarget:self action:@selector(onOkButtonTapped) forControlEvents:UIControlEventTouchUpInside];
} }
@@ -256,41 +254,41 @@
_colorWheelView.onColorTapped = ^(NSString *hexColor, NSInteger index) { _colorWheelView.onColorTapped = ^(NSString *hexColor, NSInteger index) {
__strong typeof(weakSelf) self = weakSelf; __strong typeof(weakSelf) self = weakSelf;
//
self.currentSelectedColor = hexColor; self.currentSelectedColor = hexColor;
self.currentSelectedIndex = index; self.currentSelectedIndex = index;
//
[self updateSelectedColorDisplay:hexColor index:index]; [self updateSelectedColorDisplay:hexColor index:index];
}; };
} }
return _colorWheelView; return _colorWheelView;
} }
///
- (void)updateSelectedColorDisplay:(NSString *)hexColor index:(NSInteger)index { - (void)updateSelectedColorDisplay:(NSString *)hexColor index:(NSInteger)index {
NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"]; NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"];
//
self.selectedColorView.hidden = NO; self.selectedColorView.hidden = NO;
//
UIView *colorDot = [self.selectedColorView viewWithTag:100]; UIView *colorDot = [self.selectedColorView viewWithTag:100];
colorDot.backgroundColor = [self colorFromHex:hexColor]; colorDot.backgroundColor = [self colorFromHex:hexColor];
//
self.selectedColorLabel.text = emotions[index]; self.selectedColorLabel.text = emotions[index];
// OK
self.okButton.enabled = YES; self.okButton.enabled = YES;
self.okButton.alpha = 1.0; self.okButton.alpha = 1.0;
} }
/// Hex UIColor
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
unsigned rgbValue = 0; unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString]; NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // # [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue]; [scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0xFF00) >> 8)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0
@@ -299,4 +297,3 @@
} }
@end @end

View File

@@ -1,9 +1,7 @@
//
// EPEmotionColorWheelView.m
// YuMi
//
// Created by AI on 2025-10-15. // Created by AI on 2025-10-15.
//
#import "EPEmotionColorWheelView.h" #import "EPEmotionColorWheelView.h"
#import "EPEmotionColorStorage.h" #import "EPEmotionColorStorage.h"
@@ -11,7 +9,7 @@
@interface EPEmotionColorWheelView () @interface EPEmotionColorWheelView ()
@property (nonatomic, strong) NSMutableArray<UIButton *> *colorButtons; @property (nonatomic, strong) NSMutableArray<UIButton *> *colorButtons;
@property (nonatomic, assign) NSInteger selectedIndex; // @property (nonatomic, assign) NSInteger selectedIndex;
@end @end
@@ -21,7 +19,7 @@
- (instancetype)initWithFrame:(CGRect)frame { - (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) { if (self = [super initWithFrame:frame]) {
//
_radius = 80.0; _radius = 80.0;
_buttonSize = 50.0; _buttonSize = 50.0;
_colorButtons = [NSMutableArray array]; _colorButtons = [NSMutableArray array];
@@ -34,7 +32,7 @@
- (void)layoutSubviews { - (void)layoutSubviews {
[super layoutSubviews]; [super layoutSubviews];
//
if (self.colorButtons.count == 0) { if (self.colorButtons.count == 0) {
[self createColorButtons]; [self createColorButtons];
} }
@@ -45,13 +43,13 @@
- (void)reloadWithPreselectedColor:(NSString *)color { - (void)reloadWithPreselectedColor:(NSString *)color {
self.preselectedColor = color; self.preselectedColor = color;
//
for (UIButton *btn in self.colorButtons) { for (UIButton *btn in self.colorButtons) {
[btn removeFromSuperview]; [btn removeFromSuperview];
} }
[self.colorButtons removeAllObjects]; [self.colorButtons removeAllObjects];
//
[self createColorButtons]; [self createColorButtons];
} }
@@ -66,7 +64,7 @@
CGFloat centerY = CGRectGetHeight(self.bounds) / 2.0; CGFloat centerY = CGRectGetHeight(self.bounds) / 2.0;
for (NSInteger i = 0; i < colors.count; i++) { for (NSInteger i = 0; i < colors.count; i++) {
//
CGFloat angle = angleStep * i - M_PI_2; CGFloat angle = angleStep * i - M_PI_2;
CGFloat x = centerX + self.radius * cos(angle) - self.buttonSize / 2.0; CGFloat x = centerX + self.radius * cos(angle) - self.buttonSize / 2.0;
CGFloat y = centerY + self.radius * sin(angle) - self.buttonSize / 2.0; CGFloat y = centerY + self.radius * sin(angle) - self.buttonSize / 2.0;
@@ -81,13 +79,13 @@
button.tag = i; button.tag = i;
[button addTarget:self action:@selector(onButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; [button addTarget:self action:@selector(onButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
//
if (self.preselectedColor && [colors[i] isEqualToString:self.preselectedColor]) { if (self.preselectedColor && [colors[i] isEqualToString:self.preselectedColor]) {
button.layer.borderWidth = 5.0; // button.layer.borderWidth = 5.0;
button.transform = CGAffineTransformMakeScale(1.1, 1.1); // button.transform = CGAffineTransformMakeScale(1.1, 1.1);
} }
//
button.layer.shadowColor = [self colorFromHex:colors[i]].CGColor; button.layer.shadowColor = [self colorFromHex:colors[i]].CGColor;
button.layer.shadowOffset = CGSizeMake(0, 2); button.layer.shadowOffset = CGSizeMake(0, 2);
button.layer.shadowOpacity = 0.6; button.layer.shadowOpacity = 0.6;
@@ -103,10 +101,10 @@
NSInteger index = sender.tag; NSInteger index = sender.tag;
self.selectedIndex = index; self.selectedIndex = index;
//
[self updateSelectionState]; [self updateSelectionState];
// UI
NSArray<NSString *> *colors = [EPEmotionColorStorage allEmotionColors]; NSArray<NSString *> *colors = [EPEmotionColorStorage allEmotionColors];
NSString *selectedColor = colors[index]; NSString *selectedColor = colors[index];
if (self.onColorTapped) { if (self.onColorTapped) {
@@ -114,16 +112,16 @@
} }
} }
///
- (void)updateSelectionState { - (void)updateSelectionState {
for (NSInteger i = 0; i < self.colorButtons.count; i++) { for (NSInteger i = 0; i < self.colorButtons.count; i++) {
UIButton *button = self.colorButtons[i]; UIButton *button = self.colorButtons[i];
if (i == self.selectedIndex) { if (i == self.selectedIndex) {
//
button.layer.borderWidth = 5.0; button.layer.borderWidth = 5.0;
button.transform = CGAffineTransformMakeScale(1.1, 1.1); button.transform = CGAffineTransformMakeScale(1.1, 1.1);
} else { } else {
//
button.layer.borderWidth = 3.0; button.layer.borderWidth = 3.0;
button.transform = CGAffineTransformIdentity; button.transform = CGAffineTransformIdentity;
} }
@@ -135,7 +133,7 @@
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
unsigned rgbValue = 0; unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString]; NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // # [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue]; [scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0xFF00) >> 8)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0
@@ -144,4 +142,3 @@
} }
@end @end

View File

@@ -1,9 +1,7 @@
//
// EPEmotionInfoView.m
// YuMi
//
// Created by AI on 2025-10-16. // Created by AI on 2025-10-16.
//
#import "EPEmotionInfoView.h" #import "EPEmotionInfoView.h"
#import <Masonry/Masonry.h> #import <Masonry/Masonry.h>
@@ -33,13 +31,13 @@
- (void)setupUI { - (void)setupUI {
self.backgroundColor = [UIColor clearColor]; self.backgroundColor = [UIColor clearColor];
//
[self addSubview:self.backgroundMask]; [self addSubview:self.backgroundMask];
[self.backgroundMask mas_makeConstraints:^(MASConstraintMaker *make) { [self.backgroundMask mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self); make.edges.equalTo(self);
}]; }];
//
[self addSubview:self.contentContainer]; [self addSubview:self.contentContainer];
[self.contentContainer mas_makeConstraints:^(MASConstraintMaker *make) { [self.contentContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self); make.center.equalTo(self);
@@ -47,14 +45,14 @@
make.height.mas_lessThanOrEqualTo(500); make.height.mas_lessThanOrEqualTo(500);
}]; }];
//
[self.contentContainer addSubview:self.titleLabel]; [self.contentContainer addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentContainer).offset(24); make.top.equalTo(self.contentContainer).offset(24);
make.leading.trailing.equalTo(self.contentContainer).inset(20); make.leading.trailing.equalTo(self.contentContainer).inset(20);
}]; }];
//
[self.contentContainer addSubview:self.scrollView]; [self.contentContainer addSubview:self.scrollView];
[self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) { [self.scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleLabel.mas_bottom).offset(16); make.top.equalTo(self.titleLabel.mas_bottom).offset(16);
@@ -62,14 +60,14 @@
make.height.mas_lessThanOrEqualTo(320); make.height.mas_lessThanOrEqualTo(320);
}]; }];
//
[self.scrollView addSubview:self.contentLabel]; [self.scrollView addSubview:self.contentLabel];
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.scrollView); make.edges.equalTo(self.scrollView);
make.width.equalTo(self.scrollView); make.width.equalTo(self.scrollView);
}]; }];
//
[self.contentContainer addSubview:self.closeButton]; [self.contentContainer addSubview:self.closeButton];
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.scrollView.mas_bottom).offset(20); make.top.equalTo(self.scrollView.mas_bottom).offset(20);
@@ -98,12 +96,12 @@
make.edges.equalTo(parentView); make.edges.equalTo(parentView);
}]; }];
//
self.backgroundMask.alpha = 0; self.backgroundMask.alpha = 0;
self.contentContainer.alpha = 0; self.contentContainer.alpha = 0;
self.contentContainer.transform = CGAffineTransformMakeScale(0.9, 0.9); self.contentContainer.transform = CGAffineTransformMakeScale(0.9, 0.9);
//
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.backgroundMask.alpha = 1; self.backgroundMask.alpha = 1;
self.contentContainer.alpha = 1; self.contentContainer.alpha = 1;
@@ -170,7 +168,7 @@
_contentLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9]; _contentLabel.textColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
_contentLabel.font = [UIFont systemFontOfSize:15]; _contentLabel.font = [UIFont systemFontOfSize:15];
//
NSString *content = @"Based on Plutchik's Wheel of Emotions, we use 8 core colors to represent fundamental human emotions:\n\n" NSString *content = @"Based on Plutchik's Wheel of Emotions, we use 8 core colors to represent fundamental human emotions:\n\n"
"🟡 Joy (Gold)\n" "🟡 Joy (Gold)\n"
"Represents happiness, delight, and cheerfulness. Like sunshine warming your heart.\n\n" "Represents happiness, delight, and cheerfulness. Like sunshine warming your heart.\n\n"
@@ -210,4 +208,3 @@
} }
@end @end

View File

@@ -1,10 +1,8 @@
//
// NewMomentCell.m
// YuMi
//
// Created by AI on 2025-10-09. // Created by AI on 2025-10-09.
// Copyright © 2025 YuMi. All rights reserved. // Copyright © 2025 YuMi. All rights reserved.
//
#import "EPMomentCell.h" #import "EPMomentCell.h"
#import "MomentsInfoModel.h" #import "MomentsInfoModel.h"
@@ -12,52 +10,50 @@
#import "NetImageView.h" #import "NetImageView.h"
#import "EPEmotionColorStorage.h" #import "EPEmotionColorStorage.h"
#import "SDPhotoBrowser.h" #import "SDPhotoBrowser.h"
#import "YuMi-Swift.h" // Swift #import "YuMi-Swift.h"
@interface EPMomentCell () <SDPhotoBrowserDelegate> @interface EPMomentCell () <SDPhotoBrowserDelegate>
// MARK: - UI Components // MARK: - UI Components
///
@property (nonatomic, strong) UIView *cardView; @property (nonatomic, strong) UIView *cardView;
///
@property (nonatomic, strong) UIView *colorBackgroundView; @property (nonatomic, strong) UIView *colorBackgroundView;
///
@property (nonatomic, strong) UIVisualEffectView *blurEffectView; @property (nonatomic, strong) UIVisualEffectView *blurEffectView;
///
@property (nonatomic, strong) NetImageView *avatarImageView; @property (nonatomic, strong) NetImageView *avatarImageView;
///
@property (nonatomic, strong) UILabel *nameLabel; @property (nonatomic, strong) UILabel *nameLabel;
///
@property (nonatomic, strong) UILabel *timeLabel; @property (nonatomic, strong) UILabel *timeLabel;
///
@property (nonatomic, strong) UILabel *contentLabel; @property (nonatomic, strong) UILabel *contentLabel;
///
@property (nonatomic, strong) UIView *imagesContainer; @property (nonatomic, strong) UIView *imagesContainer;
@property (nonatomic, strong) NSMutableArray<NetImageView *> *imageViews; @property (nonatomic, strong) NSMutableArray<NetImageView *> *imageViews;
///
@property (nonatomic, strong) UIView *actionBar; @property (nonatomic, strong) UIView *actionBar;
///
@property (nonatomic, strong) UIButton *likeButton; @property (nonatomic, strong) UIButton *likeButton;
///
@property (nonatomic, strong) UIButton *commentButton; @property (nonatomic, strong) UIButton *commentButton;
//
///
@property (nonatomic, strong) MomentsInfoModel *currentModel; @property (nonatomic, strong) MomentsInfoModel *currentModel;
/// API Helper (Swift )
@property (nonatomic, strong) EPMomentAPISwiftHelper *apiHelper; @property (nonatomic, strong) EPMomentAPISwiftHelper *apiHelper;
@end @end
@@ -78,7 +74,7 @@
// MARK: - Setup UI // MARK: - Setup UI
- (void)setupUI { - (void)setupUI {
// +
[self.contentView addSubview:self.cardView]; [self.contentView addSubview:self.cardView];
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) { [self.cardView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.contentView).inset(15); make.leading.trailing.equalTo(self.contentView).inset(15);
@@ -86,19 +82,19 @@
make.bottom.equalTo(self.contentView).offset(-8).priority(UILayoutPriorityRequired - 1); make.bottom.equalTo(self.contentView).offset(-8).priority(UILayoutPriorityRequired - 1);
}]; }];
//
[self.cardView addSubview:self.colorBackgroundView]; [self.cardView addSubview:self.colorBackgroundView];
[self.colorBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) { [self.colorBackgroundView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.cardView); make.edges.equalTo(self.cardView);
}]; }];
//
[self.cardView addSubview:self.blurEffectView]; [self.cardView addSubview:self.blurEffectView];
[self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) { [self.blurEffectView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.cardView); make.edges.equalTo(self.cardView);
}]; }];
//
[self.blurEffectView.contentView addSubview:self.avatarImageView]; [self.blurEffectView.contentView addSubview:self.avatarImageView];
[self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) { [self.avatarImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.cardView).offset(15); make.leading.equalTo(self.cardView).offset(15);
@@ -106,7 +102,7 @@
make.size.mas_equalTo(CGSizeMake(40, 40)); make.size.mas_equalTo(CGSizeMake(40, 40));
}]; }];
//
[self.blurEffectView.contentView addSubview:self.nameLabel]; [self.blurEffectView.contentView addSubview:self.nameLabel];
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.avatarImageView.mas_trailing).offset(10); make.leading.equalTo(self.avatarImageView.mas_trailing).offset(10);
@@ -114,7 +110,7 @@
make.trailing.equalTo(self.cardView).offset(-15); make.trailing.equalTo(self.cardView).offset(-15);
}]; }];
//
[self.blurEffectView.contentView addSubview:self.timeLabel]; [self.blurEffectView.contentView addSubview:self.timeLabel];
[self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.nameLabel); make.leading.equalTo(self.nameLabel);
@@ -122,32 +118,32 @@
make.trailing.equalTo(self.cardView).offset(-15); make.trailing.equalTo(self.cardView).offset(-15);
}]; }];
//
[self.blurEffectView.contentView addSubview:self.contentLabel]; [self.blurEffectView.contentView addSubview:self.contentLabel];
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.cardView).inset(15); make.leading.trailing.equalTo(self.cardView).inset(15);
make.top.equalTo(self.avatarImageView.mas_bottom).offset(12); make.top.equalTo(self.avatarImageView.mas_bottom).offset(12);
}]; }];
//
[self.blurEffectView.contentView addSubview:self.imagesContainer]; [self.blurEffectView.contentView addSubview:self.imagesContainer];
[self.imagesContainer mas_makeConstraints:^(MASConstraintMaker *make) { [self.imagesContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.cardView).inset(15); make.leading.trailing.equalTo(self.cardView).inset(15);
make.top.equalTo(self.contentLabel.mas_bottom).offset(12); make.top.equalTo(self.contentLabel.mas_bottom).offset(12);
make.height.mas_equalTo(0); // 0renderImages remakeConstraints make.height.mas_equalTo(0);
}]; }];
//
[self.blurEffectView.contentView addSubview:self.actionBar]; [self.blurEffectView.contentView addSubview:self.actionBar];
[self.actionBar mas_makeConstraints:^(MASConstraintMaker *make) { [self.actionBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.trailing.equalTo(self.cardView); make.leading.trailing.equalTo(self.cardView);
make.top.equalTo(self.imagesContainer.mas_bottom).offset(12); make.top.equalTo(self.imagesContainer.mas_bottom).offset(12);
make.height.mas_equalTo(50); make.height.mas_equalTo(50);
//
make.bottom.equalTo(self.cardView).offset(-8).priority(UILayoutPriorityRequired - 2); make.bottom.equalTo(self.cardView).offset(-8).priority(UILayoutPriorityRequired - 2);
}]; }];
//
[self.actionBar addSubview:self.likeButton]; [self.actionBar addSubview:self.likeButton];
[self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.actionBar); make.leading.equalTo(self.actionBar);
@@ -161,19 +157,19 @@
- (void)configureWithModel:(MomentsInfoModel *)model { - (void)configureWithModel:(MomentsInfoModel *)model {
self.currentModel = model; self.currentModel = model;
//
self.nameLabel.text = model.nick ?: YMLocalizedString(@"user.anonymous"); self.nameLabel.text = model.nick ?: YMLocalizedString(@"user.anonymous");
// MM/dd
self.timeLabel.text = [self formatTimestampToDate:model.publishTime]; self.timeLabel.text = [self formatTimestampToDate:model.publishTime];
//
self.contentLabel.text = model.content ?: @""; self.contentLabel.text = model.content ?: @"";
//
[self renderImages:model.dynamicResList]; [self renderImages:model.dynamicResList];
//
NSInteger likeCnt = MAX(0, model.likeCount.integerValue); NSInteger likeCnt = MAX(0, model.likeCount.integerValue);
self.likeButton.selected = model.isLike; self.likeButton.selected = model.isLike;
[self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCnt] forState:UIControlStateNormal]; [self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCnt] forState:UIControlStateNormal];
@@ -181,16 +177,16 @@
self.avatarImageView.imageUrl = model.avatar; self.avatarImageView.imageUrl = model.avatar;
// border shadow
[self applyEmotionColorEffect:model.emotionColor]; [self applyEmotionColorEffect:model.emotionColor];
// cell
[self setNeedsLayout]; [self setNeedsLayout];
} }
/// Background + Shadow
- (void)applyEmotionColorEffect:(NSString *)emotionColorHex { - (void)applyEmotionColorEffect:(NSString *)emotionColorHex {
// 使
if (!emotionColorHex) { if (!emotionColorHex) {
NSLog(@"[EPMomentCell] 警告emotionColorHex 为 nil"); NSLog(@"[EPMomentCell] 警告emotionColorHex 为 nil");
return; return;
@@ -198,24 +194,24 @@
UIColor *color = [self colorFromHex:emotionColorHex]; UIColor *color = [self colorFromHex:emotionColorHex];
//
self.cardView.layer.borderWidth = 0; self.cardView.layer.borderWidth = 0;
// 50%
self.colorBackgroundView.backgroundColor = [color colorWithAlphaComponent:0.5]; self.colorBackgroundView.backgroundColor = [color colorWithAlphaComponent:0.5];
// shadow使
self.cardView.layer.shadowColor = color.CGColor; self.cardView.layer.shadowColor = color.CGColor;
self.cardView.layer.shadowOffset = CGSizeMake(0, 2); self.cardView.layer.shadowOffset = CGSizeMake(0, 2);
self.cardView.layer.shadowOpacity = 0.5; self.cardView.layer.shadowOpacity = 0.5;
self.cardView.layer.shadowRadius = 16.0; self.cardView.layer.shadowRadius = 16.0;
} }
/// Hex UIColor
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
unsigned rgbValue = 0; unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString]; NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // # [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue]; [scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0xFF00) >> 8)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0
@@ -226,7 +222,7 @@
// MARK: - Images Grid // MARK: - Images Grid
- (void)renderImages:(NSArray *)resList { - (void)renderImages:(NSArray *)resList {
//
for (UIView *iv in self.imageViews) { [iv removeFromSuperview]; } for (UIView *iv in self.imageViews) { [iv removeFromSuperview]; }
[self.imageViews removeAllObjects]; [self.imageViews removeAllObjects];
if (resList.count == 0) { if (resList.count == 0) {
@@ -236,14 +232,14 @@
make.height.mas_equalTo(0); make.height.mas_equalTo(0);
}]; }];
//
[self.contentView setNeedsLayout]; [self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded]; [self.contentView layoutIfNeeded];
return; return;
} }
NSInteger columns = 3; NSInteger columns = 3;
CGFloat spacing = 6.0; CGFloat spacing = 6.0;
CGFloat totalWidth = [UIScreen mainScreen].bounds.size.width - 30 - 30; // 15 15 CGFloat totalWidth = [UIScreen mainScreen].bounds.size.width - 30 - 30;
CGFloat itemW = floor((totalWidth - spacing * (columns - 1)) / columns); CGFloat itemW = floor((totalWidth - spacing * (columns - 1)) / columns);
for (NSInteger i = 0; i < resList.count && i < 9; i++) { for (NSInteger i = 0; i < resList.count && i < 9; i++) {
@@ -255,9 +251,9 @@
iv.layer.masksToBounds = YES; iv.layer.masksToBounds = YES;
iv.contentMode = UIViewContentModeScaleAspectFill; iv.contentMode = UIViewContentModeScaleAspectFill;
iv.userInteractionEnabled = YES; iv.userInteractionEnabled = YES;
iv.tag = i; // iv.tag = i;
//
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageTapped:)]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageTapped:)];
[iv addGestureRecognizer:tap]; [iv addGestureRecognizer:tap];
@@ -270,7 +266,7 @@
make.top.equalTo(self.imagesContainer).offset((itemW + spacing) * row); make.top.equalTo(self.imagesContainer).offset((itemW + spacing) * row);
make.size.mas_equalTo(CGSizeMake(itemW, itemW)); make.size.mas_equalTo(CGSizeMake(itemW, itemW));
}]; }];
//
NSString *url = nil; NSString *url = nil;
id item = resList[i]; id item = resList[i];
if ([item isKindOfClass:[NSDictionary class]]) { if ([item isKindOfClass:[NSDictionary class]]) {
@@ -289,18 +285,18 @@
make.height.mas_equalTo(height); make.height.mas_equalTo(height);
}]; }];
// cell
[self.contentView setNeedsLayout]; [self.contentView setNeedsLayout];
[self.contentView layoutIfNeeded]; [self.contentView layoutIfNeeded];
} }
/// MM/dd
- (NSString *)formatTimestampToDate:(NSString *)timestampString { - (NSString *)formatTimestampToDate:(NSString *)timestampString {
if (!timestampString || timestampString.length == 0) { if (!timestampString || timestampString.length == 0) {
return @""; return @"";
} }
//
NSTimeInterval timestamp = [timestampString doubleValue] / 1000.0; NSTimeInterval timestamp = [timestampString doubleValue] / 1000.0;
if (timestamp <= 0) { if (timestamp <= 0) {
@@ -314,7 +310,7 @@
return [formatter stringFromDate:date]; return [formatter stringFromDate:date];
} }
///
- (NSString *)formatTimeInterval:(NSInteger)timestamp { - (NSString *)formatTimeInterval:(NSInteger)timestamp {
if (timestamp <= 0) return YMLocalizedString(@"time.just_now"); if (timestamp <= 0) return YMLocalizedString(@"time.just_now");
@@ -340,20 +336,20 @@
- (void)onLikeButtonTapped { - (void)onLikeButtonTapped {
if (!self.currentModel) return; if (!self.currentModel) return;
//
if (self.currentModel.isLike) { if (self.currentModel.isLike) {
[self performLikeAction:NO]; [self performLikeAction:NO];
return; return;
} }
//
if (self.currentModel.status == 0) { if (self.currentModel.status == 0) {
NSLog(@"[EPMomentCell] 动态审核中,无法点赞"); NSLog(@"[EPMomentCell] 动态审核中,无法点赞");
// TODO: Toast // TODO: Toast
return; return;
} }
//
[self performLikeAction:YES]; [self performLikeAction:YES];
} }
@@ -364,7 +360,7 @@
NSString *likedUid = self.currentModel.uid; NSString *likedUid = self.currentModel.uid;
long worldId = self.currentModel.worldId; long worldId = self.currentModel.worldId;
// 使 Swift API Helper
@kWeakify(self); @kWeakify(self);
[self.apiHelper likeMomentWithDynamicId:dynamicId [self.apiHelper likeMomentWithDynamicId:dynamicId
isLike:isLike isLike:isLike
@@ -372,14 +368,14 @@
worldId:worldId worldId:worldId
completion:^{ completion:^{
@kStrongify(self); @kStrongify(self);
//
self.currentModel.isLike = isLike; self.currentModel.isLike = isLike;
NSInteger likeCount = [self.currentModel.likeCount integerValue]; NSInteger likeCount = [self.currentModel.likeCount integerValue];
likeCount += isLike ? 1 : -1; likeCount += isLike ? 1 : -1;
likeCount = MAX(0, likeCount); // likeCount = MAX(0, likeCount);
self.currentModel.likeCount = @(likeCount).stringValue; self.currentModel.likeCount = @(likeCount).stringValue;
// UI
self.likeButton.selected = self.currentModel.isLike; self.likeButton.selected = self.currentModel.isLike;
[self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCount] forState:UIControlStateNormal]; [self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCount] forState:UIControlStateNormal];
[self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCount] forState:UIControlStateSelected]; [self.likeButton setTitle:[NSString stringWithFormat:@" %ld", (long)likeCount] forState:UIControlStateSelected];
@@ -390,10 +386,6 @@
}]; }];
} }
//
// - (void)onCommentButtonTapped {
// NSLog(@"[EPMomentCell] 评论");
// }
- (void)onImageTapped:(UITapGestureRecognizer *)gesture { - (void)onImageTapped:(UITapGestureRecognizer *)gesture {
if (!self.currentModel || !self.currentModel.dynamicResList.count) return; if (!self.currentModel || !self.currentModel.dynamicResList.count) return;
@@ -436,9 +428,9 @@
- (UIView *)cardView { - (UIView *)cardView {
if (!_cardView) { if (!_cardView) {
_cardView = [[UIView alloc] init]; _cardView = [[UIView alloc] init];
_cardView.backgroundColor = [UIColor clearColor]; // colorBackgroundView _cardView.backgroundColor = [UIColor clearColor];
_cardView.layer.cornerRadius = 12; // _cardView.layer.cornerRadius = 12;
// Shadow applyEmotionColorEffect
_cardView.layer.masksToBounds = NO; _cardView.layer.masksToBounds = NO;
} }
return _cardView; return _cardView;
@@ -507,7 +499,7 @@
- (UIView *)actionBar { - (UIView *)actionBar {
if (!_actionBar) { if (!_actionBar) {
_actionBar = [[UIView alloc] init]; _actionBar = [[UIView alloc] init];
_actionBar.backgroundColor = [UIColor clearColor]; // _actionBar.backgroundColor = [UIColor clearColor];
} }
return _actionBar; return _actionBar;
} }
@@ -526,7 +518,7 @@
return _likeButton; return _likeButton;
} }
//
- (UIButton *)commentButton { - (UIButton *)commentButton {
return nil; return nil;
} }

View File

@@ -1,9 +1,7 @@
//
// EPMomentListView.m
// YuMi
//
// Created by AI on 2025-10-10. // Created by AI on 2025-10-10.
//
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "EPMomentListView.h" #import "EPMomentListView.h"
@@ -34,7 +32,7 @@
_api = [[EPMomentAPISwiftHelper alloc] init]; _api = [[EPMomentAPISwiftHelper alloc] init];
_mutableRawList = [NSMutableArray array]; _mutableRawList = [NSMutableArray array];
_sourceType = EPMomentListSourceTypeRecommend; _sourceType = EPMomentListSourceTypeRecommend;
_isLocalMode = NO; // _isLocalMode = NO;
[self addSubview:self.tableView]; [self addSubview:self.tableView];
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
@@ -49,8 +47,10 @@
} }
- (void)reloadFirstPage { - (void)reloadFirstPage {
NSLog(@"[EPMomentListView] 📄 开始刷新第一页isLocalMode=%d", self.isLocalMode);
if (self.isLocalMode) { if (self.isLocalMode) {
//
if (self.refreshCallback) { if (self.refreshCallback) {
self.refreshCallback(); self.refreshCallback();
} }
@@ -58,7 +58,7 @@
return; return;
} }
//
self.nextID = @""; self.nextID = @"";
[self.mutableRawList removeAllObjects]; [self.mutableRawList removeAllObjects];
[self.tableView reloadData]; [self.tableView reloadData];
@@ -76,7 +76,7 @@
[self.mutableRawList addObjectsFromArray:dynamicInfo]; [self.mutableRawList addObjectsFromArray:dynamicInfo];
} }
// footer
self.tableView.mj_footer.hidden = YES; self.tableView.mj_footer.hidden = YES;
[self.tableView reloadData]; [self.tableView reloadData];
@@ -84,20 +84,27 @@
} }
- (void)requestNextPage { - (void)requestNextPage {
if (self.isLoading) return; if (self.isLoading) {
NSLog(@"[EPMomentListView] ⚠️ 已有加载任务进行中,跳过本次请求");
return;
}
NSLog(@"[EPMomentListView] 🌐 发起网络请求nextID=%@", self.nextID.length > 0 ? self.nextID : @"(首页)");
self.isLoading = YES; self.isLoading = YES;
@kWeakify(self); @kWeakify(self);
[self.api fetchLatestMomentsWithNextID:self.nextID [self.api fetchLatestMomentsWithNextID:self.nextID
completion:^(NSArray<MomentsInfoModel *> * _Nonnull list, NSString * _Nonnull nextMomentID) { completion:^(NSArray<MomentsInfoModel *> * _Nonnull list, NSString * _Nonnull nextMomentID) {
@kStrongify(self); @kStrongify(self);
NSLog(@"[EPMomentListView] ✅ 请求成功,获得 %lu 条数据", (unsigned long)list.count);
[self endLoading]; [self endLoading];
if (list.count > 0) { if (list.count > 0) {
//
[self processEmotionColors:list isFirstPage:(self.nextID.length == 0)]; [self processEmotionColors:list isFirstPage:(self.nextID.length == 0)];
self.nextID = nextMomentID; self.nextID = nextMomentID;
[self.mutableRawList addObjectsFromArray:list]; [self.mutableRawList addObjectsFromArray:list];
[self removeEmptyState];
[self.tableView reloadData]; [self.tableView reloadData];
if (nextMomentID.length > 0) { if (nextMomentID.length > 0) {
[self.tableView.mj_footer endRefreshing]; [self.tableView.mj_footer endRefreshing];
@@ -105,13 +112,21 @@
[self.tableView.mj_footer endRefreshingWithNoMoreData]; [self.tableView.mj_footer endRefreshingWithNoMoreData];
} }
} else { } else {
// "no more data" NSLog(@"[EPMomentListView] ⚠️ 返回数据为空");
if (self.mutableRawList.count == 0) {
[self showEmptyStateWithMessage:YMLocalizedString(@"common.no_data")];
}
[self.tableView.mj_footer endRefreshingWithNoMoreData]; [self.tableView.mj_footer endRefreshingWithNoMoreData];
} }
} failure:^(NSInteger code, NSString * _Nonnull msg) { } failure:^(NSInteger code, NSString * _Nonnull msg) {
@kStrongify(self); @kStrongify(self);
NSLog(@"[EPMomentListView] ❌ 请求失败code=%ld, msg=%@", (long)code, msg);
[self endLoading]; [self endLoading];
// TODO:
if (self.mutableRawList.count == 0) {
[self showEmptyStateWithMessage:msg ?: YMLocalizedString(@"error.request_failed")];
}
[self.tableView.mj_footer endRefreshing]; [self.tableView.mj_footer endRefreshing];
}]; }];
} }
@@ -121,25 +136,48 @@
[self.refreshControl endRefreshing]; [self.refreshControl endRefreshing];
} }
/// UserDefaults +
- (void)showEmptyStateWithMessage:(NSString *)message {
UILabel *emptyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
emptyLabel.text = [NSString stringWithFormat:@"%@\n\n%@", message, YMLocalizedString(@"common.pull_to_retry")];
emptyLabel.textColor = [UIColor whiteColor];
emptyLabel.textAlignment = NSTextAlignmentCenter;
emptyLabel.numberOfLines = 0;
emptyLabel.font = [UIFont systemFontOfSize:15];
emptyLabel.tag = 9999;
[[self.tableView viewWithTag:9999] removeFromSuperview];
[self.tableView addSubview:emptyLabel];
[emptyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.tableView);
make.leading.trailing.equalTo(self.tableView).inset(40);
}];
}
- (void)removeEmptyState {
[[self.tableView viewWithTag:9999] removeFromSuperview];
}
- (void)processEmotionColors:(NSArray<MomentsInfoModel *> *)list isFirstPage:(BOOL)isFirstPage { - (void)processEmotionColors:(NSArray<MomentsInfoModel *> *)list isFirstPage:(BOOL)isFirstPage {
//
NSString *pendingColor = [[NSUserDefaults standardUserDefaults] stringForKey:@"EP_Pending_Emotion_Color"]; NSString *pendingColor = [[NSUserDefaults standardUserDefaults] stringForKey:@"EP_Pending_Emotion_Color"];
NSNumber *pendingTimestamp = [[NSUserDefaults standardUserDefaults] objectForKey:@"EP_Pending_Emotion_Timestamp"]; NSNumber *pendingTimestamp = [[NSUserDefaults standardUserDefaults] objectForKey:@"EP_Pending_Emotion_Timestamp"];
for (NSInteger i = 0; i < list.count; i++) { for (NSInteger i = 0; i < list.count; i++) {
MomentsInfoModel *model = list[i]; MomentsInfoModel *model = list[i];
//
if (isFirstPage && i == 0 && pendingColor && pendingTimestamp) { if (isFirstPage && i == 0 && pendingColor && pendingTimestamp) {
// 5
NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSTimeInterval pending = pendingTimestamp.doubleValue; NSTimeInterval pending = pendingTimestamp.doubleValue;
if ((now - pending) < 5.0) { if ((now - pending) < 5.0) {
model.emotionColor = pendingColor; model.emotionColor = pendingColor;
//
[EPEmotionColorStorage saveColor:pendingColor forDynamicId:model.dynamicId]; [EPEmotionColorStorage saveColor:pendingColor forDynamicId:model.dynamicId];
//
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Color"]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Color"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Timestamp"]; [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"EP_Pending_Emotion_Timestamp"];
[[NSUserDefaults standardUserDefaults] synchronize]; [[NSUserDefaults standardUserDefaults] synchronize];
@@ -147,12 +185,12 @@
} }
} }
//
NSString *savedColor = [EPEmotionColorStorage colorForDynamicId:model.dynamicId]; NSString *savedColor = [EPEmotionColorStorage colorForDynamicId:model.dynamicId];
if (savedColor) { if (savedColor) {
model.emotionColor = savedColor; model.emotionColor = savedColor;
} else { } else {
//
NSString *randomColor = [EPEmotionColorStorage randomEmotionColor]; NSString *randomColor = [EPEmotionColorStorage randomEmotionColor];
model.emotionColor = randomColor; model.emotionColor = randomColor;
[EPEmotionColorStorage saveColor:randomColor forDynamicId:model.dynamicId]; [EPEmotionColorStorage saveColor:randomColor forDynamicId:model.dynamicId];
@@ -190,7 +228,7 @@
} }
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
//
if (self.isLocalMode) return; if (self.isLocalMode) return;
CGFloat offsetY = scrollView.contentOffset.y; CGFloat offsetY = scrollView.contentOffset.y;
@@ -213,13 +251,13 @@
_tableView.estimatedRowHeight = 200; _tableView.estimatedRowHeight = 200;
_tableView.rowHeight = UITableViewAutomaticDimension; _tableView.rowHeight = UITableViewAutomaticDimension;
_tableView.showsVerticalScrollIndicator = NO; _tableView.showsVerticalScrollIndicator = NO;
// TabBar
_tableView.contentInset = UIEdgeInsetsMake(10, 0, 120, 0); _tableView.contentInset = UIEdgeInsetsMake(10, 0, 120, 0);
_tableView.scrollIndicatorInsets = UIEdgeInsetsMake(10, 0, 120, 0); _tableView.scrollIndicatorInsets = UIEdgeInsetsMake(10, 0, 120, 0);
[_tableView registerClass:[EPMomentCell class] forCellReuseIdentifier:@"NewMomentCell"]; [_tableView registerClass:[EPMomentCell class] forCellReuseIdentifier:@"NewMomentCell"];
_tableView.refreshControl = self.refreshControl; _tableView.refreshControl = self.refreshControl;
// MJRefresh Footer -
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{ MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
__strong typeof(weakSelf) self = weakSelf; __strong typeof(weakSelf) self = weakSelf;
@@ -231,7 +269,7 @@
[self.tableView.mj_footer endRefreshing]; [self.tableView.mj_footer endRefreshing];
} }
}]; }];
//
footer.stateLabel.textColor = [UIColor whiteColor]; footer.stateLabel.textColor = [UIColor whiteColor];
footer.loadingView.color = [UIColor whiteColor]; footer.loadingView.color = [UIColor whiteColor];
_tableView.mj_footer = footer; _tableView.mj_footer = footer;
@@ -242,12 +280,10 @@
- (UIRefreshControl *)refreshControl { - (UIRefreshControl *)refreshControl {
if (!_refreshControl) { if (!_refreshControl) {
_refreshControl = [[UIRefreshControl alloc] init]; _refreshControl = [[UIRefreshControl alloc] init];
_refreshControl.tintColor = [UIColor whiteColor]; // _refreshControl.tintColor = [UIColor whiteColor];
[_refreshControl addTarget:self action:@selector(reloadFirstPage) forControlEvents:UIControlEventValueChanged]; [_refreshControl addTarget:self action:@selector(reloadFirstPage) forControlEvents:UIControlEventValueChanged];
} }
return _refreshControl; return _refreshControl;
} }
@end @end

View File

@@ -1,9 +1,7 @@
//
// EPSignatureColorGuideView.m
// YuMi
//
// Created by AI on 2025-10-15. // Created by AI on 2025-10-15.
//
#import "EPSignatureColorGuideView.h" #import "EPSignatureColorGuideView.h"
#import "EPEmotionColorWheelView.h" #import "EPEmotionColorWheelView.h"
@@ -22,7 +20,7 @@
@property (nonatomic, strong) EPEmotionColorWheelView *colorWheelView; @property (nonatomic, strong) EPEmotionColorWheelView *colorWheelView;
@property (nonatomic, strong) UIButton *confirmButton; @property (nonatomic, strong) UIButton *confirmButton;
@property (nonatomic, strong) UIButton *skipButton; @property (nonatomic, strong) UIButton *skipButton;
@property (nonatomic, copy) NSString *selectedColor; // @property (nonatomic, copy) NSString *selectedColor;
@end @end
@@ -38,7 +36,7 @@
} }
- (void)setupUI { - (void)setupUI {
//
CAGradientLayer *gradientLayer = [CAGradientLayer layer]; CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = @[ gradientLayer.colors = @[
(id)[UIColor colorWithRed:0x1a/255.0 green:0x09/255.0 blue:0x33/255.0 alpha:1.0].CGColor, (id)[UIColor colorWithRed:0x1a/255.0 green:0x09/255.0 blue:0x33/255.0 alpha:1.0].CGColor,
@@ -49,29 +47,30 @@
[self.layer insertSublayer:gradientLayer atIndex:0]; [self.layer insertSublayer:gradientLayer atIndex:0];
self.gradientLayer = gradientLayer; self.gradientLayer = gradientLayer;
//
[self addSubview:self.contentContainer]; [self addSubview:self.contentContainer];
[self.contentContainer mas_makeConstraints:^(MASConstraintMaker *make) { [self.contentContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self); make.top.equalTo(self).offset(100);
make.leading.trailing.equalTo(self).inset(30); make.leading.trailing.equalTo(self).inset(30);
make.bottom.lessThanOrEqualTo(self).offset(-30);
}]; }];
//
[self.contentContainer addSubview:self.titleLabel]; [self.contentContainer addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.contentContainer); make.top.equalTo(self.contentContainer);
make.centerX.equalTo(self.contentContainer); make.centerX.equalTo(self.contentContainer);
}]; }];
//
[self.contentContainer addSubview:self.subtitleLabel]; [self.contentContainer addSubview:self.subtitleLabel];
[self.subtitleLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.subtitleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleLabel.mas_bottom).offset(12); make.top.equalTo(self.titleLabel.mas_bottom).offset(8);
make.centerX.equalTo(self.contentContainer); make.centerX.equalTo(self.contentContainer);
make.leading.trailing.equalTo(self.contentContainer).inset(20); make.leading.trailing.equalTo(self.contentContainer).inset(20);
}]; }];
// Info Skip
[self addSubview:self.infoButton]; [self addSubview:self.infoButton];
[self.infoButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.infoButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self).offset(20); make.leading.equalTo(self).offset(20);
@@ -79,33 +78,34 @@
make.size.mas_equalTo(CGSizeMake(36, 36)); make.size.mas_equalTo(CGSizeMake(36, 36));
}]; }];
//
[self.contentContainer addSubview:self.selectedColorView]; [self.contentContainer addSubview:self.selectedColorView];
[self.selectedColorView mas_makeConstraints:^(MASConstraintMaker *make) { [self.selectedColorView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.subtitleLabel.mas_bottom).offset(30); make.top.equalTo(self.subtitleLabel.mas_bottom).offset(20);
make.centerX.equalTo(self.contentContainer); make.centerX.equalTo(self.contentContainer);
make.height.mas_equalTo(60); make.height.mas_equalTo(60);
make.leading.trailing.equalTo(self.contentContainer).inset(40); make.leading.trailing.equalTo(self.contentContainer).inset(40);
}]; }];
// 使
[self.contentContainer addSubview:self.colorWheelView]; [self.contentContainer addSubview:self.colorWheelView];
[self.colorWheelView mas_makeConstraints:^(MASConstraintMaker *make) { [self.colorWheelView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.selectedColorView.mas_bottom).offset(30); make.top.equalTo(self.selectedColorView.mas_bottom).offset(20);
make.centerX.equalTo(self.contentContainer); make.centerX.equalTo(self.contentContainer);
make.size.mas_equalTo(CGSizeMake(360, 360)); // 280x280360x360 CGFloat wheelSize = MIN(300, [UIScreen mainScreen].bounds.size.width - 80);
make.size.mas_equalTo(CGSizeMake(wheelSize, wheelSize));
}]; }];
//
[self.contentContainer addSubview:self.confirmButton]; [self.contentContainer addSubview:self.confirmButton];
[self.confirmButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.confirmButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.colorWheelView.mas_bottom).offset(50); make.top.equalTo(self.colorWheelView.mas_bottom).offset(30);
make.leading.trailing.equalTo(self.contentContainer).inset(20); make.leading.trailing.equalTo(self.contentContainer).inset(20);
make.height.mas_equalTo(56); make.height.mas_equalTo(56);
make.bottom.equalTo(self.contentContainer); make.bottom.equalTo(self.contentContainer);
}]; }];
// Skip
[self addSubview:self.skipButton]; [self addSubview:self.skipButton];
[self.skipButton mas_makeConstraints:^(MASConstraintMaker *make) { [self.skipButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self).offset(60); make.top.equalTo(self).offset(60);
@@ -116,7 +116,7 @@
- (void)layoutSubviews { - (void)layoutSubviews {
[super layoutSubviews]; [super layoutSubviews];
// frame
self.gradientLayer.frame = self.bounds; self.gradientLayer.frame = self.bounds;
} }
@@ -125,22 +125,22 @@
- (void)onConfirmButtonTapped { - (void)onConfirmButtonTapped {
if (!self.selectedColor) return; if (!self.selectedColor) return;
//
if (self.onColorConfirmed) { if (self.onColorConfirmed) {
self.onColorConfirmed(self.selectedColor); self.onColorConfirmed(self.selectedColor);
} }
//
[self dismiss]; [self dismiss];
} }
- (void)onSkipButtonTapped { - (void)onSkipButtonTapped {
// skip
if (self.onSkipTapped) { if (self.onSkipTapped) {
self.onSkipTapped(); self.onSkipTapped();
} }
//
[self dismiss]; [self dismiss];
} }
@@ -161,14 +161,14 @@
make.edges.equalTo(window); make.edges.equalTo(window);
}]; }];
// Skip
self.skipButton.hidden = !showSkip; self.skipButton.hidden = !showSkip;
//
self.alpha = 0; self.alpha = 0;
self.contentContainer.transform = CGAffineTransformMakeScale(0.8, 0.8); self.contentContainer.transform = CGAffineTransformMakeScale(0.8, 0.8);
//
[UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ [UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.alpha = 1.0; self.alpha = 1.0;
self.contentContainer.transform = CGAffineTransformIdentity; self.contentContainer.transform = CGAffineTransformIdentity;
@@ -223,11 +223,11 @@
_selectedColorView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.15]; _selectedColorView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.15];
_selectedColorView.layer.cornerRadius = 30; _selectedColorView.layer.cornerRadius = 30;
_selectedColorView.layer.masksToBounds = YES; _selectedColorView.layer.masksToBounds = YES;
_selectedColorView.hidden = YES; // _selectedColorView.hidden = YES;
//
UIView *colorDot = [[UIView alloc] init]; UIView *colorDot = [[UIView alloc] init];
colorDot.tag = 100; // colorDot.tag = 100;
colorDot.layer.cornerRadius = 16; colorDot.layer.cornerRadius = 16;
colorDot.layer.masksToBounds = YES; colorDot.layer.masksToBounds = YES;
[_selectedColorView addSubview:colorDot]; [_selectedColorView addSubview:colorDot];
@@ -237,7 +237,7 @@
make.size.mas_equalTo(CGSizeMake(32, 32)); make.size.mas_equalTo(CGSizeMake(32, 32));
}]; }];
//
[_selectedColorView addSubview:self.selectedColorLabel]; [_selectedColorView addSubview:self.selectedColorLabel];
[self.selectedColorLabel mas_makeConstraints:^(MASConstraintMaker *make) { [self.selectedColorLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(colorDot.mas_trailing).offset(16); make.leading.equalTo(colorDot.mas_trailing).offset(16);
@@ -261,20 +261,21 @@
- (EPEmotionColorWheelView *)colorWheelView { - (EPEmotionColorWheelView *)colorWheelView {
if (!_colorWheelView) { if (!_colorWheelView) {
_colorWheelView = [[EPEmotionColorWheelView alloc] init]; _colorWheelView = [[EPEmotionColorWheelView alloc] init];
_colorWheelView.radius = 100.0; CGFloat wheelSize = MIN(300, [UIScreen mainScreen].bounds.size.width - 80);
_colorWheelView.buttonSize = 54.0; _colorWheelView.radius = wheelSize / 3.0;
_colorWheelView.buttonSize = 48.0;
__weak typeof(self) weakSelf = self; __weak typeof(self) weakSelf = self;
_colorWheelView.onColorTapped = ^(NSString *hexColor, NSInteger index) { _colorWheelView.onColorTapped = ^(NSString *hexColor, NSInteger index) {
__strong typeof(weakSelf) self = weakSelf; __strong typeof(weakSelf) self = weakSelf;
//
self.selectedColor = hexColor; self.selectedColor = hexColor;
//
[self updateSelectedColorDisplay:hexColor index:index]; [self updateSelectedColorDisplay:hexColor index:index];
//
self.confirmButton.enabled = YES; self.confirmButton.enabled = YES;
self.confirmButton.alpha = 1.0; self.confirmButton.alpha = 1.0;
}; };
@@ -282,26 +283,26 @@
return _colorWheelView; return _colorWheelView;
} }
///
- (void)updateSelectedColorDisplay:(NSString *)hexColor index:(NSInteger)index { - (void)updateSelectedColorDisplay:(NSString *)hexColor index:(NSInteger)index {
NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"]; NSArray<NSString *> *emotions = @[@"Joy", @"Sadness", @"Anger", @"Fear", @"Surprise", @"Disgust", @"Trust", @"Anticipation"];
//
self.selectedColorView.hidden = NO; self.selectedColorView.hidden = NO;
//
UIView *colorDot = [self.selectedColorView viewWithTag:100]; UIView *colorDot = [self.selectedColorView viewWithTag:100];
colorDot.backgroundColor = [self colorFromHex:hexColor]; colorDot.backgroundColor = [self colorFromHex:hexColor];
//
self.selectedColorLabel.text = emotions[index]; self.selectedColorLabel.text = emotions[index];
} }
/// Hex UIColor
- (UIColor *)colorFromHex:(NSString *)hexString { - (UIColor *)colorFromHex:(NSString *)hexString {
unsigned rgbValue = 0; unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hexString]; NSScanner *scanner = [NSScanner scannerWithString:hexString];
[scanner setScanLocation:1]; // # [scanner setScanLocation:1];
[scanner scanHexInt:&rgbValue]; [scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0
green:((rgbValue & 0xFF00) >> 8)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0
@@ -318,7 +319,7 @@
_confirmButton.layer.cornerRadius = 28; _confirmButton.layer.cornerRadius = 28;
_confirmButton.layer.masksToBounds = YES; _confirmButton.layer.masksToBounds = YES;
//
CAGradientLayer *gradient = [CAGradientLayer layer]; CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.colors = @[ gradient.colors = @[
(id)[UIColor colorWithRed:0x9B/255.0 green:0x59/255.0 blue:0xB6/255.0 alpha:1.0].CGColor, (id)[UIColor colorWithRed:0x9B/255.0 green:0x59/255.0 blue:0xB6/255.0 alpha:1.0].CGColor,
@@ -326,12 +327,12 @@
]; ];
gradient.startPoint = CGPointMake(0, 0); gradient.startPoint = CGPointMake(0, 0);
gradient.endPoint = CGPointMake(1, 0); gradient.endPoint = CGPointMake(1, 0);
gradient.frame = CGRectMake(0, 0, 1000, 56); // gradient.frame = CGRectMake(0, 0, 1000, 56);
[_confirmButton.layer insertSublayer:gradient atIndex:0]; [_confirmButton.layer insertSublayer:gradient atIndex:0];
[_confirmButton addTarget:self action:@selector(onConfirmButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_confirmButton addTarget:self action:@selector(onConfirmButtonTapped) forControlEvents:UIControlEventTouchUpInside];
//
_confirmButton.enabled = NO; _confirmButton.enabled = NO;
_confirmButton.alpha = 0.5; _confirmButton.alpha = 0.5;
} }
@@ -342,12 +343,12 @@
if (!_infoButton) { if (!_infoButton) {
_infoButton = [UIButton buttonWithType:UIButtonTypeCustom]; _infoButton = [UIButton buttonWithType:UIButtonTypeCustom];
// 使 info.circle
UIImage *infoIcon = [UIImage systemImageNamed:@"info.circle"]; UIImage *infoIcon = [UIImage systemImageNamed:@"info.circle"];
[_infoButton setImage:infoIcon forState:UIControlStateNormal]; [_infoButton setImage:infoIcon forState:UIControlStateNormal];
_infoButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8]; _infoButton.tintColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
//
[_infoButton addTarget:self action:@selector(onInfoButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_infoButton addTarget:self action:@selector(onInfoButtonTapped) forControlEvents:UIControlEventTouchUpInside];
} }
return _infoButton; return _infoButton;
@@ -363,10 +364,9 @@
_skipButton.layer.cornerRadius = 18; _skipButton.layer.cornerRadius = 18;
_skipButton.layer.masksToBounds = YES; _skipButton.layer.masksToBounds = YES;
[_skipButton addTarget:self action:@selector(onSkipButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [_skipButton addTarget:self action:@selector(onSkipButtonTapped) forControlEvents:UIControlEventTouchUpInside];
_skipButton.hidden = YES; // _skipButton.hidden = YES;
} }
return _skipButton; return _skipButton;
} }
@end @end

View File

@@ -1,33 +1,27 @@
//
// EPTabBarController.swift
// YuMi
//
// Created by AI on 2025-10-09. // Created by AI on 2025-10-09.
// Copyright © 2025 YuMi. All rights reserved. // Copyright © 2025 YuMi. All rights reserved.
//
import UIKit import UIKit
import SnapKit import SnapKit
/// EP TabBar
/// + Moment Mine Tab
@objc class EPTabBarController: UITabBarController { @objc class EPTabBarController: UITabBarController {
// MARK: - Properties // MARK: - Properties
///
private var globalEventManager: GlobalEventManager?
///
private var isLoggedIn: Bool = false private var isLoggedIn: Bool = false
/// TabBar
private var customTabBarView: UIView! private var customTabBarView: UIView!
///
private var tabBarBackgroundView: UIVisualEffectView! private var tabBarBackgroundView: UIVisualEffectView!
/// Tab
private var tabButtons: [UIButton] = [] private var tabButtons: [UIButton] = []
// MARK: - Lifecycle // MARK: - Lifecycle
@@ -35,49 +29,47 @@ import SnapKit
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
//
#if DEBUG #if DEBUG
APIConfig.testEncryption() APIConfig.testEncryption()
#endif #endif
// TabBar
self.tabBar.isHidden = true self.tabBar.isHidden = true
// delegate
self.delegate = self self.delegate = self
// ticket OC
performAutoLogin() performAutoLogin()
setupCustomFloatingTabBar() setupCustomFloatingTabBar()
setupGlobalManagers()
setupInitialViewControllers() setupInitialViewControllers()
NSLog("[EPTabBarController] 悬浮 TabBar 初始化完成") NSLog("[EPTabBarController] 悬浮 TabBar 初始化完成")
} }
deinit { deinit {
globalEventManager?.removeAllDelegates()
NSLog("[EPTabBarController] 已释放") NSLog("[EPTabBarController] 已释放")
} }
// MARK: - Setup // MARK: - Setup
/// TabBar
private func setupCustomFloatingTabBar() { private func setupCustomFloatingTabBar() {
//
customTabBarView = UIView() customTabBarView = UIView()
customTabBarView.translatesAutoresizingMaskIntoConstraints = false customTabBarView.translatesAutoresizingMaskIntoConstraints = false
customTabBarView.backgroundColor = .clear customTabBarView.backgroundColor = .clear
view.addSubview(customTabBarView) view.addSubview(customTabBarView)
// /
let effect: UIVisualEffect let effect: UIVisualEffect
if #available(iOS 26.0, *) { if #available(iOS 26.0, *) {
// iOS 26+ 使Material
effect = UIGlassEffect() effect = UIGlassEffect()
} else { } else {
// iOS 13-17 使
effect = UIBlurEffect(style: .systemMaterial) effect = UIBlurEffect(style: .systemMaterial)
} }
@@ -86,13 +78,13 @@ import SnapKit
tabBarBackgroundView.layer.cornerRadius = 28 tabBarBackgroundView.layer.cornerRadius = 28
tabBarBackgroundView.layer.masksToBounds = true tabBarBackgroundView.layer.masksToBounds = true
//
tabBarBackgroundView.layer.borderWidth = 0.5 tabBarBackgroundView.layer.borderWidth = 0.5
tabBarBackgroundView.layer.borderColor = UIColor.white.withAlphaComponent(0.2).cgColor tabBarBackgroundView.layer.borderColor = UIColor.white.withAlphaComponent(0.2).cgColor
customTabBarView.addSubview(tabBarBackgroundView) customTabBarView.addSubview(tabBarBackgroundView)
// Masonry
customTabBarView.snp.makeConstraints { make in customTabBarView.snp.makeConstraints { make in
make.leading.equalTo(view).offset(16) make.leading.equalTo(view).offset(16)
make.trailing.equalTo(view).offset(-16) make.trailing.equalTo(view).offset(-16)
@@ -104,20 +96,20 @@ import SnapKit
make.edges.equalTo(customTabBarView) make.edges.equalTo(customTabBarView)
} }
// Tab
setupTabButtons() setupTabButtons()
NSLog("[EPTabBarController] 悬浮 TabBar 设置完成") NSLog("[EPTabBarController] 悬浮 TabBar 设置完成")
} }
/// Tab
private func setupTabButtons() { private func setupTabButtons() {
let momentButton = createTabButton( let momentButton = createTabButton(
normalImage: "tab_moment_off", normalImage: "tab_moment_off",
selectedImage: "tab_moment_on", selectedImage: "tab_moment_on",
tag: 0 tag: 0
) )
// Message
let messageButton = createTabButton( let messageButton = createTabButton(
normalImage: "tab_message_off", normalImage: "tab_message_off",
selectedImage: "tab_message_on", selectedImage: "tab_message_on",
@@ -146,23 +138,23 @@ import SnapKit
make.bottom.equalTo(tabBarBackgroundView).offset(-8) make.bottom.equalTo(tabBarBackgroundView).offset(-8)
} }
//
updateTabButtonStates(selectedIndex: 0) updateTabButtonStates(selectedIndex: 0)
} }
/// Tab
private func createTabButton(normalImage: String, selectedImage: String, tag: Int) -> UIButton { private func createTabButton(normalImage: String, selectedImage: String, tag: Int) -> UIButton {
let button = UIButton(type: .custom) let button = UIButton(type: .custom)
button.tag = tag button.tag = tag
button.adjustsImageWhenHighlighted = false // button.adjustsImageWhenHighlighted = false
// 使 SF Symbols
if let normalImg = UIImage(named: normalImage), let selectedImg = UIImage(named: selectedImage) { if let normalImg = UIImage(named: normalImage), let selectedImg = UIImage(named: selectedImage) {
// normal selected
button.setImage(normalImg, for: .normal) button.setImage(normalImg, for: .normal)
button.setImage(selectedImg, for: .selected) button.setImage(selectedImg, for: .selected)
} else { } else {
// 使 SF Symbols
let fallbackIcons = ["sparkles", "person.circle"] let fallbackIcons = ["sparkles", "person.circle"]
let iconName = fallbackIcons[tag] let iconName = fallbackIcons[tag]
let imageConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .medium) let imageConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .medium)
@@ -173,14 +165,14 @@ import SnapKit
button.tintColor = .white.withAlphaComponent(0.6) button.tintColor = .white.withAlphaComponent(0.6)
} }
//
button.imageView?.contentMode = .scaleAspectFit button.imageView?.contentMode = .scaleAspectFit
//
button.setTitle(nil, for: .normal) button.setTitle(nil, for: .normal)
button.setTitle(nil, for: .selected) button.setTitle(nil, for: .selected)
//
button.imageView?.snp.makeConstraints { make in button.imageView?.snp.makeConstraints { make in
make.size.equalTo(28) make.size.equalTo(28)
} }
@@ -189,105 +181,90 @@ import SnapKit
return button return button
} }
/// Tab
@objc private func tabButtonTapped(_ sender: UIButton) { @objc private func tabButtonTapped(_ sender: UIButton) {
let newIndex = sender.tag let newIndex = sender.tag
// tab
if newIndex == selectedIndex { if newIndex == selectedIndex {
return return
} }
//
updateTabButtonStates(selectedIndex: newIndex) updateTabButtonStates(selectedIndex: newIndex)
// UITabBarController
UIView.performWithoutAnimation { UIView.performWithoutAnimation {
selectedIndex = newIndex selectedIndex = newIndex
} }
let tabNames = [ let tabNames = [YMLocalizedString("tab.moment"),
YMLocalizedString("tab.moment"), YMLocalizedString("tab.message"),
YMLocalizedString("tab.message"), YMLocalizedString("tab.mine")]
YMLocalizedString("tab.mine")
]
NSLog("[EPTabBarController] 选中 Tab: \(tabNames[newIndex])") NSLog("[EPTabBarController] 选中 Tab: \(tabNames[newIndex])")
} }
/// Tab
private func updateTabButtonStates(selectedIndex: Int) { private func updateTabButtonStates(selectedIndex: Int) {
//
tabButtons.forEach { $0.isUserInteractionEnabled = false } tabButtons.forEach { $0.isUserInteractionEnabled = false }
for (index, button) in tabButtons.enumerated() { for (index, button) in tabButtons.enumerated() {
let isSelected = (index == selectedIndex) let isSelected = (index == selectedIndex)
// isSelected
button.isSelected = isSelected button.isSelected = isSelected
// SF Symbols tintColor
if button.currentImage?.isSymbolImage == true { if button.currentImage?.isSymbolImage == true {
button.tintColor = isSelected ? .white : .white.withAlphaComponent(0.6) button.tintColor = isSelected ? .white : .white.withAlphaComponent(0.6)
} }
//
UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseOut], animations: { UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseOut], animations: {
button.transform = isSelected ? CGAffineTransform(scaleX: 1.1, y: 1.1) : .identity button.transform = isSelected ? CGAffineTransform(scaleX: 1.1, y: 1.1) : .identity
}) })
} }
//
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
self.tabButtons.forEach { $0.isUserInteractionEnabled = true } self.tabButtons.forEach { $0.isUserInteractionEnabled = true }
} }
} }
///
private func setupGlobalManagers() {
globalEventManager = GlobalEventManager.shared()
globalEventManager?.setupSDKDelegates()
// TODO: v0.2
// Build Configuration
/*
if let containerView = view {
globalEventManager?.setupRoomMiniView(on: containerView)
}
*/
//
globalEventManager?.registerSocialShareCallback()
NSLog("[EPTabBarController] 全局管理器设置完成v0.2 - 无 MiniRoom")
}
/// ViewController
private func setupInitialViewControllers() { private func setupInitialViewControllers() {
// Moment | Message | Mine // Moment | Message | Mine
let v1 = UINavigationController(rootViewController: UIViewController()) let momentVC = UIViewController()
v1.view.backgroundColor = .white momentVC.view.backgroundColor = .systemBlue
v1.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.moment"), normalImage: "tab_moment_normal", selectedImage: "tab_moment_selected") momentVC.title = "Moment"
let momentNav = UINavigationController(rootViewController: momentVC)
momentNav.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.moment"), normalImage: "tab_moment_normal", selectedImage: "tab_moment_selected")
let v2 = UINavigationController(rootViewController: UIViewController()) let messageVC = EPMessageMainViewController()
v2.view.backgroundColor = .white messageVC.title = "Message"
v2.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.message"), normalImage: "tab_message_normal", selectedImage: "tab_message_selected") let messageNav = UINavigationController(rootViewController: messageVC)
messageNav.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.message"), normalImage: "tab_message_normal", selectedImage: "tab_message_selected")
let v3 = UINavigationController(rootViewController: UIViewController()) //
v3.view.backgroundColor = .white messageVC.unreadCountDidChange = { [weak self] c in
v3.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.mine"), normalImage: "tab_mine_normal", selectedImage: "tab_mine_selected") let value: String? = c > 0 ? (c > 99 ? "99+" : "\(c)") : nil
self?.viewControllers?[1].tabBarItem.badgeValue = value
}
viewControllers = [v1, v2, v3] let mineVC = UIViewController()
mineVC.view.backgroundColor = .systemGreen
mineVC.title = "Mine"
let mineNav = UINavigationController(rootViewController: mineVC)
mineNav.tabBarItem = createTabBarItem(title: YMLocalizedString("tab.mine"), normalImage: "tab_mine_normal", selectedImage: "tab_mine_selected")
viewControllers = [momentNav, messageNav, mineNav]
selectedIndex = 0 selectedIndex = 0
NSLog("[EPTabBarController] 初始 ViewControllers 设置完成") NSLog("[EPTabBarController] 初始 ViewControllers 设置完成")
} }
/// TabBarItem
/// - Parameters:
/// - title:
/// - normalImage:
/// - selectedImage:
/// - Returns: UITabBarItem
private func createTabBarItem(title: String, normalImage: String, selectedImage: String) -> UITabBarItem { private func createTabBarItem(title: String, normalImage: String, selectedImage: String) -> UITabBarItem {
let item = UITabBarItem( let item = UITabBarItem(
title: title, title: title,
@@ -299,8 +276,7 @@ import SnapKit
// MARK: - Public Methods // MARK: - Public Methods
/// TabBar
/// - Parameter isLogin:
func refreshTabBar(isLogin: Bool) { func refreshTabBar(isLogin: Bool) {
isLoggedIn = isLogin isLoggedIn = isLogin
@@ -313,63 +289,50 @@ import SnapKit
NSLog("[EPTabBarController] TabBar 已刷新,登录状态: \(isLogin)") NSLog("[EPTabBarController] TabBar 已刷新,登录状态: \(isLogin)")
} }
/// ViewControllers
private func setupLoggedInViewControllers() { private func setupLoggedInViewControllers() {
// Moment | Message | Mine
if viewControllers?.count != 3 ||
!(viewControllers?[0] is UINavigationController) ||
!(viewControllers?[1] is UINavigationController) ||
!(viewControllers?[2] is UINavigationController) {
// //
let momentVC = EPMomentViewController() let momentVC = EPMomentViewController()
momentVC.title = YMLocalizedString("tab.moment") momentVC.title = YMLocalizedString("tab.moment")
let momentNav = createTransparentNavigationController( let momentNav = createTransparentNavigationController(
rootViewController: momentVC, rootViewController: momentVC,
tabTitle: YMLocalizedString("tab.moment"), tabTitle: YMLocalizedString("tab.moment"),
normalImage: "tab_moment_normal", normalImage: "tab_moment_normal",
selectedImage: "tab_moment_selected" selectedImage: "tab_moment_selected"
) )
// Swift UIKit // Swift UIKit
let messageVC = EPMessageMainViewController() let messageVC = EPMessageMainViewController()
let messageNav = createTransparentNavigationController( let messageNav = createTransparentNavigationController(
rootViewController: messageVC, rootViewController: messageVC,
tabTitle: YMLocalizedString("tab.message"), tabTitle: YMLocalizedString("tab.message"),
normalImage: "tab_message_normal", normalImage: "tab_message_normal",
selectedImage: "tab_message_selected" selectedImage: "tab_message_selected"
) )
//
// messageVC.unreadCountDidChange = { [weak self] c in
messageVC.unreadCountDidChange = { [weak self] c in let value: String? = c > 0 ? (c > 99 ? "99+" : "\(c)") : nil
let value: String? = c > 0 ? (c > 99 ? "99+" : "\(c)") : nil self?.viewControllers?[1].tabBarItem.badgeValue = value
self?.viewControllers?[1].tabBarItem.badgeValue = value
}
//
let mineVC = EPMineViewController()
mineVC.title = YMLocalizedString("tab.mine")
let mineNav = createTransparentNavigationController(
rootViewController: mineVC,
tabTitle: YMLocalizedString("tab.mine"),
normalImage: "tab_mine_normal",
selectedImage: "tab_mine_selected"
)
viewControllers = [momentNav, messageNav, mineNav]
NSLog("[EPTabBarController] 登录后 ViewControllers 创建完成 - Moment & Message & Mine")
} }
//
let mineVC = EPMineViewController()
mineVC.title = YMLocalizedString("tab.mine")
let mineNav = createTransparentNavigationController(
rootViewController: mineVC,
tabTitle: YMLocalizedString("tab.mine"),
normalImage: "tab_mine_normal",
selectedImage: "tab_mine_selected"
)
viewControllers = [momentNav, messageNav, mineNav]
NSLog("[EPTabBarController] 登录后 ViewControllers 创建完成 - Moment & Message & Mine")
selectedIndex = 0 selectedIndex = 0
} }
///
/// - Parameters:
/// - rootViewController:
/// - tabTitle: TabBar
/// - normalImage:
/// - selectedImage:
/// - Returns: UINavigationController
private func createTransparentNavigationController( private func createTransparentNavigationController(
rootViewController: UIViewController, rootViewController: UIViewController,
tabTitle: String, tabTitle: String,
@@ -387,7 +350,7 @@ import SnapKit
selectedImage: selectedImage selectedImage: selectedImage
) )
// delegate
nav.delegate = self nav.delegate = self
return nav return nav
@@ -395,7 +358,7 @@ import SnapKit
// MARK: - TabBar Visibility Control // MARK: - TabBar Visibility Control
/// TabBar
private func showCustomTabBar(animated: Bool = true) { private func showCustomTabBar(animated: Bool = true) {
guard customTabBarView.isHidden else { return } guard customTabBarView.isHidden else { return }
@@ -414,7 +377,7 @@ import SnapKit
} }
} }
/// TabBar
private func hideCustomTabBar(animated: Bool = true) { private func hideCustomTabBar(animated: Bool = true) {
guard !customTabBarView.isHidden else { return } guard !customTabBarView.isHidden else { return }
@@ -441,18 +404,18 @@ extension EPTabBarController: UITabBarControllerDelegate {
NSLog("[EPTabBarController] 选中 Tab: \(item.title ?? "Unknown")") NSLog("[EPTabBarController] 选中 Tab: \(item.title ?? "Unknown")")
} }
///
func tabBarController(_ tabBarController: UITabBarController, func tabBarController(_ tabBarController: UITabBarController,
animationControllerForTransitionFrom fromVC: UIViewController, animationControllerForTransitionFrom fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// nil 使
return nil return nil
} }
///
func tabBarController(_ tabBarController: UITabBarController, func tabBarController(_ tabBarController: UITabBarController,
shouldSelect viewController: UIViewController) -> Bool { shouldSelect viewController: UIViewController) -> Bool {
// nil animationController
return true return true
} }
} }
@@ -465,15 +428,15 @@ extension EPTabBarController: UINavigationControllerDelegate {
willShow viewController: UIViewController, willShow viewController: UIViewController,
animated: Bool) { animated: Bool) {
//
let isRootViewController = navigationController.viewControllers.count == 1 let isRootViewController = navigationController.viewControllers.count == 1
if isRootViewController { if isRootViewController {
// TabBar
showCustomTabBar(animated: animated) showCustomTabBar(animated: animated)
NSLog("[EPTabBarController] 显示 TabBar - 根页面") NSLog("[EPTabBarController] 显示 TabBar - 根页面")
} else { } else {
// TabBar
hideCustomTabBar(animated: animated) hideCustomTabBar(animated: animated)
NSLog("[EPTabBarController] 隐藏 TabBar - 子页面 (层级: \(navigationController.viewControllers.count))") NSLog("[EPTabBarController] 隐藏 TabBar - 子页面 (层级: \(navigationController.viewControllers.count))")
} }
@@ -484,16 +447,16 @@ extension EPTabBarController: UINavigationControllerDelegate {
extension EPTabBarController { extension EPTabBarController {
/// ticket OC MainPresenter.autoLogin
private func performAutoLogin() { private func performAutoLogin() {
// 1.
guard let accountModel = AccountInfoStorage.instance().getCurrentAccountInfo() else { guard let accountModel = AccountInfoStorage.instance().getCurrentAccountInfo() else {
NSLog("[EPTabBarController] ⚠️ 账号信息不存在,跳转到登录页") NSLog("[EPTabBarController] ⚠️ 账号信息不存在,跳转到登录页")
handleTokenInvalid() handleTokenInvalid()
return return
} }
// 2. uid access_token
let uid = accountModel.uid let uid = accountModel.uid
let accessToken = accountModel.access_token let accessToken = accountModel.access_token
@@ -503,14 +466,14 @@ extension EPTabBarController {
return return
} }
// 3. ticket
let existingTicket = AccountInfoStorage.instance().getTicket() ?? "" let existingTicket = AccountInfoStorage.instance().getTicket() ?? ""
if !existingTicket.isEmpty { if !existingTicket.isEmpty {
NSLog("[EPTabBarController] ✅ Ticket 已存在,自动登录成功") NSLog("[EPTabBarController] ✅ Ticket 已存在,自动登录成功")
return return
} }
// 4. Ticket ticket
NSLog("[EPTabBarController] 🔄 Ticket 不存在,正在请求...") NSLog("[EPTabBarController] 🔄 Ticket 不存在,正在请求...")
let loginService = EPLoginService() let loginService = EPLoginService()
@@ -520,28 +483,28 @@ extension EPTabBarController {
} failure: { [weak self] code, msg in } failure: { [weak self] code, msg in
NSLog("[EPTabBarController] ❌ Ticket 请求失败 (\(code)): \(msg)") NSLog("[EPTabBarController] ❌ Ticket 请求失败 (\(code)): \(msg)")
// Ticket 退 OC MainPresenter
DispatchQueue.main.async { DispatchQueue.main.async {
self?.handleTokenInvalid() self?.handleTokenInvalid()
} }
} }
} }
/// Token
private func handleTokenInvalid() { private func handleTokenInvalid() {
NSLog("[EPTabBarController] ⚠️ Token 失效,清空账号数据...") NSLog("[EPTabBarController] ⚠️ Token 失效,清空账号数据...")
// 1.
AccountInfoStorage.instance().saveAccountInfo(nil) AccountInfoStorage.instance().saveAccountInfo(nil)
AccountInfoStorage.instance().saveTicket("") AccountInfoStorage.instance().saveTicket("")
// 2.
DispatchQueue.main.async { DispatchQueue.main.async {
let loginVC = EPLoginViewController() let loginVC = EPLoginViewController()
let nav = BaseNavigationController(rootViewController: loginVC) let nav = BaseNavigationController(rootViewController: loginVC)
nav.modalPresentationStyle = .fullScreen nav.modalPresentationStyle = .fullScreen
// keyWindowiOS 13+
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
for scene in UIApplication.shared.connectedScenes { for scene in UIApplication.shared.connectedScenes {
if let windowScene = scene as? UIWindowScene, if let windowScene = scene as? UIWindowScene,
@@ -568,12 +531,12 @@ extension EPTabBarController {
extension EPTabBarController { extension EPTabBarController {
/// OC
@objc static func create() -> EPTabBarController { @objc static func create() -> EPTabBarController {
return EPTabBarController() return EPTabBarController()
} }
/// OC TabBar
@objc func refreshTabBarWithIsLogin(_ isLogin: Bool) { @objc func refreshTabBarWithIsLogin(_ isLogin: Bool) {
refreshTabBar(isLogin: isLogin) refreshTabBar(isLogin: isLogin)
} }

View File

@@ -65,7 +65,7 @@ static XPCoreDataManager *manager = nil;
* URL: * URL:
* options: * options:
*/ */
NSURL *url = [[self getDocumnetUrlpath] URLByAppendingPathComponent:@"sqlit.db" isDirectory:true]; NSURL *url = [[self getDocumnetUrlpath] URLByAppendingPathComponent:@"sqlit.db" isDirectory:NO];
[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:nil]; [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:nil];
} }
return _persistentStoreCoordinator; return _persistentStoreCoordinator;