Merge branch 'develop' into element_3655

This commit is contained in:
SBiOSoftWhare 2020-11-06 10:35:23 +01:00 committed by GitHub
commit 3429b60227
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 173 additions and 177 deletions

View file

@ -8,13 +8,17 @@ Changes to be released in next version
* Upgrade to Xcode 12 (#3712).
* Xcode 12: Make Xcode 12 and fastlane(xcodebuild) happy while some pods are not updated.
* Update Gemfile.lock.
* MXAnalyticsDelegate: Make it fully agnostic on tracked data.
* KeyValueStore improvements.
* Jitsi: Support authenticated Jitsi widgets (#3655).
🐛 Bugfix
*
* Fix analytics in order to track performance improvements.
* Fix long placeholder cropping in room input toolbar. Prevent long placeholder to be displayed on small devices (#3790).
⚠️ API Changes
* Xcode 12 is now mandatory to build the project.
* Remove MXDecryptionFailureDelegate in flavor of agnostic MXAnalyticsDelegate.
🗣 Translations
*

View file

@ -905,6 +905,8 @@
ECB101322477CFDB00CF8C11 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB1012E2477CFDB00CF8C11 /* UIDevice.swift */; };
ECB101332477CFDB00CF8C11 /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB1012F2477CFDB00CF8C11 /* UITableViewCell.swift */; };
ECB101362477D00700CF8C11 /* UniversalLink.m in Sources */ = {isa = PBXBuildFile; fileRef = ECB101352477D00700CF8C11 /* UniversalLink.m */; };
ECB5D98F255420F8000AD89C /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB5D98E255420F8000AD89C /* Keychain.swift */; };
ECB5D9902554221F000AD89C /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB5D98E255420F8000AD89C /* Keychain.swift */; };
ECDC15F224AF41D2003437CF /* FormattedBodyParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECDC15F124AF41D2003437CF /* FormattedBodyParser.swift */; };
ECF57A4425090C23004BBF9D /* CreateRoomCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF57A3825090C23004BBF9D /* CreateRoomCoordinatorBridgePresenter.swift */; };
ECF57A4525090C23004BBF9D /* CreateRoomCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECF57A3925090C23004BBF9D /* CreateRoomCoordinatorType.swift */; };
@ -2139,6 +2141,7 @@
ECB1012F2477CFDB00CF8C11 /* UITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = "<group>"; };
ECB101342477D00700CF8C11 /* UniversalLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UniversalLink.h; sourceTree = "<group>"; };
ECB101352477D00700CF8C11 /* UniversalLink.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UniversalLink.m; sourceTree = "<group>"; };
ECB5D98E255420F8000AD89C /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = "<group>"; };
ECDC15F124AF41D2003437CF /* FormattedBodyParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattedBodyParser.swift; sourceTree = "<group>"; };
ECF57A3825090C23004BBF9D /* CreateRoomCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateRoomCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
ECF57A3925090C23004BBF9D /* CreateRoomCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateRoomCoordinatorType.swift; sourceTree = "<group>"; };
@ -4871,6 +4874,7 @@
EC1CA87124C823E700DE9EBF /* KeyValueStore.swift */,
EC1CA87424C8259700DE9EBF /* KeychainStore.swift */,
EC1CA87624C82D0E00DE9EBF /* MemoryStore.swift */,
ECB5D98D255420EA000AD89C /* Extensions */,
);
path = KeyValueStorage;
sourceTree = "<group>";
@ -5190,6 +5194,14 @@
path = Models;
sourceTree = "<group>";
};
ECB5D98D255420EA000AD89C /* Extensions */ = {
isa = PBXGroup;
children = (
ECB5D98E255420F8000AD89C /* Keychain.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
ECF57A3725090C23004BBF9D /* CreateRoom */ = {
isa = PBXGroup;
children = (
@ -6195,6 +6207,7 @@
EC9A3EC624E1632C00A8CFAE /* PushNotificationStore.swift in Sources */,
EC31F0952521FC4600D407DA /* PinCodePreferences.swift in Sources */,
32FD757424D2BEF700BA7B37 /* InfoPlist.swift in Sources */,
ECB5D9902554221F000AD89C /* Keychain.swift in Sources */,
EC31F09C2524AE1400D407DA /* BiometricsAuthenticationPresenter.swift in Sources */,
EC85D752247C0F52002C44C9 /* UNUserNotificationCenter.swift in Sources */,
EC9A3EC724E1634100A8CFAE /* KeyValueStore.swift in Sources */,
@ -6774,6 +6787,7 @@
ECF57A87250A6872004BBF9D /* TextViewTableViewCell.swift in Sources */,
B1C562E1228C7C8C0037F12A /* RoomContextualMenuToolbarView.swift in Sources */,
B1CE83DF2422817200D07506 /* KeyVerificationVerifyBySASCoordinatorType.swift in Sources */,
ECB5D98F255420F8000AD89C /* Keychain.swift in Sources */,
B1B557BF20EF5B4500210D55 /* DisabledRoomInputToolbarView.m in Sources */,
B1B5578620EF564900210D55 /* GroupTableViewCellWithSwitch.m in Sources */,
B1098BE821ECFE52000DDA48 /* Coordinator.swift in Sources */,

View file

@ -17,12 +17,11 @@
#import <Foundation/Foundation.h>
#import <MatrixSDK/MatrixSDK.h>
#import "DecryptionFailureTracker.h"
/**
`Analytics` sends analytics to an analytics tool.
*/
@interface Analytics : NSObject <MXAnalyticsDelegate, MXDecryptionFailureDelegate>
@interface Analytics : NSObject <MXAnalyticsDelegate>
/**
Returns the shared Analytics manager.
@ -53,11 +52,4 @@
*/
- (void)dispatch;
/**
Track how long the launch screen has been displayed to the end user.
@param seconds the duration in seconds.
*/
- (void)trackLaunchScreenDisplayDuration: (NSTimeInterval)seconds;
@end

View file

@ -18,42 +18,21 @@
#import "Riot-Swift.h"
// All metrics are store under a Piwik category called "Metrics".
// Then, there are 2 Piwik actions: "iOS.startup" and "iOS.stats" (these actions
// are namespaced by plaform to have a nice rendering on the Piwik website).
// Then, we use constants defined by the Matrix SDK as Piwik Names (ex:"mountData")
NSString *const kAnalyticsMetricsCategory = @"Metrics";
NSString *const kAnalyticsMetricsActionPattern = @"iOS.%@";
// E2E telemetry is stored under a Piwik category called "E2E".
NSString *const kAnalyticsE2eCategory = @"E2E";
NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure";
// Duration data will be visible under the Piwik category called "Performance".
// Other values will be visible in "Metrics".
// Some Matomo screenshots are available at https://github.com/vector-im/element-ios/pull/3789.
NSString *const kAnalyticsPerformanceCategory = @"Performance";
NSString *const kAnalyticsMetricsCategory = @"Metrics";
@import MatomoTracker;
@interface MatomoTracker (MatomoTrackerMigration)
+ (MatomoTracker *)shared;
- (void)migrateFromFourPointFourSharedInstance;
@end
@implementation MatomoTracker (MatomoTrackerMigration)
+ (MatomoTracker *)shared
@interface Analytics ()
{
MatomoTracker *matomoTracker = [[MatomoTracker alloc] initWithSiteId:BuildSettings.analyticsAppId
baseURL:BuildSettings.analyticsServerUrl
userAgent:@"iOSMatomoTracker"];
[matomoTracker migrateFromFourPointFourSharedInstance];
return matomoTracker;
MatomoTracker *matomoTracker;
}
- (void)migrateFromFourPointFourSharedInstance
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"migratedFromFourPointFourSharedInstance"]) return;
[self copyFromOldSharedInstance];
[[NSUserDefaults standardUserDefaults] setBool:true forKey:@"migratedFromFourPointFourSharedInstance"];
}
@end
@implementation Analytics
@ -70,26 +49,46 @@ NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure";
return sharedInstance;
}
- (instancetype)init
{
self = [super init];
if (self)
{
matomoTracker = [[MatomoTracker alloc] initWithSiteId:BuildSettings.analyticsAppId
baseURL:BuildSettings.analyticsServerUrl
userAgent:@"iOSMatomoTracker"];
[self migrateFromFourPointFourSharedInstance];
}
return self;
}
- (void)migrateFromFourPointFourSharedInstance
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"migratedFromFourPointFourSharedInstance"]) return;
[matomoTracker copyFromOldSharedInstance];
[[NSUserDefaults standardUserDefaults] setBool:true forKey:@"migratedFromFourPointFourSharedInstance"];
}
- (void)start
{
// Check whether the user has enabled the sending of crash reports.
if (RiotSettings.shared.enableCrashReport)
{
[MatomoTracker shared].isOptedOut = NO;
matomoTracker.isOptedOut = NO;
[[MatomoTracker shared] setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"];
[[MatomoTracker shared] setCustomVariableWithIndex:2 name:@"App Version" value:[AppDelegate theDelegate].appVersion];
[matomoTracker setCustomVariableWithIndex:1 name:@"App Platform" value:@"iOS Platform"];
[matomoTracker setCustomVariableWithIndex:2 name:@"App Version" value:[AppDelegate theDelegate].appVersion];
// The language is either the one selected by the user within the app
// or, else, the one configured by the OS
NSString *language = [NSBundle mxk_language] ? [NSBundle mxk_language] : [[NSBundle mainBundle] preferredLocalizations][0];
[[MatomoTracker shared] setCustomVariableWithIndex:4 name:@"Chosen Language" value:language];
[matomoTracker setCustomVariableWithIndex:4 name:@"Chosen Language" value:language];
MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject;
if (account)
{
[[MatomoTracker shared] setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer];
[[MatomoTracker shared] setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL];
[matomoTracker setCustomVariableWithIndex:7 name:@"Homeserver URL" value:account.mxCredentials.homeServer];
[matomoTracker setCustomVariableWithIndex:8 name:@"Identity Server URL" value:account.identityServerURL];
}
// TODO: We should also track device and os version
@ -101,20 +100,20 @@ NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure";
#ifdef DEBUG
// Disable analytics in debug as it pollutes stats
[MatomoTracker shared].isOptedOut = YES;
matomoTracker.isOptedOut = YES;
#endif
}
else
{
NSLog(@"[AppDelegate] The user decided to not send analytics");
[MatomoTracker shared].isOptedOut = YES;
matomoTracker.isOptedOut = YES;
[MXLogger logCrashes:NO];
}
}
- (void)stop
{
[MatomoTracker shared].isOptedOut = YES;
matomoTracker.isOptedOut = YES;
[MXLogger logCrashes:NO];
}
@ -124,84 +123,35 @@ NSString *const kAnalyticsE2eDecryptionFailureAction = @"Decryption failure";
NSString *appName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
NSString *appVersion = [AppDelegate theDelegate].appVersion;
[[MatomoTracker shared] trackWithView:@[@"ios", appName, appVersion, screenName]
[matomoTracker trackWithView:@[@"ios", appName, appVersion, screenName]
url:nil];
}
- (void)dispatch
{
[[MatomoTracker shared] dispatch];
}
- (void)trackLaunchScreenDisplayDuration:(NSTimeInterval)seconds
{
NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory];
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory
action:action
name:kMXAnalyticsStartupLaunchScreen
number:@(seconds * 1000)
url:nil];
[matomoTracker dispatch];
}
#pragma mark - MXAnalyticsDelegate
- (void)trackStartupStorePreloadDuration: (NSTimeInterval)seconds
- (void)trackDuration:(NSTimeInterval)seconds category:(NSString*)category name:(NSString*)name
{
NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory];
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory
action:action
name:kMXAnalyticsStartupStorePreload
number:@(seconds * 1000)
url:nil];
// Report time in ms to make figures look better in Matomo
NSNumber *value = @(seconds * 1000);
[matomoTracker trackWithEventWithCategory:kAnalyticsPerformanceCategory
action:category
name:name
number:value
url:nil];
}
- (void)trackStartupMountDataDuration: (NSTimeInterval)seconds
- (void)trackValue:(NSNumber*)value category:(NSString*)category name:(NSString*)name
{
NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory];
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory
action:action
name:kMXAnalyticsStartupMountData
number:@(seconds * 1000)
url:nil];
}
- (void)trackStartupSyncDuration: (NSTimeInterval)seconds isInitial: (BOOL)isInitial
{
NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStartupCategory];
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory
action:action
name:isInitial ? kMXAnalyticsStartupInititialSync : kMXAnalyticsStartupIncrementalSync
number:@(seconds * 1000)
url:nil];
}
- (void)trackRoomCount: (NSUInteger)roomCount
{
NSString *action = [NSString stringWithFormat:kAnalyticsMetricsActionPattern, kMXAnalyticsStatsCategory];
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsMetricsCategory
action:action
name:kMXAnalyticsStatsRooms
number:@(roomCount)
url:nil];
}
#pragma mark - MXDecryptionFailureDelegate
- (void)trackFailures:(NSDictionary<NSString *,NSNumber *> *)failuresCounts
{
for (NSString *reason in failuresCounts)
{
[[MatomoTracker shared] trackWithEventWithCategory:kAnalyticsE2eCategory
action:kAnalyticsE2eDecryptionFailureAction
name:reason
number:failuresCounts[reason]
url:nil];
}
[matomoTracker trackWithEventWithCategory:kAnalyticsMetricsCategory
action:category
name:name
number:value
url:nil];
}
@end

View file

@ -20,8 +20,6 @@
@import MatrixSDK;
@protocol MXDecryptionFailureDelegate;
@interface DecryptionFailureTracker : NSObject
/**
@ -34,7 +32,7 @@
/**
The delegate object to receive analytics events.
*/
@property (nonatomic) id<MXDecryptionFailureDelegate> delegate;
@property (nonatomic) id<MXAnalyticsDelegate> delegate;
/**
Report an event unable to decrypt.
@ -54,18 +52,3 @@
- (void)dispatch;
@end
/**
The `MXDecryptionFailureDelegate` protocol receives some stats computed by
`DecryptionFailureTracker`.
*/
@protocol MXDecryptionFailureDelegate <NSObject>
/**
Stats for decryption failures.
@param failuresCounts the number of errors per failure reason.
*/
- (void)trackFailures:(NSDictionary<NSString*, NSNumber*> *)failuresCounts;
@end

View file

@ -24,6 +24,8 @@
// and reporting them as failures
#define GRACE_PERIOD 60
// E2E failures analytics category.
NSString *const kDecryptionFailureTrackerAnalyticsCategory = @"e2e.failure";
@interface DecryptionFailureTracker()
{
@ -128,6 +130,11 @@
*/
- (void)checkFailures
{
if (!_delegate)
{
return;
}
NSTimeInterval tsNow = [NSDate date].timeIntervalSince1970;
NSMutableArray *failuresToTrack = [NSMutableArray array];
@ -142,7 +149,7 @@
}
}
if (_delegate && failuresToTrack.count)
if (failuresToTrack.count)
{
// Sort failures by error reason
NSMutableDictionary<NSString*, NSNumber*> *failuresCounts = [NSMutableDictionary dictionary];
@ -152,8 +159,11 @@
}
NSLog(@"[DecryptionFailureTracker] trackFailures: %@", failuresCounts);
[_delegate trackFailures:failuresCounts];
for (NSString *reason in failuresCounts)
{
[_delegate trackValue:failuresCounts[reason] category:kDecryptionFailureTrackerAnalyticsCategory name:reason];
}
}
}

View file

@ -0,0 +1,35 @@
//
// Copyright 2020 New Vector Ltd
//
// 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
import KeychainAccess
/// Extension on Keychain to get/set booleans
extension Keychain {
public func set(_ value: Bool, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
try set(value.description, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func getBool(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Bool? {
guard let value = try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
return nil
}
guard value == true.description || value == false.description else { return nil }
return value == true.description
}
}

View file

@ -24,12 +24,17 @@ protocol KeyValueStore {
func set(_ value: String?, forKey key: KeyValueStoreKey) throws
func set(_ value: Bool?, forKey key: KeyValueStoreKey) throws
func set(_ value: Int?, forKey key: KeyValueStoreKey) throws
func set(_ value: UInt?, forKey key: KeyValueStoreKey) throws
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data?
func string(forKey key: KeyValueStoreKey) throws -> String?
func bool(forKey key: KeyValueStoreKey) throws -> Bool?
func integer(forKey key: KeyValueStoreKey) throws -> Int?
func unsignedInteger(forKey key: KeyValueStoreKey) throws -> UInt?
// checkers
func containsObject(forKey key: KeyValueStoreKey) -> Bool
// remove
func removeObject(forKey key: KeyValueStoreKey) throws

View file

@ -17,23 +17,6 @@
import Foundation
import KeychainAccess
/// Extension on Keychain to get/set booleans
extension Keychain {
public func set(_ value: Bool, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
try set(value.description, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}
public func getBool(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Bool? {
guard let value = try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
return nil
}
guard value == true.description || value == false.description else { return nil }
return value == true.description
}
}
class KeychainStore {
private var keychain: Keychain
@ -85,6 +68,15 @@ extension KeychainStore: KeyValueStore {
try keychain.set(String(value), key: key)
}
func set(_ value: UInt?, forKey key: KeyValueStoreKey) throws {
guard let value = value else {
try removeObject(forKey: key)
return
}
try keychain.set(String(value), key: key)
}
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data? {
return try keychain.getData(key)
@ -105,6 +97,18 @@ extension KeychainStore: KeyValueStore {
return Int(stringValue)
}
func unsignedInteger(forKey key: KeyValueStoreKey) throws -> UInt? {
guard let stringValue = try keychain.getString(key) else {
return nil
}
return UInt(stringValue)
}
// checkers
func containsObject(forKey key: KeyValueStoreKey) -> Bool {
return (try? keychain.contains(key)) ?? false
}
// remove
func removeObject(forKey key: KeyValueStoreKey) throws {
try keychain.remove(key)

View file

@ -18,13 +18,13 @@ import Foundation
class MemoryStore {
private var map: Dictionary<KeyValueStoreKey, Any> = [:]
private(set) var map: [KeyValueStoreKey: Any] = [:]
private func setObject(_ value: Any?, forKey key: KeyValueStoreKey) {
if let value = value {
map[key] = value
} else {
removeObject(forKey: key)
try? removeObject(forKey: key)
}
}
@ -32,6 +32,10 @@ class MemoryStore {
return map[key]
}
init(withMap map: [KeyValueStoreKey: Any] = [:]) {
self.map = map
}
}
extension MemoryStore: KeyValueStore {
@ -53,6 +57,10 @@ extension MemoryStore: KeyValueStore {
setObject(value, forKey: key)
}
func set(_ value: UInt?, forKey key: KeyValueStoreKey) throws {
setObject(value, forKey: key)
}
// getters
func data(forKey key: KeyValueStoreKey) throws -> Data? {
return object(forKey: key) as? Data
@ -70,8 +78,17 @@ extension MemoryStore: KeyValueStore {
return object(forKey: key) as? Int
}
func unsignedInteger(forKey key: KeyValueStoreKey) throws -> UInt? {
return object(forKey: key) as? UInt
}
// checkers
func containsObject(forKey key: KeyValueStoreKey) -> Bool {
return object(forKey: key) != nil
}
// remove
func removeObject(forKey key: KeyValueStoreKey) {
func removeObject(forKey key: KeyValueStoreKey) throws {
map.removeValue(forKey: key)
}

View file

@ -34,6 +34,7 @@
#import "BugReportViewController.h"
#import "RoomKeyRequestViewController.h"
#import "DecryptionFailureTracker.h"
#import <MatrixKit/MatrixKit.h>
@ -2418,7 +2419,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
NSLog(@"[AppDelegate] hideLaunchAnimation: LaunchAnimation was shown for %.3fms", duration * 1000);
// Track it on our analytics
[[Analytics sharedInstance] trackLaunchScreenDisplayDuration:duration];
[[MXSDKOptions sharedInstance].analyticsDelegate trackDuration:duration
category:kMXAnalyticsStartupCategory
name:kMXAnalyticsStartupLaunchScreen];
// TODO: Send durationMs to Piwik
// Such information should be the same on all platforms

View file

@ -132,28 +132,7 @@
{
_isEncryptionEnabled = isEncryptionEnabled;
// Consider the default placeholder
NSString *placeholder= NSLocalizedStringFromTable(@"room_message_short_placeholder", @"Vector", nil);
if (_isEncryptionEnabled)
{
// Check the device screen size before using large placeholder
if ([GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay4p7Inch)
{
placeholder = NSLocalizedStringFromTable(@"encrypted_room_message_placeholder", @"Vector", nil);
}
}
else
{
// Check the device screen size before using large placeholder
if ([GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay4p7Inch)
{
placeholder = NSLocalizedStringFromTable(@"room_message_placeholder", @"Vector", nil);
}
}
self.placeholder = placeholder;
[self updatePlaceholder];
}
- (void)setSendMode:(RoomInputToolbarViewSendMode)sendMode
@ -192,7 +171,7 @@
NSString *placeholder;
// Check the device screen size before using large placeholder
BOOL shouldDisplayLargePlaceholder = [GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay4p7Inch;
BOOL shouldDisplayLargePlaceholder = [GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay5p8Inch;
if (!shouldDisplayLargePlaceholder)
{