1
This commit is contained in:
parent
010ea1cd70
commit
008d5b55b8
11
FAWidget/Assets.xcassets/AccentColor.colorset/Contents.json
Normal file
11
FAWidget/Assets.xcassets/AccentColor.colorset/Contents.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
35
FAWidget/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
35
FAWidget/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
6
FAWidget/Assets.xcassets/Contents.json
Normal file
6
FAWidget/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
84
FAWidget/FAWidget.swift
Normal file
84
FAWidget/FAWidget.swift
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// FAWidget.swift
|
||||||
|
// FAWidget
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct Provider: TimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> SimpleEntry {
|
||||||
|
SimpleEntry(date: Date(), emoji: "😀")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||||
|
let entry = SimpleEntry(date: Date(), emoji: "😀")
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
var entries: [SimpleEntry] = []
|
||||||
|
|
||||||
|
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
|
||||||
|
let currentDate = Date()
|
||||||
|
for hourOffset in 0 ..< 5 {
|
||||||
|
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
||||||
|
let entry = SimpleEntry(date: entryDate, emoji: "😀")
|
||||||
|
entries.append(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func relevances() async -> WidgetRelevances<Void> {
|
||||||
|
// // Generate a list containing the contexts this widget is relevant in.
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimpleEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let emoji: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FAWidgetEntryView : View {
|
||||||
|
var entry: Provider.Entry
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text("Time:")
|
||||||
|
Text(entry.date, style: .time)
|
||||||
|
|
||||||
|
Text("Emoji:")
|
||||||
|
Text(entry.emoji)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FAWidget: Widget {
|
||||||
|
let kind: String = "FAWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
FAWidgetEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
} else {
|
||||||
|
FAWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configurationDisplayName("My Widget")
|
||||||
|
.description("This is an example widget.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#Preview(as: .systemSmall) {
|
||||||
|
// FAWidget()
|
||||||
|
//} timeline: {
|
||||||
|
// SimpleEntry(date: .now, emoji: "😀")
|
||||||
|
// SimpleEntry(date: .now, emoji: "🤩")
|
||||||
|
//}
|
||||||
17
FAWidget/FAWidgetBundle.swift
Normal file
17
FAWidget/FAWidgetBundle.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// FAWidgetBundle.swift
|
||||||
|
// FAWidget
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
@main
|
||||||
|
struct FAWidgetBundle: WidgetBundle {
|
||||||
|
var body: some Widget {
|
||||||
|
// FAWidget()
|
||||||
|
FAWidgetLiveActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
129
FAWidget/FAWidgetLiveActivity.swift
Normal file
129
FAWidget/FAWidgetLiveActivity.swift
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
//
|
||||||
|
// FAWidgetLiveActivity.swift
|
||||||
|
// FAWidget
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ActivityKit
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
|
struct FAWidgetLiveActivity: Widget {
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
ActivityConfiguration(for: ActivityManagerAttributes.self) { context in
|
||||||
|
// 🔹 Live Activity UI(锁屏 & Banner)
|
||||||
|
HStack(spacing: 16) {
|
||||||
|
// 🔹 网络图片
|
||||||
|
if let imageData = try? Data(contentsOf: URL(string: context.state.videoCoverPath)!),
|
||||||
|
let uiImage = UIImage(data: imageData) {
|
||||||
|
Image(uiImage: uiImage)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 108, height: 146)
|
||||||
|
.cornerRadius(8)
|
||||||
|
.clipped()
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Image("logo100")
|
||||||
|
.frame(width: 100, height: 100)
|
||||||
|
.cornerRadius(8)
|
||||||
|
.clipped()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 文本内容
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
HStack {
|
||||||
|
Text("Playing")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
Spacer()
|
||||||
|
Image("logo40")
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(context.state.videoTitle)
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundColor(.black)
|
||||||
|
|
||||||
|
Text("Ep.\(context.state.videoEpisode)")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
// 🔹 按钮
|
||||||
|
Button(action: { print("Watch Now") }) {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Image(systemName: "play.fill")
|
||||||
|
Text("Watch Now")
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 14)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
.background(
|
||||||
|
LinearGradient(colors: [Color.red, Color.orange], startPoint: .leading, endPoint: .trailing)
|
||||||
|
)
|
||||||
|
.foregroundColor(.white)
|
||||||
|
.cornerRadius(20)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.background(RoundedRectangle(cornerRadius: 8).fill(Color.white))
|
||||||
|
.activityBackgroundTint(Color.white)
|
||||||
|
.activitySystemActionForegroundColor(.primary)
|
||||||
|
.widgetURL(URL(string: "fableonapp://liveActivity?short_play_id=\(context.state.videoId)"))
|
||||||
|
|
||||||
|
} dynamicIsland: { context in
|
||||||
|
DynamicIsland {
|
||||||
|
// 🔹 Expanded UI
|
||||||
|
DynamicIslandExpandedRegion(.leading) {
|
||||||
|
VStack (alignment: .center) {
|
||||||
|
Spacer()
|
||||||
|
Image("logo40")
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 40, height: 40)
|
||||||
|
.cornerRadius(5)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicIslandExpandedRegion(.center) {
|
||||||
|
VStack (alignment: .center) {
|
||||||
|
Spacer()
|
||||||
|
Text(context.state.videoTitle)
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicIslandExpandedRegion(.trailing) {
|
||||||
|
VStack (alignment: .center) {
|
||||||
|
Spacer()
|
||||||
|
Text("Ep.\(context.state.videoEpisode)")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} compactLeading: {
|
||||||
|
Image("logo40")
|
||||||
|
} compactTrailing: {
|
||||||
|
Text("Ep.\(context.state.videoEpisode)")
|
||||||
|
.font(.caption2)
|
||||||
|
} minimal: {
|
||||||
|
Image("logo40")
|
||||||
|
}
|
||||||
|
.widgetURL(URL(string: "fableonapp://liveActivity?short_play_id=\(context.state.videoId)"))
|
||||||
|
.keylineTint(Color.red)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
11
FAWidget/Info.plist
Normal file
11
FAWidget/Info.plist
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.widgetkit-extension</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
10
FAWidgetExtension.entitlements
Normal file
10
FAWidgetExtension.entitlements
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.com.hn.qinjiu.fableon</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -227,6 +227,21 @@
|
|||||||
03E9A74E2EB5E0F7000D1067 /* FALanguageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A74D2EB5E0F7000D1067 /* FALanguageModel.swift */; };
|
03E9A74E2EB5E0F7000D1067 /* FALanguageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A74D2EB5E0F7000D1067 /* FALanguageModel.swift */; };
|
||||||
03E9A7502EB5EAC0000D1067 /* FALanguageDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A74F2EB5EAC0000D1067 /* FALanguageDataModel.swift */; };
|
03E9A7502EB5EAC0000D1067 /* FALanguageDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A74F2EB5EAC0000D1067 /* FALanguageDataModel.swift */; };
|
||||||
03E9A7522EB83A58000D1067 /* FAAppStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7512EB83A58000D1067 /* FAAppStartViewController.swift */; };
|
03E9A7522EB83A58000D1067 /* FAAppStartViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7512EB83A58000D1067 /* FAAppStartViewController.swift */; };
|
||||||
|
03E9A75E2EC19101000D1067 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 03E9A7572EC19101000D1067 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
03E9A7682EC19110000D1067 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7652EC19110000D1067 /* NotificationService.swift */; };
|
||||||
|
03E9A76F2EC1950F000D1067 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E9A76E2EC1950F000D1067 /* WidgetKit.framework */; };
|
||||||
|
03E9A7712EC1950F000D1067 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 03E9A7702EC1950F000D1067 /* SwiftUI.framework */; };
|
||||||
|
03E9A77E2EC19510000D1067 /* FAWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 03E9A76D2EC1950F000D1067 /* FAWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
03E9A7892EC19516000D1067 /* FAWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7842EC19516000D1067 /* FAWidget.swift */; };
|
||||||
|
03E9A78A2EC19516000D1067 /* FAWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7852EC19516000D1067 /* FAWidgetBundle.swift */; };
|
||||||
|
03E9A78B2EC19516000D1067 /* FAWidgetLiveActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7862EC19516000D1067 /* FAWidgetLiveActivity.swift */; };
|
||||||
|
03E9A78C2EC19516000D1067 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 03E9A7832EC19516000D1067 /* Assets.xcassets */; };
|
||||||
|
03E9A7902EC1B007000D1067 /* FAActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A78F2EC1B007000D1067 /* FAActivityManager.swift */; };
|
||||||
|
03E9A7912EC1B007000D1067 /* FAActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A78F2EC1B007000D1067 /* FAActivityManager.swift */; };
|
||||||
|
03E9A7942EC1B24E000D1067 /* UIImage+FAAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7932EC1B24E000D1067 /* UIImage+FAAdd.swift */; };
|
||||||
|
03E9A7972EC2C7DF000D1067 /* FAHomeNewTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7962EC2C7DF000D1067 /* FAHomeNewTransformer.swift */; };
|
||||||
|
03E9A79A2EC2C8FD000D1067 /* NSNumber+FAAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A7992EC2C8F3000D1067 /* NSNumber+FAAdd.swift */; };
|
||||||
|
03E9A79C2EC31AD0000D1067 /* FAFeedbackCountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E9A79B2EC31AD0000D1067 /* FAFeedbackCountModel.swift */; };
|
||||||
B86XD3O90WO2R4725L084287 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */; };
|
B86XD3O90WO2R4725L084287 /* Pods_Fableon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */; };
|
||||||
F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38E33739F391364D0151P7Z /* ZStreamCell.swift */; };
|
F3019606DA7P36H41G408X13 /* ZStreamCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F38E33739F391364D0151P7Z /* ZStreamCell.swift */; };
|
||||||
F30470W590T8274E1642349G /* CControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32MR5F8X6Q3HSZ560BD0159 /* CControlCell.swift */; };
|
F30470W590T8274E1642349G /* CControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F32MR5F8X6Q3HSZ560BD0159 /* CControlCell.swift */; };
|
||||||
@ -333,6 +348,38 @@
|
|||||||
F3ZT3I4VAGB5405FWL36UW12 /* ZFGEtworkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3342A2631Z4ZPCT74M73CK1 /* ZFGEtworkCell.swift */; };
|
F3ZT3I4VAGB5405FWL36UW12 /* ZFGEtworkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3342A2631Z4ZPCT74M73CK1 /* ZFGEtworkCell.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
03E9A75C2EC19101000D1067 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = F3LK276P33H73Y39H9X6VTDI /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 03E9A7562EC19101000D1067;
|
||||||
|
remoteInfo = NotificationService;
|
||||||
|
};
|
||||||
|
03E9A77C2EC19510000D1067 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = F3LK276P33H73Y39H9X6VTDI /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 03E9A76C2EC1950F000D1067;
|
||||||
|
remoteInfo = FAWidgetExtension;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
03E9A7632EC19101000D1067 /* Embed Foundation Extensions */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 13;
|
||||||
|
files = (
|
||||||
|
03E9A75E2EC19101000D1067 /* NotificationService.appex in Embed Foundation Extensions */,
|
||||||
|
03E9A77E2EC19510000D1067 /* FAWidgetExtension.appex in Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
name = "Embed Foundation Extensions";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
031FDEAB2EAF05FB00F4CAC7 /* FAStoreVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreVipCell.swift; sourceTree = "<group>"; };
|
031FDEAB2EAF05FB00F4CAC7 /* FAStoreVipCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAStoreVipCell.swift; sourceTree = "<group>"; };
|
||||||
031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABuyRecordsModel.swift; sourceTree = "<group>"; };
|
031FDEAD2EB093B100F4CAC7 /* FABuyRecordsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FABuyRecordsModel.swift; sourceTree = "<group>"; };
|
||||||
@ -552,6 +599,23 @@
|
|||||||
03E9A74D2EB5E0F7000D1067 /* FALanguageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALanguageModel.swift; sourceTree = "<group>"; };
|
03E9A74D2EB5E0F7000D1067 /* FALanguageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALanguageModel.swift; sourceTree = "<group>"; };
|
||||||
03E9A74F2EB5EAC0000D1067 /* FALanguageDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALanguageDataModel.swift; sourceTree = "<group>"; };
|
03E9A74F2EB5EAC0000D1067 /* FALanguageDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FALanguageDataModel.swift; sourceTree = "<group>"; };
|
||||||
03E9A7512EB83A58000D1067 /* FAAppStartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAppStartViewController.swift; sourceTree = "<group>"; };
|
03E9A7512EB83A58000D1067 /* FAAppStartViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAAppStartViewController.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7572EC19101000D1067 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
03E9A7642EC19110000D1067 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
03E9A7652EC19110000D1067 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A76D2EC1950F000D1067 /* FAWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FAWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
03E9A76E2EC1950F000D1067 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||||
|
03E9A7702EC1950F000D1067 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
|
03E9A7832EC19516000D1067 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
03E9A7842EC19516000D1067 /* FAWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWidget.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7852EC19516000D1067 /* FAWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWidgetBundle.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7862EC19516000D1067 /* FAWidgetLiveActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAWidgetLiveActivity.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7872EC19516000D1067 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
03E9A78F2EC1B007000D1067 /* FAActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAActivityManager.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7922EC1B0BC000D1067 /* FAWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FAWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||||
|
03E9A7932EC1B24E000D1067 /* UIImage+FAAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+FAAdd.swift"; sourceTree = "<group>"; };
|
||||||
|
03E9A7962EC2C7DF000D1067 /* FAHomeNewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAHomeNewTransformer.swift; sourceTree = "<group>"; };
|
||||||
|
03E9A7992EC2C8F3000D1067 /* NSNumber+FAAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSNumber+FAAdd.swift"; sourceTree = "<group>"; };
|
||||||
|
03E9A79B2EC31AD0000D1067 /* FAFeedbackCountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FAFeedbackCountModel.swift; sourceTree = "<group>"; };
|
||||||
19196I43BR665O55RD205171 /* Pods-Fableon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.debug.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.debug.xcconfig"; sourceTree = "<group>"; };
|
19196I43BR665O55RD205171 /* Pods-Fableon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.debug.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fableon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Fableon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
DCD59738B6J31K33W4Z524S0 /* Pods-Fableon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.release.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.release.xcconfig"; sourceTree = "<group>"; };
|
DCD59738B6J31K33W4Z524S0 /* Pods-Fableon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Fableon.release.xcconfig"; path = "Target Support Files/Pods-Fableon/Pods-Fableon.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
@ -663,6 +727,22 @@
|
|||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
03E9A7542EC19101000D1067 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
03E9A76A2EC1950F000D1067 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
03E9A7712EC1950F000D1067 /* SwiftUI.framework in Frameworks */,
|
||||||
|
03E9A76F2EC1950F000D1067 /* WidgetKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
F37182X6857153T873504S9J /* Frameworks */ = {
|
F37182X6857153T873504S9J /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -809,6 +889,8 @@
|
|||||||
03E239772EAA1A29004A8CEC /* UIStackView+FAAdd.swift */,
|
03E239772EAA1A29004A8CEC /* UIStackView+FAAdd.swift */,
|
||||||
03E239782EAA1A29004A8CEC /* UIView+FAAdd.swift */,
|
03E239782EAA1A29004A8CEC /* UIView+FAAdd.swift */,
|
||||||
03E239792EAA1A29004A8CEC /* UserDefaults+FAAdd.swift */,
|
03E239792EAA1A29004A8CEC /* UserDefaults+FAAdd.swift */,
|
||||||
|
03E9A7932EC1B24E000D1067 /* UIImage+FAAdd.swift */,
|
||||||
|
03E9A7992EC2C8F3000D1067 /* NSNumber+FAAdd.swift */,
|
||||||
);
|
);
|
||||||
path = Extension;
|
path = Extension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -897,6 +979,7 @@
|
|||||||
03E239BD2EAA1A4E004A8CEC /* FAHomeItem.swift */,
|
03E239BD2EAA1A4E004A8CEC /* FAHomeItem.swift */,
|
||||||
03E239BE2EAA1A4E004A8CEC /* FAHomeModuleItem.swift */,
|
03E239BE2EAA1A4E004A8CEC /* FAHomeModuleItem.swift */,
|
||||||
03E239BF2EAA1A4E004A8CEC /* FAPopularModel.swift */,
|
03E239BF2EAA1A4E004A8CEC /* FAPopularModel.swift */,
|
||||||
|
03E9A7962EC2C7DF000D1067 /* FAHomeNewTransformer.swift */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -988,6 +1071,7 @@
|
|||||||
children = (
|
children = (
|
||||||
03E239ED2EAA1A4E004A8CEC /* FAMeItemModel.swift */,
|
03E239ED2EAA1A4E004A8CEC /* FAMeItemModel.swift */,
|
||||||
03E9A7412EB4A603000D1067 /* FAVersionUpdateModel.swift */,
|
03E9A7412EB4A603000D1067 /* FAVersionUpdateModel.swift */,
|
||||||
|
03E9A79B2EC31AD0000D1067 /* FAFeedbackCountModel.swift */,
|
||||||
);
|
);
|
||||||
path = M;
|
path = M;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1212,6 +1296,7 @@
|
|||||||
03E23A962EAA1A65004A8CEC /* Libs */ = {
|
03E23A962EAA1A65004A8CEC /* Libs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
03E9A78E2EC1AFEA000D1067 /* ActivityManager */,
|
||||||
031FDEE22EB3487700F4CAC7 /* Alert */,
|
031FDEE22EB3487700F4CAC7 /* Alert */,
|
||||||
039CE6122EAB0DE1007B5EED /* FAIap */,
|
039CE6122EAB0DE1007B5EED /* FAIap */,
|
||||||
039CE60F2EAB0D2D007B5EED /* JXIAPManager */,
|
039CE60F2EAB0D2D007B5EED /* JXIAPManager */,
|
||||||
@ -1302,10 +1387,41 @@
|
|||||||
path = WaterfallFlowLayout;
|
path = WaterfallFlowLayout;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
03E9A7662EC19110000D1067 /* NotificationService */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
03E9A7642EC19110000D1067 /* Info.plist */,
|
||||||
|
03E9A7652EC19110000D1067 /* NotificationService.swift */,
|
||||||
|
);
|
||||||
|
path = NotificationService;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
03E9A7882EC19516000D1067 /* FAWidget */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
03E9A7832EC19516000D1067 /* Assets.xcassets */,
|
||||||
|
03E9A7842EC19516000D1067 /* FAWidget.swift */,
|
||||||
|
03E9A7852EC19516000D1067 /* FAWidgetBundle.swift */,
|
||||||
|
03E9A7862EC19516000D1067 /* FAWidgetLiveActivity.swift */,
|
||||||
|
03E9A7872EC19516000D1067 /* Info.plist */,
|
||||||
|
);
|
||||||
|
path = FAWidget;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
03E9A78E2EC1AFEA000D1067 /* ActivityManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
03E9A78F2EC1B007000D1067 /* FAActivityManager.swift */,
|
||||||
|
);
|
||||||
|
path = ActivityManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
612P1QES0606A2642109V515 /* Frameworks */ = {
|
612P1QES0606A2642109V515 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */,
|
C4THBP0A1283PFXW440071Q5 /* Pods_Fableon.framework */,
|
||||||
|
03E9A76E2EC1950F000D1067 /* WidgetKit.framework */,
|
||||||
|
03E9A7702EC1950F000D1067 /* SwiftUI.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1343,7 +1459,10 @@
|
|||||||
F31ABI705806054356280I22 = {
|
F31ABI705806054356280I22 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
03E9A7922EC1B0BC000D1067 /* FAWidgetExtension.entitlements */,
|
||||||
F3YR32SS1P8731297KD665X5 /* Fableon */,
|
F3YR32SS1P8731297KD665X5 /* Fableon */,
|
||||||
|
03E9A7662EC19110000D1067 /* NotificationService */,
|
||||||
|
03E9A7882EC19516000D1067 /* FAWidget */,
|
||||||
F3B536I6734E05L319J6654P /* Products */,
|
F3B536I6734E05L319J6654P /* Products */,
|
||||||
A9370738344P8616G77589I7 /* Pods */,
|
A9370738344P8616G77589I7 /* Pods */,
|
||||||
612P1QES0606A2642109V515 /* Frameworks */,
|
612P1QES0606A2642109V515 /* Frameworks */,
|
||||||
@ -1634,6 +1753,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
F36676EN936M89B15P51177W /* Fableon.app */,
|
F36676EN936M89B15P51177W /* Fableon.app */,
|
||||||
|
03E9A7572EC19101000D1067 /* NotificationService.appex */,
|
||||||
|
03E9A76D2EC1950F000D1067 /* FAWidgetExtension.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1788,6 +1909,40 @@
|
|||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
03E9A7562EC19101000D1067 /* NotificationService */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 03E9A7602EC19101000D1067 /* Build configuration list for PBXNativeTarget "NotificationService" */;
|
||||||
|
buildPhases = (
|
||||||
|
03E9A7532EC19101000D1067 /* Sources */,
|
||||||
|
03E9A7542EC19101000D1067 /* Frameworks */,
|
||||||
|
03E9A7552EC19101000D1067 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = NotificationService;
|
||||||
|
productName = NotificationService;
|
||||||
|
productReference = 03E9A7572EC19101000D1067 /* NotificationService.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
|
03E9A76C2EC1950F000D1067 /* FAWidgetExtension */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 03E9A7802EC19510000D1067 /* Build configuration list for PBXNativeTarget "FAWidgetExtension" */;
|
||||||
|
buildPhases = (
|
||||||
|
03E9A7692EC1950F000D1067 /* Sources */,
|
||||||
|
03E9A76A2EC1950F000D1067 /* Frameworks */,
|
||||||
|
03E9A76B2EC1950F000D1067 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = FAWidgetExtension;
|
||||||
|
productName = FAWidgetExtension;
|
||||||
|
productReference = 03E9A76D2EC1950F000D1067 /* FAWidgetExtension.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
F3F6B3Q1BI331E859340M109 /* Fableon */ = {
|
F3F6B3Q1BI331E859340M109 /* Fableon */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = F3511CV60KB1225F8K46932G /* Build configuration list for PBXNativeTarget "Fableon" */;
|
buildConfigurationList = F3511CV60KB1225F8K46932G /* Build configuration list for PBXNativeTarget "Fableon" */;
|
||||||
@ -1797,10 +1952,13 @@
|
|||||||
F37182X6857153T873504S9J /* Frameworks */,
|
F37182X6857153T873504S9J /* Frameworks */,
|
||||||
F3T938414J234X46539JR019 /* Resources */,
|
F3T938414J234X46539JR019 /* Resources */,
|
||||||
4809W21R638Z15866LWB2041 /* [CP] Embed Pods Frameworks */,
|
4809W21R638Z15866LWB2041 /* [CP] Embed Pods Frameworks */,
|
||||||
|
03E9A7632EC19101000D1067 /* Embed Foundation Extensions */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
03E9A75D2EC19101000D1067 /* PBXTargetDependency */,
|
||||||
|
03E9A77D2EC19510000D1067 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Fableon;
|
name = Fableon;
|
||||||
productName = Fableon;
|
productName = Fableon;
|
||||||
@ -1814,9 +1972,15 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1640;
|
LastSwiftUpdateCheck = 2600;
|
||||||
LastUpgradeCheck = 1640;
|
LastUpgradeCheck = 1640;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
03E9A7562EC19101000D1067 = {
|
||||||
|
CreatedOnToolsVersion = 26.0.1;
|
||||||
|
};
|
||||||
|
03E9A76C2EC1950F000D1067 = {
|
||||||
|
CreatedOnToolsVersion = 26.0.1;
|
||||||
|
};
|
||||||
F3F6B3Q1BI331E859340M109 = {
|
F3F6B3Q1BI331E859340M109 = {
|
||||||
CreatedOnToolsVersion = 16.4;
|
CreatedOnToolsVersion = 16.4;
|
||||||
LastSwiftMigration = 1640;
|
LastSwiftMigration = 1640;
|
||||||
@ -1842,11 +2006,28 @@
|
|||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
F3F6B3Q1BI331E859340M109 /* Fableon */,
|
F3F6B3Q1BI331E859340M109 /* Fableon */,
|
||||||
|
03E9A7562EC19101000D1067 /* NotificationService */,
|
||||||
|
03E9A76C2EC1950F000D1067 /* FAWidgetExtension */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
||||||
/* Begin PBXResourcesBuildPhase section */
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
03E9A7552EC19101000D1067 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
03E9A76B2EC1950F000D1067 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
03E9A78C2EC19516000D1067 /* Assets.xcassets in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
F3T938414J234X46539JR019 /* Resources */ = {
|
F3T938414J234X46539JR019 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -1937,12 +2118,32 @@
|
|||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
03E9A7532EC19101000D1067 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
03E9A7682EC19110000D1067 /* NotificationService.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
03E9A7692EC1950F000D1067 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
03E9A7892EC19516000D1067 /* FAWidget.swift in Sources */,
|
||||||
|
03E9A78A2EC19516000D1067 /* FAWidgetBundle.swift in Sources */,
|
||||||
|
03E9A7912EC1B007000D1067 /* FAActivityManager.swift in Sources */,
|
||||||
|
03E9A78B2EC19516000D1067 /* FAWidgetLiveActivity.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
F3A707N33187J9XN3E985764 /* Sources */ = {
|
F3A707N33187J9XN3E985764 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
F39C9Y266RT4H0109L9T1807 /* LKVRecommendedHomeView.swift in Sources */,
|
F39C9Y266RT4H0109L9T1807 /* LKVRecommendedHomeView.swift in Sources */,
|
||||||
F37S2W333F5881I12F59EXJ0 /* KCFAlignment.swift in Sources */,
|
F37S2W333F5881I12F59EXJ0 /* KCFAlignment.swift in Sources */,
|
||||||
|
03E9A79C2EC31AD0000D1067 /* FAFeedbackCountModel.swift in Sources */,
|
||||||
F34Y5K0497T0B7D95Q1F4304 /* VRResult.swift in Sources */,
|
F34Y5K0497T0B7D95Q1F4304 /* VRResult.swift in Sources */,
|
||||||
F3Q1B8O8164TYQ9724T34V29 /* OACAbleView.swift in Sources */,
|
F3Q1B8O8164TYQ9724T34V29 /* OACAbleView.swift in Sources */,
|
||||||
F36MZ39RQ295569BV1915908 /* FOMptyView.swift in Sources */,
|
F36MZ39RQ295569BV1915908 /* FOMptyView.swift in Sources */,
|
||||||
@ -1984,6 +2185,7 @@
|
|||||||
F3362Y34741Z8AE0YP4S2Y54 /* YORecommended.swift in Sources */,
|
F3362Y34741Z8AE0YP4S2Y54 /* YORecommended.swift in Sources */,
|
||||||
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */,
|
03E239632EAA1945004A8CEC /* AppDelegate+FAConfig.swift in Sources */,
|
||||||
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */,
|
03E239642EAA1945004A8CEC /* AppDelegate.swift in Sources */,
|
||||||
|
03E9A7972EC2C7DF000D1067 /* FAHomeNewTransformer.swift in Sources */,
|
||||||
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
03E239652EAA1945004A8CEC /* SceneDelegate.swift in Sources */,
|
||||||
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */,
|
039CE6092EAA2F71007B5EED /* FAAdjustStateManager.swift in Sources */,
|
||||||
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
F333U95746V7VK13QI9275B3 /* UMenuTransformerCell.swift in Sources */,
|
||||||
@ -2089,6 +2291,7 @@
|
|||||||
03E23A5C2EAA1A4E004A8CEC /* FAGenresListViewController.swift in Sources */,
|
03E23A5C2EAA1A4E004A8CEC /* FAGenresListViewController.swift in Sources */,
|
||||||
03E23A5D2EAA1A4E004A8CEC /* FARecommendViewModel.swift in Sources */,
|
03E23A5D2EAA1A4E004A8CEC /* FARecommendViewModel.swift in Sources */,
|
||||||
03E23A5E2EAA1A4E004A8CEC /* FAHomeMustSeeContentView.swift in Sources */,
|
03E23A5E2EAA1A4E004A8CEC /* FAHomeMustSeeContentView.swift in Sources */,
|
||||||
|
03E9A7902EC1B007000D1067 /* FAActivityManager.swift in Sources */,
|
||||||
03E23A5F2EAA1A4E004A8CEC /* FAEpSelectorCell.swift in Sources */,
|
03E23A5F2EAA1A4E004A8CEC /* FAEpSelectorCell.swift in Sources */,
|
||||||
031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */,
|
031FDEEC2EB35DF600F4CAC7 /* FACoinsPackAlert.swift in Sources */,
|
||||||
03E23A602EAA1A4E004A8CEC /* FASearchResultView.swift in Sources */,
|
03E23A602EAA1A4E004A8CEC /* FASearchResultView.swift in Sources */,
|
||||||
@ -2111,6 +2314,7 @@
|
|||||||
03E23A6E2EAA1A4E004A8CEC /* FARankingListCell.swift in Sources */,
|
03E23A6E2EAA1A4E004A8CEC /* FARankingListCell.swift in Sources */,
|
||||||
031FDED22EB2F69200F4CAC7 /* FALoginView.swift in Sources */,
|
031FDED22EB2F69200F4CAC7 /* FALoginView.swift in Sources */,
|
||||||
03E23A6F2EAA1A4E004A8CEC /* FAHomeBannerCell.swift in Sources */,
|
03E23A6F2EAA1A4E004A8CEC /* FAHomeBannerCell.swift in Sources */,
|
||||||
|
03E9A79A2EC2C8FD000D1067 /* NSNumber+FAAdd.swift in Sources */,
|
||||||
03E23A702EAA1A4E004A8CEC /* FAGenresCell.swift in Sources */,
|
03E23A702EAA1A4E004A8CEC /* FAGenresCell.swift in Sources */,
|
||||||
03E23A712EAA1A4E004A8CEC /* FAHomeSectionTitleView.swift in Sources */,
|
03E23A712EAA1A4E004A8CEC /* FAHomeSectionTitleView.swift in Sources */,
|
||||||
03E23A722EAA1A4E004A8CEC /* FASettingViewController.swift in Sources */,
|
03E23A722EAA1A4E004A8CEC /* FASettingViewController.swift in Sources */,
|
||||||
@ -2206,6 +2410,7 @@
|
|||||||
03E239AF2EAA1A29004A8CEC /* FAAPI.swift in Sources */,
|
03E239AF2EAA1A29004A8CEC /* FAAPI.swift in Sources */,
|
||||||
031FDECA2EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift in Sources */,
|
031FDECA2EB1F8F200F4CAC7 /* FACoinsPackReceiveModel.swift in Sources */,
|
||||||
03E239B02EAA1A29004A8CEC /* FAWebView.swift in Sources */,
|
03E239B02EAA1A29004A8CEC /* FAWebView.swift in Sources */,
|
||||||
|
03E9A7942EC1B24E000D1067 /* UIImage+FAAdd.swift in Sources */,
|
||||||
039CE61C2EAB0F29007B5EED /* FAIapOrderModel.swift in Sources */,
|
039CE61C2EAB0F29007B5EED /* FAIapOrderModel.swift in Sources */,
|
||||||
03E9A7522EB83A58000D1067 /* FAAppStartViewController.swift in Sources */,
|
03E9A7522EB83A58000D1067 /* FAAppStartViewController.swift in Sources */,
|
||||||
03E239B12EAA1A29004A8CEC /* FANetworkMonitor.swift in Sources */,
|
03E239B12EAA1A29004A8CEC /* FANetworkMonitor.swift in Sources */,
|
||||||
@ -2232,6 +2437,19 @@
|
|||||||
};
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
03E9A75D2EC19101000D1067 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 03E9A7562EC19101000D1067 /* NotificationService */;
|
||||||
|
targetProxy = 03E9A75C2EC19101000D1067 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
03E9A77D2EC19510000D1067 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 03E9A76C2EC1950F000D1067 /* FAWidgetExtension */;
|
||||||
|
targetProxy = 03E9A77C2EC19510000D1067 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
F3A0557617AU32W3L218F159 /* Localizable.strings */ = {
|
F3A0557617AU32W3L218F159 /* Localizable.strings */ = {
|
||||||
isa = PBXVariantGroup;
|
isa = PBXVariantGroup;
|
||||||
@ -2252,6 +2470,132 @@
|
|||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
03E9A7612EC19101000D1067 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon.NotificationService;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
03E9A7622EC19101000D1067 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = NotificationService;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon.NotificationService;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
03E9A7812EC19510000D1067 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = FAWidgetExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = FAWidget/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = FAWidget;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon.FAWidget;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
03E9A7822EC19510000D1067 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = FAWidgetExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 6XALB8RSYF;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = FAWidget/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = FAWidget;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 16.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon.FAWidget;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
F33W2S46100182427H2605Y0 /* Release */ = {
|
F33W2S46100182427H2605Y0 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@ -2391,6 +2735,7 @@
|
|||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
|
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||||
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||||
@ -2402,7 +2747,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1;
|
MARKETING_VERSION = 1.0.4;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
@ -2432,6 +2777,7 @@
|
|||||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||||
|
INFOPLIST_KEY_NSSupportsLiveActivities = YES;
|
||||||
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||||
@ -2443,7 +2789,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.1;
|
MARKETING_VERSION = 1.0.4;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
PRODUCT_BUNDLE_IDENTIFIER = com.hn.qinjiu.fableon;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||||
@ -2458,6 +2804,24 @@
|
|||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
03E9A7602EC19101000D1067 /* Build configuration list for PBXNativeTarget "NotificationService" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
03E9A7612EC19101000D1067 /* Debug */,
|
||||||
|
03E9A7622EC19101000D1067 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
03E9A7802EC19510000D1067 /* Build configuration list for PBXNativeTarget "FAWidgetExtension" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
03E9A7812EC19510000D1067 /* Debug */,
|
||||||
|
03E9A7822EC19510000D1067 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
F3511CV60KB1225F8K46932G /* Build configuration list for PBXNativeTarget "Fableon" */ = {
|
F3511CV60KB1225F8K46932G /* Build configuration list for PBXNativeTarget "Fableon" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@ -42,7 +42,8 @@ extension SceneDelegate {
|
|||||||
|
|
||||||
guard FANetworkMonitor.manager.isReachable == true,
|
guard FANetworkMonitor.manager.isReachable == true,
|
||||||
manager.isOpenApp,
|
manager.isOpenApp,
|
||||||
manager.idfaAuthorizationFinish //idfa授权完成
|
manager.idfaAuthorizationFinish, //idfa授权完成
|
||||||
|
manager.upgradeAlertFinish
|
||||||
else {
|
else {
|
||||||
if let webpageURL = webpageURL {
|
if let webpageURL = webpageURL {
|
||||||
manager.webpageURL = webpageURL
|
manager.webpageURL = webpageURL
|
||||||
|
|||||||
@ -22,16 +22,16 @@ extension SceneDelegate {
|
|||||||
|
|
||||||
center.requestAuthorization(options: [.badge, .sound, .alert]) { grant, error in
|
center.requestAuthorization(options: [.badge, .sound, .alert]) { grant, error in
|
||||||
if !grant {
|
if !grant {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||||
self.showApnsAlert()
|
self.showApnsAlert()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
FAAdjustStateManager.manager.apnsFinish()
|
||||||
|
|
||||||
}
|
}
|
||||||
FAAdjustStateManager.manager.apnsAuthorizationFinish = true
|
|
||||||
|
|
||||||
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
|
||||||
|
|
||||||
|
|
||||||
FATool.requestIDFAAuthorization(nil)
|
|
||||||
FAStatAPI.uploadApnsAuthorizationStatus()
|
FAStatAPI.uploadApnsAuthorizationStatus()
|
||||||
}
|
}
|
||||||
UIApplication.shared.registerForRemoteNotifications()
|
UIApplication.shared.registerForRemoteNotifications()
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import YYText
|
import YYText
|
||||||
import MJRefresh
|
import MJRefresh
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||||
|
|
||||||
@ -62,6 +63,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
|
|
||||||
func sceneDidEnterBackground(_ scene: UIScene) {
|
func sceneDidEnterBackground(_ scene: UIScene) {
|
||||||
FAAdjustStateManager.manager.allowOpenMessage = true
|
FAAdjustStateManager.manager.allowOpenMessage = true
|
||||||
|
if #available(iOS 16.1, *) {
|
||||||
|
startWidgeLiveActivity()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -123,10 +127,18 @@ extension SceneDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func networkStatusDidChangeNotification() {
|
@objc private func networkStatusDidChangeNotification() {
|
||||||
|
let localizedData = FALanguageManager.manager.languageData ?? [:]
|
||||||
|
|
||||||
if FANetworkMonitor.manager.isReachable == true {
|
if FANetworkMonitor.manager.isReachable == true {
|
||||||
|
handleOnLine()
|
||||||
FATool.requestIDFAAuthorization(nil)
|
FATool.requestIDFAAuthorization(nil)
|
||||||
self.retryHandleOpenAppMessage()
|
self.retryHandleOpenAppMessage()
|
||||||
FAIapManager.manager.preloadingProducts()
|
FAIapManager.manager.preloadingProducts()
|
||||||
|
|
||||||
|
///缺少语言数据,重新获取语言数据
|
||||||
|
if localizedData.isEmpty {
|
||||||
|
self.startApp()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,4 +146,35 @@ extension SceneDelegate {
|
|||||||
MJRefreshConfig.default.languageCode = FALanguageManager.manager.mjLanguageKey
|
MJRefreshConfig.default.languageCode = FALanguageManager.manager.mjLanguageKey
|
||||||
setTabBarController()
|
setTabBarController()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.1, *)
|
||||||
|
private func startWidgeLiveActivity() {
|
||||||
|
|
||||||
|
guard let model = FATool.widgetLiveActivityModel, let imageUrl = URL(string: model.image_url ?? "") else { return }
|
||||||
|
|
||||||
|
KingfisherManager.shared.retrieveImage(with: imageUrl) { result in
|
||||||
|
switch result {
|
||||||
|
case .success(let imageResult):
|
||||||
|
let image = imageResult.image
|
||||||
|
|
||||||
|
guard let data = image.compressImageSize(toByte: 9 * 1024) else { return }
|
||||||
|
guard let filePath = FAActivityManager.coverFileUrl else { return }
|
||||||
|
|
||||||
|
do {
|
||||||
|
try data.write(to: filePath, options: .atomic)
|
||||||
|
|
||||||
|
FAActivityManager.liveActivity(with: model.name ?? "",
|
||||||
|
videoId: model.short_play_id ?? "",
|
||||||
|
videoEpisode: model.current_episode ?? "")
|
||||||
|
} catch {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,11 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>applinks:fableon.go.link</string>
|
<string>applinks:fableon.go.link</string>
|
||||||
<string>applinks:kuzt.adj.st</string>
|
<string>applinks:kuzt.adj.st</string>
|
||||||
|
<string>applinks:www.hbqinjiu.com</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.com.hn.qinjiu.fableon</string>
|
||||||
</array>
|
</array>
|
||||||
<key>keychain-access-groups</key>
|
<key>keychain-access-groups</key>
|
||||||
<array/>
|
<array/>
|
||||||
|
|||||||
@ -12,6 +12,10 @@ class FANavigationController: UINavigationController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
if #available(iOS 26.0, *) {
|
||||||
|
self.interactiveContentPopGestureRecognizer?.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
fd_fullscreenPopGestureRecognizer.isEnabled = true
|
fd_fullscreenPopGestureRecognizer.isEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
Fableon/Object/Base/Extension/NSNumber+FAAdd.swift
Normal file
25
Fableon/Object/Base/Extension/NSNumber+FAAdd.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// NSNumber+FAAdd.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension NSNumber {
|
||||||
|
|
||||||
|
func toString(maximumFractionDigits: Int = 10, minimumFractionDigits: Int? = nil, roundingMode: NumberFormatter.RoundingMode? = nil) -> String {
|
||||||
|
let formatter = NumberFormatter()
|
||||||
|
formatter.minimumIntegerDigits = 1
|
||||||
|
formatter.maximumFractionDigits = maximumFractionDigits
|
||||||
|
if let minimumFractionDigits = minimumFractionDigits {
|
||||||
|
formatter.minimumFractionDigits = minimumFractionDigits
|
||||||
|
}
|
||||||
|
if let roundingMode = roundingMode {
|
||||||
|
formatter.roundingMode = roundingMode
|
||||||
|
}
|
||||||
|
formatter.numberStyle = .none
|
||||||
|
return formatter.string(from: self) ?? "0"
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Fableon/Object/Base/Extension/UIImage+FAAdd.swift
Normal file
68
Fableon/Object/Base/Extension/UIImage+FAAdd.swift
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
//
|
||||||
|
// UIImage+FAAdd.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
extension UIImage {
|
||||||
|
/// 根据图片大小计算压缩率
|
||||||
|
static func getCompressRate(imageSize: CGFloat, targetSize: CGFloat) -> CGFloat {
|
||||||
|
var rate = Int(imageSize / targetSize)
|
||||||
|
rate = (rate == 0) ? 1 : rate
|
||||||
|
|
||||||
|
// 默认压缩范围
|
||||||
|
let maxCompressRate: CGFloat = 0.8
|
||||||
|
let minCompressRate: CGFloat = 0.2
|
||||||
|
|
||||||
|
// 反比例压缩函数
|
||||||
|
var compressRate = 0.8 / CGFloat(rate)
|
||||||
|
|
||||||
|
// 限制范围
|
||||||
|
compressRate = min(max(compressRate, minCompressRate), maxCompressRate)
|
||||||
|
return compressRate
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 压缩图片到指定字节大小(JPEG格式)
|
||||||
|
func compressImageSize(toByte maxLength: Int) -> Data? {
|
||||||
|
let image = self
|
||||||
|
|
||||||
|
// 初次压缩(质量)
|
||||||
|
guard var data = image.jpegData(compressionQuality: 1.0) else { return nil }
|
||||||
|
if data.count < maxLength {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
var compressRate = UIImage.getCompressRate(imageSize: CGFloat(data.count), targetSize: CGFloat(maxLength))
|
||||||
|
data = image.jpegData(compressionQuality: compressRate) ?? data
|
||||||
|
if data.count < maxLength {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次通过缩放降低体积
|
||||||
|
var resultImage = UIImage(data: data) ?? image
|
||||||
|
var lastDataLength = 0
|
||||||
|
|
||||||
|
while data.count > maxLength && data.count != lastDataLength {
|
||||||
|
lastDataLength = data.count
|
||||||
|
let ratio = CGFloat(maxLength) / CGFloat(data.count)
|
||||||
|
let newWidth = max(Int(resultImage.size.width * sqrt(ratio)), 10)
|
||||||
|
let newHeight = max(Int(resultImage.size.height * sqrt(ratio)), 10)
|
||||||
|
let newSize = CGSize(width: newWidth, height: newHeight)
|
||||||
|
|
||||||
|
if newSize.width < 10 || newSize.height < 10 { break }
|
||||||
|
|
||||||
|
// 绘制新尺寸图片
|
||||||
|
UIGraphicsBeginImageContext(newSize)
|
||||||
|
resultImage.draw(in: CGRect(origin: .zero, size: newSize))
|
||||||
|
resultImage = UIGraphicsGetImageFromCurrentImageContext() ?? resultImage
|
||||||
|
UIGraphicsEndImageContext()
|
||||||
|
|
||||||
|
data = resultImage.jpegData(compressionQuality: compressRate) ?? data
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,12 +18,11 @@ extension UIScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fa_addRefreshFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
|
func fa_addRefreshFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) {
|
||||||
let footer = MJRefreshAutoNormalFooter(refreshingBlock: {
|
self.mj_footer = MJRefreshBackNormalFooter(refreshingBlock: {
|
||||||
block?()
|
block?()
|
||||||
})
|
})
|
||||||
footer.ignoredScrollViewContentInsetBottom = insetBottom
|
|
||||||
|
|
||||||
self.mj_footer = footer
|
self.mj_footer?.ignoredScrollViewContentInsetBottom = insetBottom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -54,17 +53,17 @@ extension UIScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func fa_updateNoMoreDataState(_ hasNextPage: Bool?) {
|
func fa_updateNoMoreDataState(_ hasNextPage: Bool?) {
|
||||||
if hasNextPage == false {
|
// if hasNextPage == false {
|
||||||
self.fa_endRefreshingWithNoMoreData()
|
// self.fa_endRefreshingWithNoMoreData()
|
||||||
} else {
|
// } else {
|
||||||
self.fa_resetNoMoreData()
|
// self.fa_resetNoMoreData()
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if self.mj_totalDataCount() == 0 {
|
// if self.mj_totalDataCount() == 0 {
|
||||||
self.mj_footer?.isHidden = true
|
// self.mj_footer?.isHidden = true
|
||||||
} else {
|
// } else {
|
||||||
self.mj_footer?.isHidden = false
|
// self.mj_footer?.isHidden = false
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,6 +65,9 @@ struct FAAPI {
|
|||||||
]
|
]
|
||||||
|
|
||||||
FANetworkManager.manager.request(FABaseURL + "/myHistorys", method: .get, parameters: parameters, isToast: false) { (response: FANetworkManager.Response<FANetworkManager.List<FAShortPlayModel>>) in
|
FANetworkManager.manager.request(FABaseURL + "/myHistorys", method: .get, parameters: parameters, isToast: false) { (response: FANetworkManager.Response<FANetworkManager.List<FAShortPlayModel>>) in
|
||||||
|
if page == 1, let model = response.data?.list?.first {
|
||||||
|
FATool.widgetLiveActivityModel = model
|
||||||
|
}
|
||||||
completer?(response.data)
|
completer?(response.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +106,7 @@ struct FAAPI {
|
|||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
isLoding: true) { (response: FANetworkManager.Response<FAShortDetailModel>) in
|
isLoding: true) { (response: FANetworkManager.Response<FAShortDetailModel>) in
|
||||||
if response.isSuccess {
|
if response.isSuccess {
|
||||||
|
FAToast.show(text: "fableo_success".localized)
|
||||||
success?()
|
success?()
|
||||||
NotificationCenter.default.post(name: FAAPI.updateShortCollectStateNotification, object: nil, userInfo: [
|
NotificationCenter.default.post(name: FAAPI.updateShortCollectStateNotification, object: nil, userInfo: [
|
||||||
"state" : isCollect,
|
"state" : isCollect,
|
||||||
@ -301,6 +305,19 @@ struct FAAPI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///获取反馈红点数量
|
||||||
|
static func requestFeedbackRedCount(completer: ((_ model: FAFeedbackCountModel?) -> Void)?) {
|
||||||
|
|
||||||
|
FANetworkManager.manager.request(FABaseURL + "/noticeNum",
|
||||||
|
method: .post,
|
||||||
|
parameters: nil,
|
||||||
|
isLoding: false,
|
||||||
|
isToast: true) { (response: FANetworkManager.Response<FAFeedbackCountModel>) in
|
||||||
|
completer?(response.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -70,6 +70,10 @@ class FANetworkManager {
|
|||||||
response.code = -1
|
response.code = -1
|
||||||
completion?(response)
|
completion?(response)
|
||||||
} else {
|
} else {
|
||||||
|
if code == 402, isToast {
|
||||||
|
FAToast.show(text: "fableon_kick_out_login".localized)
|
||||||
|
}
|
||||||
|
|
||||||
self.requestUserToken {
|
self.requestUserToken {
|
||||||
if FALogin.manager.token != nil {
|
if FALogin.manager.token != nil {
|
||||||
FALogin.manager.requestUserInfo(completer: nil)
|
FALogin.manager.requestUserInfo(completer: nil)
|
||||||
@ -173,8 +177,10 @@ extension FANetworkManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var headers: HTTPHeaders {
|
private var headers: HTTPHeaders {
|
||||||
|
|
||||||
|
|
||||||
let token = FALogin.manager.token?.token ?? ""
|
let token = FALogin.manager.token?.token ?? ""
|
||||||
let dic = [
|
var dic = [
|
||||||
"authorization" : token,
|
"authorization" : token,
|
||||||
"system-version" : UIDevice.current.systemVersion,
|
"system-version" : UIDevice.current.systemVersion,
|
||||||
"lang-key" : FALanguageManager.manager.currentLanguageKey,
|
"lang-key" : FALanguageManager.manager.currentLanguageKey,
|
||||||
@ -187,8 +193,11 @@ extension FANetworkManager {
|
|||||||
"idfa" : ASIdentifierManager.shared().advertisingIdentifier.uuidString,
|
"idfa" : ASIdentifierManager.shared().advertisingIdentifier.uuidString,
|
||||||
"device-id" : FADeviceIDManager.shared.id, //设备id
|
"device-id" : FADeviceIDManager.shared.id, //设备id
|
||||||
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
|
"device-gaid" : UIDevice.current.identifierForVendor?.uuidString ?? "",
|
||||||
"product-prefix" : FAIapManager.IAPPrefix
|
"product-prefix" : FAIapManager.IAPPrefix,
|
||||||
]
|
]
|
||||||
|
#if DEBUG
|
||||||
|
dic["security"] = "false"
|
||||||
|
#endif
|
||||||
return HTTPHeaders(dic)
|
return HTTPHeaders(dic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,7 @@ extension FABaseWebViewController {
|
|||||||
|
|
||||||
case kFAWebMessageAccountDeletionFinish:
|
case kFAWebMessageAccountDeletionFinish:
|
||||||
self.navigationController?.popToRootViewController(animated: true)
|
self.navigationController?.popToRootViewController(animated: true)
|
||||||
|
NotificationCenter.default.post(name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
|||||||
@ -30,12 +30,13 @@ class FAGenresListViewController: FAViewController {
|
|||||||
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
|
collectionView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||||
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
collectionView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
collectionView.fa_addRefreshFooter(insetBottom: collectionView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return collectionView
|
return collectionView
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class FAGenresViewController: FAViewController {
|
|||||||
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: self.collectionViewLayout)
|
let collectionView = FACollectionView(frame: .zero, collectionViewLayout: self.collectionViewLayout)
|
||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
|
collectionView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
collectionView.contentInset = .init(top: 24, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
collectionView.contentInset = .init(top: 24, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
collectionView.register(UINib(nibName: "FAGenresCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
collectionView.register(UINib(nibName: "FAGenresCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||||
return collectionView
|
return collectionView
|
||||||
@ -38,7 +39,7 @@ class FAGenresViewController: FAViewController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.title = "Genres".localized
|
self.title = "fableon_genres".localized
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,21 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SnapKit
|
import SnapKit
|
||||||
|
import LYEmptyView
|
||||||
|
|
||||||
class FAHomeViewController: FAViewController {
|
class FAHomeViewController: FAViewController {
|
||||||
|
|
||||||
private var viewModel = FAHomeViewModel()
|
private var viewModel = FAHomeViewModel()
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var notNetworkEmptyView: LYEmptyView = {
|
||||||
|
let view = FAEmpty.fa_notNetworkEmptyView { [weak self] in
|
||||||
|
self?.requestAllData(completer: nil)
|
||||||
|
self?.fa_setupLayout()
|
||||||
|
}
|
||||||
|
view.autoShowEmptyView = false
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
private lazy var cvLayout: FAWaterfallFlowLayout = {
|
private lazy var cvLayout: FAWaterfallFlowLayout = {
|
||||||
let layout = FAWaterfallFlowLayout()
|
let layout = FAWaterfallFlowLayout()
|
||||||
@ -80,6 +88,7 @@ class FAHomeViewController: FAViewController {
|
|||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(loginStatusChangeNotification), name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
|
||||||
requestAllData(completer: nil)
|
requestAllData(completer: nil)
|
||||||
@ -107,12 +116,27 @@ class FAHomeViewController: FAViewController {
|
|||||||
if self.viewModel.dataArr.isEmpty, FANetworkMonitor.manager.isReachable == true {
|
if self.viewModel.dataArr.isEmpty, FANetworkMonitor.manager.isReachable == true {
|
||||||
requestAllData(completer: nil)
|
requestAllData(completer: nil)
|
||||||
}
|
}
|
||||||
|
self.fa_setupLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func loginStatusChangeNotification() {
|
||||||
|
requestAllData(completer: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAHomeViewController {
|
extension FAHomeViewController {
|
||||||
|
|
||||||
private func fa_setupLayout() {
|
private func fa_setupLayout() {
|
||||||
|
if FANetworkMonitor.manager.isReachable == false, collectionView.superview == nil {
|
||||||
|
view.ly_emptyView = notNetworkEmptyView
|
||||||
|
view.ly_showEmpty()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if collectionView.superview != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
view.ly_hideEmpty()
|
||||||
|
|
||||||
view.addSubview(titleView)
|
view.addSubview(titleView)
|
||||||
view.addSubview(searchButton)
|
view.addSubview(searchButton)
|
||||||
view.addSubview(collectionView)
|
view.addSubview(collectionView)
|
||||||
@ -182,7 +206,7 @@ extension FAHomeViewController: UICollectionViewDelegate, UICollectionViewDataSo
|
|||||||
|
|
||||||
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||||
if kind == UICollectionView.elementKindSectionHeader {
|
if kind == UICollectionView.elementKindSectionHeader {
|
||||||
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FAHomeSectionTitleView", for: indexPath)
|
let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FAHomeSectionTitleView", for: indexPath) as! FAHomeSectionTitleView
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "footer", for: indexPath)
|
return collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "footer", for: indexPath)
|
||||||
@ -295,6 +319,8 @@ extension FAHomeViewController {
|
|||||||
if let playHistory = self.viewModel.playHistory {
|
if let playHistory = self.viewModel.playHistory {
|
||||||
self.playHistoryView.model = playHistory
|
self.playHistoryView.model = playHistory
|
||||||
self.playHistoryView.isHidden = false
|
self.playHistoryView.isHidden = false
|
||||||
|
} else {
|
||||||
|
self.playHistoryView.isHidden = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ class FAPopularListViewController: FAViewController {
|
|||||||
collectionView.delegate = self
|
collectionView.delegate = self
|
||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
collectionView.contentInset = .init(top: 20, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
|
collectionView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
collectionView.register(UINib(nibName: "FAGenresListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||||
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
collectionView.fa_addRefreshHeader(insetTop: collectionView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
|
|||||||
@ -36,6 +36,7 @@ class FARankingListViewController: FAViewController {
|
|||||||
collectionView.dataSource = self
|
collectionView.dataSource = self
|
||||||
collectionView.showsVerticalScrollIndicator = false
|
collectionView.showsVerticalScrollIndicator = false
|
||||||
collectionView.showsHorizontalScrollIndicator = false
|
collectionView.showsHorizontalScrollIndicator = false
|
||||||
|
collectionView.ly_emptyView = FAEmpty.fa_emptyView()
|
||||||
collectionView.contentInset = .init(top: 15, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
collectionView.contentInset = .init(top: 15, left: 0, bottom: UIScreen.safeBottom + 10, right: 0)
|
||||||
collectionView.register(UINib(nibName: "FARankingListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
collectionView.register(UINib(nibName: "FARankingListCell", bundle: nil), forCellWithReuseIdentifier: "cell")
|
||||||
return collectionView
|
return collectionView
|
||||||
@ -43,7 +44,7 @@ class FARankingListViewController: FAViewController {
|
|||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.title = "Rankings".localized
|
self.title = "fableon_rabkings".localized
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
|
|
||||||
|
|||||||
@ -13,4 +13,10 @@ struct FACategoryModel: SmartCodable {
|
|||||||
var id: String?
|
var id: String?
|
||||||
var category_name: String?
|
var category_name: String?
|
||||||
var short_play_list: [FAShortPlayModel]?
|
var short_play_list: [FAShortPlayModel]?
|
||||||
|
|
||||||
|
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||||
|
return [
|
||||||
|
CodingKeys.category_name <--- ["category_name", "name"],
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
Fableon/Object/Class/Home/M/FAHomeNewTransformer.swift
Normal file
17
Fableon/Object/Class/Home/M/FAHomeNewTransformer.swift
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// FAHomeNewTransformer.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import FSPagerView
|
||||||
|
|
||||||
|
class FAHomeNewTransformer: FSPagerViewTransformer {
|
||||||
|
|
||||||
|
|
||||||
|
override func proposedInteritemSpacing() -> CGFloat {
|
||||||
|
return -50
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -61,7 +61,7 @@ struct FAHomeMustSeeView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text("selection".localized)
|
Text("fableon_selection".localized)
|
||||||
.font(Font.font(size: 12, weight: .medium))
|
.font(Font.font(size: 12, weight: .medium))
|
||||||
.foregroundStyle(textColor)
|
.foregroundStyle(textColor)
|
||||||
.padding(.leading, 8)
|
.padding(.leading, 8)
|
||||||
|
|||||||
@ -14,7 +14,7 @@ struct FAHomeNewView: View {
|
|||||||
@ObservedObject var viewModel: FAHomeViewModel
|
@ObservedObject var viewModel: FAHomeViewModel
|
||||||
|
|
||||||
@State private var transformer: FSPagerViewTransformer = {
|
@State private var transformer: FSPagerViewTransformer = {
|
||||||
let transformer = FSPagerViewTransformer(type: .overlap)
|
let transformer = FAHomeNewTransformer(type: .overlap)
|
||||||
transformer.minimumScale = 0.9
|
transformer.minimumScale = 0.9
|
||||||
transformer.minimumAlpha = 1
|
transformer.minimumAlpha = 1
|
||||||
return transformer
|
return transformer
|
||||||
|
|||||||
@ -14,14 +14,22 @@ class FAGenresCell: UICollectionViewCell {
|
|||||||
var list = model?.short_play_list
|
var list = model?.short_play_list
|
||||||
let firstModel = list?.removeFirst()
|
let firstModel = list?.removeFirst()
|
||||||
|
|
||||||
hotCountLabel.text = "\(firstModel?.watch_total ?? 0)"
|
let count = firstModel?.watch_total ?? 0
|
||||||
|
var countStr = "\(count)"
|
||||||
|
if count > 1000 {
|
||||||
|
countStr = NSNumber(value: CGFloat(count) / 1000).toString(maximumFractionDigits: 1) + "k"
|
||||||
|
}
|
||||||
|
hotCountLabel.text = countStr
|
||||||
|
|
||||||
nameLabel.text = model?.category_name
|
nameLabel.text = model?.category_name
|
||||||
coverImageView.fa_setImage(firstModel?.image_url)
|
coverImageView.fa_setImage(firstModel?.image_url)
|
||||||
|
|
||||||
|
|
||||||
list?.enumerated().forEach {
|
list?.enumerated().forEach {
|
||||||
let i = $0
|
let i = $0
|
||||||
let imageView = smallImageViewArr[i]
|
let viewCount = smallImageViewArr.count
|
||||||
|
if i > viewCount { return }
|
||||||
|
let imageView = smallImageViewArr[viewCount - i - 1]
|
||||||
imageView.fa_setImage($1.image_url)
|
imageView.fa_setImage($1.image_url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,11 @@ class FAHomeBannerCell: FSPagerViewCell {
|
|||||||
|
|
||||||
var model: FAShortPlayModel? {
|
var model: FAShortPlayModel? {
|
||||||
didSet {
|
didSet {
|
||||||
coverImageView.fa_setImage(model?.horizontally_img)
|
if let image = model?.horizontally_img, image.count > 0 {
|
||||||
|
coverImageView.fa_setImage(image)
|
||||||
|
} else {
|
||||||
|
coverImageView.fa_setImage(model?.image_url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class FAHomeBannerContentCell: UICollectionViewCell {
|
|||||||
|
|
||||||
|
|
||||||
let view = FSPagerView()
|
let view = FSPagerView()
|
||||||
|
view.automaticSlidingInterval = 5
|
||||||
view.itemSize = .init(width: 282, height: 146)
|
view.itemSize = .init(width: 282, height: 146)
|
||||||
view.transformer = transformer
|
view.transformer = transformer
|
||||||
view.delegate = self
|
view.delegate = self
|
||||||
|
|||||||
@ -9,9 +9,12 @@ import UIKit
|
|||||||
|
|
||||||
class FAHomeSectionTitleView: UICollectionReusableView {
|
class FAHomeSectionTitleView: UICollectionReusableView {
|
||||||
|
|
||||||
|
|
||||||
|
@IBOutlet weak var titleLabel: UILabel!
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
// Initialization code
|
self.titleLabel.text = "fableon_recommended_for_you".localized
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="24128" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24063"/>
|
||||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<objects>
|
<objects>
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="U6b-Vx-4bR">
|
<collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="U6b-Vx-4bR" customClass="FAHomeSectionTitleView" customModule="Fableon" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="555" height="123"/>
|
<rect key="frame" x="0.0" y="0.0" width="555" height="123"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
@ -27,6 +27,9 @@
|
|||||||
<constraint firstItem="8Zn-D3-Qbm" firstAttribute="leading" secondItem="U6b-Vx-4bR" secondAttribute="leading" constant="16" id="EqE-jT-c4H"/>
|
<constraint firstItem="8Zn-D3-Qbm" firstAttribute="leading" secondItem="U6b-Vx-4bR" secondAttribute="leading" constant="16" id="EqE-jT-c4H"/>
|
||||||
<constraint firstAttribute="top" secondItem="8Zn-D3-Qbm" secondAttribute="top" id="WgU-9Y-14J"/>
|
<constraint firstAttribute="top" secondItem="8Zn-D3-Qbm" secondAttribute="top" id="WgU-9Y-14J"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
<connections>
|
||||||
|
<outlet property="titleLabel" destination="8Zn-D3-Qbm" id="ApY-aQ-yPU"/>
|
||||||
|
</connections>
|
||||||
<point key="canvasLocation" x="318.32061068702291" y="66.549295774647888"/>
|
<point key="canvasLocation" x="318.32061068702291" y="66.549295774647888"/>
|
||||||
</collectionReusableView>
|
</collectionReusableView>
|
||||||
</objects>
|
</objects>
|
||||||
|
|||||||
@ -14,7 +14,14 @@ class FARankingListCell: UICollectionViewCell {
|
|||||||
coverImageView.fa_setImage(model?.image_url)
|
coverImageView.fa_setImage(model?.image_url)
|
||||||
nameLabel.text = model?.name
|
nameLabel.text = model?.name
|
||||||
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
||||||
countLabel.text = "\(model?.watch_total ?? 0)"
|
|
||||||
|
|
||||||
|
let count = model?.watch_total ?? 0
|
||||||
|
var countStr = "\(count)"
|
||||||
|
if count > 1000 {
|
||||||
|
countStr = NSNumber(value: CGFloat(count) / 1000).toString(maximumFractionDigits: 1) + "k"
|
||||||
|
}
|
||||||
|
countLabel.text = countStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,14 @@ class FASearchRecommendCell: UICollectionViewCell {
|
|||||||
didSet {
|
didSet {
|
||||||
coverImageView.fa_setImage(model?.image_url)
|
coverImageView.fa_setImage(model?.image_url)
|
||||||
titleLabel.text = model?.name
|
titleLabel.text = model?.name
|
||||||
countLabel.text = "\(model?.watch_total ?? 0)"
|
|
||||||
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
||||||
|
|
||||||
|
let count = model?.watch_total ?? 0
|
||||||
|
var countStr = "\(count)"
|
||||||
|
if count > 1000 {
|
||||||
|
countStr = NSNumber(value: CGFloat(count) / 1000).toString(maximumFractionDigits: 1) + "k"
|
||||||
|
}
|
||||||
|
countLabel.text = countStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class FASearchResultCell: UICollectionViewCell {
|
|||||||
titleLabel.text = model?.name
|
titleLabel.text = model?.name
|
||||||
coverImageView.fa_setImage(model?.image_url)
|
coverImageView.fa_setImage(model?.image_url)
|
||||||
|
|
||||||
if let category = model?.category?.first, !category.isEmpty {
|
if let category = model?.categoryList?.first?.category_name, !category.isEmpty {
|
||||||
categoryView.isHidden = false
|
categoryView.isHidden = false
|
||||||
categoryLabel.text = category
|
categoryLabel.text = category
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -41,10 +41,10 @@ class FAHomeViewModel: ObservableObject {
|
|||||||
$0.title = "fableon_popular".localized
|
$0.title = "fableon_popular".localized
|
||||||
popularItem = $0
|
popularItem = $0
|
||||||
} else if $0.module_key == .week_ranking {
|
} else if $0.module_key == .week_ranking {
|
||||||
$0.title = "Rankings".localized
|
$0.title = "fableon_rabkings".localized
|
||||||
rankingsItem = $0
|
rankingsItem = $0
|
||||||
} else if $0.module_key == .cagetory_recommand, genresItem == nil {
|
} else if $0.module_key == .cagetory_recommand, genresItem == nil {
|
||||||
$0.title = "Genres".localized
|
$0.title = "fableon_genres".localized
|
||||||
genresItem = $0
|
genresItem = $0
|
||||||
} else if $0.module_key == .new_recommand {
|
} else if $0.module_key == .new_recommand {
|
||||||
$0.title = "fableon_new".localized
|
$0.title = "fableon_new".localized
|
||||||
@ -109,6 +109,8 @@ class FAHomeViewModel: ObservableObject {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let model = listModel?.list?.first {
|
if let model = listModel?.list?.first {
|
||||||
self.playHistory = model
|
self.playHistory = model
|
||||||
|
} else {
|
||||||
|
self.playHistory = nil
|
||||||
}
|
}
|
||||||
completer?()
|
completer?()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -101,6 +101,8 @@ class FACoinPackViewController: FAViewController {
|
|||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private weak var recommandView: UIView?
|
||||||
|
|
||||||
private lazy var tipTextLabel: UILabel = {
|
private lazy var tipTextLabel: UILabel = {
|
||||||
let att = NSMutableAttributedString(string: "coins_pack_tips".localized)
|
let att = NSMutableAttributedString(string: "coins_pack_tips".localized)
|
||||||
att.yy_lineSpacing = 3
|
att.yy_lineSpacing = 3
|
||||||
@ -210,7 +212,34 @@ extension FACoinPackViewController {
|
|||||||
FAStoreAPI.requestReceiveCoinsPackCoins(id: id) { [weak self] finish in
|
FAStoreAPI.requestReceiveCoinsPackCoins(id: id) { [weak self] finish in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.requestCoinsPackData()
|
self.requestCoinsPackData()
|
||||||
|
if finish {
|
||||||
|
self.showVideoRecommand()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///展示视频推荐
|
||||||
|
private func showVideoRecommand() {
|
||||||
|
guard self.recommandView == nil else { return }
|
||||||
|
|
||||||
|
FAAPI.requestDetailRecommendVideo { [weak self] list in
|
||||||
|
guard let self = self else { return }
|
||||||
|
guard let list = list else { return }
|
||||||
|
guard self.recommandView == nil else { return }
|
||||||
|
|
||||||
|
let view = FADetailRecommendView()
|
||||||
|
view.dataArr = list
|
||||||
|
view.didSelectedVideo = { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let vc = FAPlayerDetailViewController()
|
||||||
|
vc.shortPlayId = model.short_play_id
|
||||||
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
view.show(in: FATool.keyWindow)
|
||||||
|
self.recommandView = view
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,11 +9,59 @@ import UIKit
|
|||||||
|
|
||||||
class FAFeedbackViewController: FAAppWebViewController {
|
class FAFeedbackViewController: FAAppWebViewController {
|
||||||
|
|
||||||
|
|
||||||
|
private lazy var rightButton: UIButton = {
|
||||||
|
let button = UIButton(type: .custom)
|
||||||
|
button.setImage(UIImage(named: "Frame 2085663258"), for: .normal)
|
||||||
|
button.addTarget(self, action: #selector(handleRightBarButton), for: .touchUpInside)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var redView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.backgroundColor = .FF_313_B
|
||||||
|
view.layer.cornerRadius = 8
|
||||||
|
view.isHidden = true
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private lazy var redLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .font(ofSize: 12, weight: .bold)
|
||||||
|
label.textColor = .FFFFFF
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
self.webUrl = kFAFeedBackHomeWebUrl
|
self.webUrl = kFAFeedBackHomeWebUrl
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Frame 2085663258"), style: .plain, target: self, action: #selector(handleRightBarButton))
|
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "Frame 2085663258"), style: .plain, target: self, action: #selector(handleRightBarButton))
|
||||||
|
|
||||||
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightButton)
|
||||||
|
|
||||||
|
|
||||||
|
rightButton.addSubview(redView)
|
||||||
|
redView.addSubview(redLabel)
|
||||||
|
|
||||||
|
redView.snp.makeConstraints { make in
|
||||||
|
make.height.equalTo(16)
|
||||||
|
make.width.greaterThanOrEqualTo(16)
|
||||||
|
make.top.equalToSuperview().offset(-8)
|
||||||
|
make.right.equalToSuperview().offset(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
redLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
// make.left.equalToSuperview().offset(5)
|
||||||
|
make.left.greaterThanOrEqualToSuperview().offset(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
self.requestRedCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -23,6 +71,22 @@ class FAFeedbackViewController: FAAppWebViewController {
|
|||||||
vc.webUrl = kFAFeedBackListWebUrl
|
vc.webUrl = kFAFeedBackListWebUrl
|
||||||
|
|
||||||
self.navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FAFeedbackViewController {
|
||||||
|
|
||||||
|
private func requestRedCount() {
|
||||||
|
FAAPI.requestFeedbackRedCount { [weak self] model in
|
||||||
|
guard let self = self else { return }
|
||||||
|
if let count = model?.feedback_notice_num, count > 0 {
|
||||||
|
self.redView.isHidden = false
|
||||||
|
self.redLabel.text = "\(count)"
|
||||||
|
} else {
|
||||||
|
self.redView.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,22 +12,7 @@ class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate {
|
|||||||
|
|
||||||
var scrollCallback: ((_ : UIScrollView) -> Void)?
|
var scrollCallback: ((_ : UIScrollView) -> Void)?
|
||||||
|
|
||||||
private lazy var dataArr: [FAMeItemModel] = {
|
private lazy var dataArr: [FAMeItemModel] = []
|
||||||
let arr = [
|
|
||||||
FAMeItemModel(type: .language, name: "fableon_language".localized, icon: UIImage(named: "icon_language")),
|
|
||||||
FAMeItemModel(type: .feedback, name: "fableon_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
|
||||||
FAMeItemModel(type: .about, name: "fableon_about_us".localized, icon: UIImage(named: "icon_about")),
|
|
||||||
|
|
||||||
FAMeItemModel(type: .privacyPolicy, name: "fableon_privacy_policy".localized, icon: UIImage(named: "icon_privacy")),
|
|
||||||
FAMeItemModel(type: .userAgreement, name: "fableon_user_agreement".localized, icon: UIImage(named: "icon_user")),
|
|
||||||
// FAMeItemModel(type: .visitWebsite, name: "fableon_visit_website".localized, icon: UIImage(named: "icon_visit")),
|
|
||||||
|
|
||||||
FAMeItemModel(type: .setting, name: "fableon_settings".localized, icon: UIImage(named: "icon_setting"))
|
|
||||||
]
|
|
||||||
return arr
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private lazy var tableViewHeaderView: FAMeTableViewHeaderView = {
|
private lazy var tableViewHeaderView: FAMeTableViewHeaderView = {
|
||||||
let view = FAMeTableViewHeaderView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 124))
|
let view = FAMeTableViewHeaderView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 124))
|
||||||
@ -49,7 +34,6 @@ class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate {
|
|||||||
tableView.rowHeight = 56
|
tableView.rowHeight = 56
|
||||||
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
tableView.separatorInset = .init(top: 0, left: 32, bottom: 0, right: 32)
|
||||||
tableView.register(UINib(nibName: "FAMeCell", bundle: nil), forCellReuseIdentifier: "cell")
|
tableView.register(UINib(nibName: "FAMeCell", bundle: nil), forCellReuseIdentifier: "cell")
|
||||||
// tableView.addObserver(self, forKeyPath: "contentSize", context: nil)
|
|
||||||
return tableView
|
return tableView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -61,7 +45,7 @@ class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate {
|
|||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: FALogin.userInfoUpdateNotification, object: nil)
|
||||||
|
setDataArr()
|
||||||
self.bgView.isHidden = true
|
self.bgView.isHidden = true
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
@ -70,6 +54,7 @@ class FAMeListViewController: FAViewController, JXPagingViewListViewDelegate {
|
|||||||
|
|
||||||
@objc private func userInfoUpdateNotification() {
|
@objc private func userInfoUpdateNotification() {
|
||||||
tableViewHeaderView.userInfo = FALogin.manager.userInfo
|
tableViewHeaderView.userInfo = FALogin.manager.userInfo
|
||||||
|
setDataArr()
|
||||||
}
|
}
|
||||||
|
|
||||||
func listScrollView() -> UIScrollView {
|
func listScrollView() -> UIScrollView {
|
||||||
@ -159,3 +144,27 @@ extension FAMeListViewController: UITableViewDelegate, UITableViewDataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FAMeListViewController {
|
||||||
|
|
||||||
|
private func setDataArr() {
|
||||||
|
|
||||||
|
var arr = [
|
||||||
|
FAMeItemModel(type: .language, name: "fableon_language".localized, icon: UIImage(named: "icon_language")),
|
||||||
|
FAMeItemModel(type: .feedback, name: "fableon_feedback".localized, icon: UIImage(named: "icon_feedback")),
|
||||||
|
FAMeItemModel(type: .about, name: "fableon_about_us".localized, icon: UIImage(named: "icon_about")),
|
||||||
|
|
||||||
|
FAMeItemModel(type: .privacyPolicy, name: "fableon_privacy_policy".localized, icon: UIImage(named: "icon_privacy")),
|
||||||
|
FAMeItemModel(type: .userAgreement, name: "fableon_user_agreement".localized, icon: UIImage(named: "icon_user")),
|
||||||
|
]
|
||||||
|
|
||||||
|
if FALogin.manager.isLogin {
|
||||||
|
arr.append(
|
||||||
|
FAMeItemModel(type: .setting, name: "fableon_settings".localized, icon: UIImage(named: "icon_setting"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
self.dataArr = arr
|
||||||
|
self.tableView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
15
Fableon/Object/Class/Me/M/FAFeedbackCountModel.swift
Normal file
15
Fableon/Object/Class/Me/M/FAFeedbackCountModel.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// FAFeedbackCountModel.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/11.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import SmartCodable
|
||||||
|
|
||||||
|
struct FAFeedbackCountModel: SmartCodable {
|
||||||
|
|
||||||
|
var feedback_notice_num: Int?
|
||||||
|
|
||||||
|
}
|
||||||
@ -104,7 +104,7 @@ class FACoinPackHeaderView: UIView {
|
|||||||
.foregroundColor : UIColor.FFFFFF
|
.foregroundColor : UIColor.FFFFFF
|
||||||
]))
|
]))
|
||||||
|
|
||||||
let countAtt = AttributedString(" \(0)".localized, attributes: AttributeContainer([
|
let countAtt = AttributedString(" \(self.model?.receive_coins ?? 0)".localized, attributes: AttributeContainer([
|
||||||
.font : UIFont.font(ofSize: 14, weight: .bold),
|
.font : UIFont.font(ofSize: 14, weight: .bold),
|
||||||
.foregroundColor : UIColor.FFFFFF
|
.foregroundColor : UIColor.FFFFFF
|
||||||
]))
|
]))
|
||||||
|
|||||||
@ -24,7 +24,8 @@ class FACoinsPackClaimListCell: UICollectionViewCell {
|
|||||||
titleAtt.yy_color = .FFFFFF
|
titleAtt.yy_color = .FFFFFF
|
||||||
titleAtt.yy_font = .font(ofSize: 14, weight: .bold)
|
titleAtt.yy_font = .font(ofSize: 14, weight: .bold)
|
||||||
|
|
||||||
let dayAtt = NSMutableAttributedString(string: " (Day \(model?.day_text ?? ""))")
|
let day = "fableon_d".localized
|
||||||
|
let dayAtt = NSMutableAttributedString(string: " (\(day) \(model?.day_text ?? ""))")
|
||||||
dayAtt.yy_color = ._20_A_1_FF
|
dayAtt.yy_color = ._20_A_1_FF
|
||||||
dayAtt.yy_font = .font(ofSize: 14, weight: .regular)
|
dayAtt.yy_font = .font(ofSize: 14, weight: .regular)
|
||||||
titleAtt.append(dayAtt)
|
titleAtt.append(dayAtt)
|
||||||
|
|||||||
@ -97,6 +97,24 @@ class FAMeHeaderView: UIView {
|
|||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var topUpButton: UIButton = {
|
||||||
|
let button = FAGradientButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
let vc = FAWalletViewController()
|
||||||
|
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||||
|
}))
|
||||||
|
button.fa_colors = [UIColor.BEDFFF.cgColor, UIColor._52_A_2_F_1.cgColor]
|
||||||
|
button.fa_locations = [0, 1]
|
||||||
|
button.fa_startPoint = .init(x: 0, y: 0.5)
|
||||||
|
button.fa_endPoint = .init(x: 1, y: 0.5)
|
||||||
|
button.layer.cornerRadius = 18
|
||||||
|
button.layer.masksToBounds = true
|
||||||
|
button.setTitle("GO", for: .normal)
|
||||||
|
button.setTitleColor(._000000, for: .normal)
|
||||||
|
button.titleLabel?.font = .font(ofSize: 14, weight: .semibold)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
@ -118,6 +136,7 @@ extension FAMeHeaderView {
|
|||||||
addSubview(bonusCoinsView)
|
addSubview(bonusCoinsView)
|
||||||
addSubview(coinPackButton)
|
addSubview(coinPackButton)
|
||||||
addSubview(loginButton)
|
addSubview(loginButton)
|
||||||
|
addSubview(topUpButton)
|
||||||
|
|
||||||
avatarImageView.snp.makeConstraints { make in
|
avatarImageView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(16)
|
make.left.equalToSuperview().offset(16)
|
||||||
@ -159,6 +178,13 @@ extension FAMeHeaderView {
|
|||||||
make.width.equalTo(76)
|
make.width.equalTo(76)
|
||||||
make.height.equalTo(28)
|
make.height.equalTo(28)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
topUpButton.snp.makeConstraints { make in
|
||||||
|
make.centerY.equalTo(coinsView)
|
||||||
|
make.right.equalToSuperview().offset(-16)
|
||||||
|
make.width.equalTo(84)
|
||||||
|
make.height.equalTo(36)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,18 +11,18 @@ class FAMeTableViewHeaderView: UIView {
|
|||||||
|
|
||||||
var userInfo: FAUserInfo? {
|
var userInfo: FAUserInfo? {
|
||||||
didSet {
|
didSet {
|
||||||
|
subtitleLabel.text = "vip_tip_01".localized
|
||||||
if userInfo?.is_vip == true {
|
if userInfo?.is_vip == true {
|
||||||
subscribeView.isHidden = true
|
subscribeView.isHidden = true
|
||||||
expirationView.isHidden = false
|
expirationView.isHidden = false
|
||||||
vipImageView.image = UIImage(named: "vip_image_02")
|
vipImageView.image = UIImage(named: "vip_image_02")
|
||||||
titleLabel.text = "fableon_activated".localized
|
titleLabel.text = "fableon_activated".localized
|
||||||
subtitleLabel.text = "vip_tip_01".localized
|
|
||||||
} else {
|
} else {
|
||||||
subscribeView.isHidden = false
|
subscribeView.isHidden = false
|
||||||
expirationView.isHidden = true
|
expirationView.isHidden = true
|
||||||
vipImageView.image = UIImage(named: "vip_image_01")
|
vipImageView.image = UIImage(named: "vip_image_01")
|
||||||
titleLabel.text = "fableon_not_activated".localized
|
titleLabel.text = "fableon_not_activated".localized
|
||||||
subtitleLabel.text = "vip_tip_02".localized
|
// subtitleLabel.text = "vip_tip_02".localized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,10 @@ class FASettingFooterView: UIView {
|
|||||||
|
|
||||||
let view = FALogoutAlert()
|
let view = FALogoutAlert()
|
||||||
view.clickHighlightButton = {
|
view.clickHighlightButton = {
|
||||||
FALogin.manager.logout(completer: nil)
|
FALogin.manager.logout { [weak self] finish in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.viewController?.navigationController?.popToRootViewController(animated: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
view.show()
|
view.show()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ class FACollectViewController: FAViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var needUpdate = false
|
||||||
|
|
||||||
|
|
||||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||||
let width = floor((UIScreen.width - 16 - 32) / 3)
|
let width = floor((UIScreen.width - 16 - 32) / 3)
|
||||||
@ -67,11 +69,17 @@ class FACollectViewController: FAViewController {
|
|||||||
return item
|
return item
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
self.edgesForExtendedLayout = .top
|
self.edgesForExtendedLayout = .top
|
||||||
self.title = "fableon_collect".localized
|
self.title = "fableon_collect".localized
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(loginStatusChangeNotification), name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: FAAPI.updateShortCollectStateNotification, object: nil)
|
||||||
|
|
||||||
self.navigationItem.rightBarButtonItems = [historyButton, spaceButton, editBarButton]
|
self.navigationItem.rightBarButtonItems = [historyButton, spaceButton, editBarButton]
|
||||||
|
|
||||||
@ -87,6 +95,14 @@ class FACollectViewController: FAViewController {
|
|||||||
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewDidAppear(_ animated: Bool) {
|
||||||
|
super.viewDidAppear(animated)
|
||||||
|
if needUpdate {
|
||||||
|
needUpdate = false
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidDisappear(_ animated: Bool) {
|
override func viewDidDisappear(_ animated: Bool) {
|
||||||
super.viewDidDisappear(animated)
|
super.viewDidDisappear(animated)
|
||||||
self.fa_isEditing = false
|
self.fa_isEditing = false
|
||||||
@ -138,6 +154,13 @@ class FACollectViewController: FAViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc private func loginStatusChangeNotification() {
|
||||||
|
requestDataArr(page: 1, completer: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func updateShortCollectStateNotification() {
|
||||||
|
needUpdate = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FACollectViewController {
|
extension FACollectViewController {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class FAHistoryViewController: FAViewController {
|
|||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.handleHeaderRefresh(nil)
|
self.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
collectionView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
collectionView.fa_addRefreshFooter(insetBottom: collectionView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return collectionView
|
return collectionView
|
||||||
|
|||||||
@ -22,6 +22,7 @@ class FAShortPlayModel: NSObject, Identifiable, SmartCodable {
|
|||||||
var episode_total: Int?
|
var episode_total: Int?
|
||||||
var horizontally_img: String?
|
var horizontally_img: String?
|
||||||
var category: [String]?
|
var category: [String]?
|
||||||
|
var categoryList: [FACategoryModel]?
|
||||||
var short_play_id: String?
|
var short_play_id: String?
|
||||||
var short_play_video_id: String?
|
var short_play_video_id: String?
|
||||||
var video_info: FAVideoInfoModel?
|
var video_info: FAVideoInfoModel?
|
||||||
|
|||||||
@ -21,6 +21,7 @@ class FADetailRecommendCell: FSPagerViewCell {
|
|||||||
private lazy var player: JXPlayer = {
|
private lazy var player: JXPlayer = {
|
||||||
let player = JXPlayer(controlView: nil)
|
let player = JXPlayer(controlView: nil)
|
||||||
player.playerView = self.playerView
|
player.playerView = self.playerView
|
||||||
|
player.isLoop = true
|
||||||
return player
|
return player
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ class FADetailRecommendView: FABaseAlert {
|
|||||||
var dataArr: [FAShortPlayModel] = [] {
|
var dataArr: [FAShortPlayModel] = [] {
|
||||||
didSet {
|
didSet {
|
||||||
self.pagerView.reloadData()
|
self.pagerView.reloadData()
|
||||||
|
pageControl.numberOfPages = dataArr.count
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
||||||
self?.updateCurrentData()
|
self?.updateCurrentData()
|
||||||
@ -68,6 +69,15 @@ class FADetailRecommendView: FABaseAlert {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private lazy var pageControl: UIPageControl = {
|
||||||
|
let view = UIPageControl()
|
||||||
|
view.isUserInteractionEnabled = false
|
||||||
|
view.pageIndicatorTintColor = .FFFFFF.withAlphaComponent(0.6)
|
||||||
|
view.currentPageIndicatorTintColor = .FFFFFF
|
||||||
|
view.numberOfPages = 0
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
contentWidth = UIScreen.width
|
contentWidth = UIScreen.width
|
||||||
@ -96,6 +106,7 @@ class FADetailRecommendView: FABaseAlert {
|
|||||||
guard let cell = self.pagerView.cellForItem(at: self.pagerView.currentIndex) as? FADetailRecommendCell else { return }
|
guard let cell = self.pagerView.cellForItem(at: self.pagerView.currentIndex) as? FADetailRecommendCell else { return }
|
||||||
|
|
||||||
self.currentCell = cell
|
self.currentCell = cell
|
||||||
|
self.pageControl.currentPage = self.pagerView.currentIndex
|
||||||
// let model = cell.model
|
// let model = cell.model
|
||||||
// self.videoNameLabel.text = model?.name
|
// self.videoNameLabel.text = model?.name
|
||||||
}
|
}
|
||||||
@ -109,6 +120,7 @@ extension FADetailRecommendView {
|
|||||||
contentView.addSubview(bgView)
|
contentView.addSubview(bgView)
|
||||||
contentView.addSubview(cancelButton)
|
contentView.addSubview(cancelButton)
|
||||||
bgView.addSubview(pagerView)
|
bgView.addSubview(pagerView)
|
||||||
|
bgView.addSubview(pageControl)
|
||||||
|
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
make.top.equalToSuperview()
|
make.top.equalToSuperview()
|
||||||
@ -131,6 +143,11 @@ extension FADetailRecommendView {
|
|||||||
make.height.equalTo(267)
|
make.height.equalTo(267)
|
||||||
make.center.equalToSuperview()
|
make.center.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pageControl.snp.makeConstraints { make in
|
||||||
|
make.centerX.equalToSuperview()
|
||||||
|
make.top.equalTo(pagerView.snp.bottom).offset(10)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -158,3 +175,13 @@ extension FADetailRecommendView: FSPagerViewDelegate, FSPagerViewDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension FADetailRecommendView {
|
||||||
|
|
||||||
|
class PageControl: UIPageControl{
|
||||||
|
override func size(forNumberOfPages pageCount: Int) -> CGSize {
|
||||||
|
return .init(width: 4, height: 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -192,9 +192,8 @@ extension FAEpSelectorView: UICollectionViewDelegate, UICollectionViewDataSource
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.didSelected?(indexPath.row)
|
self.dismiss(animated: true) { [weak self] in
|
||||||
self.dismiss(animated: true) {
|
self?.didSelected?(indexPath.row)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ class FAOldVideoRechargeView: FAPanModalContentView {
|
|||||||
|
|
||||||
private lazy var scrollView: FAScrollView = {
|
private lazy var scrollView: FAScrollView = {
|
||||||
let scrollView = FAScrollView()
|
let scrollView = FAScrollView()
|
||||||
scrollView.clipsToBounds = false
|
// scrollView.clipsToBounds = false
|
||||||
return scrollView
|
return scrollView
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ class FAOldVideoRechargeView: FAPanModalContentView {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 12, weight: .medium)
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
label.textColor = .FFFFFF
|
label.textColor = .FFFFFF
|
||||||
label.text = "store_tips_title".localized
|
label.text = "fableon_tips".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,8 @@ class FAPlayerDetailCell: JXPlayerListCell {
|
|||||||
didSet {
|
didSet {
|
||||||
let controlView = self.controlView as? FAPlayerDetailControlView
|
let controlView = self.controlView as? FAPlayerDetailControlView
|
||||||
controlView?.shortModel = shortModel
|
controlView?.shortModel = shortModel
|
||||||
|
|
||||||
|
self.player.coverImageView?.fa_setImage(shortModel?.image_url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,6 +58,12 @@ class FAPlayerDetailControlView: JXPlayerListControlView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var isLoading: Bool {
|
||||||
|
didSet {
|
||||||
|
progressView.isLoading = isLoading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private lazy var epButton: UIHostingController<FAPlayerEpUIButton> = {
|
private lazy var epButton: UIHostingController<FAPlayerEpUIButton> = {
|
||||||
let view = FAPlayerEpUIButton()
|
let view = FAPlayerEpUIButton()
|
||||||
let hc = UIHostingController(rootView: view)
|
let hc = UIHostingController(rootView: view)
|
||||||
@ -126,7 +132,15 @@ class FAPlayerDetailControlView: JXPlayerListControlView {
|
|||||||
let videoId = (self.model as? FAVideoInfoModel)?.short_play_video_id
|
let videoId = (self.model as? FAVideoInfoModel)?.short_play_video_id
|
||||||
let isCollect = !(self.shortModel?.is_collect ?? false)
|
let isCollect = !(self.shortModel?.is_collect ?? false)
|
||||||
|
|
||||||
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
if isCollect {
|
||||||
|
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
||||||
|
} else {
|
||||||
|
let alert = FARemoveCollectAlert()
|
||||||
|
alert.clickHighlightButton = {
|
||||||
|
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
||||||
|
}
|
||||||
|
alert.show()
|
||||||
|
}
|
||||||
|
|
||||||
}), for: .touchUpInside)
|
}), for: .touchUpInside)
|
||||||
|
|
||||||
|
|||||||
@ -152,7 +152,7 @@ class FAPlayerProgressView: UIView {
|
|||||||
if self.isPaning {
|
if self.isPaning {
|
||||||
progress = self.panProgress
|
progress = self.panProgress
|
||||||
}
|
}
|
||||||
|
let currentProgressWidth = progressWidth * progress
|
||||||
|
|
||||||
///绘制进度
|
///绘制进度
|
||||||
let progressPath = UIBezierPath(roundedRect: CGRect(x: progressX, y: progressY, width: progressWidth, height: lineWidth), cornerRadius: lineWidth / 2)
|
let progressPath = UIBezierPath(roundedRect: CGRect(x: progressX, y: progressY, width: progressWidth, height: lineWidth), cornerRadius: lineWidth / 2)
|
||||||
@ -165,6 +165,12 @@ class FAPlayerProgressView: UIView {
|
|||||||
context.addPath(currentPath.cgPath)
|
context.addPath(currentPath.cgPath)
|
||||||
context.setFillColor(currentProgress.cgColor)
|
context.setFillColor(currentProgress.cgColor)
|
||||||
context.fillPath()
|
context.fillPath()
|
||||||
|
|
||||||
|
///绘制一个点
|
||||||
|
let path = UIBezierPath(arcCenter: .init(x: currentProgressWidth + progressX, y: progressY + lineWidth / 2), radius: 3, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
|
||||||
|
context.addPath(path.cgPath)
|
||||||
|
context.setFillColor(currentProgress.cgColor)
|
||||||
|
context.fillPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -78,13 +78,13 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
|||||||
self.viewModel.currentCell?.pause()
|
self.viewModel.currentCell?.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var previousVideoUrl: String? {
|
// override var previousVideoUrl: String? {
|
||||||
return self.fa_viewModel.previousEpisode?.video_url
|
// return self.fa_viewModel.previousEpisode?.video_url
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
override var nextVideoUrl: String? {
|
// override var nextVideoUrl: String? {
|
||||||
return self.fa_viewModel.nextEpisode?.video_url
|
// return self.fa_viewModel.nextEpisode?.video_url
|
||||||
}
|
// }
|
||||||
|
|
||||||
override func play() {
|
override func play() {
|
||||||
let videoInfo = self.viewModel.currentCell?.model as? FAVideoInfoModel
|
let videoInfo = self.viewModel.currentCell?.model as? FAVideoInfoModel
|
||||||
@ -92,6 +92,11 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
|||||||
if videoInfo?.is_lock != true {
|
if videoInfo?.is_lock != true {
|
||||||
super.play()
|
super.play()
|
||||||
FAAPI.requestCreatePlayHistory(videoId: videoInfo?.short_play_video_id, shortPlayId: videoInfo?.short_play_id)
|
FAAPI.requestCreatePlayHistory(videoId: videoInfo?.short_play_video_id, shortPlayId: videoInfo?.short_play_id)
|
||||||
|
|
||||||
|
if let cell = viewModel.currentCell as? FAPlayerDetailCell, let model = cell.shortModel {
|
||||||
|
FATool.widgetLiveActivityModel = model
|
||||||
|
FATool.widgetLiveActivityModel?.current_episode = videoInfo?.episode
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.pause()
|
self.pause()
|
||||||
@ -114,7 +119,7 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
|||||||
@objc private func handleBackButton() {
|
@objc private func handleBackButton() {
|
||||||
self.pause()
|
self.pause()
|
||||||
|
|
||||||
if !self.fa_viewModel.recommandDataArr.isEmpty {
|
if !self.fa_viewModel.recommandDataArr.isEmpty, self.fa_viewModel.isShowRecommand {
|
||||||
let view = FADetailRecommendView()
|
let view = FADetailRecommendView()
|
||||||
view.dataArr = self.fa_viewModel.recommandDataArr
|
view.dataArr = self.fa_viewModel.recommandDataArr
|
||||||
view.clickCloseButton = { [weak self] in
|
view.clickCloseButton = { [weak self] in
|
||||||
@ -126,6 +131,8 @@ class FAPlayerDetailViewController: JXPlayerListViewController {
|
|||||||
self.requestDetailList()
|
self.requestDetailList()
|
||||||
}
|
}
|
||||||
view.show(in: FATool.keyWindow)
|
view.show(in: FATool.keyWindow)
|
||||||
|
} else {
|
||||||
|
self.handleNavigationBack()
|
||||||
}
|
}
|
||||||
|
|
||||||
// self.handleNavigationBack()
|
// self.handleNavigationBack()
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import JXPlayer
|
import JXPlayer
|
||||||
|
import YYText
|
||||||
|
|
||||||
//@MainActor
|
//@MainActor
|
||||||
class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
||||||
@ -14,6 +15,9 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
|||||||
private(set) var dataArr: [FAShortDetailModel] = []
|
private(set) var dataArr: [FAShortDetailModel] = []
|
||||||
|
|
||||||
private(set) var recommandDataArr: [FAShortPlayModel] = []
|
private(set) var recommandDataArr: [FAShortPlayModel] = []
|
||||||
|
///是否展示推荐数据
|
||||||
|
private(set) var isShowRecommand = false
|
||||||
|
private var recommandTimer: Timer?
|
||||||
|
|
||||||
var shortPlayId: String = ""
|
var shortPlayId: String = ""
|
||||||
|
|
||||||
@ -43,6 +47,11 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
|||||||
|
|
||||||
|
|
||||||
func requestDetailData(indexPath: IndexPath? = nil, completer: ((_ code: Int) -> Void)?) {
|
func requestDetailData(indexPath: IndexPath? = nil, completer: ((_ code: Int) -> Void)?) {
|
||||||
|
isShowRecommand = false
|
||||||
|
recommandTimer?.invalidate()
|
||||||
|
recommandTimer = nil
|
||||||
|
recommandTimer = Timer.scheduledTimer(timeInterval: 6, target: YYTextWeakProxy(target: self), selector: #selector(handleRecommandTimer), userInfo: nil, repeats: false)
|
||||||
|
|
||||||
FAAPI.requestShortDetailData(shortPlayId: shortPlayId) { [weak self] model, code, msg in
|
FAAPI.requestShortDetailData(shortPlayId: shortPlayId) { [weak self] model, code, msg in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let model = model {
|
if let model = model {
|
||||||
@ -99,6 +108,18 @@ class FAShortDetailViewModel: JXPlayerListViewModel, ObservableObject {
|
|||||||
FAAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: Int(time) * 1000)
|
FAAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: Int(time) * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func playFinish(player: any JXPlayerCell) {
|
||||||
|
super.playFinish(player: player)
|
||||||
|
|
||||||
|
let videoInfo = self.currentCell?.model as? FAVideoInfoModel
|
||||||
|
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
|
||||||
|
FAAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func handleRecommandTimer() {
|
||||||
|
self.isShowRecommand = true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAShortDetailViewModel {
|
extension FAShortDetailViewModel {
|
||||||
@ -119,6 +140,7 @@ extension FAShortDetailViewModel {
|
|||||||
func handleUnlockVideo() {
|
func handleUnlockVideo() {
|
||||||
unlockVideo { [weak self] finish in
|
unlockVideo { [weak self] finish in
|
||||||
if finish {
|
if finish {
|
||||||
|
FAToast.show(text: "fableo_success".localized)
|
||||||
self?.playerListVC?.reloadData {
|
self?.playerListVC?.reloadData {
|
||||||
self?.playerListVC?.play()
|
self?.playerListVC?.play()
|
||||||
}
|
}
|
||||||
@ -166,6 +188,10 @@ extension FAShortDetailViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func _openOldRechargeView(_ model: FAPayDateModel, _ videoInfo: FAVideoInfoModel) {
|
private func _openOldRechargeView(_ model: FAPayDateModel, _ videoInfo: FAVideoInfoModel) {
|
||||||
|
FAStatAPI.requestEventStat(orderCode: nil, shortPlayId: videoInfo.short_play_id, videoId: videoInfo.short_play_video_id, eventKey: .payTemplateDialog, errorMsg: nil, otherParamenters: [
|
||||||
|
"event_name" : "pay open"
|
||||||
|
])
|
||||||
|
|
||||||
let view = FAOldVideoRechargeView()
|
let view = FAOldVideoRechargeView()
|
||||||
view.model = model
|
view.model = model
|
||||||
view.videoInfo = videoInfo
|
view.videoInfo = videoInfo
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import JXPlayer
|
import JXPlayer
|
||||||
|
import LYEmptyView
|
||||||
|
|
||||||
class FARecommendViewController: JXPlayerListViewController {
|
class FARecommendViewController: JXPlayerListViewController {
|
||||||
|
|
||||||
@ -22,15 +23,37 @@ class FARecommendViewController: JXPlayerListViewController {
|
|||||||
return self.viewModel as! FARecommendViewModel
|
return self.viewModel as! FARecommendViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lazy var notNetworkEmptyView: LYEmptyView = {
|
||||||
|
let view = FAEmpty.fa_notNetworkEmptyView { [weak self] in
|
||||||
|
self?.fa_viewModel.requestDataArr(page: 1)
|
||||||
|
self?.fa_setupLayout()
|
||||||
|
}
|
||||||
|
view.autoShowEmptyView = false
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: FANetworkMonitor.networkStatusDidChangeNotification, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(loginStatusChangeNotification), name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
self.register(FARecommendPlayerCell.self, forCellWithReuseIdentifier: "cell")
|
self.register(FARecommendPlayerCell.self, forCellWithReuseIdentifier: "cell")
|
||||||
|
self.collectionView.fa_addRefreshHeader { [weak self] in
|
||||||
|
self?.fa_viewModel.requestDataArr(page: 1) {
|
||||||
|
self?.collectionView.fa_endHeaderRefreshing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.collectionView.isHidden = true
|
||||||
|
|
||||||
self.delegate = self
|
self.delegate = self
|
||||||
self.dataSource = self
|
self.dataSource = self
|
||||||
|
|
||||||
self.fa_viewModel.requestDataArr(page: 1)
|
self.fa_viewModel.requestDataArr(page: 1)
|
||||||
|
|
||||||
|
fa_setupLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@ -43,12 +66,39 @@ class FARecommendViewController: JXPlayerListViewController {
|
|||||||
self.viewModel.currentCell?.pause()
|
self.viewModel.currentCell?.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var previousVideoUrl: String? {
|
// override var previousVideoUrl: String? {
|
||||||
return self.fa_viewModel.previousEpisode?.video_url
|
// return self.fa_viewModel.previousEpisode?.video_url
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override var nextVideoUrl: String? {
|
||||||
|
// return self.fa_viewModel.nextEpisode?.video_url
|
||||||
|
// }
|
||||||
|
|
||||||
|
@objc private func loginStatusChangeNotification() {
|
||||||
|
self.fa_viewModel.requestDataArr(page: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var nextVideoUrl: String? {
|
@objc private func networkStatusDidChangeNotification() {
|
||||||
return self.fa_viewModel.nextEpisode?.video_url
|
if FANetworkMonitor.manager.isReachable == true, self.fa_viewModel.dataArr.isEmpty {
|
||||||
|
self.fa_viewModel.requestDataArr(page: 1)
|
||||||
|
}
|
||||||
|
fa_setupLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension FARecommendViewController {
|
||||||
|
|
||||||
|
private func fa_setupLayout() {
|
||||||
|
if FANetworkMonitor.manager.isReachable == false, self.collectionView.isHidden {
|
||||||
|
view.ly_emptyView = notNetworkEmptyView
|
||||||
|
view.ly_showEmpty()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !self.collectionView.isHidden {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
view.ly_hideEmpty()
|
||||||
|
self.collectionView.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -69,5 +119,7 @@ extension FARecommendViewController: JXPlayerListViewControllerDataSource {
|
|||||||
|
|
||||||
//MARK: JXPlayerListViewControllerDelegate
|
//MARK: JXPlayerListViewControllerDelegate
|
||||||
extension FARecommendViewController: JXPlayerListViewControllerDelegate {
|
extension FARecommendViewController: JXPlayerListViewControllerDelegate {
|
||||||
|
func jx_playerViewControllerLoadMoreData(playerViewController: JXPlayerListViewController) {
|
||||||
|
self.fa_viewModel.requestDataArr(page: self.fa_viewModel.page + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,7 @@ class FARecommendPlayerCell: JXPlayerListCell {
|
|||||||
let videoInfo = model?.video_info
|
let videoInfo = model?.video_info
|
||||||
|
|
||||||
self.player.setPlayUrl(url: videoInfo?.video_url ?? "")
|
self.player.setPlayUrl(url: videoInfo?.video_url ?? "")
|
||||||
|
self.player.coverImageView?.fa_setImage(model?.image_url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,12 +57,12 @@ class FARecommendPlayerControlView: JXPlayerListControlView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lazy var epButton: UIHostingController<FAPlayerEpUIButton> = {
|
// private lazy var epButton: UIHostingController<FAPlayerEpUIButton> = {
|
||||||
let view = FAPlayerEpUIButton()
|
// let view = FAPlayerEpUIButton()
|
||||||
let hc = UIHostingController(rootView: view)
|
// let hc = UIHostingController(rootView: view)
|
||||||
hc.view.backgroundColor = .clear
|
// hc.view.backgroundColor = .clear
|
||||||
return hc
|
// return hc
|
||||||
}()
|
// }()
|
||||||
|
|
||||||
private lazy var progressView: FAPlayerProgressView = {
|
private lazy var progressView: FAPlayerProgressView = {
|
||||||
let view = FAPlayerProgressView()
|
let view = FAPlayerProgressView()
|
||||||
@ -79,6 +79,9 @@ class FARecommendPlayerControlView: JXPlayerListControlView {
|
|||||||
label.font = .font(ofSize: 12, weight: .regular);
|
label.font = .font(ofSize: 12, weight: .regular);
|
||||||
label.textColor = UIColor(named: .color_FFFFFF)!.withAlphaComponent(0.8)
|
label.textColor = UIColor(named: .color_FFFFFF)!.withAlphaComponent(0.8)
|
||||||
label.numberOfLines = 2
|
label.numberOfLines = 2
|
||||||
|
label.isUserInteractionEnabled = true
|
||||||
|
let tap = UITapGestureRecognizer(target: self, action: #selector(handleEp))
|
||||||
|
label.addGestureRecognizer(tap)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -125,7 +128,15 @@ class FARecommendPlayerControlView: JXPlayerListControlView {
|
|||||||
let videoId = (self.model as? FAVideoInfoModel)?.short_play_video_id
|
let videoId = (self.model as? FAVideoInfoModel)?.short_play_video_id
|
||||||
let isCollect = !(self.shortModel?.is_collect ?? false)
|
let isCollect = !(self.shortModel?.is_collect ?? false)
|
||||||
|
|
||||||
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
if isCollect {
|
||||||
|
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
||||||
|
} else {
|
||||||
|
let alert = FARemoveCollectAlert()
|
||||||
|
alert.clickHighlightButton = {
|
||||||
|
FAAPI.requestShortCollect(isCollect: isCollect, shortPlayId: shortPlayId, videoId: videoId, success: nil)
|
||||||
|
}
|
||||||
|
alert.show()
|
||||||
|
}
|
||||||
|
|
||||||
}), for: .touchUpInside)
|
}), for: .touchUpInside)
|
||||||
|
|
||||||
@ -154,17 +165,20 @@ class FARecommendPlayerControlView: JXPlayerListControlView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateEp() {
|
private func updateEp() {
|
||||||
// let model = self.model as? FAVideoInfoModel
|
// let model = self.model as? FAShortPlayModel
|
||||||
let model = self.model as? FAShortPlayModel
|
// let videoInfo = model?.video_info
|
||||||
let videoInfo = model?.video_info
|
//
|
||||||
|
//
|
||||||
|
// let text = "fableon_episode_set".localizedReplace(text: videoInfo?.episode ?? "") + "/" + "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
||||||
|
// var view = FAPlayerEpUIButton(text: text)
|
||||||
|
// view.clickHandle = { [weak self] in
|
||||||
|
// self?.fa_viewModel?.pushPlayerDetail(self?.shortModel)
|
||||||
|
// }
|
||||||
|
// epButton.rootView = view
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func handleEp() {
|
||||||
let text = "fableon_episode_set".localizedReplace(text: videoInfo?.episode ?? "") + "/" + "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
self.fa_viewModel?.pushPlayerDetail(self.shortModel)
|
||||||
var view = FAPlayerEpUIButton(text: text)
|
|
||||||
view.clickHandle = { [weak self] in
|
|
||||||
self?.fa_viewModel?.pushPlayerDetail(self?.shortModel)
|
|
||||||
}
|
|
||||||
epButton.rootView = view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateProgress() {
|
private func updateProgress() {
|
||||||
@ -191,7 +205,7 @@ extension FARecommendPlayerControlView {
|
|||||||
|
|
||||||
private func fa_setupLayout() {
|
private func fa_setupLayout() {
|
||||||
|
|
||||||
addSubview(epButton.view)
|
// addSubview(epButton.view)
|
||||||
addSubview(progressView)
|
addSubview(progressView)
|
||||||
addSubview(textLabel)
|
addSubview(textLabel)
|
||||||
addSubview(shortNameLabel)
|
addSubview(shortNameLabel)
|
||||||
@ -199,16 +213,17 @@ extension FARecommendPlayerControlView {
|
|||||||
addSubview(collectButton)
|
addSubview(collectButton)
|
||||||
|
|
||||||
|
|
||||||
epButton.view.snp.makeConstraints { make in
|
// epButton.view.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview().offset(16)
|
// make.left.equalToSuperview().offset(16)
|
||||||
make.centerX.equalToSuperview()
|
// make.centerX.equalToSuperview()
|
||||||
make.bottom.equalToSuperview().offset(-10)
|
// make.bottom.equalToSuperview().offset(-10)
|
||||||
}
|
// }
|
||||||
|
|
||||||
progressView.snp.makeConstraints { make in
|
progressView.snp.makeConstraints { make in
|
||||||
make.left.equalToSuperview()
|
make.left.equalToSuperview()
|
||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.bottom.equalTo(epButton.view.snp.top).offset(-8)
|
// make.bottom.equalTo(epButton.view.snp.top).offset(-8)
|
||||||
|
make.bottom.equalToSuperview().offset(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
textLabel.snp.makeConstraints { make in
|
textLabel.snp.makeConstraints { make in
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import JXPlayer
|
|||||||
class FARecommendViewModel: JXPlayerListViewModel {
|
class FARecommendViewModel: JXPlayerListViewModel {
|
||||||
|
|
||||||
private(set) var dataArr: [FAShortPlayModel] = []
|
private(set) var dataArr: [FAShortPlayModel] = []
|
||||||
|
private(set) lazy var page = 1
|
||||||
|
|
||||||
|
|
||||||
var previousEpisode: FAVideoInfoModel? {
|
var previousEpisode: FAVideoInfoModel? {
|
||||||
@ -65,6 +65,7 @@ extension FARecommendViewModel {
|
|||||||
FAAPI.requestRecommendVideo(page: page) { [weak self] listModel in
|
FAAPI.requestRecommendVideo(page: page) { [weak self] listModel in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let listModel = listModel, let list = listModel.list {
|
if let listModel = listModel, let list = listModel.list {
|
||||||
|
self.page = page
|
||||||
if page == 1 {
|
if page == 1 {
|
||||||
self.playerListVC?.clearData()
|
self.playerListVC?.clearData()
|
||||||
self.dataArr = list
|
self.dataArr = list
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class FACoinRecordViewController: FAViewController {
|
|||||||
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
tableView.fa_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return tableView
|
return tableView
|
||||||
@ -65,11 +65,7 @@ extension FACoinRecordViewController: UITableViewDelegate, UITableViewDataSource
|
|||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let model = self.dataArr[indexPath.row]
|
let model = self.dataArr[indexPath.row]
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! FAOrderRecordCell
|
||||||
if model.type == "send" {
|
cell.titleLabel.text = model.type
|
||||||
cell.titleLabel.text = "fableo_bonus_coins".localized
|
|
||||||
} else {
|
|
||||||
cell.titleLabel.text = "fableo_recharge_coins".localized
|
|
||||||
}
|
|
||||||
cell.dateLabel.text = model.created_at
|
cell.dateLabel.text = model.created_at
|
||||||
cell.countLabel.text = "+\(model.value ?? "0")"
|
cell.countLabel.text = "+\(model.value ?? "0")"
|
||||||
return cell
|
return cell
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class FAConsumptionRecordsViewController: FAViewController {
|
|||||||
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
tableView.fa_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return tableView
|
return tableView
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class FARewardCoinsViewController: FAViewController {
|
|||||||
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
tableView.fa_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return tableView
|
return tableView
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class FAStoreViewController: FAViewController {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 12, weight: .medium)
|
label.font = .font(ofSize: 12, weight: .medium)
|
||||||
label.textColor = .FFFFFF
|
label.textColor = .FFFFFF
|
||||||
label.text = "store_tips_title".localized
|
label.text = "fableon_tips".localized
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -130,21 +130,21 @@ class FAStoreViewController: FAViewController {
|
|||||||
self.stackView.fa_removeAllArrangedSubview()
|
self.stackView.fa_removeAllArrangedSubview()
|
||||||
guard let model = self.payDataModel else { return }
|
guard let model = self.payDataModel else { return }
|
||||||
|
|
||||||
if model.pay_mode == 1 {
|
// if model.pay_mode == 1 {
|
||||||
self.addCoinsView()
|
// self.addCoinsView()
|
||||||
} else {
|
// } else {
|
||||||
if let sort = model.sort, sort.count > 0 {
|
// }
|
||||||
sort.forEach {
|
if let sort = model.sort, sort.count > 0 {
|
||||||
if $0 == .vip {
|
sort.forEach {
|
||||||
self.addVipView()
|
if $0 == .vip {
|
||||||
} else if $0 == .coin {
|
self.addVipView()
|
||||||
self.addCoinsView()
|
} else if $0 == .coin {
|
||||||
}
|
self.addCoinsView()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.addVipView()
|
|
||||||
self.addCoinsView()
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.addVipView()
|
||||||
|
self.addCoinsView()
|
||||||
}
|
}
|
||||||
self.stackView.addArrangedSubview(tipView)
|
self.stackView.addArrangedSubview(tipView)
|
||||||
}
|
}
|
||||||
@ -154,18 +154,18 @@ class FAStoreViewController: FAViewController {
|
|||||||
|
|
||||||
var newList: [FAPayItem] = []
|
var newList: [FAPayItem] = []
|
||||||
|
|
||||||
if model.show_type == 1, model.pay_mode == 1 {
|
// if model.show_type == 1, model.pay_mode == 1 {
|
||||||
if let list = model.list_coins, list.count > 0 {
|
// if let list = model.list_coins, list.count > 0 {
|
||||||
list.forEach {
|
// list.forEach {
|
||||||
if $0.buy_type == .subCoins {
|
// if $0.buy_type == .subCoins {
|
||||||
newList.append($0)
|
// newList.append($0)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if let list = model.list_coins, list.count > 0 {
|
// }
|
||||||
newList = list
|
if let list = model.list_coins, list.count > 0 {
|
||||||
}
|
newList = list
|
||||||
}
|
}
|
||||||
if newList.count > 0 {
|
if newList.count > 0 {
|
||||||
coinsView.setDataArr(newList)
|
coinsView.setDataArr(newList)
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class FAVipRecordViewController: FAViewController {
|
|||||||
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
tableView.fa_addRefreshHeader(insetTop: tableView.contentInset.top) { [weak self] in
|
||||||
self?.handleHeaderRefresh(nil)
|
self?.handleHeaderRefresh(nil)
|
||||||
}
|
}
|
||||||
tableView.fa_addRefreshFooter(insetBottom: 0) { [weak self] in
|
tableView.fa_addRefreshFooter(insetBottom: tableView.contentInset.bottom) { [weak self] in
|
||||||
self?.handleFooterRefresh(nil)
|
self?.handleFooterRefresh(nil)
|
||||||
}
|
}
|
||||||
return tableView
|
return tableView
|
||||||
|
|||||||
@ -38,7 +38,7 @@ class FACoinPackConfirmItem2View: FACoinPackConfirmItemView {
|
|||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
self.titleLabel.text = "How Do I Receive Coins?"
|
self.titleLabel.text = "fableon_coin_bag_buy_tip_title".localized
|
||||||
|
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,12 @@ class FAStoreCoinsPackCell: FAStoreCoinsCell {
|
|||||||
override var model: FAPayItem? {
|
override var model: FAPayItem? {
|
||||||
didSet {
|
didSet {
|
||||||
coinsLabel.text = "\(model?.ext_info?.max_total_coins ?? 0)"
|
coinsLabel.text = "\(model?.ext_info?.max_total_coins ?? 0)"
|
||||||
ratioLabel.text = "\(model?.ext_info?.receive_coins_rate ?? "0%")"
|
if let text = model?.ext_info?.receive_coins_rate, !text.isEmpty {
|
||||||
|
ratioLabel.text = text
|
||||||
|
ratioBgView.isHidden = false
|
||||||
|
} else {
|
||||||
|
ratioBgView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
priceView.setNeedsUpdateConfiguration()
|
priceView.setNeedsUpdateConfiguration()
|
||||||
}
|
}
|
||||||
@ -124,9 +129,9 @@ class FAStoreCoinsPackCell: FAStoreCoinsCell {
|
|||||||
|
|
||||||
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
var subtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||||
.foregroundColor : UIColor._636_F_7_B.withAlphaComponent(0.2),
|
.foregroundColor : UIColor._636_F_7_B.withAlphaComponent(0.05),
|
||||||
.strikethroughStyle: NSUnderlineStyle.single.rawValue,
|
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||||
.strikethroughColor: UIColor._636_F_7_B.withAlphaComponent(0.2)
|
.strikethroughColor: UIColor._636_F_7_B.withAlphaComponent(0.05)
|
||||||
]))
|
]))
|
||||||
|
|
||||||
button.configuration?.attributedSubtitle = subtitle
|
button.configuration?.attributedSubtitle = subtitle
|
||||||
|
|||||||
@ -110,7 +110,9 @@ extension FAStoreCoinsView {
|
|||||||
addSubview(collectionView)
|
addSubview(collectionView)
|
||||||
|
|
||||||
collectionView.snp.makeConstraints { make in
|
collectionView.snp.makeConstraints { make in
|
||||||
make.edges.equalToSuperview()
|
// make.edges.equalToSuperview()
|
||||||
|
make.top.equalToSuperview().offset(8)
|
||||||
|
make.left.right.bottom.equalToSuperview()
|
||||||
make.height.equalTo(1)
|
make.height.equalTo(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -190,6 +192,8 @@ extension FAStoreCoinsView: UICollectionViewDelegate, UICollectionViewDataSource
|
|||||||
|
|
||||||
if model.buy_type == .subCoins {
|
if model.buy_type == .subCoins {
|
||||||
let view = FACoinPackConfirmView()
|
let view = FACoinPackConfirmView()
|
||||||
|
view.shortPlayId = self.shortPlayId
|
||||||
|
view.videoId = self.videoId
|
||||||
view.model = model
|
view.model = model
|
||||||
view.buyFinishHandle = { [weak self] in
|
view.buyFinishHandle = { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class FAStoreVipCell: UICollectionViewCell {
|
|||||||
|
|
||||||
var item: FAPayItem? {
|
var item: FAPayItem? {
|
||||||
didSet {
|
didSet {
|
||||||
nameLabel.text = item?.title
|
nameLabel.text = item?.brief
|
||||||
desLabel.text = item?.fa_description
|
desLabel.text = item?.fa_description
|
||||||
// coinTimeLabel.text = item?.auto_sub
|
// coinTimeLabel.text = item?.auto_sub
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ class FAStoreVipCell: UICollectionViewCell {
|
|||||||
|
|
||||||
let oldPriceStr = NSMutableAttributedString(string: oldPrice)
|
let oldPriceStr = NSMutableAttributedString(string: oldPrice)
|
||||||
oldPriceStr.yy_strikethroughColor = discountLabel.textColor
|
oldPriceStr.yy_strikethroughColor = discountLabel.textColor
|
||||||
oldPriceStr.yy_strikethroughStyle = .single
|
oldPriceStr.yy_strikethroughStyle = .double
|
||||||
discountLabel.attributedText = oldPriceStr
|
discountLabel.attributedText = oldPriceStr
|
||||||
|
|
||||||
discountLabel.isHidden = false
|
discountLabel.isHidden = false
|
||||||
@ -156,7 +156,7 @@ class FAStoreVipCell: UICollectionViewCell {
|
|||||||
private lazy var discountLabel: UILabel = {
|
private lazy var discountLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .font(ofSize: 16, weight: .medium)
|
label.font = .font(ofSize: 16, weight: .medium)
|
||||||
label.textColor = .FFFFFF.withAlphaComponent(0.4)
|
label.textColor = .FFFFFF.withAlphaComponent(0.03)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@ -20,16 +20,18 @@ class FAStoreVipView: UIView {
|
|||||||
|
|
||||||
var buyFinishHandle: (() -> Void)?
|
var buyFinishHandle: (() -> Void)?
|
||||||
|
|
||||||
|
|
||||||
private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
private lazy var collectionViewLayout: UICollectionViewCompositionalLayout = {
|
||||||
|
|
||||||
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
let item = NSCollectionLayoutItem(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1)))
|
||||||
|
|
||||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(110)), subitems: [item])
|
let group = NSCollectionLayoutGroup.horizontal(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(110)), subitems: [item])
|
||||||
group.interItemSpacing = .fixed(14)
|
|
||||||
|
|
||||||
let layoutSection = NSCollectionLayoutSection(group: group)
|
let layoutSection = NSCollectionLayoutSection(group: group)
|
||||||
|
layoutSection.interGroupSpacing = 14
|
||||||
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
layoutSection.contentInsets = .init(top: 0, leading: 16, bottom: 0, trailing: 16)
|
||||||
|
|
||||||
|
|
||||||
let config = UICollectionViewCompositionalLayoutConfiguration()
|
let config = UICollectionViewCompositionalLayoutConfiguration()
|
||||||
|
|
||||||
let layout = UICollectionViewCompositionalLayout(section: layoutSection)
|
let layout = UICollectionViewCompositionalLayout(section: layoutSection)
|
||||||
|
|||||||
62
Fableon/Object/Libs/ActivityManager/FAActivityManager.swift
Normal file
62
Fableon/Object/Libs/ActivityManager/FAActivityManager.swift
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//
|
||||||
|
// FAActivityManager.swift
|
||||||
|
// Fableon
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import ActivityKit
|
||||||
|
|
||||||
|
struct ActivityManagerAttributes: ActivityAttributes {
|
||||||
|
public struct ContentState: Codable, Hashable {
|
||||||
|
// Dynamic stateful properties about your activity go here!
|
||||||
|
var videoTitle: String
|
||||||
|
var videoCoverPath: String
|
||||||
|
var videoEpisode:String
|
||||||
|
var videoId: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed non-changing properties about your activity go here!
|
||||||
|
var name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 16.1, *)
|
||||||
|
class FAActivityManager {
|
||||||
|
static var coverFileUrl: URL? {
|
||||||
|
let sharedContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.hn.qinjiu.fableon")
|
||||||
|
let fileURL = sharedContainerURL?.appendingPathComponent("cover.png")
|
||||||
|
return fileURL
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc public static func liveActivity(with videoTitle: String, videoId: String, videoEpisode: String) {
|
||||||
|
|
||||||
|
let fileURL = self.coverFileUrl?.absoluteString ?? ""
|
||||||
|
|
||||||
|
let contentState = ActivityManagerAttributes.ContentState(videoTitle: videoTitle,
|
||||||
|
videoCoverPath: fileURL,
|
||||||
|
videoEpisode: videoEpisode,
|
||||||
|
videoId:videoId)
|
||||||
|
|
||||||
|
do {
|
||||||
|
if Activity<ActivityManagerAttributes>.activities.count == 0 {
|
||||||
|
let attributes = ActivityManagerAttributes(name: "live activity")
|
||||||
|
let activity = try Activity<ActivityManagerAttributes>.request(attributes: attributes,
|
||||||
|
contentState: contentState,
|
||||||
|
pushType: nil)
|
||||||
|
|
||||||
|
print("Requested a pizza delivery Live Activity \(activity.id)")
|
||||||
|
} else {
|
||||||
|
Task {
|
||||||
|
for activity in Activity<ActivityManagerAttributes>.activities {
|
||||||
|
await activity.update(using: contentState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (let error) {
|
||||||
|
print("Error requesting pizza delivery Live Activity \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,5 +20,14 @@ class FAAdjustStateManager {
|
|||||||
|
|
||||||
var idfaAuthorizationFinish = false
|
var idfaAuthorizationFinish = false
|
||||||
|
|
||||||
var apnsAuthorizationFinish = false
|
private(set) var apnsAuthorizationFinish = false
|
||||||
|
|
||||||
|
var upgradeAlertFinish = false
|
||||||
|
|
||||||
|
|
||||||
|
func apnsFinish() {
|
||||||
|
self.apnsAuthorizationFinish = true
|
||||||
|
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||||
|
FATool.requestIDFAAuthorization(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,6 +58,12 @@ class FAApnsAlert: FABaseAlert {
|
|||||||
override func handleHighlightButton() {
|
override func handleHighlightButton() {
|
||||||
super.handleHighlightButton()
|
super.handleHighlightButton()
|
||||||
FATool.openApnsSetting()
|
FATool.openApnsSetting()
|
||||||
|
FAAdjustStateManager.manager.apnsFinish()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func dismiss() {
|
||||||
|
super.dismiss()
|
||||||
|
FAAdjustStateManager.manager.apnsFinish()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ class FAUpdatesAlert: FABaseAlert {
|
|||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
highlightButton.layer.cornerRadius = 18
|
highlightButton.layer.cornerRadius = 18
|
||||||
highlightButton.setTitle("fableon_update_now", for: .normal)
|
highlightButton.setTitle("fableon_update_now".localized, for: .normal)
|
||||||
fa_setupLayout()
|
fa_setupLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +74,12 @@ class FAUpdatesAlert: FABaseAlert {
|
|||||||
application.open(url)
|
application.open(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func dismiss() {
|
||||||
|
super.dismiss()
|
||||||
|
FAAdjustStateManager.manager.upgradeAlertFinish = true
|
||||||
|
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension FAUpdatesAlert {
|
extension FAUpdatesAlert {
|
||||||
|
|||||||
@ -132,6 +132,7 @@ extension FAVipRetainAlert {
|
|||||||
var payItem: FAPayItem? {
|
var payItem: FAPayItem? {
|
||||||
didSet {
|
didSet {
|
||||||
nameLabel.text = payItem?.getVipTitle()
|
nameLabel.text = payItem?.getVipTitle()
|
||||||
|
textLabel.text = "vip_tip_01".localized
|
||||||
|
|
||||||
button.setNeedsUpdateConfiguration()
|
button.setNeedsUpdateConfiguration()
|
||||||
}
|
}
|
||||||
@ -215,9 +216,9 @@ extension FAVipRetainAlert {
|
|||||||
|
|
||||||
button.configuration?.attributedSubtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
button.configuration?.attributedSubtitle = AttributedString("\(currency)\(oldPrice)", attributes: AttributeContainer([
|
||||||
.font : UIFont.font(ofSize: 12, weight: .regular),
|
.font : UIFont.font(ofSize: 12, weight: .regular),
|
||||||
.foregroundColor : UIColor._000000.withAlphaComponent(0.5),
|
.foregroundColor : UIColor._000000.withAlphaComponent(0.05),
|
||||||
.strikethroughStyle: NSUnderlineStyle.single.rawValue,
|
.strikethroughStyle: NSUnderlineStyle.double.rawValue,
|
||||||
.strikethroughColor: UIColor._000000.withAlphaComponent(0.5)
|
.strikethroughColor: UIColor._000000.withAlphaComponent(0.05)
|
||||||
]))
|
]))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -239,7 +240,7 @@ extension FAVipRetainAlert {
|
|||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
nameLabel.text = "Weekly VIP"
|
nameLabel.text = "Weekly VIP"
|
||||||
textLabel.text = "Unlimited access to all series"
|
|
||||||
|
|
||||||
addSubview(bgView)
|
addSubview(bgView)
|
||||||
bgView.addSubview(bgIconImageView4)
|
bgView.addSubview(bgIconImageView4)
|
||||||
|
|||||||
@ -24,4 +24,33 @@ struct FAEmpty {
|
|||||||
return view!
|
return view!
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func fa_notNetworkEmptyView(clickBlock: (() -> Void)?) -> LYEmptyView {
|
||||||
|
|
||||||
|
let view = LYEmptyView.emptyActionView(with: UIImage(named: "__startap"), titleStr: "No connection", detailStr: "Please check your network", btnTitleStr: "Try again") {
|
||||||
|
clickBlock?()
|
||||||
|
}
|
||||||
|
|
||||||
|
view?.titleLabFont = .font(ofSize: 17, weight: .bold)
|
||||||
|
view?.titleLabTextColor = .FFFFFF
|
||||||
|
view?.detailLabFont = .font(ofSize: 15, weight: .regular)
|
||||||
|
view?.detailLabTextColor = .E_5_E_5_E_5
|
||||||
|
|
||||||
|
view?.actionBtnHeight = 32
|
||||||
|
view?.actionBtnHorizontalMargin = 26
|
||||||
|
view?.actionBtnCornerRadius = 16
|
||||||
|
view?.actionBtnBorderWidth = 1
|
||||||
|
view?.actionBtnBorderColor = .FFFFFF
|
||||||
|
view?.actionBtnBackGroundColor = .clear
|
||||||
|
view?.actionBtnTitleColor = .FFFFFF
|
||||||
|
view?.actionBtnFont = .font(ofSize: 14, weight: .medium)
|
||||||
|
|
||||||
|
view?.contentViewOffset = -20
|
||||||
|
view?.titleLabMargin = 30
|
||||||
|
view?.detailLabMargin = 2
|
||||||
|
view?.actionBtnMargin = 20
|
||||||
|
return view!
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,6 +77,7 @@ class FALogin: NSObject {
|
|||||||
FAStatAPI.requestStatOnLine()
|
FAStatAPI.requestStatOnLine()
|
||||||
completer?(true)
|
completer?(true)
|
||||||
NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil)
|
NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil)
|
||||||
|
NotificationCenter.default.post(name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +94,7 @@ class FALogin: NSObject {
|
|||||||
FAStatAPI.requestStatOnLine()
|
FAStatAPI.requestStatOnLine()
|
||||||
completer?(true)
|
completer?(true)
|
||||||
NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil)
|
NotificationCenter.default.post(name: FALogin.userInfoUpdateNotification, object: nil)
|
||||||
|
NotificationCenter.default.post(name: FALogin.loginStatusChangeNotification, object: nil)
|
||||||
} else {
|
} else {
|
||||||
completer?(false)
|
completer?(false)
|
||||||
}
|
}
|
||||||
@ -129,5 +131,7 @@ extension FALogin {
|
|||||||
|
|
||||||
///用户信息更新
|
///用户信息更新
|
||||||
@objc static let userInfoUpdateNotification = NSNotification.Name(rawValue: "FALogin.userInfoUpdateNotification")
|
@objc static let userInfoUpdateNotification = NSNotification.Name(rawValue: "FALogin.userInfoUpdateNotification")
|
||||||
|
///登录状态发生变化
|
||||||
|
@objc static let loginStatusChangeNotification = NSNotification.Name(rawValue: "FALogin.loginStatusChangeNotification")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,9 @@ class FATool {
|
|||||||
return keyWindow?.rootViewController
|
return keyWindow?.rootViewController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///灵动岛数据
|
||||||
|
static var widgetLiveActivityModel: FAShortPlayModel?
|
||||||
|
|
||||||
///获得启动图
|
///获得启动图
|
||||||
static func getLanuchViewController() -> UIViewController? {
|
static func getLanuchViewController() -> UIViewController? {
|
||||||
let storyboard = UIStoryboard(name: "LaunchScreen", bundle: nil)
|
let storyboard = UIStoryboard(name: "LaunchScreen", bundle: nil)
|
||||||
@ -102,18 +105,31 @@ extension FATool {
|
|||||||
//MARK: 检查更新
|
//MARK: 检查更新
|
||||||
extension FATool {
|
extension FATool {
|
||||||
|
|
||||||
|
static weak var updateAlert: UIView?
|
||||||
|
|
||||||
static func checkUpdates() {
|
static func checkUpdates() {
|
||||||
|
guard self.self.updateAlert == nil else { return }
|
||||||
|
|
||||||
FAAPI.requestVersionUpdateData { model in
|
FAAPI.requestVersionUpdateData { model in
|
||||||
guard let model = model else { return }
|
guard let model = model else {
|
||||||
|
FAAdjustStateManager.manager.upgradeAlertFinish = true
|
||||||
|
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
self.showUpdatesAlert(model)
|
self.showUpdatesAlert(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static func showUpdatesAlert(_ model: FAVersionUpdateModel) {
|
static func showUpdatesAlert(_ model: FAVersionUpdateModel) {
|
||||||
|
guard self.self.updateAlert == nil else { return }
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if model.force != true {
|
if model.force != true {
|
||||||
if let date = UserDefaults.standard.object(forKey: kFAVersionUpdateAlertDefaultsKey) as? Date {
|
if let date = UserDefaults.standard.object(forKey: kFAVersionUpdateAlertDefaultsKey) as? Date {
|
||||||
if date.fa_isToday { return }
|
if date.fa_isToday {
|
||||||
|
FAAdjustStateManager.manager.upgradeAlertFinish = true
|
||||||
|
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UserDefaults.standard.set(Date(), forKey: kFAVersionUpdateAlertDefaultsKey)
|
UserDefaults.standard.set(Date(), forKey: kFAVersionUpdateAlertDefaultsKey)
|
||||||
}
|
}
|
||||||
@ -121,9 +137,17 @@ extension FATool {
|
|||||||
|
|
||||||
|
|
||||||
if model.canUpdate() {
|
if model.canUpdate() {
|
||||||
|
FAStatAPI.requestEventStat(orderCode: nil, shortPlayId: nil, videoId: nil, eventKey: .forceUpdate, errorMsg: nil, otherParamenters: [
|
||||||
|
"is_force" : model.force == true ? "true" : "false"
|
||||||
|
])
|
||||||
|
|
||||||
let view = FAUpdatesAlert()
|
let view = FAUpdatesAlert()
|
||||||
view.model = model
|
view.model = model
|
||||||
view.show()
|
view.show()
|
||||||
|
self.updateAlert = view
|
||||||
|
} else {
|
||||||
|
FAAdjustStateManager.manager.upgradeAlertFinish = true
|
||||||
|
FATool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x3B",
|
||||||
|
"green" : "0x31",
|
||||||
|
"red" : "0xFF"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,12 +5,12 @@
|
|||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "Thalire@2x.png",
|
"filename" : "Fableon@2x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename" : "Thalire@3x.png",
|
"filename" : "Fableon@3x.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Fableon/Source/Assets.xcassets/image/Thalire.imageset/Fableon@2x.png
vendored
Normal file
BIN
Fableon/Source/Assets.xcassets/image/Thalire.imageset/Fableon@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Fableon/Source/Assets.xcassets/image/Thalire.imageset/Fableon@3x.png
vendored
Normal file
BIN
Fableon/Source/Assets.xcassets/image/Thalire.imageset/Fableon@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB |
22
Fableon/Source/Assets.xcassets/image/__startap.imageset/Contents.json
vendored
Normal file
22
Fableon/Source/Assets.xcassets/image/__startap.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "__startap@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "__startap@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Fableon/Source/Assets.xcassets/image/__startap.imageset/__startap@2x.png
vendored
Normal file
BIN
Fableon/Source/Assets.xcassets/image/__startap.imageset/__startap@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
BIN
Fableon/Source/Assets.xcassets/image/__startap.imageset/__startap@3x.png
vendored
Normal file
BIN
Fableon/Source/Assets.xcassets/image/__startap.imageset/__startap@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@ -46,5 +46,12 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>UIBackgroundModes</key>
|
||||||
|
<array>
|
||||||
|
<string>fetch</string>
|
||||||
|
<string>remote-notification</string>
|
||||||
|
</array>
|
||||||
|
<key>UIDesignRequiresCompatibility</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -91,6 +91,13 @@
|
|||||||
"fableon_editor's_picks" = "Editor's Picks";
|
"fableon_editor's_picks" = "Editor's Picks";
|
||||||
"fableon_home_new" = "New Releases";
|
"fableon_home_new" = "New Releases";
|
||||||
"fableon_watch" = "Watch";
|
"fableon_watch" = "Watch";
|
||||||
|
"fableon_top_up" = "Top Up";
|
||||||
|
"fableon_selection" = "selection";
|
||||||
|
"fableon_coin_bag_buy_tip_title" = "How Do I Receive Coins?";
|
||||||
|
"fableon_d" = "Day";
|
||||||
|
"fableon_kick_out_login" = "Your account is already logged in on another device~";
|
||||||
|
"fableon_rabkings" = "Rankings";
|
||||||
|
"fableon_recommended_for_you" = "Recommended for you";
|
||||||
|
|
||||||
"remove_collect_alert_title" = "Remove from Favorites?";
|
"remove_collect_alert_title" = "Remove from Favorites?";
|
||||||
"remove_collect_alert_text" = "This drama will be removed from your favorites.";
|
"remove_collect_alert_text" = "This drama will be removed from your favorites.";
|
||||||
@ -107,6 +114,7 @@
|
|||||||
|
|
||||||
"network_error_01" = "The service is abnormal. Check the network.";
|
"network_error_01" = "The service is abnormal. Check the network.";
|
||||||
|
|
||||||
|
|
||||||
"buy_fail_toast_01" = "Purchase failed, please try again later!";
|
"buy_fail_toast_01" = "Purchase failed, please try again later!";
|
||||||
"buy_fail_toast_02" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
|
"buy_fail_toast_02" = "The prequel to this series is not unlocked. Please unlock the prequel before unlocking this series";
|
||||||
|
|
||||||
@ -130,4 +138,4 @@
|
|||||||
|
|
||||||
|
|
||||||
"coins_pack_tips_title" = "Subscription Rules";
|
"coins_pack_tips_title" = "Subscription Rules";
|
||||||
"coins_pack_tips" = "1.Up to 2 subscriptions can be active at once.<br>2.Coins are delivered instantly upon purchase.<br>3.Daily bonus coins available from the next day.<br>4.All coins will be revoked when the subscription expires, including both initial and daily coins.";
|
"coins_pack_tips" = "1.Coins are delivered instantly upon purchase.<br>2.Daily bonus coins available from the next day.<br>3.All coins will be revoked when the subscription expires, including both initial and daily coins.";
|
||||||
|
|||||||
@ -169,7 +169,7 @@ withUnsafeMutablePointer(to: &writeclearWatchdog) { pointer in
|
|||||||
$0.title = "fableon_popular".localized
|
$0.title = "fableon_popular".localized
|
||||||
popularItem = $0
|
popularItem = $0
|
||||||
} else if $0.module_key == .week_ranking {
|
} else if $0.module_key == .week_ranking {
|
||||||
$0.title = "Rankings".localized
|
$0.title = "fableon_rabkings".localized
|
||||||
rankingsItem = $0
|
rankingsItem = $0
|
||||||
} else if $0.module_key == .cagetory_recommand, genresItem == nil {
|
} else if $0.module_key == .cagetory_recommand, genresItem == nil {
|
||||||
$0.title = "veloriaDetailPath".localized
|
$0.title = "veloriaDetailPath".localized
|
||||||
|
|||||||
@ -74,7 +74,7 @@ var deceleratingMax: Double = 0.0
|
|||||||
}
|
}
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text("selection".localized)
|
Text("fableon_selection".localized)
|
||||||
.font(Font.font(size: 12, weight: .medium))
|
.font(Font.font(size: 12, weight: .medium))
|
||||||
.foregroundStyle(textColor)
|
.foregroundStyle(textColor)
|
||||||
.padding(.leading, 8)
|
.padding(.leading, 8)
|
||||||
|
|||||||
@ -16,8 +16,14 @@ var bottomProgressDict: [String: Any]?
|
|||||||
didSet {
|
didSet {
|
||||||
coverImageView.fa_setImage(model?.image_url)
|
coverImageView.fa_setImage(model?.image_url)
|
||||||
titleLabel.text = model?.name
|
titleLabel.text = model?.name
|
||||||
countLabel.text = "\(model?.watch_total ?? 0)"
|
|
||||||
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
epLabel.text = "fableon_episode_set".localizedReplace(text: "\(model?.episode_total ?? 0)")
|
||||||
|
|
||||||
|
let count = model?.watch_total ?? 0
|
||||||
|
var countStr = "\(count)"
|
||||||
|
if count > 1000 {
|
||||||
|
countStr = NSNumber(value: CGFloat(count) / 1000).toString(maximumFractionDigits: 1) + "k"
|
||||||
|
}
|
||||||
|
countLabel.text = countStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
NotificationService/Info.plist
Normal file
13
NotificationService/Info.plist
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.usernotifications.service</string>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
69
NotificationService/NotificationService.swift
Normal file
69
NotificationService/NotificationService.swift
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
//
|
||||||
|
// NotificationService.swift
|
||||||
|
// NotificationService
|
||||||
|
//
|
||||||
|
// Created by 湖北秦九 on 2025/11/10.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
|
class NotificationService: UNNotificationServiceExtension {
|
||||||
|
|
||||||
|
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||||
|
var bestAttemptContent: UNMutableNotificationContent?
|
||||||
|
|
||||||
|
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||||
|
|
||||||
|
self.contentHandler = contentHandler
|
||||||
|
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
|
||||||
|
|
||||||
|
guard let bestAttemptContent = bestAttemptContent else {
|
||||||
|
contentHandler(request.content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let options = request.content.userInfo["fcm_options"] as? [String : Any],
|
||||||
|
let imageURLString = options["image"] as? String,
|
||||||
|
let imageURL = URL(string: imageURLString) {
|
||||||
|
|
||||||
|
downloadImage(from: imageURL) { attachment in
|
||||||
|
if let attachment = attachment {
|
||||||
|
bestAttemptContent.attachments = [attachment]
|
||||||
|
}
|
||||||
|
contentHandler(bestAttemptContent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contentHandler(bestAttemptContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func serviceExtensionTimeWillExpire() {
|
||||||
|
// Called just before the extension will be terminated by the system.
|
||||||
|
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
|
||||||
|
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
|
||||||
|
contentHandler(bestAttemptContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func downloadImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
|
||||||
|
let task = URLSession.shared.downloadTask(with: url) { (downloadedUrl, _, error) in
|
||||||
|
guard let downloadedUrl = downloadedUrl else {
|
||||||
|
completion(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let tmpDir = FileManager.default.temporaryDirectory
|
||||||
|
let tmpFile = tmpDir.appendingPathComponent(url.lastPathComponent)
|
||||||
|
|
||||||
|
do {
|
||||||
|
try FileManager.default.moveItem(at: downloadedUrl, to: tmpFile)
|
||||||
|
let attachment = try UNNotificationAttachment(identifier: UUID().uuidString, url: tmpFile, options: nil)
|
||||||
|
completion(attachment)
|
||||||
|
} catch {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task.resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
Podfile
2
Podfile
@ -20,7 +20,7 @@ target 'Fableon' do
|
|||||||
pod 'YYText'
|
pod 'YYText'
|
||||||
pod 'Alamofire'
|
pod 'Alamofire'
|
||||||
pod 'SmartCodable'
|
pod 'SmartCodable'
|
||||||
pod 'JXPlayer', '~> 0.1.5'
|
pod 'JXPlayer', '~> 0.1.8'
|
||||||
pod 'Kingfisher'
|
pod 'Kingfisher'
|
||||||
pod 'SnapKit'
|
pod 'SnapKit'
|
||||||
pod 'FSPagerView'
|
pod 'FSPagerView'
|
||||||
|
|||||||
20
Podfile.lock
20
Podfile.lock
@ -50,9 +50,9 @@ PODS:
|
|||||||
- IQTextView (1.0.5):
|
- IQTextView (1.0.5):
|
||||||
- IQKeyboardToolbar/Placeholderable
|
- IQKeyboardToolbar/Placeholderable
|
||||||
- JXPagingView/Paging (2.1.3)
|
- JXPagingView/Paging (2.1.3)
|
||||||
- JXPlayer (0.1.5):
|
- JXPlayer (0.1.8):
|
||||||
- SJMediaCacheServer
|
- SJMediaCacheServer (= 2.1.6)
|
||||||
- SJVideoPlayer
|
- SJVideoPlayer (= 3.4.3)
|
||||||
- JXSegmentedView (1.4.1)
|
- JXSegmentedView (1.4.1)
|
||||||
- Kingfisher (8.5.0)
|
- Kingfisher (8.5.0)
|
||||||
- LYEmptyView (1.3.1)
|
- LYEmptyView (1.3.1)
|
||||||
@ -86,10 +86,10 @@ PODS:
|
|||||||
- SJUIKit/ObserverHelper
|
- SJUIKit/ObserverHelper
|
||||||
- SJUIKit/Queues
|
- SJUIKit/Queues
|
||||||
- SJUIKit/SQLite3
|
- SJUIKit/SQLite3
|
||||||
- SJMediaCacheServer (2.1.7):
|
- SJMediaCacheServer (2.1.6):
|
||||||
- SJMediaCacheServer/Core (= 2.1.7)
|
- SJMediaCacheServer/Core (= 2.1.6)
|
||||||
- SJUIKit/SQLite3
|
- SJUIKit/SQLite3
|
||||||
- SJMediaCacheServer/Core (2.1.7):
|
- SJMediaCacheServer/Core (2.1.6):
|
||||||
- SJUIKit/SQLite3
|
- SJUIKit/SQLite3
|
||||||
- SJUIKit/AttributesFactory (0.0.0.59):
|
- SJUIKit/AttributesFactory (0.0.0.59):
|
||||||
- SJUIKit/AttributesFactory/Deprecated (= 0.0.0.59)
|
- SJUIKit/AttributesFactory/Deprecated (= 0.0.0.59)
|
||||||
@ -148,7 +148,7 @@ DEPENDENCIES:
|
|||||||
- HWPanModal
|
- HWPanModal
|
||||||
- IQKeyboardManagerSwift
|
- IQKeyboardManagerSwift
|
||||||
- JXPagingView/Paging
|
- JXPagingView/Paging
|
||||||
- JXPlayer (~> 0.1.5)
|
- JXPlayer (~> 0.1.8)
|
||||||
- JXSegmentedView
|
- JXSegmentedView
|
||||||
- Kingfisher
|
- Kingfisher
|
||||||
- LYEmptyView
|
- LYEmptyView
|
||||||
@ -215,14 +215,14 @@ SPEC CHECKSUMS:
|
|||||||
IQTextInputViewNotification: 3b9fb27a16e7ee8958cc9092cfb07a1a9e1fd559
|
IQTextInputViewNotification: 3b9fb27a16e7ee8958cc9092cfb07a1a9e1fd559
|
||||||
IQTextView: ae13b4922f22e6f027f62c557d9f4f236b19d5c7
|
IQTextView: ae13b4922f22e6f027f62c557d9f4f236b19d5c7
|
||||||
JXPagingView: afdd2e9af09c90160dd232b970d603cc6e7ddd0e
|
JXPagingView: afdd2e9af09c90160dd232b970d603cc6e7ddd0e
|
||||||
JXPlayer: 0e0cd9a2ee406ebb3051d00c760cd5fc599bf09b
|
JXPlayer: 8ca57987b506419cb51a8c84e6196c25043634ca
|
||||||
JXSegmentedView: cd73555ce2134d1656db2cb383ba9c2f36fb5078
|
JXSegmentedView: cd73555ce2134d1656db2cb383ba9c2f36fb5078
|
||||||
Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c
|
Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c
|
||||||
LYEmptyView: b6d418cfa38b78df0cf243f9a9c25ccbdc399922
|
LYEmptyView: b6d418cfa38b78df0cf243f9a9c25ccbdc399922
|
||||||
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
|
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
|
||||||
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
|
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
|
||||||
SJBaseVideoPlayer: b3122de12225b27b71bd9a8a1f08f4dcf2f4e5ec
|
SJBaseVideoPlayer: b3122de12225b27b71bd9a8a1f08f4dcf2f4e5ec
|
||||||
SJMediaCacheServer: 0ca17fcdd5340fe1d2ad03110e511376f290d924
|
SJMediaCacheServer: f6cd08ff32f5c6fc18ff06e676b42d6c17ce4cf1
|
||||||
SJUIKit: a40111941e408cc17d4c1c23495aa92999e814b0
|
SJUIKit: a40111941e408cc17d4c1c23495aa92999e814b0
|
||||||
SJVideoPlayer: 4f09814f58522e0975cb2dccfda925f6c8643467
|
SJVideoPlayer: 4f09814f58522e0975cb2dccfda925f6c8643467
|
||||||
SmartCodable: 545dd052990fe7e80085463b79a1a5e462ee29ff
|
SmartCodable: 545dd052990fe7e80085463b79a1a5e462ee29ff
|
||||||
@ -234,6 +234,6 @@ SPEC CHECKSUMS:
|
|||||||
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
|
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
|
||||||
ZLPhotoBrowser: d5928f08485c90a0b349a3a1e804e82c83ccf193
|
ZLPhotoBrowser: d5928f08485c90a0b349a3a1e804e82c83ccf193
|
||||||
|
|
||||||
PODFILE CHECKSUM: ee93369942c41a1babdca4fd27a29e21997fc357
|
PODFILE CHECKSUM: 0d6c1bc4222cac60ce66cfe1a22456b0a9cc1685
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user