Commit 763e6cee authored by yqz's avatar yqz

学英语

parent 29992f2f
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "image@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -9,7 +9,7 @@
"scale" : "2x"
},
{
"filename" : "dengluye@3x.png",
"filename" : "Log_in_bg@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "10000h+@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Welcome to SpeakEasy Learning@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_send_off@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -5,12 +5,11 @@
"scale" : "1x"
},
{
"filename" : "Send@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Send@3x.png",
"filename" : "icon_send_on@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
......
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "bg_blue_home@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_guide_on@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_guide_on@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_no@3x(1).png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_no@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -5,7 +5,6 @@
"scale" : "1x"
},
{
"filename" : "Google@2x 1@2x(1).png",
"idiom" : "universal",
"scale" : "2x"
},
......
......@@ -18,7 +18,7 @@ extension AppDelegate {
_ = SpeakCache.cache
SpeakDayEveryManager.manager.loadData(Date().toStr() ?? "")
_ = SpeakLeassonData.data.leassionData
// _ = SpeakVideoPlayer.share
SpeakAIVideoPlayManager.share.loadVideo()
IAPViewModel.share.fetchProducts { product in // 初始化内购
Print("内购列表\(product?.count ?? 0)")
}
......
......@@ -89,7 +89,7 @@ func copyMatchingProperties<T, U>(from source: T, to destination: inout U) {
}
func updateUserInformation() -> Void {
func updateUserInformation(_ complate:((Bool)->Void)? = nil) -> Void {
if SpeakElePublicManager.share.userInfo.isLogin() {
let name = SpeakElePublicManager.share.userInfo.userName ?? ""
let lanaguage = SpeakElePublicManager.share.userInfo.nativeLanguage ?? ""
......@@ -104,7 +104,7 @@ func updateUserInformation() -> Void {
"targetLevel": level,
"targetLanguage":en
]) { su in
complate?(su)
}
}
}
......
......@@ -37,6 +37,13 @@ extension UIColor {
public func generate(_ size:CGSize = CGSize(width: 1, height: 1),
_ cornerRadius:CGFloat = 0) -> UIImage? {
var size = size;
if size.width <= 0 {
size.width = 1
}
if size.height <= 0 {
size.height = 1
}
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
......
......@@ -51,6 +51,12 @@ class SpeakEleHomeViewCtr: SpeakEleBaseViewCtr, UIPopoverPresentationControllerD
SpeakElePublicManager.share.userInfo.targetLanguage = "🇪🇸 Español"
self?.SpeakEnglistShow.setImage(UIImage(named: "sp-home-Es"), for: .normal)
}
updateUserInformation {[weak self] su in
if su {
self?.viewModel.fetchSesson()
self?.viewModel.fetchUserInfo()
}
}
}
}
return tip
......@@ -101,7 +107,7 @@ class SpeakEleHomeViewCtr: SpeakEleBaseViewCtr, UIPopoverPresentationControllerD
/// 改变学习的语言
@IBAction func SpeakChangeLangu(_ sender: Any) {
if !IAPViewModel.share.isSubscribed {
if IAPViewModel.share.isSubscribed {
self.view.bringSubviewToFront(tipView)
tipView.selectIdx = SpeakElePublicManager.share.userInfo.targetLanguage == "🇬🇧 English" ? 0 : 1
tipView.show()
......@@ -146,7 +152,6 @@ class SpeakEleHomeViewCtr: SpeakEleBaseViewCtr, UIPopoverPresentationControllerD
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
SpeakPermission.requestNotificationPermission()
titleView.isHidden = true
setAISer()
viewModel.fetchSesson()
......@@ -156,13 +161,22 @@ class SpeakEleHomeViewCtr: SpeakEleBaseViewCtr, UIPopoverPresentationControllerD
self?.SpeakDataUpdate()
}
}
SpeakAIVideoPlayManager.share.loadVideo()
if SpeakElePublicManager.share.userInfo.targetLanguage == "🇬🇧 English" {
self.SpeakEnglistShow.setImage(UIImage(named: "sp-home-En"), for: .normal)
}else{
self.SpeakEnglistShow.setImage(UIImage(named: "sp-home-Es"), for: .normal)
}
/// 新用户直接进课程
if SpeakElePublicManager.share.userInfo.newUser ?? true {
SpeakElePublicManager.share.userInfo.newUser = false
let vc = SpeakNewUserViewCtr()
vc.isReStart = true
vc.isMute = false
vc.view.callblack = { [weak self] tip in
self?.TipsSign(tip as? Bool ?? false)
}
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
......@@ -173,14 +187,15 @@ extension SpeakEleHomeViewCtr {
for (v) in self.lessonDataSource {
if v.isLocked == false {
lessonId = v.lessonId ?? 0
}else{
break
}
}
for (i,v) in lessonViews.enumerated() {
let data = lessonDataSource[safe: i]
v.data = data
v.SpeakLessionStart.isHidden = !(data?.lessonId == lessonId)
if data?.lessonId == lessonId {
offsetY = v.y - 70.0
}
}
}
......@@ -293,8 +308,6 @@ extension SpeakEleHomeViewCtr {
for (v) in self.lessonDataSource {
if v.isLocked == false {
lessonId = v.lessonId ?? 0
}else{
break
}
}
for i in 1...6 {
......
......@@ -126,8 +126,11 @@
</userDefinedRuntimeAttributes>
</view>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="REb-HE-Vml">
<rect key="frame" x="24" y="119" width="345" height="79"/>
<rect key="frame" x="24" y="103" width="345" height="79"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_bg_blue_home" translatesAutoresizingMaskIntoConstraints="NO" id="7aS-Wk-Ktd">
<rect key="frame" x="0.0" y="0.0" width="345" height="79"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-home-headerivar" translatesAutoresizingMaskIntoConstraints="NO" id="pAk-N9-Dv6">
<rect key="frame" x="16" y="16" width="48" height="48"/>
<constraints>
......@@ -147,7 +150,7 @@
</userDefinedRuntimeAttributes>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="245" verticalHuggingPriority="245" horizontalCompressionResistancePriority="745" verticalCompressionResistancePriority="745" axis="vertical" alignment="top" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="EgX-1V-LiS">
<rect key="frame" x="80" y="15.666666666666657" width="126" height="49"/>
<rect key="frame" x="80" y="15.666666666666671" width="126" height="49"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Amelia" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GO5-4q-Wtk">
<rect key="frame" x="0.0" y="0.0" width="59.333333333333336" height="24"/>
......@@ -156,7 +159,7 @@
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Lde-SU-5MS">
<rect key="frame" x="0.0" y="29" width="126" height="20"/>
<rect key="frame" x="0.0" y="28.999999999999986" width="126" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="iK8-oc-A1D"/>
</constraints>
......@@ -181,7 +184,7 @@
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="255" verticalHuggingPriority="255" horizontalCompressionResistancePriority="755" verticalCompressionResistancePriority="755" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="tji-S9-nFP">
<rect key="frame" x="240" y="23.666666666666657" width="87" height="32"/>
<rect key="frame" x="240" y="23.666666666666671" width="87" height="32"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="87" id="ayL-fl-zR2"/>
......@@ -200,15 +203,19 @@
</userDefinedRuntimeAttributes>
</button>
</subviews>
<color key="backgroundColor" red="0.22352941176470587" green="0.50196078431372548" blue="0.96470588235294119" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="tji-S9-nFP" secondAttribute="trailing" constant="18" id="12u-v5-UR0"/>
<constraint firstItem="pAk-N9-Dv6" firstAttribute="top" secondItem="REb-HE-Vml" secondAttribute="top" constant="16" id="3rQ-4P-EMq"/>
<constraint firstItem="tji-S9-nFP" firstAttribute="centerY" secondItem="REb-HE-Vml" secondAttribute="centerY" id="Al5-9M-UVy"/>
<constraint firstAttribute="bottom" secondItem="7aS-Wk-Ktd" secondAttribute="bottom" id="KMU-9T-dgH"/>
<constraint firstItem="EgX-1V-LiS" firstAttribute="centerY" secondItem="pAk-N9-Dv6" secondAttribute="centerY" id="MOK-MF-8ZK"/>
<constraint firstItem="EgX-1V-LiS" firstAttribute="leading" secondItem="pAk-N9-Dv6" secondAttribute="trailing" constant="16" id="Ndk-uL-Uhq"/>
<constraint firstItem="pAk-N9-Dv6" firstAttribute="leading" secondItem="REb-HE-Vml" secondAttribute="leading" constant="16" id="OLG-nC-Uwh"/>
<constraint firstItem="7aS-Wk-Ktd" firstAttribute="top" secondItem="REb-HE-Vml" secondAttribute="top" id="PFT-M8-wBt"/>
<constraint firstAttribute="trailing" secondItem="7aS-Wk-Ktd" secondAttribute="trailing" id="TzI-w3-0wo"/>
<constraint firstAttribute="bottom" secondItem="pAk-N9-Dv6" secondAttribute="bottom" constant="15" id="ha2-7J-HlX"/>
<constraint firstItem="7aS-Wk-Ktd" firstAttribute="leading" secondItem="REb-HE-Vml" secondAttribute="leading" id="oPp-t1-H2p"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="corners">
......@@ -221,7 +228,7 @@
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="REb-HE-Vml" firstAttribute="leading" secondItem="rqH-oW-agY" secondAttribute="leading" constant="24" id="Cvh-VK-8kb"/>
<constraint firstItem="REb-HE-Vml" firstAttribute="top" secondItem="KYz-Od-c9d" secondAttribute="bottom" constant="26" id="FHQ-WP-3fM"/>
<constraint firstItem="REb-HE-Vml" firstAttribute="top" secondItem="KYz-Od-c9d" secondAttribute="bottom" constant="10" id="FHQ-WP-3fM"/>
<constraint firstItem="KYz-Od-c9d" firstAttribute="top" secondItem="Ia2-3z-Nib" secondAttribute="top" constant="61" id="ISI-vx-5CZ"/>
<constraint firstAttribute="trailing" secondItem="KYz-Od-c9d" secondAttribute="trailing" constant="24" id="KEg-YG-8N8"/>
<constraint firstItem="KYz-Od-c9d" firstAttribute="leading" secondItem="Ia2-3z-Nib" secondAttribute="leading" constant="24" id="Kv8-Bt-b6l"/>
......@@ -231,6 +238,7 @@
</view>
</objects>
<resources>
<image name="icon_bg_blue_home" width="354" height="82"/>
<image name="sp-home-En" width="28" height="28"/>
<image name="sp-home-book" width="20.333333969116211" height="20"/>
<image name="sp-home-clock" width="20" height="20"/>
......
......@@ -77,6 +77,7 @@ class SpeakChangeStuLanguesView: UIView {
@IBAction func TOIjkjdklsf(_ sender: UIButton) {
if !sender.isSelected {
SpeakCache.cache.SaveModel(cache: SpeakPracticeLesLocalModel(lesson: [] ,select: 0), state: .PracticeCache, name: "Lesson")
if let call = callblack {
call( sender == SpeakChangeBtns.first ? 0 : 1)
}
......
......@@ -82,8 +82,8 @@ class SpeakEleLessionView: UIView {
}
private func setupUI() {
private func setupUI() {
self.addSubview(backView)
backView.addSubview(button)
self.addSubview(nameLb)
......@@ -103,7 +103,7 @@ class SpeakEleLessionView: UIView {
}
SpeakLessionStart.snp.makeConstraints { make in
make.bottom.equalTo(self.snp.top)
make.bottom.equalTo(self.button.snp.top).offset(5.adapterH())
make.centerX.equalToSuperview()
}
......
......@@ -15,7 +15,7 @@ class SpeakElePracticeReviewViewCtr: SpeakEleBaseViewCtr {
@IBOutlet var SpeakItemBtns: [UIButton]!
private let viewModel = SpeakPracticeNetViewModel()
private let collectViewModel = SpeakEleProfileNetViewModel()
private var startStudyT:Date = Date()
@IBOutlet weak var SpeakTipsRight: UIView!
@IBOutlet weak var SpeakTipsLeft: UIView!
......@@ -52,6 +52,17 @@ class SpeakElePracticeReviewViewCtr: SpeakEleBaseViewCtr {
UserDefaults.standard.setValue(true, forKey: UnsafeRawUserDefaultsKey.UnsafePracticeTipsShow.rawValue)
}
}
override func PopViewCtr() {
let name = SpeakElePublicManager.share.userInfo.targetLanguage ?? ""
let saveData = self.datasource.map { bt in
var temp = bt
temp.isFront = nil
return temp
}
SpeakCache.cache.SaveModel(cache: saveData, state: .PracticeCache, name: name)
super.PopViewCtr()
}
@objc private func tipsHide(_ res:UIGestureRecognizer) -> Void {
let view = res.view
......@@ -127,6 +138,17 @@ class SpeakElePracticeReviewViewCtr: SpeakEleBaseViewCtr {
extension SpeakElePracticeReviewViewCtr : UICollectionViewDelegate,UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
private func setFavaret(_ fw:Bool , indexPath:IndexPath) -> Void {
let d = self.datasource[indexPath.row].wordId
collectViewModel.collect(param: ["businessId":d,
"type":2,
"isCollect":fw]) {[weak self] su, data in
self?.datasource[indexPath.row].isCollected = su ? fw : !fw
let cell = self?.SpeakCollectionV.cellForItem(at: indexPath) as? SpeakPracticeReviewCell
cell?.data = self?.datasource[indexPath.row]
}
}
private func StrangeFamilar(state:SpeakPracticeReviewCell.SpeakPracticeReviewState) -> Void {
let cell = SpeakCollectionV.cellForItem(at: IndexPath(row: currentIdx, section: 0))
......@@ -199,7 +221,7 @@ extension SpeakElePracticeReviewViewCtr : UICollectionViewDelegate,UICollectionV
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SpeakPracticeReviewCell.id, for: indexPath) as! SpeakPracticeReviewCell
cell.isHidden = (indexPath.row < currentIdx ? true : false)
cell.data = datasource[indexPath.row]
cell.clipsToBounds = true
// cell.clipsToBounds = true
cell.SpeakCallblack = { [weak self] state in
self?.StrangeFamilar(state: state)
}
......@@ -214,6 +236,8 @@ extension SpeakElePracticeReviewViewCtr : UICollectionViewDelegate,UICollectionV
}else{
self?.SpeakItemBtns.forEach({$0.isSelected = false})
}
}else if let fav = state as? Bool {
self?.setFavaret( fav,indexPath: indexPath)
}
}
return cell
......
......@@ -19,6 +19,7 @@ class SpeakElePracticeViewCtr: SpeakEleBaseViewCtr {
/// 课程
private var Session:[SpeakPracticeLessonModel] = []
private var currentLess:SpeakPracticeLessonModel?
private var selectIdx:Int = -1
override func viewDidLoad() {
super.viewDidLoad()
......@@ -41,6 +42,12 @@ class SpeakElePracticeViewCtr: SpeakEleBaseViewCtr {
learnedW.view.callblack = { [weak self] data in
if let da = data as? SpeakPracticeLessonModel {
if self?.currentLess?.lessonId != da.lessonId {
for (i,v) in (self?.Session ?? []).enumerated() {
if v.lessonId == da.lessonId {
self?.selectIdx = i
break
}
}
self?.currentLess = da
self?.SpeakselectSession()
}
......@@ -51,7 +58,11 @@ class SpeakElePracticeViewCtr: SpeakEleBaseViewCtr {
@IBAction func SpeakReviewTaps(_ sender: Any) {
if self.currentLess != nil {
let review = SpeakElePracticeReviewViewCtr()
review.datasource = dataSource
review.datasource = dataSource.map({ bd in
var temp = bd
temp.isFront = nil
return temp
})
review.leassion = self.currentLess?.lessonId ?? 0
self.parent?.navigationController?.pushViewController(review, animated: true)
}
......@@ -60,20 +71,33 @@ class SpeakElePracticeViewCtr: SpeakEleBaseViewCtr {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
titleView.isHidden = true
let model:SpeakPracticeLesLocalModel? = SpeakCache.cache.LoadMode(state: .PracticeCache, name: "Lesson")
self.Session = model?.lesson ?? []
self.selectIdx = model?.select ?? 0
if self.selectIdx >= 0 && self.selectIdx < (model?.lesson?.count ?? 0) && (model?.lesson?.count ?? 0) > 0 {
self.currentLess = self.Session[self.selectIdx]
}
let name = SpeakElePublicManager.share.userInfo.targetLanguage ?? ""
let data:[SpeakPracticeWordModel] = SpeakCache.cache.LoadMode(state: .MessageCache, name: name) ?? []
if data.count <= 0 {
let data:[SpeakPracticeWordModel] = SpeakCache.cache.LoadMode(state: .PracticeCache, name: name) ?? []
if self.Session.count <= 0 {
self.getLeasion()
}else{
SpeakSectionL.text = currentLess?.lessonName
if data.count != self.dataSource.count {
self.dataSource = data
setPage(current: 1)
self.SpeakCollection.reloadData()
}else{
for (i,var v) in self.dataSource.enumerated() {
if let cell = SpeakCollection.cellForItem(at: IndexPath(row: i, section: 0)) as? SpeakElePracticeViewCell {
v.isCollected = data[i].isCollected
cell.data = v
}
}
}
}
}
private var dataSource:[SpeakPracticeWordModel] = []
}
extension SpeakElePracticeViewCtr :UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
......@@ -93,7 +117,7 @@ extension SpeakElePracticeViewCtr :UICollectionViewDelegate,UICollectionViewData
viewModel.learnedLesson {[weak self] (success, data:[SpeakPracticeLessonModel]?) in
if success {
self?.Session = data ?? []
self?.currentLess = data?.first
self?.currentLess = data?[safe:self?.selectIdx ?? 0]
self?.SpeakselectSession()
}
}
......@@ -104,10 +128,14 @@ extension SpeakElePracticeViewCtr :UICollectionViewDelegate,UICollectionViewData
viewModel.leassionWord(param: ["lessonId":self.currentLess?.lessonId ?? ""]) {[weak self] (su, data:[SpeakPracticeWordModel]? ) in
if su {
self?.dataSource = data ?? []
let point = self?.SpeakCollection.contentOffset ?? CGPoint()
let name = SpeakElePublicManager.share.userInfo.targetLanguage ?? ""
SpeakCache.cache.SaveModel(cache: self?.dataSource, state: .PracticeCache, name: name)
self?.setPage(current: ( Int(round(point.x/(self?.SpeakCollection.width ?? 1))) + 1) )
let model = SpeakPracticeLesLocalModel(lesson: self?.Session, select: self?.selectIdx)
SpeakCache.cache.SaveModel(cache: model, state: .PracticeCache, name: "Lesson")
self?.setPage(current: 1 )
self?.SpeakCollection.reloadData()
}
}
......@@ -125,10 +153,9 @@ extension SpeakElePracticeViewCtr :UICollectionViewDelegate,UICollectionViewData
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SpeakElePracticeViewCell.id, for: indexPath) as! SpeakElePracticeViewCell
var data = self.dataSource[indexPath.row]
cell.data = data
cell.SpeakPracticeNormal.SpeakPracticeIcon.image = UIImage(named: "sp-Practicebg-\(((data.wordId ?? 0)%14)+1)")
cell.callblack = {[weak self] fw in
if let i = fw as? Int {
data.isFront = (i == 1 ? true : false)
if let i = fw as? String {
data.isFront = (i == "1" ? true : false)
self?.dataSource[indexPath.row] = data
}else{
self?.setFavaret( (fw as? Bool ?? false) ,indexPath: indexPath)
......
......@@ -7,6 +7,12 @@
import UIKit
struct SpeakPracticeLesLocalModel : Codable {
var lesson:[SpeakPracticeLessonModel]?
var select:Int?
}
struct SpeakPracticeLessonModel: Codable {
var lessonId : Int?
var lessonName : String?
......
......@@ -40,6 +40,7 @@ class SpeakElePracticeViewCell: UICollectionViewCell {
}else if !isShow{
self.HideDescp()
}
SpeakPracticeNormal.SpeakPracticeIcon.image = UIImage(named: "sp-Practicebg-\(((data?.wordId ?? 0)%14)+1)")
}
}
......@@ -84,7 +85,6 @@ class SpeakElePracticeViewCell: UICollectionViewCell {
call(fw)
}
}
}
override func layoutSubviews() {
......@@ -107,7 +107,7 @@ class SpeakElePracticeViewCell: UICollectionViewCell {
completion: { [weak self] _ in
self?.isShowingFront.toggle()
guard let call = self?.callblack else { return }
call( (self?.isShowingFront ?? true ? 1 : 0) )
call( (self?.isShowingFront ?? true ? "1" : "0") )
}
)
}
......
......@@ -15,8 +15,14 @@ class SpeakPracticeReviewCell: UICollectionViewCell {
@IBOutlet var SpeakRightTips: UIView!
@IBOutlet weak var SpeakRightLabel: UILabel!
private let viewmodel = SpeakPracticeNetViewModel()
static let id = "SpeakPracticeReviewCell"
private let leftMax:Double = -70
private let rightMax:Double = 70
var isShowingFront = true
var wordDetail:SpeakPracticeWordDetailModel?
enum SpeakPracticeReviewState {
case left
case right
......@@ -26,20 +32,51 @@ class SpeakPracticeReviewCell: UICollectionViewCell {
private var beginP = CGPoint()
var SpeakCallblack: ((_ state:SpeakPracticeReviewState)-> Void)?
private var isShow:Bool{
set {}
get {
return IAPViewModel.share.isSubscribed || SpeakDayEveryManager.manager.SpeakDayData.PracticeFreeNum ?? 0 > 0
}
}
var data:SpeakPracticeWordModel? {
didSet{
isShowingFront = data?.isFront ?? true
UIView.transition(with: isShowingFront ? Word : back , duration: 0, options: [.transitionFlipFromRight]) { }
Word.SpeakPracticeWord.text = data?.word
Word.setLabel(data?.markStatus == 1 ? 1 : (data?.markStatus == 2 ? 2 : 0 ) )
Word.SpeakPracticeIcon.image = UIImage(named: "sp-Practicebg-\(((data?.wordId ?? 0)%14)+1)")
Word.clipsToBounds = true
Word.corners = 16
Word.backgroundColor = .clear
Word.SpeakPracticeFavorites.isSelected = data?.isCollected ?? false
back.SpeakPracticeBackWord.text = data?.word
back.SpeakPracticeBackFavorites.isSelected = data?.isCollected ?? false
Word.isHidden = !isShowingFront
back.isHidden = isShowingFront
back.corners = 16
wordDetail = SpeakWordTranslateData.data.WordTranslate?[data?.wordId ?? 0]
if let translation = wordDetail?.translation {
translationFunc()
}else{
translationHide()
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
self.gesture(target: self, class: UIPanGestureRecognizer.self, selector: #selector(panGesture(_:)))
self.gesture(target: self, class: UITapGestureRecognizer.self, selector: #selector(FlipTaps))
back.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
Word.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
......@@ -53,10 +90,71 @@ class SpeakPracticeReviewCell: UICollectionViewCell {
super.layoutSubviews()
contentView.bringSubviewToFront(SpeakLeftTips)
contentView.bringSubviewToFront(SpeakRightTips)
self.layoutIfNeeded()
back.shadow(cornerRadius: 16, shadowColor: .init(hex: 0x000000), offset: CGSize(width: 0, height: 0), opacity: 0.06, radius: 4)
}
private let leftMax:Double = -70
private let rightMax:Double = 70
private lazy var Word: SpeakPracticeWordView = {
let w = SpeakPracticeWordView()
contentView.addSubview(w)
w.callblack = { [weak self] fw in
if let call = self?.callblack {
call(fw)
}
}
return w
}()
private lazy var back: SpeakPracticeBackView = {
let b = SpeakPracticeBackView.xib()
b.callblack = { [weak self] fw in
if let call = self?.callblack {
call(fw)
}
}
contentView.addSubview(b)
return b
}()
deinit {
SpeakCallblack = nil
}
}
extension SpeakPracticeReviewCell {
private func netwokng() -> Void {
viewmodel.cardTranslate(param: ["word":data?.word ?? ""]) {[weak self] (success, data:SpeakPracticeWordDetailModel?) in
if success {
self?.wordDetail = data
SpeakWordTranslateData.data.WordTranslate?[self?.data?.wordId ?? 0] = data
SpeakDayEveryManager.manager.SpeakDayData.PracticeFreeNum! -= 1
SpeakDayEveryManager.manager.update()
self?.translationHide()
}
}
}
@objc private func FlipTaps() -> Void {
if wordDetail == nil && isShow == true {
self.netwokng()
}else if wordDetail == nil {
self.translationHide()
}
UIView.transition(
from: isShowingFront ? Word : back,
to: isShowingFront ? back : Word,
duration: 12/60.0,
options: [.transitionFlipFromRight, .showHideTransitionViews],
completion: { [weak self] _ in
self?.isShowingFront.toggle()
guard let call = self?.callblack else { return }
// call( (self?.isShowingFront ?? true ? 1 : 0) )
}
)
}
@objc private func panGesture(_ recognizer:UIGestureRecognizer) -> Void {
let p = recognizer.location(in: self)
......@@ -99,13 +197,19 @@ class SpeakPracticeReviewCell: UICollectionViewCell {
}
}
private lazy var Word: SpeakPracticeWordView = {
let w = SpeakPracticeWordView()
contentView.addSubview(w)
return w
}()
deinit {
SpeakCallblack = nil
private func translationFunc() -> Void {
back.SpeakPracticeBackWord1.text = wordDetail?.translation
back.SpeakPracticeBackUnlock.isHidden = true
let anto = "Antonym:".attributed().color(.init(hex: 0x3980F6)).build()
let Example = "Example sentence:".attributed().color(.init(hex: 0x3980F6)).build()
let att = "Synonyms:".attributed().color(.init(hex: 0x3980F6)).build().combined(with: [wordDetail?.synonyms,"\n\n",anto,wordDetail?.antonym,"\n\n" ,Example,wordDetail?.example])
back.SpeakPracticeBackDesc.attributedText = att
}
private func translationHide() -> Void {
back.SpeakPracticeBackWord1.text = wordDetail?.translation
back.SpeakPracticeBackUnlock.isHidden = false
back.SpeakPracticeBackDesc.attributedText = "".attributed().build()
}
}
......@@ -216,7 +216,7 @@ extension SpeakEleProfileViewCtr {
SpeakElePublicManager.share.PublicData.state = .start
let nav = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleLoginGuideCtr())
SpWindow.switchToController(nav)
SpWindow.rootViewController = (nav)
}
}
......@@ -63,7 +63,7 @@ class SpeakProfileMoreViewCtr: SpeakEleBaseViewCtr {
get{
if state == .TargetLanguage {
var iap = ["🇬🇧 English"]
if !IAPViewModel.share.isSubscribed {
if IAPViewModel.share.isSubscribed {
iap.append("🇪🇸 Español")
}
return iap
......
......@@ -39,6 +39,9 @@ class SpeakEleProgressViewCtr: SpeakEleBaseViewCtr {
if let cell = self?.SpeakTableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? SpeakProgressStudyCell {
cell.data = self?.dayStudy ?? []
}
if let cell = self?.SpeakTableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? SpeakProgressSignCell {
cell.signList = speakSignListViewModel.share.signList
}
}
}
......
......@@ -6,6 +6,7 @@
//
import UIKit
import AVFAudio
class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
......@@ -57,7 +58,6 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
}
}
private var studyTime = 0
private var offset:Int = 0 {
didSet{
......@@ -75,7 +75,6 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
SpeakAskContentV.isHidden = true
SpeakEleLoadingView.isHidden = true
SpeakLastMsg.isHidden = true
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
SpeakDisplayV.gesture(target: self, class: UITapGestureRecognizer.self, selector: #selector(SpeakDisplayTaps))
SpeakAskAgainV.gesture(target: self, class: UITapGestureRecognizer.self, selector: #selector(SpeakAskAgain))
......@@ -100,6 +99,7 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
SpeakCache.cache.saveData(data: d, fileName: "\(save.recordId ?? 0)")
}
}
self?.SpeakLastMsgDescp.text = audio.contentList?.last?.content ?? ""
DispatchQueue.main.async {
if Audioplay.count > 0 {
AudioPlayerManager.shared.setupAudioPlayer(with: Audioplay.first! ,isMuted: self?.isMate ?? false)
......@@ -118,21 +118,16 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
self?.startTime = 0
}
if let ai = SpeakAIVideoPlayManager.share.SpeakAI.SpeakPlayerLayer ,
let bg = SpeakAIVideoPlayManager.share.backgoundAI.SpeakPlayerLayer{
ai.videoGravity = .resizeAspectFill
self.SpeakAISer.layer.addSublayer(ai)
self.SpeakAISer.layer.addSublayer(bg)
bg.videoGravity = .resizeAspectFill
SpeakAIVideoPlayManager.share.PlayBg()
}
let dsts = SpeakAIVideoPlayManager.share
dsts.removeFromSuperview()
self.SpeakAISer.addSubview(dsts)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.layoutIfNeeded()
SpeakAIVideoPlayManager.share.SpeakAI.SpeakPlayerLayer?.frame = SpeakAISer.bounds
SpeakAIVideoPlayManager.share.backgoundAI.SpeakPlayerLayer?.frame = SpeakAISer.bounds
SpeakAIVideoPlayManager.share.frame = SpeakAISer.bounds
}
override func SpeakUpdate() {
......@@ -151,7 +146,7 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
}
if isRecord {
self.startTime += 1
if self.startTime > 5 {
if self.startTime > 2 {
isRecord = false
if self.SpeakText.count > 0 {
var talk = SpeakDialogueModel()
......@@ -175,16 +170,20 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
titleView.isHidden = true
SpeakSoundBtn.isSelected = isMate
let aiser = viewModel.AIser()
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
let idx = SpeakElePublicManager.share.PublicData.AIerIndex
let icon = "img_" + (aiser[safe: idx]?.name.lowercased() ?? "")
self.SpeakCallIcon.image = UIImage(named: icon)
SpeakName.text = aiser[safe: idx]?.name
do{
let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.playback)
try audioSession.setActive(true)
}catch{ }
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.display.isPaused = false
self.dataSource = self.netViewModel.dialogLeassAsk
// if self.netViewModel.isSpeech {
self.Ask()
// }
self.Ask()
}
}
......@@ -194,7 +193,7 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
SpeakCallIcon.isHidden = true
SpeakAskWaitL.isHidden = true
SpeakAISer.isHidden = false
SpeakAIVideoPlayManager.share.PlayBg()
if netViewModel.isSpeech {
SpeakAskT.isHidden = false
}
......@@ -241,8 +240,8 @@ class SpeakEleCallAIViewCtr: SpeakEleBaseViewCtr {
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
display.isPaused = true
display.invalidate()
AudioPlayerManager.shared.stop()
......
......@@ -30,6 +30,8 @@ class SpeakEleGeneratePlanViewCtr: SpeakEleBaseViewCtr, UIScrollViewDelegate {
private var offset:Int = 0
private var selectIdx:CGFloat = -1
private var SpeakPlanChilds:[SpeakEleGeneratePlanView] = [
SpeakEleGeneratePlanView(string: "Creating diverse topics"),
SpeakEleGeneratePlanView(string: "Preparing interactive dialogues"),
......@@ -39,12 +41,11 @@ class SpeakEleGeneratePlanViewCtr: SpeakEleBaseViewCtr, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
SpeakPlanChilds.forEach { plan in
SpeakStackView.addArrangedSubview(plan)
}
timer.fire()
}
override func viewWillAppear(_ animated: Bool) {
......@@ -128,8 +129,8 @@ class SpeakEleGeneratePlanViewCtr: SpeakEleBaseViewCtr, UIScrollViewDelegate {
child2.startRotation()
child2.offset = offset-200
break
default:
default:
let child = SpeakPlanChilds[2]
child.stop()
child.offset = 100
......@@ -151,6 +152,12 @@ class SpeakEleGeneratePlanViewCtr: SpeakEleBaseViewCtr, UIScrollViewDelegate {
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if timer.isValid {
timer.invalidate()
}
}
private lazy var pagectrol: UIView = {
let p = UIView()
p.corners = 3
......@@ -174,4 +181,22 @@ class SpeakEleGeneratePlanViewCtr: SpeakEleBaseViewCtr, UIScrollViewDelegate {
let offset = scrollView.contentOffset.x
setPages(Int(offset / scrollView.width) )
}
private lazy var timer: Timer = {
let tim = Timer(timeInterval: 3, repeats: true) {[weak self] tm in
Print("timer 1111111111")
self?.selectIdx += 1
if (self?.selectIdx ?? 3) < 3 {
UIView.animate(withDuration: 0.8) {
self?.SpeakScroll.contentOffset = CGPoint(x: (self?.SpeakScroll.width ?? 0.0) * (self?.selectIdx ?? 0), y: 0)
} completion: { su in
self?.setPages(Int(self?.selectIdx ?? 0))
}
}else{
tm.invalidate()
}
}
RunLoop.main.add(tim, forMode: .common)
return tim
}()
}
......@@ -27,6 +27,7 @@ class SpeakEleGeneratePlanView: UIView {
}else if self.state == .start {
self.info.isHidden = false
self.SpeakOffsetL.text = "\(self.offset)%"
self.SpeakL.textColor = .init(hex: 0x000000,alpha: 0.54)
self.ProgressV.snp.remakeConstraints({ make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(self.SpeakL.snp.bottom).offset(10)
......@@ -36,6 +37,7 @@ class SpeakEleGeneratePlanView: UIView {
self.animationLayer.frame = CGRectMake(0, 0, self.ProgressV.width * (CGFloat(self.offset) / 100.0), self.ProgressV.height)
}
}else{
self.SpeakL.textColor = .init(hex: 0x000000,alpha: 0.9)
self.SpeakOffsetL.isHidden = true
self.ProgressV.snp.remakeConstraints({ make in
make.height.equalTo(12)
......@@ -83,7 +85,7 @@ class SpeakEleGeneratePlanView: UIView {
private lazy var SpeakL: UILabel = {
let l = UILabel()
l.font = UIFont.montserrat(.semiBold,size: 18)
l.textColor = .init(hex: 0x000000 ,alpha: 0.9)
l.textColor = .init(hex: 0x000000 ,alpha: 0.54)
l.text = Plan
l.numberOfLines = 0
addSubview(l)
......
......@@ -52,7 +52,7 @@ class SpeakEleGuideViewCtr: SpeakEleBaseViewCtr ,UIScrollViewDelegate {
super.viewDidLayoutSubviews()
self.view.layoutIfNeeded()
SpeakTrustContentVs.forEach { trust in
trust.shadow(cornerRadius: 12, shadowColor: .init(hex: 0x49D9F9,alpha: 0.1), offset: CGSizeMake(0, 4), opacity: 1, radius: 2)
trust.shadow(cornerRadius: 12, shadowColor: .init(hex: 0x49D9F9,alpha: 0.1), offset: CGSizeMake(0, 0), opacity: 1, radius: 3)
}
}
......
......@@ -18,6 +18,9 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
@IBOutlet weak var contiuneBtn: SpeakEleButton!
@IBOutlet weak var SpeakTopVideoView: UIView!
@IBOutlet weak var SpeakBottomTool: UIView!
@IBOutlet weak var ContiueContentV: UIView!
private var offsets = 0
......@@ -32,7 +35,14 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
private var isCountiue:Int = -1 {
didSet {
contiuneBtn.isEnabled = !(isCountiue == -1)
let enable = !(isCountiue == -1)
if !enable {
contiuneBtn.setBackgroundImage(UIImage(named: "icon-button_no(1)"), for: .normal)
contiuneBtn.setBackgroundImage(UIImage(named: "button_guide_on-Heigiose"), for: .highlighted)
}else{
contiuneBtn.setBackgroundImage(UIImage(named: "icon-button_guide_on"), for: .normal)
contiuneBtn.setBackgroundImage(UIImage(named: "icon-button_no-hight"), for: .highlighted)
}
SpeakTableView.reloadData()
}
}
......@@ -40,6 +50,7 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
private var step = 0 {
didSet{
contiuneBtn.isHidden = step < 3
ContiueContentV.isHidden = contiuneBtn.isHidden
InputBoxContent.isHidden = !(step < 3)
SpeakInputBox.isUserInteractionEnabled = (step == 2)
}
......@@ -84,6 +95,7 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
titleView.isHidden = true
isCountiue = -1
GetLostMessage()
}
......@@ -98,6 +110,9 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
}
@IBAction func contineTaps(_ sender: Any) {
if self.isCountiue < 0 {
return
}
if let last = viewModel.anwer.last {
if last.speakMsg == "" {
let language = moreItem[safe:self.isCountiue] ?? ""
......@@ -175,7 +190,7 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
display.isPaused = true
offsets = 0
}
if msg.messageType == .name && msg.speakMsg.isEmpty{
if msg.messageType == .name && msg.speakMsg.isEmpty {
}else{
viewModel.anwer.append(msg)
......@@ -204,6 +219,7 @@ class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
}else if msg.messageType == .finish {
self.isCountiue = 0
self.contiuneBtn.setTitle("Start", for: .normal)
SpeakPermission.requestNotificationPermission()
}
return
}
......@@ -270,8 +286,22 @@ extension SpeakEleQAViewCtr {
}
private func update() -> Void {
let v = Float(self.viewModel.anwer.count) / Float(self.viewModel.questionArrys.count)
self.SpeakProgres.value = v
var pro = 0
for v in self.viewModel.anwer {
if (v.role == .speakUser && v.speakMsg.count > 0){
pro += 1
}
}
if let last = self.viewModel.anwer.last {
if (last.role == .speakUser && last.speakMsg.count <= 0) || last.messageType == .name || last.messageType == .finish{
SpeakBottomTool.isHidden = false
}else{
SpeakBottomTool.isHidden = true
}
}else{
SpeakBottomTool.isHidden = true
}
self.SpeakProgres.value = Float(pro) / 9.0
self.SpeakTableView.reloadData()
self.view.layoutIfNeeded()
if self.viewModel.anwer.count > 0 {
......@@ -343,7 +373,8 @@ extension SpeakEleQAViewCtr : UITableViewDelegate,UITableViewDataSource {
}
self?.selectSets = NSMutableSet(array: self?.selectSets.filter({($0 as! Int) < (self?.max ?? 0) }) ?? [])
}
self?.contiuneBtn.isEnabled = (self?.selectSets.count ?? 0 > 0)
// self?.contiuneBtn.isEnabled = (self?.selectSets.count ?? 0 > 0)
self?.isCountiue = (self?.selectSets.count ?? 0 > 0) ? 1 : -1
self?.SpeakTableView.reloadData()
}
return cell
......
......@@ -11,7 +11,9 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleQAViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="ContiueContentV" destination="ciK-R0-acp" id="uo5-cp-Ze1"/>
<outlet property="InputBoxContent" destination="uS5-tZ-Obr" id="E0N-dl-Lnr"/>
<outlet property="SpeakBottomTool" destination="ly6-as-jqg" id="eoy-1H-eBq"/>
<outlet property="SpeakContentV" destination="lhO-rO-ci0" id="VH2-3v-YWq"/>
<outlet property="SpeakInputBox" destination="n0s-ld-qq8" id="UMQ-9p-FAo"/>
<outlet property="SpeakProgres" destination="ZV3-Si-Hef" id="ZBs-da-fiI"/>
......@@ -91,6 +93,7 @@
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="sp-guide-Send"/>
<state key="highlighted" image="sp-guide-Send-Hight"/>
<connections>
<action selector="SpeakSendMsg:" destination="-1" eventType="touchUpInside" id="pSi-TS-fMS"/>
</connections>
......@@ -100,28 +103,40 @@
<constraint firstAttribute="height" constant="48" id="by7-wH-3pT"/>
</constraints>
</stackView>
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jZV-J1-egY" customClass="SpeakEleButton" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<rect key="frame" x="24" y="16.666666666666629" width="345" height="48"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Continue"/>
<connections>
<action selector="contineTaps:" destination="-1" eventType="touchUpInside" id="ehk-ya-RMw"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ciK-R0-acp">
<rect key="frame" x="24" y="12.666666666666629" width="345" height="52"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jZV-J1-egY">
<rect key="frame" x="0.0" y="18" width="345" height="34"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Continue"/>
<connections>
<action selector="contineTaps:" destination="-1" eventType="touchUpInside" id="ehk-ya-RMw"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="jZV-J1-egY" secondAttribute="bottom" id="6zT-87-MWy"/>
<constraint firstAttribute="height" constant="52" id="Igt-nt-xnN"/>
<constraint firstAttribute="trailing" secondItem="jZV-J1-egY" secondAttribute="trailing" id="Rxu-VC-zEZ"/>
<constraint firstItem="jZV-J1-egY" firstAttribute="leading" secondItem="ciK-R0-acp" secondAttribute="leading" id="iBs-uC-t0b"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="jZV-J1-egY" firstAttribute="top" secondItem="uS5-tZ-Obr" secondAttribute="top" id="0bt-xh-P70"/>
<constraint firstAttribute="trailing" secondItem="uS5-tZ-Obr" secondAttribute="trailing" constant="24" id="6cX-0K-4lq"/>
<constraint firstItem="uS5-tZ-Obr" firstAttribute="top" secondItem="Pk3-rK-Odt" secondAttribute="bottom" constant="16" id="D3H-sA-sez"/>
<constraint firstItem="jZV-J1-egY" firstAttribute="leading" secondItem="uS5-tZ-Obr" secondAttribute="leading" id="EWW-4z-5I0"/>
<constraint firstItem="jZV-J1-egY" firstAttribute="bottom" secondItem="uS5-tZ-Obr" secondAttribute="bottom" id="QZd-ZE-Nd6"/>
<constraint firstItem="uS5-tZ-Obr" firstAttribute="trailing" secondItem="ciK-R0-acp" secondAttribute="trailing" id="N01-8f-ISZ"/>
<constraint firstItem="uS5-tZ-Obr" firstAttribute="bottom" secondItem="ciK-R0-acp" secondAttribute="bottom" id="PRP-oR-LAN"/>
<constraint firstItem="Pk3-rK-Odt" firstAttribute="top" secondItem="ly6-as-jqg" secondAttribute="top" id="R6c-cV-kgx"/>
<constraint firstItem="uS5-tZ-Obr" firstAttribute="leading" secondItem="ly6-as-jqg" secondAttribute="leading" constant="24" id="eRl-ls-UHL"/>
<constraint firstAttribute="bottom" secondItem="uS5-tZ-Obr" secondAttribute="bottom" constant="16" id="h5H-Xb-zyy"/>
<constraint firstItem="Pk3-rK-Odt" firstAttribute="leading" secondItem="ly6-as-jqg" secondAttribute="leading" id="jeu-9r-eGu"/>
<constraint firstItem="uS5-tZ-Obr" firstAttribute="leading" secondItem="ciK-R0-acp" secondAttribute="leading" id="nkB-GL-DBD"/>
<constraint firstAttribute="trailing" secondItem="Pk3-rK-Odt" secondAttribute="trailing" id="oWt-sh-GoR"/>
<constraint firstItem="jZV-J1-egY" firstAttribute="trailing" secondItem="uS5-tZ-Obr" secondAttribute="trailing" id="rlN-TL-UlX"/>
</constraints>
</view>
</subviews>
......@@ -156,11 +171,12 @@
</objects>
<resources>
<image name="sp-guide-Send" width="48" height="48"/>
<image name="sp-guide-Send-Hight" width="48" height="48"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="systemGrayColor">
<color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
......@@ -51,12 +51,13 @@ class SpeakEleMutabSelectBoxViewCell: SpeakEleQABaseViewCell {
btn.corners = 8
btn.borderWidth = 1
btn.borderColor = .init(hex: 0x6B71E3)
btn.contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
btn.addTarget(self, action: #selector(btnTaps(_:)), for: .touchUpInside)
contentV.addSubview(btn)
items.append(btn)
btn.tag = i
let size = str.size(withFont: UIFont.montserrat(.regular,size: 16))
let width = size.width + 10.0
let width = size.width + 10.0 + 16
if ((offsetX + width + content.right) > contentV.width) {
offsetX = content.left
......@@ -104,8 +105,7 @@ class SpeakEleMutabSelectBoxViewCell: SpeakEleQABaseViewCell {
make.left.right.bottom.top.equalToSuperview().inset(UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10))
}
contentV.snp.makeConstraints { make in
make.right.top.bottom.equalToSuperview().inset(UIEdgeInsets(top: 2, left: 0, bottom: 16, right: (marginLR)))
make.width.equalTo(Dev.screenW * 0.6 )
make.right.top.left.bottom.equalToSuperview().inset(UIEdgeInsets(top: 2, left: 40, bottom: 16, right: (marginLR)))
}
}
......
......@@ -103,8 +103,8 @@ class SpeakEleSelectBoxViewCell: SpeakEleQABaseViewCell {
make.left.right.bottom.top.equalToSuperview().inset(UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10))
}
contentV.snp.makeConstraints { make in
make.right.top.bottom.equalToSuperview().inset(UIEdgeInsets(top: 2, left: 0, bottom: 16, right: (marginLR)))
make.width.equalTo(Dev.screenW * 0.6 )
make.right.left.top.bottom.equalToSuperview().inset(UIEdgeInsets(top: 2, left: 40, bottom: 16, right: (marginLR)))
// make.width.equalTo(338)
}
}
......
......@@ -13,12 +13,11 @@ class SpeakReviewViewModel: NSObject {
set {}
get {
return [
SpeakReviewModel(image: "img_1", name: "Lily Parker", country: "United States", descption: "Fragmented English practice is convenient! App drills work—greetings feel natural."),
SpeakReviewModel(image: "img_1", name: "Lily Parker", country: "United States", descption: "Fragmented English practice fits my schedule! The app’s scenario drills work—after 2 weeks, greeting foreign interns feels natural, no pauses."),
SpeakReviewModel(image: "img_2", name: "Mia Davies", country: "United Kingdom", descption: "Café work: it helps practice ordering—customers praise fluency. "),
SpeakReviewModel(image: "img_3", name: "Chloe Wang", country: "Australia", descption: "Chats with foreign friend Detailed grammar feedback helps. ")
SpeakReviewModel(image: "img_2", name: "Mia Davies", country: "United Kingdom", descption: "Working at the café lets me practice English easily! Daily chats with customers help, and a British customer said, “Your English is fluent—I can’t tell it’s not first!”"),
SpeakReviewModel(image: "img_3", name: "Chloe Wang", country: "Australia", descption: "Chatting weekly with friend Emma boosts my English! She gives great grammar feedback, and now I catch errors—my writing’s much more accurate.")
]
}
}
......@@ -27,11 +26,11 @@ class SpeakReviewViewModel: NSObject {
set{ }
get{
return [
SpeakReviewModel(image: "img_4", name: "James Scott", country: "", descption: "Business trips: plane listening with accents helps clients—English feels authentic."),
SpeakReviewModel(image: "img_4", name: "James Scott", country: "", descption: "Practicing English on business planes helps! I learn accents, and a Sydney client said, “Your English is authentic—like you lived here!” It boosted rapport."),
SpeakReviewModel(image: "img_5", name: "Nora Hayes", country: "", descption: "App boosts vocabulary—English literature reading easier."),
SpeakReviewModel(image: "img_5", name: "Nora Hayes", country: "", descption: "This English app helps my vocabulary! I once struggled with English lit, but now 500+ words later, I get tricky descriptions in Pride and Prejudice."),
SpeakReviewModel(image: "img_6", name: "Thomas Bennett", country: "", descption: "AI chat lets me speak—gentle corrections ease call nerves.")]
SpeakReviewModel(image: "img_6", name: "Thomas Bennett", country: "", descption: "I used to panic about English calls! Now AI chat practice helps—after a month, I chatted with NY office smoothly, no fluster, even joked.")]
}
}
......
......@@ -37,6 +37,8 @@ class SpeakEleIAPViewCtr: SpeakEleBaseViewCtr {
@IBOutlet weak var SpeakPayBut: SpeakEleButton!
@IBOutlet weak var SpeakBotDescription: UILabel!
@IBOutlet weak var SpeakContentBg: UIView!
var Products:[SKProduct?] = []
private let viewModel = IAPViewModel.share
......@@ -91,8 +93,10 @@ class SpeakEleIAPViewCtr: SpeakEleBaseViewCtr {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.view.layoutIfNeeded()
SpeakEasyV.shadow(cornerRadius: 16,shadowColor: .init(hex: 0x000000,alpha: 1),opacity: 0.06,radius: 2)
SpeakPayContentV.shadow(cornerRadius: 8,shadowColor: .init(hex: 0x000000,alpha: 1),opacity: 0.06,radius: 2)
SpeakContentBg.gradient(colors: [.init(hex: 0xFFFFFF,alpha: 0),.init(hex: 0xFFFFFF,alpha: 0.76) ,.white],direction: .topToBottom)
}
@IBAction func SpeakCloseTaps(_ sender: Any) {
......
......@@ -11,7 +11,7 @@ class SpeakEleLaunchViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.ToPages()
}
}
......@@ -26,7 +26,7 @@ class SpeakEleLaunchViewCtr: SpeakEleBaseViewCtr {
SpWindow.switchToController(nav)
}else{
let nav = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleLoginGuideCtr())
SpWindow.switchToController(nav)
SpWindow.rootViewController = nav
}
break
case .subscribe:
......
......@@ -26,10 +26,17 @@ class SpeakEleFLoginViewCtr: SpeakEleBaseViewCtr {
super.viewWillAppear(animated)
titleView.isHidden = true
self.view.layoutIfNeeded()
var idx = 0
LoginBtns.forEach { btn in
btn.setBackgroundImage(UIColor.white.generate(btn.size,20), for: .normal)
btn.setBackgroundImage(UIColor.init(hex: 0x191919).generate(btn.size,20), for: .highlighted)
if idx == 0 {
btn.setBackgroundImage(UIColor.black.generate(btn.size,20), for: .normal)
btn.setBackgroundImage(UIColor.black.generate(btn.size,20), for: .highlighted)
}else{
btn.setBackgroundImage(UIColor.white.generate(btn.size,20), for: .normal)
btn.setBackgroundImage(UIColor.init(hex: 0x191919).generate(btn.size,20), for: .highlighted)
}
btn.clipsToBounds = false
idx += 1
}
}
......@@ -37,7 +44,7 @@ class SpeakEleFLoginViewCtr: SpeakEleBaseViewCtr {
super.viewDidLayoutSubviews()
self.view.layoutIfNeeded()
LoginBtns.forEach { btn in
btn.shadow(cornerRadius: 20,shadowColor: .init(hex: 0x000000),offset: CGSize(width: 0, height: 2) ,opacity: 0.06,radius: 2)
btn.shadow(cornerRadius: 20,shadowColor: .init(hex: 0x000000,alpha: 0.06),offset: CGSize(width: 0, height: 2) ,opacity: 1,radius: 5)
}
}
......@@ -93,8 +100,8 @@ class SpeakEleFLoginViewCtr: SpeakEleBaseViewCtr {
private func ToHome() -> Void {
updateUserInformation()
let nav = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleTabbarViewCtr())
SpWindow.switchToController(nav)
}
}
......@@ -66,7 +66,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XM7-aG-cye">
<rect key="frame" x="0.0" y="0.0" width="272" height="60"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="gaoleyang@linkingplay.com" placeholder="E-mail address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="e0z-Rl-Mp2">
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="E-mail address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="e0z-Rl-Mp2">
<rect key="frame" x="16" y="19" width="240" height="22"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
......
......@@ -12,6 +12,21 @@ class SpeakEleLoginGuideCtr: SpeakEleBaseViewCtr {
@IBOutlet weak var SpeakDescLabel: UILabel!
@IBOutlet weak var TopIcon: UIImageView!
@IBOutlet weak var ShowTopImg: UIImageView!
@IBOutlet weak var ShowAniM1: UIImageView!
@IBOutlet weak var ShowAniM2: UIImageView!
@IBOutlet weak var ShowButtons: UIStackView!
@IBOutlet weak var centerBottonConst: NSLayoutConstraint!
@IBOutlet weak var TopWidthConst: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
}
......@@ -19,6 +34,49 @@ class SpeakEleLoginGuideCtr: SpeakEleBaseViewCtr {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setDescription()
self.startAni()
}
private func startAni() -> Void {
self.TopIcon.alpha = 1
ShowButtons.alpha = 0
ShowTopImg.alpha = 0
ShowAniM1.alpha = 1
self.ShowAniM1.isHidden = true
ShowAniM2.alpha = 0
TopWidthConst.constant = 302 * 2.0
ShowAniM2.alpha = 0
self.ShowButtons.alpha = 0
centerBottonConst.constant = 150
self.view.layoutIfNeeded()
DispatchQueue.main.async {
self.view.setNeedsDisplay()
UIView.animate(withDuration: 0.5) {
self.TopIcon.alpha = 0.0
} completion: { su in
if su {
self.ShowAniM1.isHidden = false
UIView.animate(withDuration: 0.6) {
self.ShowAniM1.alpha = 1
self.TopWidthConst.constant = 302 * 1.2
self.view.layoutIfNeeded()
} completion: { su in
if su {
UIView.animate(withDuration: 0.6) {
self.ShowAniM2.alpha = 1
self.ShowButtons.alpha = 1
self.TopWidthConst.constant = 302
self.centerBottonConst.constant = 80
self.view.layoutIfNeeded()
} completion: { su in
}
}
}
}
}
}
}
override func viewDidLayoutSubviews() {
......
......@@ -11,7 +11,14 @@
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleLoginGuideCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="ShowAniM1" destination="2Pj-ZL-FxO" id="BhB-kV-Thj"/>
<outlet property="ShowAniM2" destination="egF-1p-Cl5" id="Quz-kT-fdN"/>
<outlet property="ShowButtons" destination="veF-PY-V1F" id="PkJ-jw-li3"/>
<outlet property="ShowTopImg" destination="eyD-Iy-5pN" id="P19-KE-Kwa"/>
<outlet property="SpeakDescLabel" destination="jGO-Du-a3k" id="mxV-nA-Nwk"/>
<outlet property="TopIcon" destination="w7f-wU-Eto" id="rmc-Eq-U2D"/>
<outlet property="TopWidthConst" destination="aW6-vK-ZDa" id="O88-s0-sRq"/>
<outlet property="centerBottonConst" destination="NuM-ib-dld" id="cRg-ks-kKG"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
......@@ -20,10 +27,13 @@
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="dengluye-login" translatesAutoresizingMaskIntoConstraints="NO" id="eyD-Iy-5pN">
<rect key="frame" x="0.0" y="0.0" width="393" height="465"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="BBBBBBBBBGo.png" translatesAutoresizingMaskIntoConstraints="NO" id="w7f-wU-Eto">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="veF-PY-V1F">
<imageView clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.0" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="dengluye-login" translatesAutoresizingMaskIntoConstraints="NO" id="eyD-Iy-5pN">
<rect key="frame" x="0.0" y="0.0" width="393" height="402"/>
</imageView>
<stackView opaque="NO" alpha="0.0" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="veF-PY-V1F">
<rect key="frame" x="24" y="589.66666666666663" width="345" height="170.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="pwZ-Zv-JRo">
......@@ -89,22 +99,44 @@
</label>
</subviews>
</stackView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-10000h+" translatesAutoresizingMaskIntoConstraints="NO" id="2Pj-ZL-FxO">
<rect key="frame" x="45.666666666666657" y="279" width="302" height="130"/>
<constraints>
<constraint firstAttribute="width" secondItem="2Pj-ZL-FxO" secondAttribute="height" multiplier="302:130" id="Axm-4a-6Mu"/>
<constraint firstAttribute="width" constant="302" id="aW6-vK-ZDa"/>
</constraints>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-SpeakEasyLearning" translatesAutoresizingMaskIntoConstraints="NO" id="egF-1p-Cl5">
<rect key="frame" x="24" y="509" width="345" height="67"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="veF-PY-V1F" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="24" id="0oh-4u-Nzo"/>
<constraint firstItem="w7f-wU-Eto" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="2Fe-GS-bKr"/>
<constraint firstItem="egF-1p-Cl5" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="24" id="8nd-bH-4Et"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="veF-PY-V1F" secondAttribute="trailing" constant="24" id="9ao-KJ-und"/>
<constraint firstItem="eyD-Iy-5pN" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="9vZ-ko-bjl"/>
<constraint firstItem="w7f-wU-Eto" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="BXz-Rl-pBh"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="egF-1p-Cl5" secondAttribute="trailing" constant="24" id="Bv4-yp-t6a"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="w7f-wU-Eto" secondAttribute="trailing" id="Cz8-3M-tyJ"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="veF-PY-V1F" secondAttribute="bottom" constant="24" id="NIU-Ch-1i2"/>
<constraint firstItem="egF-1p-Cl5" firstAttribute="bottom" secondItem="i5M-Pr-FkT" secondAttribute="centerY" constant="150" id="NuM-ib-dld"/>
<constraint firstItem="egF-1p-Cl5" firstAttribute="top" secondItem="2Pj-ZL-FxO" secondAttribute="bottom" constant="100" id="X1n-a6-Ev3"/>
<constraint firstItem="2Pj-ZL-FxO" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="aJ5-Rk-qcu"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="eyD-Iy-5pN" secondAttribute="trailing" id="bbE-PY-j4r"/>
<constraint firstAttribute="bottom" secondItem="w7f-wU-Eto" secondAttribute="bottom" id="clw-Ck-R1b"/>
<constraint firstItem="eyD-Iy-5pN" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="sGi-Ff-y6I"/>
</constraints>
<point key="canvasLocation" x="131" y="-12"/>
<point key="canvasLocation" x="130.53435114503816" y="-12.67605633802817"/>
</view>
</objects>
<resources>
<image name="dengluye-login" width="402" height="465"/>
<image name="BBBBBBBBBGo.png" width="402" height="874"/>
<image name="dengluye-login" width="402" height="402"/>
<image name="sp-10000h+" width="302" height="130"/>
<image name="sp-SpeakEasyLearning" width="318.66665649414062" height="67"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
......
......@@ -82,7 +82,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xbG-3d-KMi">
<rect key="frame" x="0.0" y="0.0" width="272" height="60"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="yuanzhongqing@linkingplay.com" placeholder="E-mail address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="M4R-vQ-irk">
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="E-mail address" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="M4R-vQ-irk">
<rect key="frame" x="16" y="19" width="240" height="22"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
......@@ -141,7 +141,7 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="khn-vx-1Kx">
<rect key="frame" x="0.0" y="142" width="272" height="60"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="666666" placeholder="Password" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="RcT-ZC-XJJ">
<textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="248" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="RcT-ZC-XJJ">
<rect key="frame" x="16" y="19" width="190" height="22"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
......
......@@ -33,7 +33,8 @@ struct UserMode:Codable {
var maxContinuousSignDays:Int?
/// 当前签到
var currentContinuousSignDays:Int?
/// 是否新用户
var newUser:Bool?
func isLogin() -> Bool {
return (self.token?.count ?? 0 > 0)
......@@ -55,7 +56,8 @@ struct UserMode:Codable {
"learnedNative": \UserMode.learnedNative,
"snowNum": \UserMode.snowNum,
"maxContinuousSignDays": \UserMode.maxContinuousSignDays,
"currentContinuousSignDays":\UserMode.currentContinuousSignDays
"currentContinuousSignDays":\UserMode.currentContinuousSignDays,
"newUser":\UserMode.newUser
]
mutating func assign(from source: UserMode?) {
......@@ -73,18 +75,6 @@ struct UserMode:Codable {
break
}
}
// let mirror = Mirror(reflecting: source)
// for child in mirror.children {
// if let key = child.label {
// // 使用键路径动态设置值
// if let value = child.value as? Int, let intKey = UserMode.keyPathMap[key] as? WritableKeyPath<UserMode, Int?> {
// self[keyPath: intKey] = value
// } else if let value = child.value as? String , let intKey = UserMode.keyPathMap[key] as? WritableKeyPath<UserMode, String?>{
// self[keyPath: intKey] = value
// }
// }
// }
}
}
......@@ -33,6 +33,7 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
var isReStart = false
var isMute = false
private var Translates = NSMutableSet()
let viewModel = SpeakDialogueViewModel()
var dataLesssion:SpeakLessonDescpModel?
......@@ -94,6 +95,7 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
self.dataSource = viewModel.dialogLeassAsk
self.SpeakLeassonTableView.reloadData()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.tipsAnimateFinish()
self.scrollTop()
}
}
......@@ -111,6 +113,10 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
vc.show()
}
}
SpeakVideoPPPPPP.addSubview(SpeakAIVideoPlayManager.share)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
SpeakAIVideoPlayManager.share.PlayBg()
}
}
override func setup() {
......@@ -126,21 +132,12 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
SpeakLeassonTableView.register(UINib(nibName: SpeakDialogLoadingCell.id, bundle: nil), forCellReuseIdentifier: SpeakDialogLoadingCell.id)
SpeakLeassonTableView.register(UINib(nibName: SpeakDialogAIReviewCell.id, bundle: nil), forCellReuseIdentifier: SpeakDialogAIReviewCell.id)
SpeakLeassonTableView.register(UINib(nibName: SpeakDialogQuReviewCell.id, bundle: nil), forCellReuseIdentifier: SpeakDialogQuReviewCell.id)
if let ai = SpeakAIVideoPlayManager.share.SpeakAI.SpeakPlayerLayer ,
let bg = SpeakAIVideoPlayManager.share.backgoundAI.SpeakPlayerLayer {
self.SpeakVideoPPPPPP.layer.addSublayer(ai)
ai.videoGravity = .resizeAspectFill
self.SpeakVideoPPPPPP.layer.addSublayer(bg)
bg.videoGravity = .resizeAspectFill
SpeakAIVideoPlayManager.share.PlayBg()
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
SpeakContentView.cornerRect(radius: 16, [.topLeft,.topRight])
SpeakAIVideoPlayManager.share.SpeakAI.SpeakPlayerLayer?.frame = self.SpeakVideoPPPPPP.bounds
SpeakAIVideoPlayManager.share.backgoundAI.SpeakPlayerLayer?.frame = self.SpeakVideoPPPPPP.bounds
SpeakAIVideoPlayManager.share.frame = self.SpeakVideoPPPPPP.bounds
}
@IBAction func SpeakFavatorTaps(_ sender: UIButton) {
......@@ -150,7 +147,13 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
@IBAction func SoundTapCloseTaps(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
isMute = sender.isSelected
AudioPlayerManager.shared.setVolume(sender.isSelected ? 0 : 1)
for (i,_) in self.dataSource.enumerated() {
if let cell = self.SpeakLeassonTableView.cellForRow(at: IndexPath(row: i, section: 0)) as? SpeakDialogAIerCell {
cell.isMute = isMute
}
}
}
......@@ -163,14 +166,16 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
b == true{
self?.didddd.isPaused = true
self?.didddd.invalidate()
self?.display.isPaused = true
self?.display.invalidate()
//FIXME: test
SpeakDayEveryManager.manager.SpeakDayData.studyFreeTm = 600 //self?.studyTm
SpeakAIVideoPlayManager.share.removeFromSuperview()
SpeakDayEveryManager.manager.SpeakDayData.studyFreeTm = self?.studyTm
SpeakDayEveryManager.manager.SpeakDayData.studytime = self?.studyTime
SpeakDayEveryManager.manager.update()
if let call = self?.view.callblack {
call(self?.isSing)
}
AudioPlayerManager.shared.stop()
self?.navigationController?.popViewController(animated: true)
}
}
......@@ -219,6 +224,7 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
self?.isMute = isMate
self?.dataSource = self?.viewModel.dialogLeassAsk ?? []
self?.scrollTop()
self?.tipsAnimateFinish()
}
}
self?.navigationController?.pushViewController(call, animated: true)
......@@ -236,16 +242,9 @@ class SpeakDialogueViewCtr: SpeakEleBaseViewCtr {
return input
}()
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.display.isPaused = true
self.didddd.isPaused = true
AudioPlayerManager.shared.stop()
SpeakAIVideoPlayManager.share.stop()
}
private lazy var didddd: CADisplayLink = {
......@@ -277,7 +276,7 @@ extension SpeakDialogueViewCtr {
private func tipsAnimateFinish() {
self.view.layoutIfNeeded()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
if let last = self.dataSource.last,
last.AniState == .loading,
last.role == .AI {
......
......@@ -120,7 +120,7 @@ class SpeakDialogueViewModel: NSObject {
let idx = SpeakElePublicManager.share.PublicData.AIerIndex
let airs = SpeakHomeViewModel().AIser()[safe: idx]
let vodioID = airs?.voiceId
net.SpeakAILeasson(param: ["lessonId":lessonId,"isReStart":isReStart ,"userAnswer":userAnswer, "isSub":/*IAPViewModel.share.isSubscribed*/true ,"voiceId":vodioID]) {[weak self] ( su ,data:SpeakdialogueTalkModel?) in
net.SpeakAILeasson(param: ["lessonId":lessonId,"isReStart":isReStart ,"userAnswer":userAnswer, "isSub":IAPViewModel.share.isSubscribed ,"voiceId":vodioID]) {[weak self] ( su ,data:SpeakdialogueTalkModel?) in
if su {
self?.isSpeech = true
if var setD = data,
......
//
// SpeakAutoLayout.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/9/3.
//
import UIKit
class SpeakAutoLayout: NSLayoutConstraint {
static private let standardHeight: CGFloat = 874
override func awakeFromNib() {
super.awakeFromNib()
updateConstant()
}
private func updateConstant() {
let screenHeight = UIScreen.main.bounds.height
guard SpeakAutoLayout.standardHeight.isFinite && screenHeight.isFinite else {
self.constant = 0
return
}
let calculatedConstant = (screenHeight / SpeakAutoLayout.standardHeight) * self.constant
if calculatedConstant.isFinite {
self.constant = calculatedConstant
} else {
self.constant = 0
}
}
}
......@@ -7,48 +7,73 @@
import UIKit
class SpeakAIVideoPlayManager: NSObject {
class SpeakAIVideoPlayManager: UIView {
static let share = SpeakAIVideoPlayManager()
var backgoundAI = SpeakVideoPlayer()
var SpeakAI = SpeakVideoPlayer()
private var backgoundAI = SpeakVideoPlayer()
private var SpeakAI = SpeakVideoPlayer()
private override init() {
super.init()
self.loadVideo()
private override init(frame: CGRect) {
super.init(frame: frame)
NotificationCenter.default.addObserver(self, selector: #selector(Foreground), name: UIApplication.willEnterForegroundNotification, object: nil)
SpeakAI.PlayFinish = { [weak self] in
self?.PlayBg()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func Foreground() -> Void {
PlayBg()
}
func loadVideo() -> Void {
self.layer.sublayers?.forEach({$0.removeFromSuperlayer()})
backgoundAI.loadVideo(state: .none)
SpeakAI.loadVideo(state: .runloop)
if let bg = backgoundAI.SpeakPlayerLayer,
let ai = SpeakAI.SpeakPlayerLayer{
self.layer.insertSublayer(bg, at: 10)
self.layer.insertSublayer(ai, at: 15)
Print("添加AI动画成功")
}
}
func PlaySpeak(_ duration:Double) -> Void {
SpeakAI.SpeakPlayerLayer?.zPosition = 1
backgoundAI.stop()
backgoundAI.SpeakPlayerLayer?.zPosition = 0
SpeakAI.SpeakPlayerLayer?.zPosition = 15
backgoundAI.SpeakPlayerLayer?.zPosition = 10
backgoundAI.play()
let vduration = SpeakAI.duration
let count = ceil(duration / vduration)
let rate = (count*vduration)/duration + 0.03
SpeakAI.videoPlayer(rate, playCount: Int(count))
}
func PlayBg() -> Void {
SpeakAI.SpeakPlayerLayer?.zPosition = 0
SpeakAI.SpeakPlayerLayer?.zPosition = 10
SpeakAI.play()
backgoundAI.SpeakPlayerLayer?.zPosition = 15
backgoundAI.play()
}
override func layoutSubviews() {
super.layoutSubviews()
self.layoutIfNeeded()
SpeakAI.SpeakPlayerLayer?.frame = self.bounds
backgoundAI.SpeakPlayerLayer?.frame = self.bounds
}
func stop() -> Void {
SpeakAI.stop()
backgoundAI.videoPlayer()
backgoundAI.SpeakPlayerLayer?.zPosition = 1
backgoundAI.stop()
}
}
......@@ -18,17 +18,16 @@ class SpeakVideoPlayer {
var SpeakPlayer:AVPlayer?
var SpeakPlayerLayer:AVPlayerLayer?
var SpeakPlayCount:Int = 0
var SpeakCurrentPlay:Int = 0
private var SpeakPlayCount:Int = 0
private var SpeakCurrentPlay:Int = 0
var duration:Double = 1
var PlayFinish:(()->Void)?
open func videoPlayer(_ rate:Double = 1 , playCount:Int = 0) -> Void {
self.stop()
SpeakPlayCount = playCount
SpeakCurrentPlay = 0
SpeakPlayer?.play()
DispatchQueue.main.asyncAfter(deadline: .now()+0.1) {
self.play()
self.SpeakPlayer?.rate = Float(rate)
}
}
......@@ -47,21 +46,16 @@ class SpeakVideoPlayer {
}
}
// 初始化多个视频播放器
private func setupPlayers(videoURL: URL) {
let playerItem = AVPlayerItem(url: videoURL)
let asset = AVAsset(url: videoURL)
let playerItem = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: playerItem)
self.SpeakPlayer = player
let playerLayer = AVPlayerLayer(player: player)
let playerLayer = AVPlayerLayer(player: self.SpeakPlayer)
playerLayer.videoGravity = .resizeAspectFill
playerLayer.shouldRasterize = true
playerLayer.rasterizationScale = UIScreen.main.nativeScale
self.SpeakPlayerLayer = playerLayer
playerItem.preferredPeakBitRate = 1
let asset = AVAsset(url: videoURL)
asset.loadValuesAsynchronously(forKeys: ["duration"]) { [weak self] in
DispatchQueue.main.async {
var error: NSError?
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment