diff --git a/ProductApp/ProductApp.xcodeproj/project.pbxproj b/ProductApp/ProductApp.xcodeproj/project.pbxproj index f2d4563..1b48be0 100644 --- a/ProductApp/ProductApp.xcodeproj/project.pbxproj +++ b/ProductApp/ProductApp.xcodeproj/project.pbxproj @@ -67,6 +67,28 @@ CA11ED742CA69AC600209DFC /* GaiXieRunSeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CA11ED732CA69AC600209DFC /* GaiXieRunSeViewController.m */; }; CA11ED782CA69B5200209DFC /* GaiXieRunSeView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA11ED772CA69B5200209DFC /* GaiXieRunSeView.m */; }; CA11ED7D2CA6B0DE00209DFC /* XieZuoFenXiangAlterView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA11ED7C2CA6B0DE00209DFC /* XieZuoFenXiangAlterView.m */; }; + CA3868572CC1F66E009C98B0 /* LoginAppleView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA38684C2CC1F66E009C98B0 /* LoginAppleView.m */; }; + CA3868582CC1F66E009C98B0 /* LoginTelView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA38684E2CC1F66E009C98B0 /* LoginTelView.m */; }; + CA3868592CC1F66E009C98B0 /* LoginView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3868502CC1F66E009C98B0 /* LoginView.m */; }; + CA38685A2CC1F66E009C98B0 /* LoginWXView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3868522CC1F66E009C98B0 /* LoginWXView.m */; }; + CA38685B2CC1F66E009C98B0 /* LoginViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3868552CC1F66E009C98B0 /* LoginViewController.m */; }; + CA38685F2CC1F7B7009C98B0 /* TTTAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CA38685D2CC1F7B7009C98B0 /* TTTAttributedLabel.m */; }; + CA3868632CC1F7C0009C98B0 /* AlipaySDK.bundle in Resources */ = {isa = PBXBuildFile; fileRef = CA3868602CC1F7C0009C98B0 /* AlipaySDK.bundle */; }; + CA3868642CC1F7C0009C98B0 /* AlipaySDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868612CC1F7C0009C98B0 /* AlipaySDK.framework */; }; + CA3868662CC211E3009C98B0 /* pag_loading.pag in Resources */ = {isa = PBXBuildFile; fileRef = CA3868652CC211E3009C98B0 /* pag_loading.pag */; }; + CA3868692CC211FE009C98B0 /* LoadAlterView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA3868682CC211FE009C98B0 /* LoadAlterView.m */; }; + CA38686B2CC23992009C98B0 /* iflyMSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38686A2CC23992009C98B0 /* iflyMSC.framework */; }; + CA38686D2CC239BB009C98B0 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38686C2CC239BB009C98B0 /* AddressBook.framework */; }; + CA38686F2CC239C3009C98B0 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38686E2CC239C3009C98B0 /* AudioToolbox.framework */; }; + CA3868712CC239CB009C98B0 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868702CC239CB009C98B0 /* AVFoundation.framework */; }; + CA3868732CC239D2009C98B0 /* Contacts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868722CC239D2009C98B0 /* Contacts.framework */; }; + CA3868752CC239DA009C98B0 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868742CC239DA009C98B0 /* CoreGraphics.framework */; }; + CA3868772CC239E3009C98B0 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868762CC239E3009C98B0 /* CoreLocation.framework */; }; + CA3868792CC239EA009C98B0 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868782CC239EA009C98B0 /* CoreTelephony.framework */; }; + CA38687B2CC239FA009C98B0 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38687A2CC239FA009C98B0 /* libc++.tbd */; }; + CA38687D2CC239FF009C98B0 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38687C2CC239FF009C98B0 /* libz.tbd */; }; + CA38687F2CC23A06009C98B0 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA38687E2CC23A06009C98B0 /* QuartzCore.framework */; }; + CA3868812CC23A0E009C98B0 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CA3868802CC23A0E009C98B0 /* SystemConfiguration.framework */; }; CA4257852CA24E1100A36A10 /* StartPZXZDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4257842CA24E1100A36A10 /* StartPZXZDetailViewController.m */; }; CA4257892CA24E8C00A36A10 /* StartPZXZDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4257882CA24E8C00A36A10 /* StartPZXZDetailView.m */; }; CA42578D2CA262B300A36A10 /* StartZNPPTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CA42578C2CA262B300A36A10 /* StartZNPPTViewController.m */; }; @@ -578,6 +600,35 @@ CA11ED772CA69B5200209DFC /* GaiXieRunSeView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GaiXieRunSeView.m; sourceTree = ""; }; CA11ED7B2CA6B0DE00209DFC /* XieZuoFenXiangAlterView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XieZuoFenXiangAlterView.h; sourceTree = ""; }; CA11ED7C2CA6B0DE00209DFC /* XieZuoFenXiangAlterView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XieZuoFenXiangAlterView.m; sourceTree = ""; }; + CA38684B2CC1F66E009C98B0 /* LoginAppleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginAppleView.h; sourceTree = ""; }; + CA38684C2CC1F66E009C98B0 /* LoginAppleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginAppleView.m; sourceTree = ""; }; + CA38684D2CC1F66E009C98B0 /* LoginTelView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginTelView.h; sourceTree = ""; }; + CA38684E2CC1F66E009C98B0 /* LoginTelView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginTelView.m; sourceTree = ""; }; + CA38684F2CC1F66E009C98B0 /* LoginView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginView.h; sourceTree = ""; }; + CA3868502CC1F66E009C98B0 /* LoginView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginView.m; sourceTree = ""; }; + CA3868512CC1F66E009C98B0 /* LoginWXView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginWXView.h; sourceTree = ""; }; + CA3868522CC1F66E009C98B0 /* LoginWXView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginWXView.m; sourceTree = ""; }; + CA3868542CC1F66E009C98B0 /* LoginViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginViewController.h; sourceTree = ""; }; + CA3868552CC1F66E009C98B0 /* LoginViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginViewController.m; sourceTree = ""; }; + CA38685C2CC1F7B7009C98B0 /* TTTAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTTAttributedLabel.h; sourceTree = ""; }; + CA38685D2CC1F7B7009C98B0 /* TTTAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTTAttributedLabel.m; sourceTree = ""; }; + CA3868602CC1F7C0009C98B0 /* AlipaySDK.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = AlipaySDK.bundle; sourceTree = ""; }; + CA3868612CC1F7C0009C98B0 /* AlipaySDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AlipaySDK.framework; sourceTree = ""; }; + CA3868652CC211E3009C98B0 /* pag_loading.pag */ = {isa = PBXFileReference; lastKnownFileType = file; path = pag_loading.pag; sourceTree = ""; }; + CA3868672CC211FE009C98B0 /* LoadAlterView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LoadAlterView.h; sourceTree = ""; }; + CA3868682CC211FE009C98B0 /* LoadAlterView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoadAlterView.m; sourceTree = ""; }; + CA38686A2CC23992009C98B0 /* iflyMSC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = iflyMSC.framework; sourceTree = ""; }; + CA38686C2CC239BB009C98B0 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; + CA38686E2CC239C3009C98B0 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; + CA3868702CC239CB009C98B0 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + CA3868722CC239D2009C98B0 /* Contacts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Contacts.framework; path = System/Library/Frameworks/Contacts.framework; sourceTree = SDKROOT; }; + CA3868742CC239DA009C98B0 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + CA3868762CC239E3009C98B0 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + CA3868782CC239EA009C98B0 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + CA38687A2CC239FA009C98B0 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; + CA38687C2CC239FF009C98B0 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + CA38687E2CC23A06009C98B0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + CA3868802CC23A0E009C98B0 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; CA4257832CA24E1100A36A10 /* StartPZXZDetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StartPZXZDetailViewController.h; sourceTree = ""; }; CA4257842CA24E1100A36A10 /* StartPZXZDetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StartPZXZDetailViewController.m; sourceTree = ""; }; CA4257872CA24E8C00A36A10 /* StartPZXZDetailView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StartPZXZDetailView.h; sourceTree = ""; }; @@ -1358,11 +1409,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CA3868812CC23A0E009C98B0 /* SystemConfiguration.framework in Frameworks */, + CA38687F2CC23A06009C98B0 /* QuartzCore.framework in Frameworks */, + CA38687D2CC239FF009C98B0 /* libz.tbd in Frameworks */, + CA38687B2CC239FA009C98B0 /* libc++.tbd in Frameworks */, + CA3868792CC239EA009C98B0 /* CoreTelephony.framework in Frameworks */, + CA3868772CC239E3009C98B0 /* CoreLocation.framework in Frameworks */, + CA3868752CC239DA009C98B0 /* CoreGraphics.framework in Frameworks */, + CA3868732CC239D2009C98B0 /* Contacts.framework in Frameworks */, + CA3868712CC239CB009C98B0 /* AVFoundation.framework in Frameworks */, + CA38686F2CC239C3009C98B0 /* AudioToolbox.framework in Frameworks */, + CA38686D2CC239BB009C98B0 /* AddressBook.framework in Frameworks */, CB489F862744A0BD00DA044A /* libssl.a in Frameworks */, CB489F542744A0BD00DA044A /* libopencore-amrwb.a in Frameworks */, CB489F552744A0BD00DA044A /* libopencore-amrnb.a in Frameworks */, CB489F842744A0BD00DA044A /* libcrypto.a in Frameworks */, 664551746CA42328436EB43A /* Pods_ProductApp.framework in Frameworks */, + CA3868642CC1F7C0009C98B0 /* AlipaySDK.framework in Frameworks */, + CA38686B2CC23992009C98B0 /* iflyMSC.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1762,6 +1826,8 @@ CABD8CB12CBFB6CC009A5E5E /* PauseAlterView.m */, CA5D036D2CC0DFCD007B3BA5 /* GuiZheAlterView.h */, CA5D036E2CC0DFCD007B3BA5 /* GuiZheAlterView.m */, + CA3868672CC211FE009C98B0 /* LoadAlterView.h */, + CA3868682CC211FE009C98B0 /* LoadAlterView.m */, ); path = alter; sourceTree = ""; @@ -1817,6 +1883,49 @@ path = "写作分享"; sourceTree = ""; }; + CA3868532CC1F66E009C98B0 /* view */ = { + isa = PBXGroup; + children = ( + CA38684B2CC1F66E009C98B0 /* LoginAppleView.h */, + CA38684C2CC1F66E009C98B0 /* LoginAppleView.m */, + CA38684D2CC1F66E009C98B0 /* LoginTelView.h */, + CA38684E2CC1F66E009C98B0 /* LoginTelView.m */, + CA38684F2CC1F66E009C98B0 /* LoginView.h */, + CA3868502CC1F66E009C98B0 /* LoginView.m */, + CA3868512CC1F66E009C98B0 /* LoginWXView.h */, + CA3868522CC1F66E009C98B0 /* LoginWXView.m */, + ); + path = view; + sourceTree = ""; + }; + CA3868562CC1F66E009C98B0 /* login */ = { + isa = PBXGroup; + children = ( + CA3868532CC1F66E009C98B0 /* view */, + CA3868542CC1F66E009C98B0 /* LoginViewController.h */, + CA3868552CC1F66E009C98B0 /* LoginViewController.m */, + ); + path = login; + sourceTree = ""; + }; + CA38685E2CC1F7B7009C98B0 /* TTTAttributedLabel */ = { + isa = PBXGroup; + children = ( + CA38685C2CC1F7B7009C98B0 /* TTTAttributedLabel.h */, + CA38685D2CC1F7B7009C98B0 /* TTTAttributedLabel.m */, + ); + path = TTTAttributedLabel; + sourceTree = ""; + }; + CA3868622CC1F7C0009C98B0 /* zfbSdk */ = { + isa = PBXGroup; + children = ( + CA3868602CC1F7C0009C98B0 /* AlipaySDK.bundle */, + CA3868612CC1F7C0009C98B0 /* AlipaySDK.framework */, + ); + path = zfbSdk; + sourceTree = ""; + }; CA4257822CA24DFB00A36A10 /* 文章 */ = { isa = PBXGroup; children = ( @@ -2286,10 +2395,10 @@ children = ( CA5D034C2CC0DE8D007B3BA5 /* cell */, CA5D03532CC0DE8D007B3BA5 /* view */, - CA5D03542CC0DE8D007B3BA5 /* YouHuiQuanListViewController.h */, - CA5D03552CC0DE8D007B3BA5 /* YouHuiQuanListViewController.m */, CA5D03562CC0DE8D007B3BA5 /* YouHuiQuanViewController.h */, CA5D03572CC0DE8D007B3BA5 /* YouHuiQuanViewController.m */, + CA5D03542CC0DE8D007B3BA5 /* YouHuiQuanListViewController.h */, + CA5D03552CC0DE8D007B3BA5 /* YouHuiQuanListViewController.m */, ); path = "优惠券"; sourceTree = ""; @@ -3261,6 +3370,7 @@ CA487D942CA407F100AE773B /* D-DIN-PRO-700-Bold.otf */, CA5D02B52CC0B69E007B3BA5 /* SmileySans-Oblique.ttf */, CA5D036B2CC0DF9B007B3BA5 /* yq_animation.pag */, + CA3868652CC211E3009C98B0 /* pag_loading.pag */, ); path = ProductApp; sourceTree = ""; @@ -3405,6 +3515,9 @@ CB489E1A2744A0BC00DA044A /* BaseControl */ = { isa = PBXGroup; children = ( + CA38686A2CC23992009C98B0 /* iflyMSC.framework */, + CA3868622CC1F7C0009C98B0 /* zfbSdk */, + CA38685E2CC1F7B7009C98B0 /* TTTAttributedLabel */, CBD422B228DAF2E800C32440 /* JhtBannerScrollView */, CB489E3D2744A0BC00DA044A /* TabBar */, CB489E1B2744A0BC00DA044A /* Calendar */, @@ -3980,6 +4093,7 @@ children = ( CABA148A2C9D4302002CB3B1 /* NetWorkManager */, CA11ED692CA6924800209DFC /* alter */, + CA3868562CC1F66E009C98B0 /* login */, CABA146E2C9D0D3C002CB3B1 /* 引导 */, CABA145E2C9D0B0D002CB3B1 /* 我的 */, CABA145D2C9D0B06002CB3B1 /* 工具 */, @@ -4013,6 +4127,17 @@ F2AFD5F388A8B6D60B4992F6 /* Frameworks */ = { isa = PBXGroup; children = ( + CA3868802CC23A0E009C98B0 /* SystemConfiguration.framework */, + CA38687E2CC23A06009C98B0 /* QuartzCore.framework */, + CA38687C2CC239FF009C98B0 /* libz.tbd */, + CA38687A2CC239FA009C98B0 /* libc++.tbd */, + CA3868782CC239EA009C98B0 /* CoreTelephony.framework */, + CA3868762CC239E3009C98B0 /* CoreLocation.framework */, + CA3868742CC239DA009C98B0 /* CoreGraphics.framework */, + CA3868722CC239D2009C98B0 /* Contacts.framework */, + CA3868702CC239CB009C98B0 /* AVFoundation.framework */, + CA38686E2CC239C3009C98B0 /* AudioToolbox.framework */, + CA38686C2CC239BB009C98B0 /* AddressBook.framework */, E7E9D1598912BF8D031CA536 /* Pods_ProductApp.framework */, CBD8C286299641ED00A2E09B /* ReplayKit.framework */, CBD8C293299641ED00A2E09B /* UIKit.framework */, @@ -4087,6 +4212,7 @@ CA5D02B62CC0B69E007B3BA5 /* SmileySans-Oblique.ttf in Resources */, CA5D031B2CC0DDF0007B3BA5 /* Pay_Public_QianWang@2x.png in Resources */, CA5D03192CC0DDF0007B3BA5 /* Pay_Public_go@3x.png in Resources */, + CA3868632CC1F7C0009C98B0 /* AlipaySDK.bundle in Resources */, CB489F9E2744A0BD00DA044A /* LogTableViewCell.xib in Resources */, CABA14742C9D1165002CB3B1 /* qidong@3x.png in Resources */, CA5D03172CC0DDF0007B3BA5 /* Pay_Public_支付宝.png in Resources */, @@ -4123,6 +4249,7 @@ CA5D031E2CC0DDF0007B3BA5 /* Pay_Public_SelectN@3x.png in Resources */, CB489F872744A0BD00DA044A /* rsa_private_key.txt in Resources */, CABA14D62C9D5059002CB3B1 /* pageconN.png in Resources */, + CA3868662CC211E3009C98B0 /* pag_loading.pag in Resources */, CB489F7E2744A0BD00DA044A /* encry.txt in Resources */, CB489FB92744A0BD00DA044A /* loading@2x.png in Resources */, CB489F852744A0BD00DA044A /* LICENSE in Resources */, @@ -4241,6 +4368,7 @@ CBD422B128DAEDFC00C32440 /* UIImageView+PWebCache.m in Sources */, CABA14852C9D2710002CB3B1 /* StartGNViewController.m in Sources */, CA11ED5A2CA648AB00209DFC /* CamreTypeView.m in Sources */, + CA38685B2CC1F66E009C98B0 /* LoginViewController.m in Sources */, CA0D083A2CA509D20086855E /* ShouYeToolsCollectionViewCell.m in Sources */, CB489FB32744A0BD00DA044A /* THDatePickerView.m in Sources */, CB489FB62744A0BD00DA044A /* NSDate+CXCategory.m in Sources */, @@ -4273,6 +4401,7 @@ CB489FA72744A0BD00DA044A /* ZJScrollPageView.m in Sources */, CA5D03292CC0DDF0007B3BA5 /* PayPublicYouHuiLogVuew.m in Sources */, CA5D02ED2CC0DD6B007B3BA5 /* PayOrderModel.m in Sources */, + CA3868582CC1F66E009C98B0 /* LoginTelView.m in Sources */, CA5D03632CC0DE8D007B3BA5 /* YaoQingView.m in Sources */, CA4257A62CA29FE700A36A10 /* StartZNPPTDaGangAlterLoadView.m in Sources */, CA0C3A992CB4D4F500E01A72 /* ZhiNengXieZuoDuanLuoView.m in Sources */, @@ -4312,6 +4441,7 @@ CB489FB22744A0BD00DA044A /* FSActionSheetItem.m in Sources */, CA0C3AA52CB4DED200E01A72 /* DuanLuoXieZuoCellView.m in Sources */, CA4257AE2CA2AF3600A36A10 /* StartZNPPTYuLanTableViewCell.m in Sources */, + CA38685A2CC1F66E009C98B0 /* LoginWXView.m in Sources */, CA0D08362CA501710086855E /* ShouYeToolsTableViewCell.m in Sources */, CA6B97372CBD2102000213F3 /* AIChaAnswerTableViewCell.m in Sources */, CB489F4B2744A0BD00DA044A /* PGGDatePickView.m in Sources */, @@ -4402,6 +4532,7 @@ CA8181B62C9ECB5800EE7E6E /* StartKTXZPGDetailFJItemView.m in Sources */, CA0D08752CA555DE0086855E /* ShouYeLiShiJiLuPGTableViewCell.m in Sources */, CA5D036F2CC0DFCD007B3BA5 /* GuiZheAlterView.m in Sources */, + CA38685F2CC1F7B7009C98B0 /* TTTAttributedLabel.m in Sources */, CA8181A72C9EAB8700EE7E6E /* PGJUILabel.m in Sources */, CA81818E2C9E60B100EE7E6E /* ViewLable.m in Sources */, CB489FB42744A0BD00DA044A /* CXDatePickerView.m in Sources */, @@ -4432,11 +4563,13 @@ CB489F792744A0BD00DA044A /* UIApplication+Visible.m in Sources */, CB489FD72744A30000DA044A /* PGGMoviePlayer.m in Sources */, CA5D03692CC0DE8D007B3BA5 /* YouHuiQuanListViewController.m in Sources */, + CA3868592CC1F66E009C98B0 /* LoginView.m in Sources */, CB489F982744A0BD00DA044A /* BaseModel.m in Sources */, CA4257B92CA2C42E00A36A10 /* StartPayTQView.m in Sources */, CAA600D52CA9579800026CF4 /* KeTangXieZuoCollectionViewCell.m in Sources */, CB489F9B2744A0BD00DA044A /* YSAPIClient.m in Sources */, CB489F822744A0BD00DA044A /* NSData+Base64.m in Sources */, + CA3868692CC211FE009C98B0 /* LoadAlterView.m in Sources */, CB489FA62744A0BD00DA044A /* ZJScrollSegmentView.m in Sources */, CA5D035D2CC0DE8D007B3BA5 /* TiXianViewController.m in Sources */, CA0D08332CA4FFB90086855E /* ShouYeBannerTableViewCell.m in Sources */, @@ -4446,6 +4579,7 @@ CAF76E7F2CBE588900825E5E /* GongJuSearchListViewController.m in Sources */, CA5D032A2CC0DDF0007B3BA5 /* PayPublicYouHuiView.m in Sources */, CB489F812744A0BD00DA044A /* GTMBase64.m in Sources */, + CA3868572CC1F66E009C98B0 /* LoginAppleView.m in Sources */, CAC806642CA151ED00C21AA7 /* StartZNXZSiLuViewController.m in Sources */, CB489F962744A0BD00DA044A /* SmsloginCodeModel.m in Sources */, CA0D08612CA547C60086855E /* ShouYeLiShiJiLuViewController.m in Sources */, @@ -4728,6 +4862,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = D5PBFE23SF; ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/ProductApp/BaseControl/zfbSdk", + "$(PROJECT_DIR)/ProductApp/BaseControl", + ); GCC_PREFIX_HEADER = "$(SRCROOT)/ProductApp/PrefixHeader.pch"; GENERATE_INFOPLIST_FILE = YES; HEADER_SEARCH_PATHS = ( @@ -4752,6 +4891,10 @@ INFOPLIST_FILE = ProductApp/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "极光写作"; INFOPLIST_KEY_NSCameraUsageDescription = "极光写作意见反馈上传图片需要使用相机"; + INFOPLIST_KEY_NSContactsUsageDescription = "极光写作AI助手聊天需要使用通讯录"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "极光写作AI助手聊天需要使用位置信息"; + INFOPLIST_KEY_NSLocationUsageDescription = "极光写作AI助手聊天需要使用位置信息"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "极光写作AI助手聊天需要使用麦克风"; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "极光写作意见反馈上传图片需要使用相册"; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "极光写作分享保存图片需要保存图片到相册"; INFOPLIST_KEY_NSUserTrackingUsageDescription = "极光写作用于向您推荐个性化广告"; @@ -4789,6 +4932,11 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = D5PBFE23SF; ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/ProductApp/BaseControl/zfbSdk", + "$(PROJECT_DIR)/ProductApp/BaseControl", + ); GCC_PREFIX_HEADER = "$(SRCROOT)/ProductApp/PrefixHeader.pch"; GENERATE_INFOPLIST_FILE = YES; HEADER_SEARCH_PATHS = ( @@ -4813,6 +4961,10 @@ INFOPLIST_FILE = ProductApp/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "极光写作"; INFOPLIST_KEY_NSCameraUsageDescription = "极光写作意见反馈上传图片需要使用相机"; + INFOPLIST_KEY_NSContactsUsageDescription = "极光写作AI助手聊天需要使用通讯录"; + INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "极光写作AI助手聊天需要使用位置信息"; + INFOPLIST_KEY_NSLocationUsageDescription = "极光写作AI助手聊天需要使用位置信息"; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "极光写作AI助手聊天需要使用麦克风"; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "极光写作意见反馈上传图片需要使用相册"; INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "极光写作分享保存图片需要保存图片到相册"; INFOPLIST_KEY_NSUserTrackingUsageDescription = "极光写作用于向您推荐个性化广告"; diff --git a/ProductApp/ProductApp.xcworkspace/xcuserdata/gongzuo.xcuserdatad/UserInterfaceState.xcuserstate b/ProductApp/ProductApp.xcworkspace/xcuserdata/gongzuo.xcuserdatad/UserInterfaceState.xcuserstate index 1125e2c..de9db91 100644 Binary files a/ProductApp/ProductApp.xcworkspace/xcuserdata/gongzuo.xcuserdatad/UserInterfaceState.xcuserstate and b/ProductApp/ProductApp.xcworkspace/xcuserdata/gongzuo.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ProductApp/ProductApp/AppDelegate.m b/ProductApp/ProductApp/AppDelegate.m index 23eb337..c66d304 100644 --- a/ProductApp/ProductApp/AppDelegate.m +++ b/ProductApp/ProductApp/AppDelegate.m @@ -12,6 +12,12 @@ #import "TabBarController.h" +#import +#import +#import + +#import "IFlyMSC/IFlyMSC.h" + @interface AppDelegate () @end @@ -39,6 +45,18 @@ [self.window makeKeyAndVisible]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self getTuiSheZhi:launchOptions]; + }); + + + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *cachePath = [paths objectAtIndex:0]; + [IFlySetting setLogFilePath:cachePath]; + NSString *initString = [[NSString alloc] initWithFormat:@"appid=%@",XunFeiAppId]; + [IFlySpeechUtility createUtility:initString]; + + ///禁止黑暗模式 #if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 if(@available(iOS 13.0,*)){ @@ -58,4 +76,33 @@ self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight; } +-(void)getTuiSheZhi:(NSDictionary *)launchOptions +{ + dispatch_async(dispatch_get_main_queue(), ^{ + //超时设置,建议为8s以上,至少5s以上; + [GeYanSdk setPreLoginTimeout:10]; //预登录超时时长 + [GeYanSdk setEloginTimeout:10]; //登录超时时长 + // NSLog(@"pgj = %@",[GeYanSdk getVersion]); + //初始化 + [GeYanSdk startWithAppId:kGtAppId + withCallback:^(BOOL isSuccess, NSError *error, NSString *gtcid) { + NSLog(@"GeYanSdk startWithAppId gtcid:%@", gtcid); + }]; + + //提前进行预登录,以便节省后续用户的等待时间; + [GeYanSdk preGetToken:^(NSDictionary *preDic) { + NSLog(@"preGetToken:%@", preDic); + }]; + +// //推送 +// // 通过个推平台分配的appId、 appKey 、appSecret 启动SDK,注:该方法需要在主线程中调用 +// [GeTuiSdk startSdkWithAppId:kGtAppId appKey:kGtAppKey appSecret:kGtAppSecret delegate:self launchingOptions:launchOptions]; +// +// // 注册远程通知 +// [GeTuiSdk registerRemoteNotification: (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge)]; +// + }); +} + + @end diff --git a/ProductApp/ProductApp/Assets.xcassets/login/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/Contents.json new file mode 100644 index 0000000..472990c --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "切图 5@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "切图 5@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@2x.png new file mode 100644 index 0000000..2c65164 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@3x.png new file mode 100644 index 0000000..29981c4 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_N.imageset/切图 5@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/Contents.json new file mode 100644 index 0000000..05a0863 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "切图 4@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "切图 4@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@2x.png new file mode 100644 index 0000000..7c555ba Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@3x.png new file mode 100644 index 0000000..57d8d6b Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_Select_Y.imageset/切图 4@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/Contents.json new file mode 100644 index 0000000..1e403a6 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "容器@2x(3).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "容器@3x(3).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@2x(3).png b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@2x(3).png new file mode 100644 index 0000000..470caab Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@2x(3).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@3x(3).png b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@3x(3).png new file mode 100644 index 0000000..c31fc52 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_X.imageset/容器@3x(3).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/Contents.json new file mode 100644 index 0000000..b30c2a7 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "组 42544@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "组 42544@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@2x.png new file mode 100644 index 0000000..e17ffb2 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@3x.png new file mode 100644 index 0000000..5624ba0 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_apple.imageset/组 42544@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/Contents.json new file mode 100644 index 0000000..7b6f827 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "apple.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "apple (1).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple (1).png b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple (1).png new file mode 100644 index 0000000..eb1cd6a Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple (1).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple.png b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple.png new file mode 100644 index 0000000..a7cc6e2 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_apple_bai.imageset/apple.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/Contents.json new file mode 100644 index 0000000..7e9cb1a --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "image@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "image@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@2x.png new file mode 100644 index 0000000..bb683f8 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@3x.png new file mode 100644 index 0000000..b528b4f Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_back.imageset/image@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/Contents.json new file mode 100644 index 0000000..71810bb --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "logo@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "logo@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@2x.png new file mode 100644 index 0000000..9ac6ca8 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@3x.png new file mode 100644 index 0000000..90c7082 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_logo.imageset/logo@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/Contents.json new file mode 100644 index 0000000..2741c09 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "容器@2x(4).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "容器@3x(4).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@2x(4).png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@2x(4).png new file mode 100644 index 0000000..020d217 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@2x(4).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@3x(4).png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@3x(4).png new file mode 100644 index 0000000..d2f7002 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone.imageset/容器@3x(4).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/Contents.json new file mode 100644 index 0000000..7b6156b --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.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/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@2x.png new file mode 100644 index 0000000..eac0e58 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@3x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@3x.png new file mode 100644 index 0000000..778cb96 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_手机号.imageset/容器@3x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/Contents.json new file mode 100644 index 0000000..8925e57 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "容器@2x(1).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "容器@3x(1).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@2x(1).png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@2x(1).png new file mode 100644 index 0000000..7710239 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@2x(1).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@3x(1).png b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@3x(1).png new file mode 100644 index 0000000..9b2aca3 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_phone_验证码.imageset/容器@3x(1).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/Contents.json new file mode 100644 index 0000000..d6d7abe --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "容器@2x(2).png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "容器@3x(2).png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@2x(2).png b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@2x(2).png new file mode 100644 index 0000000..c6886e3 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@2x(2).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@3x(2).png b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@3x(2).png new file mode 100644 index 0000000..1eb5d83 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_wx.imageset/容器@3x(2).png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/Contents.json new file mode 100644 index 0000000..22df679 --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "容器@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/容器@2x.png b/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/容器@2x.png new file mode 100644 index 0000000..27f71a4 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/login/login_wx_bai.imageset/容器@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/Contents.json b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/Contents.json new file mode 100644 index 0000000..98233da --- /dev/null +++ b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "组 43021@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "组 43021@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@2x.png b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@2x.png new file mode 100644 index 0000000..c1efb3a Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@2x.png differ diff --git a/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@3x.png b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@3x.png new file mode 100644 index 0000000..5018075 Binary files /dev/null and b/ProductApp/ProductApp/Assets.xcassets/聊天/ai_yuyin_bai.imageset/组 43021@3x.png differ diff --git a/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.h b/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.h new file mode 100644 index 0000000..e467979 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.h @@ -0,0 +1,681 @@ +// TTTAttributedLabel.h +// +// Copyright (c) 2011 Mattt Thompson (http://mattt.me) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +//! Project version number for TTTAttributedLabel. +FOUNDATION_EXPORT double TTTAttributedLabelVersionNumber; + +//! Project version string for TTTAttributedLabel. +FOUNDATION_EXPORT const unsigned char TTTAttributedLabelVersionString[]; + +@class TTTAttributedLabelLink; + +/** + Vertical alignment for text in a label whose bounds are larger than its text bounds + */ +typedef NS_ENUM(NSInteger, TTTAttributedLabelVerticalAlignment) { + TTTAttributedLabelVerticalAlignmentCenter = 0, + TTTAttributedLabelVerticalAlignmentTop = 1, + TTTAttributedLabelVerticalAlignmentBottom = 2, +}; + +/** + Determines whether the text to which this attribute applies has a strikeout drawn through itself. + */ +extern NSString * const kTTTStrikeOutAttributeName; + +/** + The background fill color. Value must be a `CGColorRef`. Default value is `nil` (no fill). + */ +extern NSString * const kTTTBackgroundFillColorAttributeName; + +/** + The padding for the background fill. Value must be a `UIEdgeInsets`. Default value is `UIEdgeInsetsZero` (no padding). + */ +extern NSString * const kTTTBackgroundFillPaddingAttributeName; + +/** + The background stroke color. Value must be a `CGColorRef`. Default value is `nil` (no stroke). + */ +extern NSString * const kTTTBackgroundStrokeColorAttributeName; + +/** + The background stroke line width. Value must be an `NSNumber`. Default value is `1.0f`. + */ +extern NSString * const kTTTBackgroundLineWidthAttributeName; + +/** + The background corner radius. Value must be an `NSNumber`. Default value is `5.0f`. + */ +extern NSString * const kTTTBackgroundCornerRadiusAttributeName; + +@protocol TTTAttributedLabelDelegate; + +// Override UILabel @property to accept both NSString and NSAttributedString +@protocol TTTAttributedLabel +@property (nonatomic, copy) IBInspectable id text; +@end + +IB_DESIGNABLE + +/** + `TTTAttributedLabel` is a drop-in replacement for `UILabel` that supports `NSAttributedString`, as well as automatically-detected and manually-added links to URLs, addresses, phone numbers, and dates. + + ## Differences Between `TTTAttributedLabel` and `UILabel` + + For the most part, `TTTAttributedLabel` behaves just like `UILabel`. The following are notable exceptions, in which `TTTAttributedLabel` may act differently: + + - `text` - This property now takes an `id` type argument, which can either be a kind of `NSString` or `NSAttributedString` (mutable or immutable in both cases) + - `attributedText` - Do not set this property directly. Instead, pass an `NSAttributedString` to `text`. + - `lineBreakMode` - This property displays only the first line when the value is `UILineBreakModeHeadTruncation`, `UILineBreakModeTailTruncation`, or `UILineBreakModeMiddleTruncation` + - `adjustsFontsizeToFitWidth` - Supported in iOS 5 and greater, this property is effective for any value of `numberOfLines` greater than zero. In iOS 4, setting `numberOfLines` to a value greater than 1 with `adjustsFontSizeToFitWidth` set to `YES` may cause `sizeToFit` to execute indefinitely. + - `baselineAdjustment` - This property has no affect. + - `textAlignment` - This property does not support justified alignment. + - `NSTextAttachment` - This string attribute is not supported. + + Any properties affecting text or paragraph styling, such as `firstLineIndent` will only apply when text is set with an `NSString`. If the text is set with an `NSAttributedString`, these properties will not apply. + + ### NSCoding + + `TTTAttributedLabel`, like `UILabel`, conforms to `NSCoding`. However, if the build target is set to less than iOS 6.0, `linkAttributes` and `activeLinkAttributes` will not be encoded or decoded. This is due to an runtime exception thrown when attempting to copy non-object CoreText values in dictionaries. + + @warning Any properties changed on the label after setting the text will not be reflected until a subsequent call to `setText:` or `setText:afterInheritingLabelAttributesAndConfiguringWithBlock:`. This is to say, order of operations matters in this case. For example, if the label text color is originally black when the text is set, changing the text color to red will have no effect on the display of the label until the text is set once again. + + @bug Setting `attributedText` directly is not recommended, as it may cause a crash when attempting to access any links previously set. Instead, call `setText:`, passing an `NSAttributedString`. + */ +@interface TTTAttributedLabel : UILabel + +/** + * The designated initializers are @c initWithFrame: and @c initWithCoder:. + * init will not properly initialize many required properties and other configuration. + */ +- (instancetype) init NS_UNAVAILABLE; + +///----------------------------- +/// @name Accessing the Delegate +///----------------------------- + +/** + The receiver's delegate. + + @discussion A `TTTAttributedLabel` delegate responds to messages sent by tapping on links in the label. You can use the delegate to respond to links referencing a URL, address, phone number, date, or date with a specified time zone and duration. + */ +@property (nonatomic, unsafe_unretained) IBOutlet id delegate; + +///-------------------------------------------- +/// @name Detecting, Accessing, & Styling Links +///-------------------------------------------- + +/** + A bitmask of `NSTextCheckingType` which are used to automatically detect links in the label text. + + @warning You must specify `enabledTextCheckingTypes` before setting the `text`, with either `setText:` or `setText:afterInheritingLabelAttributesAndConfiguringWithBlock:`. + */ +@property (nonatomic, assign) NSTextCheckingTypes enabledTextCheckingTypes; + +/** + An array of `NSTextCheckingResult` objects for links detected or manually added to the label text. + */ +@property (readonly, nonatomic, strong) NSArray *links; + +/** + A dictionary containing the default `NSAttributedString` attributes to be applied to links detected or manually added to the label text. The default link style is blue and underlined. + + @warning You must specify `linkAttributes` before setting autodecting or manually-adding links for these attributes to be applied. + */ +@property (nonatomic, strong) NSDictionary *linkAttributes; + +/** + A dictionary containing the default `NSAttributedString` attributes to be applied to links when they are in the active state. If `nil` or an empty `NSDictionary`, active links will not be styled. The default active link style is red and underlined. + */ +@property (nonatomic, strong) NSDictionary *activeLinkAttributes; + +/** + A dictionary containing the default `NSAttributedString` attributes to be applied to links when they are in the inactive state, which is triggered by a change in `tintColor` in iOS 7 and later. If `nil` or an empty `NSDictionary`, inactive links will not be styled. The default inactive link style is gray and unadorned. + */ +@property (nonatomic, strong) NSDictionary *inactiveLinkAttributes; + +/** + The edge inset for the background of a link. The default value is `{0, -1, 0, -1}`. + */ +@property (nonatomic, assign) UIEdgeInsets linkBackgroundEdgeInset; + +/** + Indicates if links will be detected within an extended area around the touch + to emulate the link detection behaviour of WKWebView. + Default value is NO. Enabling this may adversely impact performance. + */ +@property (nonatomic, assign) BOOL extendsLinkTouchArea; + +///--------------------------------------- +/// @name Acccessing Text Style Attributes +///--------------------------------------- + +/** + The shadow blur radius for the label. A value of 0 indicates no blur, while larger values produce correspondingly larger blurring. This value must not be negative. The default value is 0. + */ +@property (nonatomic, assign) IBInspectable CGFloat shadowRadius; + +/** + The shadow blur radius for the label when the label's `highlighted` property is `YES`. A value of 0 indicates no blur, while larger values produce correspondingly larger blurring. This value must not be negative. The default value is 0. + */ +@property (nonatomic, assign) IBInspectable CGFloat highlightedShadowRadius; +/** + The shadow offset for the label when the label's `highlighted` property is `YES`. A size of {0, 0} indicates no offset, with positive values extending down and to the right. The default size is {0, 0}. + */ +@property (nonatomic, assign) IBInspectable CGSize highlightedShadowOffset; +/** + The shadow color for the label when the label's `highlighted` property is `YES`. The default value is `nil` (no shadow color). + */ +@property (nonatomic, strong) IBInspectable UIColor *highlightedShadowColor; + +/** + The amount to kern the next character. Default is standard kerning. If this attribute is set to 0.0, no kerning is done at all. + */ +@property (nonatomic, assign) IBInspectable CGFloat kern; + +///-------------------------------------------- +/// @name Acccessing Paragraph Style Attributes +///-------------------------------------------- + +/** + The distance, in points, from the leading margin of a frame to the beginning of the + paragraph's first line. This value is always nonnegative, and is 0.0 by default. + This applies to the full text, rather than any specific paragraph metrics. + */ +@property (nonatomic, assign) IBInspectable CGFloat firstLineIndent; + +/** + The space in points added between lines within the paragraph. This value is always nonnegative and is 0.0 by default. + */ +@property (nonatomic, assign) IBInspectable CGFloat lineSpacing; + +/** + The minimum line height within the paragraph. If the value is 0.0, the minimum line height is set to the line height of the `font`. 0.0 by default. + */ +@property (nonatomic, assign) IBInspectable CGFloat minimumLineHeight; + +/** + The maximum line height within the paragraph. If the value is 0.0, the maximum line height is set to the line height of the `font`. 0.0 by default. + */ +@property (nonatomic, assign) IBInspectable CGFloat maximumLineHeight; + +/** + The line height multiple. This value is 1.0 by default. + */ +@property (nonatomic, assign) IBInspectable CGFloat lineHeightMultiple; + +/** + The distance, in points, from the margin to the text container. This value is `UIEdgeInsetsZero` by default. + sizeThatFits: will have its returned size increased by these margins. + drawTextInRect: will inset all drawn text by these margins. + */ +@property (nonatomic, assign) IBInspectable UIEdgeInsets textInsets; + +/** + The vertical text alignment for the label, for when the frame size is greater than the text rect size. The vertical alignment is `TTTAttributedLabelVerticalAlignmentCenter` by default. + */ +@property (nonatomic, assign) TTTAttributedLabelVerticalAlignment verticalAlignment; + +///-------------------------------------------- +/// @name Accessing Truncation Token Appearance +///-------------------------------------------- + +/** + The attributed string to apply to the truncation token at the end of a truncated line. + */ +@property (nonatomic, strong) IBInspectable NSAttributedString *attributedTruncationToken; + +///-------------------------- +/// @name Long press gestures +///-------------------------- + +/** + * The long-press gesture recognizer used internally by the label. + */ +@property (nonatomic, strong, readonly) UILongPressGestureRecognizer *longPressGestureRecognizer; + +///-------------------------------------------- +/// @name Calculating Size of Attributed String +///-------------------------------------------- + +/** + Calculate and return the size that best fits an attributed string, given the specified constraints on size and number of lines. + + @param attributedString The attributed string. + @param size The maximum dimensions used to calculate size. + @param numberOfLines The maximum number of lines in the text to draw, if the constraining size cannot accomodate the full attributed string. + + @return The size that fits the attributed string within the specified constraints. + */ ++ (CGSize)sizeThatFitsAttributedString:(NSAttributedString *)attributedString + withConstraints:(CGSize)size + limitedToNumberOfLines:(NSUInteger)numberOfLines; + +///---------------------------------- +/// @name Setting the Text Attributes +///---------------------------------- + +/** + Sets the text displayed by the label. + + @param text An `NSString` or `NSAttributedString` object to be displayed by the label. If the specified text is an `NSString`, the label will display the text like a `UILabel`, inheriting the text styles of the label. If the specified text is an `NSAttributedString`, the label text styles will be overridden by the styles specified in the attributed string. + + @discussion This method overrides `UILabel -setText:` to accept both `NSString` and `NSAttributedString` objects. This string is `nil` by default. + */ +- (void)setText:(id)text; + +/** + Sets the text displayed by the label, after configuring an attributed string containing the text attributes inherited from the label in a block. + + @param text An `NSString` or `NSAttributedString` object to be displayed by the label. + @param block A block object that returns an `NSMutableAttributedString` object and takes a single argument, which is an `NSMutableAttributedString` object with the text from the first parameter, and the text attributes inherited from the label text styles. For example, if you specified the `font` of the label to be `[UIFont boldSystemFontOfSize:14]` and `textColor` to be `[UIColor redColor]`, the `NSAttributedString` argument of the block would be contain the `NSAttributedString` attribute equivalents of those properties. In this block, you can set further attributes on particular ranges. + + @discussion This string is `nil` by default. + */ +- (void)setText:(id)text +afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString *(^)(NSMutableAttributedString *mutableAttributedString))block; + +///------------------------------------ +/// @name Accessing the Text Attributes +///------------------------------------ + +/** + A copy of the label's current attributedText. This returns `nil` if an attributed string has never been set on the label. + + @warning Do not set this property directly. Instead, set @c text to an @c NSAttributedString. + */ +@property (readwrite, nonatomic, copy) NSAttributedString *attributedText; + +///------------------- +/// @name Adding Links +///------------------- + +/** + Adds a link. You can customize an individual link's appearance and accessibility value by creating your own @c TTTAttributedLabelLink and passing it to this method. The other methods for adding links will use the label's default attributes. + + @warning Modifying the link's attribute dictionaries must be done before calling this method. + + @param link A @c TTTAttributedLabelLink object. + */ +- (void)addLink:(TTTAttributedLabelLink *)link; + +/** + Adds a link to an @c NSTextCheckingResult. + + @param result An @c NSTextCheckingResult representing the link's location and type. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result; + +/** + Adds a link to an @c NSTextCheckingResult. + + @param result An @c NSTextCheckingResult representing the link's location and type. + @param attributes The attributes to be added to the text in the range of the specified link. If set, the label's @c activeAttributes and @c inactiveAttributes will be applied to the link. If `nil`, no attributes are added to the link. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result + attributes:(NSDictionary *)attributes; + +/** + Adds a link to a URL for a specified range in the label text. + + @param url The url to be linked to + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToURL:(NSURL *)url + withRange:(NSRange)range; + +/** + Adds a link to an address for a specified range in the label text. + + @param addressComponents A dictionary of address components for the address to be linked to + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @discussion The address component dictionary keys are described in `NSTextCheckingResult`'s "Keys for Address Components." + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToAddress:(NSDictionary *)addressComponents + withRange:(NSRange)range; + +/** + Adds a link to a phone number for a specified range in the label text. + + @param phoneNumber The phone number to be linked to. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToPhoneNumber:(NSString *)phoneNumber + withRange:(NSRange)range; + +/** + Adds a link to a date for a specified range in the label text. + + @param date The date to be linked to. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToDate:(NSDate *)date + withRange:(NSRange)range; + +/** + Adds a link to a date with a particular time zone and duration for a specified range in the label text. + + @param date The date to be linked to. + @param timeZone The time zone of the specified date. + @param duration The duration, in seconds from the specified date. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToDate:(NSDate *)date + timeZone:(NSTimeZone *)timeZone + duration:(NSTimeInterval)duration + withRange:(NSRange)range; + +/** + Adds a link to transit information for a specified range in the label text. + + @param components A dictionary containing the transit components. The currently supported keys are `NSTextCheckingAirlineKey` and `NSTextCheckingFlightKey`. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @return The newly added link object. + */ +- (TTTAttributedLabelLink *)addLinkToTransitInformation:(NSDictionary *)components + withRange:(NSRange)range; + +/** + Returns whether an @c NSTextCheckingResult is found at the give point. + + @discussion This can be used together with @c UITapGestureRecognizer to tap interactions with overlapping views. + + @param point The point inside the label. + */ +- (BOOL)containslinkAtPoint:(CGPoint)point; + +/** + Returns the @c TTTAttributedLabelLink at the give point if it exists. + + @discussion This can be used together with @c UIViewControllerPreviewingDelegate to peek into links. + + @param point The point inside the label. + */ +- (TTTAttributedLabelLink *)linkAtPoint:(CGPoint)point; + +@end + +/** + The `TTTAttributedLabelDelegate` protocol defines the messages sent to an attributed label delegate when links are tapped. All of the methods of this protocol are optional. + */ +@protocol TTTAttributedLabelDelegate + +///----------------------------------- +/// @name Responding to Link Selection +///----------------------------------- +@optional + +/** + Tells the delegate that the user did select a link to a URL. + + @param label The label whose link was selected. + @param url The URL for the selected link. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label + didSelectLinkWithURL:(NSURL *)url; + +/** + Tells the delegate that the user did select a link to an address. + + @param label The label whose link was selected. + @param addressComponents The components of the address for the selected link. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didSelectLinkWithAddress:(NSDictionary *)addressComponents; + +/** + Tells the delegate that the user did select a link to a phone number. + + @param label The label whose link was selected. + @param phoneNumber The phone number for the selected link. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didSelectLinkWithPhoneNumber:(NSString *)phoneNumber; + +/** + Tells the delegate that the user did select a link to a date. + + @param label The label whose link was selected. + @param date The datefor the selected link. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label + didSelectLinkWithDate:(NSDate *)date; + +/** + Tells the delegate that the user did select a link to a date with a time zone and duration. + + @param label The label whose link was selected. + @param date The date for the selected link. + @param timeZone The time zone of the date for the selected link. + @param duration The duration, in seconds from the date for the selected link. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label + didSelectLinkWithDate:(NSDate *)date + timeZone:(NSTimeZone *)timeZone + duration:(NSTimeInterval)duration; + +/** + Tells the delegate that the user did select a link to transit information + + @param label The label whose link was selected. + @param components A dictionary containing the transit components. The currently supported keys are `NSTextCheckingAirlineKey` and `NSTextCheckingFlightKey`. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didSelectLinkWithTransitInformation:(NSDictionary *)components; + +/** + Tells the delegate that the user did select a link to a text checking result. + + @discussion This method is called if no other delegate method was called, which can occur by either now implementing the method in `TTTAttributedLabelDelegate` corresponding to a particular link, or the link was added by passing an instance of a custom `NSTextCheckingResult` subclass into `-addLinkWithTextCheckingResult:`. + + @param label The label whose link was selected. + @param result The custom text checking result. + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result; + +///--------------------------------- +/// @name Responding to Long Presses +///--------------------------------- + +/** + * Long-press delegate methods include the CGPoint tapped within the label's coordinate space. + * This may be useful on iPad to present a popover from a specific origin point. + */ + +/** + Tells the delegate that the user long-pressed a link to a URL. + + @param label The label whose link was long pressed. + @param url The URL for the link. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithURL:(NSURL *)url + atPoint:(CGPoint)point; + +/** + Tells the delegate that the user long-pressed a link to an address. + + @param label The label whose link was long pressed. + @param addressComponents The components of the address for the link. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithAddress:(NSDictionary *)addressComponents + atPoint:(CGPoint)point; + +/** + Tells the delegate that the user long-pressed a link to a phone number. + + @param label The label whose link was long pressed. + @param phoneNumber The phone number for the link. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithPhoneNumber:(NSString *)phoneNumber + atPoint:(CGPoint)point; + + +/** + Tells the delegate that the user long-pressed a link to a date. + + @param label The label whose link was long pressed. + @param date The date for the selected link. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithDate:(NSDate *)date + atPoint:(CGPoint)point; + + +/** + Tells the delegate that the user long-pressed a link to a date with a time zone and duration. + + @param label The label whose link was long pressed. + @param date The date for the link. + @param timeZone The time zone of the date for the link. + @param duration The duration, in seconds from the date for the link. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithDate:(NSDate *)date + timeZone:(NSTimeZone *)timeZone + duration:(NSTimeInterval)duration + atPoint:(CGPoint)point; + + +/** + Tells the delegate that the user long-pressed a link to transit information. + + @param label The label whose link was long pressed. + @param components A dictionary containing the transit components. The currently supported keys are `NSTextCheckingAirlineKey` and `NSTextCheckingFlightKey`. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithTransitInformation:(NSDictionary *)components + atPoint:(CGPoint)point; + +/** + Tells the delegate that the user long-pressed a link to a text checking result. + + @discussion Similar to `-attributedLabel:didSelectLinkWithTextCheckingResult:`, this method is called if a link is long pressed and the delegate does not implement the method corresponding to this type of link. + + @param label The label whose link was long pressed. + @param result The custom text checking result. + @param point the point pressed, in the label's coordinate space + */ +- (void)attributedLabel:(TTTAttributedLabel *)label +didLongPressLinkWithTextCheckingResult:(NSTextCheckingResult *)result + atPoint:(CGPoint)point; + +@end + +@interface TTTAttributedLabelLink : NSObject + +typedef void (^TTTAttributedLabelLinkBlock) (TTTAttributedLabel *, TTTAttributedLabelLink *); + +/** + An `NSTextCheckingResult` representing the link's location and type. + */ +@property (readonly, nonatomic, strong) NSTextCheckingResult *result; + +/** + A dictionary containing the @c NSAttributedString attributes to be applied to the link. + */ +@property (readonly, nonatomic, copy) NSDictionary *attributes; + +/** + A dictionary containing the @c NSAttributedString attributes to be applied to the link when it is in the active state. + */ +@property (readonly, nonatomic, copy) NSDictionary *activeAttributes; + +/** + A dictionary containing the @c NSAttributedString attributes to be applied to the link when it is in the inactive state, which is triggered by a change in `tintColor` in iOS 7 and later. + */ +@property (readonly, nonatomic, copy) NSDictionary *inactiveAttributes; + +/** + Additional information about a link for VoiceOver users. Has default values if the link's @c result is @c NSTextCheckingTypeLink, @c NSTextCheckingTypePhoneNumber, or @c NSTextCheckingTypeDate. + */ +@property (nonatomic, copy) NSString *accessibilityValue; + +/** + A block called when this link is tapped. + If non-nil, tapping on this link will call this block instead of the + @c TTTAttributedLabelDelegate tap methods, which will not be called for this link. + */ +@property (nonatomic, copy) TTTAttributedLabelLinkBlock linkTapBlock; + +/** + A block called when this link is long-pressed. + If non-nil, long pressing on this link will call this block instead of the + @c TTTAttributedLabelDelegate long press methods, which will not be called for this link. + */ +@property (nonatomic, copy) TTTAttributedLabelLinkBlock linkLongPressBlock; + +/** + Initializes a link using the attribute dictionaries specified. + + @param attributes The @c attributes property for the link. + @param activeAttributes The @c activeAttributes property for the link. + @param inactiveAttributes The @c inactiveAttributes property for the link. + @param result An @c NSTextCheckingResult representing the link's location and type. + + @return The initialized link object. + */ +- (instancetype)initWithAttributes:(NSDictionary *)attributes + activeAttributes:(NSDictionary *)activeAttributes + inactiveAttributes:(NSDictionary *)inactiveAttributes + textCheckingResult:(NSTextCheckingResult *)result; + +/** + Initializes a link using the attribute dictionaries set on a specified label. + + @param label The attributed label from which to inherit attribute dictionaries. + @param result An @c NSTextCheckingResult representing the link's location and type. + + @return The initialized link object. + */ +- (instancetype)initWithAttributesFromLabel:(TTTAttributedLabel*)label + textCheckingResult:(NSTextCheckingResult *)result; + +@end diff --git a/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.m b/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.m new file mode 100644 index 0000000..a5250f7 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/TTTAttributedLabel/TTTAttributedLabel.m @@ -0,0 +1,1832 @@ +// TTTAttributedLabel.m +// +// Copyright (c) 2011 Mattt Thompson (http://mattt.me) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "TTTAttributedLabel.h" + +#import +#import +#import + +#define kTTTLineBreakWordWrapTextWidthScalingFactor (M_PI / M_E) + +static CGFloat const TTTFLOAT_MAX = 100000; + +NSString * const kTTTStrikeOutAttributeName = @"TTTStrikeOutAttribute"; +NSString * const kTTTBackgroundFillColorAttributeName = @"TTTBackgroundFillColor"; +NSString * const kTTTBackgroundFillPaddingAttributeName = @"TTTBackgroundFillPadding"; +NSString * const kTTTBackgroundStrokeColorAttributeName = @"TTTBackgroundStrokeColor"; +NSString * const kTTTBackgroundLineWidthAttributeName = @"TTTBackgroundLineWidth"; +NSString * const kTTTBackgroundCornerRadiusAttributeName = @"TTTBackgroundCornerRadius"; + +const NSTextAlignment TTTTextAlignmentLeft = NSTextAlignmentLeft; +const NSTextAlignment TTTTextAlignmentCenter = NSTextAlignmentCenter; +const NSTextAlignment TTTTextAlignmentRight = NSTextAlignmentRight; +const NSTextAlignment TTTTextAlignmentJustified = NSTextAlignmentJustified; +const NSTextAlignment TTTTextAlignmentNatural = NSTextAlignmentNatural; + +const NSLineBreakMode TTTLineBreakByWordWrapping = NSLineBreakByWordWrapping; +const NSLineBreakMode TTTLineBreakByCharWrapping = NSLineBreakByCharWrapping; +const NSLineBreakMode TTTLineBreakByClipping = NSLineBreakByClipping; +const NSLineBreakMode TTTLineBreakByTruncatingHead = NSLineBreakByTruncatingHead; +const NSLineBreakMode TTTLineBreakByTruncatingMiddle = NSLineBreakByTruncatingMiddle; +const NSLineBreakMode TTTLineBreakByTruncatingTail = NSLineBreakByTruncatingTail; + +typedef NSTextAlignment TTTTextAlignment; +typedef NSLineBreakMode TTTLineBreakMode; + + +static inline CGFLOAT_TYPE CGFloat_ceil(CGFLOAT_TYPE cgfloat) { +#if CGFLOAT_IS_DOUBLE + return ceil(cgfloat); +#else + return ceilf(cgfloat); +#endif +} + +static inline CGFLOAT_TYPE CGFloat_floor(CGFLOAT_TYPE cgfloat) { +#if CGFLOAT_IS_DOUBLE + return floor(cgfloat); +#else + return floorf(cgfloat); +#endif +} + +static inline CGFLOAT_TYPE CGFloat_round(CGFLOAT_TYPE cgfloat) { +#if CGFLOAT_IS_DOUBLE + return round(cgfloat); +#else + return roundf(cgfloat); +#endif +} + +static inline CGFLOAT_TYPE CGFloat_sqrt(CGFLOAT_TYPE cgfloat) { +#if CGFLOAT_IS_DOUBLE + return sqrt(cgfloat); +#else + return sqrtf(cgfloat); +#endif +} + +static inline CGFloat TTTFlushFactorForTextAlignment(NSTextAlignment textAlignment) { + switch (textAlignment) { + case TTTTextAlignmentCenter: + return 0.5f; + case TTTTextAlignmentRight: + return 1.0f; + case TTTTextAlignmentLeft: + default: + return 0.0f; + } +} + +static inline NSDictionary * NSAttributedStringAttributesFromLabel(TTTAttributedLabel *label) { + NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionary]; + + [mutableAttributes setObject:label.font forKey:(NSString *)kCTFontAttributeName]; + [mutableAttributes setObject:label.textColor forKey:(NSString *)kCTForegroundColorAttributeName]; + [mutableAttributes setObject:@(label.kern) forKey:(NSString *)kCTKernAttributeName]; + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.alignment = label.textAlignment; + paragraphStyle.lineSpacing = label.lineSpacing; + paragraphStyle.minimumLineHeight = label.minimumLineHeight > 0 ? label.minimumLineHeight : label.font.lineHeight * label.lineHeightMultiple; + paragraphStyle.maximumLineHeight = label.maximumLineHeight > 0 ? label.maximumLineHeight : label.font.lineHeight * label.lineHeightMultiple; + paragraphStyle.lineHeightMultiple = label.lineHeightMultiple; + paragraphStyle.firstLineHeadIndent = label.firstLineIndent; + + if (label.numberOfLines == 1) { + paragraphStyle.lineBreakMode = label.lineBreakMode; + } else { + paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; + } + + [mutableAttributes setObject:paragraphStyle forKey:(NSString *)kCTParagraphStyleAttributeName]; + + return [NSDictionary dictionaryWithDictionary:mutableAttributes]; +} + +static inline CGColorRef CGColorRefFromColor(id color); +static inline NSDictionary * convertNSAttributedStringAttributesToCTAttributes(NSDictionary *attributes); + +static inline NSAttributedString * NSAttributedStringByScalingFontSize(NSAttributedString *attributedString, CGFloat scale) { + NSMutableAttributedString *mutableAttributedString = [attributedString mutableCopy]; + [mutableAttributedString enumerateAttribute:(NSString *)kCTFontAttributeName inRange:NSMakeRange(0, [mutableAttributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL * __unused stop) { + UIFont *font = (UIFont *)value; + if (font) { + NSString *fontName; + CGFloat pointSize; + + if ([font isKindOfClass:[UIFont class]]) { + fontName = font.fontName; + pointSize = font.pointSize; + } else { + fontName = (NSString *)CFBridgingRelease(CTFontCopyName((__bridge CTFontRef)font, kCTFontPostScriptNameKey)); + pointSize = CTFontGetSize((__bridge CTFontRef)font); + } + + [mutableAttributedString removeAttribute:(NSString *)kCTFontAttributeName range:range]; + CTFontRef fontRef = CTFontCreateWithName((__bridge CFStringRef)fontName, CGFloat_floor(pointSize * scale), NULL); + [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)fontRef range:range]; + CFRelease(fontRef); + } + }]; + + return mutableAttributedString; +} + +static inline NSAttributedString * NSAttributedStringBySettingColorFromContext(NSAttributedString *attributedString, UIColor *color) { + if (!color) { + return attributedString; + } + + NSMutableAttributedString *mutableAttributedString = [attributedString mutableCopy]; + [mutableAttributedString enumerateAttribute:(NSString *)kCTForegroundColorFromContextAttributeName inRange:NSMakeRange(0, [mutableAttributedString length]) options:0 usingBlock:^(id value, NSRange range, __unused BOOL *stop) { + BOOL usesColorFromContext = (BOOL)value; + if (usesColorFromContext) { + [mutableAttributedString setAttributes:[NSDictionary dictionaryWithObject:color forKey:(NSString *)kCTForegroundColorAttributeName] range:range]; + [mutableAttributedString removeAttribute:(NSString *)kCTForegroundColorFromContextAttributeName range:range]; + } + }]; + + return mutableAttributedString; +} + +static inline CGSize CTFramesetterSuggestFrameSizeForAttributedStringWithConstraints(CTFramesetterRef framesetter, NSAttributedString *attributedString, CGSize size, NSUInteger numberOfLines) { + CFRange rangeToSize = CFRangeMake(0, (CFIndex)[attributedString length]); + CGSize constraints = CGSizeMake(size.width, TTTFLOAT_MAX); + + if (numberOfLines == 1) { + // If there is one line, the size that fits is the full width of the line + constraints = CGSizeMake(TTTFLOAT_MAX, TTTFLOAT_MAX); + } else if (numberOfLines > 0) { + // If the line count of the label more than 1, limit the range to size to the number of lines that have been set + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, CGRectMake(0.0f, 0.0f, constraints.width, TTTFLOAT_MAX)); + CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); + CFArrayRef lines = CTFrameGetLines(frame); + + if (CFArrayGetCount(lines) > 0) { + NSInteger lastVisibleLineIndex = MIN((CFIndex)numberOfLines, CFArrayGetCount(lines)) - 1; + CTLineRef lastVisibleLine = CFArrayGetValueAtIndex(lines, lastVisibleLineIndex); + + CFRange rangeToLayout = CTLineGetStringRange(lastVisibleLine); + rangeToSize = CFRangeMake(0, rangeToLayout.location + rangeToLayout.length); + } + + CFRelease(frame); + CGPathRelease(path); + } + + CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, rangeToSize, NULL, constraints, NULL); + + return CGSizeMake(CGFloat_ceil(suggestedSize.width), CGFloat_ceil(suggestedSize.height)); +} + +@interface TTTAccessibilityElement : UIAccessibilityElement +@property (nonatomic, weak) UIView *superview; +@property (nonatomic, assign) CGRect boundingRect; +@end + +@implementation TTTAccessibilityElement + +- (CGRect)accessibilityFrame { + return UIAccessibilityConvertFrameToScreenCoordinates(self.boundingRect, self.superview); +} + +@end + +@interface TTTAttributedLabel () +@property (readwrite, nonatomic, copy) NSAttributedString *inactiveAttributedText; +@property (readwrite, nonatomic, copy) NSAttributedString *renderedAttributedText; +@property (readwrite, atomic, strong) NSDataDetector *dataDetector; +@property (readwrite, nonatomic, strong) NSArray *linkModels; +@property (readwrite, nonatomic, strong) TTTAttributedLabelLink *activeLink; +@property (readwrite, nonatomic, strong) NSArray *accessibilityElements; + +- (void) longPressGestureDidFire:(UILongPressGestureRecognizer *)sender; +@end + +@implementation TTTAttributedLabel { +@private + BOOL _needsFramesetter; + CTFramesetterRef _framesetter; + CTFramesetterRef _highlightFramesetter; +} + +@dynamic text; +@synthesize attributedText = _attributedText; + +#ifndef kCFCoreFoundationVersionNumber_iOS_7_0 +#define kCFCoreFoundationVersionNumber_iOS_7_0 847.2 +#endif + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_7_0) { + Class class = [self class]; + Class superclass = class_getSuperclass(class); + + NSArray *strings = @[ + NSStringFromSelector(@selector(isAccessibilityElement)), + NSStringFromSelector(@selector(accessibilityElementCount)), + NSStringFromSelector(@selector(accessibilityElementAtIndex:)), + NSStringFromSelector(@selector(indexOfAccessibilityElement:)), + ]; + + for (NSString *string in strings) { + SEL selector = NSSelectorFromString(string); + IMP superImplementation = class_getMethodImplementation(superclass, selector); + Method method = class_getInstanceMethod(class, selector); + const char *types = method_getTypeEncoding(method); + class_replaceMethod(class, selector, superImplementation, types); + } + } + }); +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (!self) { + return nil; + } + + [self commonInit]; + + return self; +} + +- (void)commonInit { + self.userInteractionEnabled = YES; +#if !TARGET_OS_TV + self.multipleTouchEnabled = NO; +#endif + + self.textInsets = UIEdgeInsetsZero; + self.lineHeightMultiple = 1.0f; + + self.linkModels = [NSArray array]; + + self.linkBackgroundEdgeInset = UIEdgeInsetsMake(0.0f, -1.0f, 0.0f, -1.0f); + + NSMutableDictionary *mutableLinkAttributes = [NSMutableDictionary dictionary]; + [mutableLinkAttributes setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName]; + + NSMutableDictionary *mutableActiveLinkAttributes = [NSMutableDictionary dictionary]; + [mutableActiveLinkAttributes setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCTUnderlineStyleAttributeName]; + + NSMutableDictionary *mutableInactiveLinkAttributes = [NSMutableDictionary dictionary]; + [mutableInactiveLinkAttributes setObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCTUnderlineStyleAttributeName]; + + if ([NSMutableParagraphStyle class]) { + [mutableLinkAttributes setObject:[UIColor blueColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + [mutableActiveLinkAttributes setObject:[UIColor redColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + [mutableInactiveLinkAttributes setObject:[UIColor grayColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + } else { + [mutableLinkAttributes setObject:(__bridge id)[[UIColor blueColor] CGColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + [mutableActiveLinkAttributes setObject:(__bridge id)[[UIColor redColor] CGColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + [mutableInactiveLinkAttributes setObject:(__bridge id)[[UIColor grayColor] CGColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + } + + self.linkAttributes = [NSDictionary dictionaryWithDictionary:mutableLinkAttributes]; + self.activeLinkAttributes = [NSDictionary dictionaryWithDictionary:mutableActiveLinkAttributes]; + self.inactiveLinkAttributes = [NSDictionary dictionaryWithDictionary:mutableInactiveLinkAttributes]; + _extendsLinkTouchArea = NO; + _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self + action:@selector(longPressGestureDidFire:)]; + self.longPressGestureRecognizer.delegate = self; + [self addGestureRecognizer:self.longPressGestureRecognizer]; +} + +- (void)dealloc { + if (_framesetter) { + CFRelease(_framesetter); + } + + if (_highlightFramesetter) { + CFRelease(_highlightFramesetter); + } + + if (_longPressGestureRecognizer) { + [self removeGestureRecognizer:_longPressGestureRecognizer]; + } +} + +#pragma mark - + ++ (CGSize)sizeThatFitsAttributedString:(NSAttributedString *)attributedString + withConstraints:(CGSize)size + limitedToNumberOfLines:(NSUInteger)numberOfLines +{ + if (!attributedString || attributedString.length == 0) { + return CGSizeZero; + } + + CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attributedString); + + CGSize calculatedSize = CTFramesetterSuggestFrameSizeForAttributedStringWithConstraints(framesetter, attributedString, size, numberOfLines); + + CFRelease(framesetter); + + return calculatedSize; +} + +#pragma mark - + +- (void)setAttributedText:(NSAttributedString *)text { + if ([text isEqualToAttributedString:_attributedText]) { + return; + } + + _attributedText = [text copy]; + + [self setNeedsFramesetter]; + [self setNeedsDisplay]; + + if ([self respondsToSelector:@selector(invalidateIntrinsicContentSize)]) { + [self invalidateIntrinsicContentSize]; + } + + [super setText:[self.attributedText string]]; +} + +- (NSAttributedString *)renderedAttributedText { + if (!_renderedAttributedText) { + NSMutableAttributedString *fullString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; + + if (self.attributedTruncationToken) { + [fullString appendAttributedString:self.attributedTruncationToken]; + } + + NSAttributedString *string = [[NSAttributedString alloc] initWithAttributedString:fullString]; + self.renderedAttributedText = NSAttributedStringBySettingColorFromContext(string, self.textColor); + } + + return _renderedAttributedText; +} + +- (NSArray *) links { + return [_linkModels valueForKey:@"result"]; +} + +- (void)setLinkModels:(NSArray *)linkModels { + _linkModels = linkModels; + + self.accessibilityElements = nil; +} + +- (void)setNeedsFramesetter { + // Reset the rendered attributed text so it has a chance to regenerate + self.renderedAttributedText = nil; + + _needsFramesetter = YES; +} + +- (CTFramesetterRef)framesetter { + if (_needsFramesetter) { + @synchronized(self) { + CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.renderedAttributedText); + [self setFramesetter:framesetter]; + [self setHighlightFramesetter:nil]; + _needsFramesetter = NO; + + if (framesetter) { + CFRelease(framesetter); + } + } + } + + return _framesetter; +} + +- (void)setFramesetter:(CTFramesetterRef)framesetter { + if (framesetter) { + CFRetain(framesetter); + } + + if (_framesetter) { + CFRelease(_framesetter); + } + + _framesetter = framesetter; +} + +- (CTFramesetterRef)highlightFramesetter { + return _highlightFramesetter; +} + +- (void)setHighlightFramesetter:(CTFramesetterRef)highlightFramesetter { + if (highlightFramesetter) { + CFRetain(highlightFramesetter); + } + + if (_highlightFramesetter) { + CFRelease(_highlightFramesetter); + } + + _highlightFramesetter = highlightFramesetter; +} + +#pragma mark - + +- (void)setEnabledTextCheckingTypes:(NSTextCheckingTypes)enabledTextCheckingTypes { + if (self.enabledTextCheckingTypes == enabledTextCheckingTypes) { + return; + } + + _enabledTextCheckingTypes = enabledTextCheckingTypes; + + // one detector instance per type (combination), fast reuse e.g. in cells + static NSMutableDictionary *dataDetectorsByType = nil; + + if (!dataDetectorsByType) { + dataDetectorsByType = [NSMutableDictionary dictionary]; + } + + if (enabledTextCheckingTypes) { + if (![dataDetectorsByType objectForKey:@(enabledTextCheckingTypes)]) { + NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:enabledTextCheckingTypes + error:nil]; + if (detector) { + [dataDetectorsByType setObject:detector forKey:@(enabledTextCheckingTypes)]; + } + } + self.dataDetector = [dataDetectorsByType objectForKey:@(enabledTextCheckingTypes)]; + } else { + self.dataDetector = nil; + } +} + +- (void)addLink:(TTTAttributedLabelLink *)link { + [self addLinks:@[link]]; +} + +- (void)addLinks:(NSArray *)links { + NSMutableArray *mutableLinkModels = [NSMutableArray arrayWithArray:self.linkModels]; + + NSMutableAttributedString *mutableAttributedString = [self.attributedText mutableCopy]; + + for (TTTAttributedLabelLink *link in links) { + if (link.attributes) { + [mutableAttributedString addAttributes:link.attributes range:link.result.range]; + } + } + + self.attributedText = mutableAttributedString; + [self setNeedsDisplay]; + + [mutableLinkModels addObjectsFromArray:links]; + + self.linkModels = [NSArray arrayWithArray:mutableLinkModels]; +} + +- (TTTAttributedLabelLink *)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result + attributes:(NSDictionary *)attributes +{ + return [self addLinksWithTextCheckingResults:@[result] attributes:attributes].firstObject; +} + +- (NSArray *)addLinksWithTextCheckingResults:(NSArray *)results + attributes:(NSDictionary *)attributes +{ + NSMutableArray *links = [NSMutableArray array]; + + for (NSTextCheckingResult *result in results) { + NSDictionary *activeAttributes = attributes ? self.activeLinkAttributes : nil; + NSDictionary *inactiveAttributes = attributes ? self.inactiveLinkAttributes : nil; + + TTTAttributedLabelLink *link = [[TTTAttributedLabelLink alloc] initWithAttributes:attributes + activeAttributes:activeAttributes + inactiveAttributes:inactiveAttributes + textCheckingResult:result]; + + [links addObject:link]; + } + + [self addLinks:links]; + + return links; +} + +- (TTTAttributedLabelLink *)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result { + return [self addLinkWithTextCheckingResult:result attributes:self.linkAttributes]; +} + +- (TTTAttributedLabelLink *)addLinkToURL:(NSURL *)url + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult linkCheckingResultWithRange:range URL:url]]; +} + +- (TTTAttributedLabelLink *)addLinkToAddress:(NSDictionary *)addressComponents + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult addressCheckingResultWithRange:range components:addressComponents]]; +} + +- (TTTAttributedLabelLink *)addLinkToPhoneNumber:(NSString *)phoneNumber + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult phoneNumberCheckingResultWithRange:range phoneNumber:phoneNumber]]; +} + +- (TTTAttributedLabelLink *)addLinkToDate:(NSDate *)date + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult dateCheckingResultWithRange:range date:date]]; +} + +- (TTTAttributedLabelLink *)addLinkToDate:(NSDate *)date + timeZone:(NSTimeZone *)timeZone + duration:(NSTimeInterval)duration + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult dateCheckingResultWithRange:range date:date timeZone:timeZone duration:duration]]; +} + +- (TTTAttributedLabelLink *)addLinkToTransitInformation:(NSDictionary *)components + withRange:(NSRange)range +{ + return [self addLinkWithTextCheckingResult:[NSTextCheckingResult transitInformationCheckingResultWithRange:range components:components]]; +} + +#pragma mark - + +- (BOOL)containslinkAtPoint:(CGPoint)point { + return [self linkAtPoint:point] != nil; +} + +- (TTTAttributedLabelLink *)linkAtPoint:(CGPoint)point { + + // Stop quickly if none of the points to be tested are in the bounds. + if (!CGRectContainsPoint(CGRectInset(self.bounds, -15.f, -15.f), point) || self.links.count == 0) { + return nil; + } + + TTTAttributedLabelLink *result = [self linkAtCharacterIndex:[self characterIndexAtPoint:point]]; + + if (!result && self.extendsLinkTouchArea) { + result = [self linkAtRadius:2.5f aroundPoint:point] + ?: [self linkAtRadius:5.f aroundPoint:point] + ?: [self linkAtRadius:7.5f aroundPoint:point] + ?: [self linkAtRadius:12.5f aroundPoint:point] + ?: [self linkAtRadius:15.f aroundPoint:point]; + } + + return result; +} + +- (TTTAttributedLabelLink *)linkAtRadius:(const CGFloat)radius aroundPoint:(CGPoint)point { + const CGFloat diagonal = CGFloat_sqrt(2 * radius * radius); + const CGPoint deltas[] = { + CGPointMake(0, -radius), CGPointMake(0, radius), // Above and below + CGPointMake(-radius, 0), CGPointMake(radius, 0), // Beside + CGPointMake(-diagonal, -diagonal), CGPointMake(-diagonal, diagonal), + CGPointMake(diagonal, diagonal), CGPointMake(diagonal, -diagonal) // Diagonal + }; + const size_t count = sizeof(deltas) / sizeof(CGPoint); + + TTTAttributedLabelLink *link = nil; + + for (NSUInteger i = 0; i < count && link.result == nil; i ++) { + CGPoint currentPoint = CGPointMake(point.x + deltas[i].x, point.y + deltas[i].y); + link = [self linkAtCharacterIndex:[self characterIndexAtPoint:currentPoint]]; + } + + return link; +} + +- (TTTAttributedLabelLink *)linkAtCharacterIndex:(CFIndex)idx { + // Do not enumerate if the index is outside of the bounds of the text. + if (!NSLocationInRange((NSUInteger)idx, NSMakeRange(0, self.attributedText.length))) { + return nil; + } + + NSEnumerator *enumerator = [self.linkModels reverseObjectEnumerator]; + TTTAttributedLabelLink *link = nil; + while ((link = [enumerator nextObject])) { + if (NSLocationInRange((NSUInteger)idx, link.result.range)) { + return link; + } + } + + return nil; +} + +- (CFIndex)characterIndexAtPoint:(CGPoint)p { + if (!CGRectContainsPoint(self.bounds, p)) { + return NSNotFound; + } + + CGRect textRect = [self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines]; + if (!CGRectContainsPoint(textRect, p)) { + return NSNotFound; + } + + // Offset tap coordinates by textRect origin to make them relative to the origin of frame + p = CGPointMake(p.x - textRect.origin.x, p.y - textRect.origin.y); + // Convert tap coordinates (start at top left) to CT coordinates (start at bottom left) + p = CGPointMake(p.x, textRect.size.height - p.y); + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, textRect); + CTFrameRef frame = CTFramesetterCreateFrame([self framesetter], CFRangeMake(0, (CFIndex)[self.attributedText length]), path, NULL); + if (frame == NULL) { + CGPathRelease(path); + return NSNotFound; + } + + CFArrayRef lines = CTFrameGetLines(frame); + NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines); + if (numberOfLines == 0) { + CFRelease(frame); + CGPathRelease(path); + return NSNotFound; + } + + CFIndex idx = NSNotFound; + + CGPoint lineOrigins[numberOfLines]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins); + + for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) { + CGPoint lineOrigin = lineOrigins[lineIndex]; + CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); + + // Get bounding information of line + CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f; + CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading); + CGFloat yMin = (CGFloat)floor(lineOrigin.y - descent); + CGFloat yMax = (CGFloat)ceil(lineOrigin.y + ascent); + + // Apply penOffset using flushFactor for horizontal alignment to set lineOrigin since this is the horizontal offset from drawFramesetter + CGFloat flushFactor = TTTFlushFactorForTextAlignment(self.textAlignment); + CGFloat penOffset = (CGFloat)CTLineGetPenOffsetForFlush(line, flushFactor, textRect.size.width); + lineOrigin.x = penOffset; + + // Check if we've already passed the line + if (p.y > yMax) { + break; + } + // Check if the point is within this line vertically + if (p.y >= yMin) { + // Check if the point is within this line horizontally + if (p.x >= lineOrigin.x && p.x <= lineOrigin.x + width) { + // Convert CT coordinates to line-relative coordinates + CGPoint relativePoint = CGPointMake(p.x - lineOrigin.x, p.y - lineOrigin.y); + idx = CTLineGetStringIndexForPosition(line, relativePoint); + break; + } + } + } + + CFRelease(frame); + CGPathRelease(path); + + return idx; +} + +- (CGRect)boundingRectForCharacterRange:(NSRange)range { + NSMutableAttributedString *mutableAttributedString = [self.attributedText mutableCopy]; + + NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:mutableAttributedString]; + + NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; + [textStorage addLayoutManager:layoutManager]; + + NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:self.bounds.size]; + [layoutManager addTextContainer:textContainer]; + + NSRange glyphRange; + [layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange]; + + return [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer]; +} + +- (void)drawFramesetter:(CTFramesetterRef)framesetter + attributedString:(NSAttributedString *)attributedString + textRange:(CFRange)textRange + inRect:(CGRect)rect + context:(CGContextRef)c +{ + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, rect); + CTFrameRef frame = CTFramesetterCreateFrame(framesetter, textRange, path, NULL); + + [self drawBackground:frame inRect:rect context:c]; + + CFArrayRef lines = CTFrameGetLines(frame); + NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines); + BOOL truncateLastLine = (self.lineBreakMode == TTTLineBreakByTruncatingHead || self.lineBreakMode == TTTLineBreakByTruncatingMiddle || self.lineBreakMode == TTTLineBreakByTruncatingTail); + + CGPoint lineOrigins[numberOfLines]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins); + + for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) { + CGPoint lineOrigin = lineOrigins[lineIndex]; + CGContextSetTextPosition(c, lineOrigin.x, lineOrigin.y); + CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); + + CGFloat descent = 0.0f; + CTLineGetTypographicBounds((CTLineRef)line, NULL, &descent, NULL); + + // Adjust pen offset for flush depending on text alignment + CGFloat flushFactor = TTTFlushFactorForTextAlignment(self.textAlignment); + + if (lineIndex == numberOfLines - 1 && truncateLastLine) { + // Check if the range of text in the last line reaches the end of the full attributed string + CFRange lastLineRange = CTLineGetStringRange(line); + + if (!(lastLineRange.length == 0 && lastLineRange.location == 0) && lastLineRange.location + lastLineRange.length < textRange.location + textRange.length) { + // Get correct truncationType and attribute position + CTLineTruncationType truncationType; + CFIndex truncationAttributePosition = lastLineRange.location; + TTTLineBreakMode lineBreakMode = self.lineBreakMode; + + // Multiple lines, only use UILineBreakModeTailTruncation + if (numberOfLines != 1) { + lineBreakMode = TTTLineBreakByTruncatingTail; + } + + switch (lineBreakMode) { + case TTTLineBreakByTruncatingHead: + truncationType = kCTLineTruncationStart; + break; + case TTTLineBreakByTruncatingMiddle: + truncationType = kCTLineTruncationMiddle; + truncationAttributePosition += (lastLineRange.length / 2); + break; + case TTTLineBreakByTruncatingTail: + default: + truncationType = kCTLineTruncationEnd; + truncationAttributePosition += (lastLineRange.length - 1); + break; + } + + NSAttributedString *attributedTruncationString = self.attributedTruncationToken; + if (!attributedTruncationString) { + NSString *truncationTokenString = @"\u2026"; // Unicode Character 'HORIZONTAL ELLIPSIS' (U+2026) + + NSDictionary *truncationTokenStringAttributes = truncationTokenStringAttributes = [attributedString attributesAtIndex:(NSUInteger)truncationAttributePosition effectiveRange:NULL]; + + attributedTruncationString = [[NSAttributedString alloc] initWithString:truncationTokenString attributes:truncationTokenStringAttributes]; + } + CTLineRef truncationToken = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)attributedTruncationString); + + // Append truncationToken to the string + // because if string isn't too long, CT won't add the truncationToken on its own. + // There is no chance of a double truncationToken because CT only adds the + // token if it removes characters (and the one we add will go first) + NSMutableAttributedString *truncationString = [[NSMutableAttributedString alloc] initWithAttributedString: + [attributedString attributedSubstringFromRange: + NSMakeRange((NSUInteger)lastLineRange.location, + (NSUInteger)lastLineRange.length)]]; + if (lastLineRange.length > 0) { + // Remove any newline at the end (we don't want newline space between the text and the truncation token). There can only be one, because the second would be on the next line. + unichar lastCharacter = [[truncationString string] characterAtIndex:(NSUInteger)(lastLineRange.length - 1)]; + if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastCharacter]) { + [truncationString deleteCharactersInRange:NSMakeRange((NSUInteger)(lastLineRange.length - 1), 1)]; + } + } + [truncationString appendAttributedString:attributedTruncationString]; + CTLineRef truncationLine = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)truncationString); + + // Truncate the line in case it is too long. + CTLineRef truncatedLine = CTLineCreateTruncatedLine(truncationLine, rect.size.width, truncationType, truncationToken); + if (!truncatedLine) { + // If the line is not as wide as the truncationToken, truncatedLine is NULL + truncatedLine = CFRetain(truncationToken); + } + + CGFloat penOffset = (CGFloat)CTLineGetPenOffsetForFlush(truncatedLine, flushFactor, rect.size.width); + CGContextSetTextPosition(c, penOffset, lineOrigin.y - descent - self.font.descender); + + CTLineDraw(truncatedLine, c); + + NSRange linkRange; + if ([attributedTruncationString attribute:NSLinkAttributeName atIndex:0 effectiveRange:&linkRange]) { + NSRange tokenRange = [truncationString.string rangeOfString:attributedTruncationString.string]; + NSRange tokenLinkRange = NSMakeRange((NSUInteger)(lastLineRange.location+lastLineRange.length)-tokenRange.length, (NSUInteger)tokenRange.length); + + [self addLinkToURL:[attributedTruncationString attribute:NSLinkAttributeName atIndex:0 effectiveRange:&linkRange] withRange:tokenLinkRange]; + } + + CFRelease(truncatedLine); + CFRelease(truncationLine); + CFRelease(truncationToken); + } else { + CGFloat penOffset = (CGFloat)CTLineGetPenOffsetForFlush(line, flushFactor, rect.size.width); + CGContextSetTextPosition(c, penOffset, lineOrigin.y - descent - self.font.descender); + CTLineDraw(line, c); + } + } else { + CGFloat penOffset = (CGFloat)CTLineGetPenOffsetForFlush(line, flushFactor, rect.size.width); + CGContextSetTextPosition(c, penOffset, lineOrigin.y - descent - self.font.descender); + CTLineDraw(line, c); + } + } + + [self drawStrike:frame inRect:rect context:c]; + + CFRelease(frame); + CGPathRelease(path); +} + +- (void)drawBackground:(CTFrameRef)frame + inRect:(CGRect)rect + context:(CGContextRef)c +{ + NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); + CGPoint origins[[lines count]]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); + + CFIndex lineIndex = 0; + for (id line in lines) { + CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f; + CGFloat width = (CGFloat)CTLineGetTypographicBounds((__bridge CTLineRef)line, &ascent, &descent, &leading) ; + + for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { + NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); + CGColorRef strokeColor = CGColorRefFromColor([attributes objectForKey:kTTTBackgroundStrokeColorAttributeName]); + CGColorRef fillColor = CGColorRefFromColor([attributes objectForKey:kTTTBackgroundFillColorAttributeName]); + UIEdgeInsets fillPadding = [[attributes objectForKey:kTTTBackgroundFillPaddingAttributeName] UIEdgeInsetsValue]; + CGFloat cornerRadius = [[attributes objectForKey:kTTTBackgroundCornerRadiusAttributeName] floatValue]; + CGFloat lineWidth = [[attributes objectForKey:kTTTBackgroundLineWidthAttributeName] floatValue]; + + if (strokeColor || fillColor) { + CGRect runBounds = CGRectZero; + CGFloat runAscent = 0.0f; + CGFloat runDescent = 0.0f; + + runBounds.size.width = (CGFloat)CTRunGetTypographicBounds((__bridge CTRunRef)glyphRun, CFRangeMake(0, 0), &runAscent, &runDescent, NULL) + fillPadding.left + fillPadding.right; + runBounds.size.height = runAscent + runDescent + fillPadding.top + fillPadding.bottom; + + CGFloat xOffset = 0.0f; + CFRange glyphRange = CTRunGetStringRange((__bridge CTRunRef)glyphRun); + switch (CTRunGetStatus((__bridge CTRunRef)glyphRun)) { + case kCTRunStatusRightToLeft: + xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, glyphRange.location + glyphRange.length, NULL); + break; + default: + xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, glyphRange.location, NULL); + break; + } + + runBounds.origin.x = origins[lineIndex].x + rect.origin.x + xOffset - fillPadding.left - rect.origin.x; + runBounds.origin.y = origins[lineIndex].y + rect.origin.y - fillPadding.bottom - rect.origin.y; + runBounds.origin.y -= runDescent; + + // Don't draw higlightedLinkBackground too far to the right + if (CGRectGetWidth(runBounds) > width) { + runBounds.size.width = width; + } + + CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:CGRectInset(UIEdgeInsetsInsetRect(runBounds, self.linkBackgroundEdgeInset), lineWidth, lineWidth) cornerRadius:cornerRadius] CGPath]; + + CGContextSetLineJoin(c, kCGLineJoinRound); + + if (fillColor) { + CGContextSetFillColorWithColor(c, fillColor); + CGContextAddPath(c, path); + CGContextFillPath(c); + } + + if (strokeColor) { + CGContextSetStrokeColorWithColor(c, strokeColor); + CGContextAddPath(c, path); + CGContextStrokePath(c); + } + } + } + + lineIndex++; + } +} + +- (void)drawStrike:(CTFrameRef)frame + inRect:(__unused CGRect)rect + context:(CGContextRef)c +{ + NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); + CGPoint origins[[lines count]]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); + + CFIndex lineIndex = 0; + for (id line in lines) { + CGFloat ascent = 0.0f, descent = 0.0f, leading = 0.0f; + CGFloat width = (CGFloat)CTLineGetTypographicBounds((__bridge CTLineRef)line, &ascent, &descent, &leading) ; + + for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { + NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); + BOOL strikeOut = [[attributes objectForKey:kTTTStrikeOutAttributeName] boolValue]; + NSInteger superscriptStyle = [[attributes objectForKey:(id)kCTSuperscriptAttributeName] integerValue]; + + if (strikeOut) { + CGRect runBounds = CGRectZero; + CGFloat runAscent = 0.0f; + CGFloat runDescent = 0.0f; + + runBounds.size.width = (CGFloat)CTRunGetTypographicBounds((__bridge CTRunRef)glyphRun, CFRangeMake(0, 0), &runAscent, &runDescent, NULL); + runBounds.size.height = runAscent + runDescent; + + CGFloat xOffset = 0.0f; + CFRange glyphRange = CTRunGetStringRange((__bridge CTRunRef)glyphRun); + switch (CTRunGetStatus((__bridge CTRunRef)glyphRun)) { + case kCTRunStatusRightToLeft: + xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, glyphRange.location + glyphRange.length, NULL); + break; + default: + xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, glyphRange.location, NULL); + break; + } + runBounds.origin.x = origins[lineIndex].x + xOffset; + runBounds.origin.y = origins[lineIndex].y; + runBounds.origin.y -= runDescent; + + // Don't draw strikeout too far to the right + if (CGRectGetWidth(runBounds) > width) { + runBounds.size.width = width; + } + + switch (superscriptStyle) { + case 1: + runBounds.origin.y -= runAscent * 0.47f; + break; + case -1: + runBounds.origin.y += runAscent * 0.25f; + break; + default: + break; + } + + // Use text color, or default to black + id color = [attributes objectForKey:(id)kCTForegroundColorAttributeName]; + if (color) { + CGContextSetStrokeColorWithColor(c, CGColorRefFromColor(color)); + } else { + CGContextSetGrayStrokeColor(c, 0.0f, 1.0); + } + + CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)self.font.fontName, self.font.pointSize, NULL); + CGContextSetLineWidth(c, CTFontGetUnderlineThickness(font)); + CFRelease(font); + + CGFloat y = CGFloat_round(runBounds.origin.y + runBounds.size.height / 2.0f); + CGContextMoveToPoint(c, runBounds.origin.x, y); + CGContextAddLineToPoint(c, runBounds.origin.x + runBounds.size.width, y); + + CGContextStrokePath(c); + } + } + + lineIndex++; + } +} + +#pragma mark - TTTAttributedLabel + +- (void)setText:(id)text { + NSParameterAssert(!text || [text isKindOfClass:[NSAttributedString class]] || [text isKindOfClass:[NSString class]]); + + if ([text isKindOfClass:[NSString class]]) { + [self setText:text afterInheritingLabelAttributesAndConfiguringWithBlock:nil]; + return; + } + + self.attributedText = text; + self.activeLink = nil; + + self.linkModels = [NSArray array]; + if (text && self.attributedText && self.enabledTextCheckingTypes) { + __weak __typeof(self)weakSelf = self; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + __strong __typeof(weakSelf)strongSelf = weakSelf; + + NSDataDetector *dataDetector = strongSelf.dataDetector; + if (dataDetector && [dataDetector respondsToSelector:@selector(matchesInString:options:range:)]) { + NSArray *results = [dataDetector matchesInString:[(NSAttributedString *)text string] options:0 range:NSMakeRange(0, [(NSAttributedString *)text length])]; + if ([results count] > 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + if ([[strongSelf.attributedText string] isEqualToString:[(NSAttributedString *)text string]]) { + [strongSelf addLinksWithTextCheckingResults:results attributes:strongSelf.linkAttributes]; + } + }); + } + } + }); + } + + [self.attributedText enumerateAttribute:NSLinkAttributeName inRange:NSMakeRange(0, self.attributedText.length) options:0 usingBlock:^(id value, __unused NSRange range, __unused BOOL *stop) { + if (value) { + NSURL *URL = [value isKindOfClass:[NSString class]] ? [NSURL URLWithString:value] : value; + [self addLinkToURL:URL withRange:range]; + } + }]; +} + +- (void)setText:(id)text +afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString * (^)(NSMutableAttributedString *mutableAttributedString))block +{ + NSMutableAttributedString *mutableAttributedString = nil; + if ([text isKindOfClass:[NSString class]]) { + mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:NSAttributedStringAttributesFromLabel(self)]; + } else { + mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:text]; + [mutableAttributedString addAttributes:NSAttributedStringAttributesFromLabel(self) range:NSMakeRange(0, [mutableAttributedString length])]; + } + + if (block) { + mutableAttributedString = block(mutableAttributedString); + } + + [self setText:mutableAttributedString]; +} + +- (void)setActiveLink:(TTTAttributedLabelLink *)activeLink { + _activeLink = activeLink; + + NSDictionary *activeAttributes = activeLink.activeAttributes ?: self.activeLinkAttributes; + + if (_activeLink && activeAttributes.count > 0) { + if (!self.inactiveAttributedText) { + self.inactiveAttributedText = [self.attributedText copy]; + } + + NSMutableAttributedString *mutableAttributedString = [self.inactiveAttributedText mutableCopy]; + if (self.activeLink.result.range.length > 0 && NSLocationInRange(NSMaxRange(self.activeLink.result.range) - 1, NSMakeRange(0, [self.inactiveAttributedText length]))) { + [mutableAttributedString addAttributes:activeAttributes range:self.activeLink.result.range]; + } + + self.attributedText = mutableAttributedString; + [self setNeedsDisplay]; + + [CATransaction flush]; + } else if (self.inactiveAttributedText) { + self.attributedText = self.inactiveAttributedText; + self.inactiveAttributedText = nil; + + [self setNeedsDisplay]; + } +} + +- (void)setLinkAttributes:(NSDictionary *)linkAttributes { + _linkAttributes = convertNSAttributedStringAttributesToCTAttributes(linkAttributes); +} + +- (void)setActiveLinkAttributes:(NSDictionary *)activeLinkAttributes { + _activeLinkAttributes = convertNSAttributedStringAttributesToCTAttributes(activeLinkAttributes); +} + +- (void)setInactiveLinkAttributes:(NSDictionary *)inactiveLinkAttributes { + _inactiveLinkAttributes = convertNSAttributedStringAttributesToCTAttributes(inactiveLinkAttributes); +} + +#pragma mark - UILabel + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + [self setNeedsDisplay]; +} + +// Fixes crash when loading from a UIStoryboard +- (UIColor *)textColor { + UIColor *color = [super textColor]; + if (!color) { + color = [UIColor blackColor]; + } + + return color; +} + +- (void)setTextColor:(UIColor *)textColor { + UIColor *oldTextColor = self.textColor; + [super setTextColor:textColor]; + + // Redraw to allow any ColorFromContext attributes a chance to update + if (textColor != oldTextColor) { + [self setNeedsFramesetter]; + [self setNeedsDisplay]; + } +} + +- (CGRect)textRectForBounds:(CGRect)bounds + limitedToNumberOfLines:(NSInteger)numberOfLines +{ + bounds = UIEdgeInsetsInsetRect(bounds, self.textInsets); + if (!self.attributedText) { + return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; + } + + CGRect textRect = bounds; + + // Calculate height with a minimum of double the font pointSize, to ensure that CTFramesetterSuggestFrameSizeWithConstraints doesn't return CGSizeZero, as it would if textRect height is insufficient. + textRect.size.height = MAX(self.font.lineHeight * MAX(2, numberOfLines), bounds.size.height); + + // Adjust the text to be in the center vertically, if the text size is smaller than bounds + CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints([self framesetter], CFRangeMake(0, (CFIndex)[self.attributedText length]), NULL, textRect.size, NULL); + textSize = CGSizeMake(CGFloat_ceil(textSize.width), CGFloat_ceil(textSize.height)); // Fix for iOS 4, CTFramesetterSuggestFrameSizeWithConstraints sometimes returns fractional sizes + + if (textSize.height < bounds.size.height) { + CGFloat yOffset = 0.0f; + switch (self.verticalAlignment) { + case TTTAttributedLabelVerticalAlignmentCenter: + yOffset = CGFloat_floor((bounds.size.height - textSize.height) / 2.0f); + break; + case TTTAttributedLabelVerticalAlignmentBottom: + yOffset = bounds.size.height - textSize.height; + break; + case TTTAttributedLabelVerticalAlignmentTop: + default: + break; + } + + textRect.origin.y += yOffset; + } + + return textRect; +} + +- (void)drawTextInRect:(CGRect)rect { + CGRect insetRect = UIEdgeInsetsInsetRect(rect, self.textInsets); + if (!self.attributedText) { + [super drawTextInRect:insetRect]; + return; + } + + NSAttributedString *originalAttributedText = nil; + + // Adjust the font size to fit width, if necessarry + if (self.adjustsFontSizeToFitWidth && self.numberOfLines > 0) { + // Framesetter could still be working with a resized version of the text; + // need to reset so we start from the original font size. + // See #393. + [self setNeedsFramesetter]; + [self setNeedsDisplay]; + + if ([self respondsToSelector:@selector(invalidateIntrinsicContentSize)]) { + [self invalidateIntrinsicContentSize]; + } + + // Use infinite width to find the max width, which will be compared to availableWidth if needed. + CGSize maxSize = (self.numberOfLines > 1) ? CGSizeMake(TTTFLOAT_MAX, TTTFLOAT_MAX) : CGSizeZero; + + CGFloat textWidth = [self sizeThatFits:maxSize].width; + CGFloat availableWidth = self.frame.size.width * self.numberOfLines; + if (self.numberOfLines > 1 && self.lineBreakMode == TTTLineBreakByWordWrapping) { + textWidth *= kTTTLineBreakWordWrapTextWidthScalingFactor; + } + + if (textWidth > availableWidth && textWidth > 0.0f) { + originalAttributedText = [self.attributedText copy]; + + CGFloat scaleFactor = availableWidth / textWidth; + if ([self respondsToSelector:@selector(minimumScaleFactor)] && self.minimumScaleFactor > scaleFactor) { + scaleFactor = self.minimumScaleFactor; + } + + self.attributedText = NSAttributedStringByScalingFontSize(self.attributedText, scaleFactor); + } + } + + CGContextRef c = UIGraphicsGetCurrentContext(); + CGContextSaveGState(c); + { + CGContextSetTextMatrix(c, CGAffineTransformIdentity); + + // Inverts the CTM to match iOS coordinates (otherwise text draws upside-down; Mac OS's system is different) + CGContextTranslateCTM(c, 0.0f, insetRect.size.height); + CGContextScaleCTM(c, 1.0f, -1.0f); + + CFRange textRange = CFRangeMake(0, (CFIndex)[self.attributedText length]); + + // First, get the text rect (which takes vertical centering into account) + CGRect textRect = [self textRectForBounds:rect limitedToNumberOfLines:self.numberOfLines]; + + // CoreText draws its text aligned to the bottom, so we move the CTM here to take our vertical offsets into account + CGContextTranslateCTM(c, insetRect.origin.x, insetRect.size.height - textRect.origin.y - textRect.size.height); + + // Second, trace the shadow before the actual text, if we have one + if (self.shadowColor && !self.highlighted) { + CGContextSetShadowWithColor(c, self.shadowOffset, self.shadowRadius, [self.shadowColor CGColor]); + } else if (self.highlightedShadowColor) { + CGContextSetShadowWithColor(c, self.highlightedShadowOffset, self.highlightedShadowRadius, [self.highlightedShadowColor CGColor]); + } + + // Finally, draw the text or highlighted text itself (on top of the shadow, if there is one) + if (self.highlightedTextColor && self.highlighted) { + NSMutableAttributedString *highlightAttributedString = [self.renderedAttributedText mutableCopy]; + [highlightAttributedString addAttribute:(__bridge NSString *)kCTForegroundColorAttributeName value:(id)[self.highlightedTextColor CGColor] range:NSMakeRange(0, highlightAttributedString.length)]; + + if (![self highlightFramesetter]) { + CTFramesetterRef highlightFramesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)highlightAttributedString); + [self setHighlightFramesetter:highlightFramesetter]; + CFRelease(highlightFramesetter); + } + + [self drawFramesetter:[self highlightFramesetter] attributedString:highlightAttributedString textRange:textRange inRect:textRect context:c]; + } else { + [self drawFramesetter:[self framesetter] attributedString:self.renderedAttributedText textRange:textRange inRect:textRect context:c]; + } + + // If we adjusted the font size, set it back to its original size + if (originalAttributedText) { + // Use ivar directly to avoid clearing out framesetter and renderedAttributedText + _attributedText = originalAttributedText; + } + } + CGContextRestoreGState(c); +} + +#pragma mark - UIAccessibilityElement + +- (BOOL)isAccessibilityElement { + return NO; +} + +- (NSInteger)accessibilityElementCount { + return (NSInteger)[[self accessibilityElements] count]; +} + +- (id)accessibilityElementAtIndex:(NSInteger)index { + return [[self accessibilityElements] objectAtIndex:(NSUInteger)index]; +} + +- (NSInteger)indexOfAccessibilityElement:(id)element { + return (NSInteger)[[self accessibilityElements] indexOfObject:element]; +} + +- (NSArray *)accessibilityElements { + if (!_accessibilityElements) { + @synchronized(self) { + NSMutableArray *mutableAccessibilityItems = [NSMutableArray array]; + + for (TTTAttributedLabelLink *link in self.linkModels) { + + if (link.result.range.location == NSNotFound) { + continue; + } + + NSString *sourceText = [self.text isKindOfClass:[NSString class]] ? self.text : [(NSAttributedString *)self.text string]; + + NSString *accessibilityLabel = [sourceText substringWithRange:link.result.range]; + NSString *accessibilityValue = link.accessibilityValue; + + if (accessibilityLabel) { + TTTAccessibilityElement *linkElement = [[TTTAccessibilityElement alloc] initWithAccessibilityContainer:self]; + linkElement.accessibilityTraits = UIAccessibilityTraitLink; + linkElement.boundingRect = [self boundingRectForCharacterRange:link.result.range]; + linkElement.superview = self; + linkElement.accessibilityLabel = accessibilityLabel; + + if (![accessibilityLabel isEqualToString:accessibilityValue]) { + linkElement.accessibilityValue = accessibilityValue; + } + + [mutableAccessibilityItems addObject:linkElement]; + } + } + + TTTAccessibilityElement *baseElement = [[TTTAccessibilityElement alloc] initWithAccessibilityContainer:self]; + baseElement.accessibilityLabel = [super accessibilityLabel]; + baseElement.accessibilityHint = [super accessibilityHint]; + baseElement.accessibilityValue = [super accessibilityValue]; + baseElement.boundingRect = self.bounds; + baseElement.superview = self; + baseElement.accessibilityTraits = [super accessibilityTraits]; + + [mutableAccessibilityItems addObject:baseElement]; + + self.accessibilityElements = [NSArray arrayWithArray:mutableAccessibilityItems]; + } + } + + return _accessibilityElements; +} + +#pragma mark - UIView + +- (CGSize)sizeThatFits:(CGSize)size { + if (!self.attributedText) { + return [super sizeThatFits:size]; + } else { + NSAttributedString *string = [self renderedAttributedText]; + + CGSize labelSize = CTFramesetterSuggestFrameSizeForAttributedStringWithConstraints([self framesetter], string, size, (NSUInteger)self.numberOfLines); + labelSize.width += self.textInsets.left + self.textInsets.right; + labelSize.height += self.textInsets.top + self.textInsets.bottom; + + return labelSize; + } +} + +- (CGSize)intrinsicContentSize { + // There's an implicit width from the original UILabel implementation + return [self sizeThatFits:[super intrinsicContentSize]]; +} + +- (void)tintColorDidChange { + if (!self.inactiveLinkAttributes || [self.inactiveLinkAttributes count] == 0) { + return; + } + + BOOL isInactive = (self.tintAdjustmentMode == UIViewTintAdjustmentModeDimmed); + + NSMutableAttributedString *mutableAttributedString = [self.attributedText mutableCopy]; + for (TTTAttributedLabelLink *link in self.linkModels) { + NSDictionary *attributesToRemove = isInactive ? link.attributes : link.inactiveAttributes; + NSDictionary *attributesToAdd = isInactive ? link.inactiveAttributes : link.attributes; + + [attributesToRemove enumerateKeysAndObjectsUsingBlock:^(NSString *name, __unused id value, __unused BOOL *stop) { + if (NSMaxRange(link.result.range) <= mutableAttributedString.length) { + [mutableAttributedString removeAttribute:name range:link.result.range]; + } + }]; + + if (attributesToAdd) { + if (NSMaxRange(link.result.range) <= mutableAttributedString.length) { + [mutableAttributedString addAttributes:attributesToAdd range:link.result.range]; + } + } + } + + self.attributedText = mutableAttributedString; + + [self setNeedsDisplay]; +} + +- (UIView *)hitTest:(CGPoint)point + withEvent:(UIEvent *)event +{ + if (![self linkAtPoint:point] || !self.userInteractionEnabled || self.hidden || self.alpha < 0.01) { + return [super hitTest:point withEvent:event]; + } + + return self; +} + +#pragma mark - UIResponder + +- (BOOL)canBecomeFirstResponder { + return YES; +} + +- (BOOL)canPerformAction:(SEL)action + withSender:(__unused id)sender +{ +#if !TARGET_OS_TV + return (action == @selector(copy:)); +#else + return NO; +#endif +} + +- (void)touchesBegan:(NSSet *)touches + withEvent:(UIEvent *)event +{ + UITouch *touch = [touches anyObject]; + + self.activeLink = [self linkAtPoint:[touch locationInView:self]]; + + if (!self.activeLink) { + [super touchesBegan:touches withEvent:event]; + } +} + +- (void)touchesMoved:(NSSet *)touches + withEvent:(UIEvent *)event +{ + if (self.activeLink) { + UITouch *touch = [touches anyObject]; + + if (self.activeLink != [self linkAtPoint:[touch locationInView:self]]) { + self.activeLink = nil; + } + } else { + [super touchesMoved:touches withEvent:event]; + } +} + +- (void)touchesEnded:(NSSet *)touches + withEvent:(UIEvent *)event +{ + if (self.activeLink) { + if (self.activeLink.linkTapBlock) { + self.activeLink.linkTapBlock(self, self.activeLink); + self.activeLink = nil; + return; + } + + NSTextCheckingResult *result = self.activeLink.result; + self.activeLink = nil; + + switch (result.resultType) { + case NSTextCheckingTypeLink: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithURL:)]) { + [self.delegate attributedLabel:self didSelectLinkWithURL:result.URL]; + return; + } + break; + case NSTextCheckingTypeAddress: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithAddress:)]) { + [self.delegate attributedLabel:self didSelectLinkWithAddress:result.addressComponents]; + return; + } + break; + case NSTextCheckingTypePhoneNumber: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithPhoneNumber:)]) { + [self.delegate attributedLabel:self didSelectLinkWithPhoneNumber:result.phoneNumber]; + return; + } + break; + case NSTextCheckingTypeDate: + if (result.timeZone && [self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithDate:timeZone:duration:)]) { + [self.delegate attributedLabel:self didSelectLinkWithDate:result.date timeZone:result.timeZone duration:result.duration]; + return; + } else if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithDate:)]) { + [self.delegate attributedLabel:self didSelectLinkWithDate:result.date]; + return; + } + break; + case NSTextCheckingTypeTransitInformation: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithTransitInformation:)]) { + [self.delegate attributedLabel:self didSelectLinkWithTransitInformation:result.components]; + return; + } + default: + break; + } + + // Fallback to `attributedLabel:didSelectLinkWithTextCheckingResult:` if no other delegate method matched. + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithTextCheckingResult:)]) { + [self.delegate attributedLabel:self didSelectLinkWithTextCheckingResult:result]; + } + } else { + [super touchesEnded:touches withEvent:event]; + } +} + +- (void)touchesCancelled:(NSSet *)touches + withEvent:(UIEvent *)event +{ + if (self.activeLink) { + self.activeLink = nil; + } else { + [super touchesCancelled:touches withEvent:event]; + } +} + +#pragma mark - UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { + return [self containslinkAtPoint:[touch locationInView:self]]; +} + +#pragma mark - UILongPressGestureRecognizer + +- (void)longPressGestureDidFire:(UILongPressGestureRecognizer *)sender { + switch (sender.state) { + case UIGestureRecognizerStateBegan: { + CGPoint touchPoint = [sender locationInView:self]; + TTTAttributedLabelLink *link = [self linkAtPoint:touchPoint]; + + if (link) { + if (link.linkLongPressBlock) { + link.linkLongPressBlock(self, link); + return; + } + + NSTextCheckingResult *result = link.result; + + if (!result) { + return; + } + + switch (result.resultType) { + case NSTextCheckingTypeLink: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithURL:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithURL:result.URL atPoint:touchPoint]; + return; + } + break; + case NSTextCheckingTypeAddress: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithAddress:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithAddress:result.addressComponents atPoint:touchPoint]; + return; + } + break; + case NSTextCheckingTypePhoneNumber: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithPhoneNumber:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithPhoneNumber:result.phoneNumber atPoint:touchPoint]; + return; + } + break; + case NSTextCheckingTypeDate: + if (result.timeZone && [self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithDate:timeZone:duration:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithDate:result.date timeZone:result.timeZone duration:result.duration atPoint:touchPoint]; + return; + } else if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithDate:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithDate:result.date atPoint:touchPoint]; + return; + } + break; + case NSTextCheckingTypeTransitInformation: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithTransitInformation:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithTransitInformation:result.components atPoint:touchPoint]; + return; + } + default: + break; + } + + // Fallback to `attributedLabel:didLongPressLinkWithTextCheckingResult:atPoint:` if no other delegate method matched. + if ([self.delegate respondsToSelector:@selector(attributedLabel:didLongPressLinkWithTextCheckingResult:atPoint:)]) { + [self.delegate attributedLabel:self didLongPressLinkWithTextCheckingResult:result atPoint:touchPoint]; + } + } + break; + } + default: + break; + } +} + +#if !TARGET_OS_TV +#pragma mark - UIResponderStandardEditActions + +- (void)copy:(__unused id)sender { + [[UIPasteboard generalPasteboard] setString:self.text]; +} +#endif + +#pragma mark - NSCoding + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + + [coder encodeObject:@(self.enabledTextCheckingTypes) forKey:NSStringFromSelector(@selector(enabledTextCheckingTypes))]; + + [coder encodeObject:self.linkModels forKey:NSStringFromSelector(@selector(linkModels))]; + if ([NSMutableParagraphStyle class]) { + [coder encodeObject:self.linkAttributes forKey:NSStringFromSelector(@selector(linkAttributes))]; + [coder encodeObject:self.activeLinkAttributes forKey:NSStringFromSelector(@selector(activeLinkAttributes))]; + [coder encodeObject:self.inactiveLinkAttributes forKey:NSStringFromSelector(@selector(inactiveLinkAttributes))]; + } + [coder encodeObject:@(self.shadowRadius) forKey:NSStringFromSelector(@selector(shadowRadius))]; + [coder encodeObject:@(self.highlightedShadowRadius) forKey:NSStringFromSelector(@selector(highlightedShadowRadius))]; + [coder encodeCGSize:self.highlightedShadowOffset forKey:NSStringFromSelector(@selector(highlightedShadowOffset))]; + [coder encodeObject:self.highlightedShadowColor forKey:NSStringFromSelector(@selector(highlightedShadowColor))]; + [coder encodeObject:@(self.kern) forKey:NSStringFromSelector(@selector(kern))]; + [coder encodeObject:@(self.firstLineIndent) forKey:NSStringFromSelector(@selector(firstLineIndent))]; + [coder encodeObject:@(self.lineSpacing) forKey:NSStringFromSelector(@selector(lineSpacing))]; + [coder encodeObject:@(self.lineHeightMultiple) forKey:NSStringFromSelector(@selector(lineHeightMultiple))]; + [coder encodeUIEdgeInsets:self.textInsets forKey:NSStringFromSelector(@selector(textInsets))]; + [coder encodeInteger:self.verticalAlignment forKey:NSStringFromSelector(@selector(verticalAlignment))]; + + [coder encodeObject:self.attributedTruncationToken forKey:NSStringFromSelector(@selector(attributedTruncationToken))]; + + [coder encodeObject:NSStringFromUIEdgeInsets(self.linkBackgroundEdgeInset) forKey:NSStringFromSelector(@selector(linkBackgroundEdgeInset))]; + [coder encodeObject:self.attributedText forKey:NSStringFromSelector(@selector(attributedText))]; + [coder encodeObject:self.text forKey:NSStringFromSelector(@selector(text))]; +} + +- (id)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (!self) { + return nil; + } + + [self commonInit]; + + if ([coder containsValueForKey:NSStringFromSelector(@selector(enabledTextCheckingTypes))]) { + self.enabledTextCheckingTypes = [[coder decodeObjectForKey:NSStringFromSelector(@selector(enabledTextCheckingTypes))] unsignedLongLongValue]; + } + + if ([NSMutableParagraphStyle class]) { + if ([coder containsValueForKey:NSStringFromSelector(@selector(linkAttributes))]) { + self.linkAttributes = [coder decodeObjectForKey:NSStringFromSelector(@selector(linkAttributes))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(activeLinkAttributes))]) { + self.activeLinkAttributes = [coder decodeObjectForKey:NSStringFromSelector(@selector(activeLinkAttributes))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(inactiveLinkAttributes))]) { + self.inactiveLinkAttributes = [coder decodeObjectForKey:NSStringFromSelector(@selector(inactiveLinkAttributes))]; + } + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(links))]) { + NSArray *oldLinks = [coder decodeObjectForKey:NSStringFromSelector(@selector(links))]; + [self addLinksWithTextCheckingResults:oldLinks attributes:nil]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(linkModels))]) { + self.linkModels = [coder decodeObjectForKey:NSStringFromSelector(@selector(linkModels))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(shadowRadius))]) { + self.shadowRadius = [[coder decodeObjectForKey:NSStringFromSelector(@selector(shadowRadius))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(highlightedShadowRadius))]) { + self.highlightedShadowRadius = [[coder decodeObjectForKey:NSStringFromSelector(@selector(highlightedShadowRadius))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(highlightedShadowOffset))]) { + self.highlightedShadowOffset = [coder decodeCGSizeForKey:NSStringFromSelector(@selector(highlightedShadowOffset))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(highlightedShadowColor))]) { + self.highlightedShadowColor = [coder decodeObjectForKey:NSStringFromSelector(@selector(highlightedShadowColor))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(kern))]) { + self.kern = [[coder decodeObjectForKey:NSStringFromSelector(@selector(kern))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(firstLineIndent))]) { + self.firstLineIndent = [[coder decodeObjectForKey:NSStringFromSelector(@selector(firstLineIndent))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(lineSpacing))]) { + self.lineSpacing = [[coder decodeObjectForKey:NSStringFromSelector(@selector(lineSpacing))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(minimumLineHeight))]) { + self.minimumLineHeight = [[coder decodeObjectForKey:NSStringFromSelector(@selector(minimumLineHeight))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(maximumLineHeight))]) { + self.maximumLineHeight = [[coder decodeObjectForKey:NSStringFromSelector(@selector(maximumLineHeight))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(lineHeightMultiple))]) { + self.lineHeightMultiple = [[coder decodeObjectForKey:NSStringFromSelector(@selector(lineHeightMultiple))] floatValue]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(textInsets))]) { + self.textInsets = [coder decodeUIEdgeInsetsForKey:NSStringFromSelector(@selector(textInsets))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(verticalAlignment))]) { + self.verticalAlignment = [coder decodeIntegerForKey:NSStringFromSelector(@selector(verticalAlignment))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(attributedTruncationToken))]) { + self.attributedTruncationToken = [coder decodeObjectForKey:NSStringFromSelector(@selector(attributedTruncationToken))]; + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(linkBackgroundEdgeInset))]) { + self.linkBackgroundEdgeInset = UIEdgeInsetsFromString([coder decodeObjectForKey:NSStringFromSelector(@selector(linkBackgroundEdgeInset))]); + } + + if ([coder containsValueForKey:NSStringFromSelector(@selector(attributedText))]) { + self.attributedText = [coder decodeObjectForKey:NSStringFromSelector(@selector(attributedText))]; + } else { + self.text = super.text; + } + + return self; +} + +@end + +#pragma mark - TTTAttributedLabelLink + +@implementation TTTAttributedLabelLink + +- (instancetype)initWithAttributes:(NSDictionary *)attributes + activeAttributes:(NSDictionary *)activeAttributes + inactiveAttributes:(NSDictionary *)inactiveAttributes + textCheckingResult:(NSTextCheckingResult *)result { + + if ((self = [super init])) { + _result = result; + _attributes = [attributes copy]; + _activeAttributes = [activeAttributes copy]; + _inactiveAttributes = [inactiveAttributes copy]; + } + + return self; +} + +- (instancetype)initWithAttributesFromLabel:(TTTAttributedLabel*)label + textCheckingResult:(NSTextCheckingResult *)result { + + return [self initWithAttributes:label.linkAttributes + activeAttributes:label.activeLinkAttributes + inactiveAttributes:label.inactiveLinkAttributes + textCheckingResult:result]; +} + +#pragma mark - Accessibility + +- (NSString *) accessibilityValue { + if ([_accessibilityValue length] == 0) { + switch (self.result.resultType) { + case NSTextCheckingTypeLink: + _accessibilityValue = self.result.URL.absoluteString; + break; + case NSTextCheckingTypePhoneNumber: + _accessibilityValue = self.result.phoneNumber; + break; + case NSTextCheckingTypeDate: + _accessibilityValue = [NSDateFormatter localizedStringFromDate:self.result.date + dateStyle:NSDateFormatterLongStyle + timeStyle:NSDateFormatterLongStyle]; + break; + default: + break; + } + } + + return _accessibilityValue; +} + +#pragma mark - NSCoding + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.result forKey:NSStringFromSelector(@selector(result))]; + [aCoder encodeObject:self.attributes forKey:NSStringFromSelector(@selector(attributes))]; + [aCoder encodeObject:self.activeAttributes forKey:NSStringFromSelector(@selector(activeAttributes))]; + [aCoder encodeObject:self.inactiveAttributes forKey:NSStringFromSelector(@selector(inactiveAttributes))]; + [aCoder encodeObject:self.accessibilityValue forKey:NSStringFromSelector(@selector(accessibilityValue))]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + if ((self = [super init])) { + _result = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(result))]; + _attributes = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(attributes))]; + _activeAttributes = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(activeAttributes))]; + _inactiveAttributes = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(inactiveAttributes))]; + self.accessibilityValue = [aDecoder decodeObjectForKey:NSStringFromSelector(@selector(accessibilityValue))]; + } + + return self; +} + +@end + +#pragma mark - + +static inline CGColorRef CGColorRefFromColor(id color) { + return [color isKindOfClass:[UIColor class]] ? [color CGColor] : (__bridge CGColorRef)color; +} + +static inline CTFontRef CTFontRefFromUIFont(UIFont * font) { + CTFontRef ctfont = CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL); + return CFAutorelease(ctfont); +} + +static inline NSDictionary * convertNSAttributedStringAttributesToCTAttributes(NSDictionary *attributes) { + if (!attributes) return nil; + + NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionary]; + + NSDictionary *NSToCTAttributeNamesMap = @{ + NSFontAttributeName: (NSString *)kCTFontAttributeName, + NSBackgroundColorAttributeName: (NSString *)kTTTBackgroundFillColorAttributeName, + NSForegroundColorAttributeName: (NSString *)kCTForegroundColorAttributeName, + NSUnderlineColorAttributeName: (NSString *)kCTUnderlineColorAttributeName, + NSUnderlineStyleAttributeName: (NSString *)kCTUnderlineStyleAttributeName, + NSStrokeWidthAttributeName: (NSString *)kCTStrokeWidthAttributeName, + NSStrokeColorAttributeName: (NSString *)kCTStrokeWidthAttributeName, + NSKernAttributeName: (NSString *)kCTKernAttributeName, + NSLigatureAttributeName: (NSString *)kCTLigatureAttributeName + }; + + [attributes enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { + key = [NSToCTAttributeNamesMap objectForKey:key] ? : key; + + if (![NSMutableParagraphStyle class]) { + if ([value isKindOfClass:[UIFont class]]) { + value = (__bridge id)CTFontRefFromUIFont(value); + } else if ([value isKindOfClass:[UIColor class]]) { + value = (__bridge id)((UIColor *)value).CGColor; + } + } + + [mutableAttributes setObject:value forKey:key]; + }]; + + return [NSDictionary dictionaryWithDictionary:mutableAttributes]; +} diff --git a/ProductApp/ProductApp/BaseControl/UserInfo/UserInfoModel.h b/ProductApp/ProductApp/BaseControl/UserInfo/UserInfoModel.h index e2e42fe..9522693 100644 --- a/ProductApp/ProductApp/BaseControl/UserInfo/UserInfoModel.h +++ b/ProductApp/ProductApp/BaseControl/UserInfo/UserInfoModel.h @@ -50,6 +50,9 @@ NS_ASSUME_NONNULL_BEGIN ///1学生 2家长 3老师 @property (nonatomic , strong) NSString *shenfen; +///余额 +@property (nonatomic , strong) NSString *balance; + +(void)setLoingState:(NSString *)value; +(void)setToken:(NSString *)value; +(void)setName:(NSString *)value; diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyAudioSession.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyAudioSession.h new file mode 100644 index 0000000..e3b975e --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyAudioSession.h @@ -0,0 +1,35 @@ +// +// IFlyAudioSession.h +// MSCDemo +// +// Created by AlexHHC on 1/9/14. +// +// + +#import + +/** + * 音频环境初始化,设置AVAudioSession的Category属性。 + */ +@interface IFlyAudioSession : NSObject + +/** + * 初始化播音环境,主要用于合成播放器。 + * + * 此接口主要根据原来的音频环境,重新优化设置AVAudioSession的Category属性值。
+ * 若原来的Category属性值为AVAudioSessionCategoryPlayAndRecord,则添加AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionAllowBluetooth选项;若为其他Category属性值且isMPCenter为NO,则设置Category属性值为AVAudioSessionCategoryPlayback,选项为AVAudioSessionCategoryOptionMixWithOthers;若为其他Category属性值且isMPCenter为YES,则保持原来的设置,不做任何更改。 + * + * @param isMPCenter 是否初始化MPPlayerCenter:0不初始化,1初始化。此参数只在AVAudioSession的Category属性值不为AVAudioSessionCategoryPlayAndRecord时设置有效。 + */ ++(void) initPlayingAudioSession:(BOOL)isMPCenter; + +/** + * 初始化录音环境,主要用于识别录音器。 + * + * 设置AVAudioSession的Category属性值为AVAudioSessionCategoryPlayAndRecord,选项为AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionAllowBluetooth。 + * + * @return 成功返回YES,失败返回NO + */ ++(BOOL) initRecordingAudioSession; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyContact.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyContact.h new file mode 100644 index 0000000..a251f87 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyContact.h @@ -0,0 +1,24 @@ +// +// IFlyContact.h +// msc +// +// Created by ypzhao on 13-3-1. +// Copyright (c) 2013年 IFLYTEK. All rights reserved. +// + +#import + +/*! + * 此接口为获取通信录中的联系人。
+ * 获取联系人是为了在进行语音识别时(sms)能更好的识别出您说的人名,联系人上传是属于个性化的一部分。 + */ +@interface IFlyContact : NSObject + +/*! + * 获取联系人。
+ * 调用此方法需要添加 AddressBook.framework 和 Contacts.framework到工程中,调用此方法后可以直接将通信录中的联系人转化为语音云识别的数据结构。您可以将获取的数据通过IFlyDataUploader类,上传到语音云,我们只获取通信录中的人名。 + * + * @return 返回联系人信息 + */ +- (NSString *) contact; +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDataUploader.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDataUploader.h new file mode 100644 index 0000000..5eb0584 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDataUploader.h @@ -0,0 +1,54 @@ +// +// IFlyDataUploader.h +// MSC +// +// Created by ypzhao on 13-4-8. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + + +@class IFlySpeechError; + +/*! + * 数据上传类,主要用于上传语法文件或上传联系人、词表等个性化数据。 + */ +@interface IFlyDataUploader : NSObject + +/*! + * 数据名称 + */ +@property(nonatomic,copy) NSString *dataName; +/*! + * 数据 + */ +@property(nonatomic,copy) NSString *data; + +/*! + * 上传完成回调 + * + * @param result 结果 + * @param error 错误码 + */ +typedef void(^IFlyUploadDataCompletionHandler)(NSString* result,IFlySpeechError * error); + +/*! + * 上传数据 + * 此函数用于上传数据,下载的过程是**异步**的。 + * + * @param completionHandler -[in] 上传完成回调 + * @param name -[in] 上传的内容名称,名称最好和你要上传的数据内容相关,不可以为nil + * @param data -[in] 上传的数据,以utf8编码,不可以为nil + */ +- (void) uploadDataWithCompletionHandler:(IFlyUploadDataCompletionHandler)completionHandler name:(NSString *)name data:(NSString *)data; + +/*! + * 设置上传数据参数 + * + * @param parameter 参数值 + * @param key 参数名 + */ +-(void) setParameter:(NSString*) parameter forKey:(NSString*) key; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDebugLog.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDebugLog.h new file mode 100644 index 0000000..9cf2987 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyDebugLog.h @@ -0,0 +1,37 @@ +// +// IFlyDebugLog.h +// MSC + +// description: 程序中的log处理类 + +// Created by ypzhao on 12-11-22. +// Copyright (c) 2012年 iflytek. All rights reserved. +// + +#import + +/*! + * 调试信息 + */ +@interface IFlyDebugLog : NSObject + +/*! + * 打印调试信息 + * + * @param format -[in] 要打印的内容格式 + * @param ... -[in] 要打印的内容 + */ ++ (void) showLog:(NSString *)format, ...; + +/*! + * 将log写入文件中 + */ ++ (void) writeLog; + +/*! + * 设置是否显示log + * + * @param showLog YES:显示;NO:不显示 + */ ++ (void) setShowLog:(BOOL) showLog; +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVDelegate.h new file mode 100644 index 0000000..814b676 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVDelegate.h @@ -0,0 +1,48 @@ +// +// IFlyISVDelegate.h +// msc_UI +// +// Created by admin on 14-9-15. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + + +#import + +@class IFlySpeechError; + +/*! + * 声纹回调协议 + */ +@protocol IFlyISVDelegate + +/*! + * 声纹结果回调 + * + * @param dic 结果 + */ +-(void) onResult:(NSDictionary *)dic; + +/*! + * 错误码回调 + * + * @param errorCode 错误码 + */ +-(void) onCompleted:(IFlySpeechError *) errorCode; + +@optional + +/*! + * 等待结果 + */ +-(void) onRecognition; + +/*! + * 音量改变回调 + * + * @param volume 音量值 + */ +-(void) onVolumeChanged: (int)volume; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVRecognizer.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVRecognizer.h new file mode 100644 index 0000000..a8e52b7 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyISVRecognizer.h @@ -0,0 +1,132 @@ +// +// IFlyISVRecognizer.h +// ISV +// +// Created by wangdan on 14-9-6. +// Copyright (c) 2014年 IFlyTEK. All rights reserved. +// + + +#import +#import "IFlyISVDelegate.h" + +/** + * 声纹接口类 + */ +@interface IFlyISVRecognizer : NSObject +{ + +} + +/*! + * The delegate of FlyISVRecognizer responsing to IFlyISVDelegate. + */ +@property (assign) id delegate; + + +/*! + * FlyISVRecognizer is a kind of Singleton calss.The function can be used as below:
+ * IFLyISVRecognizer *recognizer=[IFlyISVRecognizer creteRecognizer: self]; + */ ++(instancetype) sharedInstance; + + +/*! + * Genrerate a serial number password
+ * Princeple:
+ * 1.Number serial has no 1 in itself;
+ * 2.The nuber serial has no same number("98765432"is right while "99876543" is wrong) + * + * @param length the serial number's length,length of "98765432" is 8,generally length is 8 and other value is forbidden + */ +-(NSString*) generatePassword:(int)length; + + + +/*! + * Used to get password from server + * + * @param pwdt when pwdt is 1,the function will return chinese text;while pwdt is 2, the funciton will return number serial + */ +-(NSArray*) getPasswordList:(int)pwdt; + + +/*! + * Used to judge if the engine is running in listenning + * + * @return YES: the engine is listenning;
No : the engine is not listenning + */ +-(BOOL) isListening; + + + +/*! + * Used to query or delete the voiceprint model in server + * + * @param cmd "del": delete model;
"que": query model; + * @param authid: user id ,can be @"tianxia" or other; + * @param pwdt voiceprint type
+ * 1: fixed txt voiceprint code ,like @"我的地盘我做主";
+ * 2: free voiceprint code , user can speek anything,but 5 times trainning the speech shall be same;
+ * 3: number serial voiceprint code ,like @"98765432" and so on. + * @param ptxt voiceprint txt,only fixed voiceprint and number serial have this,in free voiceprint model this param shall be set nil. + * @param vid another voiceprint type model,user can use this to query or delete model in server can be @"jakillasdfasdjjjlajlsdfhdfdsadff",totally 32 bits;
+ * NOTES:
+ * when vid is not nil,then the server will judge the vid first; while the vid is nil, server can still query or delete the voiceprint model by other params. + */ +-(BOOL) sendRequest:(NSString*)cmd authid:(NSString *)auth_id pwdt:(int)pwdt ptxt:(NSString *)ptxt vid:(NSString *)vid err:(int *)err; + + +/*! + * Set the voiceprint params + * + * | key | value | + * |:---------------:|:-------------------------------------------------:| + * | sst | @"train" or @"verify" | + * | auth_id | @"tianxia" or other | + * | sub | @"ivp" | + * | ptxt | | + * | rgn | @"5" | + * | pwdt | @"1",or @"2", or @"3" | + * | auf | @"audio/L16;rate=16000" or @"audio/L16;rate=8000" | + * | vad_enable | @"1" or @"0" | + * | vad_timeout | @"3000" | + * | vad_speech_tail | @"100" | + * + * @param value 参数值 + * @param key 参数类型 + * + * @return 设置成功返回YES,失败返回NO + */ +-(BOOL) setParameter:(NSString *)value forKey:(NSString *)key; + + + +/*! + * Get the voiceprint params used the same as function of setParameter + */ +-(NSString*) getParameter:(NSString *)key; + + +/*! + * Start recording + */ +-(void) startListening; + + +/*! + * Stop recording + */ +-(void) stopListening; + + +/*! + * Cancel recording,like function stopListening + */ +-(void) cancel; /* cancel recognization */ + + + + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityResult.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityResult.h new file mode 100644 index 0000000..c43432a --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityResult.h @@ -0,0 +1,37 @@ +// +// IFlyIdentityResult.h +// IFlyMSC +// +// Created by 张剑 on 15/5/14. +// Copyright (c) 2015年 iflytek. All rights reserved. +// + +#import + +/** + * 身份验证结果类 + */ +@interface IFlyIdentityResult : NSObject + +/** + * json字符串格式结果 + */ +@property(nonatomic,retain)NSString* result; + +/** + * 创建身份验证结果类实例 + * + * @param jsonString json字符串 + * + * @return 身份验证结果类实例 + */ ++(instancetype)identityResultWithString:(NSString*)jsonString; + +/** + * 返回字典格式的结果 + * + * @return 字典格式的结果 + */ +-(NSDictionary*)dictionaryResults; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifier.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifier.h new file mode 100644 index 0000000..be23ffa --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifier.h @@ -0,0 +1,176 @@ +// +// IFlyIdentityVerifier.h +// IFlyMSC +// +// Created by 张剑 on 15/4/22. +// Copyright (c) 2015年 iflytek. All rights reserved. +// + + +#import +#import "IFlyIdentityVerifierDelegate.h" + +/** + * 身份验证功能类 + */ +@interface IFlyIdentityVerifier : NSObject + +/*! + * 设置委托对象 + */ +@property (nonatomic, assign) id delegate; + +/** + * 返回身份验证对象的单例 + * + * @return 身份验证对象的单例 + */ ++ (instancetype) sharedInstance; + +/** + * 销毁身份验证对象单例。 + * + * @return 成功返回YES,失败返回NO。 + */ ++ (void)purgeSharedInstance; + +/** + * 设置参数 + * + * @param value 参数值 + * @param key 参数名 + * + * @return 设置的参数和取值正确返回YES,失败返回NO + */ +- (BOOL)setParameter:(NSString *)value forKey:(NSString *)key; + +/** + * 开始会话 + * 在这之后会开始各项业务。 + */ +- (void)startWorking; + +/* + * | ------------- |----------------------------------------------------------- + * | ifr 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | data_format |数据格式:即图片格式,支持jpg(默认),gif + * | ------------- |----------------------------------------------------------- + * | data_encoding |数据压缩编码:即图片压缩编码,支持raw(不压缩,默认值) + * | ------------- |----------------------------------------------------------- + * | wtt |等待超时时间: 支持大于0的整数,默认为3000ms + * | ------------- |----------------------------------------------------------- + * | ivp 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | rgn |训练次数:取值2~9.无默认值,必须明确指定。 + * | ------------- |----------------------------------------------------------- + * | |声纹确认门限值,验证得分>=tsd验证通过,否则验证失败(该参数目前不支持, + * | tsd |作为保留参数。)却只范围:0~100. + * | ------------- |----------------------------------------------------------- + * | ptxt |密码文本。从服务端下载,比如数字密码所需要的数字串。 + * | ------------- |----------------------------------------------------------- + * | pwdt |密码类型。取值:1(文本密码),2(自由说),3(数字密码). + * | ------------- |----------------------------------------------------------- + * | fin |取消注册。取值:0(不取消,即不生效),1(取消本次注册). + * | ------------- |----------------------------------------------------------- + * | wtt |等待超时时间:描述客户端等待结果的超时时间 + * | ------------- |----------------------------------------------------------- + * | vad_enable |VAD功能开关。是否启用VAD处理,取值:1(开启,默认),0(不开启)。 + * | ------------- |----------------------------------------------------------- + * | |头部静音最大长度。如果静音长度超过此值,则认为用户此次无有效音频输入。 + * | vad_bos |此参数仅在打开VAD功能时生效。(云端暂时没有)。取值:0~30000ms, + * | |默认为10000ms + * | ------------- |----------------------------------------------------------- + * | |尾部静音长度。如果尾部静音长度超过了此值,则认为音频已经结束。 + * | |此参数仅在打开VAD功能时生效。(云端暂时没有)。取值:0~30000ms, + * | vad_eos |默认为2000ms + * | ------------- |----------------------------------------------------------- + * | data_encoding |数据压缩编码,音频压缩编码。 + * | ------------- |----------------------------------------------------------- + * | data_format |在声纹业务中为音频采样率,取值:16000(默认),8000 + * | ------------- |----------------------------------------------------------- + * | ipt 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | scope |操作范围 person,group + * | ------------- |----------------------------------------------------------- + * | group_id |指定鉴别的组数字或者字符串,唯一值 不为空 + * | ------------- |----------------------------------------------------------- + * | |组名称 “”或者不能包含^@,&=*'"等非法字符,且长度不得超过255. + * | group_name |此参数可以为空,对于group_name约束不在云端控制,由前段控制 + * | ------------- |----------------------------------------------------------- + * | topc |[top candidates],返回得分最高的候选人数目 取值1-5 默认是1. + * | | 可以开放由用户设置,最大topc值为5 + * | ------------- |----------------------------------------------------------- + * + */ + +/** + * 写入子业务数据、或者进行模型操作、下载密码。 + * + * @param ssub 子业务名 + * @param data 数据 + * @param offset 偏移量 + * @param length 长度 + * @param params 参数 + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
*ifr参数描述
data_format数据格式:即图片格式,支持jpg(默认),gif
data_encoding数据压缩编码:即图片压缩编码,支持raw(不压缩,默认值)
wtt等待超时时间: 支持大于0的整数,默认为3000ms
*ivp参数描述
rgn训练次数:取值2~9.无默认值,必须明确指定。
tsd声纹确认门限值,验证得分>=tsd验证通过,否则验证失败(该参数目前不支持,作为保留参数。)却只范围:0~100.
ptxt密码文本。从服务端下载,比如数字密码所需要的数字串。
pwdt密码类型。取值:1(文本密码),2(自由说),3(数字密码).
fin取消注册。取值:0(不取消,即不生效),1(取消本次注册).
wtt等待超时时间:描述客户端等待结果的超时时间.
vad_enableVAD功能开关。是否启用VAD处理,取值:1(开启,默认),0(不开启)。
vad_bos头部静音最大长度。如果静音长度超过此值,则认为用户此次无有效音频输入。
此参数仅在打开VAD功能时生效。(云端暂时没有)。
取值:0~30000ms,默认为10000ms
vad_eos尾部静音长度。如果尾部静音长度超过了此值,则认为音频已经结束。
此参数仅在打开VAD功能时生效。(云端暂时没有)。
取值:0~30000ms,默认为2000ms
data_encoding数据压缩编码,音频压缩编码。
data_format在声纹业务中为音频采样率,取值:16000(默认),8000
*ipt参数描述
scope操作范围 person,group
group_id指定鉴别的组数字或者字符串,唯一值 不为空
group_name组名称 “”或者不能包含^@,&=*'"等非法字符,且长度不得超过255.此参数可以为空,对于group_name约束不在云端控制,由前段控制
topc组名称[top candidates],返回得分最高的候选人数目 取值1-5 默认是1.可以开放由用户设置,最大topc值为5
+ */ +-(void)write:(NSString*)ssub data:(NSData*)data offset:(int)offset length:(int)length withParams:(NSString*)params; + +/** + * 停止子业务数据写入 + * + * @param ssub 子业务名:ivp,ifr,ipt + */ +-(void)stopWrite:(NSString*)ssub; + +/** + * 执行模型查询、删除和声纹密码下载等操作 + * *注意此方法不能与startWorking方法同时使用。 + * + * @param ssub 子业务类型、可选值:ivp(声纹)、ifr(人脸)、ipt(鉴别) + * @param cmd 操作命令,可选值:query、delete、download、add + * @param params 子业务参数,参见write:data:offset:length:withParams: + */ +-(void)execute:(NSString*)ssub cmd:(NSString*)cmd params:(NSString*)params; + +/** + * 取消本次会话 + */ +- (void)cancel; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifierDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifierDelegate.h new file mode 100644 index 0000000..6daedef --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyIdentityVerifierDelegate.h @@ -0,0 +1,47 @@ +// +// IFlyIdentityVerifierDelegate.h +// IFlyMSC +// +// Created by 张剑 on 15/4/22. +// Copyright (c) 2015年 iflytek. All rights reserved. +// + + + +#import + +@class IFlySpeechError; +@class IFlyIdentityResult; + +/** + * 身份验证功能类回调 + */ +@protocol IFlyIdentityVerifierDelegate + +/*! + * 错误回调 + * + * @param error 错误描述类 + */ +- (void)onCompleted:(IFlySpeechError *)error; + +/*! + * 结果回调 + * + * @param results -[out] 结果。 + * @param isLast -[out] 是否最后一条结果 + */ +- (void)onResults:(IFlyIdentityResult *)results isLast:(BOOL)isLast; + +/** + * 扩展接口,用于抛出音量和vad_eos消息 + * + * @param eventType 消息类型 + * @param arg1 eventType为 Event_volume 时 arg1为音量值 + * @param arg2 参数2 + * @param obj 扩展参数 + */ +- (void)onEvent:(int)eventType arg1:(int)arg1 arg2:(int)arg2 extra:(id)obj; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyMSC.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyMSC.h new file mode 100644 index 0000000..f8d81ff --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyMSC.h @@ -0,0 +1,40 @@ +// +// IFlyMSC.h +// msc +// +// Created by 张剑 on 15/1/14. +// Copyright (c) 2015年 iflytek. All rights reserved. +// + +#ifndef MSC_IFlyMSC_h +#define MSC_IFlyMSC_h + +#import "IFlyAudioSession.h" +#import "IFlyDataUploader.h" +#import "IFlyDebugLog.h" +#import "IFlyIdentityVerifier.h" +#import "IFlyIdentityResult.h" +#import "IFlyIdentityVerifierDelegate.h" +#import "IFlyISVDelegate.h" +#import "IFlyISVRecognizer.h" +#import "IFlyRecognizerView.h" +#import "IFlyRecognizerViewDelegate.h" +#import "IFlyResourceUtil.h" +#import "IFlySetting.h" +#import "IFlySpeechConstant.h" +#import "IFlySpeechError.h" +#import "IFlySpeechEvaluator.h" +#import "IFlySpeechEvaluatorDelegate.h" +#import "IFlySpeechEvent.h" +#import "IFlySpeechRecognizer.h" +#import "IFlySpeechRecognizerDelegate.h" +#import "IFlySpeechSynthesizer.h" +#import "IFlySpeechSynthesizerDelegate.h" +#import "IFlySpeechUtility.h" +#import "IFlyUserWords.h" +#import "IFlyPcmRecorder.h" +#import "IFlyVerifierUtil.h" +#import "IFlyVoiceWakeuper.h" +#import "IFlyVoiceWakeuperDelegate.h" + +#endif diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyPcmRecorder.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyPcmRecorder.h new file mode 100644 index 0000000..1d624b3 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyPcmRecorder.h @@ -0,0 +1,116 @@ +// +// IFlyPcmRecorder.h +// MSC + +// description: + +// Created by ypzhao on 12-11-15. +// Copyright (c) 2012年 iflytek. All rights reserved. +// + +#import + +#import +#import +#import +#import +#import + + +@class IFlyPcmRecorder; + +/*! + * 录音协议 + */ +@protocol IFlyPcmRecorderDelegate + +/*! + * 回调音频数据 + * + * @param buffer 音频数据 + * @param size 表示音频的长度 + */ +- (void) onIFlyRecorderBuffer: (const void *)buffer bufferSize:(int)size; + +/*! + * 回调音频的错误码 + * + * @param recoder 录音器 + * @param error 错误码 + */ +- (void) onIFlyRecorderError:(IFlyPcmRecorder*)recoder theError:(int) error; + +@optional + +/*! + * 回调录音音量 + * + * @param power 音量值 + */ +- (void) onIFlyRecorderVolumeChanged:(int) power; + +@end + + +/*! + * 录音器控件 + */ +@interface IFlyPcmRecorder : NSObject + +/*! + * 录音委托对象 + */ +@property (nonatomic,assign) id delegate; + +/*! + * 用于设置是否在录音结束后发送Deactive通知,默认是YES:发送 + */ +@property (nonatomic,assign) BOOL isNeedDeActive; + +/*! + * 单例模式 + * + * @return 返回录音对象单例 + */ ++ (instancetype) sharedInstance; + +/*! + * 开始录音 + * + * @return 开启录音成功返回YES,否则返回NO + */ +- (BOOL) start; + +/*! + * 停止录音 + */ +- (void) stop; + +/*! + * 设置音频采样率 + * + * @param rate -[in] 采样率,8k/16k + */ +- (void) setSample:(NSString *) rate; + +/*! + * 设置录音音量回调时间间隔参数 + */ +- (void) setPowerCycle:(float) cycle; + +/*! + * 保存录音 + * + * @param savePath 音频保存路径 + */ +-(void) setSaveAudioPath:(NSString *)savePath; + +/*! + * 录音器是否完成 + * + * @return 录音器完全结束返回YES,否则返回NO + */ +-(BOOL) isCompleted; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerView.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerView.h new file mode 100644 index 0000000..483a217 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerView.h @@ -0,0 +1,134 @@ +// +// IFlyRecognizerView.h +// MSC +// +// Created by admin on 13-4-16. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + + +@protocol IFlyRecognizerViewDelegate ; + +/*! + * 语音识别控件
+ * 录音时触摸控件结束录音,开始识别(相当于旧版的停止);触摸其他位置,取消录音,结束会话(取消)
+ * 出错时触摸控件,重新开启会话(相当于旧版的再说一次);触摸其他位置,取消录音,结束会话(取消) + * + */ +@interface IFlyRecognizerView : UIView + +/*! + * 设置委托对象 + */ +@property(nonatomic,assign)id delegate; + +/*! + * 初始化控件 + * + * @param origin 控件左上角的坐标 + * + * @return IFlyRecognizerView 对象 + */ +- (id)initWithOrigin:(CGPoint)origin; + +/*! + * 初始化控件 + * + * @param center 控件中心的坐标 + * + * @return IFlyRecognizerView 对象 + */ +- (id) initWithCenter:(CGPoint)center; + +/*! + * 设置横竖屏自适应 + * + * @param autoRotate 默认值YES,横竖屏自适应 + */ +- (void) setAutoRotate:(BOOL)autoRotate; + +/* + * | ------------- |----------------------------------------------------------- + * | 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | domain |应用的领域: 取值为:iat、search、video、poi、music、asr; + * | | iat:普通文本听写; + * | | search:热词搜索; + * | | video:视频音乐搜索; + * | | asr:关键词识别; + * | ------------- |----------------------------------------------------------- + * | vad_bos |前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms; + * | | engine指定iat识别默认值为5000; + * | | 其他情况默认值为 4000,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | vad_eos |后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, + * | | 自动停止录音;单位:ms; + * | | sms 识别默认值为 1800; + * | | 其他默认值为 700,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | sample_rate |采样率:目前支持的采样率设置有 16000 和 8000。 + * | ------------- |----------------------------------------------------------- + * | asr_ptt |标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。 + * | ------------- |----------------------------------------------------------- + * | result_type |返回结果的数据格式: 可设置为json,xml,plain,默认为json。 + * | ------------- |----------------------------------------------------------- + * | grammarID |识别的语法id: 只针对 domain 设置为”asr”的应用。 + * | ------------- |----------------------------------------------------------- + * | asr_audio_path|音频文件名: 设置此参数后,将会自动保存识别的录音文件。 + * | | 路径为Documents/(指定值)。 + * | | 不设置或者设置为nil,则不保存音频。 + * | ------------- |----------------------------------------------------------- + * | params |扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。 + * | ------------- |----------------------------------------------------------- + * + */ + +/*! + * 设置识别引擎的参数 + * + * 识别的引擎参数(key)取值如下:
+ * + * | 参数 | 描述 | + * |-----------------|-------------------------------------------------------| + * | domain | 应用的领域: 取值为:iat、search、video、poi、music、asr;
iat:普通文本听写;
search:热词搜索;
video:视频音乐搜索;
asr:关键词识别;| + * | vad_bos | 前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms;
engine指定iat识别默认值为5000;
其他情况默认值为 4000,范围 0-10000。| + * | vad_eos | 后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入,自动停止录音;单位:ms;
sms 识别默认值为 1800;
其他默认值为 700,范围 0-10000。| + * | sample_rate | 采样率:目前支持的采样率设置有 16000 和 8000。| + * | asr_ptt | 标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。| + * | result_type | 返回结果的数据格式: 可设置为json,xml,plain,默认为json。| + * | grammarID | 识别的语法id: 只针对 domain 设置为”asr”的应用。| + * | asr_audio_path | 音频文件名: 设置此参数后,将会自动保存识别的录音文件。
路径为Documents/(指定值)。
不设置或者设置为nil,则不保存音频。| + * | params | 扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。| + * + * @param value 参数对应的取值 + * @param key 识别引擎参数 + * + * @return 成功返回YES;失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 获取识别引擎参数 + * + * @param key 参数key + * + * @return 参数值 + */ +-(NSString*) parameterForKey:(NSString *)key; + +/*! + * 开始识别 + * + * @return 成功返回YES;失败返回NO + */ +- (BOOL)start; + +/*! + * 取消本次识别 + */ +- (void)cancel; + + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerViewDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerViewDelegate.h new file mode 100644 index 0000000..c05bce6 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyRecognizerViewDelegate.h @@ -0,0 +1,36 @@ +// +// IFlyRecognizerDelegate.h +// MSC +// +// Created by admin on 13-4-16. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + +@class IFlyRecognizerView; +@class IFlySpeechError; + +/*! + * 识别回调委托 + */ +@protocol IFlyRecognizerViewDelegate + +/*! + * 回调返回识别结果 + * + * @param resultArray 识别结果,NSArray的第一个元素为NSDictionary,NSDictionary的key为识别结果,sc为识别结果的置信度 + * @param isLast -[out] 是否最后一个结果 + */ +- (void)onResult:(NSArray *)resultArray isLast:(BOOL) isLast; + +/*! + * 识别结束回调 + * + * @param error 识别结束错误码 + */ +- (void)onCompleted: (IFlySpeechError *) error; + +@optional + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyResourceUtil.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyResourceUtil.h new file mode 100644 index 0000000..c824a63 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyResourceUtil.h @@ -0,0 +1,90 @@ +// +// IFlyResourceUtil.h +// MSCDemo +// +// Created by admin on 14-6-20. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + +#import + +/*! + * 资源工具类 + */ +@interface IFlyResourceUtil : NSObject + +/*! + * 获取通过MSPSetParam,启动引擎的标识 + * + * @return 通过MSPSetParam,启动引擎的标识 + */ ++(NSString*) ENGINE_START; + +/*! + * 获取通过MSPSetParam,销毁引擎的标识 + * + * @return 通过MSPSetParam,销毁引擎的标识 + */ ++(NSString*) ENGINE_DESTROY; + +/*! + * 获取识别引擎的资源目录标识 + * + * @return 识别引擎的资源目录标识 + */ ++(NSString*) ASR_RES_PATH; + +/*! + * 得到语法构建目录 + * + * @return 语法构建目录 + */ ++(NSString*) GRM_BUILD_PATH; + +/*! + * 获取合成引擎的资源目录标识,同时需要先传入voice_name方可生效 + * + * @return 合成引擎的资源目录标识,同时需要先传入voice_name方可生效 + */ ++(NSString*) TTS_RES_PATH; + +/*! + * 获取唤醒资源的资源目录标识 + * + * @return 唤醒资源的资源目录标识 + */ ++(NSString*) IVW_RES_PATH; + +/*! + * 语法类型 + * + * @return 语法类型 + */ ++(NSString*) GRAMMARTYPE; + +/*! + * 语记SDK专用参数,用于设置本地默认资源路径 + * + * @return 本地默认资源路径key字符串 + */ ++(NSString*) PLUS_LOCAL_DEFAULT_RES_PATH; + +#pragma mark - +/*! + * 资源存放路径 + * + * @param path 设置的路径 + * + * @return 资源目录 + */ ++(NSString*) generateResourcePath:(NSString *)path; + +/** + * 获得离线发音人对应的id + * + * @param voiceName 发音人名称 + * + * @return 有,发音人对应的id;无,返回nil + */ ++(NSString*) identifierForVoiceName:(NSString*)voiceName; +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySetting.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySetting.h new file mode 100644 index 0000000..2054da6 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySetting.h @@ -0,0 +1,88 @@ +// +// IFlySetting.h +// MSC +// +// Created by iflytek on 13-4-12. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + +/*! + * 日志打印等级 + */ +typedef NS_OPTIONS(NSInteger, LOG_LEVEL){ + /*! + * 全部打印 + */ + LVL_ALL = -1, + /*! + * 高,异常分析需要的级别 + */ + LVL_DETAIL = 31, + /*! + * 中,打印基本日志信息 + */ + LVL_NORMAL = 15, + /*! + * 低,只打印主要日志信息 + */ + LVL_LOW = 7, + /*! + * 不打印 + */ + LVL_NONE = 0 +}; + +/*! + * 此接口为iflyMSC sdk 配置接口。
+ * 可以获取版本号,设置日志打印等级等 + */ +@interface IFlySetting : NSObject + +/*! + * 获取版本号 + * + * @return 版本号 + */ ++ (NSString *) getVersion; + +/*! + * 获取日志等级 + * + * @return 返回日志等级 + */ ++ (LOG_LEVEL) logLvl; + +/*! + * 是否打印控制台log
+ * 在软件发布时,建议关闭此log。 + * + * @param showLog -[in] YES,打印log;NO,不打印 + */ ++ (void) showLogcat:(BOOL) showLog; + +/*! + * 设置日志msc.log生成路径以及日志等级 + * + * | 日志打印等级 | 描述 | + * |------------------------|-----------------------------------| + * | LVL_ALL | 全部打印 | + * | LVL_DETAIL | 高,异常分析需要的级别 | + * | LVL_NORMAL | 中,打印基本日志信息 | + * | LVL_LOW | 低,只打印主要日志信息 | + * | LVL_NONE | 不打印 | + * + * @param level -[in] 日志打印等级 + */ ++ (void) setLogFile:(LOG_LEVEL) level; + +/*! + * 设置日志文件的路径
+ * 日志文件默认存放在Documents目录。 + * + * @param path -[in] 日志文件的全路径 + */ ++ (void) setLogFilePath:(NSString*) path; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechConstant.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechConstant.h new file mode 100644 index 0000000..d3bac9f --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechConstant.h @@ -0,0 +1,945 @@ +// +// IFlySpeechConstant.h +// MSCDemo +// +// Created by iflytek on 5/9/14. +// Copyright (c) 2014 iflytek. All rights reserved. +// + +#import + +/*! + * 公共常量类
+ * 主要定义参数的key value值 + */ +@interface IFlySpeechConstant : NSObject + + +#pragma mark - 通用参数key + +/*! + * 语音应用ID
+ * 通过开发者网站申请 + * + * @return 语音应用IDkey + */ ++(NSString*)APPID; + + +/*! + * 语言区域。 + * + * @return 语言区域key。 + */ ++(NSString*)ACCENT; + +/*! + * 语言区域。 + * + * @return 普通话value。 + */ ++(NSString*)ACCENT_MANDARIN; + +/*! + * 语言区域。 + * + * @return 河南话value。 + */ ++(NSString*)ACCENT_HENANESE; + +/*! + * 语言区域。 + * + * @return 四川话value。 + */ ++(NSString*)ACCENT_SICHUANESE; + +/*! + * 语言区域。 + * + * @return 粤语value。 + */ ++(NSString*)ACCENT_CANTONESE; + +/*! + * 语言
+ * 支持:zh_cn,zh_tw,en_us
+ * + * @return 语言key + */ ++(NSString*)LANGUAGE; + +/*! + * 语言 + * + * @return 中文value + */ ++(NSString*)LANGUAGE_CHINESE; + + +/*! + * 语言 + * + * @return 中文台湾value + */ ++(NSString*)LANGUAGE_CHINESE_TW; + +/*! + * 语言 + * + * @return 英文value + */ ++(NSString*)LANGUAGE_ENGLISH; + +/*! + * 语言 + * + * @return 俄语value + */ ++(NSString*)LANGUAGE_RUSSIAN; + +/*! + * 语言 + * + * @return 日语value + */ ++(NSString*)LANGUAGE_JAPANESE; + +/*! + * 语言 + * + * @return 法语value + */ ++(NSString*)LANGUAGE_FRENCH; + +/*! + * 语言 + * + * @return 西班牙语value + */ ++(NSString*)LANGUAGE_SPANISH; + +/*! + * 语言 + * + * @return 韩语value + */ ++(NSString*)LANGUAGE_KOREAN; + +/*! + * 返回结果的数据格式,可设置为json,xml,plain,默认为json。 + * + * @return 返回结果的数据格式key + */ ++(NSString*)RESULT_TYPE; + +/*! + * 应用领域。 + * + * @return 应用领域key + */ ++(NSString*)IFLY_DOMAIN; + +/*! + * 个性化数据上传类型 + * + * @return 个性化数据上传类型key + */ ++(NSString*)DATA_TYPE; + +/*! + * 语音输入超时时间
+ * 单位:ms,默认30000 + * + * @return 语音输入超时时间key + */ ++(NSString*)SPEECH_TIMEOUT; + +/*! + * 网络连接超时时间
+ * 单位:ms,默认20000 + * + * @return 网络连接超时时间key + */ ++(NSString*)NET_TIMEOUT; + +/*! + * 业务类型。 + * + * @return 业务类型key。 + */ ++(NSString*)SUBJECT; + +/*! + * 扩展参数。 + * + * @return 扩展参数key。 + */ ++(NSString*)PARAMS; + +/*! + * 加密参数 + * + * 支持类型:ssl 加密 tcp 非加密 默认:tcp
+ * 建议对安全性要求较高时使用ssl。 + * + * @return 加密参数key + */ ++(NSString*)PROT_TYPE; + +/*! + * ssl证书内容 + * + * @return ssl证书内容key + */ ++(NSString*)SSL_CERT; + +/*! + * 录音音量返回时间间隔。 + * + * @return 间隔key。 + */ ++(NSString*)POWER_CYCLE; + +/*! + * 合成、识别、唤醒、评测、声纹等业务采样率。 + * + * @return 合成及识别采样率key。 + */ ++(NSString*)SAMPLE_RATE; + +/*! + * 合成、识别、唤醒、声纹等业务采样率。 + * + * @return 合成及识别采样率8K Value。 + */ ++(NSString*)SAMPLE_RATE_8K; + +/*! + * 合成、识别、唤醒、评测、声纹等业务采样率。 + * + * @return 合成及识别采样率16K Value。 + */ ++(NSString*)SAMPLE_RATE_16K; + +/*! + * 引擎类型。
+ * 可选:local,cloud,auto
+ * 默认:auto + * + * @return 引擎类型key。 + */ ++(NSString*)ENGINE_TYPE; + +/*! + * 本地xtts识别引擎。 + * + * @return 本地识别引擎value。 + */ ++(NSString*)TYPE_LOCAL_XTTS; + +/*! + * 本地识别引擎。 + * + * @return 本地识别引擎value。 + */ ++(NSString*)TYPE_LOCAL; + +/*! + * 云端识别引擎。 + * + * @return 云端识别引擎value。 + */ ++(NSString*)TYPE_CLOUD; + +/*! + * 混合识别引擎。 + * + * @return 混合识别引擎value。 + */ ++(NSString*)TYPE_MIX; + +/*! + * 引擎根据当前配置进行选择。 + * + * @return 引擎根据当前配置进行选择value。 + */ ++(NSString*)TYPE_AUTO; + +/*! + * 输入文本编码格式。 + * + * @return 编码格式key。 + */ ++(NSString*)TEXT_ENCODING; + +/*! + * 结果编码格式。 + * + * @return 结果编码格式key。 + */ ++(NSString*)RESULT_ENCODING; + +/*! + * 是否初始化播放器
+ * SDK内部播放器采用音频队列实现,有部分外部需求需要自定义音频队列,可以通过此开关控制
+ * 0:不初始化,非0或者参数为空:初始化,默认初始化 + * + * @return 是否初始化播放器参数key + */ ++(NSString*)PLAYER_INIT; + +/*! + * 是否播放器结束后发送deactive系统通知
+ * SDK内部播放器结束后可通过此开关发送deactive系统通知,使其他被中断的音频应用解除中断
+ * 0:不发送,非0或者参数为空:发送,默认发送 + * + * @return 是否播放器结束后发送deactive系统通知参数key + */ ++(NSString*)PLAYER_DEACTIVE; + +/** + * 是否初始化录音器
+ * SDK内部录音器采用音频队列实现,有部分外部需求需要自定义音频队列,可以通过此开关控制
+ * 0:不初始化,非0或者参数为空:初始化,默认初始化 + * + * @return 是否初始化录音器参数key + */ ++(NSString*)RECORDER_INIT; + +/** + * 是否录音器结束后发送deactive系统通知
+ * SDK内部录音器结束后可通过此开关发送deactive系统通知,使其他被中断的音频应用解除中断
+ * 0:不发送,非0或者参数为空:发送,默认发送 + * + * @return 是否录音器结束后发送deactive系统通知参数key + */ ++(NSString*)RECORDER_DEACTIVE; + + +#pragma mark - 合成相关设置key +/*! + * 语速
+ * 范围 (0~100) 默认值:50 + * + * @return 语速key + */ ++(NSString*)SPEED; + +/*! + * 音调
+ * 范围(0~100)默认值:50 + * + * @return 音调key + */ ++(NSString*)PITCH; + +/*! + * 合成录音保存路径 + * + * 注意:只需要设置文件名则可,会自动拼接到[IFlySetting setLogFilePath]接口设置的目录后 + * + * @return 合成录音保存路径key + */ ++(NSString*)TTS_AUDIO_PATH; + +/** + * 启用VAD功能 + * + * @return 启用VAD功能key + */ ++(NSString*)VAD_ENABLE; + +/*! + * VAD前端点超时
+ * 范围:0-10000(单位ms) + * + * @return VAD前端点超时key + */ ++(NSString*)VAD_BOS; + +/*! + * VAD后端点超时。
+ * 可选范围:0-10000(单位ms) + * + * @return VAD后端点超时key + */ ++(NSString*)VAD_EOS; + + +/* + * 云端支持如下发音人: + * 对于网络TTS的发音人角色,不同引擎类型支持的发音人不同,使用中请注意选择。 + * + * |--------|----------------| + * | 发音人 | 参数 | + * |--------|----------------| + * | 小燕 | xiaoyan | + * |--------|----------------| + * | 小宇 | xiaoyu | + * |--------|----------------| + * | 凯瑟琳 | catherine | + * |--------|----------------| + * | 亨利 | henry | + * |--------|----------------| + * | 玛丽 | vimary | + * |--------|----------------| + * | 小研 | vixy | + * |--------|----------------| + * | 小琪 | vixq | + * |--------|----------------| + * | 小峰 | vixf | + * |--------|----------------| + * | 小梅 | vixl | + * |--------|----------------| + * | 小莉 | vixq | + * |--------|----------------| + * | 小蓉 | vixr | + * |--------|----------------| + * | 小芸 | vixyun | + * |--------|----------------| + * | 小坤 | vixk | + * |--------|----------------| + * | 小强 | vixqa | + * |--------|----------------| + * | 小莹 | vixyin | + * |--------|----------------| + * | 小新 | vixx | + * |--------|----------------| + * | 楠楠 | vinn | + * |--------|----------------| + * | 老孙 | vils | + * |--------|----------------| + */ + +/*! + * 发音人 + * + * 云端支持如下发音人:
+ * 对于网络TTS的发音人角色,不同引擎类型支持的发音人不同,使用中请注意选择。
+ * + * | 发音人 | 参数 | + * |:--------:|:----------------:| + * | 小燕 | xiaoyan | + * | 小宇 | xiaoyu | + * | 凯瑟琳 | catherine | + * | 亨利 | henry | + * | 玛丽 | vimary | + * | 小研 | vixy | + * | 小琪 | vixq | + * | 小峰 | vixf | + * | 小梅 | vixl | + * | 小莉 | vixq | + * | 小蓉 | vixr | + * | 小芸 | vixyun | + * | 小坤 | vixk | + * | 小强 | vixqa | + * | 小莹 | vixyin | + * | 小新 | vixx | + * | 楠楠 | vinn | + * | 老孙 | vils | + * + * @return 发音人key + */ ++(NSString*)VOICE_NAME; + +/*! + * 发音人ID key。 + * + * @return 发音人ID key + */ ++(NSString*)VOICE_ID; + +/*! + * 发音人语种 key。 + * + * 参数值:0:Auto 1:中文 2英文 ,默认 0. + * + * @return 发音人ID key + */ ++(NSString*)VOICE_LANG; + +/*! + * 音量
+ * 范围(0~100) 默认值:50 + * + * @return 音量key + */ ++(NSString*)VOLUME ; + +/*! + * 合成音频播放缓冲时间
+ * 即缓冲多少秒音频后开始播放,如tts_buffer_time=1000;
+ * 默认缓冲1000ms毫秒后播放。 + * + * @return 合成音频播放缓冲时间缓冲时间key + */ ++(NSString*)TTS_BUFFER_TIME ; + + +/*! + * 合成数据是否即时返回 + * + * 是否需要数据回调,为1时,当合成一段音频会通过onEvent回调返回,直接合成结束;
+ * 设置为1为即时返回;0为非即时返回;默认值为0; + * + * @return 合成数据即时返回key + */ ++(NSString*)TTS_DATA_NOTIFY; + +/*! + * 预合成文本 + * + * @return 预合成文本参数key + */ ++(NSString*)NEXT_TEXT; + +/*! + * 是否需要打开MPPlayingInfocenter
+ * 是否需要初始化MPPlayerCenter的属性;0:需要初始化,1:不初始化 + * + * @return 是否需要打开MPPlayingInfocenter 参数key + */ ++(NSString*)MPPLAYINGINFOCENTER; + +#pragma mark - 识别、听写、语义相关设置key + +/*! + * 录音源
+ * 录音时的录音方式,默认为麦克风,设置为1;
+ * 如果需要外部送入音频,设置为-1,通过WriteAudio接口送入音频。 + * + * @return 录音源key + */ ++(NSString*)AUDIO_SOURCE; + +/*! + * 识别录音保存路径 + * + * @return 识别录音保存路径key + */ ++(NSString*) ASR_AUDIO_PATH; + +/*! + * 设置是否开启语义 + * + * @return 设置是否开启语义key + */ ++(NSString*)ASR_SCH; + +/*! + * 设置是否有标点符号 + * + * @return 设置是否有标点符号key + */ ++(NSString*)ASR_PTT; + +/*! + * ASR_PTT 参数值:设置带标点符号 + * + * @return 设置是有标点符号Value + */ ++(NSString*)ASR_PTT_HAVEDOT; + +/*! + * ASR_PTT 参数值:设置不带标点符号 + * + * @return 设置是无标点符号Value + */ ++(NSString*)ASR_PTT_NODOT; + +/*! + * 本地语法名称。
+ * 本地语法名称,对应云端的有CLOUD_GRAMMAR + * + * @return 本地语法名称key。 + */ ++(NSString*)LOCAL_GRAMMAR; + +/*! + * 云端语法ID。
+ * 云端编译语法返回的表示,早期版本使用GRAMMAR_ID,仍然兼容,但建议使用新的。 + * + * @return 云端语法ID key。 + */ ++(NSString*)CLOUD_GRAMMAR; + +/*! + * 语法类型 + * + * @return 语法类型key + */ ++(NSString*)GRAMMAR_TYPE; + +/*! + * 语法内容。 + * + * @return 语法内容key。 + */ ++(NSString*)GRAMMAR_CONTENT; + +/*! + * 字典内容。 + * + * @return 字典内容key。 + */ ++(NSString*)LEXICON_CONTENT; + +/*! + * 字典名字。 + * + * @return 字典名字key。 + */ ++(NSString*)LEXICON_NAME; + +/*! + * 语法名称列表。 + * + * @return 语法名称列表key。 + */ ++(NSString*)GRAMMAR_LIST; + +/*! + * 开放语义协议版本号。
+ * 如需使用请在http://osp.voicecloud.cn/上进行业务配置 + * + * @return 开放语义协议版本号key。 + */ ++(NSString*)NLP_VERSION; + +#pragma mark - 唤醒相关设置key +/*! + * 唤醒门限值。 + * + * @return 唤醒门限值key。 + */ ++(NSString*)IVW_THRESHOLD; + +/*! + * 唤醒服务类型。 + * + * @return 唤醒服务类型key。 + */ ++(NSString*)IVW_SST; + +/*! + * 唤醒+识别。 + * + * @return 唤醒+识别key。 + */ ++(NSString*)IVW_ONESHOT; + +/*! + * 唤醒工作方式
+ * 1:表示唤醒成功后继续录音,0:表示唤醒成功后停止录音。 + * + * @return 唤醒工作方式key + */ ++(NSString*)KEEP_ALIVE; + +/*! + * 唤醒录音保存路径 + * + * @return 唤醒录音保存路径key + */ ++(NSString*) IVW_AUDIO_PATH; + +#pragma mark - 评测相关设置key +/*! + * 评测类型
+ * 可选值:read_syllable(英文评测不支持):单字;read_word:词语;read_sentence:句子;read_chapter(待开放):篇章。 + * + * @return 评测类型 key + */ ++(NSString*)ISE_CATEGORY; + +/*! + * 评测结果等级
+ * 可选值:complete:完整 ;plain:简单 + * + * @return 评测结果等级 key + */ ++(NSString*)ISE_RESULT_LEVEL; + +/*! + * 评测结果格式
+ * 可选值:xml;plain + * + * @return 评测结果格式 key + */ ++(NSString*)ISE_RESULT_TYPE; + +/*! + * 评测录音保存路径 + * + * @return 评测录音保存路径key + */ ++(NSString*) ISE_AUDIO_PATH; + + +/*! + * 朗读跟踪,只对句子和篇章有效
+ * 可选值:enable:开启;disable:关闭。 + * + * @return 朗读跟踪 key + */ ++(NSString*)ISE_AUTO_TRACKING; + +/*! + * 跟踪模式
+ * 可选值:easy:简单;hard:复杂。 + * + * @return 跟踪模式 key + */ ++(NSString*)ISE_TRACK_TYPE; + +#pragma mark - 语记SDK业务key +/*! + * 本地所有资源 + * + * @return 本地所有资源key + */ ++ (NSString *)PLUS_LOCAL_ALL; + +/*! + * 本地合成资源 + * + * @return 本地合成资源key + */ ++ (NSString *)PLUS_LOCAL_TTS; + +/*! + * 本地识别资源 + * + * @return 本地识别资源key + */ ++ (NSString *)PLUS_LOCAL_ASR; + +/*! + * 本地唤醒资源 + * + * @return 本地唤醒资源key + */ ++ (NSString *)PLUS_LOCAL_IVW; + +#pragma mark - 身份验证业务key + +/*! + * auth_id
+ * 用于用户注册和登录、查询、删除等业务时标识用户身份 + * + * @return 用户标识 + */ ++ (NSString*)MFV_AUTH_ID; + +/*! + * 请求业务类型,可选值:mfv(默认,融合验证),ivp(声纹),ifr(人脸) + * + * @return 请求业务类型key + */ ++ (NSString*)MFV_SUB; + +/*! + * 会话类型,不同sub有不同的sst取值。
+ * ifr:enroll,verify,identify,reenroll,query,delete
+ * ivp:enroll(train),verify,reenroll,query,delete,download + * + * @return 会话类型key + */ ++ (NSString*)MFV_SST; + +/*! + * 融合验证模式,仅在融合验证场景下使用。可选值:sin(单一生物特征数据验证),mix(混合生物特征数据验证),agi(灵活生物特征数据验证) + * + * @return 融合验证模式key + */ ++ (NSString*)MFV_VCM; + +/*! + * 特征场景,用来说明本次验证将涉及的业务。可选值:ivp,ifr,ivp|ifr + * + * @return 特征场景 key + */ ++ (NSString*)MFV_SCENES; + +/*! + * 确认周期(affirmance cycle,单位:s),用户设置的确认超时时间(生命周期),仅在灵活融合验证场景下使用 + * + * @return 确认周期key + */ ++ (NSString*)MFV_AFC; + +/*! + * 数据保存路径 + * + * @return 数据保存路径key + */ ++ (NSString*)MFV_DATA_PATH; + +/*! + * 训练次数:取值2~9.无默认值,必须明确指定。 + * + * @return 训练次数key + */ ++ (NSString*)MFV_RGN; + +/*! + * 声纹确认门限值,验证得分>=tsd验证通过,否则验证失败(该参数目前不支持,作为保留参数。)却只范围:0~100. + * + * @return 声纹确认门限值key + */ ++ (NSString*)MFV_TSD; + +/*! + * 密码文本。从服务端下载,比如数字密码所需要的数字串。 + * + * @return 密码文本key + */ ++ (NSString*)MFV_PTXT; + +/*! + * 密码类型。取值:1(文本密码),2(自由说),3(数字密码). + * + * @return 密码类型key + */ ++ (NSString*)MFV_PWDT; + +/*! + * 取消注册。取值:0(不取消,即不生效),1(取消本次注册). + * + * @return 取消注册key + */ ++ (NSString*)MFV_FIN; + +/*! + * 等待超时时间:描述客户端等待结果的超时时间 + * + * @return 等待超时时间:key + */ ++ (NSString*)MFV_WTT; + +/*! + * 数据格式
+ * 声纹为音频采样率支持:16000和8000;人脸为图片格式,支持jpg和gif + * + * @return 数据格式key + */ ++ (NSString*)MFV_DATA_FORMAT; + +/*! + * 数据压缩编码
+ * 声纹为;人脸支持raw,不对图片压缩 + * + * @return 数据压缩编码key + */ ++ (NSString*)MFV_DATA_ENCODING; + +#pragma mark - 人脸业务key + +//1. sub 取值: wfr 用途: 用于区分业务类型,web访问方式中,nginx配置不用使用,但是在结构化日志和染色日志记录中使用。 +//2. sst 取值: reg、verify、detect、align 用途: 指定本路会话是属于何种性质 +// + 人脸图像注册(reg):上传图像,验证图像的有效性,然后存储起来,作为数据源。 +// + 人脸图像验证(verify):通过与指定源图像比较,验证人脸相似性。 +// + 人脸图像检测(detect):能够检测出不同姿态方位的人脸在图中的位置。 +// + 人脸图像聚焦(align):在给定人脸框下自动标定出两眼、鼻尖、嘴角的坐标。 +//3. aue 取值: raw 用途: 图像压缩格式,现在引擎不支持图像压缩,aue只能取值raw +//4. pset 取值: 整数 用途: 人脸识别验证阈值,取值可以是负数也可以是整数。 +//5. skip 取值: true/false 用途: 后台图片处理是否进行过滤。true表示不过滤,false表示过滤 +//6. gid 取值: *********** 用途: 图像模型id,如:4a6c124ed6b78436ee5aac4563f13eb5 +//7. appid 取值:用户申请的appid 用途: 验证用户 + + +/*! + * sub 默认值:wfr
+ * 用于区分业务类型,web访问方式中,nginx配置不用使用,但是在结构化日志和染色日志记录中使用。 + */ ++ (NSString*) FACE_SUB; + +/*! + * WFR
+ * sub参数的默认值 + */ ++ (NSString*) FACE_WFR; + +/*! + * sst
+ * 指定本路会话是属于何种性质 + */ ++ (NSString*) FACE_SST; + +/*! + * REG
+ * 人脸图像注册(reg):上传图像,验证图像的有效性,然后存储起来,作为数据源。 + */ ++ (NSString*) FACE_REG; + +/*! + * VERIFY
+ * 人脸图像验证(verify):通过与指定源图像比较,验证人脸相似性。 + */ ++ (NSString*) FACE_VERIFY; + +/*! + * DETECT
+ * 人脸图像检测(detect):能够检测出不同姿态方位的人脸在图中的位置。 + */ ++ (NSString*) FACE_DETECT; + +/*! + * ALIGN
+ * 人脸图像聚焦(align):在给定人脸框下自动标定出两眼、鼻尖、嘴角的坐标。 + */ ++ (NSString*) FACE_ALIGN; + +/*! + * ATTR
+ * 面部属性识别(attr):对面部属性进行识别:例如秃顶、刘海、大嘴、模糊、眼镜等。 + */ ++ (NSString*) FACE_ATTR; + + +/*! + * AUE
+ * 图像压缩格式,现在引擎不支持图像压缩,aue只能取值raw + */ ++ (NSString*) FACE_AUE; + +/*! + * RAW
+ * AUE参数的值 + */ ++ (NSString*) FACE_RAW; + +/*! + * PSET
+ * 人脸识别验证阈值,取值可以是负数也可以是整数。 + */ ++ (NSString*) FACE_PSET; + +/*! + * SKIP
+ * 后台图片处理是否进行过滤。true表示不过滤,false表示过滤,传入字符串@“true”或@“false” + */ ++ (NSString*) FACE_SKIP; + +/*! + * GID
+ * 图像模型id,如:4a6c124ed6b78436ee5aac4563f13eb5 + */ ++ (NSString*) FACE_GID; + +/*! + * auth_id
+ * 用于用户注册和登录、查询、删除等业务时标识用户身份 + * + * @return 用户标识 + */ ++ (NSString*)FACE_AUTH_ID; + +/*! + * DVC
+ * 用户设备编号,用于验证用户 + */ ++ (NSString*) FACE_DVC; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechError.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechError.h new file mode 100644 index 0000000..3db75e6 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechError.h @@ -0,0 +1,58 @@ +// +// IFlySpeechError.h +// MSC +// +// Created by iflytek on 13-3-19. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#ifndef __IFlySpeechError__ +#define __IFlySpeechError__ + +#import + +/*! + * 错误描述类 + */ +@interface IFlySpeechError : NSObject + +/*! + * 错误码 + */ +@property(nonatomic,assign) int errorCode; + +/*! + * 错误码类型 + */ +@property(nonatomic,assign) int errorType; + +/*! + * 错误描述 + */ +@property(nonatomic,retain) NSString* errorDesc; + +/*! + * 初始化 + * + * @param errorCode -[in] 错误码 + * + * @return IFlySpeechError对象 + */ ++ (instancetype) initWithError:(int) errorCode; + +/*! + * 获取错误码 + * + * @return 错误码 + */ +-(int) errorCode; + +/*! + * 获取错误描述 + * + * @return 错误描述 + */ +- (NSString *) errorDesc; + +@end +#endif diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluator.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluator.h new file mode 100644 index 0000000..81e6026 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluator.h @@ -0,0 +1,101 @@ +// +// IFlySpeechEvaluator.h +// msc +// +// Created by jianzhang on 14-1-13 +// Copyright (c) 2013年 iflytek. All rights reserved. +// + + +#import +#import "IFlySpeechEvaluatorDelegate.h" + +#define IFLY_AUDIO_SOURCE_MIC @"1" +#define IFLY_AUDIO_SOURCE_STREAM @"-1" + +/*! + * 语音评测类 + */ +@interface IFlySpeechEvaluator : NSObject + +/*! + * 设置委托对象 + */ +@property (assign) id delegate; + +/*! + * 返回评测对象的单例 + * + * @return 别对象的单例 + */ ++ (instancetype)sharedInstance; + +/*! + * 销毁评测对象。 + * + * @return 成功返回YES,失败返回NO。 + */ +- (BOOL)destroy; + +/*! + * 设置评测引擎的参数 + * + * @param value 评测引擎参数值 + * @param key 评测引擎参数 + * + * @return 设置的参数和取值正确返回YES,失败返回NO + */ +- (BOOL)setParameter:(NSString *)value forKey:(NSString *)key; + + +/*! + * 获得评测引擎的参数 + * + * @param key 评测引擎参数 + * + * @return key对应的参数值 + */ +- (NSString*)parameterForKey:(NSString *)key; + +/*! + * 开始评测
+ * 同时只能进行一路会话,这次会话没有结束不能进行下一路会话,否则会报错 + * + * @param data 评测的试题 + * @param params 评测的参数 + * @return 成功返回YES,失败返回NO + */ +- (BOOL)startListening:(NSData *)data params:(NSString *)params; + +/*! + * 停止录音
+ * 调用此函数会停止录音,并开始进行语音识别 + */ +- (void)stopListening; + +/*! + * 取消本次会话 + */ +- (void)cancel; + +@end + +/*! + * 音频流评测
+ * 音频流评测可以将文件分段写入 + */ +@interface IFlySpeechEvaluator(IFlyStreamISERecognizer) + +/*! + * 写入音频流 + * + * @param audioData 音频数据 + * + * @return 写入成功返回YES,写入失败返回NO + */ +- (BOOL) writeAudio:(NSData *) audioData; + +@end + + + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluatorDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluatorDelegate.h new file mode 100644 index 0000000..5afc832 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvaluatorDelegate.h @@ -0,0 +1,64 @@ +// +// IFlySpeechEvaluatorDelegate.h +// msc +// +// Created by admin on 13-6-19. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + + +#import + +@class IFlySpeechError; + +/*! + * 评测协议 + */ +@protocol IFlySpeechEvaluatorDelegate + +/*! + * 音量和数据回调 + * + * @param volume 音量 + * @param buffer 音频数据 + */ +- (void)onVolumeChanged:(int)volume buffer:(NSData *)buffer; + +/*! + * 开始录音回调
+ * 当调用了`startListening`函数之后,如果没有发生错误则会回调此函数。如果发生错误则回调onCompleted:函数 + */ +- (void)onBeginOfSpeech; + +/*! + * 停止录音回调
+ * 当调用了`stopListening`函数或者引擎内部自动检测到断点,如果没有发生错误则回调此函数。
+ * 如果发生错误则回调onCompleted:函数 + */ +- (void)onEndOfSpeech; + +/*! + * 正在取消 + */ +- (void)onCancel; + +/*! + * 评测错误回调 + * + * 在进行语音评测过程中的任何时刻都有可能回调此函数,你可以根据errorCode进行相应的处理.当errorCode没有错误时,表示此次会话正常结束,否则,表示此次会话有错误发生。特别的当调用`cancel`函数时,引擎不会自动结束,需要等到回调此函数,才表示此次会话结束。在没有回调此函数之前如果重新调用了`startListenging`函数则会报错误。 + * + * @param errorCode 错误描述类 + */ +- (void)onCompleted:(IFlySpeechError *)errorCode; + +/*! + * 评测结果回调
+ * 在评测过程中可能会多次回调此函数,你最好不要在此回调函数中进行界面的更改等操作,只需要将回调的结果保存起来。 + * + * @param results -[out] 评测结果。 + * @param isLast -[out] 是否最后一条结果 + */ +- (void)onResults:(NSData *)results isLast:(BOOL)isLast; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvent.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvent.h new file mode 100644 index 0000000..9b4a863 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechEvent.h @@ -0,0 +1,151 @@ +// +// IFlySpeechEvent.h +// MSCDemo +// +// Created by admin on 14-8-12. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + +#import + +/*! + * 事件类型 + */ +typedef NS_ENUM(NSUInteger,IFlySpeechEventType){ + /*! + * 网络状态消息
+ * 在消息到达时,可通过onEvent的第2个参数arg1,获取当前网络连接状态值 + */ + IFlySpeechEventTypeNetPref = 10001, + /*! + * 转写音频文件消息
+ * 在录音模式下,成功创建音频文件时返回。可通过onEvent第4个参数data,指定Key为[IFlySpeechConstant IST_AUDIO_PATH],获取音频文件绝对路径.或通过[IFlySpeechTranscripter getParameter:[IFlySpeechConstant IST_AUDIO_PATH]],获取音频文件绝对路径. + */ + IFlySpeechEventTypeISTAudioFile = 10004, + /*! + * 转写已上传字节消息
+ * 在消息到达时,通过onEvent的第二个参数arg1,获取已确认上传到服务器的字节数.若当前音频源为非写音频模式,还可通过onEvent + * 的第三个参数arg2,获取当前所有音频的字节大小.录音模式时,由于所有音频字节大小会变。当停止音频输入后(等待录音时间超时[IFlySpeechConstant SPEECH_TIMEOUT],或调用[IFlySpeechTranscripter stopTranscripting]),且服务器收到所有音频时,第四个参数data,将包含完成标记的布尔值(true),可通过data调用指定KEY为KCIFlySpeechEventKeyISTUploadComplete获取。此消息可能多次返回. + */ + IFlySpeechEventTypeISTUploadBytes = 10006, + + /*! + * 转写缓存剩余
+ * 此消息仅在音频源为-1时需要关注,在调用[IFlySpeechTranscripter writeAudio]写音频时,应该关注此事件。
+ * 此事件在调用写音频接口、及音频最后被写入底库库时分别回调一次。当事件回调时,通过onEvent的第二个参数arg1,获取当前剩余的缓存大小,当缓存小于要写入的音频时,应该先暂停写音频数据,直到下次缓存大小大于要写入的音频时.最大缓存为128KByte。 + */ + IFlySpeechEventTypeISTCacheLeft = 10007, + + /*! + * 转写结果等待时间消息
+ * 在消息到达时,通过 onEvent的第二个参数arg1,获取当前结果需要的时间.
+ * 此消息可能多次返回,返回时间不定,且不一定会返回. + */ + IFlySpeechEventTypeISTResultTime= 10008, + + /*! + * 转写转写音频同步ID消息
+ * 在消息到达时,通过 onEvent的第二个参数arg1,获取当前写音频同步ID.
+ * 此消息可能多次返回. + */ + IFlySpeechEventTypeISTSyncID= 10009, + + /*! + * 会话开始消息
+ * 在会话开始成功后返回 + */ + IFlySpeechEventTypeSessionBegin = 10010, + + /*! + * 会话结束消息
+ * 在会话结束前返回 + */ + IFlySpeechEventTypeSessionEnd = 10011, + + /*! + * 音量消息,在得到音量时抛出,暂时只有身份验证的声纹业务用到 + */ + IFlySpeechEventTypeVolume = 10012, + + /*! + * VAD后端点消息,在检测到VAD后端点时抛出,暂时只有身份验证的声纹业务用到 + */ + IFlySpeechEventTypeVadEOS = 10013, + + /*! + * 服务端会话id
+ * 在消息到达时,可通过onEvent的第4个参数data(字典类型),指定key KCIFlySpeechEventKeySessionID,获取服务端会话id. + */ + IFlySpeechEventTypeSessionID = 20001, + + /*! + * TTS合成数据消息
+ * -(void)onEvent:(int)eventType arg0:(int)arg0 arg1:(int)arg1 data:(NSData *)eventData
+ * 其中eventData中包含数据 + * + */ + IFlySpeechEventTypeTTSBuffer = 21001, + + /*! + * 通知cancel方法被调用的回调 + * + */ + IFlySpeechEventTypeTTSCancel = 21002, + + /*! + * IVW onshot 听写 or 识别结果
+ * 在消息到达时,第2个参数arg1包含是否为最后一个结果:1为是,0为否;
+ * 第4个参数data中包含数据,通过指定KEY为KCIFlySpeechEventKeyIVWResult获取. + */ + IFlySpeechEventTypeIVWResult = 22001, + + /*! + * 开始处理录音数据 + * + */ + IFlySpeechEventTypeSpeechStart= 22002, + + /*! + * 录音停止 + * + */ + IFlySpeechEventTypeRecordStop= 22003, + + /*! + * 服务端音频url
+ * 在消息到达时,第4个参数data,包含数据,通过指定KEY为KCIFlySpeechEventKeyAudioUrl获取. + */ + IFlySpeechEventTypeAudioUrl = 23001, + + /*! + * 变声数据结果返回
+ * 设置voice_change参数获取结果. + */ + IFlySpeechEventTypeVoiceChangeResult = 24001 + +}; + +#pragma mark - keys for event data + +/** + * 转写是否已上传完标记key + */ +extern NSString* const KCIFlySpeechEventKeyISTUploadComplete; + +/** + * 服务端会话key + */ +extern NSString* const KCIFlySpeechEventKeySessionID; +/** + * TTS取音频数据key + */ +extern NSString* const KCIFlySpeechEventKeyTTSBuffer; +/** + * IVW oneshot 听写 or 识别结果 key + */ +extern NSString* const KCIFlySpeechEventKeyIVWResult; +/** + * 服务端音频url key + */ +extern NSString* const KCIFlySpeechEventKeyAudioUrl; + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizer.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizer.h new file mode 100644 index 0000000..12fcfd9 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizer.h @@ -0,0 +1,175 @@ +// +// IFlySpeechRecognizer.h +// MSC +// +// Created by iflytek on 13-3-19. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + +#import "IFlySpeechRecognizerDelegate.h" + +#define IFLY_AUDIO_SOURCE_MIC @"1" +#define IFLY_AUDIO_SOURCE_STREAM @"-1" + +/*! + * 语音识别类
+ * 此类现在设计为单例,你在使用中只需要创建此对象,不能调用release/dealloc函数去释放此对象。所有关于语音识别的操作都在此类中。 + */ +@interface IFlySpeechRecognizer : NSObject + +/*! + * 设置委托对象 + */ +@property(nonatomic,assign) id delegate ; + +/*! + * 返回识别对象的单例 + * + * @return 识别对象的单例 + */ ++ (instancetype) sharedInstance; + +/*! + * 销毁识别对象。 + * + * @return 成功返回YES,失败返回NO + */ +- (BOOL) destroy; + +/* + * | ------------- |----------------------------------------------------------- + * | 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | domain |应用的领域: 取值为:iat、search、video、poi、music、asr; + * | | iat:普通文本听写; + * | | search:热词搜索; + * | | video:视频音乐搜索; + * | | asr:关键词识别; + * | ------------- |----------------------------------------------------------- + * | vad_bos |前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms; + * | | engine指定iat识别默认值为5000; + * | | 其他情况默认值为 4000,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | vad_eos |后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, + * | | 自动停止录音;单位:ms; + * | | sms 识别默认值为 1800; + * | | 其他默认值为 700,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | sample_rate |采样率:目前支持的采样率设置有 16000 和 8000。 + * | ------------- |----------------------------------------------------------- + * | asr_ptt |标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。 + * | ------------- |----------------------------------------------------------- + * | result_type |返回结果的数据格式: 可设置为json,xml,plain,默认为json。 + * | ------------- |----------------------------------------------------------- + * | grammarID |识别的语法id: 只针对 domain 设置为”asr”的应用。 + * | ------------- |----------------------------------------------------------- + * | asr_audio_path|音频文件名: 设置此参数后,将会自动保存识别的录音文件。 + * | | 路径为Documents/(指定值)。 + * | | 不设置或者设置为nil,则不保存音频。 + * | ------------- |----------------------------------------------------------- + * | params |扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。 + * | ------------- |----------------------------------------------------------- + * + */ + +/*! + * 设置识别引擎的参数 + * + * 识别的引擎参数(key)取值如下: + * + * | 参数 | 描述 | + * |-----------------|-------------------------------------------------------| + * | domain | 应用的领域: 取值为:iat、search、video、poi、music、asr;
iat:普通文本听写;
search:热词搜索;
video:视频音乐搜索;
asr:关键词识别;| + * | vad_bos | 前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms;
engine指定iat识别默认值为5000;
其他情况默认值为 4000,范围 0-10000。| + * | vad_eos | 后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入,自动停止录音;单位:ms;
sms 识别默认值为 1800;
其他默认值为 700,范围 0-10000。| + * | sample_rate | 采样率:目前支持的采样率设置有 16000 和 8000。| + * | asr_ptt | 标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。| + * | result_type | 返回结果的数据格式: 可设置为json,xml,plain,默认为json。| + * | grammarID | 识别的语法id: 只针对 domain 设置为”asr”的应用。| + * | asr_audio_path | 音频文件名: 设置此参数后,将会自动保存识别的录音文件。
路径为Documents/(指定值)。
不设置或者设置为nil,则不保存音频。| + * | params | 扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。| + * + * @param value 参数对应的取值 + * @param key 识别引擎参数 + * + * @return 成功返回YES;失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 获取识别引擎参数 + * + * @param key 参数key + * + * @return 参数值 + */ +-(NSString*) parameterForKey:(NSString *)key; + +/*! + * 开始识别 + * + * 同时只能进行一路会话,这次会话没有结束不能进行下一路会话,否则会报错。若有需要多次回话,请在onCompleted回调返回后请求下一路回话。 + * + * @return 成功返回YES;失败返回NO + */ +- (BOOL) startListening; + +/*! + * 停止录音
+ * 调用此函数会停止录音,并开始进行语音识别 + */ +- (void) stopListening; + +/*! + * 取消本次会话 + */ +- (void) cancel; + +/*! + * 上传语法 + * + * @param completionHandler 上传语法完成回调 + * @param grammarType 语法类型 + * @param grammarContent 语法内容 + * + * @return 错误码 + */ +- (int) buildGrammarCompletionHandler:(IFlyOnBuildFinishCompletionHandler)completionHandler + grammarType:(NSString *)grammarType + grammarContent:(NSString *)grammarContent; + +/*! + * 是否正在识别 + */ +@property (nonatomic, readonly) BOOL isListening; + +@end + +/*! + * 音频流识别
+ * 音频流识别可以将文件分段写入 + */ +@interface IFlySpeechRecognizer(IFlyStreamRecognizer) + +/*! +* 写入音频流 +* +* 此方法的使用示例如下: +*
[_iFlySpeechRecognizer setParameter:@"-1" value:@"audio_source"];
+* [_iFlySpeechRecognizer startListening];
+* [_iFlySpeechRecognizer writeAudio:audioData1];
+* [_iFlySpeechRecognizer writeAudio:audioData2];
+* ...
+* [_iFlySpeechRecognizer stopListening];
+* 
+* +* @param audioData 音频数据 +* +* @return 写入成功返回YES,写入失败返回NO +*/ +- (BOOL) writeAudio:(NSData *) audioData; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizerDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizerDelegate.h new file mode 100644 index 0000000..77331b5 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechRecognizerDelegate.h @@ -0,0 +1,111 @@ +// +// IFlySpeechRecognizerDelegate.h +// MSC +// +// Created by ypzhao on 13-3-27. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + +@class IFlySpeechError; + +/*! + * 构建语法结束回调 + * + * @param grammarId 语法id + * @param error 错误描述 + */ +typedef void(^IFlyOnBuildFinishCompletionHandler)(NSString* grammarId,IFlySpeechError * error); + + +/*! + * 语音识别协议
+ * 在使用语音识别时,需要实现这个协议中的方法. + */ +@protocol IFlySpeechRecognizerDelegate + +@required + +/*! + * 识别结果回调 + * + * 在进行语音识别过程中的任何时刻都有可能回调此函数,你可以根据errorCode进行相应的处理,当errorCode没有错误时,表示此次会话正常结束;否则,表示此次会话有错误发生。特别的当调用`cancel`函数时,引擎不会自动结束,需要等到回调此函数,才表示此次会话结束。在没有回调此函数之前如果重新调用了`startListenging`函数则会报错误。 + * + * @param errorCode 错误描述 + */ +- (void) onCompleted:(IFlySpeechError *) errorCode; + +/*! + * 识别结果回调 + * + * 在识别过程中可能会多次回调此函数,你最好不要在此回调函数中进行界面的更改等操作,只需要将回调的结果保存起来。
+ * 使用results的示例如下: + *

+ *  - (void) onResults:(NSArray *) results{
+ *     NSMutableString *result = [[NSMutableString alloc] init];
+ *     NSDictionary *dic = [results objectAtIndex:0];
+ *     for (NSString *key in dic){
+ *        [result appendFormat:@"%@",key];//合并结果
+ *     }
+ *   }
+ *  
+ * + * @param results -[out] 识别结果,NSArray的第一个元素为NSDictionary,NSDictionary的key为识别结果,sc为识别结果的置信度。 + * @param isLast -[out] 是否最后一个结果 + */ +- (void) onResults:(NSArray *) results isLast:(BOOL)isLast; + +@optional + +/*! + * 音量变化回调
+ * 在录音过程中,回调音频的音量。 + * + * @param volume -[out] 音量,范围从0-30 + */ +- (void) onVolumeChanged: (int)volume; + +/*! + * 开始录音回调
+ * 当调用了`startListening`函数之后,如果没有发生错误则会回调此函数。
+ * 如果发生错误则回调onCompleted:函数 + */ +- (void) onBeginOfSpeech; + +/*! + * 停止录音回调
+ * 当调用了`stopListening`函数或者引擎内部自动检测到断点,如果没有发生错误则回调此函数。
+ * 如果发生错误则回调onCompleted:函数 + */ +- (void) onEndOfSpeech; + +/*! + * 取消识别回调
+ * 当调用了`cancel`函数之后,会回调此函数,在调用了cancel函数和回调onCompleted之前会有一个
+ * 短暂时间,您可以在此函数中实现对这段时间的界面显示。 + */ +- (void) onCancel; + +#ifdef _EDUCATION_ +/*! + * 返回音频Key + * + * @param key 音频Key + */ +- (void) getAudioKey:(NSString *)key; + +#endif + +/*! + * 扩展事件回调
+ * 根据事件类型返回额外的数据 + * + * @param eventType 事件类型,具体参见IFlySpeechEventType的IFlySpeechEventTypeVoiceChangeResult枚举。 + * @param arg0 arg0 + * @param arg1 arg1 + * @param eventData 事件数据 + */ +- (void) onEvent:(int)eventType arg0:(int)arg0 arg1:(int)arg1 data:(NSData *)eventData; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizer.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizer.h new file mode 100644 index 0000000..e7d220c --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizer.h @@ -0,0 +1,123 @@ +// +// IFlySpeechSynthesizer.h +// MSC +// +// Created by 侯效林 on 16-4-22. +// Copyright (c) 2016年 iflytek. All rights reserved. +// + +#import +#import "IFlySpeechSynthesizerDelegate.h" + + +/*! + * 语音合成 + */ +@interface IFlySpeechSynthesizer : NSObject + +/*! + * 设置识别的委托对象 + */ +@property(nonatomic,assign) id delegate; + +/*! + * 返回合成对象的单例 + * + * @return 合成对象 + */ ++ (instancetype) sharedInstance; + +/*! + * 销毁合成对象。 + * + * @return 成功返回YES,失败返回NO. + */ ++ (BOOL) destroy; + +/* + * | ------------- |----------------------------------------------------------- + * | 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | speed |合成语速,取值范围 0~100 + * | ------------- |----------------------------------------------------------- + * | volume |合成的音量,取值范围 0~100 + * | ------------- |----------------------------------------------------------- + * | voice_name |默认为”xiaoyan”;可以设置的参数列表可参考个性化发音人列表 + * | ------------- |----------------------------------------------------------- + * | sample_rate |采样率:目前支持的采样率设置有 16000 和 8000。 + * | ------------- |----------------------------------------------------------- + * | tts_audio_path|音频文件名 设置此参数后,将会自动保存合成的音频文件。 + * | |路径为Documents/(指定值)。不设置或者设置为nil,则不保存音频。 + * | ------------- |----------------------------------------------------------- + * | params |扩展参数: 对于一些特殊的参数可在此设置。 + * | ------------- |----------------------------------------------------------- + * + */ + +/*! + * 设置合成参数 + * + * | 参数 | 描述 | + * |-----------------|----------------------------------------------------| + * | speed | 合成语速,取值范围 0~100 | + * | volume | 合成的音量,取值范围 0~100 | + * | voice_name | 默认为”xiaoyan”;可以设置的参数列表可参考个性化发音人列表 | + * | sample_rate | 采样率:目前支持的采样率设置有 16000 和 8000。 | + * | tts_audio_path | 音频文件名 设置此参数后,将会自动保存合成的音频文件。
路径为Documents/(指定值)。不设置或者设置为nil,则不保存音频。| + * | params | 扩展参数: 对于一些特殊的参数可在此设置。 | + * + * @param value 参数取值 + * @param key 合成参数 + * + * @return 设置成功返回YES,失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 获取合成参数 + * + * @param key 参数key + * + * @return 参数值 + */ +-(NSString*) parameterForKey:(NSString *)key; + +/*! + * 开始合成(播放)
+ * 调用此函数进行合成,如果发生错误会回调错误`onCompleted` + * + * @param text 合成的文本,最大的字节数为1k + */ +- (void) startSpeaking:(NSString *)text; + +/*! + * 开始合成(不播放)
+ * 调用此函数进行合成,如果发生错误会回调错误`onCompleted` + * + * @param text 合成的文本,最大的字节数为1k + * @param uri 合成后,保存再本地的音频路径 + */ +-(void)synthesize:(NSString *)text toUri:(NSString*)uri; + +/*! + * 暂停播放
+ * 暂停播放之后,合成不会暂停,仍会继续,如果发生错误则会回调错误`onCompleted` + */ +- (void) pauseSpeaking; + +/*! + * 恢复播放 + */ +- (void) resumeSpeaking; + +/*! + * 停止播放并停止合成 + */ +- (void) stopSpeaking; + +/*! + * 是否正在播放 + */ +@property (nonatomic, readonly) BOOL isSpeaking; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizerDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizerDelegate.h new file mode 100644 index 0000000..bdef9ac --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechSynthesizerDelegate.h @@ -0,0 +1,81 @@ +// +// IFlySpeechSynthesizerDelegate.h +// MSC +// +// Created by ypzhao on 13-3-20. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import +#import "IFlySpeechEvent.h" + +@class IFlySpeechError; + +/*! + * 语音合成回调 + */ +@protocol IFlySpeechSynthesizerDelegate + +@required + +/*! + * 结束回调
+ * 当整个合成结束之后会回调此函数 + * + * @param error 错误码 + */ +- (void) onCompleted:(IFlySpeechError*) error; + +@optional + +/*! + * 开始合成回调 + */ +- (void) onSpeakBegin; + +/*! + * 缓冲进度回调 + * + * @param progress 缓冲进度,0-100 + * @param msg 附件信息,此版本为nil + */ +- (void) onBufferProgress:(int) progress message:(NSString *)msg; + +/*! + * 播放进度回调 + * + * @param progress 当前播放进度,0-100 + * @param beginPos 当前播放文本的起始位置(按照字节计算),对于汉字(2字节)需/2处理 + * @param endPos 当前播放文本的结束位置(按照字节计算),对于汉字(2字节)需/2处理 + */ +- (void) onSpeakProgress:(int) progress beginPos:(int)beginPos endPos:(int)endPos; + +/*! + * 暂停播放回调 + */ +- (void) onSpeakPaused; + +/*! + * 恢复播放回调
+ * 注意:此回调方法SDK内部不执行,播放恢复全部在onSpeakBegin中执行 + */ +- (void) onSpeakResumed; + +/*! + * 正在取消回调
+ * 注意:此回调方法SDK内部不执行 + */ +- (void) onSpeakCancel; + +/*! + * 扩展事件回调
+ * 根据事件类型返回额外的数据 + * + * @param eventType 事件类型,具体参见IFlySpeechEventType枚举。目前只支持EVENT_TTS_BUFFER也就是实时返回合成音频。 + * @param arg0 arg0 + * @param arg1 arg1 + * @param eventData 事件数据 + */ +- (void) onEvent:(int)eventType arg0:(int)arg0 arg1:(int)arg1 data:(NSData *)eventData; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUnderstander.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUnderstander.h new file mode 100644 index 0000000..3dbd3b9 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUnderstander.h @@ -0,0 +1,132 @@ +// +// IFlySpeechUnderstander.h +// MSC +// +// Created by iflytek on 2014-03-12. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + +#import + +@class IFlySpeechError; +@protocol IFlySpeechRecognizerDelegate; + +/*! + * 语义理解接口 + */ +@interface IFlySpeechUnderstander : NSObject + +/*! + * 是否正在语义理解 + */ +@property (readonly) BOOL isUnderstanding; + +/*! + * 设置委托对象 + */ +@property(nonatomic,retain) id delegate ; + +/*! + * 创建语义理解对象的单例 + * + * @return 语义理解对象 + */ ++(instancetype) sharedInstance; + +/*! + * 开始义理解 + * + * 同时只能进行一路会话,这次会话没有结束不能进行下一路会话,否则会报错。若有需要多次回话,请在onCompleted回调返回后请求下一路回话。 + * + * @return 成功返回YES,失败返回NO + */ +- (BOOL) startListening; + +/*! + * 停止录音
+ * 调用此函数会停止录音,并开始进行语义理解 + */ +- (void) stopListening; + +/*! + * 取消本次会话 + */ +- (void) cancel; + +/* + * | ------------- |----------------------------------------------------------- + * | 参数 | 描述 + * | ------------- |----------------------------------------------------------- + * | domain |应用的领域: 取值为:iat、search、video、poi、music、asr; + * | | iat:普通文本听写; + * | | search:热词搜索; + * | | video:视频音乐搜索; + * | | asr:关键词识别; + * | ------------- |----------------------------------------------------------- + * | vad_bos |前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms; + * | | engine指定iat识别默认值为5000; + * | | 其他情况默认值为 4000,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | vad_eos |后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入, + * | | 自动停止录音;单位:ms; + * | | sms 识别默认值为 1800; + * | | 其他默认值为 700,范围 0-10000。 + * | ------------- |----------------------------------------------------------- + * | sample_rate |采样率:目前支持的采样率设置有 16000 和 8000。 + * | ------------- |----------------------------------------------------------- + * | asr_ptt |标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。 + * | ------------- |----------------------------------------------------------- + * | result_type |返回结果的数据格式: 可设置为json,xml,plain,默认为json。 + * | ------------- |----------------------------------------------------------- + * | grammarID |识别的语法id: 只针对 domain 设置为”asr”的应用。 + * | ------------- |----------------------------------------------------------- + * | asr_audio_path|音频文件名: 设置此参数后,将会自动保存识别的录音文件。 + * | | 路径为Documents/(指定值)。 + * | | 不设置或者设置为nil,则不保存音频。 + * | ------------- |----------------------------------------------------------- + * | params |扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。 + * | ------------- |----------------------------------------------------------- + * + */ + +/*! + * 设置语义理解引擎的参数 + * + * 语义理解的引擎参数(key)取值如下: + * + * | 参数 | 描述 | + * |-----------------|-------------------------------------------------------| + * | domain | 应用的领域: 取值为:iat、search、video、poi、music、asr;
iat:普通文本听写;
search:热词搜索;
video:视频音乐搜索;
asr:关键词识别;| + * | vad_bos | 前端点检测: 静音超时时间,即用户多长时间不说话则当做超时处理; 单位:ms;
engine指定iat识别默认值为5000;
其他情况默认值为 4000,范围 0-10000。| + * | vad_eos | 后断点检测: 后端点静音检测时间,即用户停止说话多长时间内即认为不再输入,自动停止录音;单位:ms;
sms 识别默认值为 1800;
其他默认值为 700,范围 0-10000。| + * | sample_rate | 采样率:目前支持的采样率设置有 16000 和 8000。| + * | asr_ptt | 标点符号设置: 默认为 1,当设置为 0 时,将返回无标点符号文本。| + * | result_type | 返回结果的数据格式: 可设置为json,xml,plain,默认为json。| + * | grammarID | 识别的语法id: 只针对 domain 设置为”asr”的应用。| + * | asr_audio_path | 音频文件名: 设置此参数后,将会自动保存识别的录音文件。
路径为Documents/(指定值)。
不设置或者设置为nil,则不保存音频。| + * | params | 扩展参数: 对于一些特殊的参数可在此设置,一般用于设置语义。| + * + * @param value 参数对应的取值 + * @param key 语义理解引擎参数 + * + * @return 成功返回YES;失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 写入音频流 + * + * @param audioData 音频数据 + * + * @return 写入成功返回YES,写入失败返回NO + */ +- (BOOL) writeAudio:(NSData *) audioData; + +/*! + * 销毁语义理解对象。 + * + * @return 成功返回YES;失败返回NO + */ +- (BOOL) destroy; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUtility.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUtility.h new file mode 100644 index 0000000..13fdd2a --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlySpeechUtility.h @@ -0,0 +1,184 @@ +// +// IFlySpeechUtility.h +// MSCDemo +// +// Created by admin on 14-5-7. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + +#import + +#define iOS_EXCLUSIVE //iOS平台独占API + +@class IFlySpeechError; + +/*! + * 引擎模式 + */ +typedef NS_ENUM(NSUInteger,IFlyEngineMode){ + /*! + * 云端使用MSC,本地优先使用语记 + */ + IFlyEngineModeAuto = 0, + /*! + * 只使用MSC + */ + IFlyEngineModeMsc, + /*! + * 本地只使用语记(受平台限制,云端无法使用语记) + */ + IFlyEngineModePlus, +}; + + +/*! + * 服务类型 + */ +typedef NS_ENUM(NSUInteger,IFlySpeechPlusServiceType){ + /*! + * 打开语记主界面 + */ + IFlySpeechPlusServiceTypeNone=0, + /*! + * 获取合成资源 + */ + IFlySpeechPlusServiceTypeTTS, + /*! + * 获取识别资源(未开放) + */ + IFlySpeechPlusServiceTypeISR, + /*! + * 获取唤醒资源(未开放) + */ + IFlySpeechPlusServiceTypeIVW, +} ; + +/*! 语记返回回调 + */ +@protocol IFlySpeechplusDelegate + +/*! + * 发生错误 + * + * @param errorCode 错误码 + */ +- (void)onCompleted:(int)errorCode; + +/*! + * 服务正常结束 + */ +- (void)onCompleted; + +@end + +/*! + * 用户配置 + */ +@interface IFlySpeechUtility : NSObject + +/*! + * 创建用户语音配置
+ * 注册应用请前往语音云开发者网站。
+ * 网站:http://www.xfyun.cn + * + * @param params 启动参数,必须保证appid参数传入,示例:appid=123456 + * + * @return 语音配置对象 + */ ++ (IFlySpeechUtility*) createUtility:(NSString *) params; + +/*! + * 销毁用户配置对象 + * + * @return 成功返回YES,失败返回NO + */ ++(BOOL) destroy; + +/*! + * 获取用户配置对象 + * + * @return 用户配置对象 + */ ++(IFlySpeechUtility *) getUtility; + +/*! + * 设置MSC引擎的状态参数 + * + * @param value 参数值 + * @param key 参数名称 + * + * @return 成功返回YES,失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 获取MSC引擎状态参数 + * + * @param key 参数名 + * + * @return 参数值 + */ +- (NSString *)parameterForKey:(NSString *)key; + +/*! + * 引擎类型 + */ +@property (nonatomic, readonly) IFlyEngineMode engineMode; + +/*! + * 语记协议委托 + */ +@property (nonatomic, assign) id delegate; + +@end + +/*! + * 讯飞语记类别 + */ +@interface IFlySpeechUtility (SpeechPlus) + +/*! + * 检查讯飞语记是否安装 + * + * @return 已安装返回YES,否则返回NO + */ ++ (BOOL)checkServiceInstalled; + +/*! + * 获取讯飞语记下载地址进行下载,安装完成后即可使用服务。
+ * 下载地址需要通过[[UIApplication sharedApplication] openUrl:]打开 + * + * @return 讯飞语记在App Store下载地址 + */ ++ (NSString *)componentUrl; + + +/*! + * 注意:此接口废弃,不再需要使用
+ * 处理语记使用URL启动第三方应用程序时传递的数据
+ * 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。 + * + * @param url 语记启动第三方应用程序时传递过来的URL + * + * @return 成功返回YES,失败返回NO。 + */ +- (BOOL)handleOpenURL:(NSURL *)url iOS_EXCLUSIVE; + +/*! + * 打开讯飞语记获取相应类型服务,0表示打开主界面 + * + * @param serviceType 服务类型 + * + * @return 成功打开返回YES,否则返回NO + */ +- (BOOL)openSpeechPlus:(IFlySpeechPlusServiceType)serviceType iOS_EXCLUSIVE; + +@end + + + + + + + + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyTextUnderstander.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyTextUnderstander.h new file mode 100644 index 0000000..b411a23 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyTextUnderstander.h @@ -0,0 +1,57 @@ +// +// TextUnderstand.h +// MSCDemo +// +// Created by iflytek on 4/24/14. +// Copyright (c) 2014 iflytek. All rights reserved. +// + +#import + +@class IFlySpeechError; + +/*! + * 文本转语义完成回调函数 + * + * @param result 成功,返回文本语义理解结果 + * @param error 错误描述 + */ +typedef void(^IFlyUnderstandTextCompletionHandler)(NSString* result, IFlySpeechError * error); + +/*! + * 文本转语义类 + */ +@interface IFlyTextUnderstander : NSObject + +/*! + * 是否正在文本转语义 + */ +@property (readonly, atomic) __block BOOL isUnderstanding; + +/*! + * 文本转语义接口
+ * 输入文本内容,获取语义理解结果 + * + * @param text 输入的文本内容 + * @param completionHandler 文本转语义完成回调函数 + * + * @return 错误码 + */ +-(int) understandText:(NSString*)text withCompletionHandler:(IFlyUnderstandTextCompletionHandler) completionHandler; + +/*! + * 设置文本转语义参数 + * + * @param value 参数对应的取值 + * @param key 文本转语义参数参数 + * + * @return 成功返回YES,失败返回NO + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +/*! + * 取消本次会话 + */ +-(void)cancel; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyUserWords.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyUserWords.h new file mode 100644 index 0000000..f7fc91b --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyUserWords.h @@ -0,0 +1,74 @@ +// +// IFlyUserWords.h +// MSC +// +// Created by ypzhao on 13-2-26. +// Copyright (c) 2013年 iflytek. All rights reserved. +// + +#import + +/*! + * 用户词表类 + * 获取用户词表是为了更好的语音识别(iat),用户词表也属于个性化的一部分. + */ +@interface IFlyUserWords : NSObject + +/*! + * 初始化对象 + * + * 在进行初始化时,需要传入的格式如下: + *
{\"userword\":[{\"name\":\"iflytek\",\"words\":[\"科大讯飞\",
+ *  \"云平台\",\"用户词条\",\"开始上传词条\"]}]}
+ * + * @param json 初始化时传入的数据 + * + * @return IFlyUserWords对象 + */ +- (id) initWithJson:(NSString *)json; + +/*! + * 将数据转化为上传的数据格式 + * + * @return 没有数据或者格式不对时返回nil + */ +- (NSString *) toString; + +/*! + * 返回key对应的数据 + * + * @param key 在putword:value中设置的key + * + * @return key对应的数组 + */ +- (NSArray *) getWords: (NSString *) key; + +/*! + * 添加一条用户词数据 + * + * @param key 用户词对应的key + * @param value 上传的用户词数据 + * + * @return 成功返回YES,失败返回NO + */ +- (BOOL) putWord: (NSString *) key value:(NSString *)value; + +/*! + * 添加一组数据 + * + * @param key 用户词对应的key + * @param words 上传的用户词数据 + * + * @return 成功返回YES,失败返回NO + */ +- (BOOL) putwords: (NSString *) key words:(NSArray *)words; + +/*! + * 是否包含key对应的用户词数据 + * + * @param key 用户词对应的key + * + * @return 成功返回YES,失败返回NO + */ +- (BOOL) containsKey: (NSString *) key; +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVerifierUtil.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVerifierUtil.h new file mode 100644 index 0000000..b9bda99 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVerifierUtil.h @@ -0,0 +1,39 @@ +// +// IFlyVerifierUtil.h +// IFlyMSC +// +// Created by 张剑 on 15/4/28. +// Copyright (c) 2015年 iflytek. All rights reserved. +// + +#import +#import + +/** + * 身份验证工具类 + */ +@interface IFlyVerifierUtil : NSObject + +#pragma mark - ISV + +/** + * 返回定长的随机数字字符串(不包含数字1,而且2和5不邻接) + * + * @param length 随机字符串长度 + * + * @return 随机字符串 + */ ++(NSString*)generateNumberPassword:(int)length; + + +#pragma mark - Face +/** + * ARGB彩图转灰度图,Detector和Alignment需要灰度图的输入 + * + * @param sourceImage ARGB彩图 + * + * @return 灰度图 + */ ++ (UIImage*)ARGBToGray:(UIImage*)sourceImage; + +@end diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuper.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuper.h new file mode 100644 index 0000000..de51776 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuper.h @@ -0,0 +1,83 @@ +// +// IFlyVoiceWakeuper.h +// wakeup +// +// Created by admin on 14-3-18. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + + +#import +#import "IFlyVoiceWakeuperDelegate.h" + +#define IFLY_AUDIO_SOURCE_MIC @"1" +#define IFLY_AUDIO_SOURCE_STREAM @"-1" + +/*! + * 语音唤醒 + */ +@interface IFlyVoiceWakeuper : NSObject + +/*! + * 代理 + */ +@property (nonatomic, assign) id delegate; + +/*! + * 是否正在唤醒 + */ +@property (nonatomic, readonly) BOOL isListening; + +/*! + * 创建唤醒实例,采用单例模式 + */ ++ (instancetype) sharedInstance; + + +/*! + * 启动唤醒 + * 返回值:YES 成功,NO:失败 + */ +-(BOOL) startListening; + +/*! + * 停止录音 + */ +-(BOOL) stopListening; + +/*! + * 取消唤醒会话 + */ +-(BOOL) cancel; + +/*! + * 获取工作参数 + */ +-(NSString*) getParameter:(NSString *)key; + +/*! + * 设置工作参数
+ * 注意服务正在运行中,不能设置参数 + */ +-(BOOL) setParameter:(NSString *) value forKey:(NSString*)key; + +@end + +/*! + * 音频流唤醒
+ * 音频流唤醒可以将文件分段写入 + */ +@interface IFlyVoiceWakeuper(IFlyStreamVoiceWakeuper) + +/*! + * 写入音频流 + * + * @param audioData 音频数据 + * + * @return 写入成功返回YES,写入失败返回NO + */ +- (BOOL) writeAudio:(NSData *) audioData; + +@end + + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuperDelegate.h b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuperDelegate.h new file mode 100644 index 0000000..9032a8e --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/Headers/IFlyVoiceWakeuperDelegate.h @@ -0,0 +1,60 @@ + +// +// IFlyVoiceWakeuperDel.h +// wakeup +// +// Created by admin on 14-3-18. +// Copyright (c) 2014年 iflytek. All rights reserved. +// + + + +#import + +@class IFlySpeechError; + +@protocol IFlyVoiceWakeuperDelegate + +@optional + +/*! + * 录音开始 + */ +-(void) onBeginOfSpeech; + +/*! + * 录音结束 + */ +-(void) onEndOfSpeech; + +/*! + * 会话错误 + * + * @param errorCode 错误描述类, + */ +- (void) onCompleted:(IFlySpeechError *) error; + +/*! + * 唤醒结果 + * + * @param resultDic 唤醒结果字典 + */ +-(void) onResult:(NSMutableDictionary *)resultDic; + +/*! + * 音量反馈,返回频率与录音数据返回回调频率一致 + * + * @param volume 音量值 + */ +- (void) onVolumeChanged: (int)volume; + +/*! + * 扩展事件回调
+ * 根据事件类型返回额外的数据 + * + @param eventType 事件类型,具体参见IFlySpeechEvent枚举。 + */ +- (void) onEvent:(int)eventType isLast:(BOOL)isLast arg1:(int)arg1 data:(NSMutableDictionary *)eventData; + +@end + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/PrivacyInfo.xcprivacy b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..f0db006 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/PrivacyInfo.xcprivacy @@ -0,0 +1,17 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + diff --git a/ProductApp/ProductApp/BaseControl/iflyMSC.framework/iflyMSC b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/iflyMSC new file mode 100644 index 0000000..906da9f Binary files /dev/null and b/ProductApp/ProductApp/BaseControl/iflyMSC.framework/iflyMSC differ diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_back@2x.png b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_back@2x.png new file mode 100644 index 0000000..4a55816 Binary files /dev/null and b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_back@2x.png differ diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_refresh@2x.png b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_refresh@2x.png new file mode 100644 index 0000000..767d84c Binary files /dev/null and b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/alipay_msp_refresh@2x.png differ diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bar@2x.png b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bar@2x.png new file mode 100644 index 0000000..9f5fa56 Binary files /dev/null and b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bar@2x.png differ diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bridge.js b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bridge.js new file mode 100644 index 0000000..0d37a94 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.bundle/bridge.js @@ -0,0 +1 @@ +!function(){if(!window.AlipayJSBridge){window.alipayjsbridgeSetTitle=function(e){document.title=e,t("alipayjsbridge://setTitle?title="+encodeURIComponent(e))},window.alipayjsbridgeRefresh=function(){t("alipayjsbridge://onRefresh?")},window.alipayjsbridgeBack=function(){t("alipayjsbridge://onBack?")},window.alipayjsbridgeExit=function(e){t("alipayjsbridge://onExit?bsucc="+e)},window.alipayjsbridgeShowBackButton=function(e){t("alipayjsbridge://showBackButton?bshow="+e)},window.AlipayJSBridge={version:"2.0",addListener:function(e,i){a[e]=i},hasListener:function(e){if(!a[e])return!1;return!0},callListener:function(e,i,n){var t;n&&(t=function(e){var i="";e&&(i=encodeURIComponent(JSON.stringify(e)));var a="func=h5JsFuncCallback&cbId="+n+"&data="+i;o(a)});var r=a[e];r?r(i,t):console.log("AlipayJSBridge: no h5JsFunc ",e+i)},callNativeFunc:function(e,a,t){var r="";t&&(r="cb_"+i+++"_"+(new Date).getTime(),n[r]=t);var d="";a&&(d=encodeURIComponent(JSON.stringify(a)));o("func="+e+"&cbId="+r+"&data="+d)},callBackFromNativeFunc:function(e,i){var a=n[e];a&&(a(i),delete n[i])}};var e,i=1,n={},a={};window.CustomEvent?e=new CustomEvent("alipayjsbridgeready"):(e=document.createEvent("Event")).initEvent("alipayjsbridgeready",!0,!0),document.dispatchEvent(e),setTimeout(function(){if(window.AlipayJSBridgeInitArray){var e=window.AlipayJSBridgeInitArray;delete window.AlipayJSBridgeInitArray;for(var i=0;i + +@class AFServiceResponse; + +/** + SDK支持的业务枚举值 + + - AFServiceEInvoice: 电子发票 + - AFServiceAuth: 账户授权 + */ +typedef NS_ENUM(NSUInteger, AFService) { + AFServiceEInvoice, + AFServiceAuth, + AFServiceDeduct +}; + + +extern NSString * const kAFServiceOptionBizParams; // 钱包服务调用入参 +extern NSString * const kAFServiceOptionCallbackScheme; // 业务回跳当前app的scheme +extern NSString * const kAFServiceOptionNotUseLanding; // 不使用支付宝提示下载页做补偿,为true时需要商户自己处理用户未安装支付宝的情况 +extern NSString * const kAFServiceBizParamsKeyUrl; // 独立签约入参url + +typedef void(^AFServiceResultBlock)(AFServiceResponse *response); + +@interface AFServiceCenter : NSObject + +/** + 调用钱包服务 + + @param service 业务service, 见AFService枚举值 + @param params 参数Dictionary, key值详情参见kAFServiceOptionBizParams、kAFServiceOptionCallbackScheme注释 + @param block 业务结果回调的block, block参数是AFServiceResponse类型,业务结果通过result属性获取,如果未用户未安装支付宝并且kAFServiceOptionNotUseLanding未设置为true,会使用H5landing页做补偿,这种情况下不会有block回调结果。 + */ ++ (void)callService:(AFService)service + withParams:(NSDictionary *)params + andCompletion:(AFServiceResultBlock)block; + + +/** + 处理钱包服务回跳APP的URL + + @param url 回跳URL + @param block 业务结果回掉的block,详情见调用接口入参上的block。注意此接口上的block只有在跳转钱包后,当前APP被系统回收的情况下回跳才生效 + */ ++ (void)handleResponseURL:(NSURL *)url + withCompletion:(AFServiceResultBlock)block; + +@end diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AFServiceResponse.h b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AFServiceResponse.h new file mode 100644 index 0000000..801fbf8 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AFServiceResponse.h @@ -0,0 +1,43 @@ +// +// AFServiceResponse.h +// AFServiceSDK +// +// Created by jiajunchen on 08/01/2018. +// Copyright © 2018 antfin. All rights reserved. +// + +#import + +/** + 钱包服务调用结果状态吗 + + - AFResSuccess: 默认值,业务调用成功,结果数据参见result字段 + - AFResInvalidService: service枚举值错误 + - AFResInvalidURL: 钱包回跳URL错误 + - AFResRepeatCall: 业务重复调用(3s内) + - AFResOpenURLErr: 跳转失败 + */ +typedef NS_ENUM(NSUInteger, AFResCode) { + AFResSuccess = 0, + AFResInvalidService = 100, + AFResInvalidURL, + AFResRepeatCall, + AFResOpenURLErr, +}; + + +@interface AFServiceResponse : NSObject + + +/** + 业务调用状态吗 + */ +@property (nonatomic, assign) AFResCode responseCode; + + +/** + 业务结果Dictionary, 内容请参考具体业务方接入文档 + */ +@property (readonly) NSDictionary *result; + +@end diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/APayAuthInfo.h b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/APayAuthInfo.h new file mode 100644 index 0000000..afab31e --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/APayAuthInfo.h @@ -0,0 +1,33 @@ +// +// APAuthInfo.h +// APAuth +// +// Created by antfin on 17-10-24. +// Copyright (c) 2017年 AntFin. All rights reserved. +// + +#import + +@interface APayAuthInfo : NSObject + +@property(nonatomic, copy)NSString *appID; +@property(nonatomic, copy)NSString *pid; +@property(nonatomic, copy)NSString *redirectUri; + +/** + * 初始化AuthInfo + * + * @param appIDStr 应用ID + * @param pidStr 商户ID 可不填 + * @param uriStr 授权的应用回调地址 比如:alidemo://auth + * + * @return authinfo实例 + */ +- (id)initWithAppID:(NSString *)appIDStr + pid:(NSString *)pidStr + redirectUri:(NSString *)uriStr; + +- (NSString *)description; +- (NSString *)wapDescription; + +@end diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDK.h b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDK.h new file mode 100644 index 0000000..c956c0a --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDK.h @@ -0,0 +1,246 @@ +// +// AlipaySDK.h +// AlipaySDK +// +// Created by antfin on 17-10-24. +// Copyright (c) 2017年 AntFin. All rights reserved. +// + + +//////////////////////////////////////////////////////// +///////////////// 支付宝标准版本支付SDK /////////////////// +///////// version:15.8.18 modify:2024.04.08/////////// +//////////////////////////////////////////////////////// + +#import +#import "APayAuthInfo.h" +#import "AFServiceCenter.h" +#import "AFServiceResponse.h" + +typedef void(^CompletionBlock)(NSDictionary *resultDic); + +typedef enum { + ALIPAY_TIDFACTOR_IMEI, + ALIPAY_TIDFACTOR_IMSI, + ALIPAY_TIDFACTOR_TID, + ALIPAY_TIDFACTOR_CLIENTKEY, + ALIPAY_TIDFACTOR_VIMEI, + ALIPAY_TIDFACTOR_VIMSI, + ALIPAY_TIDFACTOR_CLIENTID, + ALIPAY_TIDFACTOR_APDID, + ALIPAY_TIDFACTOR_MAX +} AlipayTidFactor; + +@interface AlipaySDK : NSObject + +/** + * 创建支付单例服务 + * + * @return 返回单例对象 + */ ++ (AlipaySDK *)defaultService; + +/** + * 用于设置SDK使用的window,如果没有自行创建window无需设置此接口 + */ +@property (nonatomic, weak) UIWindow *targetWindow; + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝支付相关接口///////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * 支付接口 + * + * @param orderStr 支付订单信息字串 + * @param schemeStr 调用支付的app注册在info.plist中的scheme + * @param completionBlock 支付结果回调Block,用于wap支付结果回调,跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock + */ +- (void)payOrder:(NSString *)orderStr + fromScheme:(NSString *)schemeStr + callback:(CompletionBlock)completionBlock; + +/** + * 支付接口 v2 + * + * @param orderStr 支付订单信息字串 + * @param dynamicLaunch 是否使用动态配置策略跳转支付宝支付 + * @param schemeStr 调用支付的app注册在info.plist中的scheme + * @param completionBlock 支付结果回调Block,用于wap支付结果回调 + 跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock + */ +- (void)payOrder:(NSString *)orderStr + dynamicLaunch:(BOOL)dynamicLaunch + fromScheme:(NSString *)schemeStr + callback:(CompletionBlock)completionBlock; + +/** + * 处理支付宝app支付后跳回商户app携带的支付结果Url + * + * @param resultUrl 支付宝app返回的支付结果url + * @param completionBlock 支付结果回调 为nil时默认使用支付接口的completionBlock + */ +- (void)processOrderWithPaymentResult:(NSURL *)resultUrl + standbyCallback:(CompletionBlock)completionBlock; + + +/** + * 商户接入UniversalLink支付接口使用该接口 + * + * @param orderStr 支付订单信息字串 + * @param schemeStr 调用支付的app注册在info.plist中的scheme + * @param universalLink 调用支付的app关联的universalLink,如'https://render.alipay.com/' + * @param completionBlock 支付结果回调Block,用于wap支付结果回调,跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock + */ +- (void) payOrder:(NSString *)orderStr + fromScheme:(NSString *)schemeStr +fromUniversalLink:(NSString *)universalLink + callback:(CompletionBlock)completionBlock; + + +/** + * 处理支付宝app支付后通过universalLink跳回商户app携带的支付结果处理 + * + * @param userActivity 系统接口传入的userActivity + * @param completionBlock 支付结果回调 为nil时默认使用支付接口的completionBlock + */ +- (void)handleOpenUniversalLink:(NSUserActivity *)userActivity standbyCallback:(CompletionBlock)completionBlock; + + +/** + * 获取交易token。 + * + * @return 交易token,若无则为空。 + */ +- (NSString *)fetchTradeToken; + + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝授权 2.0 相关接口//////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * 快登授权2.0 + * + * @param infoStr 授权请求信息字串 + * @param schemeStr 调用授权的app注册在info.plist中的scheme + * @param completionBlock 授权结果回调,需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果 + * 若在授权过程中,调用方应用被系统终止则此block无效(此时会调用'processAuth_V2Result:standbyCallback:'传入的standbyCallback) + */ +- (void)auth_V2WithInfo:(NSString *)infoStr + fromScheme:(NSString *)schemeStr + callback:(CompletionBlock)completionBlock; + +/** + * 处理支付宝app授权后跳回商户app携带的授权结果Url + * + * @param resultUrl 支付宝app返回的授权结果url + * @param completionBlock 授权结果回调,用于处理跳转支付宝授权过程中商户APP被系统终止的情况 + */ +- (void)processAuth_V2Result:(NSURL *)resultUrl + standbyCallback:(CompletionBlock)completionBlock; + + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝授权 1.0 相关接口//////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// + + +/** + * 快登授权 + * @param authInfo 授权相关信息 + * @param completionBlock 授权结果回调,若在授权过程中,调用方应用被系统终止,则此block无效, + 需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果 + */ +- (void)authWithInfo:(APayAuthInfo *)authInfo + callback:(CompletionBlock)completionBlock; + +/** + * 处理支付宝app授权后跳回商户app携带的授权结果Url + * + * @param resultUrl 支付宝app返回的授权结果url + * @param completionBlock 授权结果回调 + */ +- (void)processAuthResult:(NSURL *)resultUrl + standbyCallback:(CompletionBlock)completionBlock; + + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝 h5 支付转 native 支付接口//////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 从h5链接中获取订单串并支付接口(自版本15.4.0起,推荐使用该接口) + * + * @param urlStr 拦截的 url string + * + * @return YES为成功获取订单信息并发起支付流程;NO为无法获取订单信息,输入url是普通url + */ +- (BOOL)payInterceptorWithUrl:(NSString *)urlStr + fromScheme:(NSString *)schemeStr + callback:(CompletionBlock)completionBlock; + + + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝 tid 相关信息获取接口///////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * 获取当前tid相关信息 + * + * @return tid相关信息 + */ +- (NSString*)queryTidFactor:(AlipayTidFactor)factor; + + + +////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////支付宝支付环境相关信息接口////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * 是否已经使用过 + * + * @return YES为已经使用过,NO反之 + */ +- (BOOL)isLogined; + +/** + * 获取当前版本号 + * + * @return 当前版本字符串 + */ +- (NSString *)currentVersion; + +/** + * 測試所用,realse包无效 + * + * @param url 测试环境 + */ +- (void)setUrl:(NSString *)url; + +/** + * 支付前主动更新本地配置 + * + * @param block 更新请求结果回调 + */ +- (void)fetchSdkConfigWithBlock:(void(^)(BOOL success))block; + + +typedef void(^APLogBlock)(NSString *log); + +/** +* 接收AlipaySDK的log信息 +* +* @param logBlock 打印log的回调block +*/ ++ (void)startLogWithBlock:(APLogBlock)logBlock; + +/** +* 停止输出log,会释放logBlock +* +* +*/ ++ (void)stopLog; + +@end diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDKModule.h b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDKModule.h new file mode 100644 index 0000000..00183b9 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Headers/AlipaySDKModule.h @@ -0,0 +1,17 @@ +// +// AlipaySDKModule.h +// AlipaySDK +// +// Created by mingsheng on 2023/11/14. +// Copyright © 2023 Alipay. All rights reserved. +// + +#ifndef AlipaySDKModule_h +#define AlipaySDKModule_h + +#import "AlipaySDK.h" +#import "APayAuthInfo.h" +#import "AFServiceCenter.h" +#import "AFServiceResponse.h" + +#endif /* AlipaySDKModule_h */ diff --git a/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Modules/module.modulemap b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Modules/module.modulemap new file mode 100644 index 0000000..a7db362 --- /dev/null +++ b/ProductApp/ProductApp/BaseControl/zfbSdk/AlipaySDK.framework/Modules/module.modulemap @@ -0,0 +1,14 @@ +// +// AlipaySDK.modulemap +// AlipaySDK +// +// Created by mingsheng on 2023/11/14. +// Copyright © 2023 Alipay. All rights reserved. +// + +framework module AlipaySDK { + umbrella header "AlipaySDKModule.h" + + export * + module * { export * } +} diff --git a/ProductApp/ProductApp/Configure/ConfigireSetting.h b/ProductApp/ProductApp/Configure/ConfigireSetting.h index b03f221..9c35d03 100644 --- a/ProductApp/ProductApp/Configure/ConfigireSetting.h +++ b/ProductApp/ProductApp/Configure/ConfigireSetting.h @@ -27,8 +27,14 @@ NS_ASSUME_NONNULL_BEGIN #define WeiXinStringPay @"5b6u5L+h5pSv5LuY" #define ZhiFuBaoStringPay @"5pSv5LuY5a6d5pSv5LuY" +/// 个推开发者网站中申请App时,注册的AppId、AppKey、AppSecret +#define kGtAppId @"bgxjUoVnGE65VaJLpy40T6" +#define kGtAppKey @"o20R2nHKevAixnfCD66ZO9" +#define kGtAppSecret @"FjOHLjio6GAGnOl3rphtt4" +///讯飞appid +#define XunFeiAppId @"a26724a7" //网络请求数据回调block #define SAFE_BLOCK_CALL_NO_P(b) (b == nil ?: b()) @@ -103,7 +109,15 @@ alpha:alphaValue] ///设备uuid #define UserIDFA @"UserIDFA" +///登录账号弹窗 +#define DengluZhangHaoTanChuang @"DengluZhangHaoTanChuang" +///隐私协议 +#define UserYinSiUrl @"" +#define UserXieUrl @"" + +///微信登录通知 +#define WeiXinDengLuSQ @"WeiXinDengLuSQ" @end diff --git a/ProductApp/ProductApp/Info.plist b/ProductApp/ProductApp/Info.plist index 283cba8..7cc10fc 100644 --- a/ProductApp/ProductApp/Info.plist +++ b/ProductApp/ProductApp/Info.plist @@ -2,6 +2,8 @@ + GT_MinimumOSVersion + 11 LSApplicationQueriesSchemes weixin @@ -11,6 +13,36 @@ NSAllowsArbitraryLoads + NSExceptionDomains + + id6.me + + NSAllowsArbitraryLoadsInWebContent + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + mdn.open.wo.cn + + NSAllowsArbitraryLoadsInWebContent + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + wap.cmpassport.com + + NSAllowsArbitraryLoadsInWebContent + + NSExceptionAllowsInsecureHTTPLoads + + NSIncludesSubdomains + + + UIAppFonts diff --git a/ProductApp/ProductApp/PrefixHeader.pch b/ProductApp/ProductApp/PrefixHeader.pch index 236aa68..818a8d6 100644 --- a/ProductApp/ProductApp/PrefixHeader.pch +++ b/ProductApp/ProductApp/PrefixHeader.pch @@ -40,4 +40,7 @@ #import "UIImageView+PWebCache.h" #import "PGJUILabel.h" #import "ViewLable.h" + +#import "LoadAlterView.h" + #endif /* PrefixHeader_pch */ diff --git a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatBottomView.m b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatBottomView.m index 76c208a..8144eb9 100644 --- a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatBottomView.m +++ b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatBottomView.m @@ -21,6 +21,12 @@ @property (nonatomic , strong) UIButton *btsend; @property (nonatomic , strong) UIButton *btyuyin ; +/// +@property (nonatomic , strong) AIChatYuYinView *viewYy; + +/// +@property (nonatomic , assign) NSInteger starttime; + @end @implementation AIChatBottomView @@ -134,6 +140,14 @@ [btyuyin addTarget:self action:@selector(yuyinDownAction) forControlEvents:UIControlEventTouchDown]; [btyuyin addTarget:self action:@selector(yuyinUpAction) forControlEvents:UIControlEventTouchUpInside]; + [btyuyin addTarget:self action:@selector(yuyinUpAction) forControlEvents:UIControlEventTouchCancel]; + [btyuyin addTarget:self action:@selector(yuyinUpAction) forControlEvents:UIControlEventTouchUpOutside]; + + + [btyuyin addTarget:self action:@selector(yuyinInAction) forControlEvents:UIControlEventTouchDragInside]; + [btyuyin addTarget:self action:@selector(yuyinChangeAction) forControlEvents:UIControlEventTouchDragOutside]; + + [btyuyin setHidden:YES]; _btyuyin = btyuyin; } @@ -144,11 +158,37 @@ { AIChatYuYinView *view = [[AIChatYuYinView alloc] initWithFrame:CGRectMake(0, 0, UISCREEN_WIDTH, UISCREEN_HEIGHT)];; [self.viewController.view.window addSubview:view]; + _viewYy = view; NSLog(@"按下"); + self.starttime = [[Tools getCurrentTime:@"yyyyMMddHHmmss"] integerValue]; } -(void)yuyinUpAction { NSLog(@"放开"); + if(self.viewYy.type==1) + { + [self.viewYy removeAllInfo]; + [self.viewYy removeFromSuperview]; + } + else + { + self.viewYy.isbtend = YES; + NSInteger end = [[Tools getCurrentTime:@"yyyyMMddHHmmss"] integerValue]; + if(end-self.starttime<=0) + { + [self.viewYy removeAllInfo]; + [self.viewYy removeFromSuperview]; + [HXHud showMessage:@"录音时间太短" afterDelayType:0]; + } + } +} +-(void)yuyinChangeAction +{ + self.viewYy.type=1; +} +-(void)yuyinInAction +{ + self.viewYy.type=0; } -(void)inputAction:(UIButton *)sender diff --git a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.h b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.h index 26cb4cc..9941cfd 100644 --- a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.h +++ b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.h @@ -11,6 +11,12 @@ NS_ASSUME_NONNULL_BEGIN @interface AIChatYuYinView : UIView +@property (nonatomic , assign) int type; + +@property (nonatomic , assign) BOOL isbtend; + +-(void)removeAllInfo; + @end NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.m b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.m index ebf2da0..43f7dce 100644 --- a/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.m +++ b/ProductApp/ProductApp/ProductMain/AIChart/view/AIChatYuYinView.m @@ -7,20 +7,34 @@ #import "AIChatYuYinView.h" #import "AIChatYuYinBackView.h" +#import "IFlyMSC/IFlyMSC.h" -@interface AIChatYuYinView () +@interface AIChatYuYinView () /// @property (nonatomic , strong) UIButton *btok; +@property (nonatomic , strong) UIButton *btcancle; + +@property (nonatomic , assign) BOOL iseyend; /// @property (nonatomic , strong) AIChatYuYinBackView *viewback; /// @property (nonatomic , strong) UITextView *textview; +//不带界面的识别对象 +@property (nonatomic, strong) IFlySpeechRecognizer *iFlySpeechRecognizer; + +/// +@property (nonatomic , strong) NSMutableString *strshibie; + @end @implementation AIChatYuYinView - +-(void)removeAllInfo +{ + [self.iFlySpeechRecognizer stopListening]; + [self.iFlySpeechRecognizer cancel]; +} -(id)initWithFrame:(CGRect)frame { if(self = [super initWithFrame:frame]) @@ -36,6 +50,7 @@ make.width.height.offset(70); }]; [btcancle addTarget:self action:@selector(cancleAction) forControlEvents:UIControlEventTouchUpInside]; + _btcancle = btcancle; UIButton *btok = [[UIButton alloc] init]; [btok setImage:[UIImage imageNamed:@"ai_yuyin_ok"] forState:UIControlStateNormal]; @@ -45,6 +60,7 @@ make.centerY.equalTo(btcancle); make.width.height.offset(90); }]; + [btok setHidden:YES]; [btok addTarget:self action:@selector(okAction) forControlEvents:UIControlEventTouchUpInside]; _btok = btok; @@ -74,6 +90,7 @@ }]; _textview = textview; + [self startYuYIn]; } return self; } @@ -106,6 +123,24 @@ } +-(void)setType:(int)type +{ + _type = type; + if(type==1) + { + [self.btcancle mas_updateConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(90); + }]; + [self.btcancle setImage:[UIImage imageNamed:@"ai_yuyin_bai"] forState:UIControlStateNormal]; + } + else + { + [self.btcancle mas_updateConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(70); + }]; + [self.btcancle setImage:[UIImage imageNamed:@"ai_yuyin_x"] forState:UIControlStateNormal]; + } +} -(void)cancleAction { @@ -113,10 +148,78 @@ } -(void)okAction { - [self noinfo]; +// [self noinfo]; // self.textview.text = @"测试"; +} + +-(void)startYuYIn +{ + self.strshibie = [[NSMutableString alloc] init]; + //创建语音识别对象 + _iFlySpeechRecognizer = [IFlySpeechRecognizer sharedInstance]; + //设置识别参数 + //设置为听写模式 + [_iFlySpeechRecognizer setParameter: @"iat" forKey: [IFlySpeechConstant IFLY_DOMAIN]]; + //asr_audio_path 是录音文件名,设置value为nil或者为空取消保存,默认保存目录在Library/cache下。 + [_iFlySpeechRecognizer setParameter:@"iat.pcm" forKey:[IFlySpeechConstant ASR_AUDIO_PATH]]; + [_iFlySpeechRecognizer setDelegate:self]; + //启动识别服务 + [_iFlySpeechRecognizer startListening]; +} + +#pragma mark -//IFlySpeechRecognizerDelegate协议实现 +//识别结果返回代理 +- (void) onResults:(NSArray *) results isLast:(BOOL)isLast{ +// NSLog(@"%@",results); + for(NSDictionary *dicvalue in results) + { + NSArray *arrkeys = [dicvalue allKeys]; + for(NSString *strkey in arrkeys) + { + NSDictionary *dicitem = [NSJSONSerialization JSONObjectWithData:[strkey dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil]; + NSArray *arr = [dicitem objectForKey:@"ws"]; + for(NSDictionary *dic in arr) + { + NSArray *arrcw = [dic objectForKey:@"cw"]; + for(NSDictionary *dicson in arrcw) + { + [self.strshibie appendString:[dicson objectForKey:@"w"]]; + } + } + } + } + self.textview.text = self.strshibie; +} +//识别会话结束返回代理 +- (void)onCompleted: (IFlySpeechError *) error{ + NSLog(@"识别会话结束返回代理"); + self.iseyend = YES; + if(self.isbtend && self.strshibie.length==0) + { + [self noinfo]; + } + if(self.strshibie.length>0&&self.isbtend) + { + [self.btok setHidden:NO]; + } +} +//停止录音回调 +- (void) onEndOfSpeech{ + +} +//开始录音回调 +- (void) onBeginOfSpeech{ + +} +//音量回调函数 +- (void) onVolumeChanged: (int)volume{ + +} +//会话取消回调 +- (void) onCancel{ + } @end diff --git a/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.h b/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.h new file mode 100644 index 0000000..703324b --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.h @@ -0,0 +1,17 @@ +// +// LoadAlterView.h +// ProductApp +// +// Created by 工作 on 2024/10/18. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LoadAlterView : UIView ++(void)show; ++(void)dismiss; +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.m b/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.m new file mode 100644 index 0000000..76c1a52 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/alter/LoadAlterView.m @@ -0,0 +1,95 @@ +// +// LoadAlterView.m +// ProductApp +// +// Created by 工作 on 2024/10/18. +// + +#import "LoadAlterView.h" +#import + +#import "AppDelegate.h" + +static LoadAlterView *viewshow; + +@interface LoadAlterView () +@property (nonatomic , strong) PAGView *pagView; +@end + +@implementation LoadAlterView + +-(id)initWithFrame:(CGRect)frame +{ + if(self = [super initWithFrame:frame]) + { + [self setBackgroundColor:RGBACOLOR(0, 0, 0, 0.4)]; + + UIView *viewback = [[UIView alloc] init]; + [viewback setBackgroundColor:[UIColor whiteColor]]; + [self addSubview:viewback]; + [viewback mas_makeConstraints:^(MASConstraintMaker *make) { + make.size.sizeOffset(CGSizeMake(132, 120)); + make.center.equalTo(self); + }]; + [viewback.layer setMasksToBounds:YES]; + [viewback.layer setCornerRadius:15]; + + NSString *strpath = [[NSBundle mainBundle] pathForResource:@"pag_loading" ofType:@"pag"]; + PAGView *pagView = [[PAGView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + [viewback addSubview:pagView]; + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + PAGFile* pagFile = [PAGFile Load:strpath]; + [pagView setComposition:pagFile]; + [pagView setRepeatCount:0]; + dispatch_async(dispatch_get_main_queue(), ^{ + [pagView play]; + }); + }); + [pagView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.offset(0); + make.width.height.offset(100); + make.centerX.equalTo(viewback); + }]; + _pagView = pagView; + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"加载中"]; + [lbname setTextColor:RGBCOLOR(51, 51, 51)]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont systemFontOfSize:14]]; + [viewback addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(viewback).offset(-20); + make.centerX.equalTo(viewback); + }]; + + } + return self; +} + ++(void)show +{ + if(!viewshow) + { + LoadAlterView *view = [[LoadAlterView alloc] initWithFrame:CGRectMake(0, 0, UISCREEN_WIDTH, UISCREEN_HEIGHT)]; + AppDelegate *appd = (AppDelegate *)[UIApplication sharedApplication].delegate; + [appd.window addSubview:view]; + viewshow = view; + } +} + ++(void)dismiss +{ + if(viewshow) + { + if(viewshow.pagView.isPlaying) + { + [viewshow.pagView stop]; + [viewshow.pagView freeCache]; + } + [viewshow removeFromSuperview]; + viewshow = nil; + } +} + +@end diff --git a/ProductApp/ProductApp/ProductMain/login/LoginViewController.h b/ProductApp/ProductApp/ProductMain/login/LoginViewController.h new file mode 100644 index 0000000..dbee47f --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/LoginViewController.h @@ -0,0 +1,18 @@ +// +// LoginViewController.h +// ProductApp +// +// Created by 工作 on 2024/7/27. +// + +#import "BaseViewController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface LoginViewController : BaseViewController +@property (nonatomic , assign) BOOL isbind; +///是否直接显示手机号登录 +@property (nonatomic , assign) BOOL isphoneView; +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/login/LoginViewController.m b/ProductApp/ProductApp/ProductMain/login/LoginViewController.m new file mode 100644 index 0000000..04a12da --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/LoginViewController.m @@ -0,0 +1,300 @@ +// +// LoginViewController.m +// ProductApp +// +// Created by 工作 on 2024/7/27. +// + +#import "LoginViewController.h" +#import "LoginView.h" +#import "PublicNetWorkManager.h" +#import "ZhangHuGuanLiAlterView.h" + +#import +#import "LoginTelView.h" +#import "UIAlertController+Blocks.h" +#import "AppDelegate.h" +#import "ZhangHaoBangDingViewController.h" + + +@interface LoginViewController () +@property(nonatomic, strong) UIView *contentView; +@property (nonatomic , strong) LoginTelView *viewtel; + +@end + +@implementation LoginViewController +- (UIStatusBarStyle)preferredStatusBarStyle { + return UIStatusBarStyleDefault; +} +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; +} +- (void)viewDidLoad { + [super viewDidLoad]; + [self.navigationController setNavigationBarHidden:YES animated:NO]; + [self.navigationView setHidden:YES]; + [self.view setBackgroundColor:[UIColor whiteColor]]; + + if([UserInfoModel shareModel].isloadconfig) + { + [self drawUI]; + } + else + { + [self getPaizhi]; + } +} +-(void)drawUI +{ + LoginView *view = [[LoginView alloc] init]; + [self.view addSubview:view]; + [view mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(self.view); + make.top.offset(0); + }]; + view.isbind = self.isbind; + view.isphoneView = self.isphoneView; + [view setBackValue:^{ + [self laqiyijian]; + }]; + [self getData]; + + + if(self.isphoneView==NO) + { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self laqiyijian]; + }); + } +} + +-(void)getPaizhi +{ + [HXLoadingHUD showWithStatus:@"" maskType:0]; + NSString *stridfa = [[NSUserDefaults standardUserDefaults] objectForKey:UserIDFA]; + [PublicNetWorkManager requestUserConfigData:self.view idfa:stridfa Callback:^(BOOL state, UserConfigModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + [UserInfoModel setToken:responseObject.data.token]; +// [UserInfoModel setLoingState:@"1"]; + [UserInfoModel setAppid:responseObject.data.app_id]; + [UserInfoModel setTemp:responseObject.data.temp]; + [UserInfoModel setName:responseObject.data.name]; + [UserInfoModel setConfig:responseObject.data.config]; + [UserInfoModel shareModel].isloadconfig=YES; + + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:0]; + } + [self drawUI]; + }]; +} + +-(void)getData +{ + if(self.isbind==YES)return; + if([[[NSUserDefaults standardUserDefaults] objectForKey:DengluZhangHaoTanChuang] intValue] == 1)return; + [PublicNetWorkManager requestUserAccountData:self.view scene:@"login" Callback:^(BOOL state, UserAccountModel *responseObject, NSString * _Nullable describle) { + if(state) + { + if(responseObject.data.count>0) + { + [ZhangHuGuanLiAlterView show:responseObject.data]; + [[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:DengluZhangHaoTanChuang]; + } + } + }]; +} + +-(void)laqiyijian +{ + GyAuthViewModel *viewModel = [self customModel]; + viewModel.pullAuthVCStyle = OLPullAuthVCStylePush; + + NSArray *list = [self.viewtel getViews]; + + if ([GeYanSdk isPreGettedTokenValidate]) + { + //预登录有效,启动登录授权页 + [self.viewtel refSHow]; + // 拉起授权页 + [GeYanSdk oneTapLogin:self + viewModel:viewModel + contentView:self.contentView + subViewList:list + loginBlock:^(NSDictionary * _Nullable dic) { + + [UserInfoModel shijianShangBao:0 key:@"client.login.click" value:@"onekey" extra:@""]; + //登录完成回调 + if([[dic objectForKey:@"code"] intValue] == 30000){ + NSMutableDictionary *dicpush = [NSMutableDictionary new]; + [dicpush setObject:[Tools isStringnil:[dic objectForKey:@"gyuid"]] forKey:@"gyuid"]; + [dicpush setObject:[Tools isStringnil:[dic objectForKey:@"token"]] forKey:@"token"]; + [self telloginPush:dicpush]; + }else if([[dic objectForKey:@"code"] intValue] == 30006){ + [self jianChaXieYi]; + }else{ + [HXHud showMessage:[dic objectForKey:@"msg"] afterDelayType:0]; + } + + }]; + return; + } + + //预登录 + [GeYanSdk preGetToken:^(NSDictionary *preDic) { + if (![GeYanSdk isPreGettedTokenValidate]) { + return; + } + [self.viewtel refSHow]; + //渲染页面信息 + [GeYanSdk oneTapLogin:self + viewModel:viewModel + contentView:self.contentView + subViewList:list + loginBlock:^(NSDictionary * _Nullable dic) { + [UserInfoModel shijianShangBao:0 key:@"client.login.click" value:@"onekey" extra:@""]; + //登录完成回调 + if([[dic objectForKey:@"code"] intValue] == 30000){ + NSMutableDictionary *dicpush = [NSMutableDictionary new]; + [dicpush setObject:[Tools isStringnil:[dic objectForKey:@"gyuid"]] forKey:@"gyuid"]; + [dicpush setObject:[Tools isStringnil:[dic objectForKey:@"token"]] forKey:@"token"]; + [self telloginPush:dicpush]; + }else if([[dic objectForKey:@"code"] intValue] == 30006){ + [self jianChaXieYi]; + }else{ + [HXHud showMessage:[dic objectForKey:@"msg"] afterDelayType:0]; + } + }]; + }]; +} + +-(void)jianChaXieYi +{ + NSString *strc = [[UserInfoModel shareModel].config objectForKey:@"client.agreement.dialog"]; + if((strc.intValue == 1 || [Tools isStringnil:strc].length==0) && self.viewtel.isselect == NO) + { + [UIAlertController showAlertInViewController:self withTitle:@"温馨提示" message:@"登录需要同意中国移动认证服务条款、用户协议和隐私政策" cancelButtonTitle:@"考虑一下" destructiveButtonTitle:@"同意" otherButtonTitles:nil tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { + if(buttonIndex==1) + { + self.viewtel.isselect=YES; + [self.viewtel.btxieyi setSelected:YES]; + [self.viewtel.btdenglu sendActionsForControlEvents:UIControlEventTouchUpInside]; + } + }]; + } + else + { + if(self.viewtel.isselect == NO) + { + [HXHud showMessage:@"登录需要同意中国移动认证服务条款、用户协议和隐私政策" afterDelayType:0]; + return; + } + /// + } +} +-(void)telloginPush:(NSDictionary *)dic +{ + [HXLoadingHUD showWithStatus:@"" maskType:0]; + [PublicNetWorkManager requestUserLoginData:self.view login_type:@"onekey" phone:dic weixin:@{} apple:@{} device:@{} onekey:dic bind:[NSNumber numberWithBool:self.isbind] unbind:[NSNumber numberWithBool:NO] Callback:^(BOOL state, UserLoginModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + [UserInfoModel setLoingState:@"1"]; + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"onekey" extra:[dic objectForKey:@"gyuid"]]; + + [UserInfoModel getUserData]; + [self pushVC]; + [GeYanSdk closeAuthVC:NO completion:^{ + + AppDelegate *appde = (AppDelegate *)[UIApplication sharedApplication].delegate; + if([appde.window.rootViewController isKindOfClass:[TabBarController class]]) + { + NSArray *arr = self.navigationController.viewControllers; + for(UIViewController *vc in arr) + { + if([vc isKindOfClass:[ZhangHaoBangDingViewController class]]) + { + [self.navigationController popToViewController:vc animated:YES]; + return; + } + } + [self.navigationController popToRootViewControllerAnimated:YES]; + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"onekey" extra:[Tools isStringnil:[dic objectForKey:@"gyuid"]]]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"updataUserState" object:nil]; + } + else + { + [appde.window setRootViewController:[TabBarController new]]; + } + }]; + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:1]; + [UserInfoModel shijianShangBao:0 key:@"client.login.err" value:@"onekey" extra:responseObject.message]; + } + }]; +} + +-(void)pushVC +{ + NSString *stridfa = [[NSUserDefaults standardUserDefaults] objectForKey:UserIDFA]; + [PublicNetWorkManager requestUserConfigData:self.view idfa:stridfa Callback:^(BOOL state, UserConfigModel *responseObject, NSString * _Nullable describle) { + if(state) + { + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel setAppid:responseObject.data.app_id]; + [UserInfoModel setTemp:responseObject.data.temp]; + [UserInfoModel setName:responseObject.data.name]; + [UserInfoModel setConfig:responseObject.data.config]; + [UserInfoModel shareModel].isloadconfig=YES; + + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:0]; + } + }]; +} + + + +//MARK: - Model +- (GyAuthViewModel *)customModel { + GyAuthViewModel *viewModel = [GyAuthViewModel new]; + viewModel.statusBarStyle = UIStatusBarStyleDefault; + viewModel.pullAnimate = NO; + //暗黑模式 + viewModel.userInterfaceStyle = @(0); + viewModel.viewLifeCycleBlock = ^(NSString *viewLifeCycle, BOOL animated) { + }; + + viewModel.clickAuthButtonBlock = ^() { + //返回YES:流程继续, 返回NO:登录中断 + return YES; + }; + return viewModel; +} +- (UIView *)contentView { + if (!_contentView) { + _contentView = [[UIView alloc] initWithFrame:self.view.bounds]; + _contentView.backgroundColor = [UIColor whiteColor]; + [_contentView addSubview:self.viewtel]; + } + return _contentView; +} +- (LoginTelView *)viewtel { + if (!_viewtel) { + _viewtel = [[LoginTelView alloc] initWithFrame:self.view.bounds]; + _viewtel.backgroundColor = [UIColor whiteColor]; + _viewtel.isbind = self.isbind; + } + return _viewtel; +} +@end diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.h b/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.h new file mode 100644 index 0000000..e2783a8 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.h @@ -0,0 +1,18 @@ +// +// LoginAppleView.h +// ProductApp +// +// Created by 工作 on 2024/8/5. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef void(^LoginAppleViewBackValue)(NSInteger tag); +@interface LoginAppleView : UIView +/// +@property (nonatomic , strong) LoginAppleViewBackValue backValue; +@property (nonatomic , assign) BOOL isbind; +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.m b/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.m new file mode 100644 index 0000000..04d1a98 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginAppleView.m @@ -0,0 +1,443 @@ +// +// LoginAppleView.m +// ProductApp +// +// Created by 工作 on 2024/8/5. +// + +#import "LoginAppleView.h" +#import +#import "PublicNetWorkManager.h" +#import "WkWebviewViewController.h" +#import "UIAlertController+Blocks.h" +#import "AppDelegate.h" +#import "ZhangHaoBangDingViewController.h" +#import + + +@interface LoginAppleView () +/// +@property (nonatomic , strong) UIView *viewother; +/// +@property (nonatomic , strong) UIButton *btxy; +@end + +@implementation LoginAppleView + +-(id)initWithFrame:(CGRect)frame +{ + if(self = [super initWithFrame:frame]) + { + UIImageView *imgvback = [[UIImageView alloc] init]; + [imgvback setImage:[UIImage imageNamed:@"login_back"]]; + [self addSubview:imgvback]; + [imgvback mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + UIButton *btback = [[UIButton alloc] init]; + [btback setImage:[UIImage imageNamed:@"login_X"] forState:UIControlStateNormal]; + [self addSubview:btback]; + [btback mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(40); + make.right.equalTo(self).offset(-10); + make.top.offset(NavHeight-20); + }]; + [btback addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"Hello!"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont boldSystemFontOfSize:36]]; + [self addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(43); + make.top.offset(NavHeight+20); + }]; + + UILabel *lbinfo = [[UILabel alloc] init]; + [lbinfo setText:@"欢迎使用智能写作"]; + [lbinfo setTextColor:[UIColor whiteColor]]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:20]]; + [self addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(lbname); + make.top.equalTo(lbname.mas_bottom).offset(5); + }]; + + + UIImageView *imgvlog = [[UIImageView alloc] init]; + [imgvlog setImage:[UIImage imageNamed:@"login_logo"]]; + [self addSubview:imgvlog]; + [imgvlog mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(100); + make.centerX.equalTo(self); + make.centerY.equalTo(self).offset(-30); + }]; + + UIButton *btdenglu = [[UIButton alloc] init]; + [btdenglu setTitle:@"Apple一键登录" forState:UIControlStateNormal]; + [btdenglu setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [btdenglu.titleLabel setFont:[UIFont systemFontOfSize:20]]; + [btdenglu setImage:[Tools imageWithImageName:[UIImage imageNamed:@"login_apple_bai"] imageColor:[UIColor whiteColor]] forState:UIControlStateNormal]; + [btdenglu.layer setMasksToBounds:YES]; + [btdenglu.layer setCornerRadius:25]; + [btdenglu setBackgroundColor:RGBCOLOR(60, 60, 60)]; + [self addSubview:btdenglu]; + [btdenglu mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(40); + make.right.equalTo(self).offset(-40); + make.height.offset(50); + make.top.equalTo(imgvlog.mas_bottom).offset(40); + }]; + [btdenglu setIconInLeftWithSpacing:6]; + [btdenglu addTarget:self action:@selector(dengluAction) forControlEvents:UIControlEventTouchUpInside]; + + UIButton *btxy = [[UIButton alloc] init]; + [btxy setImage:[UIImage imageNamed:@"login_Select_N"] forState:UIControlStateNormal]; + [btxy setImage:[UIImage imageNamed:@"login_Select_Y"] forState:UIControlStateSelected]; + [self addSubview:btxy]; + [btxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btdenglu).offset(30); + make.top.equalTo(btdenglu.mas_bottom).offset(10); + make.width.offset(40); + make.height.offset(30); + }]; + [btxy addTarget:self action:@selector(xieyiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btxy = btxy; + + YYLabel *lbxy = [[YYLabel alloc] init]; + [lbxy setText:@"我已阅读并同意用户协议和隐私协议"]; + [lbxy setTextColor:RGBCOLOR(155, 155, 155)]; + [lbxy setTextAlignment:NSTextAlignmentLeft]; + [lbxy setFont:[UIFont systemFontOfSize:12]]; + [self addSubview:lbxy]; + [lbxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btxy.mas_right).offset(0); + make.right.equalTo(lbxy).offset(-24); + make.centerY.equalTo(btxy); + make.height.offset(20); + }]; + NSMutableAttributedString *noteStr = [[NSMutableAttributedString alloc]initWithString:lbxy.text]; + NSMutableParagraphStyle *style = [NSMutableParagraphStyle new]; + style.lineSpacing = 5; + style.lineBreakMode = NSLineBreakByTruncatingTail; + [noteStr addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, lbinfo.text.length)]; + noteStr.yy_font = [UIFont systemFontOfSize:12.0f]; + noteStr.yy_color = RGBCOLOR(155, 155, 155); + [noteStr yy_setTextHighlightRange:NSMakeRange(7, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"用户协议"); + [self xieyiPushAction:0]; + }]; + [noteStr yy_setTextHighlightRange:NSMakeRange(12, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"隐私协议"); + [self xieyiPushAction:1]; + }]; + lbxy.attributedText = noteStr; + + UIView *viewother= [[UIView alloc] init]; + [self addSubview:viewother]; + [viewother mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.offset(90); + make.left.right.equalTo(self); + make.bottom.equalTo(self); + }]; + [self drawOtherView:viewother]; + _viewother = viewother; + } + return self; +} + +-(void)drawOtherView:(UIView *)view +{ + NSArray *arrpz = [[UserInfoModel shareModel].config objectForKey:@"client.login.type"]; + if(arrpz.count==0)return; + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"其他登录方式"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentCenter]; + [lbname setFont:[UIFont systemFontOfSize:12]]; + [view addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.offset(0); + make.centerX.equalTo(view); + make.width.offset(80); + }]; + + UIView *viewlineL = [[UIView alloc] init]; + [viewlineL setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineL]; + [viewlineL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(50); + make.right.equalTo(lbname.mas_left).offset(-10); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewlineR = [[UIView alloc] init]; + [viewlineR setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineR]; + [viewlineR mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(view).offset(-50); + make.width.equalTo(viewlineL); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewcollect = [[UIView alloc] init]; + [view addSubview:viewcollect]; + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(lbname.mas_bottom); + make.bottom.equalTo(view); + make.centerX.equalTo(view); + }]; + + NSMutableArray *arrtmep = [NSMutableArray new]; + for(NSString *str in arrpz) + { + if([str isEqualToString:@"phone"]) + { + [arrtmep addObject:@"login_phone"]; + } + else if([str isEqualToString:@"weixin"]) + { + [arrtmep addObject:@"login_wx"]; + } + } + NSArray *arr = arrtmep; + for(int i = 0 ; i < arr.count; i++) + { + UIButton *btitem = [[UIButton alloc] init]; + [btitem setImage:[UIImage imageNamed:arr[i]] forState:UIControlStateNormal]; + [viewcollect addSubview:btitem]; + [btitem mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(60*i); + make.top.equalTo(lbname.mas_bottom).offset(10); + make.width.offset(50); + make.height.offset(50); + }]; + if([arr[i] isEqualToString:@"login_phone"]) + { + [btitem setTag:0]; + } + else if([arr[i] isEqualToString:@"login_wx"]) + { + [btitem setTag:1]; + } + + [btitem addTarget:self action:@selector(otherAction:) forControlEvents:UIControlEventTouchUpInside]; + if(i==arr.count-1) + { + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(btitem); + }]; + } + } +} +-(void)xieyiPushAction:(int)tag +{ + WkWebviewViewController *vc = [[WkWebviewViewController alloc] init]; + if(tag==1) + { + vc.strtitle = @"隐私协议"; + vc.strurl = UserYinSiUrl; + } + else + { + vc.strtitle = @"用户协议"; + vc.strurl = UserXieUrl; + } + [self.viewController.navigationController pushViewController:vc animated:YES]; +} +-(void)otherAction:(UIButton *)sender +{ + if(sender.tag==0) + { + self.backValue(0); + } + else + { + self.backValue(1); + } +} +-(void)xieyiAction:(UIButton *)sender +{ + sender.selected = !sender.selected; +} +///apple +-(void)dengluAction +{ + [UserInfoModel shijianShangBao:0 key:@"client.login.click" value:@"apple" extra:@""]; + NSString *strc = [[UserInfoModel shareModel].config objectForKey:@"client.agreement.dialog"]; + if((strc.intValue == 1 || [Tools isStringnil:strc].length==0) && self.btxy.selected == NO) + { + [UIAlertController showAlertInViewController:self.viewController withTitle:@"温馨提示" message:@"登录需要同意用户协议和隐私政策" cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { + if(buttonIndex==1) + { + [self.btxy setSelected:YES]; + /// + [self loginApple]; + } + }]; + } + else + { + if(self.btxy.selected == NO) + { + [HXHud showMessage:@"需要同意用户协议和隐私政策" afterDelayType:0]; + return; + } + [self loginApple]; + } +} + +///登录 Apple +-(void)loginApple +{ + if (@available(iOS 13.0, *)) { + [HXLoadingHUD showWithStatus:@"" maskType:0]; + // 基于用户的 Apple ID 授权用户,生成用户授权请求的一种机制 + ASAuthorizationAppleIDProvider *appleIdProvider = [[ASAuthorizationAppleIDProvider alloc] init]; + // 创建新的 AppleID 授权请求 + ASAuthorizationAppleIDRequest *request = appleIdProvider.createRequest; + // 在用户授权期间请求的联系信息 + request.requestedScopes = @[ASAuthorizationScopeEmail, ASAuthorizationScopeFullName]; + // 由 ASAuthorizationAppleIDProvider 创建的授权请求,管理授权请求的控制器 + ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]]; + // 设置授权控制器通知授权请求的成功与失败的代理 + controller.delegate = self; + // 设置提供展示上下文的代理,在这个上下文中,系统可以向用户展示授权界面 + controller.presentationContextProvider = self; + // 在控制器初始化期间启动授权流 + [controller performRequests]; + } + else + { + [HXHud showMessage:@"请升级手机系统" afterDelayType:0]; + } +} +-(void)loginPushApple:(NSDictionary *)dic login_type:(NSString *)login_type +{ + [PublicNetWorkManager requestUserLoginData:self login_type:login_type phone:@{} weixin:@{} apple:dic device:@{} onekey:@{} bind:[NSNumber numberWithBool:self.isbind] unbind:[NSNumber numberWithBool:NO] Callback:^(BOOL state, UserLoginModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + [UserInfoModel setLoingState:@"1"]; + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"apple" extra:@""]; + [UserInfoModel getUserData]; + [self pushVC]; + + AppDelegate *appde = (AppDelegate *)[UIApplication sharedApplication].delegate; + + if([appde.window.rootViewController isKindOfClass:[TabBarController class]]) + { + NSArray *arr = self.viewController.navigationController.viewControllers; + for(UIViewController *vc in arr) + { + if([vc isKindOfClass:[ZhangHaoBangDingViewController class]]) + { + [self.viewController.navigationController popToViewController:vc animated:YES]; + return; + } + } + [self.viewController.navigationController popToRootViewControllerAnimated:YES]; + } + else + { + [appde.window setRootViewController:[TabBarController new]]; + } + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"apple" extra:@""]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"updataUserState" object:nil]; + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:1]; + [UserInfoModel shijianShangBao:0 key:@"client.login.err" value:@"apple" extra:responseObject.message]; + } + }]; +} +-(void)pushVC +{ + NSString *stridfa = [[NSUserDefaults standardUserDefaults] objectForKey:UserIDFA]; + [PublicNetWorkManager requestUserConfigData:self idfa:stridfa Callback:^(BOOL state, UserConfigModel *responseObject, NSString * _Nullable describle) { + if(state) + { + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel setAppid:responseObject.data.app_id]; + [UserInfoModel setTemp:responseObject.data.temp]; + [UserInfoModel setName:responseObject.data.name]; + [UserInfoModel setConfig:responseObject.data.config]; + [UserInfoModel shareModel].isloadconfig=YES; + + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:0]; + } + }]; +} + +#pragma mark - ASAuthorizationController +- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization { + if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) { + // 用户登录使用 ASAuthorizationAppleIDCredential + ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential; + NSString *user = appleIDCredential.user; + NSString *nickname = appleIDCredential.fullName.nickname?:appleIDCredential.email; + if([Tools isStringnil:nickname].length==0) + { + nickname = @""; + } + NSDictionary *dic = @{@"user_id":[Tools isStringnil:user], + @"user_name":nickname, + @"identify_code":[[NSString alloc] initWithData:appleIDCredential.authorizationCode encoding:NSUTF8StringEncoding], + @"identify_token":[[NSString alloc] initWithData:appleIDCredential.identityToken encoding:NSUTF8StringEncoding]}; + + [self loginPushApple:dic login_type:@"apple"]; + + } else { + NSLog(@"授权信息不符"); + [HXLoadingHUD dismiss]; + + } +} +- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error { + + NSString *errorMsg; + switch (error.code) { + case ASAuthorizationErrorUnknown: { + errorMsg = @"授权请求失败,未知原因"; + break; + } + case ASAuthorizationErrorCanceled: { + errorMsg = @"用户取消了授权请求"; + break; + } + case ASAuthorizationErrorInvalidResponse: { + errorMsg = @"授权请求响应无效"; + break; + } + case ASAuthorizationErrorNotHandled: { + errorMsg = @"未能处理授权请求"; + break; + } + case ASAuthorizationErrorFailed: { + errorMsg = @"获取授权失败"; + break; + } + } + [HXLoadingHUD dismiss]; + NSLog(@"error message:%@", errorMsg); +} +#pragma mark - +// 告诉代理应该在哪个 window 展示内容给用户 +- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller { + return self.window; +} + +@end diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.h b/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.h new file mode 100644 index 0000000..f3ada56 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.h @@ -0,0 +1,25 @@ +// +// LoginTelView.h +// ProductApp +// +// Created by 工作 on 2024/6/21. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +@interface LoginTelView : UIView +/// +@property (nonatomic , assign) BOOL isbind; +/// +@property (nonatomic , strong) UIButton *btdenglu; +@property (nonatomic , assign) BOOL isselect; +@property (nonatomic , strong) UIButton *btxieyi; + +-(NSArray *)getViews; +-(void)refSHow; +-(void)dengluAction; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.m b/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.m new file mode 100644 index 0000000..b5d6e3e --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginTelView.m @@ -0,0 +1,329 @@ +// +// LoginTelView.m +// ProductApp +// +// Created by 工作 on 2024/6/21. +// + +#import "LoginTelView.h" +#import "TTTAttributedLabel.h" +#import "WkWebviewViewController.h" +#import "PublicNetWorkManager.h" +#import +#import "LoginViewController.h" + +#import "AppDelegate.h" +#import "TabBarController.h" +#import "ZhangHaoBangDingViewController.h" + +#import "UIAlertController+Blocks.h" + +typedef NS_ENUM(NSInteger, Mode) { + ModeFullScreen = 1, + ModePop, + ModeWindow, + ModeLandscape +}; + +@interface LoginTelView () +/// +@property (nonatomic , strong) UILabel *lbtel; +/// +@property (nonatomic , strong) UILabel *lbinfo; +/// + + +@property (nonatomic , strong) TTTAttributedLabel *termLabel; + + + +/// +@property (nonatomic , strong) GyContentModel *modelGT; + +/// +@property (nonatomic , strong) UIButton *btback; + +@end + +@implementation LoginTelView + +-(id)initWithFrame:(CGRect)frame +{ + if(self = [super initWithFrame:frame]) + { + + UIImageView *imgvback = [[UIImageView alloc] init]; + [imgvback setImage:[UIImage imageNamed:@"login_back"]]; + [self addSubview:imgvback]; + [imgvback mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + UIButton *btback = [[UIButton alloc] init]; + [btback setImage:[UIImage imageNamed:@"login_X"] forState:UIControlStateNormal]; + [self addSubview:btback]; + [btback mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(40); + make.right.equalTo(self).offset(-10); + make.top.offset(NavHeight-20); + }]; + [btback addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + _btback = btback; + + UIImageView *imgvlog = [[UIImageView alloc] init]; + [imgvlog setImage:[UIImage imageNamed:@"login_logo"]]; + [self addSubview:imgvlog]; + [imgvlog mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(80); + make.centerX.equalTo(self); + make.top.offset(NavHeight+ 40); + }]; + + UILabel *lbtel = [[UILabel alloc] init]; + [lbtel setTextColor:RGBCOLOR(51, 51, 51)]; + [lbtel setTextAlignment:NSTextAlignmentLeft]; + [lbtel setFont:[UIFont systemFontOfSize:18]]; + [self addSubview:lbtel]; + [lbtel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerX.equalTo(self); + make.top.equalTo(imgvlog.mas_bottom).offset(60); + }]; + _lbtel = lbtel; + + UIButton *btdenglu = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, UISCREEN_WIDTH-80, 40)]; + [btdenglu setTitle:@"本机号码一键登录" forState:UIControlStateNormal]; + [btdenglu setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [btdenglu.titleLabel setFont:[UIFont systemFontOfSize:16]]; + [btdenglu.layer setMasksToBounds:YES]; + [btdenglu.layer setCornerRadius:20]; + [self addSubview:btdenglu]; + [btdenglu mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(40); + make.right.equalTo(self).offset(-40); + make.top.equalTo(lbtel.mas_bottom).offset(50); + make.height.offset(40); + }]; + [btdenglu addTarget:self action:@selector(dengluAction) forControlEvents:UIControlEventTouchUpInside]; + [Tools changedView:btdenglu colors:MainJBColors startPoint:CGPointMake(0, 0) endPoint:CGPointMake(1, 0)]; + _btdenglu = btdenglu; + + UILabel *lbinfo = [[UILabel alloc] init]; + [lbinfo setTextColor:RGBCOLOR(121, 121, 121)]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:14]]; + [self addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(btdenglu.mas_bottom).offset(30); + make.centerX.equalTo(self); + }]; + _lbinfo = lbinfo; + + UIView *viewother= [[UIView alloc] init]; + [self addSubview:viewother]; + [viewother mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.offset(90); + make.left.right.equalTo(self); + make.top.equalTo(lbinfo.mas_bottom).offset(40); + }]; + [self drawOtherView:viewother]; + [viewother setHidden:YES]; + + + UIView *viewxy = [[UIView alloc] init]; + [self addSubview:viewxy]; + [viewxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(self).offset(-TabHeight); + make.left.offset(20); + make.right.equalTo(self).offset(-20); + make.height.offset(40); + }]; + [self drawXieyiView:viewxy]; + [self refSHow]; + } + return self; +} +-(void)drawOtherView:(UIView *)view +{ + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"其他登录方式"]; + [lbname setTextColor:RGBCOLOR(102, 102, 102)]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont systemFontOfSize:14]]; + [view addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.offset(0); + make.centerX.equalTo(view); + }]; + + NSArray *arr = @[@"login_phone",@"login_apple",@"login_wx"]; + for(int i = 0 ; i < arr.count; i++) + { + UIButton *btitem = [[UIButton alloc] init]; + [btitem setImage:[UIImage imageNamed:arr[i]] forState:UIControlStateNormal]; + [view addSubview:btitem]; + [btitem mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(60*i); + make.top.equalTo(lbname.mas_bottom).offset(10); + make.width.offset(60); + make.height.offset(60); + }]; + [btitem setTag:i]; + [btitem addTarget:self action:@selector(otherAction:) forControlEvents:UIControlEventTouchUpInside]; + if(i==arr.count-1) + { + [view mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(btitem); + }]; + } + } + + +} + +-(void)drawXieyiView:(UIView *)viewxy +{ + UIButton *btxieyi = [[UIButton alloc] init]; + [btxieyi setImage:[UIImage imageNamed:@"login_Select_N"] forState:UIControlStateNormal]; + [btxieyi setImage:[UIImage imageNamed:@"login_Select_Y"] forState:UIControlStateSelected]; + [viewxy addSubview:btxieyi]; + [btxieyi mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.offset(0); + make.width.height.offset(40); + }]; + [btxieyi setIconInLeft]; + [btxieyi addTarget:self action:@selector(xieyiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btxieyi = btxieyi; + + TTTAttributedLabel *lbinfo = [[TTTAttributedLabel alloc] initWithFrame:CGRectMake(0, 0, 100, 40)]; +// [lbinfo setText:@"登录即认可中国移动认证服务条款、用户协议和隐私协议并使用本机号码登录"]; + [lbinfo setTextColor:RGBCOLOR(102, 102, 102)]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:12]]; + [lbinfo setNumberOfLines:0]; + + // 隐私协议样式 + lbinfo.enabledTextCheckingTypes = NSTextCheckingTypeLink; + lbinfo.delegate = self; + + [viewxy addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btxieyi.mas_right); + make.height.offset(40); + make.centerY.equalTo(btxieyi); + make.right.equalTo(viewxy); + }]; + _termLabel = lbinfo; + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.lineSpacing = 7; + paragraphStyle.alignment = NSTextAlignmentLeft; + paragraphStyle.paragraphSpacing = 0.0; + paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping; + paragraphStyle.firstLineHeadIndent = 0.0; + + NSDictionary *attr = @{ + NSForegroundColorAttributeName: RGBCOLOR(254, 122, 133), + NSParagraphStyleAttributeName: paragraphStyle, + NSFontAttributeName: [UIFont systemFontOfSize:12] + }; + self.termLabel.linkAttributes = attr; + + + [viewxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(lbinfo); + }]; +} + +-(void)xieyiAction:(UIButton *)sender +{ + sender.selected=!sender.selected; + self.isselect = sender.selected; +} + +/// 隐私协议点击回调 +- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url { + NSLog(@"%@", url.absoluteString); + NSString *strtemp = url.absoluteString; + WkWebviewViewController *vc = [[WkWebviewViewController alloc] init]; + + if([strtemp isEqualToString:UserYinSiUrl]) + { + vc.strtitle = @"隐私政策"; + vc.strurl = UserYinSiUrl; + } + else if([strtemp isEqualToString:UserXieUrl]) + { + vc.strtitle = @"用户协议"; + vc.strurl = UserXieUrl; + } + else + { + vc.strtitle = @"中国移动提供认证服务条款"; + vc.strurl = self.modelGT.link; + } + [self.viewController.navigationController pushViewController:vc animated:YES]; +} + +-(void)otherAction:(UIButton *)sender +{ + +} +-(void)backAction +{ + [GeYanSdk closeAuthVC:NO completion:^{ + [self.viewController.navigationController popViewControllerAnimated:YES]; + }]; + +} +-(void)refSHow +{ + GyContentModel *model = [GyContentModel currentModel];//预取号缓存信息 + self.modelGT = model; + + self.lbtel.text = model.pn; + self.lbinfo.text = model.slogan; + self.termLabel.text = model.term; + + self.termLabel.text = [NSString stringWithFormat:@"登录即认可%@条款、用户协议和隐私协议并使用本机号码登录",model.term]; + + [self.termLabel addLinkToURL:[[NSURL alloc] initWithString:UserXieUrl] withRange:NSMakeRange(16, 4)]; + [self.termLabel addLinkToURL:[[NSURL alloc] initWithString:UserYinSiUrl] withRange:NSMakeRange(21, 4)]; + + [self.termLabel addLinkToURL:[[NSURL alloc] initWithString:@"https://www.yidongxieyi.com"] withRange:NSMakeRange(5, 11)]; + +} +-(NSArray *)getViews +{ + NSArray *list = @[self.lbtel, + self.lbinfo, + self.btdenglu, + self.btxieyi, + self.termLabel]; + return list; +} +-(void)dengluAction +{ + + NSString *strc = [[UserInfoModel shareModel].config objectForKey:@"client.agreement.dialog"]; + if((strc.intValue == 1 || [Tools isStringnil:strc].length==0) && self.isselect == NO) + { + [UIAlertController showAlertInViewController:self.viewController withTitle:@"温馨提示" message:@"需要同意用户协议和隐私政策" cancelButtonTitle:@"取消" destructiveButtonTitle:@"同意" otherButtonTitles:nil tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { + if(buttonIndex == 1) + { + self.isselect=YES; + [self.btxieyi setSelected:YES]; + + } + }]; + } + else + { + if(self.isselect == NO) + { + [HXHud showMessage:@"需要同意用户协议和隐私政策" afterDelayType:0]; + return; + } + + } +} +@end diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginView.h b/ProductApp/ProductApp/ProductMain/login/view/LoginView.h new file mode 100644 index 0000000..dbf8c3c --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginView.h @@ -0,0 +1,20 @@ +// +// LoginView.h +// ProductApp +// +// Created by 工作 on 2024/7/27. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef void(^LoginViewBackTel)(void); +@interface LoginView : UIView +/// +@property (nonatomic , strong) LoginViewBackTel backValue; +@property (nonatomic , assign) BOOL isbind; +///是否只显示手机号登录 +@property (nonatomic , assign) BOOL isphoneView; +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginView.m b/ProductApp/ProductApp/ProductMain/login/view/LoginView.m new file mode 100644 index 0000000..269955a --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginView.m @@ -0,0 +1,619 @@ +// +// LoginView.m +// ProductApp +// +// Created by 工作 on 2024/7/27. +// + +#import "LoginView.h" +#import "UITextField+SY.h" +#import +#import "PublicNetWorkManager.h" +#import "WkWebviewViewController.h" + +#import "LoginWXView.h" +#import "LoginAppleView.h" +#import "UIAlertController+Blocks.h" +#import "AppDelegate.h" +#import "ZhangHaoBangDingViewController.h" + + +@interface LoginView () +/// +@property (nonatomic , strong) UITextField *fieldPhone; +@property (nonatomic , strong) UITextField *fieldCode; +/// +@property (nonatomic , strong) UIView *viewother; +/// +@property (nonatomic , strong) UIButton *btxy; + +/// +@property (nonatomic , strong) LoginWXView *viewwx; +@property (nonatomic , strong) LoginAppleView *viewapple; + +/// +@property (nonatomic , strong) UserCodeModelData *modelCode; + +@end + +@implementation LoginView + +-(id)initWithFrame:(CGRect)frame +{ + if(self = [super initWithFrame:frame]) + { + UIImageView *imgvback = [[UIImageView alloc] init]; + [imgvback setImage:[UIImage imageNamed:@"login_back"]]; + [self addSubview:imgvback]; + [imgvback mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + UIButton *btback = [[UIButton alloc] init]; + [btback setImage:[UIImage imageNamed:@"login_X"] forState:UIControlStateNormal]; + [self addSubview:btback]; + [btback mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(40); + make.right.equalTo(self).offset(-10); + make.top.offset(NavHeight-20); + }]; + [btback addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"Hello!"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont boldSystemFontOfSize:36]]; + [self addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(43); + make.top.offset(NavHeight+20); + }]; + + UILabel *lbinfo = [[UILabel alloc] init]; + [lbinfo setText:@"欢迎使用智能写作"]; + [lbinfo setTextColor:[UIColor whiteColor]]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:20]]; + [self addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(lbname); + make.top.equalTo(lbname.mas_bottom).offset(5); + }]; + + + UIView *viewinput = [[UIView alloc] init]; + [viewinput setBackgroundColor:[UIColor whiteColor]]; + [self addSubview:viewinput]; + [viewinput mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(42); + make.right.equalTo(self).offset(-42); + make.height.offset(251); + make.centerY.equalTo(self); + }]; + [viewinput.layer setMasksToBounds:YES]; + [viewinput.layer setCornerRadius:20]; + + + UIView *viewlast = nil; + NSArray *arrpl = @[@"手机号",@"验证码"]; + for(int i = 0 ; i < arrpl.count; i++) + { + UIView *viewitem = [[UIView alloc] init]; + [viewinput addSubview:viewitem]; + [viewitem mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.offset(80); + make.left.right.equalTo(viewinput); + make.top.offset(10+90*i); + + }]; + viewlast = viewitem; + UITextField *field = [self drawFieldView:viewitem title:arrpl[i]]; + + if(i==1) + { + self.fieldCode = field; + [field setMaxlength:8]; + + UIButton *btcode = [[UIButton alloc] init]; + [btcode setTitle:@"获取验证码" forState:UIControlStateNormal]; + [btcode setTitleColor:RGBCOLOR(108, 119, 246) forState:UIControlStateNormal]; + [btcode.titleLabel setFont:[UIFont systemFontOfSize:12]]; + [field.superview addSubview:btcode]; + [btcode mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.bottom.equalTo(field.superview); + make.right.equalTo(field.superview).offset(-15); + }]; + [btcode addTarget:self action:@selector(codeAction:) forControlEvents:UIControlEventTouchUpInside]; + } + else + { + self.fieldPhone = field; + [field setMaxlength:11]; + } + } + + UIButton *btdenglu = [[UIButton alloc] init]; + [btdenglu setTitle:@"登录" forState:UIControlStateNormal]; + [btdenglu setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [btdenglu.titleLabel setFont:[UIFont systemFontOfSize:16]]; + [btdenglu.layer setMasksToBounds:YES]; + [btdenglu.layer setCornerRadius:20]; + [btdenglu setBackgroundColor:RGBCOLOR(108, 119, 246)]; + [viewinput addSubview:btdenglu]; + [btdenglu mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(20); + make.right.equalTo(viewinput).offset(-20); + make.top.equalTo(viewlast.mas_bottom).offset(10); + make.height.offset(40); + }]; + [btdenglu addTarget:self action:@selector(dengluAction) forControlEvents:UIControlEventTouchUpInside]; + + + + UIButton *btxy = [[UIButton alloc] init]; + [btxy setImage:[UIImage imageNamed:@"login_Select_N"] forState:UIControlStateNormal]; + [btxy setImage:[UIImage imageNamed:@"login_Select_Y"] forState:UIControlStateSelected]; + [self addSubview:btxy]; + [btxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(viewinput).offset(30); + make.top.equalTo(viewinput.mas_bottom).offset(10); + make.width.offset(40); + make.height.offset(30); + }]; + [btxy addTarget:self action:@selector(xieyiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btxy = btxy; + + YYLabel *lbxy = [[YYLabel alloc] init]; + [lbxy setText:@"我已阅读并同意用户协议和隐私协议"]; + [lbxy setTextColor:RGBCOLOR(155, 155, 155)]; + [lbxy setTextAlignment:NSTextAlignmentLeft]; + [lbxy setFont:[UIFont systemFontOfSize:12]]; + [self addSubview:lbxy]; + [lbxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btxy.mas_right).offset(0); + make.right.equalTo(lbxy).offset(-24); + make.centerY.equalTo(btxy); + make.height.offset(20); + }]; + NSMutableAttributedString *noteStr = [[NSMutableAttributedString alloc]initWithString:lbxy.text]; + NSMutableParagraphStyle *style = [NSMutableParagraphStyle new]; + style.lineSpacing = 5; + style.lineBreakMode = NSLineBreakByTruncatingTail; + [noteStr addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, lbinfo.text.length)]; + noteStr.yy_font = [UIFont systemFontOfSize:12.0f]; + noteStr.yy_color = RGBCOLOR(155, 155, 155); + [noteStr yy_setTextHighlightRange:NSMakeRange(7, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"用户协议"); + [self xieyiPushAction:0]; + }]; + [noteStr yy_setTextHighlightRange:NSMakeRange(12, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"隐私协议"); + [self xieyiPushAction:1]; + }]; + lbxy.attributedText = noteStr; + + + UIView *viewother= [[UIView alloc] init]; + [self addSubview:viewother]; + [viewother mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.offset(90); + make.bottom.equalTo(self); + make.left.right.equalTo(self); + }]; + [self drawOtherView:viewother]; + _viewother = viewother; + + ///其它登录页面 + LoginWXView *viewwx = [[LoginWXView alloc] init]; + [viewwx setBackgroundColor:[UIColor whiteColor]]; + [self addSubview:viewwx]; + [viewwx mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + [viewwx setHidden:YES]; + [viewwx setBackValue:^(NSInteger tag) { + [self otherSelectAction:tag]; + }]; + _viewwx = viewwx; + + + LoginAppleView *viewapple = [[LoginAppleView alloc] init]; + [viewapple setBackgroundColor:[UIColor whiteColor]]; + [self addSubview:viewapple]; + [viewapple mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + [viewapple setHidden:YES]; + [viewapple setBackValue:^(NSInteger tag) { + [self otherSelectAction:tag]; + }]; + _viewapple = viewapple; + } + return self; +} + +-(UITextField *)drawFieldView:(UIView *)view title:(NSString *)title +{ + UIImageView *imgvback = [[UIImageView alloc] init]; + [imgvback setImage:[UIImage imageNamed:[NSString stringWithFormat:@"login_phone_%@",title]]]; + [view addSubview:imgvback]; + [imgvback mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(16); + make.left.offset(30); + make.top.offset(10); + }]; + + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:title]; + [lbname setTextColor:RGBCOLOR(51, 51, 51)]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont systemFontOfSize:16]]; + [view addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(imgvback.mas_right).offset(8); + make.centerY.equalTo(imgvback); + }]; + + UIView *viewfield = [[UIView alloc] init]; + [viewfield setBackgroundColor:RGBCOLOR(250, 250, 250)]; + [view addSubview:viewfield]; + [viewfield mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(20); + make.right.equalTo(view).offset(-20); + make.height.offset(36); + make.top.equalTo(imgvback.mas_bottom).offset(11); + }]; + [viewfield.layer setMasksToBounds:YES]; + [viewfield.layer setCornerRadius:18]; + + + UITextField *field = [[UITextField alloc] init]; + [field setTextColor:RGBCOLOR(51, 51, 51)]; + [field setTextAlignment:NSTextAlignmentLeft]; + [field setFont:[UIFont systemFontOfSize:14]]; + [field setPlaceholder:[NSString stringWithFormat:@"请输入%@",title]]; + [viewfield addSubview:field]; + [field mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(10); + make.top.bottom.equalTo(viewfield); + make.right.equalTo(viewfield).offset(-10); + }]; + [field setKeyboardType:UIKeyboardTypeNumberPad]; + + return field; +} +-(void)drawOtherView:(UIView *)view +{ + NSArray *arrpz = [[UserInfoModel shareModel].config objectForKey:@"client.login.type"]; + if(arrpz.count==0)return; + + + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"其他登录方式"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentCenter]; + [lbname setFont:[UIFont systemFontOfSize:12]]; + [view addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.offset(0); + make.centerX.equalTo(view); + make.width.offset(80); + }]; + + UIView *viewlineL = [[UIView alloc] init]; + [viewlineL setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineL]; + [viewlineL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(50); + make.right.equalTo(lbname.mas_left).offset(-10); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewlineR = [[UIView alloc] init]; + [viewlineR setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineR]; + [viewlineR mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(view).offset(-50); + make.width.equalTo(viewlineL); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewcollect = [[UIView alloc] init]; + [view addSubview:viewcollect]; + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(lbname.mas_bottom); + make.bottom.equalTo(view); + make.centerX.equalTo(view); + }]; + + + NSMutableArray *arrtmep = [NSMutableArray new]; + for(NSString *str in arrpz) + { + if([str isEqualToString:@"weixin"]) + { + [arrtmep addObject:@"login_wx"]; + } + else if([str isEqualToString:@"apple"]) + { + [arrtmep addObject:@"login_apple"]; + } + } + NSArray *arr = arrtmep; + for(int i = 0 ; i < arr.count; i++) + { + UIButton *btitem = [[UIButton alloc] init]; + [btitem setImage:[UIImage imageNamed:arr[i]] forState:UIControlStateNormal]; + [viewcollect addSubview:btitem]; + [btitem mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(60*i); + make.top.equalTo(lbname.mas_bottom).offset(10); + make.width.offset(50); + make.height.offset(50); + }]; + if([arr[i] isEqualToString:@"login_wx"]) + { + [btitem setTag:1]; + } + else if([arr[i] isEqualToString:@"login_apple"]) + { + [btitem setTag:2]; + } + + [btitem addTarget:self action:@selector(otherAction:) forControlEvents:UIControlEventTouchUpInside]; + if(i==arr.count-1) + { + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(btitem); + }]; + } + } +} +-(void)setIsphoneView:(BOOL)isphoneView +{ + if(isphoneView) + { + [self.viewother setHidden:YES]; + } +} +-(void)setIsbind:(BOOL)isbind +{ + _isbind = isbind; + self.viewwx.isbind = isbind; + self.viewapple.isbind = isbind; +} + +-(void)xieyiPushAction:(int)tag +{ + WkWebviewViewController *vc = [[WkWebviewViewController alloc] init]; + if(tag==1) + { + vc.strtitle = @"隐私协议"; + vc.strurl = UserYinSiUrl; + } + else + { + vc.strtitle = @"用户协议"; + vc.strurl = UserXieUrl; + } + [self.viewController.navigationController pushViewController:vc animated:YES]; +} +-(void)backAction +{ + [self.viewController.navigationController popViewControllerAnimated:YES]; +} + +///0phone 1wx 2apple +-(void)otherSelectAction:(NSInteger)tag +{ + switch (tag) { + case 0: + { + [UserInfoModel shijianShangBao:0 key:@"client.check.login.type" value:@"code" extra:@""]; + [self.viewwx setHidden:YES]; + [self.viewapple setHidden:YES]; + /// + self.backValue(); + } + break; + case 1: + { + [UserInfoModel shijianShangBao:0 key:@"client.check.login.type" value:@"weixin" extra:@""]; + [self.viewwx setHidden:NO]; + [self.viewapple setHidden:YES]; + } + break; + case 2: + { + [UserInfoModel shijianShangBao:0 key:@"client.check.login.type" value:@"apple" extra:@""]; + [self.viewwx setHidden:YES]; + [self.viewapple setHidden:NO]; + } + break; + default: + break; + } +} + +-(void)codeAction:(UIButton *)sender +{ + [self endEditing:YES]; + if(self.fieldPhone.text.length==0) + { + [HXHud showMessage:@"请输入手机号" afterDelayType:0]; + return; + } + if(self.fieldPhone.text.length!=11) + { + [HXHud showMessage:@"请输入正确的手机号" afterDelayType:0]; + return; + } + [UserInfoModel shijianShangBao:0 key:@"client.get.code" value:@"code_login" extra:self.fieldPhone.text]; + + [HXLoadingHUD showWithStatus:@"" maskType:0]; + [PublicNetWorkManager requestUserCodeData:self phone:self.fieldPhone.text Callback:^(BOOL state, UserCodeModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + self.modelCode = responseObject.data; + ///倒计时 + [Tools startTimerWithStartTime:60 isCountDown:YES result:^(NSInteger seconds) { + if (seconds <= 0) { + [Tools stopTimer]; + dispatch_async(dispatch_get_main_queue(), ^{ + [sender setTitle:@"获取验证码" forState:UIControlStateNormal]; + sender.enabled = YES; + }); + }else{ + NSString *strTime = [NSString stringWithFormat:@"重新获取(%ld)", (long)seconds]; + dispatch_async(dispatch_get_main_queue(), ^{ + [sender setTitle:strTime forState:UIControlStateNormal]; + sender.enabled = NO; + }); + } + }]; + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:1]; + } + }]; +} + +-(void)xieyiAction:(UIButton *)sender +{ + sender.selected = !sender.selected; +} + +-(void)dengluAction +{ + [self endEditing:YES]; + if(self.fieldPhone.text.length==0) + { + [HXHud showMessage:@"请输入手机号" afterDelayType:0]; + return; + } + if(self.fieldPhone.text.length!=11) + { + [HXHud showMessage:@"请输入正确的手机号" afterDelayType:0]; + return; + } + if(self.fieldCode.text.length==0)//||self.modelCode==nil + { + [HXHud showMessage:@"请输入验证码" afterDelayType:0]; + return; + } + [UserInfoModel shijianShangBao:0 key:@"client.login.click" value:@"code" extra:self.fieldPhone.text]; + + NSString *strc = [[UserInfoModel shareModel].config objectForKey:@"client.agreement.dialog"]; + if((strc.intValue == 1 || [Tools isStringnil:strc].length==0) && self.btxy.selected == NO) + { + [UIAlertController showAlertInViewController:self.viewController withTitle:@"温馨提示" message:@"登录需要同意用户协议和隐私政策" cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { + if(buttonIndex==1) + { + [self.btxy setSelected:YES]; + /// + [self pushData]; + } + }]; + } + else + { + if(self.btxy.selected == NO) + { + [HXHud showMessage:@"需要同意用户协议和隐私政策" afterDelayType:0]; + return; + } + [self pushData]; + } +} +-(void)pushData +{ + NSDictionary *dic=@{@"timestamp":[Tools isStringnil:self.modelCode.timestamp], + @"phone":self.fieldPhone.text, + @"code":self.fieldCode.text}; + + [HXLoadingHUD showWithStatus:@"" maskType:0]; + [PublicNetWorkManager requestUserLoginData:self login_type:@"phone" phone:dic weixin:@{} apple:@{} device:@{} onekey:@{} bind:[NSNumber numberWithBool:self.isbind] unbind:[NSNumber numberWithBool:NO] Callback:^(BOOL state, UserLoginModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + + + + [UserInfoModel setLoingState:@"1"]; + [UserInfoModel setToken:responseObject.data.token]; + + if(self.isbind && self.isphoneView) + { + [UserInfoModel shijianShangBao:0 key:@"client.account.bind" value:@"code" extra:self.fieldPhone.text]; + } + else + { + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"code" extra:self.fieldPhone.text]; + } + + [UserInfoModel getUserData]; + [self pushVC]; + AppDelegate *appde = (AppDelegate *)[UIApplication sharedApplication].delegate; + + if([appde.window.rootViewController isKindOfClass:[TabBarController class]]) + { + NSArray *arr = self.viewController.navigationController.viewControllers; + for(UIViewController *vc in arr) + { + if([vc isKindOfClass:[ZhangHaoBangDingViewController class]]) + { + [self.viewController.navigationController popToViewController:vc animated:YES]; + return; + } + } + [self.viewController.navigationController popToRootViewControllerAnimated:YES]; + } + else + { + [appde.window setRootViewController:[TabBarController new]]; + } + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"code" extra:self.fieldPhone.text]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"updataUserState" object:nil]; + } + else + { + [UserInfoModel shijianShangBao:0 key:@"client.login.err" value:@"phone" extra:responseObject.message]; + [HXHud showMessage:responseObject.message afterDelayType:1]; + } + }]; +} +-(void)pushVC +{ + NSString *stridfa = [[NSUserDefaults standardUserDefaults] objectForKey:UserIDFA]; + [PublicNetWorkManager requestUserConfigData:self idfa:stridfa Callback:^(BOOL state, UserConfigModel *responseObject, NSString * _Nullable describle) { + if(state) + { + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel setAppid:responseObject.data.app_id]; + [UserInfoModel setTemp:responseObject.data.temp]; + [UserInfoModel setName:responseObject.data.name]; + [UserInfoModel setConfig:responseObject.data.config]; + [UserInfoModel shareModel].isloadconfig=YES; + + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:0]; + } + }]; +} + +-(void)otherAction:(UIButton *)sender +{ + [self otherSelectAction:sender.tag]; +} + +@end diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.h b/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.h new file mode 100644 index 0000000..122db69 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.h @@ -0,0 +1,18 @@ +// +// LoginWXView.h +// ProductApp +// +// Created by 工作 on 2024/8/5. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef void(^LoginWXViewBackOther)(NSInteger tag); +@interface LoginWXView : UIView +/// +@property (nonatomic , strong) LoginWXViewBackOther backValue; +@property (nonatomic , assign) BOOL isbind; +@end + +NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.m b/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.m new file mode 100644 index 0000000..99b9e81 --- /dev/null +++ b/ProductApp/ProductApp/ProductMain/login/view/LoginWXView.m @@ -0,0 +1,400 @@ +// +// LoginWXView.m +// ProductApp +// +// Created by 工作 on 2024/8/5. +// + +#import "LoginWXView.h" +#import +#import "PublicNetWorkManager.h" +#import "WkWebviewViewController.h" +#import +#import "UIAlertController+Blocks.h" +#import "AppDelegate.h" +#import "ZhangHaoBangDingViewController.h" + +@interface LoginWXView () +/// +@property (nonatomic , strong) UIView *viewother; +/// +@property (nonatomic , strong) UIButton *btxy; + +@end + +@implementation LoginWXView + +-(id)initWithFrame:(CGRect)frame +{ + if(self = [super initWithFrame:frame]) + { + UIImageView *imgvback = [[UIImageView alloc] init]; + [imgvback setImage:[UIImage imageNamed:@"login_back"]]; + [self addSubview:imgvback]; + [imgvback mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(self); + }]; + + UIButton *btback = [[UIButton alloc] init]; + [btback setImage:[UIImage imageNamed:@"login_X"] forState:UIControlStateNormal]; + [self addSubview:btback]; + [btback mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(40); + make.right.equalTo(self).offset(-10); + make.top.offset(NavHeight-20); + }]; + [btback addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; + + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"Hello!"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentLeft]; + [lbname setFont:[UIFont boldSystemFontOfSize:36]]; + [self addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(43); + make.top.offset(NavHeight+20); + }]; + + UILabel *lbinfo = [[UILabel alloc] init]; + [lbinfo setText:@"欢迎使用智能写作"]; + [lbinfo setTextColor:[UIColor whiteColor]]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:20]]; + [self addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(lbname); + make.top.equalTo(lbname.mas_bottom).offset(5); + }]; + + + UIImageView *imgvlog = [[UIImageView alloc] init]; + [imgvlog setImage:[UIImage imageNamed:@"login_logo"]]; + [self addSubview:imgvlog]; + [imgvlog mas_makeConstraints:^(MASConstraintMaker *make) { + make.width.height.offset(100); + make.centerX.equalTo(self); + make.centerY.equalTo(self).offset(-30); + }]; + + + + UIButton *btdenglu = [[UIButton alloc] init]; + [btdenglu setTitle:@"微信一键登录" forState:UIControlStateNormal]; + [btdenglu setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + [btdenglu.titleLabel setFont:[UIFont systemFontOfSize:20]]; + [btdenglu setImage:[UIImage imageNamed:@"login_wx_bai"] forState:UIControlStateNormal]; + [btdenglu.layer setMasksToBounds:YES]; + [btdenglu.layer setCornerRadius:20]; + [btdenglu setBackgroundColor:RGBCOLOR(40, 196, 69)]; + [self addSubview:btdenglu]; + [btdenglu mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(40); + make.right.equalTo(self).offset(-40); + make.height.offset(40); + make.top.equalTo(imgvlog.mas_bottom).offset(40); + }]; + [btdenglu addTarget:self action:@selector(dengluAction) forControlEvents:UIControlEventTouchUpInside]; + + UIButton *btxy = [[UIButton alloc] init]; + [btxy setImage:[UIImage imageNamed:@"login_Select_N"] forState:UIControlStateNormal]; + [btxy setImage:[UIImage imageNamed:@"login_Select_Y"] forState:UIControlStateSelected]; + [self addSubview:btxy]; + [btxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btdenglu).offset(30); + make.top.equalTo(btdenglu.mas_bottom).offset(10); + make.width.offset(40); + make.height.offset(30); + }]; + [btxy addTarget:self action:@selector(xieyiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btxy = btxy; + + YYLabel *lbxy = [[YYLabel alloc] init]; + [lbxy setText:@"我已阅读并同意用户协议和隐私协议"]; + [lbxy setTextColor:RGBCOLOR(155, 155, 155)]; + [lbxy setTextAlignment:NSTextAlignmentLeft]; + [lbxy setFont:[UIFont systemFontOfSize:12]]; + [self addSubview:lbxy]; + [lbxy mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btxy.mas_right).offset(0); + make.right.equalTo(lbxy).offset(-24); + make.centerY.equalTo(btxy); + make.height.offset(20); + }]; + NSMutableAttributedString *noteStr = [[NSMutableAttributedString alloc]initWithString:lbxy.text]; + NSMutableParagraphStyle *style = [NSMutableParagraphStyle new]; + style.lineSpacing = 5; + style.lineBreakMode = NSLineBreakByTruncatingTail; + [noteStr addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, lbinfo.text.length)]; + noteStr.yy_font = [UIFont systemFontOfSize:12.0f]; + noteStr.yy_color = RGBCOLOR(155, 155, 155); + [noteStr yy_setTextHighlightRange:NSMakeRange(7, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"用户协议"); + [self xieyiPushAction:0]; + }]; + [noteStr yy_setTextHighlightRange:NSMakeRange(12, 4) color:MainColor backgroundColor:[UIColor whiteColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) { + NSLog(@"隐私协议"); + [self xieyiPushAction:1]; + }]; + lbxy.attributedText = noteStr; + + UIView *viewother= [[UIView alloc] init]; + [self addSubview:viewother]; + [viewother mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.offset(90); + make.left.right.equalTo(self); + make.bottom.equalTo(self); + }]; + [self drawOtherView:viewother]; + _viewother = viewother; + } + return self; +} + +-(void)drawOtherView:(UIView *)view +{ + NSArray *arrpz = [[UserInfoModel shareModel].config objectForKey:@"client.login.type"]; + if(arrpz.count==0)return; + + UILabel *lbname = [[UILabel alloc] init]; + [lbname setText:@"其他登录方式"]; + [lbname setTextColor:[UIColor whiteColor]]; + [lbname setTextAlignment:NSTextAlignmentCenter]; + [lbname setFont:[UIFont systemFontOfSize:12]]; + [view addSubview:lbname]; + [lbname mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.offset(0); + make.centerX.equalTo(view); + make.width.offset(80); + }]; + + UIView *viewlineL = [[UIView alloc] init]; + [viewlineL setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineL]; + [viewlineL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(50); + make.right.equalTo(lbname.mas_left).offset(-10); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewlineR = [[UIView alloc] init]; + [viewlineR setBackgroundColor:[UIColor whiteColor]]; + [view addSubview:viewlineR]; + [viewlineR mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(view).offset(-50); + make.width.equalTo(viewlineL); + make.height.offset(1); + make.center.equalTo(lbname); + }]; + + UIView *viewcollect = [[UIView alloc] init]; + [view addSubview:viewcollect]; + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(lbname.mas_bottom); + make.bottom.equalTo(view); + make.centerX.equalTo(view); + }]; + + NSMutableArray *arrtmep = [NSMutableArray new]; + for(NSString *str in arrpz) + { + if([str isEqualToString:@"phone"]) + { + [arrtmep addObject:@"login_phone"]; + } + else if([str isEqualToString:@"apple"]) + { + [arrtmep addObject:@"login_apple"]; + } + } + NSArray *arr = arrtmep; + for(int i = 0 ; i < arr.count; i++) + { + UIButton *btitem = [[UIButton alloc] init]; + [btitem setImage:[UIImage imageNamed:arr[i]] forState:UIControlStateNormal]; + [viewcollect addSubview:btitem]; + [btitem mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.offset(60*i); + make.top.equalTo(lbname.mas_bottom).offset(10); + make.width.offset(50); + make.height.offset(50); + }]; + if([arr[i] isEqualToString:@"login_phone"]) + { + [btitem setTag:0]; + } + else if([arr[i] isEqualToString:@"login_apple"]) + { + [btitem setTag:1]; + } + + [btitem addTarget:self action:@selector(otherAction:) forControlEvents:UIControlEventTouchUpInside]; + if(i==arr.count-1) + { + [viewcollect mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(btitem); + }]; + } + } +} +-(void)xieyiPushAction:(int)tag +{ + WkWebviewViewController *vc = [[WkWebviewViewController alloc] init]; + if(tag==1) + { + vc.strtitle = @"隐私协议"; + vc.strurl = UserYinSiUrl; + } + else + { + vc.strtitle = @"用户协议"; + vc.strurl = UserXieUrl; + } + [self.viewController.navigationController pushViewController:vc animated:YES]; +} +-(void)otherAction:(UIButton *)sender +{ + if(sender.tag==0) + { + self.backValue(0); + } + else + { + self.backValue(2); + } + +} +-(void)xieyiAction:(UIButton *)sender +{ + sender.selected = !sender.selected; +} +///wx登录 +-(void)dengluAction +{ + [UserInfoModel shijianShangBao:0 key:@"client.login.click" value:@"weixin" extra:@""]; + NSString *strc = [[UserInfoModel shareModel].config objectForKey:@"client.agreement.dialog"]; + if((strc.intValue == 1 || [Tools isStringnil:strc].length==0) && self.btxy.selected == NO) + { + [UIAlertController showAlertInViewController:self.viewController withTitle:@"温馨提示" message:@"登录需要同意用户协议和隐私政策" cancelButtonTitle:@"取消" destructiveButtonTitle:@"确定" otherButtonTitles:nil tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { + if(buttonIndex==1) + { + [self.btxy setSelected:YES]; + /// + [self pushDataWX]; + } + }]; + } + else + { + if(self.btxy.selected == NO) + { + [HXHud showMessage:@"需要同意用户协议和隐私政策" afterDelayType:0]; + return; + } + [self pushDataWX]; + } +} +-(void)pushDataWX +{ + @try { + [[NSNotificationCenter defaultCenter] removeObserver:self name:WeiXinDengLuSQ object:nil]; + } @catch (NSException *exception) { + + } @finally { + + } + + + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(weixinNotifi:) name: WeiXinDengLuSQ object: nil]; + SendAuthReq *req = [[SendAuthReq alloc] init]; + req.scope = @"snsapi_userinfo"; + req.state = @"123"; + + [WXApi sendAuthReq:req viewController:self.viewController delegate:nil completion:^(BOOL success) { + + }]; +} + +-(void)weixinNotifi:(NSNotification *)notifi +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:WeiXinDengLuSQ object:nil]; + if(notifi.object!=nil) + { + SendAuthResp *resp = notifi.object; + + NSDictionary *dic=@{@"code":[Tools isStringnil:resp.code], + @"code_type":@""}; + + [HXLoadingHUD showWithStatus:@"" maskType:0]; + [PublicNetWorkManager requestUserLoginData:self login_type:@"weixin" phone:@{} weixin:dic apple:@{} device:@{} onekey:@{} bind:[NSNumber numberWithBool:self.isbind] unbind:[NSNumber numberWithBool:NO] Callback:^(BOOL state, UserLoginModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + + [UserInfoModel setLoingState:@"1"]; + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"weixin" extra:@""]; + [UserInfoModel getUserData]; + [self pushVC]; + AppDelegate *appde = (AppDelegate *)[UIApplication sharedApplication].delegate; + + if([appde.window.rootViewController isKindOfClass:[TabBarController class]]) + { + NSArray *arr = self.viewController.navigationController.viewControllers; + for(UIViewController *vc in arr) + { + if([vc isKindOfClass:[ZhangHaoBangDingViewController class]]) + { + [self.viewController.navigationController popToViewController:vc animated:YES]; + return; + } + } + [self.viewController.navigationController popToRootViewControllerAnimated:YES]; + } + else + { + [appde.window setRootViewController:[TabBarController new]]; + } + + [UserInfoModel shijianShangBao:0 key:@"client.login.success" value:@"weixin" extra:[Tools isStringnil:resp.code]]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"updataUserState" object:nil]; + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:1]; + [UserInfoModel shijianShangBao:0 key:@"client.login.err" value:@"weixin" extra:responseObject.message]; + } + }]; + } + else + {///微信取消或者失败 + + } + + NSLog(@"111"); + +} +-(void)pushVC +{ + NSString *stridfa = [[NSUserDefaults standardUserDefaults] objectForKey:UserIDFA]; + [PublicNetWorkManager requestUserConfigData:self idfa:stridfa Callback:^(BOOL state, UserConfigModel *responseObject, NSString * _Nullable describle) { + if(state) + { + [UserInfoModel setToken:responseObject.data.token]; + [UserInfoModel setAppid:responseObject.data.app_id]; + [UserInfoModel setTemp:responseObject.data.temp]; + [UserInfoModel setName:responseObject.data.name]; + [UserInfoModel setConfig:responseObject.data.config]; + [UserInfoModel shareModel].isloadconfig=YES; + + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:0]; + } + }]; +} + +@end diff --git a/ProductApp/ProductApp/ProductMain/工具/GongJuListViewController.m b/ProductApp/ProductApp/ProductMain/工具/GongJuListViewController.m index 3bf9f8b..d14fac9 100644 --- a/ProductApp/ProductApp/ProductMain/工具/GongJuListViewController.m +++ b/ProductApp/ProductApp/ProductMain/工具/GongJuListViewController.m @@ -58,9 +58,9 @@ -(void)getdata { - [HXLoadingHUD showWithStatus:@"" maskType:0]; + [LoadAlterView show]; [NetWorkManager requestToolsListData:self.view page:self.ipage type_id:self.model.ID tool_name:self.model.type_name is_recommend:[Tools isStringnil:self.model.ID].length==0?@"0":@"" Callback:^(BOOL state, ToolsListModel *responseObject, NSString * _Nullable describle) { - [HXLoadingHUD dismiss]; + [LoadAlterView dismiss]; [self.tableView.mj_header endRefreshing]; [self.tableView.mj_footer endRefreshing]; if(self.ipage==1)self.arrdata = [NSMutableArray new]; diff --git a/ProductApp/ProductApp/ProductMain/工具/GongJuViewController.m b/ProductApp/ProductApp/ProductMain/工具/GongJuViewController.m index 1328122..210461b 100644 --- a/ProductApp/ProductApp/ProductMain/工具/GongJuViewController.m +++ b/ProductApp/ProductApp/ProductMain/工具/GongJuViewController.m @@ -164,9 +164,9 @@ -(void)getdata { - [HXLoadingHUD showWithStatus:@"" maskType:0]; + [LoadAlterView show]; [NetWorkManager requestToolsTypeData:self.view Callback:^(BOOL state, ToolsTypeModel *responseObject, NSString * _Nullable describle) { - [HXLoadingHUD dismiss]; +// [LoadAlterView dismiss]; if(state) { self.arrdata = [NSMutableArray new]; diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.h b/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.h index 7e763ec..dc668d5 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.h +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.h @@ -10,7 +10,8 @@ NS_ASSUME_NONNULL_BEGIN @interface StartPayViewController : BaseViewController - +///0引导页 1我的 +@property (nonatomic , assign) int ptype; @end NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.m b/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.m index e20017c..4e6bdee 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.m +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/StartPayViewController.m @@ -7,7 +7,7 @@ #import "StartPayViewController.h" #import "StartPayView.h" - +#import "PublicNetWorkManager.h" @interface StartPayViewController () @@ -31,6 +31,22 @@ make.left.right.bottom.equalTo(self.view); make.top.offset(0); }]; + view.ptype = self.ptype; + [view setHidden:YES]; + + [HXLoadingHUD showWithStatus:@"" maskType:0]; + [PublicNetWorkManager requestOrderGoodsData:self.view type:@"member" Callback:^(BOOL state, OrderGoodsModel *responseObject, NSString * _Nullable describle) { + [HXLoadingHUD dismiss]; + if(state) + { + [view setHidden:NO]; + view.arrGoods = responseObject.data; + } + else + { + [HXHud showMessage:responseObject.message afterDelayType:1]; + } + }]; } diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.h b/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.h index a4186ad..2d427c0 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.h +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.h @@ -6,12 +6,12 @@ // #import - +#import "OrderGoodsModel.h" NS_ASSUME_NONNULL_BEGIN @interface StartPayGoodsCollectionViewCell : UICollectionViewCell /// -@property (nonatomic , strong) baseInfoModel *model; +@property (nonatomic , strong) OrderGoodsModelData *model; @end NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.m b/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.m index b2d2a52..09b35b6 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.m +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/cell/StartPayGoodsCollectionViewCell.m @@ -98,9 +98,15 @@ return self; } --(void)setModel:(baseInfoModel *)model +-(void)setModel:(OrderGoodsModelData *)model { _model = model; + + self.lbname.text = model.goods_name; + self.lbprice.text = [NSString stringWithFormat:@"¥%@",model.price]; + self.lbyuanjia.text = [NSString stringWithFormat:@"¥%@",model.origin_price]; + self.lbyouhui.text = [NSString stringWithFormat:@"已优惠%@元",[Tools backprice:[NSString stringWithFormat:@"%.2lf",model.origin_price.floatValue-model.price.floatValue]]]; + if(model.select) { [self.viewback mas_updateConstraints:^(MASConstraintMaker *make) { diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.h b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.h index c090a39..3acf0a4 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.h +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.h @@ -6,12 +6,18 @@ // #import +#import "PayPublicView.h" +@class OrderGoodsModelData; NS_ASSUME_NONNULL_BEGIN -typedef void(^StartPayGoodsViewSelectGoods)(baseInfoModel *model); +typedef void(^StartPayGoodsViewSelectGoods)(OrderGoodsModelData *model); @interface StartPayGoodsView : UIView /// +@property (nonatomic , strong) NSArray *arrGoods; +/// @property (nonatomic , strong) StartPayGoodsViewSelectGoods backSelectGoods; +/// +@property (nonatomic , strong) PayPublicView *viewpay ; -(void)removeTime; @end diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.m b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.m index 3fb51ef..f5a546d 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.m +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayGoodsView.m @@ -10,22 +10,17 @@ #import "StartPayDaoJiShiView.h" #import "StartPayGoodsPayView.h" +#import "YaoQingViewController.h" @interface StartPayGoodsView () /// @property (nonatomic , strong) UICollectionView *collect; /// @property (nonatomic , strong) StartPayDaoJiShiView *viewtime; -/// -@property (nonatomic , strong) StartPayGoodsPayView *viewpay ; - /// -@property (nonatomic , strong) NSMutableArray *arrGoods; - -/// -@property (nonatomic , strong) baseInfoModel *modelSelect; +@property (nonatomic , strong) OrderGoodsModelData *modelSelect; @end @@ -70,7 +65,9 @@ [viewtime setBackgroundColor:RGBACOLOR(255, 255, 255, 0.5)]; _viewtime = viewtime; + ////////////更改为新版支付 /// + /* StartPayGoodsPayView *viewpay = [StartPayGoodsPayView new]; [self addSubview:viewpay]; [viewpay mas_makeConstraints:^(MASConstraintMaker *make) { @@ -84,38 +81,87 @@ }]; _viewpay = viewpay; - self.viewpay.arrPay = @[@"weixin",@"alipay"]; + */ + + ///支付 + PayPublicView *viewpay = [PayPublicView new]; + [self addSubview:viewpay]; + [viewpay mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(viewtime); + make.top.equalTo(viewtime.mas_bottom).offset(12); + }]; + _viewpay = viewpay; + [self drawpay]; + [viewpay setBackValue:^{ + + }]; + [viewpay setBackGoValue:^{ + YaoQingViewController *vc = [YaoQingViewController new]; + [self.viewController.navigationController pushViewController:vc animated:YES]; + }]; + [self mas_makeConstraints:^(MASConstraintMaker *make) { make.bottom.equalTo(viewpay).offset(10); }]; - ///测试数据 - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [self getData]; - }); - } return self; } - --(void)getData +-(void)drawpay { - self.arrGoods = [NSMutableArray new]; - for(int i = 0 ; i < 3; i++) + if([UserInfoModel PayWXQuanXian]) { - baseInfoModel *model = [baseInfoModel new]; - if(i==1) - { - model.select=YES; - self.modelSelect = model; - } - [self.arrGoods addObject:model]; + [self.viewpay setHidden:NO]; } + else + { + [self.viewpay setHidden:YES]; + } +} + +-(void)setArrGoods:(NSArray *)arrGoods +{ + _arrGoods = arrGoods; + if(arrGoods.count==0)return; + self.modelSelect = arrGoods.firstObject; + if(arrGoods.count>1) + { + self.modelSelect = arrGoods[1]; + } + self.modelSelect.select = YES; + [self.collect reloadData]; self.backSelectGoods(self.modelSelect); + [self setpayViewShow]; +} +-(void)setpayViewShow +{ + NSArray *arrtemp = [self.modelSelect.pay_type componentsSeparatedByString:@","]; + NSMutableArray *arrdraw = [NSMutableArray new]; + for(NSString *strtemp in arrtemp) + { + if ([strtemp isEqualToString:@"weixin"]) + {///微信 + [arrdraw addObject:@"weixin"]; + } + else if ([strtemp isEqualToString:@"alipay"]) + {///zfb + [arrdraw addObject:@"alipay"]; + } + else if ([strtemp isEqualToString:@"balance"]) + {///zfb + [arrdraw addObject:@"balance"]; + } + } + + ///需要判断余额是否可用 + self.viewpay.stryue = [UserInfoModel shareModel].balance; + self.viewpay.strgoodsprice = self.modelSelect.price; + self.viewpay.arrData = arrdraw; + } #pragma mark - UICollectionView diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.h b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.h index 7abc498..f0afdb9 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.h +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.h @@ -10,7 +10,10 @@ NS_ASSUME_NONNULL_BEGIN @interface StartPayView : UIView - +///0引导页 1我的 +@property (nonatomic , assign) int ptype; +///商品 +@property (nonatomic , strong) NSArray *arrGoods; @end NS_ASSUME_NONNULL_END diff --git a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.m b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.m index 91cb904..d39b7a9 100644 --- a/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.m +++ b/ProductApp/ProductApp/ProductMain/引导/支付页/view/StartPayView.m @@ -8,6 +8,9 @@ #import "StartPayView.h" #import "StartPayTQView.h" #import "StartPayGoodsView.h" +#import "TabBarController.h" +#import "AppDelegate.h" +#import "PublicNetWorkManager.h" @interface StartPayView () /// @@ -15,8 +18,13 @@ /// @property (nonatomic , strong) UILabel *lbjiage; @property (nonatomic , strong) UILabel *lbyuanjia; +///协议 +@property (nonatomic , strong) UIButton *btxiyi; +@property (nonatomic , strong) UILabel *lbinfo; +@property (nonatomic , strong) UIButton *btzd; + /// -@property (nonatomic , strong) baseInfoModel *modelSelect; +@property (nonatomic , strong) OrderGoodsModelData *modelSelect; @end @@ -112,14 +120,24 @@ make.left.width.equalTo(scvback); make.top.equalTo(viewtq.mas_bottom).offset(20); }]; - [viewgoods setBackSelectGoods:^(baseInfoModel * _Nonnull model) { + [viewgoods setBackSelectGoods:^(OrderGoodsModelData * _Nonnull model) { self.modelSelect = model; [self refBottomShow]; }]; _viewgoods = viewgoods; + ///协议 + UIView *viewxiyi = [[UIView alloc] init]; + [scvback addSubview:viewxiyi]; + [viewxiyi mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(viewtq); + make.top.equalTo(viewgoods.mas_bottom); + make.height.offset(30); + }]; + [self drawXieYiView:viewxiyi]; + [scvback mas_makeConstraints:^(MASConstraintMaker *make) { - make.bottom.equalTo(viewgoods).offset(20); + make.bottom.equalTo(viewxiyi).offset(20); }]; /// @@ -134,6 +152,69 @@ } return self; } +-(void)drawXieYiView:(UIView *)view +{ + UIView *viewback = [[UIView alloc] init]; + [view addSubview:viewback]; + [viewback mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.equalTo(view); + make.height.equalTo(view); + }]; + + UIButton *btxiyi = [[UIButton alloc] init]; + [btxiyi setTitle:@"同意并接受" forState:UIControlStateNormal]; + [btxiyi setTitleColor:RGBCOLOR(120, 120, 120) forState:UIControlStateNormal]; + [btxiyi.titleLabel setFont:[UIFont systemFontOfSize:12]]; + [btxiyi setImage:[UIImage imageNamed:@"zfb_select_N"] forState:UIControlStateNormal]; + [btxiyi setImage:[UIImage imageNamed:@"zfb_select_Y"] forState:UIControlStateSelected]; + [viewback addSubview:btxiyi]; + [btxiyi mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.left.equalTo(viewback); + }]; + [btxiyi setIconInLeftWithSpacing:2]; + [btxiyi addTarget:self action:@selector(xieyiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btxiyi = btxiyi; + + UILabel *lbinfo = [[UILabel alloc] init]; + [lbinfo setText:@"《会员服务协议》"];///《自动续费协议》和《会员服务协议》 + [lbinfo setTextColor:MainColor]; + [lbinfo setTextAlignment:NSTextAlignmentLeft]; + [lbinfo setFont:[UIFont systemFontOfSize:14]]; + [viewback addSubview:lbinfo]; + [lbinfo mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(btxiyi.mas_right); + make.centerY.equalTo(viewback); + }]; + _lbinfo = lbinfo; + + float f_w = [Tools getWidthWithText:@"《自动续费协议》" height:20 font:14]; + UIButton *bthy = [[UIButton alloc] init]; + [viewback addSubview:bthy]; + [bthy mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(viewback); + make.right.height.equalTo(viewback); + make.width.offset(f_w); + }]; + [bthy setTag:1]; + [bthy addTarget:self action:@selector(wbXieYiAction:) forControlEvents:UIControlEventTouchUpInside]; + + UIButton *btzd = [[UIButton alloc] init]; + [viewback addSubview:btzd]; + [btzd mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(viewback); + make.height.equalTo(viewback); + make.left.equalTo(lbinfo); + make.width.offset(0); + }]; + [btzd setTag:2]; + [btzd addTarget:self action:@selector(wbXieYiAction:) forControlEvents:UIControlEventTouchUpInside]; + _btzd = btzd; + [self setXieYiShow]; + [viewback mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(lbinfo); + }]; +} + -(void)drawBottomView:(UIView *)view { UIView *viewhj = [[UIView alloc] init]; @@ -199,17 +280,83 @@ [Tools changedView:btpay colors:MainJBColors startPoint:CGPointMake(0, 0) endPoint:CGPointMake(1, 0)]; } +-(void)setXieYiShow +{ + if([[Tools isStringnil:self.modelSelect.sign_value] stringByReplacingOccurrencesOfString:@" " withString:@""].length==0) + { + self.lbinfo.text = @"《会员服务协议》"; + } + else + { + self.lbinfo.text = @"《会员服务协议》"; + if(self.viewgoods.viewpay.btselect.tag==2) + { + self.lbinfo.text = @"《自动续费协议》和《会员服务协议》"; + } + } + + float f_w = [Tools getWidthWithText:@"《自动续费协议》" height:20 font:14]; + NSRange range = [self.lbinfo.text rangeOfString:@"和"]; + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:self.lbinfo.text]; + + if(range.length>0) + { + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, 8)]; + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(9, 8)]; + + [attributedString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:range]; + [attributedString addAttribute:NSForegroundColorAttributeName value:RGBCOLOR(120, 120, 120) range:range]; + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(8, 1)]; + + [self.btzd mas_updateConstraints:^(MASConstraintMaker *make) { + make.width.offset(f_w); + }]; + } + else + { + [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0, [self.lbinfo.text length])]; + [self.btzd mas_updateConstraints:^(MASConstraintMaker *make) { + make.width.offset(0); + }]; + } + self.lbinfo.attributedText = attributedString; +} + -(void)refBottomShow { [self.lbjiage setText:@"199元"]; [self.lbyuanjia setText:@"已优惠999元"]; self.lbjiage.attributedText = [Tools arrstring:self.lbjiage.text andstart:(int)self.lbjiage.text.length-1 andend:1 andfont:[UIFont boldSystemFontOfSize:14] andcolor:RGBCOLOR(249, 37, 95)]; } +-(void)xieyiAction:(UIButton *)sender +{ + sender.selected = !sender.selected; +} +-(void)wbXieYiAction:(UIButton *)sender +{ + +} +-(void)setArrGoods:(NSArray *)arrGoods +{ + _arrGoods = arrGoods; + self.viewgoods.arrGoods = arrGoods; +} -(void)delAction { [self.viewgoods removeTime]; + + if(self.ptype==0) + { + TabBarController *vc = [TabBarController new]; + AppDelegate *appde = (AppDelegate *)[UIApplication sharedApplication].delegate; + [appde.window setRootViewController:vc]; + } + else + { + [self.viewController.navigationController popViewControllerAnimated:YES]; + } } diff --git a/ProductApp/ProductApp/ProductMain/我的/view/WoDeInfoView.m b/ProductApp/ProductApp/ProductMain/我的/view/WoDeInfoView.m index 571111a..c0e7b11 100644 --- a/ProductApp/ProductApp/ProductMain/我的/view/WoDeInfoView.m +++ b/ProductApp/ProductApp/ProductMain/我的/view/WoDeInfoView.m @@ -6,7 +6,7 @@ // #import "WoDeInfoView.h" - +#import "LoginViewController.h" @interface WoDeInfoView () @@ -151,7 +151,7 @@ ////只有游客才有以下数据 并且点击进入登录页面 UIImageView *imgvnext = [[UIImageView alloc] init]; - [imgvnext setImage:[UIImage imageNamed:@"my_next"]]; + [imgvnext setImage:[UIImage imageNamed:@"yq_next"]]; [self addSubview:imgvnext]; [imgvnext mas_makeConstraints:^(MASConstraintMaker *make) { make.width.height.offset(20); @@ -213,11 +213,14 @@ ///用户信息 游客才有以下数据 并且点击进入登录页面 -(void)userAction { - if(self.modelDetail.temp.intValue == 1) - { +// if(self.modelDetail.temp.intValue == 1) +// { // LoginViewController *vc = [[LoginViewController alloc] init]; // [self.viewController.navigationController pushViewController:vc animated:YES]; - } +// } + + LoginViewController *vc = [[LoginViewController alloc] init]; + [self.viewController.navigationController pushViewController:vc animated:YES]; } @end diff --git a/ProductApp/ProductApp/ProductMain/我的/view/WoDeView.m b/ProductApp/ProductApp/ProductMain/我的/view/WoDeView.m index 98ff975..6fbde11 100644 --- a/ProductApp/ProductApp/ProductMain/我的/view/WoDeView.m +++ b/ProductApp/ProductApp/ProductMain/我的/view/WoDeView.m @@ -15,6 +15,8 @@ #import "YiJianFanKuiController.h" #import "AppDelegate.h" #import "ShareAlterView.h" +#import "StartPayViewController.h" + @interface WoDeView () @@ -175,7 +177,9 @@ -(void)kaitongAction { - + StartPayViewController *vc = [StartPayViewController new]; + vc.ptype = 1; + [self.viewController.navigationController pushViewController:vc animated:YES]; } #pragma mark - UITableView diff --git a/ProductApp/ProductApp/ProductMain/我的/view/WoDeYouHuiView.m b/ProductApp/ProductApp/ProductMain/我的/view/WoDeYouHuiView.m index 15442df..b07a3f6 100644 --- a/ProductApp/ProductApp/ProductMain/我的/view/WoDeYouHuiView.m +++ b/ProductApp/ProductApp/ProductMain/我的/view/WoDeYouHuiView.m @@ -6,6 +6,8 @@ // #import "WoDeYouHuiView.h" +#import "TiXianViewController.h" +#import "YouHuiQuanViewController.h" @interface WoDeYouHuiView () @@ -94,9 +96,7 @@ make.centerY.equalTo(imgvback); make.right.equalTo(view).offset(-10); }]; - [btitem setTag:tag]; - [btitem addTarget:self action:@selector(itemAction:) forControlEvents:UIControlEventTouchUpInside]; - + UILabel *lbvalue = [[UILabel alloc] init]; [lbvalue setText:@"0 元"]; [lbvalue setTextColor:RGBCOLOR(26, 26, 26)]; @@ -110,6 +110,15 @@ [self refLB:lbvalue]; + UIButton *btview = [[UIButton alloc] init]; + [view addSubview:btview]; + [btview mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(view); + }]; + [btview setTag:tag]; + [btview addTarget:self action:@selector(itemAction:) forControlEvents:UIControlEventTouchUpInside]; + + return lbvalue; } -(void)refLB:(UILabel *)lb @@ -119,7 +128,16 @@ -(void)itemAction:(UIButton *)sender { - + if(sender.tag==0) + { + TiXianViewController *vc = [TiXianViewController new]; + [self.viewController.navigationController pushViewController:vc animated:YES]; + } + else + { + YouHuiQuanViewController *vc = [YouHuiQuanViewController new]; + [self.viewController.navigationController pushViewController:vc animated:YES]; + } } @end diff --git a/ProductApp/ProductApp/pag_loading.pag b/ProductApp/ProductApp/pag_loading.pag new file mode 100644 index 0000000..f981a62 Binary files /dev/null and b/ProductApp/ProductApp/pag_loading.pag differ