mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Rageshake Service (#70)
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// UIImage+.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Ismail on 20.05.2022.
|
||||
// Copyright © 2022 element.io. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Vision
|
||||
import UIKit
|
||||
|
||||
enum ImageAnonymizerError: Error {
|
||||
case noCgImageBased
|
||||
}
|
||||
|
||||
struct ImageAnonymizer {
|
||||
|
||||
private static var allowedTextItems: [String] = [
|
||||
"#",
|
||||
"@",
|
||||
"%",
|
||||
"&",
|
||||
"+",
|
||||
"-",
|
||||
"_",
|
||||
"\"",
|
||||
"?",
|
||||
"*"
|
||||
]
|
||||
|
||||
static func anonymizedImage(from image: UIImage,
|
||||
confidenceLevel: Float = 0.5,
|
||||
fillColor: UIColor = .red) async throws -> UIImage {
|
||||
guard let cgImage = image.cgImage else {
|
||||
throw ImageAnonymizerError.noCgImageBased
|
||||
}
|
||||
|
||||
// create a handler with cgImage
|
||||
let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
|
||||
var observations: [VNDetectedObjectObservation] = []
|
||||
|
||||
// create a text request
|
||||
let textRequest = VNRecognizeTextRequest { request, error in
|
||||
guard let results = request.results as? [VNRecognizedTextObservation],
|
||||
error == nil else {
|
||||
return
|
||||
}
|
||||
observations.append(contentsOf: results)
|
||||
}
|
||||
textRequest.recognitionLevel = .accurate
|
||||
textRequest.revision = VNRecognizeTextRequestRevision2
|
||||
|
||||
// create a face request
|
||||
let faceRequest = VNDetectFaceRectanglesRequest { request, error in
|
||||
guard let results = request.results as? [VNFaceObservation],
|
||||
error == nil else {
|
||||
return
|
||||
}
|
||||
observations.append(contentsOf: results)
|
||||
}
|
||||
// revision3 doesn't work!
|
||||
faceRequest.revision = VNDetectFaceRectanglesRequestRevision2
|
||||
|
||||
// perform requests
|
||||
try handler.perform([
|
||||
textRequest,
|
||||
faceRequest
|
||||
])
|
||||
|
||||
return render(image: image,
|
||||
confidenceLevel: confidenceLevel,
|
||||
fillColor: fillColor,
|
||||
observations: observations)
|
||||
}
|
||||
|
||||
private static func render(image: UIImage,
|
||||
confidenceLevel: Float,
|
||||
fillColor: UIColor,
|
||||
observations: [VNDetectedObjectObservation]) -> UIImage {
|
||||
let size = image.size
|
||||
let result = UIGraphicsImageRenderer(size: size).image { rendererContext in
|
||||
// first draw self
|
||||
image.draw(in: CGRect(origin: .zero, size: size))
|
||||
// set fill color
|
||||
fillColor.setFill()
|
||||
for observation in observations {
|
||||
guard observation.confidence >= confidenceLevel else {
|
||||
// ensure observation's confidence level
|
||||
continue
|
||||
}
|
||||
if let textObservation = observation as? VNRecognizedTextObservation,
|
||||
let text = textObservation.topCandidates(1).first?.string {
|
||||
if Double(text) != nil || Self.allowedTextItems.contains(text) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
let box = observation.boundingBox
|
||||
// boc is normalized (and in starts from the lower left corner)
|
||||
// convert it to a rect in the image
|
||||
let rect = CGRect(x: box.minX * size.width,
|
||||
y: size.height - box.maxY * size.height,
|
||||
width: box.width * size.width,
|
||||
height: box.height * size.height)
|
||||
rendererContext.fill(rect)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -136,14 +136,14 @@ private var logger: SwiftyBeaver.Type = {
|
||||
// MARK: - Private
|
||||
|
||||
fileprivate static func configureLogger(_ logger: SwiftyBeaver.Type, withConfiguration configuration: MXLogConfiguration) {
|
||||
// if let subLogName = configuration.subLogName {
|
||||
// MXLogger.setSubLogName(subLogName)
|
||||
// }
|
||||
//
|
||||
// MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles,
|
||||
// numberOfFiles: configuration.maxLogFilesCount,
|
||||
// sizeLimit: configuration.logFilesSizeLimit)
|
||||
//
|
||||
if let subLogName = configuration.subLogName {
|
||||
MXLogger.setSubLogName(subLogName)
|
||||
}
|
||||
|
||||
MXLogger.redirectNSLog(toFiles: configuration.redirectLogsToFiles,
|
||||
numberOfFiles: configuration.maxLogFilesCount,
|
||||
sizeLimit: configuration.logFilesSizeLimit)
|
||||
|
||||
guard configuration.logLevel != .none else {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
The `MXLogger` tool redirects NSLog output into a fixed pool of files.
|
||||
Another log file is used every time [MXLogger redirectNSLogToFiles:YES]
|
||||
is called. The pool contains 3 files.
|
||||
|
||||
`MXLogger` can track and log uncatched exceptions or crashes.
|
||||
*/
|
||||
@interface MXLogger : NSObject
|
||||
|
||||
/**
|
||||
Redirect NSLog output to MXLogger files.
|
||||
|
||||
It is advised to condition this redirection in '#if (!isatty(STDERR_FILENO))' block to enable
|
||||
it only when the device is not attached to the debugger.
|
||||
|
||||
@param redirectNSLogToFiles YES to enable the redirection.
|
||||
*/
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles;
|
||||
|
||||
/**
|
||||
Redirect NSLog output to MXLogger files.
|
||||
|
||||
It is advised to condition this redirection in '#if (!isatty(STDERR_FILENO))' block to enable
|
||||
it only when the device is not attached to the debugger.
|
||||
|
||||
@param redirectNSLogToFiles YES to enable the redirection.
|
||||
@param numberOfFiles number of files to keep (default is 10).
|
||||
*/
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles;
|
||||
|
||||
/**
|
||||
Redirect NSLog output to MXLogger files.
|
||||
|
||||
@param redirectNSLogToFiles YES to enable the redirection.
|
||||
@param numberOfFiles number of files to keep (default is 10).
|
||||
@param sizeLimit size limit of log files in bytes. 0 means no limitation, the default value for other methods
|
||||
*/
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles sizeLimit:(NSUInteger)sizeLimit;
|
||||
|
||||
/**
|
||||
Delete all log files.
|
||||
*/
|
||||
+ (void)deleteLogFiles;
|
||||
|
||||
/**
|
||||
Get the list of all log files.
|
||||
|
||||
@return files of
|
||||
*/
|
||||
+ (NSArray<NSString*>*)logFiles;
|
||||
|
||||
/**
|
||||
Make `MXLogger` catch and log unmanaged exceptions or application crashes.
|
||||
|
||||
When such error happens, `MXLogger` stores the application stack trace into a file
|
||||
just before the application leaves. The path of this file is provided by [MXLogger crashLog].
|
||||
|
||||
@param logCrashes YES to enable the catch.
|
||||
*/
|
||||
+ (void)logCrashes:(BOOL)logCrashes;
|
||||
|
||||
/**
|
||||
Set the app build version.
|
||||
It will be reported in crash report.
|
||||
*/
|
||||
+ (void)setBuildVersion:(NSString*)buildVersion;
|
||||
|
||||
/**
|
||||
Set a sub name for namespacing log files.
|
||||
|
||||
A sub name must be set when running from an app extension because extensions can
|
||||
run in parallel to the app.
|
||||
It must be called before `redirectNSLogToFiles`.
|
||||
|
||||
@param subLogName the subname for log files. Files will be named as 'console-[subLogName].log'
|
||||
Default is nil.
|
||||
*/
|
||||
+ (void)setSubLogName:(NSString*)subLogName;
|
||||
|
||||
/**
|
||||
If any, get the file containing the last application crash log.
|
||||
|
||||
Only one crash log is stored at a time. The best moment for the app to handle it is the
|
||||
at its next startup.
|
||||
|
||||
@return the crash log file. nil if there is none.
|
||||
*/
|
||||
+ (NSString*)crashLog;
|
||||
|
||||
/**
|
||||
Delete the crash log file.
|
||||
*/
|
||||
+ (void)deleteCrashLog;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
Copyright 2015 OpenMarket Ltd
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "MXLogger.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
// stderr so it can be restored
|
||||
int stderrSave = 0;
|
||||
|
||||
static NSString *buildVersion;
|
||||
static NSString *subLogName;
|
||||
|
||||
#define MXLOGGER_CRASH_LOG @"crash.log"
|
||||
|
||||
@implementation MXLogger
|
||||
|
||||
#pragma mark - NSLog redirection
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles
|
||||
{
|
||||
[self redirectNSLogToFiles:redirectNSLogToFiles numberOfFiles:10];
|
||||
}
|
||||
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles
|
||||
{
|
||||
[self redirectNSLogToFiles:redirectNSLogToFiles numberOfFiles:numberOfFiles sizeLimit:0];
|
||||
}
|
||||
|
||||
+ (void)redirectNSLogToFiles:(BOOL)redirectNSLogToFiles numberOfFiles:(NSUInteger)numberOfFiles sizeLimit:(NSUInteger)sizeLimit
|
||||
{
|
||||
if (redirectNSLogToFiles)
|
||||
{
|
||||
NSMutableString *log = [NSMutableString string];
|
||||
|
||||
// Default subname
|
||||
if (!subLogName)
|
||||
{
|
||||
subLogName = @"";
|
||||
}
|
||||
|
||||
// Set log location
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||
|
||||
// Do a circular buffer based on X files
|
||||
for (NSInteger index = numberOfFiles - 2; index >= 0; index--)
|
||||
{
|
||||
NSString *nsLogPathOlder;
|
||||
NSString *nsLogPathCurrent;
|
||||
|
||||
if (index == 0)
|
||||
{
|
||||
nsLogPathOlder = [NSString stringWithFormat:@"console%@.1.log", subLogName];
|
||||
nsLogPathCurrent = [NSString stringWithFormat:@"console%@.log", subLogName];
|
||||
}
|
||||
else
|
||||
{
|
||||
nsLogPathOlder = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index + 1];
|
||||
nsLogPathCurrent = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||
}
|
||||
|
||||
nsLogPathOlder = [logsFolderPath stringByAppendingPathComponent:nsLogPathOlder];
|
||||
nsLogPathCurrent = [logsFolderPath stringByAppendingPathComponent:nsLogPathCurrent];
|
||||
|
||||
if ([fileManager fileExistsAtPath:nsLogPathCurrent])
|
||||
{
|
||||
if ([fileManager fileExistsAtPath:nsLogPathOlder])
|
||||
{
|
||||
// Temp log
|
||||
[log appendFormat:@"[MXLogger] redirectNSLogToFiles: removeItemAtPath: %@\n", nsLogPathOlder];
|
||||
|
||||
NSError *error;
|
||||
[fileManager removeItemAtPath:nsLogPathOlder error:&error];
|
||||
if (error)
|
||||
{
|
||||
[log appendFormat:@"[MXLogger] ERROR: removeItemAtPath: %@. Error: %@\n", nsLogPathOlder, error];
|
||||
}
|
||||
}
|
||||
|
||||
// Temp log
|
||||
[log appendFormat:@"[MXLogger] redirectNSLogToFiles: moveItemAtPath: %@ toPath: %@\n", nsLogPathCurrent, nsLogPathOlder];
|
||||
|
||||
NSError *error;
|
||||
[fileManager moveItemAtPath:nsLogPathCurrent toPath:nsLogPathOlder error:&error];
|
||||
if (error)
|
||||
{
|
||||
[log appendFormat:@"[MXLogger] ERROR: moveItemAtPath: %@ toPath: %@. Error: %@\n", nsLogPathCurrent, nsLogPathOlder, error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save stderr so it can be restored.
|
||||
stderrSave = dup(STDERR_FILENO);
|
||||
|
||||
NSString *nsLogPath = [logsFolderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"console%@.log", subLogName]];
|
||||
freopen([nsLogPath fileSystemRepresentation], "w+", stderr);
|
||||
|
||||
// MXLogDebug(@"[MXLogger] redirectNSLogToFiles: YES");
|
||||
if (log.length)
|
||||
{
|
||||
// We can now log into files
|
||||
// MXLogDebug(@"%@", log);
|
||||
}
|
||||
|
||||
[self removeExtraFilesFromCount:numberOfFiles];
|
||||
|
||||
if (sizeLimit > 0)
|
||||
{
|
||||
[self removeFilesAfterSizeLimit:sizeLimit];
|
||||
}
|
||||
}
|
||||
else if (stderrSave)
|
||||
{
|
||||
// Flush before restoring stderr
|
||||
fflush(stderr);
|
||||
|
||||
// Now restore stderr, so new output goes to console.
|
||||
dup2(stderrSave, STDERR_FILENO);
|
||||
close(stderrSave);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)deleteLogFiles
|
||||
{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
for (NSString *logFile in [self logFiles])
|
||||
{
|
||||
[fileManager removeItemAtPath:logFile error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSArray<NSString*>*)logFiles
|
||||
{
|
||||
NSMutableArray *logFiles = [NSMutableArray array];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||
|
||||
NSDirectoryEnumerator *dirEnum = [fileManager enumeratorAtPath:logsFolderPath];
|
||||
|
||||
// Find all *.log files
|
||||
NSString *file = nil;
|
||||
while ((file = [dirEnum nextObject]))
|
||||
{
|
||||
if ([[file lastPathComponent] hasPrefix:@"console"])
|
||||
{
|
||||
NSString *logPath = [logsFolderPath stringByAppendingPathComponent:file];
|
||||
[logFiles addObject:logPath];
|
||||
}
|
||||
}
|
||||
|
||||
// MXLogDebug(@"[MXLogger] logFiles: %@", logFiles);
|
||||
|
||||
return logFiles;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Exceptions and crashes
|
||||
// Exceptions uncaught by try catch block are handled here
|
||||
static void handleUncaughtException(NSException *exception)
|
||||
{
|
||||
[MXLogger logCrashes:NO];
|
||||
|
||||
// Extract running app information
|
||||
NSDictionary* infoDict = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString* appVersion;
|
||||
NSString* app, *appId;
|
||||
|
||||
app = infoDict[@"CFBundleExecutable"];
|
||||
appId = infoDict[@"CFBundleIdentifier"];
|
||||
|
||||
if ([infoDict objectForKey:@"CFBundleVersion"])
|
||||
{
|
||||
appVersion = [NSString stringWithFormat:@"%@ (r%@)", [infoDict objectForKey:@"CFBundleShortVersionString"], [infoDict objectForKey:@"CFBundleVersion"]];
|
||||
}
|
||||
else
|
||||
{
|
||||
appVersion = [infoDict objectForKey:@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
// Build the crash log
|
||||
#if TARGET_OS_IPHONE
|
||||
NSString *model = [[UIDevice currentDevice] model];
|
||||
NSString *version = [[UIDevice currentDevice] systemVersion];
|
||||
#elif TARGET_OS_OSX
|
||||
NSString *model = @"Mac";
|
||||
NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];
|
||||
#endif
|
||||
NSArray *backtrace = [exception callStackSymbols];
|
||||
NSString *description = [NSString stringWithFormat:@"%.0f - %@\n%@\nApplication: %@ (%@)\nApplication version: %@\nMatrix SDK version: %@\nBuild: %@\n%@ %@\n\nMain thread: %@\n%@\n",
|
||||
[[NSDate date] timeIntervalSince1970],
|
||||
[NSDate date],
|
||||
exception.description,
|
||||
app, appId,
|
||||
appVersion,
|
||||
@"",
|
||||
buildVersion,
|
||||
model, version,
|
||||
[NSThread isMainThread] ? @"YES" : @"NO",
|
||||
backtrace];
|
||||
|
||||
// Write to the crash log file
|
||||
[MXLogger deleteCrashLog];
|
||||
NSString *crashLog = crashLogPath();
|
||||
[description writeToFile:crashLog
|
||||
atomically:NO
|
||||
encoding:NSStringEncodingConversionAllowLossy
|
||||
error:nil];
|
||||
|
||||
NSLog(@"[MXLogger] handleUncaughtException:\n%@", description);
|
||||
// MXLogError(@"[MXLogger] handleUncaughtException:\n%@", description);
|
||||
}
|
||||
|
||||
// Signals emitted by the app are handled here
|
||||
static void handleSignal(int signalValue)
|
||||
{
|
||||
// Throw a custom Objective-C exception
|
||||
// The Objective-C runtime will then be able to build a readable call stack in handleUncaughtException
|
||||
[NSException raise:@"Signal detected" format:@"Signal detected: %d", signalValue];
|
||||
}
|
||||
|
||||
+ (void)logCrashes:(BOOL)logCrashes
|
||||
{
|
||||
if (logCrashes)
|
||||
{
|
||||
// Handle not managed exceptions by ourselves
|
||||
NSSetUncaughtExceptionHandler(&handleUncaughtException);
|
||||
|
||||
// Register signal event (seg fault & cie)
|
||||
signal(SIGABRT, handleSignal);
|
||||
signal(SIGILL, handleSignal);
|
||||
signal(SIGSEGV, handleSignal);
|
||||
signal(SIGFPE, handleSignal);
|
||||
signal(SIGBUS, handleSignal);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable crash handling
|
||||
NSSetUncaughtExceptionHandler(NULL);
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
signal(SIGILL, SIG_DFL);
|
||||
signal(SIGSEGV, SIG_DFL);
|
||||
signal(SIGFPE, SIG_DFL);
|
||||
signal(SIGBUS, SIG_DFL);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)setBuildVersion:(NSString *)theBuildVersion
|
||||
{
|
||||
buildVersion = theBuildVersion;
|
||||
}
|
||||
|
||||
+ (void)setSubLogName:(NSString *)theSubLogName
|
||||
{
|
||||
subLogName = [NSString stringWithFormat:@"-%@", theSubLogName];
|
||||
}
|
||||
|
||||
// Return the path of the crash log file
|
||||
static NSString* crashLogPath(void)
|
||||
{
|
||||
return [[MXLogger logsFolderPath] stringByAppendingPathComponent:MXLOGGER_CRASH_LOG];
|
||||
}
|
||||
|
||||
+ (NSString*)crashLog
|
||||
{
|
||||
NSString *exceptionLog;
|
||||
|
||||
NSString *crashLog = crashLogPath();
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if([fileManager fileExistsAtPath:crashLog])
|
||||
{
|
||||
exceptionLog = crashLog;
|
||||
}
|
||||
return exceptionLog;
|
||||
}
|
||||
|
||||
+ (void)deleteCrashLog
|
||||
{
|
||||
NSString *crashLog = crashLogPath();
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
if([fileManager fileExistsAtPath:crashLog])
|
||||
{
|
||||
[fileManager removeItemAtPath:crashLog error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
// The folder where logs are stored
|
||||
+ (NSString*)logsFolderPath
|
||||
{
|
||||
NSString *logsFolderPath = nil;
|
||||
|
||||
// NSURL *sharedContainerURL = [[NSFileManager defaultManager] applicationGroupContainerURL];
|
||||
// if (sharedContainerURL)
|
||||
// {
|
||||
// logsFolderPath = [sharedContainerURL path];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
NSArray<NSURL *> *paths = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
|
||||
logsFolderPath = paths[0].path;
|
||||
// }
|
||||
|
||||
return logsFolderPath;
|
||||
}
|
||||
|
||||
|
||||
// If [self redirectNSLogToFiles: numberOfFiles:] is called with a lower numberOfFiles we need to do some cleanup
|
||||
+ (void)removeExtraFilesFromCount:(NSUInteger)count
|
||||
{
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||
|
||||
NSUInteger index = count;
|
||||
do
|
||||
{
|
||||
NSString *fileName = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||
NSString *logFile = [logsFolderPath stringByAppendingPathComponent:fileName];
|
||||
|
||||
if ([fileManager fileExistsAtPath:logFile])
|
||||
{
|
||||
[fileManager removeItemAtPath:logFile error:nil];
|
||||
// MXLogDebug(@"[MXLogger] removeExtraFilesFromCount: %@. removeItemAtPath: %@\n", @(count), logFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (index++);
|
||||
}
|
||||
|
||||
+ (void)removeFilesAfterSizeLimit:(NSUInteger)sizeLimit
|
||||
{
|
||||
NSUInteger logSize = 0;
|
||||
BOOL removeFiles = NO;
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSString *logsFolderPath = [MXLogger logsFolderPath];
|
||||
|
||||
// Start from console.1.log. Do not consider console.log. It should be almost empty
|
||||
NSUInteger index = 0;
|
||||
while (++index)
|
||||
{
|
||||
NSString *fileName = [NSString stringWithFormat:@"console%@.%tu.log", subLogName, index];
|
||||
NSString *logFile = [logsFolderPath stringByAppendingPathComponent:fileName];
|
||||
|
||||
if ([fileManager fileExistsAtPath:logFile])
|
||||
{
|
||||
logSize += [fileManager attributesOfItemAtPath:logFile error:nil].fileSize;
|
||||
|
||||
if (logSize >= sizeLimit)
|
||||
{
|
||||
removeFiles = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (removeFiles)
|
||||
{
|
||||
// MXLogDebug(@"[MXLogger] removeFilesAfterSizeLimit: Remove files from index %@ because logs are too large (%@ for a limit of %@)\n",
|
||||
// @(index),
|
||||
// [NSByteCountFormatter stringFromByteCount:logSize countStyle:NSByteCountFormatterCountStyleBinary],
|
||||
// [NSByteCountFormatter stringFromByteCount:sizeLimit countStyle:NSByteCountFormatterCountStyleBinary]);
|
||||
[self removeExtraFilesFromCount:index];
|
||||
}
|
||||
else
|
||||
{
|
||||
// MXLogDebug(@"[MXLogger] removeFilesAfterSizeLimit: No need: %@ for a limit of %@\n",
|
||||
// [NSByteCountFormatter stringFromByteCount:logSize countStyle:NSByteCountFormatterCountStyleBinary],
|
||||
// [NSByteCountFormatter stringFromByteCount:sizeLimit countStyle:NSByteCountFormatterCountStyleBinary]);
|
||||
}
|
||||
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// ElementToggleStyle.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Ismail on 2.06.2022.
|
||||
// Copyright © 2022 Element. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A toggle style that uses a button, with a checked/unchecked image like a checkbox.
|
||||
struct ElementToggleStyle: ToggleStyle {
|
||||
|
||||
func makeBody(configuration: Configuration) -> some View {
|
||||
Button { configuration.isOn.toggle() } label: {
|
||||
Image(systemName: configuration.isOn ? "checkmark.square.fill" : "square")
|
||||
.font(.title3.weight(.regular))
|
||||
.imageScale(.large)
|
||||
.foregroundColor(Color(uiColor: Asset.Colors.elementGreen.color))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
}
|
||||
@@ -103,6 +103,9 @@ class RoundedToastView: UIView {
|
||||
case .success:
|
||||
imageView.image = UIImage(systemName: "checkmark.circle")
|
||||
return imageView
|
||||
case .error:
|
||||
imageView.image = UIImage(systemName: "x.circle")
|
||||
return imageView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ struct ToastViewState {
|
||||
enum Style {
|
||||
case loading
|
||||
case success
|
||||
case error
|
||||
}
|
||||
|
||||
let style: Style
|
||||
|
||||
@@ -20,6 +20,7 @@ import UIKit
|
||||
enum UserIndicatorType {
|
||||
case loading(label: String, isInteractionBlocking: Bool)
|
||||
case success(label: String)
|
||||
case error(label: String)
|
||||
}
|
||||
|
||||
/// A presenter which can handle `UserIndicatorType` by creating the underlying `UserIndicator`
|
||||
@@ -72,6 +73,8 @@ class UserIndicatorTypePresenter: UserIndicatorTypePresenterProtocol {
|
||||
}
|
||||
case .success(let label):
|
||||
return successRequest(label: label)
|
||||
case .error(let label):
|
||||
return errorRequest(label: label)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,4 +116,18 @@ class UserIndicatorTypePresenter: UserIndicatorTypePresenterProtocol {
|
||||
dismissal: .timeout(1.5)
|
||||
)
|
||||
}
|
||||
|
||||
private func errorRequest(label: String) -> UserIndicatorRequest {
|
||||
let presenter = ToastViewPresenter(
|
||||
viewState: .init(
|
||||
style: .error,
|
||||
label: label
|
||||
),
|
||||
presentationContext: presentationContext
|
||||
)
|
||||
return UserIndicatorRequest(
|
||||
presenter: presenter,
|
||||
dismissal: .timeout(1.5)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user