From ce72b78496104be45e59ab86e888b0f2b1adea1f Mon Sep 17 00:00:00 2001 From: iHTCboy Date: Fri, 27 Jan 2023 22:59:08 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E6=96=B0=E5=A2=9E=E4=B8=AD=E6=96=87?= =?UTF-8?q?=E8=AF=B5=E8=AF=BB=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=96=B9=E4=BE=BF?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8B=BC=E9=9F=B3=E6=8B=BC=E5=86=99=20-=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=9F=A5=E5=AD=97=E5=92=8C=E6=9F=A5=E8=AF=8D?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E6=9B=B4=E5=8A=A0=E6=96=B9=E4=BE=BF?= =?UTF-8?q?=E9=AB=98=E6=95=88=20-=20=E4=BC=98=E5=8C=96=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=BB=86=E8=8A=82=E5=92=8C=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- iWuBi.xcodeproj/project.pbxproj | 34 ++++-- iWuBi/Common/TCVoiceUtils.swift | 98 ++++++++++++++++ iWuBi/Resource/Images/playvoice@2x.png | Bin 0 -> 10958 bytes iWuBi/View/ITListTitleViewCell.swift | 6 +- iWuBi/View/ITListTitleViewCell.xib | 61 +++++++--- .../Base.lproj/IHTCSearchViewController.xib | 33 ++---- .../ViewController/IHTCMeViewController.swift | 10 +- iWuBi/ViewController/IHTCSearchDetailVC.swift | 12 +- .../IHTCSearchViewController.swift | 101 +++++++++++++++- .../IHTCTTSViewController.swift | 110 ++++++++++++++++++ .../IHTCWordDetailViewController.swift | 8 +- iWuBi/en.lproj/InfoPlist.strings | 3 +- iWuBi/zh-Hans.lproj/InfoPlist.strings | 3 +- iWuBi/zh-Hant.lproj/InfoPlist.strings | 3 +- 14 files changed, 428 insertions(+), 54 deletions(-) create mode 100644 iWuBi/Common/TCVoiceUtils.swift create mode 100644 iWuBi/Resource/Images/playvoice@2x.png create mode 100644 iWuBi/ViewController/IHTCTTSViewController.swift diff --git a/iWuBi.xcodeproj/project.pbxproj b/iWuBi.xcodeproj/project.pbxproj index b0acf46..b195c3e 100644 --- a/iWuBi.xcodeproj/project.pbxproj +++ b/iWuBi.xcodeproj/project.pbxproj @@ -9,6 +9,12 @@ /* Begin PBXBuildFile section */ 2D6303726115B67060D09E85 /* Pods_iWuBiTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5AA5AA6FD67142615E34DC61 /* Pods_iWuBiTests.framework */; }; 3719B7397CAA52057F9F1153 /* Pods_iWuBiUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6E83B6E1E91072EBEA6E329 /* Pods_iWuBiUITests.framework */; }; + 6D0B41282983DDFE006F8C18 /* playvoice@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D0B41272983DDFE006F8C18 /* playvoice@2x.png */; }; + 6D0B41292983DDFE006F8C18 /* playvoice@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6D0B41272983DDFE006F8C18 /* playvoice@2x.png */; }; + 6D0B412B2983E336006F8C18 /* TCVoiceUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0B412A2983E336006F8C18 /* TCVoiceUtils.swift */; }; + 6D0B412C2983E336006F8C18 /* TCVoiceUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0B412A2983E336006F8C18 /* TCVoiceUtils.swift */; }; + 6D0B412E2983FB1E006F8C18 /* IHTCTTSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0B412D2983FB1E006F8C18 /* IHTCTTSViewController.swift */; }; + 6D0B412F2983FB1E006F8C18 /* IHTCTTSViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D0B412D2983FB1E006F8C18 /* IHTCTTSViewController.swift */; }; 6D0BF3BF2442186B009EA94B /* IHTC98WordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB88DEB225B8E340099AC80 /* IHTC98WordViewController.swift */; }; 6D0BF3C02442186B009EA94B /* IHTCAboutAppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB88DE2225B8E340099AC80 /* IHTCAboutAppViewController.swift */; }; 6D0BF3C12442186B009EA94B /* IHTCMeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DB88DE3225B8E340099AC80 /* IHTCMeViewController.swift */; }; @@ -293,6 +299,9 @@ 4DFAA5851858A4D9CB53BF20 /* libPods-iWuBi-MacCatylyst.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-iWuBi-MacCatylyst.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 5AA5AA6FD67142615E34DC61 /* Pods_iWuBiTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iWuBiTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5FABFA1D936DFEDD99C5AC4A /* Pods_iWuBi.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iWuBi.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6D0B41272983DDFE006F8C18 /* playvoice@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "playvoice@2x.png"; sourceTree = ""; }; + 6D0B412A2983E336006F8C18 /* TCVoiceUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCVoiceUtils.swift; sourceTree = ""; }; + 6D0B412D2983FB1E006F8C18 /* IHTCTTSViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IHTCTTSViewController.swift; sourceTree = ""; }; 6D0BF43E2442186B009EA94B /* iWuBi.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iWuBi.app; sourceTree = BUILT_PRODUCTS_DIR; }; 6D0BF441244218FC009EA94B /* iWuBi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = iWuBi.entitlements; sourceTree = ""; }; 6D3B83D5225E238200037787 /* iWuBi-orange-word.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "iWuBi-orange-word.png"; sourceTree = ""; }; @@ -664,6 +673,7 @@ 6DB88DB9225B8E340099AC80 /* Images */ = { isa = PBXGroup; children = ( + 6D0B41272983DDFE006F8C18 /* playvoice@2x.png */, 6DA588A02605FD2400C351C4 /* favorites_normal@2x.png */, 6DA588A12605FD2400C351C4 /* favorites_selected@2x.png */, 6DA588932605FBC600C351C4 /* favorites_normal@3x.png */, @@ -758,6 +768,7 @@ 6D76E2F022632C1F005EACCA /* IHTCLearnDetailViewController.swift */, 6DB88DE3225B8E340099AC80 /* IHTCMeViewController.swift */, 6DA588AA2605FDC800C351C4 /* IHTCFavoritesListVC.swift */, + 6D0B412D2983FB1E006F8C18 /* IHTCTTSViewController.swift */, 6DB88DE2225B8E340099AC80 /* IHTCAboutAppViewController.swift */, 6DB88DE8225B8E340099AC80 /* IHTCAboutAppViewController.xib */, 6DB1AF962278A7640051A288 /* ITAdvancelDetailViewController.swift */, @@ -789,6 +800,7 @@ 6DB88E1D225B8E720099AC80 /* Common */ = { isa = PBXGroup; children = ( + 6D0B412A2983E336006F8C18 /* TCVoiceUtils.swift */, 6DB88E1E225B8E720099AC80 /* CommonDefine.swift */, 6DB88E1F225B8E720099AC80 /* ITCommonAPI.swift */, 6D76E2B62262C613005EACCA /* IAppleServiceUtil.swift */, @@ -984,6 +996,7 @@ 6D0BF4002442186B009EA94B /* Main.storyboard in Resources */, 6D0BF4012442186B009EA94B /* tabbar_selected_98@3x.png in Resources */, 6D0BF4022442186B009EA94B /* ITQuestionListViewCell.xib in Resources */, + 6D0B41292983DDFE006F8C18 /* playvoice@2x.png in Resources */, 6D0BF4032442186B009EA94B /* iWiBi-orange-icon@2x.png in Resources */, 6D0BF4042442186B009EA94B /* iWuBi-orange-word.png in Resources */, 6D0BF4052442186B009EA94B /* InfoPlist.strings in Resources */, @@ -1067,6 +1080,7 @@ 6D3B83E0225E27B500037787 /* Main.storyboard in Resources */, 6D76E2D72263118D005EACCA /* tabbar_selected_98@3x.png in Resources */, 6DB88E0C225B8E340099AC80 /* ITQuestionListViewCell.xib in Resources */, + 6D0B41282983DDFE006F8C18 /* playvoice@2x.png in Resources */, 6D531B71226379CB00C921B8 /* iWiBi-orange-icon@2x.png in Resources */, 6D3B83D6225E238300037787 /* iWuBi-orange-word.png in Resources */, 6D3B83F2225E307700037787 /* InfoPlist.strings in Resources */, @@ -1281,12 +1295,14 @@ 6D0BF3D42442186B009EA94B /* ITQuestionListViewCell.swift in Sources */, 6D0BF3D52442186B009EA94B /* ITCopyLabel.swift in Sources */, 6D0BF3D62442186B009EA94B /* IAppleServiceUtil.swift in Sources */, + 6D0B412F2983FB1E006F8C18 /* IHTCTTSViewController.swift in Sources */, 6DEB12B8244B536500CD4192 /* SceneDelegate.swift in Sources */, 6D0BF3D72442186B009EA94B /* IHTC86WordViewController.swift in Sources */, 6D0BF3D82442186B009EA94B /* ITBasePushTransitionVC.swift in Sources */, 6D0BF3D92442186B009EA94B /* IHTCWuBiWordViewCell.swift in Sources */, 6D0BF3DA2442186B009EA94B /* IHTCImgModel.swift in Sources */, 6D0BF3DB2442186B009EA94B /* ITScalePopTransition.swift in Sources */, + 6D0B412C2983E336006F8C18 /* TCVoiceUtils.swift in Sources */, 6D0BF3DC2442186B009EA94B /* IHTCLearnDetailViewController.swift in Sources */, 6D0BF3DD2442186B009EA94B /* TableHeaderView.swift in Sources */, 6D0BF3DE2442186B009EA94B /* ITPageTitleView.swift in Sources */, @@ -1326,12 +1342,14 @@ 6DB88E08225B8E340099AC80 /* ITQuestionListViewCell.swift in Sources */, 6DB88E09225B8E340099AC80 /* ITCopyLabel.swift in Sources */, 6D76E2B72262C613005EACCA /* IAppleServiceUtil.swift in Sources */, + 6D0B412E2983FB1E006F8C18 /* IHTCTTSViewController.swift in Sources */, 6DEB12B7244B536500CD4192 /* SceneDelegate.swift in Sources */, 6DB88E19225B8E340099AC80 /* IHTC86WordViewController.swift in Sources */, 6DB88E14225B8E340099AC80 /* ITBasePushTransitionVC.swift in Sources */, 6D76E27F225F95F7005EACCA /* IHTCWuBiWordViewCell.swift in Sources */, 6D76E27C225F9064005EACCA /* IHTCImgModel.swift in Sources */, 6DB88E1C225B8E340099AC80 /* ITScalePopTransition.swift in Sources */, + 6D0B412B2983E336006F8C18 /* TCVoiceUtils.swift in Sources */, 6D76E2F122632C1F005EACCA /* IHTCLearnDetailViewController.swift in Sources */, 6DB1AF952278A75D0051A288 /* TableHeaderView.swift in Sources */, 6DB88E0A225B8E340099AC80 /* ITPageTitleView.swift in Sources */, @@ -1418,7 +1436,7 @@ CODE_SIGN_ENTITLEMENTS = iWuBi/iWuBi.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2023.01.24; + CURRENT_PROJECT_VERSION = 2023.01.27; DEVELOPMENT_TEAM = 28PV6G96R7; INFOPLIST_FILE = "$(SRCROOT)/iWuBi/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -1427,7 +1445,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 7.0.0; + MARKETING_VERSION = 7.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.iHTCboy.iWuBi; PRODUCT_NAME = iWuBi; SUPPORTS_MACCATALYST = YES; @@ -1447,7 +1465,7 @@ CODE_SIGN_ENTITLEMENTS = iWuBi/iWuBi.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2023.01.24; + CURRENT_PROJECT_VERSION = 2023.01.27; DEVELOPMENT_TEAM = 28PV6G96R7; INFOPLIST_FILE = "$(SRCROOT)/iWuBi/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -1456,7 +1474,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 7.0.0; + MARKETING_VERSION = 7.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.iHTCboy.iWuBi; PRODUCT_NAME = iWuBi; SUPPORTS_MACCATALYST = YES; @@ -1593,7 +1611,7 @@ CODE_SIGN_ENTITLEMENTS = iWuBi/iWuBi.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2023.01.24; + CURRENT_PROJECT_VERSION = 2023.01.27; DEVELOPMENT_TEAM = 28PV6G96R7; INFOPLIST_FILE = iWuBi/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -1602,7 +1620,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 7.0.0; + MARKETING_VERSION = 7.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.iHTCboy.iWuBi; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1622,7 +1640,7 @@ CODE_SIGN_ENTITLEMENTS = iWuBi/iWuBi.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2023.01.24; + CURRENT_PROJECT_VERSION = 2023.01.27; DEVELOPMENT_TEAM = 28PV6G96R7; INFOPLIST_FILE = iWuBi/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -1631,7 +1649,7 @@ "@executable_path/Frameworks", ); LIBRARY_SEARCH_PATHS = "$(inherited)"; - MARKETING_VERSION = 7.0.0; + MARKETING_VERSION = 7.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.iHTCboy.iWuBi; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; diff --git a/iWuBi/Common/TCVoiceUtils.swift b/iWuBi/Common/TCVoiceUtils.swift new file mode 100644 index 0000000..70dec1d --- /dev/null +++ b/iWuBi/Common/TCVoiceUtils.swift @@ -0,0 +1,98 @@ +// +// TCVoiceUtils.swift +// iEnglish +// +// Created by HTC on 2023/1/26. +// Copyright © 2023 iHTCboy. All rights reserved. +// + +import Foundation +import AVFoundation + +class TCVoiceUtils: NSObject { + + static let shared = TCVoiceUtils() + // 参数 + static var setupSuccess: Bool = false + static var completion: (() -> Void)? + + // TTS + static var synthesizer: AVSpeechSynthesizer = AVSpeechSynthesizer() + static var utterance:AVSpeechUtterance = AVSpeechUtterance(string: "") + + static func playTTS(text: String, completion: (() -> Void)? = nil) { + + // 设置声音 + if !TCVoiceUtils.setupSuccess { + TCVoiceUtils.setupSuccess = true + TCVoiceUtils.setupVoiceSystem(allowVoice: true) + } + + if synthesizer.isSpeaking { + utterance.volume = 0 + synthesizer.delegate = nil + synthesizer.stopSpeaking(at: AVSpeechBoundary.immediate) + } + + TCVoiceUtils.completion = completion + + synthesizer.delegate = TCVoiceUtils.shared + utterance = AVSpeechUtterance(string: text) + utterance.voice = AVSpeechSynthesisVoice(language:"zh-CN") +// utterance.volume = 1 + utterance.rate = AVSpeechUtteranceDefaultSpeechRate // 范围:0~1 + synthesizer.speak(utterance) + } + + @discardableResult + static func pauseTTS() -> Bool { + return synthesizer.pauseSpeaking(at: AVSpeechBoundary.word) + } + + @discardableResult + static func continueTTS() -> Bool { + return synthesizer.continueSpeaking() + } + + static func stopTTS() { + if synthesizer.isSpeaking { + utterance.volume = 0 + synthesizer.delegate = nil + synthesizer.stopSpeaking(at: AVSpeechBoundary.immediate) + } + } + + static func playSound(audioPath: String, soundId: inout SystemSoundID) { + let fileUrl = URL.init(fileURLWithPath: audioPath) + + AudioServicesCreateSystemSoundID(fileUrl as CFURL, &soundId) + + AudioServicesAddSystemSoundCompletion(soundId, nil, nil, { + (soundID:SystemSoundID, _:UnsafeMutableRawPointer?) in + }, nil) + + AudioServicesPlaySystemSound(soundId) + } + + //设置声音模式(是否设备静音也播放) + /// - Parameter allowVoice: 是否设备静音也播放 + static func setupVoiceSystem(allowVoice: Bool) { + if allowVoice { + let audioSession = AVAudioSession.sharedInstance() + try? audioSession.setCategory(AVAudioSession.Category.playback) + try? audioSession.setActive(true, options: AVAudioSession.SetActiveOptions(rawValue: 0)) + } else { + let audioSession = AVAudioSession.sharedInstance() + try? audioSession.setCategory(AVAudioSession.Category.ambient) + try? audioSession.setActive(true, options: AVAudioSession.SetActiveOptions(rawValue: 0)) + } + } +} + +extension TCVoiceUtils: AVSpeechSynthesizerDelegate { + + func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) { + // 结束播放 + TCVoiceUtils.completion?() + } +} diff --git a/iWuBi/Resource/Images/playvoice@2x.png b/iWuBi/Resource/Images/playvoice@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9447428e460ae4f155f0d9f05b34d09646994ce GIT binary patch literal 10958 zcmY*<1yCJL7A_9CXmEFTC%C)2yE}nPaCf&raCZm85CWcje_cmQped=Rql1$hpQj-CzYu(X{eQwN znOVt&0Hma(0|4IKl5+t_)0$uo6SUfyD zm_0a{on5V2*m!w)SyBADE~oPegDOipeT|0emrJQ9{}=B~CbKwD=g(tmhO z&79qVg5>1?2>rMHd!9gBtN$rEx&5cCzXh`VbA^SCnU&?g+<#LA{)zG_yV_d*RsM%x zh)v*M$p0_)9~}Xff5iWv$^5(0e?|Y6Dg+Q<`R}p`0q~4=;2|Jr{beOYH9R2~a}d8< zYI+?#bhVr;{k)JulZZ@MSwV^>wLycICenw8Wh0*fV#di!#o8CnVina)#1!l zkIouMwjQ>&-tSxT%98xU3|LBr4O}mKeOy`yZBdjabJ-qDJf}&2pQ^*#IGY%^a3lW| zWc>MuEt_wEj!1|R`9923UkdDsEr zlna9j_(%6vojqci%Lmx?`OG=P*Uw^HMz+8a~mghkgdo%==g?e|JyR(~6#g#~5b%^8UlBrTO{b^Uo@ zmPtrYmpe+HuZqY5HDb#NLX&R;+R#3wHU=ploFMFR9I?SyVohaxhCevN1u)FA!fvwv z(8Z4fIX%OHh30I_eiPu7<)toYMA*6^^lx4>h{AVc^T8{bIDbwh-@>Zc@)zZ^v!U-I zR5C&>vJW*ku@Jk8tP$rc zHwYxm)bsd7nXHc;I9vY#VN@|IJ>Xe0lRPt(r1VmGbS)Q#3!@>GZpO?M22CH9a_~DSdf5Kc)gZJYt*Y11ce% zjVP%0Vp9(bMH>H1F4)0Iq@sqEtc`Ce)78H~*f4145lF0D$g}DX4e`0sRuGQg(dLqj zZ50ISVNv0^+fJ0Vn?l&Y=-`UG9jmaa(M4WW+`2<`HMrS62ft&Bd1FGcV>g~O*=S!I z1I4z2Th-aWu1zT>5IU8#K#mbeOC^?%Rko+dmRY0+X(Qk2#Vrs|=>-6EVRSV6JZ4c_ zT)Ik@pfOxmc5!r$uS#1z{rq^lj~71rK6XEal2z8!ABIOtFX(#m zgH5WW1MA+KcA@`>uXCnREmk4tXo5|7m7*90Yk z@5O|wk?~=}4sCNgD9$;>*79{pDbaZD7WikB*Cd87^T^q;mZEijyg*PnFTyX$m$tJgQ|)vfPnXJU)0cvv=JDDzmu zKub-{v1P+-Sq!FZJoa<(8MmEU9ELECr}>UDsp5p7GM^a_&k|WXhmkbs)ANuVt7mAt z_3u(rw&gDcsM}WCP%6un2`x3s5iLHTJ(;%*^%MC&yy!z!ETRqRg!2^QXw&kyH`Y5l z&NeGGbiiaSf=|w*O&o|7N$CD;%PPiebztq;y`S#g8aXp>Qg%nH!2-PE{4;As+zP5C zYt0mm_S#BZ^9-mP--&5;ki?cnU{%=HpXzT{hJo$r!zUSN3$Vw!gVwEZ-Er%zV1mvb zj7Xl&(?Q_XO1flFae;K|tv51mXq4!l?ipAbYDXQa$!k%sE>;Af}< zj$G~;#m#_{Wd)q-mG2jH>4daQ@CFc6MOQbtr1qr@iLW%`k@OO4?X~<~xxK|_HUr92 zrKqN|v9jeb$x>NxjV~&YEXeN54I@63uu1lVQ+J?QB$)WP#yNY!kbWR?ss;w*T79k~ zQRxX2Zdp&)ZVD(ul4^N=bNLMtE3kbNj%Q)Y;dw-fMvx)|bwX=h?%V}W`XE*<&O_|> zREkA00L)KyHr%0hW6PtJ!};c)YOsLN9xaI+Un^e=mH*K98}Ljq8?KA6su?EI0SRX; zPLxA*LTj!8b$;5u1*@W@3G~LXwk?I;f)% z7vY!Wak(XKK+%Tla)d9k|1QH5NI%c1Sxma3T^C`P){rW?4B5wD9HKU|8 zo1({$=X=)*tD{^L_+dGWz69t-qI+VO*fzGk91_JZ(abC{B;JSByy1e4A;lK^I%_SB z*3tOMTCrLNd>5t@rTeLIrU_-UbLZ@7b>Ob#TX$*ck`ia@@vC0(r^sWIj{rD~^NG|S zB_zKGhuMOeXGAN9jO*7Rl)JhSXeQ^J^scYBqk(W?m%3h*s~Z4O#g$@9RBQAeHO$A;u%Oiz!@fIC=XbIT!RW#Kbk^#0x$=JcioJr=iC@2>z z<|?mDG1jq5!X3t$C<8;HM*aS*&nnzBhC_SSoOy*w0|60RM7Fn%==N#R!dJ}@^)U9u zPI@fj>52~l(Xx9141<{Iy~iS7)u9fOp?t_{G5wmO((nL3*>HKAqFtIAaiL%=LL}H= zguuH&9=Vn4RLWs?CUYlPMq^ZFTB}LPKJhu@?A^F12ZH1PLvWqe{elLUHx>>@@Toom z)0c|mvf#xg9IM6}8})HhkBVA4fbl$V`7SV^qccWSF z83m)`7n+L1K|HGP(zCLi=ri%aM>0OYn37MMj4)oQ)?PT!i^|L}@Pt`rR90r%_0{Hj zubqGCZ5>ObiH;y9JxuNf%c(OYek+-Aj}LsSZw)Z4`^L>zKxA~snD!vlTV~z0*Lh1Y z3A&}i@82Vm>U9DaQY#gUyp#3Y5MPv8*7HOkC=$bR+`P66=vshSF51 z+;$=2I5D8Dj2P)UKRgsKv0-hw*Jz2AFaf2`bqKS&gNB@6ezj_vU@! zAsWG*Yzq7s90TEEYjfS^>;K+|#n_S!zkN70EdwK*ih2w@Z(Jv7_LnS;&G z>YMt0|2%T|`B4ziyND=da{Wq+>#MFstAr7Lva=WpZExWcF@X4aDSTK>Xw->E{`O&ja)dOmIbI{#9{JA_1fe^YY#& z14QN?lGkLmQMaKVuu}UBCNm7a8-OmL>M%D}^<<+F#PCRUz*aHA_N9Ltu-IL{x$OgOxWgWKQ!8L=T= zth`u3^|S?Eq41SA?s^(6Q+19ur`VKQs~T3E^}6G8p3$|tyecBGk?Dw88H?!X;u6#` zT@xvcDXyy3{n_iNwjReuhiqWg_b5-Rv{N-fYn{y5Z^%?R@xKeHw82D3AZvqnT<ly}IbJzavSM;yNR>(Ps6qVxc8)VV_?)+U9 zc8UrL`P$&L^JP1tShief^^eGXp-)Z6z7Cm5?MB{P_ipoJ(?2ytbU0NJ>)i+T2S#iY zokw7Z3cR(U>GULG_mh|Cdp(l|rHRdBv?XCNo{5%!8SlK9!3mlsi#0q=MLSwk=a_X5 zRhT`WMDX3bR@+&qjwKp<6drfC?>2xUzK)!PwKC5qP^2$3()qLo`XdMC9FyX#+D^BC zPVCoEIf&I20~eTLI<07>$bCQq8Hh}@_CeVi$Q zffUM3k+{)UK$A7a={ut7g79aq{0Qd38{OoQMTB-;{QV_NO~6U*ECrAq$*0Gl<{TYs z9Vy1L;GNZNkN#(zN_At?5*%P>m4C^yil(a224{Qd5p#)(Gx}l9&4bAfl#i^aJ-JuG zA3isaJi;AUsj_SOE02}M@F1wj!}q5T;b6S9qJ|-bE2!kircTqS?el$~qo{!rH~Biqz;H4U_@;X18<9%s!>5ojLdyqmB{I|cF}^`D`2i#9ChI-kMDQDj} zMU9OSl0gR-uBo?Vv=*dFDp+@2i3LG_xUUc#r2~P^yU#Ly!Y>uMv+m&h(y5_z>E>MT zEGH&Xy8@#4QQBkjxOaN)Ka^VQGG{v)vzvKTL*cY^x>8^~^4f{$UXnG{&Q*=RD`;Ck z@JzjK6@Y!pJ%4;C%E#J47ZWW;mNv&%g`ircOs`9(k&!{%@!9KgHL;bM2=L?hP7bnF zrJ1A~&~Us3)%_{Rj%z{XbCq3W(~ql~ADfabxu(l#DgKZO+HxRUMiMW%;}7=30H2}d zQtTLLon52-wKP;7iF1(JUcyB)y{!R*C+`*lTW`WjWRhyo1@`fI6xmeUS1wuYK)N`L zTTb83=E|E+KAvxqQ{GD4A`2lk(>(nr6mbneX772<sZikyy=U2-{Cr7FP?s%APGC7=>_%E*stQ_yx7oXsc z#`RiY;2+x36x7u;`;Ms!E^mJQ<9~rT!9Rb%v_Izc8&M zNs>@tgZ9o+$k$xgCiYC9OOGGtN*>lc-aPo$?fo5@P$MW$O}*I+`=poJVCUefq;J!J z+gAe&|1yc|PHon5pe&}rUP`%wW-cSdXKut6sY4ilB(oyV>w*RePw6! z>1sK4*RfdKW<~pu6UT4$OWH58=lJaV-NNo8sQh=59Mo==UBEUOnSgT)>L>9VtAZHMtc5YqWon)B%SB=I$5&$p*HVlD{{~LOSPP3P@;^L{2YNq$Rs2HT_iSgxRlS z$6j*-ws;o{PjfCsgP9Yf)%78&ci;WMzNm7;AFg~DNyBTE(mUrj=rM6zu!@8+Mja&3 zjK9FadO=;6HUgmUxCj!U);@XBI4bLSacvMm!ac3BHtUOO@lK}9C=l-_K;?h-{^b;m zz8P7NK*p_Se||ay)WA1KN;C~7cJ+D&$?$aLYax6OXtl+k8-7%H=FLeB824wph0Kg= zTy^cc`*KXt(VwGWBBE#lyFpO!0%@SuXzAeIbM3l>PRQ02;J-OKbF@lJPn z8XINgGKGt(E&gz1U{TzPRwB893`fnss7>=EeLCVD3u^z~38BJT5*<;COUwnDFj^F{ zXd1fNBZ{{gwo1c68O7_yt6=?V*68BJ*C2oboWx}da4LA1w7s5p=NNwYd(#(bD0Unp z)mX&A|9OJugB$X71mEZPn`nJY%s085uzbEk=gW>g43Hv)vJyBUv|>0I_W?(XE2v_m zZ1=$zpHl+bA8ag z2FBlRFgR7=m2vM@{8pNH5aMY$Qd{4Pht@hskvO)fly~5m+SxFcbq}Wr#mH%X{&HPA zey)vo4MhUc)epz~kkeHa;shLOaX>5Y8f8hQBW-ENTKzNmI!9s4QHdkvsO-n~9sBUB zdj~)SLzmtMloB4Jx^&_fP)KBzs}M=UOQ#WHvQjsi;DEH&MTMBqx0hk!Ny`(ljPu|6Q1iB z-#f&+L4U>;q5_u9I8Lr(@p59sNx|=a@^lx?^YC%%T0CEHwE)Q{zHk_qij~ajBa3=v z<*=``KxyA>QN9iI*iffBl8`JNl9MBtKI$wv2NPL`AzW%_uIw7t6h1<`@taBFa~aBr z2+1N4oAG*W!9}iBDEkfg&9zNMyzw(})J*n{OxDgy87YNmZR1X9M549LYe#CH!oz*J zB<$^-mq8vd^lpgEU1Ib~qo_#G9wsE1nljJtw`>CBhF!vHU%`Vi?AhW;z&y9{d+FZF z#Gs5wOq2NP9U^HZYfP<0l8oNxc5FU}B|$UVs`F5RpEqGhye-30q)oeW2hkX(d~|&e@s=tl(9Da$Q(_boo4WCqX=Q3+?)3 z_t^QZ1&$w{|Cjs%pIu#Dx%)JRL){)*HFM1@II#URCLecc?(>;RY($mgwI`|f_tJN- zZBD`8vX~SQ+nl+$NK^A6r{KBI|ITg{;TTGBd(g$ zakgMFs}!GVlAjV2u zBCmgGGE29l2fNXEvx*Ur({18tvNut5p~(iIUiV z_tN5f0t}Ve_MI&<{RN4pH@!~31(rY5Ou81r9#WG25S`brp?cL2Ij zNk2a~JZ)ID6Xy8PQBSCg8NQqb#tLPn|k0eG-Z+As~Qo3kR8SQ9Ozj6 zA*)Zz<+qcs8{c*==g?caZ!M%m4B#d8(l0!F8ZrEAj#Rv7R63yWEqU z^b}5lRA&h~mw5-9@2t!MAlOya5!AB8o?zod&X_u0#O`w}e^(T{=Pz&b)y{QY zNDKR+fjYOSXRn2ERMz5x^umAh?DG}1Z})()os`c+W-PDv7J&zu?FcElbVBgokV)NM$l%OW zTUuq-Z}l^hd(h?GE{jv!c(Kf0-jVGg)e7N{jsimUF5TG!<4kHoZ_0;>e?Hp_{9zMV zHTE}5c0dL$a6}7LfD!-R&_kH^V{P$?XRixaVqmurmn28rEzcp zZ}rW_L)8a;vK9Tb6>@2w%iYg5yQNfCbmR;P6b96#oPhB@ua#rra1&OGgV$gol1!8vBQc0>wCzkN2LSVPcp=fQ~EuSN+jBgUht0^qe< z9BLEK?@os!WBWGlg-39yt?+yJTw10DNkt7-WWGKYoG5x5pXzE&3XkmTP-P&gWxW@-JCV!&`fL6MnSIegukB{%7b^6DniNM9c zg9Qgv#!wm;y-_M+8=NZ?S09tyW!0epZ+rG{jT~}6i7}(2s>C)VqN2&f>>a2(zbEb7gqC_2loTGbUX`B~$ zJ$2l#dih6o@x)0>4+NILgH1XA9RqluD!zKD1#|JWLhp{@7A>5hY+q7GsQn-LW(E@_ zdMIdZY32-X)cqNRn{{m_+GW-kZ$|ba!X`q8_E;m6(1#@Y*7deH=Rq*r0=!>?m1g7x zv>O&+J_(m2b8PD)1Z&mAe1@2hRM$)N^-AXHE1SKus1bU+6eda!M1Fqifqxvl^Wg}Z zf)bu-an@#$ZN~IVOp$STDiS39#wo;`s)o@GM|NsX*+4D&GG%KkrUMZJX+&SRGr{!* z1;(LNxyUZBB>$>iy+|XGKu3_+`a@I+?EMpb|1h)Sw+x{^vcQmXm=p1paF0@cVk}Wx zE6_W&)($Enlbz1bur6Ni4hy%Rr9&U-aZcy98Dw)#x{-wg(L;k>Ud#~C$k8Qw_}V@3 zPHf>W5@<8d^@}<&egMzoi4gB)2d z{V8$=*3!I}FW`tDsssj}RXnYq;gIx9F0tZkg{^fHYFUteBw+5>TKf`1-9JIX6+h?1I}|ryJ_4+xbiWfxJbK6QV>m-X%w=bOj+f+zS{?P z&7ELS-^x_r69{hC$l!t+buZU^{-_}#;_RYqpUBjt(9K|US>Fk9y+B271!j0LCNnYo zePChd4NHGuP+z)<2IjHx2A)wIi@=&ps3BZ&A@fsZ=aG<@?(NyQAvCKHV&m2|T>?cn zd&+zh7|O6nuC7LZ)HmvX9JrvskH9<&kX%8Y^TZz}Jm$L+t^u7otL;?Escko;iLVnL zF-@ZR>Sw(eNmxuKEPI5^Q`h2tn;Z^M(3ov5Id~BGEEE4Mok8F5NY?_uf0J-3ZmMX4 zWi@QsL(-R3;BdQM0`g(6Nj~O8pq)QhS39_vU!N2_$7<$9t+T#Nm@Wpu3?TZCB8!x* zV&jvz7Lk?)9@*IqQw?@dqwv#za$Cf&2pEl1EZ@)(>o4COuKUit-@l45O5hofOj$GS z5%mZ~;u<43UUPYg#B=BZDI~Oi_zMcy`b=J&TUAmEpeJ$7T9`_3ukNn8n%WbY62Lw; ztEQ4qqd^zj|1e!1Qx}lTZd37z_3<5NO}_^Anc|}~R!SH4oom}v*E*t<1YG#iZ?y6B zi^W~mJCy6h9PGZ=gf0Bw=j7$O0&&(%7tQ3I&n4-AL^r2)pc<{X7H-#AI=}gi&+Ne3 z_^0GB4!n;0j;ojfXY*%o)N@+N@jiR=8_w}~W-=z%VDhSSfky;X8y$~$-IXd?gWF&e zor*-9ps<9GLEf1!QXZFV%2GI0i8mj1QLVgYHhfdv{sNOzvc-3pb9|6K{!I)^z?wDD zFAl!4Ld8bTR7MG5!iQe4BsT_yETS1t$-M4%yV=D2PSht)Ppr2njL}2BQ%j2OYvr03 z*}!BQ2HW-?x$5!DdO`Kzx}3^C*g#Cw1j;EgB>4x_)~`7Xc2Y&X!c?15+}T~S7e#(9 z)W2KekM68V#~=?I?4!E{V>(2f-6Eu9`kLTFSQd! zd52N;<1}5CR9kyjlB|G`wKmvb?JvO-r_Zn7vj}J819S5taJ8&Wa@0ib4LK#HNL)cO zx?LtGT}`1You2BRMsf|-1#ShbG5$Q^FitwC>0YrzFiDK43qq57zP8oVW);8jAyqfs z#2tbjsg{`4>>SmSOInoN+G=rR0u@^yTWP<>Ef)eB3nA|-=r22HlcqZi68j&eK*%@T zQertGBm^;k%9iWf`g`jwRg_nx{_rlg9Ttu}nKcO@3pQe31)zNONAwf;6Omo0lGh=K zg($22CiQiw;nxZN2|n_Z4G$x?IQnu9-TE8ikcVJb$7GFKZifo@gnr<1GR2wbSNJ9f zfV4^fjKM2bj-gT5tttmGv?+}mztZ7Q3d9v|O~NqPriLPTA|QVD0RHHGtGA6F+wnPX z+YdG9;_$gv=4tYABf9vb+z2r)=EKPL>dlq^$y3G Void)? + override func awakeFromNib() { super.awakeFromNib() // Initialization code @@ -34,4 +35,7 @@ class ITListTitleViewCell: UITableViewCell { // Configure the view for the selected state } + @IBAction func clickedVoiceButton(_ sender: UIButton) { + voiceCallback?() + } } diff --git a/iWuBi/View/ITListTitleViewCell.xib b/iWuBi/View/ITListTitleViewCell.xib index 3e711c2..d7c2a08 100644 --- a/iWuBi/View/ITListTitleViewCell.xib +++ b/iWuBi/View/ITListTitleViewCell.xib @@ -1,9 +1,10 @@ - + - + + @@ -13,11 +14,11 @@ - + - + @@ -92,14 +93,32 @@ - - + + + - + @@ -107,6 +126,7 @@ + @@ -122,11 +142,12 @@ + - + @@ -140,5 +161,15 @@ + + + + + + + + + + diff --git a/iWuBi/ViewController/Base.lproj/IHTCSearchViewController.xib b/iWuBi/ViewController/Base.lproj/IHTCSearchViewController.xib index 33297b5..c372688 100644 --- a/iWuBi/ViewController/Base.lproj/IHTCSearchViewController.xib +++ b/iWuBi/ViewController/Base.lproj/IHTCSearchViewController.xib @@ -1,9 +1,9 @@ - + - + @@ -11,7 +11,6 @@ - @@ -24,23 +23,15 @@ - + - - - - - - - - - - - - - - + + + + + + @@ -59,17 +50,18 @@ - + - + + @@ -85,7 +77,6 @@ - diff --git a/iWuBi/ViewController/IHTCMeViewController.swift b/iWuBi/ViewController/IHTCMeViewController.swift index bdfee8d..a1c8060 100644 --- a/iWuBi/ViewController/IHTCMeViewController.swift +++ b/iWuBi/ViewController/IHTCMeViewController.swift @@ -44,7 +44,7 @@ class IHTCMeViewController: UIViewController { return tableView }() - fileprivate var titles = ["0": "收藏夹:收藏的字,五笔版本:86版或98版,主题外观:暗黑or浅色,切换App图标:选择你的最爱", "1": "应用内评分:欢迎给\(kAppName)打评分!,AppStore评价:欢迎给\(kAppName)写评论!,分享给朋友:与身边的好友一起学习!", + fileprivate var titles = ["0": "收藏夹:收藏的字,五笔版本:86版或98版,主题外观:暗黑or浅色,切换App图标:选择你的最爱", "1": "应用内评分:欢迎给\(kAppName)打评分!,AppStore评价:欢迎给\(kAppName)写评论!,分享给朋友:与身边的好友一起学习!,文字转语音:TTS (Text-To-Speech)", "2":"意见反馈:欢迎到AppStore提需求或bug问题,邮件联系:如有问题欢迎来信,隐私条款:用户使用服务协议,开源地址:现已开源代码,欢迎关注,更多关注:欢迎访问作者博客,更多应用:更多开发者内容推荐,关于应用:\(kAppName)"] as [String : String] } @@ -54,7 +54,7 @@ extension IHTCMeViewController { func setupUI() { #if targetEnvironment(macCatalyst) - titles = ["0": "收藏夹:收藏的字,五笔版本:86版或98版,主题外观:暗黑or浅色", "1": "应用内评分:欢迎给\(kAppName)打评分!,AppStore评价:欢迎给\(kAppName)写评论!,分享给朋友:与身边的好友一起学习!", + titles = ["0": "收藏夹:收藏的字,五笔版本:86版或98版,主题外观:暗黑or浅色", "1": "应用内评分:欢迎给\(kAppName)打评分!,AppStore评价:欢迎给\(kAppName)写评论!,分享给朋友:与身边的好友一起学习!,文字转语音:TTS (Text-To-Speech)", "2":"意见反馈:欢迎到AppStore提需求或bug问题,邮件联系:如有问题欢迎来信,隐私条款:用户使用服务协议,开源地址:现已开源代码,欢迎关注,更多关注:欢迎访问作者博客,更多学习:更多开发者内容推荐,关于应用:\(kAppName)"] as [String : String] #endif @@ -285,7 +285,11 @@ extension IHTCMeViewController : UITableViewDelegate, UITableViewDataSource popup.present(from: CGRect.init(x: self.view.frame.width-44, y: 64, width: 0, height: 0), in: self.view, permittedArrowDirections: .any, animated: true) } } - + if row == 3 { + let vc = IHTCTTSViewController() + vc.hidesBottomBarWhenPushed = true + self.navigationController?.pushViewController(vc, animated: true) + } break case 2: if row == 0 { diff --git a/iWuBi/ViewController/IHTCSearchDetailVC.swift b/iWuBi/ViewController/IHTCSearchDetailVC.swift index 0c5454a..63234dc 100644 --- a/iWuBi/ViewController/IHTCSearchDetailVC.swift +++ b/iWuBi/ViewController/IHTCSearchDetailVC.swift @@ -34,6 +34,10 @@ class IHTCSearchDetailVC: UIViewController { // Dispose of any resources that can be recreated. } + deinit { + TCVoiceUtils.stopTTS() + } + var selectedCell: ITListTitleViewCell! var is86Word: Bool = true var questionModle : Dictionary? @@ -236,7 +240,8 @@ extension IHTCSearchDetailVC : UITableViewDelegate, UITableViewDataSource { let question = questionModle! - cell.wordLbl.text = question["word"] as? String + let word = question["word"] as? String ?? "" + cell.wordLbl.text = word let codeArray = question["codes"] as? Array ?? Array() @@ -258,6 +263,11 @@ extension IHTCSearchDetailVC : UITableViewDelegate, UITableViewDataSource { cell.versionLbl.text = " 98版 " } + // 播放声音 + cell.voiceCallback = { + TCVoiceUtils.playTTS(text: word) + } + self.selectedCell = cell; return cell } diff --git a/iWuBi/ViewController/IHTCSearchViewController.swift b/iWuBi/ViewController/IHTCSearchViewController.swift index 381cfb7..83658d5 100644 --- a/iWuBi/ViewController/IHTCSearchViewController.swift +++ b/iWuBi/ViewController/IHTCSearchViewController.swift @@ -131,6 +131,105 @@ extension IHTCSearchViewController { } else { model = IHTCModel.shared.search98Dict } + // 词组 + switch words.count { + case 1: + var dict = ["word": String.init(words), "codes": Array()] as [String : Any] + if let dic = model[String.init(words)] { + dict = dic + } + self.searchArray.append(dict) + break + case 2: + let w1 = String.init(words.first!) + let w2 = String.init(words.last!) + var code = "" + if let dic1 = model[String.init(w1)] { + let codes1 = dic1["codes"] as! Array + code += codes1.last!.prefix(2) + } else { + code += "ZZ" + } + + if let dic2 = model[String.init(w2)] { + let codes2 = dic2["codes"] as! Array + code += codes2.last!.prefix(2) + } else { + code += "ZZ" + } + + let dict = ["word": String.init(words), "codes": [code]] as [String : Any] + self.searchArray.append(dict) + break + case 3: + let w1 = words.subString(from: 0, to: 1) + let w2 = words.subString(from: 1, to: 2) + let w3 = words.subString(from: 2, to: 3) + var code = "" + if let dic1 = model[String.init(w1)] { + let codes1 = dic1["codes"] as! Array + code += codes1.last!.prefix(1) + } else { + code += "Z" + } + + if let dic2 = model[String.init(w2)] { + let codes2 = dic2["codes"] as! Array + code += codes2.last!.prefix(1) + } else { + code += "Z" + } + + if let dic3 = model[String.init(w3)] { + let codes3 = dic3["codes"] as! Array + code += codes3.last!.prefix(2) + } else { + code += "ZZ" + } + + let dict = ["word": String.init(words), "codes": [code]] as [String : Any] + self.searchArray.append(dict) + break + default: + let w1 = words.subString(from: 0, to: 1) + let w2 = words.subString(from: 1, to: 2) + let w3 = words.subString(from: 2, to: 3) + let w4 = words.subString(from: words.count-1, to: words.count) + var code = "" + if let dic1 = model[String.init(w1)] { + let codes1 = dic1["codes"] as! Array + code += codes1.last!.prefix(1) + } else { + code += "Z" + } + + if let dic2 = model[String.init(w2)] { + let codes2 = dic2["codes"] as! Array + code += codes2.last!.prefix(1) + } else { + code += "Z" + } + + if let dic3 = model[String.init(w3)] { + let codes3 = dic3["codes"] as! Array + code += codes3.last!.prefix(1) + } else { + code += "Z" + } + + if let dic4 = model[String.init(w4)] { + let codes4 = dic4["codes"] as! Array + code += codes4.last!.prefix(1) + } else { + code += "Z" + } + + let dict = ["word": String.init(words), "codes": [code]] as [String : Any] + self.searchArray.append(dict) + break + } + + // 单字 for word in words { var dict = ["word": String.init(word), "codes": Array()] as [String : Any] if let dic = model[String.init(word)] { @@ -295,7 +394,7 @@ extension IHTCSearchViewController : UITableViewDelegate, UITableViewDataSource func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - if isSingleWord { + if isSingleWord && indexPath.row != 0 { let cell: ITQuestionListViewCell = tableView.dequeueReusableCell(withIdentifier: "ITQuestionListViewCell") as! ITQuestionListViewCell cell.accessoryType = .disclosureIndicator diff --git a/iWuBi/ViewController/IHTCTTSViewController.swift b/iWuBi/ViewController/IHTCTTSViewController.swift new file mode 100644 index 0000000..697b0f5 --- /dev/null +++ b/iWuBi/ViewController/IHTCTTSViewController.swift @@ -0,0 +1,110 @@ +// +// IHTCTTSViewController.swift +// iWuBi +// +// Created by HTC on 2023/1/27. +// Copyright © 2023 HTC. All rights reserved. +// + +import UIKit + +class IHTCTTSViewController: UIViewController { + + + lazy var playItem: UIBarButtonItem = { + let item = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.play, target: self, action: #selector(playPlaylist)) + return item + }() + + lazy var stopItem: UIBarButtonItem = { + let item = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.stop, target: self, action: #selector(stopPlaylist)) + return item + }() + + lazy var pauseItem: UIBarButtonItem = { + let item = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.pause, target: self, action: #selector(pausePlaylist)) + return item + }() + + lazy var textView: UITextView = { + let text = UITextView() + text.delegate = self + text.isEditable = true + text.alwaysBounceVertical = true + text.font = UIFont.systemFont(ofSize: 20) + text.translatesAutoresizingMaskIntoConstraints = false + if #available(iOS 13.0, *) { + text.backgroundColor = .secondarySystemGroupedBackground + } + return text + }() + + override func viewDidLoad() { + super.viewDidLoad() + self.title = "文字转语音(TTS)" + self.navigationItem.rightBarButtonItem = playItem + if #available(iOS 13.0, *) { + view.backgroundColor = .secondarySystemGroupedBackground + } + + view.addSubview(textView) + let constraintViews = [ + "textView": textView + ] + let vFormat = "V:|-0-[textView]-0-|" + let hFormat = "H:|-5-[textView]-5-|" + let vConstraints = NSLayoutConstraint.constraints(withVisualFormat: vFormat, options: [], metrics: [:], views: constraintViews) + let hConstraints = NSLayoutConstraint.constraints(withVisualFormat: hFormat, options: [], metrics: [:], views: constraintViews) + view.addConstraints(vConstraints) + view.addConstraints(hConstraints) + view.layoutIfNeeded() + + textView.becomeFirstResponder() + } + + deinit { + TCVoiceUtils.stopTTS() + } + +} + +// 播放列表操作 +extension IHTCTTSViewController { + + @objc + func playPlaylist() { + let words = textView.text ?? "" + guard !words.isEmpty else { + return + } + TCVoiceUtils.playTTS(text: words) { [weak self] in + self?.navigationItem.rightBarButtonItem = self?.playItem + } + self.navigationItem.rightBarButtonItem = stopItem + } + + @objc + func stopPlaylist() { + if TCVoiceUtils.pauseTTS() { + self.navigationItem.rightBarButtonItem = pauseItem + } else { + self.navigationItem.rightBarButtonItem = playItem + } + } + + @objc + func pausePlaylist() { + if TCVoiceUtils.continueTTS() { + self.navigationItem.rightBarButtonItem = stopItem + } else { + self.navigationItem.rightBarButtonItem = playItem + } + } +} + +extension IHTCTTSViewController: UITextViewDelegate { + + func scrollViewDidScroll(_ scrollView: UIScrollView) { + UIApplication.shared.keyWindow?.endEditing(true) + } +} diff --git a/iWuBi/ViewController/IHTCWordDetailViewController.swift b/iWuBi/ViewController/IHTCWordDetailViewController.swift index 13d5dfa..25a1fb3 100644 --- a/iWuBi/ViewController/IHTCWordDetailViewController.swift +++ b/iWuBi/ViewController/IHTCWordDetailViewController.swift @@ -202,7 +202,8 @@ extension IHTCWordDetailViewController : UITableViewDelegate, UITableViewDataSou let question = questionModle! - cell.wordLbl.text = question["word"] as? String + let word = question["word"] as? String ?? "" + cell.wordLbl.text = word let codeArray = question["codes"] as? Array ?? Array() @@ -224,6 +225,11 @@ extension IHTCWordDetailViewController : UITableViewDelegate, UITableViewDataSou cell.versionLbl.text = " 98版 " } + // 播放声音 + cell.voiceCallback = { + TCVoiceUtils.playTTS(text: word) + } + self.selectedCell = cell; return cell } diff --git a/iWuBi/en.lproj/InfoPlist.strings b/iWuBi/en.lproj/InfoPlist.strings index fbeba9d..24fbf5a 100644 --- a/iWuBi/en.lproj/InfoPlist.strings +++ b/iWuBi/en.lproj/InfoPlist.strings @@ -6,6 +6,7 @@ Copyright © 2019 HTC. All rights reserved. */ -CFBundleDisplayName = "iWuBi"; +"CFBundleName" = "iWuBi"; +"CFBundleDisplayName" = "iWuBi"; "NSPhotoLibraryUsageDescription" = "Request access to the album, in order to save App Screenshots"; "NSPhotoLibraryAddUsageDescription" = "Request access to the album, in order to save App Screenshots"; diff --git a/iWuBi/zh-Hans.lproj/InfoPlist.strings b/iWuBi/zh-Hans.lproj/InfoPlist.strings index 946aba0..b6204f5 100644 --- a/iWuBi/zh-Hans.lproj/InfoPlist.strings +++ b/iWuBi/zh-Hans.lproj/InfoPlist.strings @@ -6,6 +6,7 @@ Copyright © 2019 HTC. All rights reserved. */ -CFBundleDisplayName = "爱五笔"; +"CFBundleName" = "爱五笔"; +"CFBundleDisplayName" = "爱五笔"; "NSPhotoLibraryUsageDescription" = "请求访问相册,以便保存App截图"; "NSPhotoLibraryAddUsageDescription" = "请求访问相册,以便保存App截图"; diff --git a/iWuBi/zh-Hant.lproj/InfoPlist.strings b/iWuBi/zh-Hant.lproj/InfoPlist.strings index e2937b5..b7a5a8b 100644 --- a/iWuBi/zh-Hant.lproj/InfoPlist.strings +++ b/iWuBi/zh-Hant.lproj/InfoPlist.strings @@ -6,6 +6,7 @@ Copyright © 2019 HTC. All rights reserved. */ -CFBundleDisplayName = "愛五筆"; +"CFBundleName" = "愛五筆"; +"CFBundleDisplayName" = "愛五筆"; "NSPhotoLibraryUsageDescription" = "請求訪問相冊,以便保存App截圖"; "NSPhotoLibraryAddUsageDescription" = "請求訪問相冊,以便保存App截圖";