登录功能完成
1
Podfile
@ -33,5 +33,6 @@ target 'ReaderHive' do
|
||||
pod 'Toast'
|
||||
pod 'SVProgressHUD'
|
||||
pod 'FDFullscreenPopGesture'
|
||||
pod 'ZLPhotoBrowser'
|
||||
|
||||
end
|
||||
|
||||
@ -96,6 +96,12 @@
|
||||
85CF94292EED4664006467E3 /* NRVipRetainAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */; };
|
||||
85CF942B2EED47F2006467E3 /* NRVipRetainItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */; };
|
||||
85CF942D2EED5204006467E3 /* NRPayAlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */; };
|
||||
85CF942F2EEFB2CF006467E3 /* NRLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */; };
|
||||
85CF94312EEFDA88006467E3 /* NRLoginManager+Apple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */; };
|
||||
85CF94332EEFDAF4006467E3 /* NRThirdSignModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */; };
|
||||
85CF94372EEFE27E006467E3 /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 85CF94362EEFE27E006467E3 /* FacebookLogin */; };
|
||||
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */; };
|
||||
85CF943B2EEFE94C006467E3 /* AppDelegate+Open.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */; };
|
||||
F34348AF2ED5B85300AA7E70 /* NRExploreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */; };
|
||||
F34348B12ED5B9A400AA7E70 /* NRExploreNovelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */; };
|
||||
F34348B32ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34348B22ED5BB6100AA7E70 /* NRExploreNovelMenuView.swift */; };
|
||||
@ -327,6 +333,12 @@
|
||||
85CF94282EED4664006467E3 /* NRVipRetainAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainAlert.swift; sourceTree = "<group>"; };
|
||||
85CF942A2EED47F2006467E3 /* NRVipRetainItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRVipRetainItemView.swift; sourceTree = "<group>"; };
|
||||
85CF942C2EED5204006467E3 /* NRPayAlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRPayAlertModel.swift; sourceTree = "<group>"; };
|
||||
85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRLoginView.swift; sourceTree = "<group>"; };
|
||||
85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NRLoginManager+Apple.swift"; sourceTree = "<group>"; };
|
||||
85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRThirdSignModel.swift; sourceTree = "<group>"; };
|
||||
85CF94342EEFDFAC006467E3 /* ReaderHive.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ReaderHive.entitlements; sourceTree = "<group>"; };
|
||||
85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NRLoginManager+Facebook.swift"; sourceTree = "<group>"; };
|
||||
85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Open.swift"; sourceTree = "<group>"; };
|
||||
C3BEE224CB3F55939653D26D /* Pods-NovelReader.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NovelReader.debug.xcconfig"; path = "Target Support Files/Pods-NovelReader/Pods-NovelReader.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
F34348AE2ED5B85300AA7E70 /* NRExploreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreViewController.swift; sourceTree = "<group>"; };
|
||||
F34348B02ED5B9A400AA7E70 /* NRExploreNovelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NRExploreNovelViewController.swift; sourceTree = "<group>"; };
|
||||
@ -469,6 +481,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
85CF94372EEFE27E006467E3 /* FacebookLogin in Frameworks */,
|
||||
67DC33BD353DB9F2D4C0FFE8 /* Pods_ReaderHive.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -588,6 +601,7 @@
|
||||
03980F862ED009EB0006E317 /* ReaderHive */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
85CF94342EEFDFAC006467E3 /* ReaderHive.entitlements */,
|
||||
03980F8F2ED00ACD0006E317 /* Delegate */,
|
||||
039810562ED046030006E317 /* Base */,
|
||||
039810752ED054090006E317 /* Class */,
|
||||
@ -615,6 +629,7 @@
|
||||
03980F7D2ED009EB0006E317 /* AppDelegate.swift */,
|
||||
03980F842ED009EB0006E317 /* SceneDelegate.swift */,
|
||||
0398107B2ED0551C0006E317 /* AppDelegate+Config.swift */,
|
||||
85CF943A2EEFE947006467E3 /* AppDelegate+Open.swift */,
|
||||
);
|
||||
path = Delegate;
|
||||
sourceTree = "<group>";
|
||||
@ -728,8 +743,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0398107E2ED055D10006E317 /* NRLoginManager.swift */,
|
||||
85CF94302EEFDA82006467E3 /* NRLoginManager+Apple.swift */,
|
||||
85CF94382EEFE34F006467E3 /* NRLoginManager+Facebook.swift */,
|
||||
039810802ED056090006E317 /* NRLoginToken.swift */,
|
||||
039810822ED0563D0006E317 /* NRUserInfo.swift */,
|
||||
85CF94322EEFDAF4006467E3 /* NRThirdSignModel.swift */,
|
||||
);
|
||||
path = Login;
|
||||
sourceTree = "<group>";
|
||||
@ -1027,6 +1045,7 @@
|
||||
F349910A2EE16B520039E939 /* NRAboutCell.swift */,
|
||||
F34991172EE1780A0039E939 /* NRNovelHistoryCell.swift */,
|
||||
F3B859382EE676610095A9CC /* NRLanguageCell.swift */,
|
||||
85CF942E2EEFB2CF006467E3 /* NRLoginView.swift */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@ -1222,6 +1241,9 @@
|
||||
);
|
||||
mainGroup = 03980F5C2ED009E30006E317;
|
||||
minimizedProjectReferenceProxies = 1;
|
||||
packageReferences = (
|
||||
85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */,
|
||||
);
|
||||
preferredProjectObjectVersion = 77;
|
||||
productRefGroup = 03980F662ED009E30006E317 /* Products */;
|
||||
projectDirPath = "";
|
||||
@ -1299,9 +1321,11 @@
|
||||
files = (
|
||||
F34991252EE27DB60039E939 /* NRGradientButton.swift in Sources */,
|
||||
F34348FD2ED8561300AA7E70 /* NRNovelReadContentBottomView.swift in Sources */,
|
||||
85CF94332EEFDAF4006467E3 /* NRThirdSignModel.swift in Sources */,
|
||||
F34348C52ED6CA4D00AA7E70 /* NRExploreNovelMenuDataSource.swift in Sources */,
|
||||
F343492A2EDD93AD00AA7E70 /* NRReadSettingFontView.swift in Sources */,
|
||||
039810982ED066B20006E317 /* NRTool.swift in Sources */,
|
||||
85CF943B2EEFE94C006467E3 /* AppDelegate+Open.swift in Sources */,
|
||||
F34991272EE2826D0039E939 /* NRNovelReadViewModel+Data.swift in Sources */,
|
||||
F34348CD2ED6DD0900AA7E70 /* NRNovelGenresCell.swift in Sources */,
|
||||
F34348FF2ED85BF200AA7E70 /* NRReadBatteryView.swift in Sources */,
|
||||
@ -1309,6 +1333,7 @@
|
||||
039810BA2ED4377E0006E317 /* NRHomeNovelReadWhatCell.swift in Sources */,
|
||||
F3B8596B2EE91C9F0095A9CC /* NRStoreCoinsCell.swift in Sources */,
|
||||
F3B859712EE94A1B0095A9CC /* NRFeedbackViewController.swift in Sources */,
|
||||
85CF94392EEFE35A006467E3 /* NRLoginManager+Facebook.swift in Sources */,
|
||||
F34348C72ED6CCBC00AA7E70 /* NRExploreNovelContentListViewController.swift in Sources */,
|
||||
039810B82ED431780006E317 /* NRHomeNovelReadWhatView.swift in Sources */,
|
||||
F34349142EDA9AE900AA7E70 /* NRNovelReadSettingView.swift in Sources */,
|
||||
@ -1435,10 +1460,12 @@
|
||||
F3B859422EE678FB0095A9CC /* NRSettingAPI.swift in Sources */,
|
||||
0373D9522ED58A950017DCC7 /* NRSearchViewModel.swift in Sources */,
|
||||
F34990BF2EDEDDCF0039E939 /* NRCategoryModel.swift in Sources */,
|
||||
85CF942F2EEFB2CF006467E3 /* NRLoginView.swift in Sources */,
|
||||
F34349242EDD3C2400AA7E70 /* NRNovelReadBottomView.swift in Sources */,
|
||||
039810622ED04F250006E317 /* NRNetwork.swift in Sources */,
|
||||
039810782ED054740006E317 /* NRHud.swift in Sources */,
|
||||
F34991032EE160F00039E939 /* NRUserAPI.swift in Sources */,
|
||||
85CF94312EEFDA88006467E3 /* NRLoginManager+Apple.swift in Sources */,
|
||||
85606A9F2EEBE95A005D989D /* NRDashedLineView.swift in Sources */,
|
||||
039810C42ED459440006E317 /* NRHomeNovelHotTagView.swift in Sources */,
|
||||
F34991122EE170E20039E939 /* NRWebView.swift in Sources */,
|
||||
@ -1546,6 +1573,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = ReaderHive/ReaderHive.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@ -1555,6 +1583,9 @@
|
||||
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "";
|
||||
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_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
@ -1587,6 +1618,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = ReaderHive/ReaderHive.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
@ -1595,6 +1627,9 @@
|
||||
INFOPLIST_FILE = ReaderHive/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ReaderHive;
|
||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "";
|
||||
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_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
@ -1764,6 +1799,25 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/facebook/facebook-ios-sdk";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 14.1.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
85CF94362EEFE27E006467E3 /* FacebookLogin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 85CF94352EEFE27E006467E3 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */;
|
||||
productName = FacebookLogin;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 03980F5D2ED009E30006E317 /* Project object */;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
import UIKit
|
||||
import Alamofire
|
||||
import SmartCodable
|
||||
|
||||
struct NRUserAPI {
|
||||
|
||||
@ -26,4 +27,35 @@ struct NRUserAPI {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func requestSignThirdLogin(model: NRThirdSignModel, completer: ((_ token: NRLoginToken?) -> Void)?) {
|
||||
|
||||
var param = NRNetwork.Parameters(path: "/customer/login")
|
||||
param.method = .post
|
||||
param.parameters = model.toDictionary()
|
||||
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRLoginToken>) in
|
||||
if response.isSuccess {
|
||||
completer?(response.data)
|
||||
} else {
|
||||
completer?(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static func requestLogout(completer: ((_ token: NRLoginToken?) -> Void)?) {
|
||||
var param = NRNetwork.Parameters(path: "/customer/signout")
|
||||
param.method = .post
|
||||
param.isLoding = true
|
||||
|
||||
NRNetwork.request(parameters: param) { (response: NRNetwork.Response<NRLoginToken>) in
|
||||
if response.isSuccess {
|
||||
completer?(response.data)
|
||||
} else {
|
||||
completer?(nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
import UIKit
|
||||
internal import WebKit
|
||||
import ZLPhotoBrowser
|
||||
|
||||
///APP交互
|
||||
let kNRWebMessageAPP = "js2app"
|
||||
@ -23,6 +24,76 @@ let kNRWebMessageAccountDeletionFinish = "accountLogout"
|
||||
extension NRWebViewController {
|
||||
|
||||
func nr_webViewUserContentController(didReceive message: WKScriptMessage) {
|
||||
let name = message.name
|
||||
let body = message.body
|
||||
|
||||
switch name {
|
||||
case kNRWebMessageOpenFeedbackList:
|
||||
let vc = NRAppWebViewController()
|
||||
vc.webUrl = kNRFeedBackListWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kNRWebMessageOpenFeedbackDetail:
|
||||
guard let body = body as? [String : Any] else { return }
|
||||
guard let id = body["id"] as? Int else { return }
|
||||
|
||||
let vc = NRAppWebViewController()
|
||||
vc.id = "\(id)"
|
||||
vc.webUrl = kNRFeedBackDetailWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
case kNRWebMessageOpenPhotoPicker:
|
||||
openPhotoPicker()
|
||||
|
||||
// case kNRWebMessageAPP:
|
||||
// guard let body = message.body as? [String : Any] else { return }
|
||||
// guard let model = FAWebMessageModel.deserialize(from: body) else { return }
|
||||
// let type = model.type
|
||||
// let data = model.data
|
||||
//
|
||||
// if type == "login" {
|
||||
//// let view = FALoginView()
|
||||
//// view.present(in: nil)
|
||||
//
|
||||
// } else {
|
||||
//
|
||||
// guard let urlStr = data?.link else { return }
|
||||
// guard let url = URL(string: urlStr) else { return }
|
||||
// if UIApplication.shared.canOpenURL(url) {
|
||||
// UIApplication.shared.open(url)
|
||||
// }
|
||||
// }
|
||||
|
||||
case kNRWebMessageAccountDeletionFinish:
|
||||
self.navigationController?.popToRootViewController(animated: true)
|
||||
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
///打开相册
|
||||
private func openPhotoPicker() {
|
||||
|
||||
ZLPhotoConfiguration.default().allowSelectOriginal = false
|
||||
ZLPhotoConfiguration.default().maxSelectCount = 1
|
||||
ZLPhotoConfiguration.default().allowEditImage = false
|
||||
ZLPhotoConfiguration.default().allowSelectVideo = false
|
||||
ZLPhotoConfiguration.default().allowSelectGif = false
|
||||
ZLPhotoConfiguration.default().allowTakePhotoInLibrary = false
|
||||
|
||||
let picker = ZLPhotoPicker()
|
||||
picker.selectImageBlock = { [weak self] (results, _) in
|
||||
guard let self = self else { return }
|
||||
guard let image = results.first?.image else { return }
|
||||
guard let imageData = image.jpegData(compressionQuality: 0.8) else { return }
|
||||
let imageDataStr = imageData.base64EncodedString(options: .endLineWithCarriageReturn)
|
||||
|
||||
let js = "uploadConvertImage('\(imageDataStr)')"
|
||||
self.webView.evaluateJavaScript(js)
|
||||
}
|
||||
|
||||
picker.showPhotoLibrary(sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,6 +115,7 @@ extension NRHomeNovelNewArrivalsCell {
|
||||
|
||||
categoryView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(4)
|
||||
make.height.equalTo(20)
|
||||
}
|
||||
|
||||
110
ReaderHive/Class/Me/V/NRLoginView.swift
Normal file
@ -0,0 +1,110 @@
|
||||
//
|
||||
// NRLoginView.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import HWPanModal
|
||||
import SnapKit
|
||||
|
||||
class NRLoginView: NRPanModalContentView {
|
||||
|
||||
|
||||
private lazy var bgView = UIImageView(image: UIImage(named: "bg_image_01"))
|
||||
|
||||
private lazy var titleView = UIImageView(image: UIImage(named: "login_logo_icon"))
|
||||
|
||||
private lazy var appleLoginButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.background.backgroundColor = .F_2_EFEE
|
||||
configuration.background.cornerRadius = 24
|
||||
configuration.image = UIImage(named: "apple_login_logo_icon")
|
||||
configuration.imagePadding = 8
|
||||
configuration.attributedTitle = AttributedString("Login with Apple".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .medium),
|
||||
.foregroundColor : UIColor.black
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.login(type: .apple)
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var facebookLoginButton: UIButton = {
|
||||
var configuration = UIButton.Configuration.plain()
|
||||
configuration.background.backgroundColor = .F_2_EFEE
|
||||
configuration.background.cornerRadius = 24
|
||||
configuration.image = UIImage(named: "facebook_login_logo_icon")
|
||||
configuration.imagePadding = 8
|
||||
configuration.attributedTitle = AttributedString("Login with Facebook".localized, attributes: AttributeContainer([
|
||||
.font : UIFont.font(ofSize: 14, weight: .medium),
|
||||
.foregroundColor : UIColor.black
|
||||
]))
|
||||
|
||||
let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.login(type: .faceBook)
|
||||
}))
|
||||
return button
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
contentHeight = 220 + UIScreen.safeBottom
|
||||
nr_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func login(type: NRLoginManager.LoginType) {
|
||||
NRHud.show()
|
||||
NRLoginManager.manager.thirdLogin(type: type, presentingViewController: nil) { [weak self] isFinish in
|
||||
NRHud.dismiss()
|
||||
guard let self = self else { return }
|
||||
guard isFinish else { return }
|
||||
self.dismiss(animated: true) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NRLoginView {
|
||||
|
||||
private func nr_setupUI() {
|
||||
addSubview(bgView)
|
||||
addSubview(titleView)
|
||||
addSubview(appleLoginButton)
|
||||
addSubview(facebookLoginButton)
|
||||
|
||||
bgView.snp.makeConstraints { make in
|
||||
make.left.right.top.equalToSuperview()
|
||||
}
|
||||
|
||||
titleView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(24)
|
||||
}
|
||||
|
||||
appleLoginButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(44)
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(84)
|
||||
make.height.equalTo(48)
|
||||
}
|
||||
|
||||
facebookLoginButton.snp.makeConstraints { make in
|
||||
make.left.right.height.equalTo(appleLoginButton)
|
||||
make.top.equalTo(appleLoginButton.snp.bottom).offset(16)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
import UIKit
|
||||
import SnapKit
|
||||
import YYCategories
|
||||
import HWPanModal
|
||||
|
||||
class NRMeHeaderView: UITableViewHeaderFooterView {
|
||||
|
||||
@ -21,6 +22,7 @@ class NRMeHeaderView: UITableViewHeaderFooterView {
|
||||
|
||||
coinsView.userInfo = userInfo
|
||||
|
||||
loginButton.isHidden = !(userInfo?.is_tourist ?? false)
|
||||
|
||||
stackView.nr_removeAllArrangedSubview()
|
||||
stackView.addArrangedSubview(coinsView)
|
||||
@ -72,6 +74,16 @@ class NRMeHeaderView: UITableViewHeaderFooterView {
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var loginButton: UIButton = {
|
||||
let button = UIButton(type: .custom, primaryAction: UIAction(handler: { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
let view = NRLoginView()
|
||||
view.present(in: nil)
|
||||
}))
|
||||
button.setImage(UIImage(named: "login_button"), for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
@ -121,6 +133,7 @@ extension NRMeHeaderView {
|
||||
contentView.addSubview(idBgView)
|
||||
idBgView.addSubview(idLabel)
|
||||
idBgView.addSubview(copyButton)
|
||||
contentView.addSubview(loginButton)
|
||||
contentView.addSubview(stackView)
|
||||
|
||||
avatarImageView.snp.makeConstraints { make in
|
||||
@ -152,6 +165,11 @@ extension NRMeHeaderView {
|
||||
make.left.equalTo(idLabel.snp.right).offset(8)
|
||||
}
|
||||
|
||||
loginButton.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(avatarImageView)
|
||||
make.right.equalToSuperview().offset(-16)
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalTo(avatarImageView.snp.bottom).offset(16)
|
||||
|
||||
@ -13,18 +13,14 @@ class NRFeedbackViewController: NRAppWebViewController {
|
||||
self.webUrl = kNRFeedBackHomeWebUrl
|
||||
super.viewDidLoad()
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "feedback_list_icon_01"), style: .plain, target: self, action: #selector(openFeedbackList))
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// MARK: - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
// Get the new view controller using segue.destination.
|
||||
// Pass the selected object to the new view controller.
|
||||
@objc private func openFeedbackList() {
|
||||
let vc = NRAppWebViewController()
|
||||
vc.webUrl = kNRFeedBackListWebUrl
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import UIKit
|
||||
import IQKeyboardManagerSwift
|
||||
import IQKeyboardToolbarManager
|
||||
import MJRefresh
|
||||
import FacebookCore
|
||||
|
||||
|
||||
extension AppDelegate {
|
||||
@ -30,4 +31,9 @@ extension AppDelegate {
|
||||
UIDevice.current.isBatteryMonitoringEnabled = true
|
||||
}
|
||||
|
||||
|
||||
func nr_registThirdparty(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
|
||||
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
33
ReaderHive/Delegate/AppDelegate+Open.swift
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// AppDelegate+Open.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FacebookCore
|
||||
|
||||
extension SceneDelegate {
|
||||
|
||||
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
|
||||
guard let url = URLContexts.first?.url else {
|
||||
return
|
||||
}
|
||||
var result = false
|
||||
|
||||
result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
|
||||
|
||||
|
||||
}
|
||||
|
||||
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
||||
guard let webpageURL = userActivity.webpageURL else { return }
|
||||
var result = false
|
||||
|
||||
result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity)
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,15 +6,16 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FacebookCore
|
||||
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
NRTool.appDelegate = self
|
||||
NRNetworkReachableManager.manager.startMonitoring()
|
||||
nr_registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(networkStatusDidChangeNotification), name: NRNetworkReachableManager.networkStatusDidChangeNotification, object: nil)
|
||||
|
||||
|
||||
107
ReaderHive/Libs/Login/NRLoginManager+Apple.swift
Normal file
@ -0,0 +1,107 @@
|
||||
//
|
||||
// NRLoginManager+Apple.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AuthenticationServices
|
||||
|
||||
extension NRLoginManager {
|
||||
|
||||
private struct AssociatedKeys {
|
||||
static var appleLoginHandle: Int?
|
||||
}
|
||||
|
||||
private var appleLoginHandle: ((_ model: NRThirdSignModel?) -> Void)? {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.appleLoginHandle, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &AssociatedKeys.appleLoginHandle) as? ((_ model: NRThirdSignModel?) -> Void)
|
||||
}
|
||||
}
|
||||
|
||||
func nr_appleLogin(completer: ((_ model: NRThirdSignModel?) -> Void)?) {
|
||||
self.appleLoginHandle = completer
|
||||
|
||||
let appleIDProvider = ASAuthorizationAppleIDProvider()
|
||||
let request = appleIDProvider.createRequest()
|
||||
request.requestedScopes = [.fullName, .email]
|
||||
|
||||
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
|
||||
authorizationController.delegate = self
|
||||
authorizationController.presentationContextProvider = self
|
||||
authorizationController.performRequests()
|
||||
}
|
||||
|
||||
private func jwtDecode(jwtStr: String) -> [String: Any]? {
|
||||
let segments = jwtStr.components(separatedBy: ".")
|
||||
guard segments.count > 1 else { return nil }
|
||||
|
||||
var base64String = segments[1]
|
||||
|
||||
// 处理 Base64 补齐
|
||||
let requiredLength = 4 * Int(ceil(Double(base64String.count) / 4.0))
|
||||
let paddingLength = requiredLength - base64String.count
|
||||
if paddingLength > 0 {
|
||||
base64String += String(repeating: "=", count: paddingLength)
|
||||
}
|
||||
|
||||
// 替换 URL 安全字符
|
||||
base64String = base64String.replacingOccurrences(of: "-", with: "+")
|
||||
base64String = base64String.replacingOccurrences(of: "_", with: "/")
|
||||
|
||||
// 解码 Base64 数据
|
||||
guard let data = Data(base64Encoded: base64String),
|
||||
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: []),
|
||||
let payload = jsonObject as? [String: Any] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: ASAuthorizationControllerDelegate
|
||||
extension NRLoginManager: ASAuthorizationControllerDelegate {
|
||||
|
||||
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
||||
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
||||
|
||||
let userIdentifier = appleIDCredential.user
|
||||
let fullName = appleIDCredential.fullName
|
||||
|
||||
let identityToken = appleIDCredential.identityToken.flatMap { String(data: $0, encoding: .utf8) }
|
||||
let identityTokenParams = self.jwtDecode(jwtStr: identityToken ?? "")
|
||||
|
||||
var model = NRThirdSignModel()
|
||||
model.platform = .apple
|
||||
model.third_id = userIdentifier
|
||||
model.giving_name = fullName?.givenName
|
||||
model.family_name = fullName?.familyName
|
||||
model.avator = identityTokenParams?["picture"] as? String
|
||||
model.email = identityTokenParams?["email"] as? String
|
||||
|
||||
appleLoginHandle?(model)
|
||||
appleLoginHandle = nil
|
||||
}
|
||||
}
|
||||
|
||||
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
||||
appleLoginHandle?(nil)
|
||||
appleLoginHandle = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: ASAuthorizationControllerPresentationContextProviding
|
||||
extension NRLoginManager: ASAuthorizationControllerPresentationContextProviding {
|
||||
|
||||
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
||||
return NRTool.keyWindow!
|
||||
}
|
||||
|
||||
}
|
||||
59
ReaderHive/Libs/Login/NRLoginManager+Facebook.swift
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// NRLoginManager+Facebook.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import FacebookLogin
|
||||
|
||||
extension NRLoginManager {
|
||||
|
||||
func nr_facebookLogin(presentingViewController: UIViewController?, completer: ((_ model: NRThirdSignModel?) -> Void)?) {
|
||||
|
||||
let loginManager = LoginManager()
|
||||
loginManager.logOut()
|
||||
loginManager.defaultAudience = .everyone
|
||||
|
||||
loginManager.logIn(permissions: ["public_profile", "email"], from: presentingViewController) { result, error in
|
||||
guard error == nil, let result = result else {
|
||||
completer?(nil)
|
||||
return
|
||||
}
|
||||
if result.isCancelled {
|
||||
completer?(nil)
|
||||
return
|
||||
}
|
||||
let request = GraphRequest(graphPath: "me", parameters: ["fields" : "id,name,email,picture"], httpMethod: .get)
|
||||
request.start { connection, result, error in
|
||||
guard let result = result as? [String : Any] else {
|
||||
completer?(nil)
|
||||
return
|
||||
}
|
||||
var model = NRThirdSignModel()
|
||||
model.platform = .faceBook
|
||||
model.third_id = result["id"] as? String
|
||||
model.email = result["email"] as? String
|
||||
|
||||
if let picture = result["picture"] as? [String : Any],
|
||||
let data = picture["data"] as? [String : Any],
|
||||
let url = data["url"] as? String
|
||||
{
|
||||
model.avator = url
|
||||
}
|
||||
|
||||
if let name = result["name"] as? String {
|
||||
model.family_name = name
|
||||
} else {
|
||||
model.family_name = result["first_name"] as? String
|
||||
model.giving_name = result["last_name"] as? String
|
||||
}
|
||||
completer?(model)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,9 +6,17 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class NRLoginManager: NSObject {
|
||||
|
||||
enum LoginType: String, SmartCaseDefaultable {
|
||||
case apple = "Apple"
|
||||
case faceBook = "Facebook"
|
||||
case google = "Google"
|
||||
case tiktok = "Tiktok"
|
||||
}
|
||||
|
||||
static let manager = NRLoginManager()
|
||||
|
||||
private(set) var token = UserDefaults.nr_object(forKey: kNRLoginTokenDefaultsKey, as: NRLoginToken.self)
|
||||
@ -30,6 +38,72 @@ class NRLoginManager: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
///第三方登录
|
||||
func thirdLogin(type: LoginType, presentingViewController: UIViewController?, completer: ((_ isFinish: Bool) -> Void)?) {
|
||||
switch type {
|
||||
case .apple:
|
||||
nr_appleLogin { [weak self] model in
|
||||
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
|
||||
}
|
||||
|
||||
case .faceBook:
|
||||
nr_facebookLogin(presentingViewController: presentingViewController) { [weak self] model in
|
||||
self?.requestSignThirdLogin(thirdSignModel: model, completer: completer)
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
///后台验证三方登录
|
||||
private func requestSignThirdLogin(thirdSignModel: NRThirdSignModel?, completer: ((_ isFinish: Bool) -> Void)?) {
|
||||
guard let thirdSignModel = thirdSignModel else {
|
||||
completer?(false)
|
||||
return
|
||||
}
|
||||
// FAStatAPI.requestLeaveApp()
|
||||
NRUserAPI.requestSignThirdLogin(model: thirdSignModel) { [weak self] token in
|
||||
guard let self = self else { return }
|
||||
guard let token = token else {
|
||||
completer?(false)
|
||||
return
|
||||
}
|
||||
self.setAccountToken(token)
|
||||
self.userInfo?.is_tourist = false
|
||||
Task {
|
||||
await self.updateUserInfo()
|
||||
}
|
||||
// FAStatAPI.requestEnterApp()
|
||||
// FAStatAPI.requestStatOnLine()
|
||||
completer?(true)
|
||||
NotificationCenter.default.post(name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
func logout(completer: ((_ isFinish: Bool) -> Void)?) {
|
||||
// FAStatAPI.requestLeaveApp()
|
||||
|
||||
NRUserAPI.requestLogout { [weak self] token in
|
||||
guard let self = self else { return }
|
||||
if let token = token {
|
||||
self.setAccountToken(token)
|
||||
self.userInfo?.is_tourist = true
|
||||
Task {
|
||||
await self.updateUserInfo()
|
||||
}
|
||||
// FAStatAPI.requestEnterApp()
|
||||
// FAStatAPI.requestStatOnLine()
|
||||
completer?(true)
|
||||
NotificationCenter.default.post(name: NRLoginManager.userInfoUpdateNotification, object: nil)
|
||||
NotificationCenter.default.post(name: NRLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
} else {
|
||||
completer?(false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
24
ReaderHive/Libs/Login/NRThirdSignModel.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// NRThirdSignModel.swift
|
||||
// ReaderHive
|
||||
//
|
||||
// Created by 澜声世纪 on 2025/12/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
struct NRThirdSignModel: SmartCodable {
|
||||
|
||||
var third_id: String?
|
||||
var email: String?
|
||||
//姓
|
||||
var family_name: String?
|
||||
//名
|
||||
var giving_name: String?
|
||||
|
||||
var avator: String?
|
||||
|
||||
var platform: NRLoginManager.LoginType?
|
||||
|
||||
}
|
||||
12
ReaderHive/ReaderHive.entitlements
Normal file
@ -0,0 +1,12 @@
|
||||
<?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.developer.applesignin</key>
|
||||
<array>
|
||||
<string>Default</string>
|
||||
</array>
|
||||
<key>keychain-access-groups</key>
|
||||
<array/>
|
||||
</dict>
|
||||
</plist>
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Apple@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Apple@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 674 B |
22
ReaderHive/Source/Assets.xcassets/Image/apple_login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Apple@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Apple@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Facebook@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Facebook@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Facebook@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 804 B |
BIN
ReaderHive/Source/Assets.xcassets/Image/facebook_login_logo_icon.imageset/Facebook@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
20
ReaderHive/Source/Assets.xcassets/Image/feedback_list_icon_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
22
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "登录@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "登录@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/登录@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/login_button.imageset/登录@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
22
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "文字LOGO(ReaderHive)@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "文字LOGO(ReaderHive)@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/文字LOGO(ReaderHive)@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
ReaderHive/Source/Assets.xcassets/Image/login_logo_icon.imageset/文字LOGO(ReaderHive)@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
@ -2,6 +2,31 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>fb1155849519865831</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>readerhiveapp</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>FacebookAppID</key>
|
||||
<string>1155849519865831</string>
|
||||
<key>FacebookClientToken</key>
|
||||
<string>696d03750f4bc7a888c815b071be555d</string>
|
||||
<key>FacebookDisplayName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
|
||||
@ -129,6 +129,8 @@
|
||||
"Balance" = "Balance";
|
||||
"Daily Coins" = "Daily Coins";
|
||||
"Buy Now" = "Buy Now";
|
||||
"Login with Apple" = "Login with Apple";
|
||||
"Login with Facebook" = "Login with Facebook";
|
||||
|
||||
"retain_alert_text" = "Unlock every show you love!";
|
||||
|
||||
|
||||