Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,53 @@
import Foundation
var isiPad: Bool {
if ProcessInfo.processInfo.isiOSAppOnMac {
return true
}
return UIDevice.current.userInterfaceIdiom == .pad
}
func L(_ key: String) -> String { return NSLocalizedString(key, comment: "") }
func L(_ key: String, languageCode: String) -> String {
guard let path = Bundle.main.path(forResource: languageCode, ofType: "lproj"),
let bundle = Bundle(path: path) else {
LOG(.warning, "Localization bundle not found for language code: \(languageCode)")
return L(key)
}
return NSLocalizedString(key, bundle: bundle, comment: "")
}
func alternative<T>(iPhone: T, iPad: T) -> T { isiPad ? iPad : iPhone }
func iPadSpecific(_ f: () -> Void) {
if isiPad {
f()
}
}
func iPhoneSpecific(_ f: () -> Void) {
if !isiPad {
f()
}
}
func toString(_ cls: AnyClass) -> String {
return String(describing: cls)
}
func LOG(_ level: LogLevel,
_ message: @autoclosure () -> Any,
functionName: StaticString = #function,
fileName: StaticString = #file,
lineNumber: UInt = #line) {
if (Logger.canLog(level)) {
let shortFileName = URL(string: "\(fileName)")?.lastPathComponent ?? ""
let formattedMessage = "\(shortFileName):\(lineNumber) \(functionName): \(message())"
Logger.log(level, message: formattedMessage)
}
}
struct Weak<T> where T: AnyObject {
weak var value: T?
}

View file

@ -0,0 +1,18 @@
#import "MWMKeyboardObserver.h"
@interface MWMKeyboard : NSObject
+ (void)applicationDidBecomeActive;
+ (void)addObserver:(id<MWMKeyboardObserver>)observer;
+ (void)removeObserver:(id<MWMKeyboardObserver>)observer;
+ (CGFloat)keyboardHeight;
- (instancetype)init __attribute__((unavailable("call +manager instead")));
- (instancetype)copy __attribute__((unavailable("call +manager instead")));
- (instancetype)copyWithZone:(NSZone *)zone __attribute__((unavailable("call +manager instead")));
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable("call +manager instead")));
+ (instancetype)new __attribute__((unavailable("call +manager instead")));
@end

View file

@ -0,0 +1,98 @@
#import "MWMKeyboard.h"
@interface MWMKeyboard ()
@property(nonatomic) NSHashTable *observers;
@property(nonatomic) CGFloat keyboardHeight;
@end
@implementation MWMKeyboard
+ (void)applicationDidBecomeActive {
[self manager];
}
+ (MWMKeyboard *)manager {
static MWMKeyboard *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] initManager];
});
return manager;
}
- (instancetype)initManager {
self = [super init];
if (self) {
_observers = [NSHashTable weakObjectsHashTable];
NSNotificationCenter *nc = NSNotificationCenter.defaultCenter;
[nc addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
- (void)dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
}
+ (CGFloat)keyboardHeight {
return [self manager].keyboardHeight;
}
#pragma mark - Add/Remove Observers
+ (void)addObserver:(id<MWMKeyboardObserver>)observer {
[[self manager].observers addObject:observer];
}
+ (void)removeObserver:(id<MWMKeyboardObserver>)observer {
[[self manager].observers removeObject:observer];
}
#pragma mark - Notifications
- (void)onKeyboardWillAnimate {
for (id<MWMKeyboardObserver> observer in self.observers) {
if ([observer respondsToSelector:@selector(onKeyboardWillAnimate)])
[observer onKeyboardWillAnimate];
}
}
- (void)onKeyboardAnimation {
for (id<MWMKeyboardObserver> observer in self.observers) {
[observer onKeyboardAnimation];
}
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self onKeyboardWillAnimate];
CGSize keyboardSize = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.keyboardHeight = MIN(keyboardSize.height, keyboardSize.width);
NSNumber *duration = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = notification.userInfo[UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:duration.doubleValue
delay:0
options:curve.integerValue
animations:^{
[self onKeyboardAnimation];
}
completion:nil];
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self onKeyboardWillAnimate];
self.keyboardHeight = 0;
NSNumber *duration = notification.userInfo[UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = notification.userInfo[UIKeyboardAnimationCurveUserInfoKey];
[UIView animateWithDuration:duration.doubleValue
delay:0
options:curve.integerValue
animations:^{
[self onKeyboardAnimation];
}
completion:nil];
}
@end

View file

@ -0,0 +1,8 @@
@protocol MWMKeyboardObserver<NSObject>
- (void)onKeyboardAnimation;
@optional
- (void)onKeyboardWillAnimate;
@end

View file

@ -0,0 +1,10 @@
static NSString * const kMapsmeErrorDomain = @"com.mapsme.error";
static NSTimeInterval const kDefaultAnimationDuration = .3;
static uint64_t const KB = 1024;
static uint64_t const MB = 1024 * 1024;
// The last 5% are left for applying diffs.
static float const kMaxProgress = 0.95f;
static NSString * const kLocaleUsedInSupportEmails = @"en_gb";
static NSString * const kTapEventKey = @"$onClick";

View file

@ -0,0 +1,3 @@
#define IPAD (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad)
#define L(str) NSLocalizedString(str, nil)

View file

@ -0,0 +1,34 @@
#import <WebKit/WebKit.h>
#import "MWMViewController.h"
#import <CoreApi/MWMTypes.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^WebViewControllerWillLoadBlock)(BOOL, NSDictionary<NSString *, NSString *> * _Nullable);
@interface WebViewController : MWMViewController <WKNavigationDelegate>
@property (nonatomic) NSURL * _Nullable m_url;
@property (copy, nonatomic) NSString * _Nullable m_htmlText;
// Set to YES if external browser should be launched
@property (nonatomic) BOOL openInSafari;
@property (nonatomic, readonly) WKWebView * webView;
- (instancetype _Nullable)initWithUrl:(NSURL *)url title:( NSString * _Nullable)title;
- (instancetype _Nullable)initWithHtml:(NSString *)htmlText
baseUrl:(NSURL * _Nullable)url
title:(NSString * _Nullable)title;
- (instancetype _Nullable)initWithAuthURL:(NSURL *)url
onSuccessAuth:(MWMStringBlock _Nullable)success
onFailure:(MWMVoidBlock _Nullable)failure;
- (void)willLoadUrl:(WebViewControllerWillLoadBlock)decisionHandler;
- (BOOL)shouldAddAccessToken;
- (void)forward;
- (void)back;
- (void)reloadFromOrigin;
- (NSString *)configuredHtmlWithText:(NSString *)htmlText;
- (void)performURLRequest;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,200 @@
#import "WebViewController.h"
#import <CoreApi/MWMFrameworkHelper.h>
#import "SwiftBridge.h"
@interface WebViewController ()
@property(copy, nonatomic) MWMVoidBlock onFailure;
@property(copy, nonatomic) MWMStringBlock onSuccess;
@property(nonatomic) BOOL authorized;
@property(nonatomic) WKWebView *webView;
@property(nonatomic) BOOL shouldResendHeaders;
@end
@implementation WebViewController
- (id)initWithUrl:(NSURL *)url title:(NSString *)title {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_m_url = url;
if (title)
self.navigationItem.title = title;
}
return self;
}
- (id)initWithHtml:(NSString *)htmlText baseUrl:(NSURL *)url title:(NSString *)title {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_m_htmlText = htmlText;
_m_url = url;
if (title)
self.navigationItem.title = title;
}
return self;
}
- (NSString *)configuredHtmlWithText:(NSString *)htmlText {
NSString *html = [htmlText stringByReplacingOccurrencesOfString:@"<body>"
withString:@"<body><font face=\"helvetica\" size=\"14pt\">"];
html = [html stringByReplacingOccurrencesOfString:@"</body>" withString:@"</font></body>"];
return html;
}
- (instancetype)initWithAuthURL:(NSURL *)url onSuccessAuth:(MWMStringBlock)success onFailure:(MWMVoidBlock)failure {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_m_url = url;
_onFailure = failure;
_onSuccess = success;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIView *view = self.view;
view.styleName = @"Background";
self.webView = [[WKWebView alloc] initWithFrame:CGRectZero];
self.webView.backgroundColor = UIColor.clearColor;
self.webView.opaque = NO;
self.webView.navigationDelegate = self;
[view addSubview:self.webView];
self.webView.translatesAutoresizingMaskIntoConstraints = NO;
self.webView.autoresizesSubviews = YES;
NSLayoutYAxisAnchor *topAnchor = view.topAnchor;
NSLayoutYAxisAnchor *bottomAnchor = view.bottomAnchor;
NSLayoutXAxisAnchor *leadingAnchor = view.leadingAnchor;
NSLayoutXAxisAnchor *trailingAnchor = view.trailingAnchor;
UILayoutGuide *safeAreaLayoutGuide = view.safeAreaLayoutGuide;
topAnchor = safeAreaLayoutGuide.topAnchor;
bottomAnchor = safeAreaLayoutGuide.bottomAnchor;
leadingAnchor = safeAreaLayoutGuide.leadingAnchor;
trailingAnchor = safeAreaLayoutGuide.trailingAnchor;
[self.webView.topAnchor constraintEqualToAnchor:topAnchor].active = YES;
[self.webView.bottomAnchor constraintEqualToAnchor:bottomAnchor].active = YES;
[self.webView.leadingAnchor constraintEqualToAnchor:leadingAnchor].active = YES;
[self.webView.trailingAnchor constraintEqualToAnchor:trailingAnchor].active = YES;
self.webView.allowsLinkPreview = NO;
[self performURLRequest];
}
- (void)performURLRequest {
__weak __typeof(self) ws = self;
[self willLoadUrl:^(BOOL load, NSDictionary<NSString *, NSString *> *headers) {
__typeof(self) self = ws;
if (load) {
if (self.m_htmlText) {
[self.webView loadHTMLString:[self configuredHtmlWithText:self.m_htmlText] baseURL:self.m_url];
} else {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.m_url];
for (NSString *header in headers.allKeys) {
[request setValue:headers[header] forHTTPHeaderField:header];
}
// if (self.shouldAddAccessToken) {
// NSString *authHeader = [NSString stringWithFormat:@"Bearer %@", [MWMFrameworkHelper userAccessToken]];
// [request setValue:authHeader forHTTPHeaderField:@"Authorization"];
// }
if ([UIColor isNightMode]) {
[request setValue:@"dark" forHTTPHeaderField:@"x-mapsme-theme"];
}
[self.webView loadRequest:request];
}
}
}];
}
- (void)willLoadUrl:(WebViewControllerWillLoadBlock)decisionHandler {
decisionHandler(YES, nil);
}
- (BOOL)shouldAddAccessToken {
return NO;
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
if (self.isMovingFromParentViewController && !self.authorized && self.onFailure)
self.onFailure();
}
- (void)pop {
[self.navigationController popViewControllerAnimated:YES];
}
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
// about:blank#localAnchor, e.g. in copyright.html.
if ([url.scheme isEqualToString:@"about"]) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
if ([url.host isEqualToString:@"localhost"]) {
NSString *query = url.query;
NSArray<NSString *> *components = [query componentsSeparatedByString:@"="];
if (components.count != 2) {
NSAssert(false, @"Incorrect query:", query);
[self pop];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
self.authorized = YES;
[self pop];
self.onSuccess(components[1]);
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
if (self.openInSafari && navigationAction.navigationType == WKNavigationTypeLinkActivated &&
![url.scheme isEqualToString:@"applewebdata"]) // do not try to open local links in Safari
{
[UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
if (!self.shouldResendHeaders) {
decisionHandler(WKNavigationActionPolicyAllow);
} else {
_m_url = url;
self.shouldResendHeaders = NO;
decisionHandler(WKNavigationActionPolicyCancel);
[self performURLRequest];
}
}
- (void)forward {
[self.webView goForward];
}
- (void)back {
[self.webView goBack];
}
- (void)reloadFromOrigin {
self.shouldResendHeaders = YES;
[self.webView reloadFromOrigin];
}
#if DEBUG
- (void)webView:(WKWebView *)webView
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
NSURLCredential *_Nullable credential))completionHandler {
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:[challenge protectionSpace].serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}
#endif
@end