推荐增加播放功能,VIP弹窗

This commit is contained in:
zeng 2025-05-14 15:27:48 +08:00
parent ff3f5a8f51
commit 1dd0094b1b
27 changed files with 638 additions and 33 deletions

41
Apple账号资料.txt Normal file
View File

@ -0,0 +1,41 @@
Thimra 开发者账号信息
认证人 :陈佳
认证设备 Mac min
设备型号 MU9D3CH/A
序列号 TVJJ97WWHH
手机号码 190 7319 2960
企业邮箱 thimra@thimratv.com 密码9oldpGT_y0qR
D-U-N-S457012112
公司主体 Changsha Jiaer Network Technology Co., Ltd.
公司地址 Room 15006, Xijing Commercial Plaza, No. 383 Jinxing Middle Road
官网 https://www.thimratv.com
appleId cs.jiaer.developer@icloud.com
密码 Discover2024
账户持有人:
Hong Kong Qin Jiu Media Culture Co., Limited
银行账号:
9558851001034420709
复制
币种:
USD
费率:
0.7%
银行名称:
Industrial And Commercial Bank Of China Shanghai Pilot Free Trade Zone Branch Xinling Road Sub-Branch
Swift Code
ICBKCNBJSHI
CNAPS代码
102290019237
银行所在国家/地区:
China
银行地址:
NO.118 Xinling Rd Shanghai Branch
沙盒账号:
jiaer@test.com
Cje12345

View File

@ -40,15 +40,6 @@ extension AppDelegate {
private func showApnsAlert() {
let view = SPApnsAlertView()
view.show()
// let alert = UIAlertController(title: nil, message: "kAlertMessage_03".localized, preferredStyle: .alert)
// alert.addAction(UIAlertAction(title: "movia_affirm".localized, style: .default, handler: { _ in
// SPAPPTool.openApnsSetting()
// }))
// alert.addAction(UIAlertAction(title: "movia_Cancel".localized, style: .cancel))
//
//
// SPAPPTool.topViewController()?.present(alert, animated: true)
}
}
@ -83,11 +74,19 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
SPStatAPI.requestStatApns(messageId: model.message_id ?? "", title: response.notification.request.content.title)
if let shortPlayId = model.short_play_id {
if model.path == .videoDetail, let shortPlayId = model.short_play_id {
let vc = SPPlayerDetailViewController()
vc.shortPlayId = shortPlayId
SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)
} else if model.path == .promotion {
SPAPPTool.mainTabBarController?.selectedReward()
} else if model.path == .feedback {
let vc = SPCampaignWebViewController()
vc.urlStr = SPFeedBackListWebUrl
SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)
}
completionHandler()

View File

@ -69,6 +69,21 @@ extension SPTabBarController {
}
}
///
func selectedReward() {
var index: Int?
self.viewControllers?.enumerated().forEach({
guard let nav = $1 as? UINavigationController else { return }
if let _ = nav.viewControllers.first as? SPRewardsViewController {
index = $0
}
})
if let index = index {
self.selectedIndex = index
}
}
}
extension SPTabBarController {

View File

@ -23,3 +23,6 @@ let kSPWaitRestoreIAPDefaultsKey = "kSPWaitRestoreIAPDefaultsKey"
///
let kSPApnsAlertDefaultsKey = "kSPApnsAlertDefaultsKey"
///vip
let kSPVipAlertDateDefaultsKey = "kSPVipAlertDateDefaultsKey"

View File

@ -416,5 +416,37 @@ extension UIColor {
static func colorFFC555(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFFC555, alpha: alpha)
}
static func colorFFC591(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xFFC591, alpha: alpha)
}
static func colorBC7616(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xBC7616, alpha: alpha)
}
static func color9C9896(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x9C9896, alpha: alpha)
}
static func colorCC9251(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xCC9251, alpha: alpha)
}
static func colorCA8D3B(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xCA8D3B, alpha: alpha)
}
static func colorA36C2D(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xA36C2D, alpha: alpha)
}
static func color412D11(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0x412D11, alpha: alpha)
}
static func colorD0C0AA(alpha: CGFloat = 1) -> UIColor {
return color(hex: 0xD0C0AA, alpha: alpha)
}
}

View File

@ -10,8 +10,16 @@ import SmartCodable
class SPOpenAppModel: SPModel, SmartCodable {
enum Path: String, SmartCaseDefaultable {
case videoDetail = "detail"
///
case feedback = "feedback"
///
case promotion = "promotion"
}
var id: String?
var message_id: String?
var short_play_id: String?
var path: Path?
}

View File

@ -49,7 +49,7 @@ class SPLoginViewController: SPViewController {
let range2 = agreementStr.ocString().range(of: privacyPolicy)
let text = NSMutableAttributedString(string: agreementStr)
text.font = .fontMedium(ofSize: 10)
text.font = .fontMedium(ofSize: 12)
text.color = .colorB0B0B3()
text.setTextHighlight(range1, color: .colorFFFFFF(), backgroundColor: nil) { [weak self] _, _, _, _ in
@ -100,7 +100,7 @@ class SPLoginViewController: SPViewController {
button.setBackgroundImage(UIImage(color: background), for: .normal)
button.setTitle(title, for: .normal)
button.setTitleColor(titleColor, for: .normal)
button.jx_font = .fontMedium(ofSize: 14)
button.jx_font = .fontMedium(ofSize: 16)
button.space = 12
button.setImage(icon, for: .normal)
button.layer.cornerRadius = 8

View File

@ -67,6 +67,9 @@ class SPMineViewController: SPViewController {
}
isHaveEntered = true
///VIP
showVipAlert()
}
private func updateHeaderView() {
@ -83,6 +86,23 @@ class SPMineViewController: SPViewController {
self?.tableView.sp_endHeaderRefreshing()
}
}
}
extension SPMineViewController {
private func showVipAlert() {
guard SPLoginManager.manager.userInfo?.is_vip != true else { return }
guard SPVipAlertView.isShowAlert else { return }
SPWalletAPI.requestPayTemplate { model in
guard let list = model?.list_sub_vip else { return }
let alert = SPVipAlertView(dataArr: list).show(in: SPAPPTool.getKeyWindow())
alert.buyFinishHandle = { [weak self] in
guard let self = self else { return }
self.requestUserInfo()
}
}
}
}

View File

@ -107,7 +107,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
//
let videoCoin = videoInfo.coins ?? 0
if myCoin < videoCoin {//
if myCoin < videoCoin, self.viewModel.currentPlayer?.hasLockUpEpisode == true {//
self.onPlayBuy()
}
return

View File

@ -7,7 +7,7 @@
import UIKit
protocol SPPlayerProtocol: NSObjectProtocol {
@objc protocol SPPlayerProtocol: NSObjectProtocol {
///
var playerFinishHadle: (() -> Void)? { get set }
@ -17,6 +17,8 @@ protocol SPPlayerProtocol: NSObjectProtocol {
var isCurrent: Bool { get set }
///
@objc optional var hasLockUpEpisode: Bool { get set }
///
var duration: Int { get }

View File

@ -29,6 +29,7 @@ class SPShortModel: SPModel, SmartCodable {
var video_info: SPVideoInfoModel?
var watch_total: Int?
var current_episode: String?
var video_url: String?
@IgnoredKey
var titleAttributedString: NSAttributedString?

View File

@ -12,18 +12,40 @@ class SPPlayerDetailRecommandCell: ZKCycleScrollViewCell {
var model: SPShortModel? {
didSet {
coverImageView.sp_setImage(url: model?.image_url)
player.setPlayUrl(url: model?.video_url ?? "")
}
}
private(set) lazy var player: SPPlayer = {
let player = SPPlayer()
player.playerView = playerView
player.delegate = self
return player
}()
var isCurrentPlayer: Bool = false {
didSet {
if !isCurrentPlayer {
coverImageView.isHidden = false
}
}
}
private lazy var coverImageView: SPImageView = {
let imageView = SPImageView()
imageView.layer.cornerRadius = 6
imageView.layer.masksToBounds = true
return imageView
}()
private lazy var playerView: UIView = {
let view = UIView()
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.layer.cornerRadius = 6
contentView.layer.masksToBounds = true
_setupUI()
}
@ -36,8 +58,13 @@ class SPPlayerDetailRecommandCell: ZKCycleScrollViewCell {
extension SPPlayerDetailRecommandCell {
private func _setupUI() {
contentView.addSubview(playerView)
contentView.addSubview(coverImageView)
playerView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
coverImageView.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
@ -45,3 +72,16 @@ extension SPPlayerDetailRecommandCell {
}
//MARK: -------------- SPPlayerDelegate --------------
extension SPPlayerDetailRecommandCell: SPPlayerDelegate {
func sp_player(_ player: SPPlayer, loadStateDidChange state: SPPlayer.LoadState) {
}
func sp_player(_ player: SPPlayer, playStateDidChanged state: SPPlayer.PlayState) {
if state == .playing, isCurrentPlayer {
self.coverImageView.isHidden = true
}
}
}

View File

@ -14,6 +14,20 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
var clickCloseButton: (() -> Void)?
var clickPlayButton: ((_ model: SPShortModel) -> Void)?
private var _currentCell: SPPlayerDetailRecommandCell?
private var currentCell: SPPlayerDetailRecommandCell? {
set {
_currentCell?.player.pause()
_currentCell?.isCurrentPlayer = false
_currentCell = newValue
_currentCell?.isCurrentPlayer = true
}
get {
return _currentCell
}
}
//MARK: UI
private lazy var bgImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "recommand_bg_image_01"))
@ -37,6 +51,7 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
private lazy var bannerView: ZKCycleScrollView = {
let view = ZKCycleScrollView(frame: .zero, shouldInfiniteLoop: true)
view.isAutoScroll = false
view.delegate = self
view.dataSource = self
view.itemSize = CGSize(width: 231, height: 322)
@ -80,6 +95,11 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
fatalError("init(coder:) has not been implemented")
}
private func play() {
self.currentCell?.player.start()
}
//MARK: HWPanModalPresentable
override func longFormHeight() -> PanModalHeight {
return PanModalHeightMake(.content, 540 + kSPTabbarSafeBottomMargin)
@ -106,6 +126,7 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
override func allowsPullDownWhenShortState() -> Bool {
return false
}
}
extension SPPlayerDetailRecommandView {
@ -191,6 +212,9 @@ extension SPPlayerDetailRecommandView: ZKCycleScrollViewDelegate, ZKCycleScrollV
let model = self.dataArr[toIndex]
videoNameLabel.text = model.name
let cell = self.bannerView.cellForItem(at: toIndex) as? SPPlayerDetailRecommandCell
self.currentCell = cell
self.play()
}
}
@ -205,7 +229,14 @@ extension SPPlayerDetailRecommandView {
let model = self.dataArr.first
self.videoNameLabel.text = model?.name
CATransaction.setCompletionBlock {
let cell = self.bannerView.cellForItem(at: 0) as? SPPlayerDetailRecommandCell
self.currentCell = cell
self.play()
}
CATransaction.begin()
self.bannerView.reloadData()
CATransaction.commit()
}
}
}

View File

@ -0,0 +1,119 @@
//
// SPVipAlertCell.swift
// MoviaBox
//
// Created by on 2025/5/14.
//
import UIKit
class SPVipAlertCell: SPCollectionViewCell {
var model: SPPayTemplateItem? {
didSet {
moneyLabel.text = "\(model?.currency ?? "")\(model?.price ?? "")"
titleLabel.text = model?.vip_type_key?.getText().capitalizingFirstLetter()
}
}
private lazy var bgView: UIView = {
let view = UIView()
view.backgroundColor = .colorFFFFFF()
view.layer.cornerRadius = 8
view.layer.masksToBounds = true
return view
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .fontBold(ofSize: 18)
label.textColor = .colorCA8D3B()
return label
}()
private lazy var desLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 12)
label.textColor = .colorD0C0AA()
label.text = "movia_vip_membership".localized
return label
}()
private lazy var moneyBgView: SPGradientView = {
let view = SPGradientView()
view.colors = [UIColor.colorA36C2D().cgColor, UIColor.color412D11().cgColor]
view.locations = [0, 1]
view.startPoint = .init(x: 0, y: 0.5)
view.endPoint = .init(x: 1, y: 0.5)
view.layer.cornerRadius = 18
view.layer.masksToBounds = true
return view
}()
private lazy var moneyLabel: UILabel = {
let label = UILabel()
label.font = .fontBold(ofSize: 14)
label.textColor = .colorFFFFFF()
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.layer.cornerRadius = 8
contentView.layer.masksToBounds = true
contentView.backgroundColor = .colorCC9251()
_setupUI()
}
@MainActor required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension SPVipAlertCell {
private func _setupUI() {
contentView.addSubview(bgView)
bgView.addSubview(titleLabel)
bgView.addSubview(desLabel)
bgView.addSubview(moneyBgView)
moneyBgView.addSubview(moneyLabel)
bgView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(1)
make.centerX.equalToSuperview()
make.top.equalToSuperview().offset(1)
make.bottom.equalToSuperview().offset(-5)
}
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(25)
make.top.equalToSuperview().offset(11)
}
desLabel.snp.makeConstraints { make in
make.left.equalTo(titleLabel)
make.top.equalTo(titleLabel.snp.bottom).offset(2)
}
moneyBgView.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.right.equalToSuperview().offset(-25)
make.height.equalTo(36)
}
moneyLabel.snp.makeConstraints { make in
make.centerY.equalToSuperview()
make.centerX.equalToSuperview()
make.left.equalToSuperview().offset(13)
}
}
}

View File

@ -0,0 +1,200 @@
//
// SPVipAlertView.swift
// MoviaBox
//
// Created by on 2025/5/14.
//
import UIKit
class SPVipAlertView: SPAlertView {
///
static var lastAlertDate: Date? = UserDefaults.standard.object(forKey: kSPVipAlertDateDefaultsKey) as? Date {
didSet {
UserDefaults.standard.set(lastAlertDate, forKey: kSPVipAlertDateDefaultsKey)
UserDefaults.standard.synchronize()
}
}
static var isShowAlert: Bool {
guard let lastAlertDate = lastAlertDate else { return true }
let nowDate = Date()
let interval = nowDate.timeIntervalSince1970 - lastAlertDate.timeIntervalSince1970
//
if interval > 60 * 60 {
return true
} else {
return false
}
}
private lazy var dataArr: [SPPayTemplateItem] = []
///
var buyFinishHandle: (() -> Void)?
//MARK: UI
private lazy var bgImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "alert_bg_image_02"))
imageView.isUserInteractionEnabled = true
return imageView
}()
private lazy var vipIconImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "vip_icon_09"))
return imageView
}()
private lazy var vipTitleLabel: UILabel = {
let label = UILabel()
label.font = .fontMedium(ofSize: 16)
label.textColor = .colorFFC591()
label.text = "movia_vip_alert_text_01".localized
return label
}()
private lazy var vipTipLabel1: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 14)
label.textColor = .colorBC7616()
label.text = "movia_vip_alert_text_02".localized
return label
}()
private lazy var vipTipLabel2: UILabel = {
let label = UILabel()
label.font = .fontRegular(ofSize: 12)
label.textColor = .color9C9896()
label.text = "movia_buy_menber_tip".localized
return label
}()
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 293, height: 65)
layout.minimumLineSpacing = 7
return layout
}()
private lazy var collectionView: SPCollectionView = {
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.isScrollEnabled = false
SPVipAlertCell.registerCell(collectionView: collectionView)
return collectionView
}()
private lazy var closeButton: UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
return button
}()
init(dataArr: [SPPayTemplateItem]) {
super.init(frame: .zero)
self.dataArr = dataArr
_setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func show(in view: UIView? = nil) -> Self {
//
SPVipAlertView.lastAlertDate = Date()
return super.show(in: view)
}
@objc private func handleCloseButton() {
self.dismiss()
}
}
extension SPVipAlertView {
private func _setupUI() {
contentView.frame = CGRect(x: 0, y: 0, width: bgImageView.image?.size.width ?? 0, height: (bgImageView.image?.size.height ?? 0) + 66)
self.addSubview(contentView)
contentView.addSubview(bgImageView)
contentView.addSubview(closeButton)
bgImageView.addSubview(vipIconImageView)
bgImageView.addSubview(vipTitleLabel)
bgImageView.addSubview(vipTipLabel1)
bgImageView.addSubview(vipTipLabel2)
bgImageView.addSubview(collectionView)
bgImageView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.bottom.equalToSuperview().offset(-66)
}
closeButton.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview()
}
vipIconImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(42)
make.top.equalToSuperview().offset(57)
}
vipTitleLabel.snp.makeConstraints { make in
make.left.equalTo(vipIconImageView)
make.top.equalTo(vipIconImageView.snp.bottom).offset(11)
}
vipTipLabel1.snp.makeConstraints { make in
make.left.equalTo(vipTitleLabel)
make.top.equalToSuperview().offset(138)
}
vipTipLabel2.snp.makeConstraints { make in
make.bottom.equalToSuperview().offset(-19)
make.centerX.equalToSuperview()
}
collectionView.snp.makeConstraints { make in
make.width.equalTo(collectionViewLayout.itemSize.width)
make.height.equalTo(collectionViewLayout.itemSize.height * 4 + collectionViewLayout.minimumLineSpacing * 3)
make.centerX.equalToSuperview()
make.bottom.equalToSuperview().offset(-50)
}
}
}
//MARK: -------------- UICollectionViewDelegate & UICollectionViewDataSource --------------
extension SPVipAlertView: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = SPVipAlertCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath)
cell.model = dataArr[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.dataArr.count
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let model = dataArr[indexPath.row]
SPIAPManager.manager.startRecharge(model: model, shortPlayId: nil, videoId: nil) { [weak self] finish in
if finish {
self?.buyFinishHandle?()
self?.dismiss()
}
}
}
}

View File

@ -17,13 +17,9 @@ class SPAlertView: UIView {
private var alertHeight: CGFloat = 284
//MARK: UI
private lazy var contentView: UIView = {
private(set) lazy var contentView: UIView = {
let view = UIView()
view.backgroundColor = .color202531()
view.layer.cornerRadius = 18
view.layer.masksToBounds = true
view.layer.borderWidth = 1
view.layer.borderColor = UIColor.color3D4556().cgColor
return view
}()
@ -64,6 +60,10 @@ class SPAlertView: UIView {
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .color000000(alpha: 0.8)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
@ -72,6 +72,8 @@ class SPAlertView: UIView {
init(iconImage: UIImage?, text: String, cancelTitle: String, sureTitle: String) {
super.init(frame: UIScreen.main.bounds)
self.backgroundColor = .color000000(alpha: 0.8)
setContentNormalStyle()
alertHeight = 0
// contentView.frame = CGRect(x: 0, y: 0, width: alertWidth, height: alertHeight)
@ -108,20 +110,35 @@ class SPAlertView: UIView {
}
private func setContentNormalStyle() {
self.contentView.backgroundColor = .color202531()
self.contentView.layer.cornerRadius = 18
self.contentView.layer.masksToBounds = true
self.contentView.layer.borderWidth = 1
self.contentView.layer.borderColor = UIColor.color3D4556().cgColor
}
}
extension SPAlertView {
// MARK: -
@discardableResult func show() -> Self {
SPAlertWindowManager.manager.createWindow().addSubview(self)
@discardableResult
@objc func show(in view: UIView? = nil) -> Self {
var inView: UIView
if let view = view {
inView = view
} else {
inView = SPAlertWindowManager.manager.createWindow()
}
inView.addSubview(self)
self.frame = inView.bounds
creatShowAnimation()
return self
}
func dismiss() {
@objc func dismiss() {
removeFromSuperview()
SPAlertWindowManager.manager.dismissWindow()
}

View File

@ -29,10 +29,16 @@ class SPAlertWindowManager {
}
func dismissWindow() {
count -= 1
if count == 0 {
window?.isHidden = true
window = nil
}
// count -= 1
guard let window = self.window else { return }
if window.subviews.count <= 0 {
window.isHidden = true
self.window = nil
}
// if count == 0 {
// window?.isHidden = true
// window = nil
// }
}
}

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "关闭按钮@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "关闭按钮@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Union@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Union@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "背景图-切图模块@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "背景图-切图模块@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 KiB

View File

@ -112,6 +112,11 @@
"m_complex" = "months";
"q_complex" = "quarter";
"Y_complex" = "years";
"movia_vip_membership" = "VIP Membership";
"movia_vip_alert_text_01" = "Short Drama VIP Exclusive";
"movia_vip_alert_text_02" = "Unlimited access to all series!";
"movia_iap_error_toast_01" = "Invalid in-app purchase";
///没有可恢复购买