diff --git a/Fableon.xcodeproj/project.pbxproj b/Fableon.xcodeproj/project.pbxproj index 73b94e6..d2428a9 100644 --- a/Fableon.xcodeproj/project.pbxproj +++ b/Fableon.xcodeproj/project.pbxproj @@ -17,6 +17,29 @@ 031FDEBA2EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEB92EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift */; }; 031FDEBC2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEBB2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift */; }; 031FDEBE2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEBD2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift */; }; + 031FDEC02EB1C08900F4CAC7 /* FAMeCoinsPackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEBF2EB1C08900F4CAC7 /* FAMeCoinsPackButton.swift */; }; + 031FDEC22EB1E19D00F4CAC7 /* FACoinPackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEC12EB1E19D00F4CAC7 /* FACoinPackViewController.swift */; }; + 031FDEC42EB1E45300F4CAC7 /* FACoinPackHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEC32EB1E45300F4CAC7 /* FACoinPackHeaderView.swift */; }; + 031FDEC62EB1E4E600F4CAC7 /* FACoinPackTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEC52EB1E4E600F4CAC7 /* FACoinPackTitleView.swift */; }; + 031FDEC82EB1F89F00F4CAC7 /* FACoinsPackModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEC72EB1F89F00F4CAC7 /* FACoinsPackModel.swift */; }; + 031FDECA2EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEC92EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift */; }; + 031FDECC2EB1FDF500F4CAC7 /* FACoinsPackClaimListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDECB2EB1FDF500F4CAC7 /* FACoinsPackClaimListView.swift */; }; + 031FDECE2EB2006000F4CAC7 /* FACoinsPackClaimListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDECD2EB2006000F4CAC7 /* FACoinsPackClaimListCell.swift */; }; + 031FDED02EB2167200F4CAC7 /* FACoinsPackBuyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDECF2EB2167200F4CAC7 /* FACoinsPackBuyView.swift */; }; + 031FDED22EB2F69200F4CAC7 /* FALoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDED12EB2F69200F4CAC7 /* FALoginView.swift */; }; + 031FDED42EB2FF4000F4CAC7 /* FALogin+Apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDED32EB2FF3A00F4CAC7 /* FALogin+Apple.swift */; }; + 031FDED62EB300F400F4CAC7 /* FAThirdSignModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDED52EB300F400F4CAC7 /* FAThirdSignModel.swift */; }; + 031FDED92EB30D6E00F4CAC7 /* FASettingCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 031FDED82EB30D6E00F4CAC7 /* FASettingCell.xib */; }; + 031FDEDA2EB30D6E00F4CAC7 /* FASettingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDED72EB30D6E00F4CAC7 /* FASettingCell.swift */; }; + 031FDEDC2EB3141E00F4CAC7 /* FASettingFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEDB2EB3141E00F4CAC7 /* FASettingFooterView.swift */; }; + 031FDEDF2EB3423000F4CAC7 /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 031FDEDE2EB3423000F4CAC7 /* FacebookLogin */; }; + 031FDEE12EB344AB00F4CAC7 /* FALogin+Facebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEE02EB344A200F4CAC7 /* FALogin+Facebook.swift */; }; + 031FDEE42EB348AA00F4CAC7 /* FABaseAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEE32EB348AA00F4CAC7 /* FABaseAlert.swift */; }; + 031FDEE62EB34FBC00F4CAC7 /* FARemoveCollectAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEE52EB34FBC00F4CAC7 /* FARemoveCollectAlert.swift */; }; + 031FDEE82EB358AE00F4CAC7 /* FAHomeCoinsPackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEE72EB358AE00F4CAC7 /* FAHomeCoinsPackButton.swift */; }; + 031FDEEA2EB35D2600F4CAC7 /* FACoinPackCanReceiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEE92EB35D2600F4CAC7 /* FACoinPackCanReceiveModel.swift */; }; + 031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEEB2EB35DF600F4CAC7 /* FACoinsPackAlert.swift */; }; + 031FDEEE2EB3682000F4CAC7 /* FAVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 031FDEED2EB3682000F4CAC7 /* FAVipRetainAlert.swift */; }; 039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */; }; 039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */; }; 039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */; }; @@ -189,6 +212,11 @@ 03E23AB72EAA1A7F004A8CEC /* FALocalized.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E23A9C2EAA1A7F004A8CEC /* FALocalized.swift */; }; 03E23AB82EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E23AAA2EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift */; }; 03E23ABA2EAA1D85004A8CEC /* MNNItemController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E23AB92EAA1D85004A8CEC /* MNNItemController.swift */; }; + 03E9A7362EB44F26000D1067 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 03E9A7352EB44F26000D1067 /* FirebaseMessaging */; }; + 03E9A7382EB44F26000D1067 /* FirebasePerformance in Frameworks */ = {isa = PBXBuildFile; productRef = 03E9A7372EB44F26000D1067 /* FirebasePerformance */; }; + 03E9A73A2EB45154000D1067 /* AppDelegate+FAApns.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7392EB45149000D1067 /* AppDelegate+FAApns.swift */; }; + 03E9A73C2EB45507000D1067 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 03E9A73B2EB45507000D1067 /* GoogleService-Info.plist */; }; + 03E9A73E2EB460F2000D1067 /* FAApnsAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A73D2EB460F2000D1067 /* FAApnsAlert.swift */; }; B86XD3O90WO2R4725L084287 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */; }; F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38E33739F391364D0151P7Z /* ZStreamCell.swift */; }; F30470W590T8274E1642349G /* CControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32MR5F8X6Q3HSZ560BD0159 /* CControlCell.swift */; }; @@ -306,6 +334,28 @@ 031FDEB92EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackConfirmItem2View.swift; sourceTree = ""; }; 031FDEBB2EB0C97A00F4CAC7 /* FAOldVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAOldVideoRechargeView.swift; sourceTree = ""; }; 031FDEBD2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FANewVideoRechargeView.swift; sourceTree = ""; }; + 031FDEBF2EB1C08900F4CAC7 /* FAMeCoinsPackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAMeCoinsPackButton.swift; sourceTree = ""; }; + 031FDEC12EB1E19D00F4CAC7 /* FACoinPackViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackViewController.swift; sourceTree = ""; }; + 031FDEC32EB1E45300F4CAC7 /* FACoinPackHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackHeaderView.swift; sourceTree = ""; }; + 031FDEC52EB1E4E600F4CAC7 /* FACoinPackTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackTitleView.swift; sourceTree = ""; }; + 031FDEC72EB1F89F00F4CAC7 /* FACoinsPackModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackModel.swift; sourceTree = ""; }; + 031FDEC92EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackReceiveModel.swift; sourceTree = ""; }; + 031FDECB2EB1FDF500F4CAC7 /* FACoinsPackClaimListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackClaimListView.swift; sourceTree = ""; }; + 031FDECD2EB2006000F4CAC7 /* FACoinsPackClaimListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackClaimListCell.swift; sourceTree = ""; }; + 031FDECF2EB2167200F4CAC7 /* FACoinsPackBuyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackBuyView.swift; sourceTree = ""; }; + 031FDED12EB2F69200F4CAC7 /* FALoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALoginView.swift; sourceTree = ""; }; + 031FDED32EB2FF3A00F4CAC7 /* FALogin+Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FALogin+Apple.swift"; sourceTree = ""; }; + 031FDED52EB300F400F4CAC7 /* FAThirdSignModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAThirdSignModel.swift; sourceTree = ""; }; + 031FDED72EB30D6E00F4CAC7 /* FASettingCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FASettingCell.swift; sourceTree = ""; }; + 031FDED82EB30D6E00F4CAC7 /* FASettingCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FASettingCell.xib; sourceTree = ""; }; + 031FDEDB2EB3141E00F4CAC7 /* FASettingFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FASettingFooterView.swift; sourceTree = ""; }; + 031FDEE02EB344A200F4CAC7 /* FALogin+Facebook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FALogin+Facebook.swift"; sourceTree = ""; }; + 031FDEE32EB348AA00F4CAC7 /* FABaseAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABaseAlert.swift; sourceTree = ""; }; + 031FDEE52EB34FBC00F4CAC7 /* FARemoveCollectAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FARemoveCollectAlert.swift; sourceTree = ""; }; + 031FDEE72EB358AE00F4CAC7 /* FAHomeCoinsPackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAHomeCoinsPackButton.swift; sourceTree = ""; }; + 031FDEE92EB35D2600F4CAC7 /* FACoinPackCanReceiveModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinPackCanReceiveModel.swift; sourceTree = ""; }; + 031FDEEB2EB35DF600F4CAC7 /* FACoinsPackAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FACoinsPackAlert.swift; sourceTree = ""; }; + 031FDEED2EB3682000F4CAC7 /* FAVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAVipRetainAlert.swift; sourceTree = ""; }; 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAAdjust.swift"; sourceTree = ""; }; 039CE6082EAA2F62007B5EED /* FAAdjustStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAdjustStateManager.swift; sourceTree = ""; }; 039CE60A2EAA31CB007B5EED /* FAStatAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStatAPI.swift; sourceTree = ""; }; @@ -479,6 +529,9 @@ 03E23AA82EAA1A7F004A8CEC /* FAToast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAToast.swift; sourceTree = ""; }; 03E23AAA2EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWaterfallFlowLayout.swift; sourceTree = ""; }; 03E23AB92EAA1D85004A8CEC /* MNNItemController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MNNItemController.swift; sourceTree = ""; }; + 03E9A7392EB45149000D1067 /* AppDelegate+FAApns.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+FAApns.swift"; sourceTree = ""; }; + 03E9A73B2EB45507000D1067 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 03E9A73D2EB460F2000D1067 /* FAApnsAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAApnsAlert.swift; sourceTree = ""; }; 19196I43BR665O55RD205171 /* Pods-Fableon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.debug.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.debug.xcconfig"; sourceTree = ""; }; C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fableon.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DCD59738B6J31K33W4Z524S0 /* Pods-Fableon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.release.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.release.xcconfig"; sourceTree = ""; }; @@ -594,6 +647,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 03E9A7362EB44F26000D1067 /* FirebaseMessaging in Frameworks */, + 031FDEDF2EB3423000F4CAC7 /* FacebookLogin in Frameworks */, + 03E9A7382EB44F26000D1067 /* FirebasePerformance in Frameworks */, B86XD3O90WO2R4725L084287 /* Pods_Fableon.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -601,6 +657,18 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 031FDEE22EB3487700F4CAC7 /* Alert */ = { + isa = PBXGroup; + children = ( + 031FDEE32EB348AA00F4CAC7 /* FABaseAlert.swift */, + 031FDEE52EB34FBC00F4CAC7 /* FARemoveCollectAlert.swift */, + 031FDEEB2EB35DF600F4CAC7 /* FACoinsPackAlert.swift */, + 031FDEED2EB3682000F4CAC7 /* FAVipRetainAlert.swift */, + 03E9A73D2EB460F2000D1067 /* FAApnsAlert.swift */, + ); + path = Alert; + sourceTree = ""; + }; 039CE6072EAA2F37007B5EED /* AdjustStateManager */ = { isa = PBXGroup; children = ( @@ -645,6 +713,9 @@ 031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */, 031FDEAF2EB09AB300F4CAC7 /* FARechargeRecordModel.swift */, 031FDEB12EB0A5AF00F4CAC7 /* FASendCoinRecordModel.swift */, + 031FDEC72EB1F89F00F4CAC7 /* FACoinsPackModel.swift */, + 031FDEC92EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift */, + 031FDEE92EB35D2600F4CAC7 /* FACoinPackCanReceiveModel.swift */, ); path = M; sourceTree = ""; @@ -849,6 +920,7 @@ 03E239DF2EAA1A4E004A8CEC /* FASearchResultCell.swift */, 03E239E02EAA1A4E004A8CEC /* FASearchResultCell.xib */, 03E239E12EAA1A4E004A8CEC /* FASearchResultView.swift */, + 031FDEE72EB358AE00F4CAC7 /* FAHomeCoinsPackButton.swift */, ); path = V; sourceTree = ""; @@ -882,6 +954,7 @@ 03E239E92EAA1A4E004A8CEC /* FAMeListViewController.swift */, 03E239EA2EAA1A4E004A8CEC /* FAMeViewController.swift */, 03E239EB2EAA1A4E004A8CEC /* FASettingViewController.swift */, + 031FDEC12EB1E19D00F4CAC7 /* FACoinPackViewController.swift */, ); path = C; sourceTree = ""; @@ -905,6 +978,16 @@ 03E239F42EAA1A4E004A8CEC /* FAMeCoinsView.swift */, 03E239F52EAA1A4E004A8CEC /* FAMeHeaderView.swift */, 03E239F62EAA1A4E004A8CEC /* FAMeTableViewHeaderView.swift */, + 031FDEBF2EB1C08900F4CAC7 /* FAMeCoinsPackButton.swift */, + 031FDEC52EB1E4E600F4CAC7 /* FACoinPackTitleView.swift */, + 031FDEC32EB1E45300F4CAC7 /* FACoinPackHeaderView.swift */, + 031FDECB2EB1FDF500F4CAC7 /* FACoinsPackClaimListView.swift */, + 031FDECD2EB2006000F4CAC7 /* FACoinsPackClaimListCell.swift */, + 031FDECF2EB2167200F4CAC7 /* FACoinsPackBuyView.swift */, + 031FDED12EB2F69200F4CAC7 /* FALoginView.swift */, + 031FDED72EB30D6E00F4CAC7 /* FASettingCell.swift */, + 031FDED82EB30D6E00F4CAC7 /* FASettingCell.xib */, + 031FDEDB2EB3141E00F4CAC7 /* FASettingFooterView.swift */, ); path = V; sourceTree = ""; @@ -1101,6 +1184,7 @@ 03E23A962EAA1A65004A8CEC /* Libs */ = { isa = PBXGroup; children = ( + 031FDEE22EB3487700F4CAC7 /* Alert */, 039CE6122EAB0DE1007B5EED /* FAIap */, 039CE60F2EAB0D2D007B5EED /* JXIAPManager */, 039CE6072EAA2F37007B5EED /* AdjustStateManager */, @@ -1145,8 +1229,11 @@ isa = PBXGroup; children = ( 03E23A9E2EAA1A7F004A8CEC /* FALogin.swift */, + 031FDED32EB2FF3A00F4CAC7 /* FALogin+Apple.swift */, + 031FDEE02EB344A200F4CAC7 /* FALogin+Facebook.swift */, 03E23A9F2EAA1A7F004A8CEC /* FATokenModel.swift */, 03E23AA02EAA1A7F004A8CEC /* FAUserInfo.swift */, + 031FDED52EB300F400F4CAC7 /* FAThirdSignModel.swift */, ); path = FALogin; sourceTree = ""; @@ -1555,6 +1642,7 @@ isa = PBXGroup; children = ( F32J2363K02108Z62849Y019 /* Assets.xcassets */, + 03E9A73B2EB45507000D1067 /* GoogleService-Info.plist */, F3718184F516RJ76435E1IQ3 /* Info.plist */, F3S22333V8I503E2Z4YYN165 /* LaunchScreen.storyboard */, F3A0557617AU32W3L218F159 /* Localizable.strings */, @@ -1600,9 +1688,10 @@ isa = PBXGroup; children = ( 03E239602EAA1945004A8CEC /* AppDelegate.swift */, + 03E239622EAA1945004A8CEC /* SceneDelegate.swift */, 03E239612EAA1945004A8CEC /* AppDelegate+FAConfig.swift */, 039CE6032EAA2612007B5EED /* AppDelegate+FAAdjust.swift */, - 03E239622EAA1945004A8CEC /* SceneDelegate.swift */, + 03E9A7392EB45149000D1067 /* AppDelegate+FAApns.swift */, ); path = App; sourceTree = ""; @@ -1713,6 +1802,10 @@ ); mainGroup = F31ABI705806054356280I22; minimizedProjectReferenceProxies = 1; + packageReferences = ( + 031FDEDD2EB3423000F4CAC7 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */, + 03E9A7342EB44F26000D1067 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, + ); preferredProjectObjectVersion = 77; productRefGroup = F3B536I6734E05L319J6654P /* Products */; projectDirPath = ""; @@ -1744,6 +1837,7 @@ 03E23A862EAA1A4E004A8CEC /* FAHistoryCell.xib in Resources */, 03E23A872EAA1A4E004A8CEC /* FAHomeRecommendedCell.xib in Resources */, 03E23A882EAA1A4E004A8CEC /* FAMeCell.xib in Resources */, + 031FDED92EB30D6E00F4CAC7 /* FASettingCell.xib in Resources */, 03E23A892EAA1A4E004A8CEC /* FASearchResultCell.xib in Resources */, 03E23A8A2EAA1A4E004A8CEC /* FASearchRecommendCell.xib in Resources */, 03E23A8B2EAA1A4E004A8CEC /* FAHomeSectionTitleView.xib in Resources */, @@ -1756,6 +1850,7 @@ 03E23A922EAA1A4E004A8CEC /* FAConsumptionRecordsCell.xib in Resources */, 03E23A932EAA1A4E004A8CEC /* FASearchRecordCell.xib in Resources */, 03E23A942EAA1A4E004A8CEC /* FARankingListCell.xib in Resources */, + 03E9A73C2EB45507000D1067 /* GoogleService-Info.plist in Resources */, 03E23A952EAA1A4E004A8CEC /* FAAboutCell.xib in Resources */, F3R81ZR0ZIP4Q85CX4Z5J3I4 /* LaunchScreen.storyboard in Resources */, F362972840Y56X1RPFI92W64 /* XKRefreshCell.xib in Resources */, @@ -1838,12 +1933,14 @@ F336143N569M8JG811WM9549 /* XHEedbackDetailView.swift in Sources */, F3F0952W592747Y1H6263E06 /* UCVBbfdebaffdFlowCell.swift in Sources */, F3SUP8DL68BIIEF1B8Z6U863 /* CFQConfigView.swift in Sources */, + 031FDEE12EB344AB00F4CAC7 /* FALogin+Facebook.swift in Sources */, F30E153206675C3SJ3974VL1 /* OJQUnechoSectionView.swift in Sources */, F381909BQ5JWXYI119A49469 /* DREychainCell.swift in Sources */, F39R66F983517825QO331145 /* QCenterEfineView.swift in Sources */, F3II3AF834346F516W51V693 /* GAMainRecommendedView.swift in Sources */, 031FDEAE2EB093B100F4CAC7 /* FABuyRecordsModel.swift in Sources */, F377Y22Z3J44H22J23963544 /* CDNewsController.swift in Sources */, + 031FDEC22EB1E19D00F4CAC7 /* FACoinPackViewController.swift in Sources */, F358686093028548K00WQIO1 /* NGleeVionView.swift in Sources */, F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */, F392T441X031FH7N0HA03SZ7 /* WPSectionView.swift in Sources */, @@ -1865,6 +1962,7 @@ F3P4D170962A2JAF14W0520R /* ADCheckMageView.swift in Sources */, 031FDEBA2EB0B82600F4CAC7 /* FACoinPackConfirmItem2View.swift in Sources */, F3206101P0DVK224N85S1W62 /* XIPathEviceController.swift in Sources */, + 031FDEC82EB1F89F00F4CAC7 /* FACoinsPackModel.swift in Sources */, F31N0S2575E3YC5AOG80WE90 /* TYElyon.swift in Sources */, F3JX29E3JQ40V23245TS8Z36 /* YRegisterController.swift in Sources */, F381171472542RD403O12925 /* QZOast.swift in Sources */, @@ -1882,6 +1980,7 @@ 03E23AAC2EAA1A7F004A8CEC /* FALogin.swift in Sources */, 03E23AAD2EAA1A7F004A8CEC /* FAKeychainHelper.swift in Sources */, 03E23AAE2EAA1A7F004A8CEC /* FATool.swift in Sources */, + 031FDECC2EB1FDF500F4CAC7 /* FACoinsPackClaimListView.swift in Sources */, 039CE6262EAB2A72007B5EED /* FAPayAlertModel.swift in Sources */, 03E23AAF2EAA1A7F004A8CEC /* FSPagerSwiftUIView.swift in Sources */, 03E23AB02EAA1A7F004A8CEC /* FADeviceIDManager.swift in Sources */, @@ -1896,6 +1995,7 @@ 03E23AB72EAA1A7F004A8CEC /* FALocalized.swift in Sources */, 039CE6222EAB1340007B5EED /* FAUserDefaultsKey.swift in Sources */, 03E23AB82EAA1A7F004A8CEC /* FAWaterfallFlowLayout.swift in Sources */, + 031FDEC62EB1E4E600F4CAC7 /* FACoinPackTitleView.swift in Sources */, F3K238643L913I6RK4G7S006 /* CSceneRegister.swift in Sources */, F3ZT3I4VAGB5405FWL36UW12 /* ZFGEtworkCell.swift in Sources */, F35O71332554S53191121042 /* UOModalCell.swift in Sources */, @@ -1908,6 +2008,7 @@ 03E23A352EAA1A4E004A8CEC /* FARecommendPlayerControlView.swift in Sources */, 03E23A362EAA1A4E004A8CEC /* FAHomeMustSeeView.swift in Sources */, 03E23A372EAA1A4E004A8CEC /* FAHomeItem.swift in Sources */, + 03E9A73E2EB460F2000D1067 /* FAApnsAlert.swift in Sources */, 03E23A382EAA1A4E004A8CEC /* FACategoryModel.swift in Sources */, 03E23A392EAA1A4E004A8CEC /* FANewListViewController.swift in Sources */, 03E23A3A2EAA1A4E004A8CEC /* FAHomeRecommendedCell.swift in Sources */, @@ -1928,12 +2029,14 @@ 03E23A492EAA1A4E004A8CEC /* FAVideoInfoModel.swift in Sources */, 039CE6202EAB114B007B5EED /* FAPayDateModel.swift in Sources */, 03E23A4A2EAA1A4E004A8CEC /* FAConsumptionRecordsViewController.swift in Sources */, + 031FDED02EB2167200F4CAC7 /* FACoinsPackBuyView.swift in Sources */, 03E23A4B2EAA1A4E004A8CEC /* FAMeCoinsView.swift in Sources */, 03E23A4C2EAA1A4E004A8CEC /* FAHomeViewModel.swift in Sources */, 03E23A4D2EAA1A4E004A8CEC /* FAGenresViewController.swift in Sources */, 03E23A4E2EAA1A4E004A8CEC /* FAHomeBannerContentCell.swift in Sources */, 03E23A4F2EAA1A4E004A8CEC /* FAEpSelectorView.swift in Sources */, 03E23A502EAA1A4E004A8CEC /* FAMeHeaderView.swift in Sources */, + 031FDEC02EB1C08900F4CAC7 /* FAMeCoinsPackButton.swift in Sources */, 03E23A512EAA1A4E004A8CEC /* FAConsumptionRecordsCell.swift in Sources */, 03E23A522EAA1A4E004A8CEC /* FARankingListHeaderView.swift in Sources */, 03E23A532EAA1A4E004A8CEC /* FAVideoLockView.swift in Sources */, @@ -1941,20 +2044,25 @@ 03E23A552EAA1A4E004A8CEC /* FAPopularListViewController.swift in Sources */, 039CE6042EAA2621007B5EED /* AppDelegate+FAAdjust.swift in Sources */, 03E23A562EAA1A4E004A8CEC /* FAPlayerEpUIButton.swift in Sources */, + 031FDEE42EB348AA00F4CAC7 /* FABaseAlert.swift in Sources */, 03E23A572EAA1A4E004A8CEC /* FAHistoryCell.swift in Sources */, 03E23A582EAA1A4E004A8CEC /* FASearchViewController.swift in Sources */, 03E23A592EAA1A4E004A8CEC /* FAWalletCell.swift in Sources */, 03E23A5A2EAA1A4E004A8CEC /* FASearchInputView.swift in Sources */, + 031FDEE82EB358AE00F4CAC7 /* FAHomeCoinsPackButton.swift in Sources */, 03E23A5B2EAA1A4E004A8CEC /* FAAboutCell.swift in Sources */, 03E23A5C2EAA1A4E004A8CEC /* FAGenresListViewController.swift in Sources */, 03E23A5D2EAA1A4E004A8CEC /* FARecommendViewModel.swift in Sources */, 03E23A5E2EAA1A4E004A8CEC /* FAHomeMustSeeContentView.swift in Sources */, 03E23A5F2EAA1A4E004A8CEC /* FAEpSelectorCell.swift in Sources */, + 031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */, 03E23A602EAA1A4E004A8CEC /* FASearchResultView.swift in Sources */, 03E23A612EAA1A4E004A8CEC /* FAHomeMustSeeContentCell.swift in Sources */, 03E23A622EAA1A4E004A8CEC /* FAShortDetailModel.swift in Sources */, 03E23A632EAA1A4E004A8CEC /* FASearchResultCell.swift in Sources */, 03E23A642EAA1A4E004A8CEC /* FAMeTableViewHeaderView.swift in Sources */, + 031FDEE62EB34FBC00F4CAC7 /* FARemoveCollectAlert.swift in Sources */, + 031FDECE2EB2006000F4CAC7 /* FACoinsPackClaimListCell.swift in Sources */, 03E23A652EAA1A4E004A8CEC /* FARewardCoinsViewController.swift in Sources */, 03E23A662EAA1A4E004A8CEC /* FAStoreViewController.swift in Sources */, 03E23A672EAA1A4E004A8CEC /* FAMeListViewController.swift in Sources */, @@ -1964,7 +2072,9 @@ 03E23A6B2EAA1A4E004A8CEC /* FARecommendPlayerCell.swift in Sources */, 03E23A6C2EAA1A4E004A8CEC /* FAHomeNewView.swift in Sources */, 03E23A6D2EAA1A4E004A8CEC /* FARankingListViewController.swift in Sources */, + 031FDEEA2EB35D2600F4CAC7 /* FACoinPackCanReceiveModel.swift in Sources */, 03E23A6E2EAA1A4E004A8CEC /* FARankingListCell.swift in Sources */, + 031FDED22EB2F69200F4CAC7 /* FALoginView.swift in Sources */, 03E23A6F2EAA1A4E004A8CEC /* FAHomeBannerCell.swift in Sources */, 03E23A702EAA1A4E004A8CEC /* FAGenresCell.swift in Sources */, 03E23A712EAA1A4E004A8CEC /* FAHomeSectionTitleView.swift in Sources */, @@ -1981,12 +2091,14 @@ 03E23A7A2EAA1A4E004A8CEC /* FASearchRecordView.swift in Sources */, 03E23A7B2EAA1A4E004A8CEC /* FACollectViewController.swift in Sources */, 03E23A7C2EAA1A4E004A8CEC /* FAMeCell.swift in Sources */, + 03E9A73A2EB45154000D1067 /* AppDelegate+FAApns.swift in Sources */, 03E23A7D2EAA1A4E004A8CEC /* FAWalletHeaderView.swift in Sources */, 03E23A7E2EAA1A4E004A8CEC /* FAPlayerProgressView.swift in Sources */, 031FDEB82EB0B80400F4CAC7 /* FACoinPackConfirmItem1View.swift in Sources */, 03E23A7F2EAA1A4E004A8CEC /* FAMeItemModel.swift in Sources */, 03E23A802EAA1A4E004A8CEC /* FAGenresListCell.swift in Sources */, 03E23A812EAA1A4E004A8CEC /* FACollectCell.swift in Sources */, + 031FDED62EB300F400F4CAC7 /* FAThirdSignModel.swift in Sources */, 03E23A822EAA1A4E004A8CEC /* FASearchRecommendView.swift in Sources */, 03E23A832EAA1A4E004A8CEC /* FAHomeMustSeeShortView.swift in Sources */, 039CE60B2EAA31CB007B5EED /* FAStatAPI.swift in Sources */, @@ -2014,11 +2126,14 @@ F3M8439X72Q55JY9G8U502D9 /* DXYFire.swift in Sources */, 03E239912EAA1A29004A8CEC /* Dictionary+FAAdd.swift in Sources */, 03E239922EAA1A29004A8CEC /* FAImageView.swift in Sources */, + 031FDEDC2EB3141E00F4CAC7 /* FASettingFooterView.swift in Sources */, 031FDEBE2EB0C99900F4CAC7 /* FANewVideoRechargeView.swift in Sources */, 03E239932EAA1A29004A8CEC /* Date+FAAdd.swift in Sources */, + 031FDEDA2EB30D6E00F4CAC7 /* FASettingCell.swift in Sources */, 03E239942EAA1A29004A8CEC /* UserDefaults+FAAdd.swift in Sources */, 039CE6322EAB796F007B5EED /* FALabel.swift in Sources */, 03E239952EAA1A29004A8CEC /* Font+FAAdd.swift in Sources */, + 031FDEEE2EB3682000F4CAC7 /* FAVipRetainAlert.swift in Sources */, 03E239962EAA1A29004A8CEC /* FACryptorService.swift in Sources */, 03E239972EAA1A29004A8CEC /* FANetworkManager.swift in Sources */, 03E239982EAA1A29004A8CEC /* UIScrollView+FARefresh.swift in Sources */, @@ -2035,6 +2150,7 @@ 03E239A22EAA1A29004A8CEC /* FATabBarController.swift in Sources */, 03E239A32EAA1A29004A8CEC /* UIStackView+FAAdd.swift in Sources */, 03E239A42EAA1A29004A8CEC /* UIScreen+FAAdd.swift in Sources */, + 031FDED42EB2FF4000F4CAC7 /* FALogin+Apple.swift in Sources */, 039CE6182EAB0E7E007B5EED /* FAStoreAPI.swift in Sources */, 03E239A52EAA1A29004A8CEC /* FACollectionView.swift in Sources */, 03E239A62EAA1A29004A8CEC /* UIView+FAAdd.swift in Sources */, @@ -2046,9 +2162,11 @@ 03E239AB2EAA1A29004A8CEC /* FATableViewCell.swift in Sources */, 03E239AC2EAA1A29004A8CEC /* FABaseWebViewController+Script.swift in Sources */, 03E239AD2EAA1A29004A8CEC /* FAAppWebViewController.swift in Sources */, + 031FDEC42EB1E45300F4CAC7 /* FACoinPackHeaderView.swift in Sources */, 03E239AE2EAA1A29004A8CEC /* SwiftUIExtension.swift in Sources */, 039CE60E2EAA32A8007B5EED /* FAOpenAppModel.swift in Sources */, 03E239AF2EAA1A29004A8CEC /* FAAPI.swift in Sources */, + 031FDECA2EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift in Sources */, 03E239B02EAA1A29004A8CEC /* FAWebView.swift in Sources */, 039CE61C2EAB0F29007B5EED /* FAIapOrderModel.swift in Sources */, 03E239B12EAA1A29004A8CEC /* FANetworkMonitor.swift in Sources */, @@ -2233,6 +2351,7 @@ INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback."; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback."; + INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = ""; @@ -2273,6 +2392,7 @@ INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback."; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback."; + INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = ""; @@ -2317,6 +2437,43 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 031FDEDD2EB3423000F4CAC7 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/facebook/facebook-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 14.1.0; + }; + }; + 03E9A7342EB44F26000D1067 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 12.5.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 031FDEDE2EB3423000F4CAC7 /* FacebookLogin */ = { + isa = XCSwiftPackageProductDependency; + package = 031FDEDD2EB3423000F4CAC7 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */; + productName = FacebookLogin; + }; + 03E9A7352EB44F26000D1067 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = 03E9A7342EB44F26000D1067 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + 03E9A7372EB44F26000D1067 /* FirebasePerformance */ = { + isa = XCSwiftPackageProductDependency; + package = 03E9A7342EB44F26000D1067 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebasePerformance; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = F3LK276P33H73Y39H9X6VTDI /* Project object */; } diff --git a/Fableon/App/AppDelegate+FAAdjust.swift b/Fableon/App/AppDelegate+FAAdjust.swift index 7e37ac7..97d493b 100644 --- a/Fableon/App/AppDelegate+FAAdjust.swift +++ b/Fableon/App/AppDelegate+FAAdjust.swift @@ -133,7 +133,7 @@ extension SceneDelegate { var result = false #if canImport(FacebookCore) - let result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity) + result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity) #endif if !result { diff --git a/Fableon/App/AppDelegate+FAApns.swift b/Fableon/App/AppDelegate+FAApns.swift new file mode 100644 index 0000000..5d2b5b0 --- /dev/null +++ b/Fableon/App/AppDelegate+FAApns.swift @@ -0,0 +1,123 @@ +// +// AppDelegate+FAApns.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/31. +// +import UIKit +import FirebaseMessaging +import SmartCodable +import FirebaseCore + +extension SceneDelegate { + + func requestFirebase() { + FirebaseApp.configure() + Messaging.messaging().delegate = self + } + + func requestApns() { + let center = UNUserNotificationCenter.current() + center.delegate = self + + center.requestAuthorization(options: [.badge, .sound, .alert]) { grant, error in + if !grant { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + self.showApnsAlert() + } + } + FAAdjustStateManager.manager.apnsAuthorizationFinish = true + + FATool.sceneDelegate?.retryHandleOpenAppMessage() + + + FATool.requestIDFAAuthorization(nil) + FAStatAPI.uploadApnsAuthorizationStatus() + } + UIApplication.shared.registerForRemoteNotifications() + } + + + + func setBadgeCount(_ count: Int) { + if #available(iOS 16.0, *) { + UNUserNotificationCenter.current().setBadgeCount(count) + } else { + UIApplication.shared.applicationIconBadgeNumber = count + } + } + + private func showApnsAlert() { + guard let date = UserDefaults.standard.object(forKey: kFAApnsAlertDefaultsKey) as? Date else { + UserDefaults.standard.set(Date(), forKey: kFAApnsAlertDefaultsKey) + return + } +#if !DEBUG + if date.fa_isToday { return } + UserDefaults.standard.set(Date(), forKey: kFAApnsAlertDefaultsKey) +#endif + + let view = FAApnsAlert() + view.show() + } +} + +extension AppDelegate { + func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { + Messaging.messaging().apnsToken = deviceToken + } + + func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: any Error) { + + } +} + +//MARK: -------------- UNUserNotificationCenterDelegate -------------- +extension SceneDelegate: UNUserNotificationCenterDelegate { + + + ///APP处于前台是接收通知消息 + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + completionHandler([.badge, .banner]) + } + + ///点击通知消息进入app + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { + setBadgeCount(0) + + guard let userInfo: [String : Any] = response.notification.request.content.userInfo as? [String : Any] else { + completionHandler() + return + } + + guard let model = FAOpenAppModel.deserialize(from: userInfo) else { + completionHandler() + return + } + FAStatAPI.requestStatApnsClick(id: model.message_id ?? "", title: response.notification.request.content.title) + + if model.path == .videoDetail, let shortPlayId = model.short_play_id { + let vc = FAPlayerDetailViewController() + vc.shortPlayId = shortPlayId + FATool.topViewController?.navigationController?.pushViewController(vc, animated: true) + + } else if model.path == .feedback { + let vc = FAAppWebViewController() + vc.webUrl = kFAFeedBackListWebUrl + FATool.topViewController?.navigationController?.pushViewController(vc, animated: true) + } + + completionHandler() + } + + +} + +//MARK: MessagingDelegate +extension SceneDelegate: MessagingDelegate { + func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { + if let token = fcmToken { + FAStatAPI.requestUploadApnsDeviceToken(token: token) + } + } +} diff --git a/Fableon/App/AppDelegate+FAConfig.swift b/Fableon/App/AppDelegate+FAConfig.swift index df96a2e..4a3e658 100644 --- a/Fableon/App/AppDelegate+FAConfig.swift +++ b/Fableon/App/AppDelegate+FAConfig.swift @@ -9,6 +9,7 @@ import UIKit import MJRefresh import IQKeyboardManagerSwift import IQKeyboardToolbarManager +import FacebookCore extension AppDelegate { @@ -30,6 +31,11 @@ extension AppDelegate { UINavigationBar.appearance().standardAppearance = appearance registerAdjust() + + } + + func fa_registThirdparty(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { + ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions) } } diff --git a/Fableon/App/AppDelegate.swift b/Fableon/App/AppDelegate.swift index d2e518a..b6b25cf 100644 --- a/Fableon/App/AppDelegate.swift +++ b/Fableon/App/AppDelegate.swift @@ -6,6 +6,7 @@ // import UIKit +import FacebookCore @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -14,6 +15,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FANetworkMonitor.manager.startMonitoring() + fa_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions) + self.fa_config() NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil) diff --git a/Fableon/App/SceneDelegate.swift b/Fableon/App/SceneDelegate.swift index 9aa1dd1..52130d4 100644 --- a/Fableon/App/SceneDelegate.swift +++ b/Fableon/App/SceneDelegate.swift @@ -6,40 +6,54 @@ // import UIKit +import YYText class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - + + private var onLineTimer: Timer? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } + NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil) + FATool.sceneDelegate = self FATool.windowScene = windowScene window = UIWindow(windowScene: windowScene) window?.rootViewController = FATabBarController() window?.makeKeyAndVisible() FAAdjustStateManager.manager.isOpenApp = true + + onLineTimer = Timer.scheduledTimer(timeInterval: 60 * 10, target: YYTextWeakProxy(target: self), selector: #selector(handleOnLine), userInfo: nil, repeats: true) + + + if let webpageURL = connectionOptions.userActivities.first?.webpageURL { + self.handleOpenAppMessage(webpageURL: webpageURL) + } else if let url = connectionOptions.urlContexts.first?.url { + self.handleOpenAppMessage(webpageURL: url) + } + + requestFirebase() + requestApns() } func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + self.handleOnLine() + FAStatAPI.requestEnterApp() + self.setBadgeCount(0) } func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). + FAStatAPI.requestLeaveApp() } func sceneWillEnterForeground(_ scene: UIScene) { + FAStatAPI.uploadApnsAuthorizationStatus() DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.handleOpenAppMessage(webpageURL: nil) } @@ -52,3 +66,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } +extension SceneDelegate { + + @objc private func handleOnLine() { + FAStatAPI.requestStatOnLine() + } + + @objc private func networkStatusDidChangeNotification() { + FATool.requestIDFAAuthorization(nil) + self.retryHandleOpenAppMessage() + } +} diff --git a/Fableon/Fableon.entitlements b/Fableon/Fableon.entitlements index 1ba3f4d..0a2e231 100644 --- a/Fableon/Fableon.entitlements +++ b/Fableon/Fableon.entitlements @@ -2,10 +2,16 @@ + com.apple.developer.applesignin + + Default + com.apple.developer.associated-domains applinks:fableon.go.link applinks:kuzt.adj.st + keychain-access-groups + diff --git a/Fableon/Object/Base/Define/FAUserDefaultsKey.swift b/Fableon/Object/Base/Define/FAUserDefaultsKey.swift index 3216986..469bf48 100644 --- a/Fableon/Object/Base/Define/FAUserDefaultsKey.swift +++ b/Fableon/Object/Base/Define/FAUserDefaultsKey.swift @@ -7,3 +7,5 @@ let kFAWaitRestoreIAPDefaultsKey = "kFAWaitRestoreIAPDefaultsKey" + +let kFAApnsAlertDefaultsKey = "kFAApnsAlertDefaultsKey" diff --git a/Fableon/Object/Base/Extension/Date+FAAdd.swift b/Fableon/Object/Base/Extension/Date+FAAdd.swift index 9ceeaf9..02e50f0 100644 --- a/Fableon/Object/Base/Extension/Date+FAAdd.swift +++ b/Fableon/Object/Base/Extension/Date+FAAdd.swift @@ -22,7 +22,7 @@ extension Date { } ///是否是今天 - var br_isToday: Bool { + var fa_isToday: Bool { get { return Calendar.current.isDateInToday(self) } diff --git a/Fableon/Object/Base/Request/FAAPI/FAAPI.swift b/Fableon/Object/Base/Request/FAAPI/FAAPI.swift index 99116a5..b5289e1 100644 --- a/Fableon/Object/Base/Request/FAAPI/FAAPI.swift +++ b/Fableon/Object/Base/Request/FAAPI/FAAPI.swift @@ -6,6 +6,7 @@ // import UIKit +import SmartCodable extension FAAPI { ///更新短剧关注状态 [ "state" : isCollect, "id" : shortPlayId,] @@ -249,6 +250,34 @@ struct FAAPI { completer?(response.data) } } + + +} + +//MARK: 用户登录 +extension FAAPI { + ///第三方用户登录 + static func requestSignThirdLogin(model: FAThirdSignModel, completer: ((_ token: FATokenModel?) -> Void)?) { + FANetworkManager.manager.request(FABaseURL + "/customer/login", + method: .post, + parameters: model.toDictionary(), + isLoding: false, + isToast: true) { (response: FANetworkManager.Response) in + completer?(response.data) + } + } + + static func requestLogout(completer: ((_ token: FATokenModel?) -> Void)?) { + + FANetworkManager.manager.request(FABaseURL + "/customer/signout", + method: .post, + parameters: nil, + isLoding: true, + isToast: true) { (response: FANetworkManager.Response) in + completer?(response.data) + } + + } } diff --git a/Fableon/Object/Base/Request/FAAPI/FAStatAPI.swift b/Fableon/Object/Base/Request/FAAPI/FAStatAPI.swift index 7efad73..977da73 100644 --- a/Fableon/Object/Base/Request/FAAPI/FAStatAPI.swift +++ b/Fableon/Object/Base/Request/FAAPI/FAStatAPI.swift @@ -84,4 +84,97 @@ class FAStatAPI: NSObject { } } + + ///进入APP + static func requestEnterApp() { + + FANetworkManager.manager.request(FABaseURL + "/customer/enterTheApp", + method: .post, + parameters: nil, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } + + ///离开APP + static func requestLeaveApp() { + + FANetworkManager.manager.request(FABaseURL + "/customer/leaveApp", + method: .post, + parameters: nil, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } + + static func requestStatOnLine() { + FANetworkManager.manager.request(FABaseURL + "/customer/onLine", + method: .post, + parameters: nil, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } + + static func requestUploadApnsAuthorizationStatus(_ status: Bool) { + let parameters = [ + "is_open_notice" : status ? 1 : 0 + ] + FANetworkManager.manager.request(FABaseURL + "/customer/uploadNoticeStatus", + method: .post, + parameters: parameters, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } + + static func requestStatApnsClick(id: String, title: String) { + let parameters = [ + "message_id" : id, + "title" : title + ] + FANetworkManager.manager.request(FABaseURL + "/message/sendReport", + method: .post, + parameters: parameters, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } + + static func requestUploadApnsDeviceToken(token: String) { + let parameters = [ + "fcm_token": token + ] + FANetworkManager.manager.request(FABaseURL + "/customer/firebaseToken", + method: .post, + parameters: parameters, + isLoding: false, + isToast: false, + ) { (response: FANetworkManager.Response) in + + } + } +} + +extension FAStatAPI { + ///更新通知状态 + static func uploadApnsAuthorizationStatus() { + UNUserNotificationCenter.current().getNotificationSettings { settings in + if settings.authorizationStatus == .authorized { + requestUploadApnsAuthorizationStatus(true) + } else if settings.authorizationStatus == .denied { + requestUploadApnsAuthorizationStatus(false) + } + } + } } diff --git a/Fableon/Object/Base/Request/FAAPI/FAStoreAPI.swift b/Fableon/Object/Base/Request/FAAPI/FAStoreAPI.swift index a902888..5a9083f 100644 --- a/Fableon/Object/Base/Request/FAAPI/FAStoreAPI.swift +++ b/Fableon/Object/Base/Request/FAAPI/FAStoreAPI.swift @@ -131,4 +131,70 @@ class FAStoreAPI: NSObject { completer?(response.data) } } + + ///金币包数据 + static func requestCoinsPackData(completer: ((_ model: FACoinsPackModel?) -> Void)?) { + + FANetworkManager.manager.request(FABaseURL + "/getReceiveDayCoinInfo", + method: .get, + parameters: nil, + isLoding: false, + isToast: true, + ) { (response: FANetworkManager.Response) in + completer?(response.data) + } + } + + ///领取金币包金币 + static func requestReceiveCoinsPackCoins(id: String?, completer: ((_ finish: Bool) -> Void)?) { + + var parameters: [String : Any]? = nil + if let id = id { + parameters = [ + "id" : id + ] + } + + FANetworkManager.manager.request(FABaseURL + "/receiveDayCoin", + method: .post, + parameters: parameters, + isLoding: true, + isToast: true, + ) { (response: FANetworkManager.Response) in + if response.isSuccess { + completer?(true) + } else { + completer?(false) + } + } + } + + ///获取金币包可领取信息 + static func requestCoinBagCanReceiveInfo(completer: ((_ model: FACoinPackCanReceiveModel?) -> Void)?) { + FANetworkManager.manager.request(FABaseURL + "/getReceiveDayCoin", + method: .get, + parameters: nil, + isLoding: false, + isToast: true, + ) { (response: FANetworkManager.Response) in + completer?(response.data) + } + } + + ///挽留支付项 + static func requestVipRetainPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) { + + FANetworkManager.manager.request(FABaseURL + "/getRetainVipPaySetting", + method: .get, + parameters: nil, + isLoding: true, + isToast: true, + ) { (response: FANetworkManager.Response) in + if let _ = response.data?.info { + completer?(response.data) + } else { + completer?(nil) + } + } + } } diff --git a/Fableon/Object/Base/Request/FAAPIPath.swift b/Fableon/Object/Base/Request/FAAPIPath.swift index 1cee6c1..589a4a4 100644 --- a/Fableon/Object/Base/Request/FAAPIPath.swift +++ b/Fableon/Object/Base/Request/FAAPIPath.swift @@ -16,3 +16,6 @@ let kFAFeedBackHomeWebUrl = FACampaignWebURL + "/pages/leave/index" let kFAFeedBackListWebUrl = FACampaignWebURL + "/pages/leave/list" ///反馈详情 let kFAFeedBackDetailWebUrl = FACampaignWebURL + "/pages/leave/detail" + +///注销账号 +let kFALogoutWebUrl = FACampaignWebURL + "/pages/setting/logout" diff --git a/Fableon/Object/Base/Request/FANetworkManager.swift b/Fableon/Object/Base/Request/FANetworkManager.swift index 3d139dc..977247b 100644 --- a/Fableon/Object/Base/Request/FANetworkManager.swift +++ b/Fableon/Object/Base/Request/FANetworkManager.swift @@ -186,7 +186,8 @@ extension FANetworkManager { "model" : UIDevice.current.machineModelName ?? "", "idfa" : ASIdentifierManager.shared().advertisingIdentifier.uuidString, "device-id" : FADeviceIDManager.shared.id, //设备id - "device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "" + "device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "", + "product-prefix" : FAIapManager.IAPPrefix ] return HTTPHeaders(dic) } diff --git a/Fableon/Object/Base/WebView/FAAppWebViewController.swift b/Fableon/Object/Base/WebView/FAAppWebViewController.swift index 80c0c7a..a641bc4 100644 --- a/Fableon/Object/Base/WebView/FAAppWebViewController.swift +++ b/Fableon/Object/Base/WebView/FAAppWebViewController.swift @@ -14,7 +14,7 @@ class FAAppWebViewController: FABaseWebViewController { private var receiveDataCount = 0 - var theme: String? = "theme_1" + var theme: String? = "theme_3" override func viewDidLoad() { super.viewDidLoad() @@ -26,6 +26,8 @@ class FAAppWebViewController: FABaseWebViewController { self.title = "Feedback".localized } else if webUrl == kFAFeedBackDetailWebUrl { self.title = "Feedback Details".localized + } else if webUrl == kFALogoutWebUrl { + self.title = "Account Deletion".localized } } @@ -51,6 +53,7 @@ extension FAAppWebViewController { "time_zone" : String.timeZone(), "lang" : FALocalized.manager.currentLocalizedKey, "type" : "ios", + "device-id" : FADeviceIDManager.shared.id ] if let theme = theme { diff --git a/Fableon/Object/Base/WebView/FABaseWebViewController+Script.swift b/Fableon/Object/Base/WebView/FABaseWebViewController+Script.swift index e3d8165..f7d4150 100644 --- a/Fableon/Object/Base/WebView/FABaseWebViewController+Script.swift +++ b/Fableon/Object/Base/WebView/FABaseWebViewController+Script.swift @@ -18,6 +18,8 @@ let kFAWebMessageOpenFeedbackList = "openFeedbackList" let kFAWebMessageOpenFeedbackDetail = "openFeedbackDetail" ///打开相册 let kFAWebMessageOpenPhotoPicker = "openPhotoPicker" +///删除账号成功 +let kFAWebMessageAccountDeletionFinish = "accountLogout" extension FABaseWebViewController { @@ -50,7 +52,8 @@ extension FABaseWebViewController { let data = model.data if type == "login" { -// VPLoginManager.manager.openLogin() + let view = FALoginView() + view.present(in: nil) } else if type == "open_notify" { // openNotify() @@ -69,6 +72,9 @@ extension FABaseWebViewController { } } + case kFAWebMessageAccountDeletionFinish: + self.navigationController?.popToRootViewController(animated: true) + default: break diff --git a/Fableon/Object/Base/WebView/FAWebView.swift b/Fableon/Object/Base/WebView/FAWebView.swift index 2c1044a..fe751f8 100644 --- a/Fableon/Object/Base/WebView/FAWebView.swift +++ b/Fableon/Object/Base/WebView/FAWebView.swift @@ -38,6 +38,7 @@ class FAWebView: WKWebView { kFAWebMessageOpenFeedbackList, kFAWebMessageOpenFeedbackDetail, kFAWebMessageOpenPhotoPicker, + kFAWebMessageAccountDeletionFinish, ] diff --git a/Fableon/Object/Class/Home/C/FAHomeViewController.swift b/Fableon/Object/Class/Home/C/FAHomeViewController.swift index 76cc569..9370ec2 100644 --- a/Fableon/Object/Class/Home/C/FAHomeViewController.swift +++ b/Fableon/Object/Class/Home/C/FAHomeViewController.swift @@ -61,6 +61,17 @@ class FAHomeViewController: FAViewController { view.isHidden = true return view }() + + private lazy var coinPackButton: FAHomeCoinsPackButton = { + let view = FAHomeCoinsPackButton() + view.addAction(UIAction(handler: { [weak self] _ in + guard let self = self else { return } + let vc = FACoinPackViewController() + self.navigationController?.pushViewController(vc, animated: true) + + }), for: .touchUpInside) + return view + }() deinit { NotificationCenter.default.removeObserver(self) @@ -72,6 +83,8 @@ class FAHomeViewController: FAViewController { fa_setupLayout() requestAllData(completer: nil) + + requestCoinBagCanReceiveInfo() } override func viewWillAppear(_ animated: Bool) { @@ -104,6 +117,7 @@ extension FAHomeViewController { view.addSubview(searchButton) view.addSubview(collectionView) view.addSubview(playHistoryView) + view.addSubview(coinPackButton) titleView.snp.makeConstraints { make in make.left.equalToSuperview().offset(16) @@ -125,6 +139,11 @@ extension FAHomeViewController { make.centerX.equalToSuperview() make.bottom.equalToSuperview().offset(-10) } + + coinPackButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-21) + make.bottom.equalTo(playHistoryView.snp.top).offset(5) + } } } @@ -280,4 +299,22 @@ extension FAHomeViewController { } } + private func requestCoinBagCanReceiveInfo() { + + FAStoreAPI.requestCoinBagCanReceiveInfo { [weak self] model in + guard let self = self else { return } + guard let model = model else { return } + let coins = model.coins ?? 0 + if coins > 0 { + let view = FACoinsPackAlert() + view.coinsCount = coins + view.show(in: self.view) + view.clickHighlightButton = { [weak self] in + let vc = FACoinPackViewController() + self?.navigationController?.pushViewController(vc, animated: true) + } + } + } + } + } diff --git a/Fableon/Object/Class/Home/V/FAHomeCoinsPackButton.swift b/Fableon/Object/Class/Home/V/FAHomeCoinsPackButton.swift new file mode 100644 index 0000000..6333b3c --- /dev/null +++ b/Fableon/Object/Class/Home/V/FAHomeCoinsPackButton.swift @@ -0,0 +1,50 @@ +// +// FAHomeCoinsPackButton.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit +import SnapKit + +class FAHomeCoinsPackButton: UIControl { + + private lazy var bgImageView = UIImageView(image: UIImage(named: "Group 2072750470")) + private lazy var textBgImageView = UIImageView(image: UIImage(named: "按钮")) + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 10, weight: .init(900)).withBoldItalic() + label.textColor = .FFFFFF + label.text = "Daily Coins".localized + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(bgImageView) + addSubview(textBgImageView) + textBgImageView.addSubview(textLabel) + + bgImageView.snp.makeConstraints { make in + make.left.right.top.equalToSuperview() + } + + textBgImageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview() + make.top.equalToSuperview().offset(50) + } + + textLabel.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.centerX.equalToSuperview() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Fableon/Object/Class/Me/C/FACoinPackViewController.swift b/Fableon/Object/Class/Me/C/FACoinPackViewController.swift new file mode 100644 index 0000000..2bbfd63 --- /dev/null +++ b/Fableon/Object/Class/Me/C/FACoinPackViewController.swift @@ -0,0 +1,216 @@ +// +// FACoinPackViewController.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit +import YYText + +class FACoinPackViewController: FAViewController { + + private var model: FACoinsPackModel? { + didSet { + headerView.model = model + claimView.dataArr = model?.receive_list ?? [] + } + } + + private var payDataModel : FAPayDateModel? { + didSet { + var arr: [FAPayItem] = [] + + payDataModel?.list_coins?.forEach { + if $0.buy_type == .subCoins { + arr.append($0) + } + } + self.buyView.dataArr = arr + } + } + + private var payDataRequest: FAPayDataRequest? + + private lazy var bgIconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "查看图片 25")) + return imageView + }() + + private lazy var scrollView: FAScrollView = { + let scrollView = FAScrollView() + return scrollView + }() + + private lazy var headerView: FACoinPackHeaderView = { + let view = FACoinPackHeaderView() + view.clickClaimButton = { [weak self] in + self?.requestReceiveCoins(nil) + } + return view + }() + + private lazy var stackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.spacing = 19 + return stackView + }() + + private lazy var claimView: FACoinsPackClaimListView = { + let view = FACoinsPackClaimListView() + view.clickClaimButton = { [weak self] id in + guard let self = self else { return } + self.requestReceiveCoins(id) + } + return view + }() + + private lazy var buyView: FACoinsPackBuyView = { + let view = FACoinsPackBuyView() + view.buyFinishHandle = { [weak self] in + self?.requestCoinsPackData() + } + return view + }() + + private lazy var tipView: UIView = { + let view = UIView() + view.addSubview(tipTitleLabel) + view.addSubview(tipTextLabel) + + tipTitleLabel.snp.makeConstraints { make in + make.top.equalToSuperview() + make.left.equalToSuperview().offset(16) + } + + tipTextLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.right.lessThanOrEqualToSuperview().offset(-16) + make.top.equalTo(tipTitleLabel.snp.bottom).offset(4) + make.bottom.equalToSuperview() + } + return view + }() + + private lazy var tipTitleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium) + label.textColor = .FFFFFF.withAlphaComponent(0.5) + label.text = "coins_pack_tips_title".localized + return label + }() + + private lazy var tipTextLabel: UILabel = { + let att = NSMutableAttributedString(string: "coins_pack_tips".localized) + att.yy_lineSpacing = 3 + + let label = UILabel() + label.font = .font(ofSize: 10, weight: .regular) + label.textColor = .FFFFFF.withAlphaComponent(0.5) + label.attributedText = att + label.numberOfLines = 0 + return label + }() + + override func viewDidLoad() { + super.viewDidLoad() + self.title = "My Refills".localized + payDataModel = FAIapManager.manager.payDateModel + + fa_setupLayout() + + requestCoinsPackData() + + updateLayout() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.setNavigationBarHidden(false, animated: true) + self.fa_setNavigationStyle() + } + + private func updateLayout() { + stackView.fa_removeAllArrangedSubview() + + if self.claimView.dataArr.count > 0 { + stackView.addArrangedSubview(self.claimView) + } else if self.buyView.dataArr.count > 0 { + stackView.addArrangedSubview(self.buyView) + } + + stackView.addArrangedSubview(tipView) + } + +} + +extension FACoinPackViewController { + + private func fa_setupLayout() { + view.addSubview(bgIconImageView) + view.addSubview(scrollView) + scrollView.addSubview(headerView) + scrollView.addSubview(stackView) + + bgIconImageView.snp.makeConstraints { make in + make.right.equalToSuperview() + make.top.equalToSuperview() + } + + scrollView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().offset(UIScreen.navBarHeight) + make.bottom.equalToSuperview() + } + + headerView.snp.makeConstraints { make in + make.left.centerX.equalToSuperview() + make.top.equalToSuperview() + } + + stackView.snp.makeConstraints { make in + make.left.centerX.equalToSuperview() + make.top.equalTo(headerView.snp.bottom).offset(16) + make.bottom.equalToSuperview().offset(-(UIScreen.safeBottom + 10)) + } + } + +} + +extension FACoinPackViewController { + + private func requestCoinsPackData() { + FAStoreAPI.requestCoinsPackData { [weak self] model in + guard let self = self else { return } + guard let model = model else { return } + self.model = model + + if (model.receive_list?.count ?? 0) == 0 { + self.requestPayData() + } + + self.updateLayout() + } + + } + + private func requestPayData() { + self.payDataRequest = FAPayDataRequest() + self.payDataRequest?.requestProducts { [weak self] model in + guard let self = self else { return } + guard let model = model else { return } + self.payDataModel = model + + self.updateLayout() + } + } + + private func requestReceiveCoins(_ id: String?) { + FAStoreAPI.requestReceiveCoinsPackCoins(id: id) { [weak self] finish in + guard let self = self else { return } + self.requestCoinsPackData() + } + } + +} diff --git a/Fableon/Object/Class/Me/C/FAMeListViewController.swift b/Fableon/Object/Class/Me/C/FAMeListViewController.swift index d12cb77..b9db860 100644 --- a/Fableon/Object/Class/Me/C/FAMeListViewController.swift +++ b/Fableon/Object/Class/Me/C/FAMeListViewController.swift @@ -16,11 +16,12 @@ class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate { let arr = [ FAMeItemModel(type: .feedback, name: "Feedback".localized, icon: UIImage(named: "icon_feedback")), FAMeItemModel(type: .about, name: "About".localized, icon: UIImage(named: "icon_about")), -// FAMeItemModel(type: .setting, name: "Setting".localized, icon: UIImage(named: "icon_setting")) FAMeItemModel(type: .privacyPolicy, name: "Privacy Policy".localized, icon: UIImage(named: "icon_privacy")), FAMeItemModel(type: .userAgreement, name: "User Agreement".localized, icon: UIImage(named: "icon_user")), FAMeItemModel(type: .visitWebsite, name: "Visit Website".localized, icon: UIImage(named: "icon_visit")), + + FAMeItemModel(type: .setting, name: "Setting".localized, icon: UIImage(named: "icon_setting")) ] return arr }() diff --git a/Fableon/Object/Class/Me/C/FASettingViewController.swift b/Fableon/Object/Class/Me/C/FASettingViewController.swift index 805df1b..0fd9e4d 100644 --- a/Fableon/Object/Class/Me/C/FASettingViewController.swift +++ b/Fableon/Object/Class/Me/C/FASettingViewController.swift @@ -8,11 +8,35 @@ import UIKit class FASettingViewController: FAViewController { + + private lazy var dataArr: [FAMeItemModel] = [ + FAMeItemModel(type: .deleteAccount, name: "Account Deletion".localized, icon: nil) + ] + + private lazy var tableView: FATableView = { + let tableView = FATableView(frame: .zero, style: .plain) + tableView.delegate = self + tableView.dataSource = self + tableView.rowHeight = 48 + tableView.contentInset = .init(top: 25, left: 0, bottom: 0, right: 0) + tableView.separatorStyle = .none + tableView.register(UINib(nibName: "FASettingCell", bundle: nil), forCellReuseIdentifier: "cell") + return tableView + }() + + private lazy var footerView: FASettingFooterView = { + let view = FASettingFooterView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 60)) + return view + }() override func viewDidLoad() { super.viewDidLoad() self.title = "Settings".localized + NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil) + + userInfoUpdateNotification() + fa_setupLayout() } override func viewWillAppear(_ animated: Bool) { @@ -20,7 +44,52 @@ class FASettingViewController: FAViewController { self.navigationController?.setNavigationBarHidden(false, animated: true) self.fa_setNavigationStyle() } - - + @objc private func userInfoUpdateNotification() { + if FALogin.manager.isLogin { + tableView.tableFooterView = footerView + } else { + tableView.tableFooterView = nil + } + } + + +} + +extension FASettingViewController { + + private func fa_setupLayout() { + + + view.addSubview(tableView) + + tableView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().offset(UIScreen.navBarHeight) + make.bottom.equalToSuperview() + } + } + +} + +//MARK: UITableViewDelegate UITableViewDataSource +extension FASettingViewController: UITableViewDelegate, UITableViewDataSource { + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let item = dataArr[indexPath.row] + let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FASettingCell + cell.titleLabel.text = item.name + return cell + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return self.dataArr.count + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let vc = FAAppWebViewController() + vc.webUrl = kFALogoutWebUrl + vc.theme = "theme_4" + self.navigationController?.pushViewController(vc, animated: true) + } } diff --git a/Fableon/Object/Class/Me/M/FAMeItemModel.swift b/Fableon/Object/Class/Me/M/FAMeItemModel.swift index b462c47..163787e 100644 --- a/Fableon/Object/Class/Me/M/FAMeItemModel.swift +++ b/Fableon/Object/Class/Me/M/FAMeItemModel.swift @@ -22,6 +22,7 @@ struct FAMeItemModel { case purchaseRecords ///金币奖励 case rewardCoins + case deleteAccount } diff --git a/Fableon/Object/Class/Me/V/FACoinPackHeaderView.swift b/Fableon/Object/Class/Me/V/FACoinPackHeaderView.swift new file mode 100644 index 0000000..5e4ae1c --- /dev/null +++ b/Fableon/Object/Class/Me/V/FACoinPackHeaderView.swift @@ -0,0 +1,266 @@ +// +// FACoinPackHeaderView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit + +class FACoinPackHeaderView: UIView { + + var clickClaimButton: (() -> Void)? + + var model: FACoinsPackModel? { + didSet { + coinsView1.coins = model?.week_max_total + coinsView2.coins = model?.week_total + + activeCountLabel.text = "\(model?.receive_count ?? 0)" + + if let coin = model?.receive_coins, coin > 0 { + claimButton.isEnabled = true + } else { + claimButton.isEnabled = false + } + + claimButton.setNeedsUpdateConfiguration() + } + } + + private lazy var titleView: FACoinPackTitleView = { + let view = FACoinPackTitleView() + view.dotColor = .C_5_DDF_5 + view.font = .font(ofSize: 14, weight: .regular) + view.textColors = [UIColor.C_5_DDF_5.cgColor, UIColor.C_5_DDF_5.cgColor] + view.text = "REWARDS OVERVIEW".localized + return view + }() + + private lazy var coinsView1: CoinsView = { + let view = CoinsView() + view.title = "Weekly Total".localized + view.coins = 0 + return view + }() + + private lazy var coinsView2: CoinsView = { + let view = CoinsView() + view.title = "Claimable Coins".localized + view.coins = 0 + return view + }() + + private lazy var lineView1: UIView = { + let view = UIImageView(image: UIImage(named: "间隔线")) + return view + }() + + private lazy var lineView2: UIView = { + let view = UIImageView(image: UIImage(named: "横间隔虚线")) + return view + }() + + private lazy var activeCountTitleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .FFFFFF.withAlphaComponent(0.5) + label.text = "Active Refills".localized + ": " + return label + }() + + private lazy var activeCountLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium) + label.textColor = ._53_A_2_F_1 + label.text = "0" + return label + }() + + private lazy var claimButton: UIButton = { + let config = UIButton.Configuration.plain() + let button = FAGradientButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in + self?.clickClaimButton?() + })) + button.isEnabled = false + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 1, y: 0.5) + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + guard let button = button as? FAGradientButton else { return } + if button.isEnabled { + button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + + let coinImage = UIImage(named: "coins_icon_03")! + let coinText = NSTextAttachment(image: coinImage) + coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height) + let coinAtt = AttributedString(NSAttributedString(attachment: coinText)) + + let textAtt = AttributedString("Claim All".localized + " ", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor.FFFFFF + ])) + + let countAtt = AttributedString(" \(0)".localized, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor.FFFFFF + ])) + + button.configuration?.attributedTitle = textAtt + coinAtt + countAtt + + + } else { + button.fa_colors = [UIColor._6_D_6_D_6_D.cgColor, UIColor._6_D_6_D_6_D.cgColor] + button.configuration?.attributedTitle = AttributedString("Get a Refill to Claim".localized, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor.FFFFFF.withAlphaComponent(0.5) + ])) + } + + } + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + fa_setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension FACoinPackHeaderView { + + private func fa_setupLayout() { + addSubview(titleView) + addSubview(coinsView1) + addSubview(coinsView2) + addSubview(lineView1) + addSubview(activeCountTitleLabel) + addSubview(activeCountLabel) + addSubview(claimButton) + addSubview(lineView2) + + titleView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.top.equalToSuperview().offset(20) + } + + coinsView1.snp.makeConstraints { make in + make.left.equalToSuperview().offset(28) + make.top.equalTo(titleView.snp.bottom).offset(23) + } + + lineView1.snp.makeConstraints { make in + make.centerY.equalTo(coinsView1) + make.left.equalTo(coinsView1.snp.right).offset(18) + } + + coinsView2.snp.makeConstraints { make in + make.centerY.equalTo(lineView1) + make.left.equalTo(lineView1.snp.right).offset(18) + } + + activeCountTitleLabel.snp.makeConstraints { make in + make.left.equalTo(coinsView1) + make.top.equalTo(coinsView1.snp.bottom).offset(23) + } + + activeCountLabel.snp.makeConstraints { make in + make.left.equalTo(activeCountTitleLabel.snp.right) + make.centerY.equalTo(activeCountTitleLabel) + } + + claimButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(23) + make.centerX.equalToSuperview() + make.top.equalTo(activeCountTitleLabel.snp.bottom).offset(12) + make.height.equalTo(48) + make.bottom.equalToSuperview().offset(-16) + } + + lineView2.snp.makeConstraints { make in + make.left.equalTo(claimButton) + make.right.equalTo(claimButton) + make.bottom.equalToSuperview() + } + } + +} + + +extension FACoinPackHeaderView { + + class CoinsView: UIView { + var title: String? { + didSet { + titleLabel.text = title + } + } + + var coins: Int? { + didSet { + coinsLabel.text = "\(coins ?? 0)" + } + } + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .bold) + label.textColor = .FFFFFF.withAlphaComponent(0.5) + return label + }() + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "coins_icon_09")) + return imageView + }() + + private lazy var coinsLabel: UILabel = { + let label = FALabel() + label.font = .font(ofSize: 18, weight: .bold) + label.textColors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + label.textStartPoint = .init(x: 0, y: 0.5) + label.textEndPoint = .init(x: 1, y: 0.5) + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(titleLabel) + addSubview(iconImageView) + addSubview(coinsLabel) + + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview() + make.top.equalToSuperview() + make.right.lessThanOrEqualToSuperview() + } + + iconImageView.snp.makeConstraints { make in + make.left.equalToSuperview() + make.top.equalTo(titleLabel.snp.bottom).offset(4) + make.bottom.equalToSuperview() + } + + coinsLabel.snp.makeConstraints { make in + make.centerY.equalTo(iconImageView) + make.left.equalTo(iconImageView.snp.right).offset(4) + make.right.lessThanOrEqualToSuperview() + } + + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } + +} diff --git a/Fableon/Object/Class/Me/V/FACoinPackTitleView.swift b/Fableon/Object/Class/Me/V/FACoinPackTitleView.swift new file mode 100644 index 0000000..848acaf --- /dev/null +++ b/Fableon/Object/Class/Me/V/FACoinPackTitleView.swift @@ -0,0 +1,91 @@ +// +// FACoinPackTitleView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit + +class FACoinPackTitleView: UIView { + + var text: String? { + didSet { + label.text = text + } + } + + var font: UIFont? { + didSet { + label.font = font + } + } + + var textColors: [CGColor]? { + didSet { + label.textColors = textColors + } + } + + var dotColor: UIColor? { + didSet { + dotView1.backgroundColor = dotColor + dotView2.backgroundColor = dotColor + } + } + + private lazy var dotView1: UIView = { + let view = UIView() + view.layer.cornerRadius = 3 + view.layer.masksToBounds = true + return view + }() + + private lazy var dotView2: UIView = { + let view = UIView() + view.layer.cornerRadius = 3 + view.layer.masksToBounds = true + return view + }() + + private lazy var label: FALabel = { + let label = FALabel() + label.textStartPoint = .init(x: 0, y: 0.5) + label.textEndPoint = .init(x: 1, y: 0.5) + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(dotView1) + addSubview(dotView2) + addSubview(label) + + dotView1.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview() + make.width.height.equalTo(6) + make.bottom.lessThanOrEqualToSuperview() + } + + label.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.bottom.lessThanOrEqualToSuperview() + make.left.equalTo(dotView1.snp.right).offset(6) + } + + dotView2.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.bottom.lessThanOrEqualToSuperview() + make.right.equalToSuperview() + make.width.height.equalTo(dotView1) + make.left.equalTo(label.snp.right).offset(6) + } + + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/Fableon/Object/Class/Me/V/FACoinsPackBuyView.swift b/Fableon/Object/Class/Me/V/FACoinsPackBuyView.swift new file mode 100644 index 0000000..9694e6b --- /dev/null +++ b/Fableon/Object/Class/Me/V/FACoinsPackBuyView.swift @@ -0,0 +1,112 @@ +// +// FACoinsPackBuyView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit + +class FACoinsPackBuyView: UIView { + + var buyFinishHandle: (() -> Void)? + + var dataArr: [FAPayItem] = [] + + private lazy var titleView: FACoinPackTitleView = { + let view = FACoinPackTitleView() + view.dotColor = .C_5_DDF_5 + view.textColors = [UIColor.C_5_DDF_5.cgColor, UIColor.C_5_DDF_5.cgColor] + view.font = .font(ofSize: 14, weight: .regular) + view.text = "Weekly Refill".localized.uppercased() + return view + }() + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: UIScreen.width - 32, height: 84) + layout.minimumLineSpacing = 12 + return layout + }() + + private lazy var collectionView: FACollectionView = { + let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.addObserver(self, forKeyPath: "contentSize", context: nil) + collectionView.register(FAStoreCoinsPackCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + deinit { + collectionView.removeObserver(self, forKeyPath: "contentSize") + } + + override init(frame: CGRect) { + super.init(frame: frame) + + fa_setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + if keyPath == "contentSize" { + let height = self.collectionView.contentSize.height + 1 + collectionView.snp.updateConstraints { make in + make.height.equalTo(height) + } + } + } +} + +extension FACoinsPackBuyView { + + private func fa_setupLayout() { + addSubview(titleView) + addSubview(collectionView) + + titleView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalToSuperview() + } + + collectionView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalToSuperview().offset(30) + make.height.equalTo(1) + make.bottom.equalToSuperview() + } + } + +} + +//MARK: UICollectionViewDelegate UICollectionViewDataSource +extension FACoinsPackBuyView: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FAStoreCoinsPackCell + cell.model = self.dataArr[indexPath.row] + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = self.dataArr[indexPath.row] + + let view = FACoinPackConfirmView() + view.model = model + view.buyFinishHandle = { [weak self] in + guard let self = self else { return } + FALogin.manager.requestUserInfo(completer: nil) + self.buyFinishHandle?() + } + view.present(in: nil) + } + +} diff --git a/Fableon/Object/Class/Me/V/FACoinsPackClaimListCell.swift b/Fableon/Object/Class/Me/V/FACoinsPackClaimListCell.swift new file mode 100644 index 0000000..b691f5d --- /dev/null +++ b/Fableon/Object/Class/Me/V/FACoinsPackClaimListCell.swift @@ -0,0 +1,280 @@ +// +// FACoinsPackClaimListCell.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit +import YYText + +class FACoinsPackClaimListCell: UICollectionViewCell { + + var clickClaimButton: ((_ id: String?) -> Void)? + + var model: FACoinsPackReceiveModel? { + didSet { + coinsView1.coins = model?.week_max_total + coinsView2.coins = model?.week_remaining_total + + claimButton.isEnabled = (model?.receive_coins ?? 0) > 0 + claimButton.setNeedsUpdateConfiguration() + + let titleAtt = NSMutableAttributedString(string: "\(model?.title ?? "")") + titleAtt.yy_color = .FFFFFF + titleAtt.yy_font = .font(ofSize: 14, weight: .bold) + + let dayAtt = NSMutableAttributedString(string: " (Day \(model?.day_text ?? ""))") + dayAtt.yy_color = ._20_A_1_FF + dayAtt.yy_font = .font(ofSize: 14, weight: .regular) + titleAtt.append(dayAtt) + + titleLabel.attributedText = titleAtt + + } + } + + private lazy var bgView: FAGradientView = { + let view = FAGradientView() + view.fa_colors = [UIColor._524_B_8_E.cgColor, UIColor._303265.cgColor] + view.fa_locations = [0, 1] + view.fa_startPoint = .init(x: 0, y: 0.5) + view.fa_endPoint = .init(x: 1, y: 0.5) + view.layer.cornerRadius = 12 + view.layer.masksToBounds = true + view.layer.borderWidth = 1 + view.layer.borderColor = UIColor.E_5_E_5_E_5.cgColor + return view + }() + + private lazy var bgIconImageView1 = UIImageView(image: UIImage(named: "coin_attachment_01")) + private lazy var bgIconImageView2 = UIImageView(image: UIImage(named: "coin_attachment_03")) + private lazy var bgIconImageView4 = UIImageView(image: UIImage(named: "coin_attachment_04")) + private lazy var bgIconImageView5 = UIImageView(image: UIImage(named: "coin_attachment_05")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.numberOfLines = 0 + return label + }() + + private lazy var lineView1 = UIImageView(image: UIImage(named: "横间隔虚线")) + private lazy var lineView2 = UIImageView(image: UIImage(named: "间隔线")) + + private lazy var coinsView1: CoinsView = { + let view = CoinsView() + view.title = "Total Reward".localized + return view + }() + + private lazy var coinsView2: CoinsView = { + let view = CoinsView() + view.title = "Remaining".localized + return view + }() + + private lazy var claimButton: UIButton = { + var config = UIButton.Configuration.plain() + config.titleAlignment = .center + + let button = FAGradientButton(configuration: config, primaryAction: UIAction(handler: { [weak self] _ in + guard let self = self else { return } + self.clickClaimButton?(self.model?.id) + })) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 1, y: 0.5) + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + guard let button = button as? FAGradientButton else { return } + + if button.isEnabled { + button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + + let coinImage = UIImage(named: "coins_icon_03")! + let coinText = NSTextAttachment(image: coinImage) + coinText.bounds = .init(x: 0, y: -2.5, width: coinImage.size.width, height: coinImage.size.height) + let coinAtt = AttributedString(NSAttributedString(attachment: coinText)) + let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 12, weight: .bold), + .foregroundColor : UIColor._000000.withAlphaComponent(0.5) + ])) + + + button.configuration?.attributedTitle = AttributedString("Claim".localized, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor._114_CEE + ])) + + button.configuration?.attributedSubtitle = coinAtt + countAtt + + } else { + button.fa_colors = [UIColor.BCBCBC.cgColor, UIColor.BCBCBC.cgColor] + button.configuration?.attributedTitle = AttributedString("Claim".localized, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor.FFFFFF_0_8 + ])) + + button.configuration?.attributedSubtitle = nil + } + + + } + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + fa_setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension FACoinsPackClaimListCell { + + private func fa_setupLayout() { + contentView.addSubview(bgView) + bgView.addSubview(bgIconImageView5) + bgView.addSubview(bgIconImageView4) + bgView.addSubview(bgIconImageView1) + bgView.addSubview(bgIconImageView2) + bgView.addSubview(titleLabel) + bgView.addSubview(lineView1) + bgView.addSubview(lineView2) + bgView.addSubview(coinsView1) + bgView.addSubview(coinsView2) + bgView.addSubview(claimButton) + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + bgIconImageView1.snp.makeConstraints { make in + make.left.top.equalToSuperview() + } + + bgIconImageView2.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-8) + } + + bgIconImageView4.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalTo(bgIconImageView2) + } + + bgIconImageView5.snp.makeConstraints { make in + make.bottom.equalToSuperview() + make.left.equalToSuperview().offset(0) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(12) + make.centerY.equalTo(self.bgView.snp.top).offset(25) + make.right.lessThanOrEqualToSuperview().offset(-12) + } + + lineView1.snp.makeConstraints { make in + make.left.equalToSuperview().offset(12) + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(48) + } + + coinsView1.snp.makeConstraints { make in + make.left.equalToSuperview().offset(12) + make.bottom.equalToSuperview().offset(-18) + } + + lineView2.snp.makeConstraints { make in + make.centerY.equalTo(coinsView1) + make.left.equalTo(coinsView1.snp.right).offset(12) + } + + coinsView2.snp.makeConstraints { make in + make.centerY.equalTo(coinsView1) + make.left.equalTo(lineView2.snp.right).offset(12) + } + + claimButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-12) + make.centerY.equalTo(coinsView1) + make.height.equalTo(48) + make.width.equalTo(120) + } + } + +} + +extension FACoinsPackClaimListCell { + + class CoinsView: UIView { + + var title: String? { + didSet { + titleLabel.text = title + } + } + + var coins: Int? { + didSet { + coinsLabel.text = "\(coins ?? 0)" + } + } + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .bold) + label.textColor = .DFEFFF + return label + }() + + private lazy var iconImageView = UIImageView(image: UIImage(named: "coins_icon_03")) + + private lazy var coinsLabel: UILabel = { + let label = FALabel() + label.font = .font(ofSize: 14, weight: .bold) + label.textColors = [UIColor.FFCE_63.cgColor, UIColor.FFE_1_AA.cgColor] + label.textStartPoint = .init(x: 0, y: 0.5) + label.textEndPoint = .init(x: 1, y: 0.5) + label.text = "0" + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + addSubview(titleLabel) + addSubview(iconImageView) + addSubview(coinsLabel) + + titleLabel.snp.makeConstraints { make in + make.left.equalToSuperview() + make.top.equalToSuperview() + make.right.lessThanOrEqualToSuperview() + } + + iconImageView.snp.makeConstraints { make in + make.left.equalToSuperview() + make.bottom.equalToSuperview() + make.top.equalTo(titleLabel.snp.bottom).offset(8) + } + + coinsLabel.snp.makeConstraints { make in + make.centerY.equalTo(iconImageView) + make.left.equalTo(iconImageView.snp.right).offset(4) + make.right.lessThanOrEqualToSuperview() + } + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + } + +} diff --git a/Fableon/Object/Class/Me/V/FACoinsPackClaimListView.swift b/Fableon/Object/Class/Me/V/FACoinsPackClaimListView.swift new file mode 100644 index 0000000..a497b53 --- /dev/null +++ b/Fableon/Object/Class/Me/V/FACoinsPackClaimListView.swift @@ -0,0 +1,106 @@ +// +// FACoinsPackClaimListView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit + +class FACoinsPackClaimListView: UIView { + + var clickClaimButton: ((_ id: String?) -> Void)? + + var dataArr: [FACoinsPackReceiveModel] = [] { + didSet { + collectionView.reloadData() + } + } + + private lazy var titleView: FACoinPackTitleView = { + let view = FACoinPackTitleView() + view.dotColor = .C_5_DDF_5 + view.textColors = [UIColor.C_5_DDF_5.cgColor, UIColor.C_5_DDF_5.cgColor] + view.font = .font(ofSize: 14, weight: .regular) + view.text = "Active Refills".localized.uppercased() + return view + }() + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: UIScreen.width - 32, height: 122) + layout.minimumLineSpacing = 12 + return layout + }() + + private lazy var collectionView: FACollectionView = { + let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.addObserver(self, forKeyPath: "contentSize", context: nil) + collectionView.register(FACoinsPackClaimListCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + deinit { + collectionView.removeObserver(self, forKeyPath: "contentSize") + } + + override init(frame: CGRect) { + super.init(frame: frame) + + fa_setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { + if keyPath == "contentSize" { + let height = self.collectionView.contentSize.height + 1 + collectionView.snp.updateConstraints { make in + make.height.equalTo(height) + } + } + } + +} + +extension FACoinsPackClaimListView { + + private func fa_setupLayout() { + addSubview(titleView) + addSubview(collectionView) + + titleView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalToSuperview() + } + + collectionView.snp.makeConstraints { make in + make.left.right.bottom.equalToSuperview() + make.top.equalToSuperview().offset(30) + make.height.equalTo(1) + make.bottom.equalToSuperview() + } + } +} + +//MARK: UICollectionViewDelegate UICollectionViewDataSource +extension FACoinsPackClaimListView: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! FACoinsPackClaimListCell + cell.model = self.dataArr[indexPath.row] + cell.clickClaimButton = { [weak self] id in + self?.clickClaimButton?(id) + } + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return dataArr.count + } + +} diff --git a/Fableon/Object/Class/Me/V/FALoginView.swift b/Fableon/Object/Class/Me/V/FALoginView.swift new file mode 100644 index 0000000..0063ef5 --- /dev/null +++ b/Fableon/Object/Class/Me/V/FALoginView.swift @@ -0,0 +1,121 @@ +// +// FALoginView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FALoginView: FAPanModalContentView { + + + private lazy var bgView = UIImageView(image: UIImage(named: "弹窗背景色")) + private lazy var bgIconImageView = UIImageView(image: UIImage(named: "Ellipse 873")) + private lazy var logoImageView = UIImageView(image: UIImage(named: "logo_image_02")) + + private lazy var stackView: UIStackView = { + let view = UIStackView(arrangedSubviews: [appleButton, facebookButton]) + view.axis = .vertical + view.spacing = 18 + return view + }() + + private lazy var appleButton: UIButton = { + let button = self.createButton(image: UIImage(named: "apple_logo_icon_01"), title: "Login with Apple".localized) + button.addAction(UIAction(handler: { [weak self] _ in + self?.login(type: .apple) + }), for: .touchUpInside) + return button + }() + + private lazy var facebookButton: UIButton = { + let button = self.createButton(image: UIImage(named: "facebook_logo_icon_01"), title: "Login with Facebook".localized) + button.addAction(UIAction(handler: { [weak self] _ in + self?.login(type: .faceBook) + }), for: .touchUpInside) + return button + }() + + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = .clear + contentHeight = 300 + fa_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func cornerRadius() -> CGFloat { + return 0 + } + + private func createButton(image: UIImage?, title: String) -> UIButton { + var config = UIButton.Configuration.plain() + config.image = image + config.imagePadding = 12 + config.attributedTitle = AttributedString(title, attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 14, weight: .bold), + .foregroundColor : UIColor._333333 + ])) + config.background.backgroundColor = .FFFFFF + + let button = UIButton(configuration: config) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + + button.snp.makeConstraints { make in + make.height.equalTo(48) + } + + return button + } + + private func login(type: FALogin.LoginType) { + FAHUD.show() + FALogin.manager.thirdLogin(type: type, presentingViewController: nil) { [weak self] isFinish in + FAHUD.dismiss() + guard let self = self else { return } + if isFinish { + Task { + await self.dismiss(animated: true) + } + } + } + + } + +} + +extension FALoginView { + + private func fa_setupLayout() { + addSubview(bgView) + bgView.addSubview(bgIconImageView) + bgView.addSubview(logoImageView) + addSubview(stackView) + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + bgIconImageView.snp.makeConstraints { make in + make.top.centerX.equalToSuperview() + } + + logoImageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(20) + } + + stackView.snp.makeConstraints { make in + make.top.equalToSuperview().offset(112) + make.left.equalToSuperview().offset(37) + make.centerX.equalToSuperview() + } + } + +} diff --git a/Fableon/Object/Class/Me/V/FAMeCoinsPackButton.swift b/Fableon/Object/Class/Me/V/FAMeCoinsPackButton.swift new file mode 100644 index 0000000..5a338f3 --- /dev/null +++ b/Fableon/Object/Class/Me/V/FAMeCoinsPackButton.swift @@ -0,0 +1,95 @@ +// +// FAMeCoinsPackButton.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit + +class FAMeCoinsPackButton: UIControl { + + private lazy var bgView: FAGradientView = { + let view = FAGradientView() + view.isUserInteractionEnabled = false + view.fa_colors = [UIColor._114_CEE.cgColor, UIColor._000000.cgColor] + view.fa_locations = [0, 1] + view.fa_startPoint = .init(x: 0, y: 0.5) + view.fa_endPoint = .init(x: 1, y: 0.5) + view.layer.cornerRadius = 12 + view.layer.masksToBounds = true + view.layer.borderWidth = 1 + view.layer.borderColor = UIColor._629_DFA.cgColor + return view + }() + + private lazy var iconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "礼物11")) + return imageView + }() + + private lazy var titleLabel: FALabel = { + let label = FALabel() + label.font = .font(ofSize: 14, weight: .init(900)).withBoldItalic() + label.textColors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + label.textStartPoint = .init(x: 0, y: 0.5) + label.textEndPoint = .init(x: 0.7, y: 0.5) + label.text = "Daily reward ready!".localized + return label + }() + + private lazy var subtitleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium).withBoldItalic() + label.textColor = .FFFFFF + label.text = "Claim your rewards now.".localized + return label + }() + + private lazy var indicatorImageView = UIImageView(image: UIImage(named: "arrow")) + + override init(frame: CGRect) { + super.init(frame: frame) + fa_setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +extension FAMeCoinsPackButton { + + private func fa_setupLayout() { + addSubview(bgView) + bgView.addSubview(iconImageView) + bgView.addSubview(titleLabel) + bgView.addSubview(subtitleLabel) + bgView.addSubview(indicatorImageView) + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + iconImageView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(12) + } + + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(13) + make.left.equalTo(iconImageView.snp.right).offset(8) + } + + subtitleLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.bottom.equalToSuperview().offset(-13) + } + + indicatorImageView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-12) + } + } + +} diff --git a/Fableon/Object/Class/Me/V/FAMeHeaderView.swift b/Fableon/Object/Class/Me/V/FAMeHeaderView.swift index 73950e4..95ef447 100644 --- a/Fableon/Object/Class/Me/V/FAMeHeaderView.swift +++ b/Fableon/Object/Class/Me/V/FAMeHeaderView.swift @@ -9,7 +9,7 @@ import UIKit class FAMeHeaderView: UIView { - var contentHeight: CGFloat = 40 + 66 + 40 + 28 + 24 + var contentHeight: CGFloat = 40 + 66 + 40 + 28 + 16 + 60 + 16 var userInfo: FAUserInfo? { didSet { @@ -22,6 +22,8 @@ class FAMeHeaderView: UIView { coinsView.count = userInfo?.coin_left_total ?? 0 bonusCoinsView.count = userInfo?.send_coin_left_total ?? 0 + + loginButton.isHidden = FALogin.manager.isLogin } } @@ -69,6 +71,32 @@ class FAMeHeaderView: UIView { return view }() + private lazy var coinPackButton: FAMeCoinsPackButton = { + let button = FAMeCoinsPackButton() + button.addAction(UIAction(handler: { [weak self] _ in + guard let self = self else { return } + let vc = FACoinPackViewController() + self.viewController?.navigationController?.pushViewController(vc, animated: true) + }), for: .touchUpInside) + return button + }() + + private lazy var loginButton: UIButton = { + let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in + guard let self = self else { return } + let view = FALoginView() + view.present(in: nil) + })) + button.layer.cornerRadius = 14 + button.layer.masksToBounds = true + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.FFFEE_9.cgColor + button.setTitle("Log in".localized, for: .normal) + button.setTitleColor(.FFFFFF, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .medium) + return button + }() + override init(frame: CGRect) { super.init(frame: frame) @@ -88,6 +116,8 @@ extension FAMeHeaderView { addSubview(idLabel) addSubview(coinsView) addSubview(bonusCoinsView) + addSubview(coinPackButton) + addSubview(loginButton) avatarImageView.snp.makeConstraints { make in make.left.equalToSuperview().offset(16) @@ -115,6 +145,20 @@ extension FAMeHeaderView { make.top.equalTo(coinsView) make.left.equalTo(coinsView.snp.right).offset(40) } + + coinPackButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.centerX.equalToSuperview() + make.top.equalTo(coinsView.snp.bottom).offset(16) + make.height.equalTo(60) + } + + loginButton.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-16) + make.centerY.equalTo(avatarImageView) + make.width.equalTo(76) + make.height.equalTo(28) + } } } diff --git a/Fableon/Object/Class/Me/V/FASettingCell.swift b/Fableon/Object/Class/Me/V/FASettingCell.swift new file mode 100644 index 0000000..13ab00a --- /dev/null +++ b/Fableon/Object/Class/Me/V/FASettingCell.swift @@ -0,0 +1,26 @@ +// +// FASettingCell.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FASettingCell: FATableViewCell { + + + @IBOutlet weak var titleLabel: UILabel! + + override func awakeFromNib() { + super.awakeFromNib() + + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + +} diff --git a/Fableon/Object/Class/Me/V/FASettingCell.xib b/Fableon/Object/Class/Me/V/FASettingCell.xib new file mode 100644 index 0000000..64905fa --- /dev/null +++ b/Fableon/Object/Class/Me/V/FASettingCell.xib @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Fableon/Object/Class/Me/V/FASettingFooterView.swift b/Fableon/Object/Class/Me/V/FASettingFooterView.swift new file mode 100644 index 0000000..33bba15 --- /dev/null +++ b/Fableon/Object/Class/Me/V/FASettingFooterView.swift @@ -0,0 +1,48 @@ +// +// FASettingFooterView.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FASettingFooterView: UIView { + + + private lazy var logoutButton: UIButton = { + let button = FAGradientButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in + guard let self = self else { return } + FALogin.manager.logout(completer: nil) + })) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor] + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 1, y: 0.5) + button.setTitle("Log out".localized, for: .normal) + button.setTitleColor(._000000, for: .normal) + button.titleLabel?.font = .font(ofSize: 18, weight: .semibold) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(logoutButton) + + logoutButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.centerX.equalToSuperview() + make.bottom.equalToSuperview() + make.height.equalTo(48) + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + + diff --git a/Fableon/Object/Class/MyShort/C/FACollectViewController.swift b/Fableon/Object/Class/MyShort/C/FACollectViewController.swift index a42dcf1..30230d4 100644 --- a/Fableon/Object/Class/MyShort/C/FACollectViewController.swift +++ b/Fableon/Object/Class/MyShort/C/FACollectViewController.swift @@ -122,6 +122,22 @@ class FACollectViewController: FAViewController { } } + private func removeCollect(_ indexPath: IndexPath) { + + let alert = FARemoveCollectAlert() + alert.show() + alert.clickHighlightButton = { [weak self] in + guard let self = self else { return } + let model = self.dataArr[indexPath.row] + guard let shortPlayId = model.short_play_id else { return } + FAAPI.requestShortCollect(isCollect: false, shortPlayId: shortPlayId, videoId: model.short_play_video_id) { [weak self] in + guard let self = self else { return } + self.dataArr.remove(at: indexPath.row) + self.collectionView.deleteItems(at: [indexPath]) + } + } + } + } extension FACollectViewController { @@ -147,13 +163,10 @@ extension FACollectViewController: UICollectionViewDataSource, UICollectionViewD cell.clickDeleteButton = { [weak self] cell in guard let self = self else { return } guard let indexPath = self.collectionView.indexPath(for: cell) else { return } - guard let shortPlayId = cell.model?.short_play_id else { return } - FAAPI.requestShortCollect(isCollect: false, shortPlayId: shortPlayId, videoId: cell.model?.short_play_video_id) { [weak self] in - guard let self = self else { return } - self.dataArr.remove(at: indexPath.row) - self.collectionView.deleteItems(at: [indexPath]) - } + self.removeCollect(indexPath) + + } return cell } diff --git a/Fableon/Object/Class/Player/V/FAEpSelectorView.swift b/Fableon/Object/Class/Player/V/FAEpSelectorView.swift index e8ba2a3..58f960a 100644 --- a/Fableon/Object/Class/Player/V/FAEpSelectorView.swift +++ b/Fableon/Object/Class/Player/V/FAEpSelectorView.swift @@ -173,12 +173,24 @@ extension FAEpSelectorView: UICollectionViewDelegate, UICollectionViewDataSource } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - model?.episodeList?.count ?? 0 + return model?.episodeList?.count ?? 0 } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard let epList = self.model?.episodeList else { return } if self.selectedIndex == indexPath.row { return } - self.selectedIndex = indexPath.row + + let lastIndex = indexPath.row - 1 + var lastIsLock = false + if lastIndex > 0 && lastIndex < epList.count { + let lastModel = epList[lastIndex] + lastIsLock = lastModel.is_lock ?? false + } + + if lastIsLock { + FAToast.show(text: "buy_fail_toast_02".localized) + return + } self.didSelected?(indexPath.row) self.dismiss(animated: true) { diff --git a/Fableon/Object/Class/Player/V/FAOldVideoRechargeView.swift b/Fableon/Object/Class/Player/V/FAOldVideoRechargeView.swift index 8dfb6d9..98a494a 100644 --- a/Fableon/Object/Class/Player/V/FAOldVideoRechargeView.swift +++ b/Fableon/Object/Class/Player/V/FAOldVideoRechargeView.swift @@ -11,6 +11,7 @@ import HWPanModal class FAOldVideoRechargeView: FAPanModalContentView { var buyFinishHandle: (() -> Void)? + var didDismissHandle: (() -> Void)? var model: FAPayDateModel? { didSet { @@ -35,7 +36,7 @@ class FAOldVideoRechargeView: FAPanModalContentView { } } -// self.stackView.addArrangedSubview(self.tipView) + self.stackView.addArrangedSubview(self.tipView) self.setNeedsLayoutUpdate() } @@ -62,6 +63,7 @@ class FAOldVideoRechargeView: FAPanModalContentView { Task { await self.dismiss(animated: true) } + self.didDismissHandle?() })) button.setImage(UIImage(named: "close_icon_02"), for: .normal) return button @@ -123,6 +125,42 @@ class FAOldVideoRechargeView: FAPanModalContentView { return label }() + private lazy var tipView: UIView = { + let view = UIView() + view.addSubview(tipTitleLabel) + view.addSubview(tipTextLabel) + + tipTitleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().offset(7) + make.left.equalToSuperview().offset(16) + } + + tipTextLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.right.lessThanOrEqualToSuperview().offset(-16) + make.top.equalTo(tipTitleLabel.snp.bottom).offset(4) + make.bottom.equalToSuperview() + } + return view + }() + + private lazy var tipTitleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .medium) + label.textColor = .FFFFFF + label.text = "store_tips_title".localized + return label + }() + + private lazy var tipTextLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 10, weight: .regular) + label.textColor = .FFFFFF + label.text = "store_tips".localized + label.numberOfLines = 0 + return label + }() + deinit { NotificationCenter.default.removeObserver(self) } diff --git a/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift b/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift index d6a8cf7..0d1bde7 100644 --- a/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift +++ b/Fableon/Object/Class/Player/VM/FAShortDetailViewModel.swift @@ -171,6 +171,10 @@ extension FAShortDetailViewModel { guard let self = self else { return } self.requestDetailData(indexPath: self.currentIndexPath, completer: nil) } + view.didDismissHandle = { [weak self] in + guard let self = self else { return } + self._showVipRetainAlert(videoInfo) + } view.present(in: nil) self.popView = view } @@ -182,6 +186,25 @@ extension FAShortDetailViewModel { view.present(in: nil) self.popView = view } + + private func _showVipRetainAlert(_ videoInfo: FAVideoInfoModel) { + + + payDataRequest = FAPayDataRequest() + + payDataRequest?.requestVipRetainPayInfo { [weak self] model in + guard let self = self else { return } + guard let model = model else { return } + let view = FAVipRetainAlert() + view.model = model + view.videoInfo = videoInfo + view.buyFinishHandle = { [weak self] in + guard let self = self else { return } + self.requestDetailData(indexPath: self.currentIndexPath, completer: nil) + } + view.show(in: FATool.keyWindow) + } + } } extension FAShortDetailViewModel { diff --git a/Fableon/Object/Class/Store/M/FACoinPackCanReceiveModel.swift b/Fableon/Object/Class/Store/M/FACoinPackCanReceiveModel.swift new file mode 100644 index 0000000..914c886 --- /dev/null +++ b/Fableon/Object/Class/Store/M/FACoinPackCanReceiveModel.swift @@ -0,0 +1,13 @@ +// +// FACoinPackCanReceiveModel.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit +import SmartCodable + +struct FACoinPackCanReceiveModel: SmartCodable { + var coins: Int? +} diff --git a/Fableon/Object/Class/Store/M/FACoinsPackModel.swift b/Fableon/Object/Class/Store/M/FACoinsPackModel.swift new file mode 100644 index 0000000..ece9d10 --- /dev/null +++ b/Fableon/Object/Class/Store/M/FACoinsPackModel.swift @@ -0,0 +1,25 @@ +// +// FACoinsPackModel.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit +import SmartCodable + +struct FACoinsPackModel: SmartCodable { + + //当前可领取订阅数 + var receive_count: Int? + //已领取累计金币总数 + var week_total: Int? + //剩余可领取金币数 + var week_remaining_total: Int? + //订阅可领取累计金币总数 + var week_max_total: Int? + //当前可领取金币总数 + var receive_coins: Int? + + var receive_list: [FACoinsPackReceiveModel]? +} diff --git a/Fableon/Object/Class/Store/M/FACoinsPackReceiveModel.swift b/Fableon/Object/Class/Store/M/FACoinsPackReceiveModel.swift new file mode 100644 index 0000000..25e0333 --- /dev/null +++ b/Fableon/Object/Class/Store/M/FACoinsPackReceiveModel.swift @@ -0,0 +1,25 @@ +// +// FACoinsPackReceiveModel.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/29. +// + +import UIKit +import SmartCodable + +struct FACoinsPackReceiveModel: SmartCodable { + + var id: String? + var title: String? + //剩余可领取金币数 + var week_remaining_total: Int? + //当前可领取金币数 + var receive_coins: Int? + //已领取累计金币总数 + var week_total: Int? + //可领取累计金币总数 + var week_max_total: Int? + //领取天数文本 + var day_text: String? +} diff --git a/Fableon/Object/Libs/AdjustStateManager/FAAdjustStateManager.swift b/Fableon/Object/Libs/AdjustStateManager/FAAdjustStateManager.swift index c70e7ae..2db0040 100644 --- a/Fableon/Object/Libs/AdjustStateManager/FAAdjustStateManager.swift +++ b/Fableon/Object/Libs/AdjustStateManager/FAAdjustStateManager.swift @@ -10,14 +10,15 @@ import UIKit class FAAdjustStateManager { static let manager = FAAdjustStateManager() + var allowOpenMessage = true + var webpageURL: URL? ///是否需要重试 var isNeedRetry = false - var allowOpenMessage = true - var isOpenApp = false var idfaAuthorizationFinish = false + var apnsAuthorizationFinish = false } diff --git a/Fableon/Object/Libs/Alert/FAApnsAlert.swift b/Fableon/Object/Libs/Alert/FAApnsAlert.swift new file mode 100644 index 0000000..5939040 --- /dev/null +++ b/Fableon/Object/Libs/Alert/FAApnsAlert.swift @@ -0,0 +1,104 @@ +// +// FAApnsAlert.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/31. +// + +import UIKit + +class FAApnsAlert: FABaseAlert { + + private lazy var imageView = UIImageView(image: UIImage(named: "__magnifying")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 18, weight: .semibold) + label.textColor = .FFFFFF + label.text = "apns_alert_title".localized + return label + }() + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.numberOfLines = 0 + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .FFFFFF + label.text = "apns_alert_text".localized + return label + }() + + private lazy var laterButton: UIButton = { + let button = UIButton(type: .custom) + button.layer.cornerRadius = 18 + button.layer.masksToBounds = true + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.FFFFFF.cgColor + button.setTitle("Later".localized, for: .normal) + button.setTitleColor(.FFFFFF, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + highlightButton.setTitle("Open".localized, for: .normal) + + fa_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func handleHighlightButton() { + super.handleHighlightButton() + FATool.openApnsSetting() + } + +} + +extension FAApnsAlert { + + private func fa_setupLayout() { + containerView.addSubview(imageView) + contentView.addSubview(titleLabel) + contentView.addSubview(textLabel) + contentView.addSubview(laterButton) + contentView.addSubview(highlightButton) + + imageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(-62) + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(imageView.snp.bottom).offset(10) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-20) + make.top.equalTo(titleLabel.snp.bottom).offset(12) + } + + laterButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(23) + make.top.equalTo(textLabel.snp.bottom).offset(21) + make.bottom.equalToSuperview().offset(-20) + make.height.equalTo(36) + } + + highlightButton.snp.makeConstraints { make in + make.width.height.top.equalTo(laterButton) + make.left.equalTo(laterButton.snp.right).offset(11) + make.right.equalToSuperview().offset(-23) + } + } +} diff --git a/Fableon/Object/Libs/Alert/FABaseAlert.swift b/Fableon/Object/Libs/Alert/FABaseAlert.swift new file mode 100644 index 0000000..c53e59a --- /dev/null +++ b/Fableon/Object/Libs/Alert/FABaseAlert.swift @@ -0,0 +1,169 @@ +// +// FABaseAlert.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit +import SnapKit + +class FABaseAlert: UIView { + + var clickHighlightButton: (() -> Void)? + + var contentWidth: CGFloat = UIScreen.width - 70 { + didSet { + containerView.snp.updateConstraints { make in + make.width.equalTo(contentWidth) + } + } + } + + private(set) var containerView: UIView = { + let view = UIView() + return view + }() + + private(set) var contentView: UIView = { + let view = UIView() + view.backgroundColor = ._404040 + view.layer.cornerRadius = 16 + view.layer.masksToBounds = true + return view + }() + + private(set) lazy var closeButton: UIButton = { + let button = UIButton(type: .custom) + button.setImage(UIImage(named: "close_icon_03"), for: .normal) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + lazy var highlightButton: FAGradientButton = { + let button = FAGradientButton(type: .custom) + button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor] + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 1, y: 0.5) + button.layer.cornerRadius = 16 + button.layer.masksToBounds = true + button.setTitleColor(._000000, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .semibold) + button.addTarget(self, action: #selector(handleHighlightButton), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + backgroundColor = ._000000.withAlphaComponent(0.5) + + addSubview(containerView) + containerView.addSubview(contentView) + containerView.addSubview(closeButton) + + containerView.snp.makeConstraints { make in + make.center.equalToSuperview() + make.width.equalTo(contentWidth) + } + + contentView.snp.makeConstraints { make in + make.left.right.top.equalToSuperview() + make.bottom.equalToSuperview().offset(-66) + } + + closeButton.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.bottom.equalToSuperview() + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @discardableResult + @objc func show(in view: UIView? = nil) -> Self { + guard self.superview == nil else { return self } + + var inView: UIView + if let view = view { + inView = view + } else { + inView = FABaseAlert.Window.manager.createWindow() + } + + inView.addSubview(self) + self.frame = inView.bounds + showAnimation() + + return self + } + @objc func dismiss() { + dismissAnimation() + } + + @objc func handleHighlightButton() { + self.dismissAnimation() + self.clickHighlightButton?() + } + +} + +extension FABaseAlert { + private func showAnimation() { + containerView.transform = CGAffineTransform(translationX: 0, y: 200) + + UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0) { + self.containerView.transform = CGAffineTransform.identity + } + } + + private func dismissAnimation() { + + UIView.animate(withDuration: 0.3) { + self.alpha = 0 + self.containerView.transform = CGAffineTransform(translationX: 0, y: 500) + } completion: { _ in + self.removeFromSuperview() + FABaseAlert.Window.manager.dismissWindow() + } + } +} + +extension FABaseAlert { + class Window { + static let manager = Window() + + private(set) var window: UIWindow? + + func createWindow() -> UIWindow { + guard let window = window else { + let window = UIWindow(windowScene: FATool.windowScene!) + window.backgroundColor = .clear + window.windowLevel = .alert + window.isHidden = false + self.window = window + return window + } + return window + } + + func dismissWindow() { + guard let window = self.window else { return } + + var isHidden = true + + window.subviews.forEach { + if $0.isKind(of: FABaseAlert.self) { + isHidden = false + } + } + if isHidden { + window.isHidden = true + self.window = nil + } + } + } +} + diff --git a/Fableon/Object/Libs/Alert/FACoinsPackAlert.swift b/Fableon/Object/Libs/Alert/FACoinsPackAlert.swift new file mode 100644 index 0000000..3bed598 --- /dev/null +++ b/Fableon/Object/Libs/Alert/FACoinsPackAlert.swift @@ -0,0 +1,117 @@ +// +// FACoinsPackAlert.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FACoinsPackAlert: FABaseAlert { + + var coinsCount: Int? { + didSet { + coinsView.setNeedsUpdateConfiguration() + } + } + + private lazy var imageView = UIImageView(image: UIImage(named: "签到")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 18, weight: .bold) + label.textColor = .FFFFFF + label.textAlignment = .center + label.numberOfLines = 0 + label.text = "coins_pack_alert_title".localized + return label + }() + + private lazy var coinsView: UIButton = { + var config = UIButton.Configuration.plain() + config.image = UIImage(named: "coins_icon_10") + config.imagePadding = 8 + config.contentInsets = .zero + let button = UIButton(configuration: config) + button.isUserInteractionEnabled = false + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + button.configuration?.attributedTitle = AttributedString("+\(self.coinsCount ?? 0)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 24, weight: .init(700)), + .foregroundColor : UIColor.F_6_CF_87 + ])) + } + return button + }() + + private lazy var laterButton: UIButton = { + let button = UIButton(type: .custom) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.layer.borderColor = UIColor._777777.cgColor + button.layer.borderWidth = 1 + button.setTitle("Later".localized, for: .normal) + button.setTitleColor(._777777, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .bold) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + self.highlightButton.setTitle("Claim Now".localized, for: .normal) + self.highlightButton.setTitleColor(.FFFFFF, for: .normal) + self.highlightButton.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + self.highlightButton.layer.cornerRadius = 24 + self.highlightButton.titleLabel?.font = .font(ofSize: 14, weight: .bold) + + fa_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension FACoinsPackAlert { + + private func fa_setupLayout() { + contentView.addSubview(imageView) + contentView.addSubview(titleLabel) + contentView.addSubview(coinsView) + contentView.addSubview(highlightButton) + contentView.addSubview(laterButton) + + imageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(24) + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(imageView.snp.bottom).offset(16) + } + + coinsView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(titleLabel.snp.bottom).offset(16) + } + + highlightButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(18) + make.centerX.equalToSuperview() + make.top.equalTo(coinsView.snp.bottom).offset(16) + make.height.equalTo(48) + } + + laterButton.snp.makeConstraints { make in + make.left.right.height.equalTo(highlightButton) + make.top.equalTo(highlightButton.snp.bottom).offset(12) + make.bottom.equalToSuperview().offset(-24) + } + } + +} diff --git a/Fableon/Object/Libs/Alert/FARemoveCollectAlert.swift b/Fableon/Object/Libs/Alert/FARemoveCollectAlert.swift new file mode 100644 index 0000000..a23141f --- /dev/null +++ b/Fableon/Object/Libs/Alert/FARemoveCollectAlert.swift @@ -0,0 +1,93 @@ +// +// FARemoveCollectAlert.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FARemoveCollectAlert: FABaseAlert { + + + private lazy var imageView = UIImageView(image: UIImage(named: "alert_image_01")) + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 18, weight: .semibold) + label.textColor = .FFFFFF + label.text = "remove_collect_alert_title".localized + label.numberOfLines = 0 + label.textAlignment = .center + return label + }() + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 12, weight: .regular) + label.textColor = .FFFFFF + label.numberOfLines = 0 + label.textAlignment = .center + label.text = "remove_collect_alert_text".localized + return label + }() + + private lazy var cancelButton: UIButton = { + let button = UIButton(type: .custom) + button.layer.cornerRadius = 18 + button.layer.masksToBounds = true + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.FFFFFF.cgColor + button.setTitle("Cancel".localized, for: .normal) + button.setTitleColor(.FFFFFF, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .medium) + button.addTarget(self, action: #selector(dismiss), for: .touchUpInside) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + highlightButton.setTitle("Remove".localized, for: .normal) + + containerView.addSubview(imageView) + contentView.addSubview(titleLabel) + contentView.addSubview(textLabel) + contentView.addSubview(cancelButton) + contentView.addSubview(highlightButton) + + imageView.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalToSuperview().offset(-62) + } + + titleLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.equalTo(imageView.snp.bottom).offset(10) + make.right.lessThanOrEqualToSuperview().offset(-10) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-20) + make.top.equalTo(titleLabel.snp.bottom).offset(12) + } + + cancelButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(24) + make.top.equalTo(textLabel.snp.bottom).offset(21) + make.bottom.equalTo(-20) + make.height.equalTo(36) + } + + highlightButton.snp.makeConstraints { make in + make.left.equalTo(cancelButton.snp.right).offset(11) + make.right.equalToSuperview().offset(-24) + make.width.height.top.equalTo(cancelButton) + } + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Fableon/Object/Libs/Alert/FAVipRetainAlert.swift b/Fableon/Object/Libs/Alert/FAVipRetainAlert.swift new file mode 100644 index 0000000..4bd9f8c --- /dev/null +++ b/Fableon/Object/Libs/Alert/FAVipRetainAlert.swift @@ -0,0 +1,307 @@ +// +// FAVipRetainAlert.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit + +class FAVipRetainAlert: FABaseAlert { + + var buyFinishHandle: (() -> Void)? + + var model: FAPayAlertModel? { + didSet { + let payItem = model?.info + titleView.text = payItem?.getVipTitle() + itemView.payItem = payItem + } + } + + var videoInfo: FAVideoInfoModel? + + + private lazy var titleView: FACoinPackTitleView = { + let view = FACoinPackTitleView() + view.dotColor = ._20_A_1_FF + view.textColors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + view.font = .font(ofSize: 24, weight: .init(900)) + view.text = "Weekly Refill".localized.uppercased() + return view + }() + + private lazy var itemView: ItemView = { + let view = ItemView() + return view + }() + + private lazy var textLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 18, weight: .bold).withBoldItalic() + label.textColor = .C_5_DDF_5 + label.text = "vip_retain_alert_text".localized + label.textAlignment = .center + label.numberOfLines = 0 + return label + }() + + private lazy var buyButton: UIButton = { + let button = FAGradientButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in + guard let self = self else { return } + guard let payItem = self.model?.info else { return } + FAIapManager.manager.start(model: payItem, shortPlayId: self.videoInfo?.short_play_id, videoId: self.videoInfo?.short_play_video_id) { [weak self] finish in + guard let self = self else { return } + if finish { + FALogin.manager.requestUserInfo(completer: nil) + self.dismiss() + self.buyFinishHandle?() + } + } + + })) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 0.7, y: 0.5) + button.setTitle("Buy Now".localized, for: .normal) + button.setTitleColor(.FFFFFF, for: .normal) + button.titleLabel?.font = .font(ofSize: 14, weight: .bold) + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + contentWidth = UIScreen.width - 55 + contentView.backgroundColor = .clear + + fa_setupLayout() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension FAVipRetainAlert { + + private func fa_setupLayout() { + contentView.addSubview(titleView) + contentView.addSubview(itemView) + contentView.addSubview(textLabel) + contentView.addSubview(buyButton) + + titleView.snp.makeConstraints { make in + make.top.equalToSuperview() + make.centerX.equalToSuperview() + } + + itemView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalTo(titleView.snp.bottom).offset(12) + make.height.equalTo(84) + } + + textLabel.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.right.lessThanOrEqualToSuperview().offset(-10) + make.top.equalTo(itemView.snp.bottom).offset(12) + } + + buyButton.snp.makeConstraints { make in + make.left.equalToSuperview().offset(20) + make.centerX.equalToSuperview() + make.top.equalTo(textLabel.snp.bottom).offset(12) + make.height.equalTo(48) + make.bottom.equalToSuperview() + } + + } + +} + +extension FAVipRetainAlert { + + + + class ItemView: UIView { + + var payItem: FAPayItem? { + didSet { + nameLabel.text = payItem?.getVipTitle() + + button.setNeedsUpdateConfiguration() + } + } + + private lazy var bgView: FAGradientView = { + let view = FAGradientView() + view.fa_colors = [UIColor._524_B_8_E.cgColor, UIColor._303265.cgColor] + view.fa_locations = [0, 1] + view.fa_startPoint = .init(x: 0, y: 0.5) + view.fa_endPoint = .init(x: 1, y: 0.5) + view.layer.cornerRadius = 12 + view.layer.masksToBounds = true + view.layer.borderWidth = 1 + view.layer.borderColor = UIColor.E_5_E_5_E_5.cgColor + return view + }() + + private lazy var bgIconImageView1: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "coin_attachment_01")) + return imageView + }() + + private lazy var bgIconImageView2: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "coin_attachment_02")) + return imageView + }() + private lazy var bgIconImageView3 = UIImageView(image: UIImage(named: "coin_attachment_04")) + private lazy var bgIconImageView4 = UIImageView(image: UIImage(named: "coin_attachment_05")) + + private lazy var vipIconImageView = UIImageView(image: UIImage(named: "皇冠-金")) + + private lazy var nameLabel: UILabel = { + let label = UILabel() + label.font = .font(ofSize: 18, weight: .bold) + label.textColor = .FFFFFF + return label + }() + + private lazy var textLabel: UILabel = { + let label = FALabel() + label.textColors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + label.textStartPoint = .init(x: 0, y: 0.5) + label.textEndPoint = .init(x: 0.7, y: 0.5) + label.font = .font(ofSize: 12, weight: .regular) + return label + }() + + private lazy var button: UIButton = { + var config = UIButton.Configuration.plain() + config.contentInsets = .init(top: 0, leading: 10, bottom: 0, trailing: 10) + config.titleAlignment = .center + + let button = FAGradientButton(configuration: config) + button.isUserInteractionEnabled = false + button.fa_colors = [UIColor._53_A_2_F_1.cgColor, UIColor.C_5_DDF_5.cgColor] + button.fa_locations = [0, 1] + button.fa_startPoint = .init(x: 0, y: 0.5) + button.fa_endPoint = .init(x: 0.5, y: 0.5) + button.layer.cornerRadius = 24 + button.layer.masksToBounds = true + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + + let currency = self.payItem?.currency ?? "" + let timeString = self.payItem?.getTimeString() ?? "" + let oldPrice = self.payItem?.price ?? "" + var discountPrice: String? = nil + + if self.payItem?.discount_type == 1, let introductoryPrice = self.payItem?.introductionaryOffer { + discountPrice = introductoryPrice.price.stringValue + } else if self.payItem?.discount_type == 2, let discount = self.payItem?.promotionalOffers?.first { + discountPrice = discount.price.stringValue + } + + if let discountPrice = discountPrice { + button.configuration?.attributedTitle = AttributedString("\(currency)\(discountPrice)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 18, weight: .bold), + .foregroundColor : UIColor._114_CEE + ])) + + button.configuration?.attributedSubtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 12, weight: .regular), + .foregroundColor : UIColor._000000.withAlphaComponent(0.5), + .strikethroughStyle: NSUnderlineStyle.single.rawValue, + .strikethroughColor: UIColor._000000.withAlphaComponent(0.5) + ])) + + } else { + button.configuration?.attributedTitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 18, weight: .bold), + .foregroundColor : UIColor._114_CEE + ])) + + button.configuration?.attributedSubtitle = AttributedString("/\(timeString)", attributes: AttributeContainer([ + .font : UIFont.font(ofSize: 12, weight: .regular), + .foregroundColor : UIColor._000000.withAlphaComponent(0.5) + ])) + } + + } + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + nameLabel.text = "Weekly VIP" + textLabel.text = "Unlimited access to all series" + + addSubview(bgView) + bgView.addSubview(bgIconImageView4) + bgView.addSubview(bgIconImageView3) + bgView.addSubview(bgIconImageView1) + bgView.addSubview(bgIconImageView2) + bgView.addSubview(vipIconImageView) + bgView.addSubview(nameLabel) + bgView.addSubview(textLabel) + bgView.addSubview(button) + + bgView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + bgIconImageView1.snp.makeConstraints { make in + make.left.equalToSuperview().offset(0) + make.top.equalToSuperview().offset(0) + } + + bgIconImageView2.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-26) + make.centerY.equalToSuperview() + } + + bgIconImageView3.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.centerX.equalTo(bgIconImageView2) + } + + bgIconImageView4.snp.makeConstraints { make in + make.left.bottom.equalToSuperview() + } + + vipIconImageView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(16) + make.top.equalToSuperview().offset(18) + } + + nameLabel.snp.makeConstraints { make in + make.centerY.equalTo(vipIconImageView) + make.left.equalTo(vipIconImageView.snp.right).offset(4) + } + + textLabel.snp.makeConstraints { make in + make.left.equalTo(vipIconImageView) + make.bottom.equalToSuperview().offset(-18) + } + + button.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.right.equalToSuperview().offset(-12) + make.height.equalTo(48) + make.width.greaterThanOrEqualTo(88) + } + + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + } + +} diff --git a/Fableon/Object/Libs/FAIap/FAPayDataRequest.swift b/Fableon/Object/Libs/FAIap/FAPayDataRequest.swift index e68f8fd..c8d5397 100644 --- a/Fableon/Object/Libs/FAIap/FAPayDataRequest.swift +++ b/Fableon/Object/Libs/FAIap/FAPayDataRequest.swift @@ -83,25 +83,25 @@ class FAPayDataRequest: NSObject { } ///挽留信息 - func requestRetainVipPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) { + func requestVipRetainPayInfo(completer: ((_ model: FAPayAlertModel?) -> Void)?) { self.completerBlock = nil self.payAlertBlock = completer -// FAStoreAPI.requestRetainVipPayInfo { [weak self] model in -// guard let self = self else { return } -// guard let model = model else { -// self.payAlertBlock?(nil) -// return -// } -// self.payAlertModel = model -// -// let productId = BRIAP.manager.getProductId(templateId: model.info?.ios_template_id) ?? "" -// -// let set = Set([productId]) -// let productsRequest = SKProductsRequest(productIdentifiers: set) -// productsRequest.delegate = self -// productsRequest.start() -// } + FAStoreAPI.requestVipRetainPayInfo { [weak self] model in + guard let self = self else { return } + guard let model = model else { + self.payAlertBlock?(nil) + return + } + self.payAlertModel = model + + let productId = FAIapManager.manager.getProductId(templateId: model.info?.ios_template_id) ?? "" + + let set = Set([productId]) + let productsRequest = SKProductsRequest(productIdentifiers: set) + productsRequest.delegate = self + productsRequest.start() + } } } diff --git a/Fableon/Object/Libs/FALogin/FALogin+Apple.swift b/Fableon/Object/Libs/FALogin/FALogin+Apple.swift new file mode 100644 index 0000000..3c508c1 --- /dev/null +++ b/Fableon/Object/Libs/FALogin/FALogin+Apple.swift @@ -0,0 +1,115 @@ +// +// FALogin+Apple.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit +import AuthenticationServices + +extension FALogin { + + private struct AssociatedKeys { + static var appleLoginHandle: Int? + } + + private var appleLoginHandle: ((_ model: FAThirdSignModel?) -> Void)? { + set { + objc_setAssociatedObject(self, &AssociatedKeys.appleLoginHandle, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) + } + get { + return objc_getAssociatedObject(self, &AssociatedKeys.appleLoginHandle) as? ((_ model: FAThirdSignModel?) -> Void) + } + } + + func appleLogin(completer: ((_ model: FAThirdSignModel?) -> Void)?) { + self.appleLoginHandle = completer + + let appleIDProvider = ASAuthorizationAppleIDProvider() + let request = appleIDProvider.createRequest() + request.requestedScopes = [.fullName, .email] + + let authorizationController = ASAuthorizationController(authorizationRequests: [request]) + authorizationController.delegate = self + authorizationController.presentationContextProvider = self + authorizationController.performRequests() + } + + private func jwtDecode(jwtStr: String) -> [String: Any]? { + let segments = jwtStr.components(separatedBy: ".") + guard segments.count > 1 else { return nil } + + var base64String = segments[1] + + // 处理 Base64 补齐 + let requiredLength = 4 * Int(ceil(Double(base64String.count) / 4.0)) + let paddingLength = requiredLength - base64String.count + if paddingLength > 0 { + base64String += String(repeating: "=", count: paddingLength) + } + + // 替换 URL 安全字符 + base64String = base64String.replacingOccurrences(of: "-", with: "+") + base64String = base64String.replacingOccurrences(of: "_", with: "/") + + // 解码 Base64 数据 + guard let data = Data(base64Encoded: base64String), + let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []), + let payload = jsonObject as? [String: Any] else { + return nil + } + + return payload + } + +} + +//MARK: ASAuthorizationControllerDelegate +extension FALogin: ASAuthorizationControllerDelegate { + + func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { + if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential { + + let userIdentifier = appleIDCredential.user + let fullName = appleIDCredential.fullName + let email = appleIDCredential.email + + let identityToken = appleIDCredential.identityToken.flatMap { String(data: $0, encoding: .utf8) } + let identityTokenParams = self.jwtDecode(jwtStr: identityToken ?? "") + + + var model = FAThirdSignModel() + model.platform = .apple + model.third_id = userIdentifier + model.giving_name = fullName?.givenName + model.family_name = fullName?.familyName + model.avator = identityTokenParams?["picture"] as? String + model.email = identityTokenParams?["email"] as? String + + + debugLog(userIdentifier) + debugLog(fullName) + debugLog(email) + + appleLoginHandle?(model) + appleLoginHandle = nil + } + } + + func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { + appleLoginHandle?(nil) + appleLoginHandle = nil + } + +} + +//MARK: ASAuthorizationControllerPresentationContextProviding +extension FALogin: ASAuthorizationControllerPresentationContextProviding { + + func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { + return FATool.keyWindow! + } + +} + diff --git a/Fableon/Object/Libs/FALogin/FALogin+Facebook.swift b/Fableon/Object/Libs/FALogin/FALogin+Facebook.swift new file mode 100644 index 0000000..ac8fb9a --- /dev/null +++ b/Fableon/Object/Libs/FALogin/FALogin+Facebook.swift @@ -0,0 +1,58 @@ +// +// FALogin+Facebook.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// +import UIKit +import FacebookLogin + +extension FALogin { + + func facebookLogin(presentingViewController: UIViewController?, completer: ((_ model: FAThirdSignModel?) -> Void)?) { + + let loginManager = LoginManager() + loginManager.logOut() + loginManager.defaultAudience = .everyone + + loginManager.logIn(permissions: ["public_profile", "email"], from: presentingViewController) { result, error in + guard error == nil, let result = result else { + completer?(nil) + return + } + if result.isCancelled { + completer?(nil) + return + } + let request = GraphRequest(graphPath: "me", parameters: ["fields" : "id,name,email,picture"], httpMethod: .get) + request.start { connection, result, error in + guard let result = result as? [String : Any] else { + completer?(nil) + return + } + var model = FAThirdSignModel() + model.platform = .faceBook + model.third_id = result["id"] as? String + model.email = result["email"] as? String + + if let picture = result["picture"] as? [String : Any], + let data = picture["data"] as? [String : Any], + let url = data["url"] as? String + { + model.avator = url + } + + if let name = result["name"] as? String { + model.family_name = name + } else { + model.family_name = result["first_name"] as? String + model.giving_name = result["last_name"] as? String + } + completer?(model) + } + + + } + } + +} diff --git a/Fableon/Object/Libs/FALogin/FALogin.swift b/Fableon/Object/Libs/FALogin/FALogin.swift index 4c677e2..23036de 100644 --- a/Fableon/Object/Libs/FALogin/FALogin.swift +++ b/Fableon/Object/Libs/FALogin/FALogin.swift @@ -6,16 +6,28 @@ // import UIKit +import SmartCodable let kFAUserTokenDefaultsKey = "kFAUserTokenDefaultsKey" let kFAUserInfoDefaultsKey = "kFAUserInfoDefaultsKey" class FALogin: NSObject { + + enum LoginType: String, SmartCaseDefaultable { + case apple = "Apple" + case faceBook = "Facebook" + case google = "Google" + case tiktok = "Tiktok" + } + static let manager = FALogin() private(set) var token = UserDefaults.fa_object(forKey: kFAUserTokenDefaultsKey, as: FATokenModel.self) private(set) var userInfo = UserDefaults.fa_object(forKey: kFAUserInfoDefaultsKey, as: FAUserInfo.self) + var isLogin: Bool { + return !(userInfo?.is_tourist ?? true) + } private func setToken(_ token: FATokenModel?) { self.token = token @@ -27,6 +39,67 @@ class FALogin: NSObject { UserDefaults.fa_setObject(userInfo, forKey: kFAUserInfoDefaultsKey) } + ///第三方登录 + func thirdLogin(type: LoginType, presentingViewController: UIViewController?, completer: ((_ isFinish: Bool) -> Void)?) { + switch type { + case .apple: + appleLogin { [weak self] model in + self?.requestSignThirdLogin(thirdSignModel: model, completer: completer) + } + + case .faceBook: + facebookLogin(presentingViewController: presentingViewController) { [weak self] model in + self?.requestSignThirdLogin(thirdSignModel: model, completer: completer) + } + + default: + break + } + } + + ///后台验证三方登录 + private func requestSignThirdLogin(thirdSignModel: FAThirdSignModel?, completer: ((_ isFinish: Bool) -> Void)?) { + guard let thirdSignModel = thirdSignModel else { + completer?(false) + return + } + FAStatAPI.requestLeaveApp() + FAAPI.requestSignThirdLogin(model: thirdSignModel) { [weak self] token in + guard let self = self else { return } + guard let token = token else { + completer?(false) + return + } + self.setToken(token) + self.userInfo?.is_tourist = false + self.requestUserInfo(completer: nil) + FAStatAPI.requestEnterApp() + FAStatAPI.requestStatOnLine() + completer?(true) + NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil) + } + } + + func logout(completer: ((_ isFinish: Bool) -> Void)?) { + FAStatAPI.requestLeaveApp() + + FAAPI.requestLogout { [weak self] token in + guard let self = self else { return } + if let token = token { + self.setToken(token) + self.userInfo?.is_tourist = true + self.requestUserInfo(completer: nil) + FAStatAPI.requestEnterApp() + FAStatAPI.requestStatOnLine() + completer?(true) + NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil) + } else { + completer?(false) + } + } + + } + } extension FALogin { diff --git a/Fableon/Object/Libs/FALogin/FAThirdSignModel.swift b/Fableon/Object/Libs/FALogin/FAThirdSignModel.swift new file mode 100644 index 0000000..47cacbb --- /dev/null +++ b/Fableon/Object/Libs/FALogin/FAThirdSignModel.swift @@ -0,0 +1,23 @@ +// +// FAThirdSignModel.swift +// Fableon +// +// Created by 湖北秦九 on 2025/10/30. +// + +import UIKit +import SmartCodable + +struct FAThirdSignModel: SmartCodable { + + var third_id: String? + var email: String? + //姓 + var family_name: String? + //名 + var giving_name: String? + + var avator: String? + + var platform: FALogin.LoginType? +} diff --git a/Fableon/Object/Libs/FATool/FATool.swift b/Fableon/Object/Libs/FATool/FATool.swift index 7496d50..0b2d5aa 100644 --- a/Fableon/Object/Libs/FATool/FATool.swift +++ b/Fableon/Object/Libs/FATool/FATool.swift @@ -6,6 +6,8 @@ // import Foundation import UIKit +import AppTrackingTransparency +import AdSupport #if DEBUG func debugLog(_ msg: Any, file: String = #file, function: String = #function, line: Int = #line) { @@ -18,6 +20,8 @@ func debugLog(_ msg: Any) { } class FATool { + static var sceneDelegate: SceneDelegate? + static var windowScene: UIWindowScene? static var keyWindow: UIWindow? { @@ -52,3 +56,38 @@ class FATool { } } + +extension FATool { + + static func requestIDFAAuthorization(_ completion: ((String?) -> Void)? = nil) { + if FAAdjustStateManager.manager.idfaAuthorizationFinish { + completion?(ASIdentifierManager.shared().advertisingIdentifier.uuidString) + return + } + guard FANetworkMonitor.manager.isReachable == true, FAAdjustStateManager.manager.apnsAuthorizationFinish, FAAdjustStateManager.manager.isOpenApp else { + return + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + ATTrackingManager.requestTrackingAuthorization { status in + FAAdjustStateManager.manager.idfaAuthorizationFinish = true + let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString + FATool.sceneDelegate?.retryHandleOpenAppMessage() + completion?(idfa) + } + } + } + + ///打开消息通知设置页面 + static func openApnsSetting() { + if #available(iOS 16.0, *) { + if let url = URL(string: UIApplication.openNotificationSettingsURLString) { + UIApplication.shared.open(url) + } + } else { + if let url = URL(string: UIApplication.openSettingsURLString) { + UIApplication.shared.open(url) + } + } + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#404040.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#404040.colorset/Contents.json new file mode 100644 index 0000000..eb2314a --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#404040.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x40", + "green" : "0x40", + "red" : "0x40" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#629DFA.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#629DFA.colorset/Contents.json new file mode 100644 index 0000000..d0d75f4 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#629DFA.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFA", + "green" : "0x9D", + "red" : "0x62" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#6D6D6D.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#6D6D6D.colorset/Contents.json new file mode 100644 index 0000000..f0de39c --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#6D6D6D.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x6D", + "green" : "0x6D", + "red" : "0x6D" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#BCBCBC.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#BCBCBC.colorset/Contents.json new file mode 100644 index 0000000..2f339e6 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#BCBCBC.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xBC", + "green" : "0xBC", + "red" : "0xBC" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#DFEFFF.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#DFEFFF.colorset/Contents.json new file mode 100644 index 0000000..521ccbf --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#DFEFFF.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xEF", + "red" : "0xDF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#F6CF87.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#F6CF87.colorset/Contents.json new file mode 100644 index 0000000..4b612bb --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#F6CF87.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x87", + "green" : "0xCF", + "red" : "0xF6" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/color/#FFFEE9.colorset/Contents.json b/Fableon/Source/Assets.xcassets/color/#FFFEE9.colorset/Contents.json new file mode 100644 index 0000000..63257e3 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/color/#FFFEE9.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE9", + "green" : "0xFE", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/Contents.json new file mode 100644 index 0000000..c1a10a0 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "浮窗@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "浮窗@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@2x.png b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@2x.png new file mode 100644 index 0000000..e329e4e Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@3x.png b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@3x.png new file mode 100644 index 0000000..d68a828 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/Group 2072750470.imageset/浮窗@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/Contents.json new file mode 100644 index 0000000..4b19138 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "__magnifying@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "__magnifying@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@2x.png b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@2x.png new file mode 100644 index 0000000..5e22bfe Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@3x.png b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@3x.png new file mode 100644 index 0000000..e79d25c Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/__magnifying.imageset/__magnifying@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/Contents.json new file mode 100644 index 0000000..5a63b3b --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "__to remove 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "__to remove 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@2x.png b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@2x.png new file mode 100644 index 0000000..467050c Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@3x.png b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@3x.png new file mode 100644 index 0000000..91cdefa Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/alert_image_01.imageset/__to remove 1@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Contents.json new file mode 100644 index 0000000..6a4d508 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Vector@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Vector@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@2x.png b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@2x.png new file mode 100644 index 0000000..b40d5e7 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@3x.png b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@3x.png new file mode 100644 index 0000000..0c40c36 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/apple_logo_icon_01.imageset/Vector@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/arrow.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/arrow.imageset/Contents.json new file mode 100644 index 0000000..397060f --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/arrow.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "arrow@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "arrow@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@2x.png b/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@2x.png new file mode 100644 index 0000000..9686ac7 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@3x.png b/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@3x.png new file mode 100644 index 0000000..82a60dd Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/arrow.imageset/arrow@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/Contents.json new file mode 100644 index 0000000..b58aab8 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "关闭按钮@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "关闭按钮@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@2x.png b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@2x.png new file mode 100644 index 0000000..b154cb4 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@3x.png b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@3x.png new file mode 100644 index 0000000..e7bdd62 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/close_icon_03.imageset/关闭按钮@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@2x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@2x.png new file mode 100644 index 0000000..027f842 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@3x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@3x.png new file mode 100644 index 0000000..73bab2e Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/Contents.json new file mode 100644 index 0000000..ab67421 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/coin_attachment_03.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "90ad09d41707261a78f7b0c4f06813390209096846c76-uqCzGu_fw240webp 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Contents.json new file mode 100644 index 0000000..865a6d7 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Ellipse 2325@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Ellipse 2325@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@2x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@2x.png new file mode 100644 index 0000000..49b0521 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@3x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@3x.png new file mode 100644 index 0000000..0c9db7b Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_04.imageset/Ellipse 2325@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Contents.json new file mode 100644 index 0000000..d875170 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Ellipse 2326@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Ellipse 2326@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@2x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@2x.png new file mode 100644 index 0000000..0ae1fa3 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@3x.png b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@3x.png new file mode 100644 index 0000000..da47ceb Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coin_attachment_05.imageset/Ellipse 2326@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/Contents.json new file mode 100644 index 0000000..6974814 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金币@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金币@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@2x.png b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@2x.png new file mode 100644 index 0000000..6ce29dd Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@3x.png b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@3x.png new file mode 100644 index 0000000..bd0ca8d Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coins_icon_09.imageset/金币@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/Contents.json new file mode 100644 index 0000000..6974814 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金币@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金币@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@2x.png b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@2x.png new file mode 100644 index 0000000..8658f43 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@3x.png b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@3x.png new file mode 100644 index 0000000..c9d0709 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/coins_icon_10.imageset/金币@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Contents.json new file mode 100644 index 0000000..5c48415 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Vector@2x 2.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Vector@3x 2.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@2x 2.png b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@2x 2.png new file mode 100644 index 0000000..28337f5 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@2x 2.png differ diff --git a/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@3x 2.png b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@3x 2.png new file mode 100644 index 0000000..fc19fad Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/facebook_logo_icon_01.imageset/Vector@3x 2.png differ diff --git a/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Contents.json new file mode 100644 index 0000000..f62f6ee --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 2414@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 2414@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@2x.png b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@2x.png new file mode 100644 index 0000000..21373c3 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@3x.png b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@3x.png new file mode 100644 index 0000000..e6645f3 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/logo_image_02.imageset/Group 2414@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/按钮.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/按钮.imageset/Contents.json new file mode 100644 index 0000000..379ba42 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/按钮.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "按钮@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "按钮@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@2x.png b/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@2x.png new file mode 100644 index 0000000..487b3f7 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@3x.png b/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@3x.png new file mode 100644 index 0000000..22d42ab Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/按钮.imageset/按钮@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Contents.json new file mode 100644 index 0000000..be2fb8e --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 2072750462@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 2072750462@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@2x.png b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@2x.png new file mode 100644 index 0000000..2b3f1d4 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@3x.png b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@3x.png new file mode 100644 index 0000000..55c80e3 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/查看图片 25.imageset/Group 2072750462@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/Contents.json new file mode 100644 index 0000000..7910c8c --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "横间隔虚线@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "横间隔虚线@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@2x.png b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@2x.png new file mode 100644 index 0000000..bf9affe Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@3x.png b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@3x.png new file mode 100644 index 0000000..eeec04b Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/横间隔虚线.imageset/横间隔虚线@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/Contents.json new file mode 100644 index 0000000..6d973a1 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "皇冠-金@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "皇冠-金@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@2x.png b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@2x.png new file mode 100644 index 0000000..43cca46 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@3x.png b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@3x.png new file mode 100644 index 0000000..7b55f79 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/皇冠-金.imageset/皇冠-金@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/礼物11.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/Contents.json new file mode 100644 index 0000000..0f547bf --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "礼物11@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "礼物11@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@2x.png b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@2x.png new file mode 100644 index 0000000..ea52b07 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@3x.png b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@3x.png new file mode 100644 index 0000000..70b0f4e Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/礼物11.imageset/礼物11@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/签到.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/签到.imageset/Contents.json new file mode 100644 index 0000000..6adfde0 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/签到.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "签到@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "签到@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@2x.png b/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@2x.png new file mode 100644 index 0000000..7f0431b Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@3x.png b/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@3x.png new file mode 100644 index 0000000..0381374 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/签到.imageset/签到@3x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/间隔线.imageset/Contents.json b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/Contents.json new file mode 100644 index 0000000..fa6d306 --- /dev/null +++ b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "间隔线@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "间隔线@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@2x.png b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@2x.png new file mode 100644 index 0000000..733e064 Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@2x.png differ diff --git a/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@3x.png b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@3x.png new file mode 100644 index 0000000..7aa649f Binary files /dev/null and b/Fableon/Source/Assets.xcassets/image/间隔线.imageset/间隔线@3x.png differ diff --git a/Fableon/Source/GoogleService-Info.plist b/Fableon/Source/GoogleService-Info.plist new file mode 100644 index 0000000..cd18c31 --- /dev/null +++ b/Fableon/Source/GoogleService-Info.plist @@ -0,0 +1,30 @@ + + + + + API_KEY + AIzaSyCVj5sGrfhpFgI28c0fOjLJfcNsBcJLMqM + GCM_SENDER_ID + 785133030017 + PLIST_VERSION + 1 + BUNDLE_ID + com.hn.qinjiu.fableon + PROJECT_ID + fableon-514a0 + STORAGE_BUCKET + fableon-514a0.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:785133030017:ios:8d62858420155d00a25b80 + + \ No newline at end of file diff --git a/Fableon/Source/Info.plist b/Fableon/Source/Info.plist index 3a365ad..7db30cc 100755 --- a/Fableon/Source/Info.plist +++ b/Fableon/Source/Info.plist @@ -12,7 +12,23 @@ fableonapp + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + fb1309643747870828 + + + FacebookAppID + 1309643747870828 + FacebookClientToken + 7a0b78de0a5f0e04738e8596b1b50aaa + FacebookDisplayName + $(PRODUCT_NAME) + FirebaseAppDelegateProxyEnabled + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/Fableon/Source/en.lproj/Localizable.strings b/Fableon/Source/en.lproj/Localizable.strings index 8ceed3d..e0ddfe1 100644 --- a/Fableon/Source/en.lproj/Localizable.strings +++ b/Fableon/Source/en.lproj/Localizable.strings @@ -54,6 +54,42 @@ "Purchase Single Episode" = "Purchase Single Episode"; "Price" = "Price"; "Balance" = "Balance"; +"Daily reward ready!" = "Daily reward ready!"; +"Claim your rewards now." = "Claim your rewards now."; +"My Refills" = "My Refills"; +"Weekly Total" = "Weekly Total"; +"Claimable Coins" = "Claimable Coins"; +"Active Refills" = "Active Refills"; +"Get a Refill to Claim" = "Get a Refill to Claim"; +"Claim All" = "Claim All"; +"Total Reward" = "Total Reward"; +"Remaining" = "Remaining"; +"Claim" = "Claim"; +"Log in" = "Log in"; +"Login with Apple" = "Login with Apple"; +"Login with Facebook" = "Login with Facebook"; +"Account Deletion" = "Account Deletion"; +"Cancel" = "Cancel"; +"Remove" = "Remove"; +"Daily Coins" = "Daily Coins"; +"Claim Now" = "Claim Now"; +"Later" = "Later"; +"Buy Now" = "Buy Now"; +"Weekly VIP" = "Weekly VIP"; +"Monthly VIP" = "Monthly VIP"; +"Quarterly VIP" = "Quarterly VIP"; +"Yearly VIP" = "Yearly VIP"; +"Open" = "Open"; + +"remove_collect_alert_title" = "Remove from Favorites?"; +"remove_collect_alert_text" = "This drama will be removed from your favorites."; +"coins_pack_alert_title" = "Daily Reward is waiting!"; +"vip_retain_alert_text" = "Unlock every show you love!"; +"apns_alert_title" = "Enable Notifications"; +"apns_alert_text" = "Stay informed with popular recommendations and latest updates!"; + + +"REWARDS OVERVIEW" = "REWARDS OVERVIEW"; "store_title_1" = "VIP Auto renew,cancel anytime"; @@ -77,3 +113,6 @@ "store_tips_title" = "Tips"; "store_tips" = "1. Coins are virtual items and cannot be refunded. Use it for this product.
2. Both the coins and the reward coins will never expire.
3. Coins will be used first when unlocking episodes. If the amount is insufficient, reward coins will automatically be used.
4. The purchase has not been credited, click torefresh.
5. For other questions, contact us via Profile>Help &feedback."; + +"coins_pack_tips_title" = "Subscription Rules"; +"coins_pack_tips" = "1.Up to 2 subscriptions can be active at once.
2.Coins are delivered instantly upon purchase.
3.Daily bonus coins available from the next day.
4.All coins will be revoked when the subscription expires, including both initial and daily coins.";