Merge tag '2.28.0.15'

pull/1/head
Michael Kirk 7 years ago
commit 78ad597e44

@ -427,6 +427,7 @@
45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; }; 45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */; };
45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; }; 45FBC5D11DF8592E00E9B410 /* SignalCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */; };
4AC4EA13C8A444455DAB351F /* Pods_SignalMessaging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */; }; 4AC4EA13C8A444455DAB351F /* Pods_SignalMessaging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 264242150E87D10A357DB07B /* Pods_SignalMessaging.framework */; };
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; };
4C11AA5020FD59C700351FBD /* MessageStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C11AA4F20FD59C700351FBD /* MessageStatusView.swift */; }; 4C11AA5020FD59C700351FBD /* MessageStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C11AA4F20FD59C700351FBD /* MessageStatusView.swift */; };
4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */; }; 4C13C9F620E57BA30089A98B /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */; };
4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; }; 4C20B2B720CA0034001BAC90 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4542DF51208B82E9007B4E76 /* ThreadViewModel.swift */; };
@ -1110,6 +1111,7 @@
45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = "<group>"; }; 45FBC59A1DF8575700E9B410 /* CallKitCallManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallKitCallManager.swift; sourceTree = "<group>"; };
45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = "<group>"; }; 45FBC5D01DF8592E00E9B410 /* SignalCall.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalCall.swift; sourceTree = "<group>"; };
45FDA43420A4D22700396358 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSNavigationBar.swift; sourceTree = "<group>"; }; 45FDA43420A4D22700396358 /* OWSNavigationBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OWSNavigationBar.swift; sourceTree = "<group>"; };
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HapticFeedback.swift; path = UserInterface/HapticFeedback.swift; sourceTree = "<group>"; };
4C11AA4F20FD59C700351FBD /* MessageStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStatusView.swift; sourceTree = "<group>"; }; 4C11AA4F20FD59C700351FBD /* MessageStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageStatusView.swift; sourceTree = "<group>"; };
4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; }; 4C13C9F520E57BA30089A98B /* ColorPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = "<group>"; };
4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = "<group>"; }; 4C20B2B820CA10DE001BAC90 /* ConversationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearchViewController.swift; sourceTree = "<group>"; };
@ -1932,6 +1934,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
450DF2071E0DD29E003D14BE /* Notifications */, 450DF2071E0DD29E003D14BE /* Notifications */,
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */,
34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */, 34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */,
34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */, 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */,
34B3F8331E8DF1700035BE1A /* ViewControllers */, 34B3F8331E8DF1700035BE1A /* ViewControllers */,
@ -3321,6 +3324,7 @@
34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */,
340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */,
340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */,
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */,
3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */,
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */, 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */,
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */,

@ -38,7 +38,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2.28.0.13</string> <string>2.28.0.15</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>LOGS_EMAIL</key> <key>LOGS_EMAIL</key>

@ -0,0 +1,51 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
protocol HapticAdapter {
func selectionChanged()
}
class LegacyHapticAdapter: NSObject, HapticAdapter {
// MARK: HapticAdapter
func selectionChanged() {
// do nothing
}
}
@available(iOS 10, *)
class FeedbackGeneratorHapticAdapter: NSObject, HapticAdapter {
let selectionFeedbackGenerator: UISelectionFeedbackGenerator
override init() {
selectionFeedbackGenerator = UISelectionFeedbackGenerator()
selectionFeedbackGenerator.prepare()
}
// MARK: HapticAdapter
func selectionChanged() {
selectionFeedbackGenerator.selectionChanged()
selectionFeedbackGenerator.prepare()
}
}
class HapticFeedback: HapticAdapter {
let adapter: HapticAdapter
init() {
if #available(iOS 10, *) {
adapter = FeedbackGeneratorHapticAdapter()
} else {
adapter = LegacyHapticAdapter()
}
}
func selectionChanged() {
adapter.selectionChanged()
}
}

@ -508,12 +508,18 @@ NS_ASSUME_NONNULL_BEGIN
[self.bubbleView addPartnerView:shadowView]; [self.bubbleView addPartnerView:shadowView];
[self.bubbleView addPartnerView:clipView]; [self.bubbleView addPartnerView:clipView];
// Prevent the layer from animating changes.
[CATransaction begin];
[CATransaction setDisableActions:YES];
OWSAssert(buttonsView.backgroundColor); OWSAssert(buttonsView.backgroundColor);
shadowView.fillColor = buttonsView.backgroundColor; shadowView.fillColor = buttonsView.backgroundColor;
shadowView.layer.shadowColor = Theme.boldColor.CGColor; shadowView.layer.shadowColor = Theme.boldColor.CGColor;
shadowView.layer.shadowOpacity = 0.12f; shadowView.layer.shadowOpacity = 0.12f;
shadowView.layer.shadowOffset = CGSizeZero; shadowView.layer.shadowOffset = CGSizeZero;
shadowView.layer.shadowRadius = 1.f; shadowView.layer.shadowRadius = 1.f;
[CATransaction commit];
} }
- (BOOL)contactShareHasSpacerTop - (BOOL)contactShareHasSpacerTop

@ -3461,9 +3461,9 @@ typedef enum : NSUInteger {
} }
[self updateLastVisibleTimestamp]; [self updateLastVisibleTimestamp];
if (scrollToBottom) { if (scrollToBottom && shouldAnimateUpdates) {
[self scrollToBottomAnimated:shouldAnimateScrollToBottom && shouldAnimateUpdates]; [self scrollToBottomAnimated:shouldAnimateScrollToBottom];
} }
}; };
if (shouldAnimateUpdates) { if (shouldAnimateUpdates) {
@ -3471,6 +3471,9 @@ typedef enum : NSUInteger {
} else { } else {
[UIView performWithoutAnimation:^{ [UIView performWithoutAnimation:^{
[self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion]; [self.collectionView performBatchUpdates:batchUpdates completion:batchUpdatesCompletion];
if (scrollToBottom) {
[self scrollToBottomAnimated:NO];
}
}]; }];
} }
self.lastReloadDate = [NSDate new]; self.lastReloadDate = [NSDate new];
@ -3482,55 +3485,40 @@ typedef enum : NSUInteger {
OWSAssert(rowChanges); OWSAssert(rowChanges);
// If user sends a new outgoing message, don't animate the change. // If user sends a new outgoing message, don't animate the change.
BOOL isOnlyInsertingNewOutgoingMessages = YES; BOOL isOnlyModifyingLastMessage = YES;
BOOL isOnlyUpdatingLastOutgoingMessage = YES;
NSNumber *_Nullable lastUpdateRow = nil;
NSNumber *_Nullable lastNonUpdateRow = nil;
for (YapDatabaseViewRowChange *rowChange in rowChanges) { for (YapDatabaseViewRowChange *rowChange in rowChanges) {
switch (rowChange.type) { switch (rowChange.type) {
case YapDatabaseViewChangeDelete: case YapDatabaseViewChangeDelete:
isOnlyInsertingNewOutgoingMessages = NO; isOnlyModifyingLastMessage = NO;
isOnlyUpdatingLastOutgoingMessage = NO;
if (!lastNonUpdateRow || lastNonUpdateRow.integerValue < rowChange.indexPath.row) {
lastNonUpdateRow = @(rowChange.indexPath.row);
}
break; break;
case YapDatabaseViewChangeInsert: { case YapDatabaseViewChangeInsert: {
isOnlyUpdatingLastOutgoingMessage = NO;
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex]; ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
if ([viewItem.interaction isKindOfClass:[TSOutgoingMessage class]] if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
&& rowChange.finalIndex >= oldViewItemCount) { && rowChange.finalIndex >= oldViewItemCount) {
continue; continue;
} }
if (!lastNonUpdateRow || lastNonUpdateRow.unsignedIntegerValue < rowChange.finalIndex) { isOnlyModifyingLastMessage = NO;
lastNonUpdateRow = @(rowChange.finalIndex);
}
} }
case YapDatabaseViewChangeMove: case YapDatabaseViewChangeMove:
isOnlyInsertingNewOutgoingMessages = NO; isOnlyModifyingLastMessage = NO;
isOnlyUpdatingLastOutgoingMessage = NO;
if (!lastNonUpdateRow || lastNonUpdateRow.integerValue < rowChange.indexPath.row) {
lastNonUpdateRow = @(rowChange.indexPath.row);
}
if (!lastNonUpdateRow || lastNonUpdateRow.unsignedIntegerValue < rowChange.finalIndex) {
lastNonUpdateRow = @(rowChange.finalIndex);
}
break; break;
case YapDatabaseViewChangeUpdate: { case YapDatabaseViewChangeUpdate: {
isOnlyInsertingNewOutgoingMessages = NO; if (rowChange.changes == YapDatabaseViewChangedDependency) {
ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex]; continue;
if (![viewItem.interaction isKindOfClass:[TSOutgoingMessage class]]
|| rowChange.indexPath.row != (NSInteger)(oldViewItemCount - 1)) {
isOnlyUpdatingLastOutgoingMessage = NO;
} }
if (!lastUpdateRow || lastUpdateRow.integerValue < rowChange.indexPath.row) { ConversationViewItem *_Nullable viewItem = [self viewItemForIndex:(NSInteger)rowChange.finalIndex];
lastUpdateRow = @(rowChange.indexPath.row); if (([viewItem.interaction isKindOfClass:[TSIncomingMessage class]] ||
[viewItem.interaction isKindOfClass:[TSOutgoingMessage class]])
&& rowChange.finalIndex >= oldViewItemCount) {
continue;
} }
isOnlyModifyingLastMessage = NO;
break; break;
} }
} }
} }
BOOL shouldAnimateRowUpdates = !(isOnlyInsertingNewOutgoingMessages || isOnlyUpdatingLastOutgoingMessage); BOOL shouldAnimateRowUpdates = !isOnlyModifyingLastMessage;
return shouldAnimateRowUpdates; return shouldAnimateRowUpdates;
} }

@ -40,6 +40,23 @@ typedef NS_ENUM(NSInteger, HomeViewMode) {
HomeViewMode_Inbox, HomeViewMode_Inbox,
}; };
// The bulk of the content in this view is driven by a YapDB view/mapping.
// However, we also want to optionally include ReminderView's at the top
// and an "Archived Conversations" button at the bottom. Rather than introduce
// index-offsets into the Mapping calculation, we introduce two pseudo groups
// to add a top and bottom section to the content, and create cells for those
// sections without consulting the YapMapping.
// This is a bit of a hack, but it consolidates the hacks into the Reminder/Archive section
// and allows us to leaves the bulk of the content logic on the happy path.
NSString *const kReminderViewPseudoGroup = @"kReminderViewPseudoGroup";
NSString *const kArchiveButtonPseudoGroup = @"kArchiveButtonPseudoGroup";
typedef NS_ENUM(NSInteger, HomeViewControllerSection) {
HomeViewControllerSectionReminders,
HomeViewControllerSectionConversations,
HomeViewControllerSectionArchiveButton,
};
NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversationsReuseIdentifier"; NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversationsReuseIdentifier";
@interface HomeViewController () <UITableViewDelegate, @interface HomeViewController () <UITableViewDelegate,
@ -76,6 +93,8 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
// Views // Views
@property (nonatomic, readonly) UIStackView *reminderStackView;
@property (nonatomic, readonly) UITableViewCell *reminderViewCell;
@property (nonatomic, readonly) UIView *deregisteredView; @property (nonatomic, readonly) UIView *deregisteredView;
@property (nonatomic, readonly) UIView *outageView; @property (nonatomic, readonly) UIView *outageView;
@property (nonatomic, readonly) UIView *archiveReminderView; @property (nonatomic, readonly) UIView *archiveReminderView;
@ -85,6 +104,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
@property (nonatomic) BOOL hasArchivedThreadsRow; @property (nonatomic) BOOL hasArchivedThreadsRow;
@property (nonatomic) BOOL hasThemeChanged; @property (nonatomic) BOOL hasThemeChanged;
@property (nonatomic) BOOL hasVisibleReminders;
@end @end
@ -252,18 +272,13 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
} }
UIStackView *reminderStackView = [UIStackView new]; UIStackView *reminderStackView = [UIStackView new];
_reminderStackView = reminderStackView;
reminderStackView.axis = UILayoutConstraintAxisVertical; reminderStackView.axis = UILayoutConstraintAxisVertical;
reminderStackView.spacing = 0; reminderStackView.spacing = 0;
[self.view addSubview:reminderStackView]; _reminderViewCell = [UITableViewCell new];
[reminderStackView autoPinWidthToSuperview]; self.reminderViewCell.selectionStyle = UITableViewCellSelectionStyleNone;
[reminderStackView autoPinToTopLayoutGuideOfViewController:self withInset:0]; [self.reminderViewCell.contentView addSubview:reminderStackView];
[reminderStackView autoPinEdgesToSuperviewEdges];
// Fixes ambiguous height of an empty stack view pinned above a scroll view on iOS10.
// Without this users would sometimes see the empty stackview take up most of their screen.
[NSLayoutConstraint autoSetPriority:UILayoutPriorityDefaultLow
forConstraints:^{
[reminderStackView autoSetDimension:ALDimensionHeight toSize:0];
}];
__weak HomeViewController *weakSelf = self; __weak HomeViewController *weakSelf = self;
ReminderView *deregisteredView = ReminderView *deregisteredView =
@ -307,11 +322,8 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
[self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:HomeViewCell.cellReuseIdentifier]; [self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:HomeViewCell.cellReuseIdentifier];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kArchivedConversationsReuseIdentifier]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kArchivedConversationsReuseIdentifier];
[self.view addSubview:self.tableView]; [self.view addSubview:self.tableView];
[self.tableView autoPinWidthToSuperview]; [self.tableView autoPinEdgesToSuperviewEdges];
[self.tableView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
// TODO - have content scroll behind navbar will require changing this.
[self.tableView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:reminderStackView];
self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 60; self.tableView.estimatedRowHeight = 60;
@ -345,6 +357,9 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
self.missingContactsPermissionView.hidden = !self.contactsManager.isSystemContactsDenied; self.missingContactsPermissionView.hidden = !self.contactsManager.isSystemContactsDenied;
self.deregisteredView.hidden = !TSAccountManager.sharedInstance.isDeregistered; self.deregisteredView.hidden = !TSAccountManager.sharedInstance.isDeregistered;
self.outageView.hidden = !OutageDetection.sharedManager.hasOutage; self.outageView.hidden = !OutageDetection.sharedManager.hasOutage;
self.hasVisibleReminders = !self.archiveReminderView.isHidden || !self.missingContactsPermissionView.isHidden
|| !self.deregisteredView.isHidden || !self.outageView.isHidden;
} }
- (void)viewDidLoad - (void)viewDidLoad
@ -400,9 +415,12 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
self.searchResultsController = searchResultsController; self.searchResultsController = searchResultsController;
[self addChildViewController:searchResultsController]; [self addChildViewController:searchResultsController];
[self.view addSubview:searchResultsController.view]; [self.view addSubview:searchResultsController.view];
[searchResultsController.view autoPinWidthToSuperview]; [searchResultsController.view autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero excludingEdge:ALEdgeTop];
[searchResultsController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:searchBar]; if (@available(iOS 11, *)) {
[searchResultsController.view autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.tableView]; [searchResultsController.view autoPinTopToSuperviewMarginWithInset:56];
} else {
[searchResultsController.view autoPinToTopLayoutGuideOfViewController:self withInset:40];
}
searchResultsController.view.hidden = YES; searchResultsController.view.hidden = YES;
[self updateBarButtonItems]; [self updateBarButtonItems];
@ -486,23 +504,23 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
{ {
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location]; NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
if ([self isIndexPathForArchivedConversations:indexPath]) { if (!indexPath) {
return nil; return nil;
} }
if (indexPath) { if (indexPath.section != HomeViewControllerSectionConversations) {
[previewingContext setSourceRect:[self.tableView rectForRowAtIndexPath:indexPath]];
ConversationViewController *vc = [ConversationViewController new];
TSThread *thread = [self threadForIndexPath:indexPath];
self.lastThread = thread;
[vc configureForThread:thread action:ConversationViewActionNone focusMessageId:nil];
[vc peekSetup];
return vc;
} else {
return nil; return nil;
} }
[previewingContext setSourceRect:[self.tableView rectForRowAtIndexPath:indexPath]];
ConversationViewController *vc = [ConversationViewController new];
TSThread *thread = [self threadForIndexPath:indexPath];
self.lastThread = thread;
[vc configureForThread:thread action:ConversationViewActionNone focusMessageId:nil];
[vc peekSetup];
return vc;
} }
- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext - (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext
@ -558,7 +576,7 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
BOOL isShowingSearchResults = !self.searchResultsController.view.hidden; BOOL isShowingSearchResults = !self.searchResultsController.view.hidden;
if (isShowingSearchResults) { if (isShowingSearchResults) {
OWSAssert(self.searchBar.text.ows_stripped.length > 0); OWSAssert(self.searchBar.text.ows_stripped.length > 0);
self.tableView.contentOffset = CGPointZero; [self scrollSearchBarToTopAnimated:NO];
} else if (self.lastThread) { } else if (self.lastThread) {
OWSAssert(self.searchBar.text.ows_stripped.length == 0); OWSAssert(self.searchBar.text.ows_stripped.length == 0);
@ -754,31 +772,30 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
return (NSInteger)[self.threadMappings numberOfSections]; return (NSInteger)[self.threadMappings numberOfSections];
} }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)aSection
{ {
NSInteger result = (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)section]; HomeViewControllerSection section = (HomeViewControllerSection)aSection;
if (self.hasArchivedThreadsRow) { switch (section) {
// Add the "archived conversations" row. case HomeViewControllerSectionReminders: {
result++; return self.hasVisibleReminders ? 1 : 0;
}
case HomeViewControllerSectionConversations: {
NSInteger result = (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)section];
return result;
}
case HomeViewControllerSectionArchiveButton: {
return self.hasArchivedThreadsRow ? 1 : 0;
}
} }
return result;
}
- (BOOL)isIndexPathForArchivedConversations:(NSIndexPath *)indexPath OWSFail(@"%@ failure: unexpected section: %lu", self.logTag, (unsigned long)section);
{ return 0;
if (self.homeViewMode != HomeViewMode_Inbox) {
return NO;
}
if (indexPath.section != 0) {
return NO;
}
NSInteger cellCount = (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)0];
return indexPath.row == cellCount;
} }
- (ThreadViewModel *)threadViewModelForIndexPath:(NSIndexPath *)indexPath - (ThreadViewModel *)threadViewModelForIndexPath:(NSIndexPath *)indexPath
{ {
TSThread *threadRecord = [self threadForIndexPath:indexPath]; TSThread *threadRecord = [self threadForIndexPath:indexPath];
OWSAssert(threadRecord);
ThreadViewModel *_Nullable cachedThreadViewModel = [self.threadViewModelCache objectForKey:threadRecord.uniqueId]; ThreadViewModel *_Nullable cachedThreadViewModel = [self.threadViewModelCache objectForKey:threadRecord.uniqueId];
if (cachedThreadViewModel) { if (cachedThreadViewModel) {
@ -795,11 +812,21 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if ([self isIndexPathForArchivedConversations:indexPath]) { HomeViewControllerSection section = (HomeViewControllerSection)indexPath.section;
return [self cellForArchivedConversationsRow:tableView]; switch (section) {
} else { case HomeViewControllerSectionReminders: {
return [self tableView:tableView cellForConversationAtIndexPath:indexPath]; return self.reminderViewCell;
}
case HomeViewControllerSectionConversations: {
return [self tableView:tableView cellForConversationAtIndexPath:indexPath];
}
case HomeViewControllerSectionArchiveButton: {
return [self cellForArchivedConversationsRow:tableView];
}
} }
OWSFail(@"%@ failure: unexpected section: %lu", self.logTag, (unsigned long)section);
return [UITableViewCell new];
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForConversationAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForConversationAtIndexPath:(NSIndexPath *)indexPath
@ -894,56 +921,70 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
- (nullable NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath - (nullable NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if ([self isIndexPathForArchivedConversations:indexPath]) { HomeViewControllerSection section = (HomeViewControllerSection)indexPath.section;
return @[]; switch (section) {
} case HomeViewControllerSectionReminders: {
return @[];
UITableViewRowAction *deleteAction = }
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault case HomeViewControllerSectionConversations: {
title:NSLocalizedString(@"TXT_DELETE_TITLE", nil) UITableViewRowAction *deleteAction =
handler:^(UITableViewRowAction *action, NSIndexPath *swipedIndexPath) { [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
[self tableViewCellTappedDelete:swipedIndexPath]; title:NSLocalizedString(@"TXT_DELETE_TITLE", nil)
}]; handler:^(UITableViewRowAction *action, NSIndexPath *swipedIndexPath) {
[self tableViewCellTappedDelete:swipedIndexPath];
UITableViewRowAction *archiveAction; }];
if (self.homeViewMode == HomeViewMode_Inbox) {
archiveAction = [UITableViewRowAction UITableViewRowAction *archiveAction;
rowActionWithStyle:UITableViewRowActionStyleNormal if (self.homeViewMode == HomeViewMode_Inbox) {
title:NSLocalizedString(@"ARCHIVE_ACTION", archiveAction = [UITableViewRowAction
@"Pressing this button moves a thread from the inbox to the archive") rowActionWithStyle:UITableViewRowActionStyleNormal
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull tappedIndexPath) { title:NSLocalizedString(@"ARCHIVE_ACTION",
[self archiveIndexPath:tappedIndexPath]; @"Pressing this button moves a thread from the inbox to the archive")
[Environment.preferences setHasArchivedAMessage:YES]; handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull tappedIndexPath) {
}]; [self archiveIndexPath:tappedIndexPath];
[Environment.preferences setHasArchivedAMessage:YES];
}];
} else {
archiveAction = [UITableViewRowAction
rowActionWithStyle:UITableViewRowActionStyleNormal
title:NSLocalizedString(@"UNARCHIVE_ACTION",
@"Pressing this button moves an archived thread from the archive back to "
@"the inbox")
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull tappedIndexPath) {
[self archiveIndexPath:tappedIndexPath];
}];
}
} else { return @[ deleteAction, archiveAction ];
archiveAction = [UITableViewRowAction }
rowActionWithStyle:UITableViewRowActionStyleNormal case HomeViewControllerSectionArchiveButton: {
title:NSLocalizedString(@"UNARCHIVE_ACTION", return @[];
@"Pressing this button moves an archived thread from the archive back to the inbox") }
handler:^(UITableViewRowAction *_Nonnull action, NSIndexPath *_Nonnull tappedIndexPath) {
[self archiveIndexPath:tappedIndexPath];
}];
} }
return @[ deleteAction, archiveAction ];
} }
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if ([self isIndexPathForArchivedConversations:indexPath]) { HomeViewControllerSection section = (HomeViewControllerSection)indexPath.section;
return NO; switch (section) {
case HomeViewControllerSectionReminders: {
return NO;
}
case HomeViewControllerSectionConversations: {
return YES;
}
case HomeViewControllerSectionArchiveButton: {
return NO;
}
} }
return YES;
} }
#pragma mark - UISearchBarDelegate #pragma mark - UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{ {
[self.tableView setContentOffset:CGPointZero animated:NO]; [self scrollSearchBarToTopAnimated:NO];
[self updateSearchResultsVisibility]; [self updateSearchResultsVisibility];
@ -996,13 +1037,19 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
self.searchResultsController.view.hidden = !isSearching; self.searchResultsController.view.hidden = !isSearching;
if (isSearching) { if (isSearching) {
[self.tableView setContentOffset:CGPointZero animated:NO]; [self scrollSearchBarToTopAnimated:NO];
self.tableView.scrollEnabled = NO; self.tableView.scrollEnabled = NO;
} else { } else {
self.tableView.scrollEnabled = YES; self.tableView.scrollEnabled = YES;
} }
} }
- (void)scrollSearchBarToTopAnimated:(BOOL)isAnimated
{
CGFloat topInset = self.topLayoutGuide.length;
[self.tableView setContentOffset:CGPointMake(0, -topInset) animated:isAnimated];
}
#pragma mark - UIScrollViewDelegate #pragma mark - UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
@ -1023,6 +1070,11 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
- (void)tableViewCellTappedDelete:(NSIndexPath *)indexPath - (void)tableViewCellTappedDelete:(NSIndexPath *)indexPath
{ {
if (indexPath.section != HomeViewControllerSectionConversations) {
OWSFail(@"%@ failure: unexpected section: %lu", self.logTag, (unsigned long)indexPath.section);
return;
}
TSThread *thread = [self threadForIndexPath:indexPath]; TSThread *thread = [self threadForIndexPath:indexPath];
if ([thread isKindOfClass:[TSGroupThread class]]) { if ([thread isKindOfClass:[TSGroupThread class]]) {
@ -1074,6 +1126,11 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
- (void)archiveIndexPath:(NSIndexPath *)indexPath - (void)archiveIndexPath:(NSIndexPath *)indexPath
{ {
if (indexPath.section != HomeViewControllerSectionConversations) {
OWSFail(@"%@ failure: unexpected section: %lu", self.logTag, (unsigned long)indexPath.section);
return;
}
TSThread *thread = [self threadForIndexPath:indexPath]; TSThread *thread = [self threadForIndexPath:indexPath];
[self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
@ -1094,15 +1151,22 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
DDLogInfo(@"%@ %s %ld %ld", self.logTag, __PRETTY_FUNCTION__, (long)indexPath.row, (long)indexPath.section); DDLogInfo(@"%@ %s %ld %ld", self.logTag, __PRETTY_FUNCTION__, (long)indexPath.row, (long)indexPath.section);
[self.searchBar resignFirstResponder]; [self.searchBar resignFirstResponder];
HomeViewControllerSection section = (HomeViewControllerSection)indexPath.section;
if ([self isIndexPathForArchivedConversations:indexPath]) { switch (section) {
[self showArchivedConversations]; case HomeViewControllerSectionReminders: {
return; break;
}
case HomeViewControllerSectionConversations: {
TSThread *thread = [self threadForIndexPath:indexPath];
[self presentThread:thread action:ConversationViewActionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
break;
}
case HomeViewControllerSectionArchiveButton: {
[self showArchivedConversations];
break;
}
} }
TSThread *thread = [self threadForIndexPath:indexPath];
[self presentThread:thread action:ConversationViewActionNone];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
} }
- (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action - (void)presentThread:(TSThread *)thread action:(ConversationViewAction)action
@ -1237,8 +1301,9 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations
{ {
OWSAssertIsOnMainThread(); OWSAssertIsOnMainThread();
self.threadMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.currentGrouping ] self.threadMappings = [[YapDatabaseViewMappings alloc]
view:TSThreadDatabaseViewExtensionName]; initWithGroups:@[ kReminderViewPseudoGroup, self.currentGrouping, kArchiveButtonPseudoGroup ]
view:TSThreadDatabaseViewExtensionName];
[self.threadMappings setIsReversed:YES forGroup:self.currentGrouping]; [self.threadMappings setIsReversed:YES forGroup:self.currentGrouping];
[self resetMappings]; [self resetMappings];

@ -71,10 +71,6 @@ class MenuActionsViewController: UIViewController, MenuActionSheetDelegate {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapBackground)) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapBackground))
self.view.addGestureRecognizer(tapGesture) self.view.addGestureRecognizer(tapGesture)
let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeBackground))
swipeGesture.direction = .down
self.view.addGestureRecognizer(swipeGesture)
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
@ -249,11 +245,6 @@ class MenuActionsViewController: UIViewController, MenuActionSheetDelegate {
animateDismiss(action: nil) animateDismiss(action: nil)
} }
@objc
func didSwipeBackground(gesture: UISwipeGestureRecognizer) {
animateDismiss(action: nil)
}
// MARK: MenuActionSheetDelegate // MARK: MenuActionSheetDelegate
func actionSheet(_ actionSheet: MenuActionSheetView, didSelectAction action: MenuAction) { func actionSheet(_ actionSheet: MenuActionSheetView, didSelectAction action: MenuAction) {
@ -269,6 +260,10 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate {
private let actionStackView: UIStackView private let actionStackView: UIStackView
private var actions: [MenuAction] private var actions: [MenuAction]
private var actionViews: [MenuActionView]
private var hapticFeedback: HapticFeedback
private var hasEverHighlightedAction = false
weak var delegate: MenuActionSheetDelegate? weak var delegate: MenuActionSheetDelegate?
override var bounds: CGRect { override var bounds: CGRect {
@ -288,29 +283,58 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate {
actionStackView.spacing = CGHairlineWidth() actionStackView.spacing = CGHairlineWidth()
actions = [] actions = []
actionViews = []
hapticFeedback = HapticFeedback()
super.init(frame: frame) super.init(frame: frame)
backgroundColor = UIColor.ows_light10 backgroundColor = UIColor.ows_light10
addSubview(actionStackView) addSubview(actionStackView)
actionStackView.ows_autoPinToSuperviewEdges() actionStackView.autoPinEdgesToSuperviewEdges()
self.clipsToBounds = true self.clipsToBounds = true
// Prevent panning from percolating to the superview, which would let touchGesture = UILongPressGestureRecognizer(target: self, action: #selector(didTouch(gesture:)))
// cause us to dismiss touchGesture.minimumPressDuration = 0.0
let panGestureSink = UIPanGestureRecognizer(target: nil, action: nil) touchGesture.allowableMovement = CGFloat.greatestFiniteMagnitude
self.addGestureRecognizer(panGestureSink) self.addGestureRecognizer(touchGesture)
} }
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
fatalError("not implemented") fatalError("not implemented")
} }
@objc
public func didTouch(gesture: UIGestureRecognizer) {
switch gesture.state {
case .possible:
break
case .began:
let location = gesture.location(in: self)
highlightActionView(location: location, fromView: self)
case .changed:
let location = gesture.location(in: self)
highlightActionView(location: location, fromView: self)
case .ended:
Logger.debug("\(logTag) in \(#function) ended")
let location = gesture.location(in: self)
selectActionView(location: location, fromView: self)
case .cancelled:
Logger.debug("\(logTag) in \(#function) canceled")
unhighlightAllActionViews()
case .failed:
Logger.debug("\(logTag) in \(#function) failed")
unhighlightAllActionViews()
}
}
public func addAction(_ action: MenuAction) { public func addAction(_ action: MenuAction) {
actions.append(action)
let actionView = MenuActionView(action: action) let actionView = MenuActionView(action: action)
actionView.delegate = self actionView.delegate = self
actions.append(action) actionViews.append(actionView)
self.actionStackView.addArrangedSubview(actionView) self.actionStackView.addArrangedSubview(actionView)
} }
@ -329,6 +353,47 @@ class MenuActionSheetView: UIView, MenuActionViewDelegate {
mask.path = path.cgPath mask.path = path.cgPath
self.layer.mask = mask self.layer.mask = mask
} }
private func unhighlightAllActionViews() {
for actionView in actionViews {
actionView.isHighlighted = false
}
}
private func actionView(touchedBy touchPoint: CGPoint, fromView: UIView) -> MenuActionView? {
for actionView in actionViews {
let convertedPoint = actionView.convert(touchPoint, from: fromView)
if actionView.point(inside: convertedPoint, with: nil) {
return actionView
}
}
return nil
}
private func highlightActionView(location: CGPoint, fromView: UIView) {
guard let touchedView = actionView(touchedBy: location, fromView: fromView) else {
unhighlightAllActionViews()
return
}
if hasEverHighlightedAction, !touchedView.isHighlighted {
self.hapticFeedback.selectionChanged()
}
touchedView.isHighlighted = true
hasEverHighlightedAction = true
self.actionViews.filter { $0 != touchedView }.forEach { $0.isHighlighted = false }
}
private func selectActionView(location: CGPoint, fromView: UIView) {
guard let selectedView: MenuActionView = actionView(touchedBy: location, fromView: fromView) else {
unhighlightAllActionViews()
return
}
selectedView.isHighlighted = true
self.actionViews.filter { $0 != selectedView }.forEach { $0.isHighlighted = false }
delegate?.actionSheet(self, didSelectAction: selectedView.action)
}
} }
protocol MenuActionViewDelegate: class { protocol MenuActionViewDelegate: class {
@ -337,7 +402,7 @@ protocol MenuActionViewDelegate: class {
class MenuActionView: UIButton { class MenuActionView: UIButton {
public weak var delegate: MenuActionViewDelegate? public weak var delegate: MenuActionViewDelegate?
private let action: MenuAction public let action: MenuAction
required init(action: MenuAction) { required init(action: MenuAction) {
self.action = action self.action = action
@ -378,10 +443,10 @@ class MenuActionView: UIButton {
contentRow.isUserInteractionEnabled = false contentRow.isUserInteractionEnabled = false
self.addSubview(contentRow) self.addSubview(contentRow)
contentRow.ows_autoPinToSuperviewMargins() contentRow.autoPinEdgesToSuperviewMargins()
contentRow.autoSetDimension(.height, toSize: 56, relation: .greaterThanOrEqual) contentRow.autoSetDimension(.height, toSize: 56, relation: .greaterThanOrEqual)
self.addTarget(self, action: #selector(didPress(sender:)), for: .touchUpInside) self.isUserInteractionEnabled = false
} }
override var isHighlighted: Bool { override var isHighlighted: Bool {

@ -43,7 +43,9 @@ NS_ASSUME_NONNULL_BEGIN
// RTCMTLVideoView requires the MTKView class, available only in iOS9+ // RTCMTLVideoView requires the MTKView class, available only in iOS9+
// So check that it exists before proceeding. // So check that it exists before proceeding.
if ([MTKView class]) { if ([MTKView class]) {
_videoRenderer = [[RTCMTLVideoView alloc] initWithFrame:CGRectZero]; RTCMTLVideoView *rtcMetalView = [[RTCMTLVideoView alloc] initWithFrame:CGRectZero];
rtcMetalView.videoContentMode = UIViewContentModeScaleAspectFill;
_videoRenderer = rtcMetalView;
[self addSubview:_videoRenderer]; [self addSubview:_videoRenderer];
[_videoRenderer autoPinEdgesToSuperviewEdges]; [_videoRenderer autoPinEdgesToSuperviewEdges];
// HACK: Although RTCMTLVideo view is positioned to the top edge of the screen // HACK: Although RTCMTLVideo view is positioned to the top edge of the screen

@ -2121,7 +2121,7 @@
"SHARE_EXTENSION_VIEW_TITLE" = "Share to Signal"; "SHARE_EXTENSION_VIEW_TITLE" = "Share to Signal";
/* Action sheet item */ /* Action sheet item */
"SHOW_SAFETY_NUMBER_ACTION" = "Show Safety Number"; "SHOW_SAFETY_NUMBER_ACTION" = "Vis sikkerhedsnummer";
/* notification action */ /* notification action */
"SHOW_THREAD_BUTTON_TITLE" = "Vis Samtale"; "SHOW_THREAD_BUTTON_TITLE" = "Vis Samtale";

@ -402,7 +402,7 @@
"CONFIRM_LEAVE_GROUP_TITLE" = "Wirklich verlassen?"; "CONFIRM_LEAVE_GROUP_TITLE" = "Wirklich verlassen?";
/* Button text */ /* Button text */
"CONFIRM_LINK_NEW_DEVICE_ACTION" = "Neues Gerät verknüpfen"; "CONFIRM_LINK_NEW_DEVICE_ACTION" = "Neues Gerät koppeln";
/* Action sheet body presented when a user's SN has recently changed. Embeds {{contact's name or phone number}} */ /* Action sheet body presented when a user's SN has recently changed. Embeds {{contact's name or phone number}} */
"CONFIRM_SENDING_TO_CHANGED_IDENTITY_BODY_FORMAT" = "%@hat Signal vielleicht erneut installiert oder das Gerät gewechselt. Verifiziert eure gemeinsame Sicherheitsnummer zur Sicherstellung der Privatsphäre."; "CONFIRM_SENDING_TO_CHANGED_IDENTITY_BODY_FORMAT" = "%@hat Signal vielleicht erneut installiert oder das Gerät gewechselt. Verifiziert eure gemeinsame Sicherheitsnummer zur Sicherstellung der Privatsphäre.";
@ -676,7 +676,7 @@
"DEVICE_LAST_ACTIVE_AT_LABEL" = "Zuletzt aktiv: %@"; "DEVICE_LAST_ACTIVE_AT_LABEL" = "Zuletzt aktiv: %@";
/* {{Short Date}} when device was linked. */ /* {{Short Date}} when device was linked. */
"DEVICE_LINKED_AT_LABEL" = "Verknüpft: %@"; "DEVICE_LINKED_AT_LABEL" = "Gekoppelt: %@";
/* Alert title that can occur when viewing device manager. */ /* Alert title that can occur when viewing device manager. */
"DEVICE_LIST_UPDATE_FAILED_TITLE" = "Aktualisieren der Geräteliste gescheitert."; "DEVICE_LIST_UPDATE_FAILED_TITLE" = "Aktualisieren der Geräteliste gescheitert.";
@ -1090,34 +1090,34 @@
"LEAVE_GROUP_ACTION" = "Gruppe verlassen"; "LEAVE_GROUP_ACTION" = "Gruppe verlassen";
/* report an invalid linking code */ /* report an invalid linking code */
"LINK_DEVICE_INVALID_CODE_BODY" = "Dieser QR-Code ist ungültig. Stelle bitte sicher, dass du den QR-Code einscannst, der auf dem zu verknüpfenden Gerät angezeigt wird."; "LINK_DEVICE_INVALID_CODE_BODY" = "Dieser QR-Code ist ungültig. Stelle bitte sicher, dass du den QR-Code einscannst, der auf dem zu koppelnden Gerät angezeigt wird.";
/* report an invalid linking code */ /* report an invalid linking code */
"LINK_DEVICE_INVALID_CODE_TITLE" = "Verknüpfen des Geräts gescheitert"; "LINK_DEVICE_INVALID_CODE_TITLE" = "Koppeln des Geräts gescheitert";
/* confirm the users intent to link a new device */ /* confirm the users intent to link a new device */
"LINK_DEVICE_PERMISSION_ALERT_BODY" = "Dieses Gerät wird in der Lage sein, deine Gruppen und Kontakte zu sehen, alle deine Nachrichten zu lesen und Nachrichten in deinem Namen zu versenden."; "LINK_DEVICE_PERMISSION_ALERT_BODY" = "Dieses Gerät wird in der Lage sein, deine Gruppen und Kontakte zu sehen, alle deine Nachrichten zu lesen und Nachrichten in deinem Namen zu versenden.";
/* confirm the users intent to link a new device */ /* confirm the users intent to link a new device */
"LINK_DEVICE_PERMISSION_ALERT_TITLE" = "Gerät verknüpfen?"; "LINK_DEVICE_PERMISSION_ALERT_TITLE" = "Gerät koppeln?";
/* attempt another linking */ /* attempt another linking */
"LINK_DEVICE_RESTART" = "Erneut versuchen"; "LINK_DEVICE_RESTART" = "Erneut versuchen";
/* QR Scanning screen instructions, placed alongside a camera view for scanning QR Codes */ /* QR Scanning screen instructions, placed alongside a camera view for scanning QR Codes */
"LINK_DEVICE_SCANNING_INSTRUCTIONS" = "Scanne zum Verknüpfen den auf dem Gerät angezeigten QR-Code ein."; "LINK_DEVICE_SCANNING_INSTRUCTIONS" = "Scanne zum Koppeln den auf dem Gerät angezeigten QR-Code ein.";
/* Subheading for 'Link New Device' navigation */ /* Subheading for 'Link New Device' navigation */
"LINK_NEW_DEVICE_SUBTITLE" = "QR-Code einscannen"; "LINK_NEW_DEVICE_SUBTITLE" = "QR-Code einscannen";
/* Navigation title when scanning QR code to add new device. */ /* Navigation title when scanning QR code to add new device. */
"LINK_NEW_DEVICE_TITLE" = "Neues Gerät verknüpfen"; "LINK_NEW_DEVICE_TITLE" = "Neues Gerät koppeln";
/* Menu item and navbar title for the device manager */ /* Menu item and navbar title for the device manager */
"LINKED_DEVICES_TITLE" = "Verknüpfte Geräte"; "LINKED_DEVICES_TITLE" = "Gekoppelte Geräte";
/* Alert Title */ /* Alert Title */
"LINKING_DEVICE_FAILED_TITLE" = "Verknüpfen des Geräts gescheitert"; "LINKING_DEVICE_FAILED_TITLE" = "Gerätekopplung gescheitert";
/* table cell label in conversation settings */ /* table cell label in conversation settings */
"LIST_GROUP_MEMBERS_ACTION" = "Gruppenmitglieder"; "LIST_GROUP_MEMBERS_ACTION" = "Gruppenmitglieder";
@ -2208,16 +2208,16 @@
"UNKNOWN_VALUE" = "Unbekannt"; "UNKNOWN_VALUE" = "Unbekannt";
/* button title for unlinking a device */ /* button title for unlinking a device */
"UNLINK_ACTION" = "Entfernen"; "UNLINK_ACTION" = "Entkoppeln";
/* Alert message to confirm unlinking a device */ /* Alert message to confirm unlinking a device */
"UNLINK_CONFIRMATION_ALERT_BODY" = "Nach Entfernen dieses Geräts wird es keine weiteren Nachrichten senden oder empfangen können."; "UNLINK_CONFIRMATION_ALERT_BODY" = "Nach Entkoppeln dieses Geräts wird es keine weiteren Nachrichten senden oder empfangen können.";
/* Alert title for confirming device deletion */ /* Alert title for confirming device deletion */
"UNLINK_CONFIRMATION_ALERT_TITLE" = "»%@« entfernen?"; "UNLINK_CONFIRMATION_ALERT_TITLE" = "»%@« entkoppeln?";
/* Alert title when unlinking device fails */ /* Alert title when unlinking device fails */
"UNLINKING_FAILED_ALERT_TITLE" = "Die Verknüpfung für dein Gerät konnte nicht entfernt werden."; "UNLINKING_FAILED_ALERT_TITLE" = "Signal konnte dein Gerät nicht entkoppeln.";
/* Label text in device manager for a device with no name */ /* Label text in device manager for a device with no name */
"UNNAMED_DEVICE" = "Unbenanntes Gerät"; "UNNAMED_DEVICE" = "Unbenanntes Gerät";

@ -1431,7 +1431,7 @@
"OPEN_SETTINGS_BUTTON" = "Ajustes"; "OPEN_SETTINGS_BUTTON" = "Ajustes";
/* Info Message when {{other user}} disables or doesn't support disappearing messages */ /* Info Message when {{other user}} disables or doesn't support disappearing messages */
"OTHER_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "%@ ha desactivado la caducidad de mensajes."; "OTHER_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "%@ ha desactivado los mensajes con caducidad.";
/* Info Message when {{other user}} updates message expiration to {{time amount}}, see the *_TIME_AMOUNT strings for context. */ /* Info Message when {{other user}} updates message expiration to {{time amount}}, see the *_TIME_AMOUNT strings for context. */
"OTHER_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION" = "%@ ha fijado la caducidad de mensajes a %@."; "OTHER_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION" = "%@ ha fijado la caducidad de mensajes a %@.";
@ -2343,7 +2343,7 @@
"WAITING_TO_COMPLETE_DEVICE_LINK_TEXT" = "Completa la configuración en la aplicación de escritorio."; "WAITING_TO_COMPLETE_DEVICE_LINK_TEXT" = "Completa la configuración en la aplicación de escritorio.";
/* Info Message when you disable disappearing messages */ /* Info Message when you disable disappearing messages */
"YOU_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "Has desactivado la caducidad de mensajes."; "YOU_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "Has desactivado los mensajes con caducidad.";
/* Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context. */ /* Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context. */
"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION" = "Has fijado la caducidad de mensajes a %@."; "YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION" = "Has fijado la caducidad de mensajes a %@.";

@ -609,10 +609,10 @@
"DATABASE_VIEW_OVERLAY_TITLE" = "Mengoptimalkan Database"; "DATABASE_VIEW_OVERLAY_TITLE" = "Mengoptimalkan Database";
/* Format string for a relative time, expressed as a certain number of hours in the past. Embeds {{The number of hours}}. */ /* Format string for a relative time, expressed as a certain number of hours in the past. Embeds {{The number of hours}}. */
"DATE_HOURS_AGO_FORMAT" = "%@ jam lalu"; "DATE_HOURS_AGO_FORMAT" = "%@ Jam Lalu";
/* Format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}. */ /* Format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}. */
"DATE_MINUTES_AGO_FORMAT" = "%@ Menit lalu"; "DATE_MINUTES_AGO_FORMAT" = "%@ Menit Lalu";
/* The present; the current time. */ /* The present; the current time. */
"DATE_NOW" = "Sekarang"; "DATE_NOW" = "Sekarang";
@ -868,7 +868,7 @@
"ERROR_MESSAGE_INVALID_KEY_EXCEPTION" = "Kunci penerima tidak cocok"; "ERROR_MESSAGE_INVALID_KEY_EXCEPTION" = "Kunci penerima tidak cocok";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"ERROR_MESSAGE_INVALID_MESSAGE" = "Pesan diterima tidak tersinkronisasi"; "ERROR_MESSAGE_INVALID_MESSAGE" = "Pesan yang diterima tidak sinkron.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"ERROR_MESSAGE_INVALID_VERSION" = "Menerima pesan yang tidak cocok dengan versi ini"; "ERROR_MESSAGE_INVALID_VERSION" = "Menerima pesan yang tidak cocok dengan versi ini";
@ -886,7 +886,7 @@
"ERROR_MESSAGE_UNKNOWN_ERROR" = "Sebuah kegagagalan tak dikenal muncul."; "ERROR_MESSAGE_UNKNOWN_ERROR" = "Sebuah kegagagalan tak dikenal muncul.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"ERROR_MESSAGE_WRONG_TRUSTED_IDENTITY_KEY" = "Nomor aman diubah"; "ERROR_MESSAGE_WRONG_TRUSTED_IDENTITY_KEY" = "Nomor keamanan diubah";
/* Format string for 'unregistered user' error. Embeds {{the unregistered user's name or signal id}}. */ /* Format string for 'unregistered user' error. Embeds {{the unregistered user's name or signal id}}. */
"ERROR_UNREGISTERED_USER_FORMAT" = "Pengguna tidak terdaftar: %@"; "ERROR_UNREGISTERED_USER_FORMAT" = "Pengguna tidak terdaftar: %@";
@ -1494,7 +1494,7 @@
"PLAY_BUTTON_ACCESSABILITY_LABEL" = "Mainkan Media"; "PLAY_BUTTON_ACCESSABILITY_LABEL" = "Mainkan Media";
/* Label indicating that the user is not verified. Embeds {{the user's name or phone number}}. */ /* Label indicating that the user is not verified. Embeds {{the user's name or phone number}}. */
"PRIVACY_IDENTITY_IS_NOT_VERIFIED_FORMAT" = "Anda tidak menandai %@telah terverifikasi."; "PRIVACY_IDENTITY_IS_NOT_VERIFIED_FORMAT" = "Anda belum menandai %@ telah terverifikasi.";
/* Badge indicating that the user is verified. */ /* Badge indicating that the user is verified. */
"PRIVACY_IDENTITY_IS_VERIFIED_BADGE" = "Terverifikasi"; "PRIVACY_IDENTITY_IS_VERIFIED_BADGE" = "Terverifikasi";
@ -2121,7 +2121,7 @@
"SHARE_EXTENSION_VIEW_TITLE" = "Bagikan ke Signal"; "SHARE_EXTENSION_VIEW_TITLE" = "Bagikan ke Signal";
/* Action sheet item */ /* Action sheet item */
"SHOW_SAFETY_NUMBER_ACTION" = "Tunjukkan nomor pengamanan"; "SHOW_SAFETY_NUMBER_ACTION" = "Tunjukkan nomor keamanan";
/* notification action */ /* notification action */
"SHOW_THREAD_BUTTON_TITLE" = "Tunjukkan pembicaraan"; "SHOW_THREAD_BUTTON_TITLE" = "Tunjukkan pembicaraan";

@ -12,7 +12,7 @@
/* Label for 'send message' button in contact view. /* Label for 'send message' button in contact view.
Label for button that lets you send a message to a contact. */ Label for button that lets you send a message to a contact. */
"ACTION_SEND_MESSAGE" = "Manda messaggio"; "ACTION_SEND_MESSAGE" = "Invia messaggio";
/* Label for 'share contact' button. */ /* Label for 'share contact' button. */
"ACTION_SHARE_CONTACT" = "Condivi contatto"; "ACTION_SHARE_CONTACT" = "Condivi contatto";
@ -168,7 +168,7 @@
"ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_TITLE" = "Documento non supportato"; "ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_TITLE" = "Documento non supportato";
/* Short text label for a voice message attachment, used for thread preview and on the lock screen */ /* Short text label for a voice message attachment, used for thread preview and on the lock screen */
"ATTACHMENT_TYPE_VOICE_MESSAGE" = "Messaggio Vocale"; "ATTACHMENT_TYPE_VOICE_MESSAGE" = "Messaggio vocale";
/* action sheet button title to enable built in speaker during a call */ /* action sheet button title to enable built in speaker during a call */
"AUDIO_ROUTE_BUILT_IN_SPEAKER" = "Vivavoce"; "AUDIO_ROUTE_BUILT_IN_SPEAKER" = "Vivavoce";
@ -742,7 +742,7 @@
"EDIT_TXT" = "Modifica"; "EDIT_TXT" = "Modifica";
/* body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to the Signal home page}} */ /* body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to the Signal home page}} */
"EMAIL_INVITE_BODY" = "Ehi,\n\nUltimamente sto usando Signal per mantenere private le conversazioni sul mio iPhone. Vorrei che anche te la installassi, così potremo essere sicuri che saremo gli unici a poter leggere i nostri messaggi e ad ascoltare le nostre chiamate.\n\nSignal è disponibile per gli iPhone e per Android. Scaricalo qui: %@\n\nSignal funziona come la tua solita app di messaggistica. Possiamo mandarci immagini, video, fare chiamate e creare chat di gruppo. Ma la ciliegina sulla torta è che nessuno potrà vedere né sentire nulla di tutto ciò, nemmeno chi sta dietro a Signal!\n\nPuoi scoprire di più su Open Whisper Systems, i creatori di Signal, qui: %@"; "EMAIL_INVITE_BODY" = "Ehi,\n\nUltimamente sto usando Signal per mantenere private le conversazioni sul mio iPhone. Vorrei che anche tu la installassi, così potremo essere sicuri di essere gli unici a poter leggere i nostri messaggi e ad ascoltare le nostre chiamate.\n\nSignal è disponibile per iPhone e Android. Scaricalo qui: %@\n\nSignal funziona come la tua solita app di messaggistica. Possiamo mandarci immagini, video, fare chiamate e creare chat di gruppo. Ma la ciliegina sulla torta è che nessuno potrà vedere né sentire nulla di tutto ciò, nemmeno chi produce Signal!\n\nPuoi scoprire di più su Open Whisper Systems, i creatori di Signal, qui: %@";
/* subject of email sent to contacts when inviting to install Signal */ /* subject of email sent to contacts when inviting to install Signal */
"EMAIL_INVITE_SUBJECT" = "Passiamo a Signal"; "EMAIL_INVITE_SUBJECT" = "Passiamo a Signal";
@ -754,7 +754,7 @@
"EMPTY_ARCHIVE_FIRST_TITLE" = "Inizia la tua prima conversazione su Signal!"; "EMPTY_ARCHIVE_FIRST_TITLE" = "Inizia la tua prima conversazione su Signal!";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"EMPTY_ARCHIVE_TEXT" = "Puoi archiviare conversazioni inattive dalla lista Chat per consultarle successivamente."; "EMPTY_ARCHIVE_TEXT" = "Puoi archiviare conversazioni inattive dalla lista chat per consultarle successivamente.";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"EMPTY_ARCHIVE_TITLE" = "Pulisci le tue conversazioni"; "EMPTY_ARCHIVE_TITLE" = "Pulisci le tue conversazioni";
@ -781,10 +781,10 @@
"ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Conferma il tuo PIN"; "ENABLE_2FA_VIEW_CONFIRM_PIN_INSTRUCTIONS" = "Conferma il tuo PIN";
/* Error indicating that attempt to disable 'two-factor auth' failed. */ /* Error indicating that attempt to disable 'two-factor auth' failed. */
"ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA" = "Impossibile disattivare il Blocco Registrazione."; "ENABLE_2FA_VIEW_COULD_NOT_DISABLE_2FA" = "Impossibile disattivare il blocco registrazione.";
/* Error indicating that attempt to enable 'two-factor auth' failed. */ /* Error indicating that attempt to enable 'two-factor auth' failed. */
"ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA" = "Impossibile abilitare il Blocco Registrazione."; "ENABLE_2FA_VIEW_COULD_NOT_ENABLE_2FA" = "Impossibile abilitare il blocco registrazione.";
/* Label for the 'enable two-factor auth' item in the settings view */ /* Label for the 'enable two-factor auth' item in the settings view */
"ENABLE_2FA_VIEW_DISABLE_2FA" = "Disabilita"; "ENABLE_2FA_VIEW_DISABLE_2FA" = "Disabilita";
@ -799,13 +799,13 @@
"ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH" = "Il PIN non corrisponde. "; "ENABLE_2FA_VIEW_PIN_DOES_NOT_MATCH" = "Il PIN non corrisponde. ";
/* Indicates that user should select a 'two factor auth pin'. */ /* Indicates that user should select a 'two factor auth pin'. */
"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Inserisci un PIN per il Blocco Registrazione. Questo PIN ti verrà richiesto la prossima volta che verrà effettuata una registrazione con questo numero di telefono."; "ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Inserisci un PIN per il blocco registrazione. Questo PIN ti verrà richiesto la prossima volta che verrà effettuata una registrazione con questo numero di telefono.";
/* Indicates that user has 'two factor auth pin' disabled. */ /* Indicates that user has 'two factor auth pin' disabled. */
"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "Per aumentare la sicurezza, attiva il PIN di Blocco Registrazione che diventerà necessario per registrare nuovamente questo numero di telefono con Signal."; "ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "Per aumentare la sicurezza, attiva il PIN di blocco registrazione che diventerà necessario per registrare nuovamente questo numero di telefono con Signal.";
/* Indicates that user has 'two factor auth pin' enabled. */ /* Indicates that user has 'two factor auth pin' enabled. */
"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "È attivo il Blocco Registrazione. Dovrai inserire il tuo PIN quando registrerai nuovamente il tuo numero di telefono con Signal."; "ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "È attivo il blocco registrazione. Dovrai inserire il tuo PIN quando registrerai nuovamente il tuo numero di telefono con Signal.";
/* Title for the 'enable two factor auth PIN' views. */ /* Title for the 'enable two factor auth PIN' views. */
"ENABLE_2FA_VIEW_TITLE" = "Blocco registrazione"; "ENABLE_2FA_VIEW_TITLE" = "Blocco registrazione";
@ -931,7 +931,7 @@
"GIF_PICKER_FAILURE_ALERT_TITLE" = "Impossibile recuperare la GIF selezionata"; "GIF_PICKER_FAILURE_ALERT_TITLE" = "Impossibile recuperare la GIF selezionata";
/* Alert message shown when user tries to search for GIFs without entering any search terms. */ /* Alert message shown when user tries to search for GIFs without entering any search terms. */
"GIF_PICKER_VIEW_MISSING_QUERY" = "Inserite la vostra la ricerca."; "GIF_PICKER_VIEW_MISSING_QUERY" = "Inserisci la tua ricerca.";
/* Title for the 'GIF picker' dialog. */ /* Title for the 'GIF picker' dialog. */
"GIF_PICKER_VIEW_TITLE" = "Ricerca GIF"; "GIF_PICKER_VIEW_TITLE" = "Ricerca GIF";
@ -1353,7 +1353,7 @@
"NETWORK_STATUS_HEADER" = "Stato della rete"; "NETWORK_STATUS_HEADER" = "Stato della rete";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"NETWORK_STATUS_OFFLINE" = "Offline"; "NETWORK_STATUS_OFFLINE" = "Sconnesso";
/* A label the cell that lets you add a new member to a group. */ /* A label the cell that lets you add a new member to a group. */
"NEW_CONVERSATION_FIND_BY_PHONE_NUMBER" = "Cerca per numero"; "NEW_CONVERSATION_FIND_BY_PHONE_NUMBER" = "Cerca per numero";
@ -2202,7 +2202,7 @@
"UNKNOWN_CONTACT_BLOCK_OFFER" = "Utente non presente nei contatti. Vuoi bloccare questo utente?"; "UNKNOWN_CONTACT_BLOCK_OFFER" = "Utente non presente nei contatti. Vuoi bloccare questo utente?";
/* Displayed if for some reason we can't determine a contacts phone number *or* name */ /* Displayed if for some reason we can't determine a contacts phone number *or* name */
"UNKNOWN_CONTACT_NAME" = "Contatto Sconosciuto"; "UNKNOWN_CONTACT_NAME" = "Contatto sconosciuto";
/* Indicates an unknown or unrecognizable value. */ /* Indicates an unknown or unrecognizable value. */
"UNKNOWN_VALUE" = "Sconosciuto"; "UNKNOWN_VALUE" = "Sconosciuto";
@ -2214,13 +2214,13 @@
"UNLINK_CONFIRMATION_ALERT_BODY" = "Dissociando questo dispositivo, non sarà più possibile inviare o ricevere messaggi."; "UNLINK_CONFIRMATION_ALERT_BODY" = "Dissociando questo dispositivo, non sarà più possibile inviare o ricevere messaggi.";
/* Alert title for confirming device deletion */ /* Alert title for confirming device deletion */
"UNLINK_CONFIRMATION_ALERT_TITLE" = "Dissocia \"%@\" ?"; "UNLINK_CONFIRMATION_ALERT_TITLE" = "Dissociare \"%@\"?";
/* Alert title when unlinking device fails */ /* Alert title when unlinking device fails */
"UNLINKING_FAILED_ALERT_TITLE" = "Signal non è riuscito a dissociare il tuo dispositivo."; "UNLINKING_FAILED_ALERT_TITLE" = "Signal non è riuscito a dissociare il tuo dispositivo.";
/* Label text in device manager for a device with no name */ /* Label text in device manager for a device with no name */
"UNNAMED_DEVICE" = "Dispositivo Senza Nome"; "UNNAMED_DEVICE" = "Dispositivo senza nome";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"UNREGISTER_SIGNAL_FAIL" = "Cancellazione da Signal fallita."; "UNREGISTER_SIGNAL_FAIL" = "Cancellazione da Signal fallita.";
@ -2274,7 +2274,7 @@
"UPGRADE_EXPERIENCE_INTRODUCING_READ_RECEIPTS_TITLE" = "Introduzione delle ricevute di lettura"; "UPGRADE_EXPERIENCE_INTRODUCING_READ_RECEIPTS_TITLE" = "Introduzione delle ricevute di lettura";
/* Description of video calling to upgrading (existing) users */ /* Description of video calling to upgrading (existing) users */
"UPGRADE_EXPERIENCE_VIDEO_DESCRIPTION" = "Signal ora supporta le chiamate video sicure. Inizia la chiamata come di consueto, tocca il pulsante della telecamere e fai ciao."; "UPGRADE_EXPERIENCE_VIDEO_DESCRIPTION" = "Signal ora supporta le videochiamate sicure. Inizia la chiamata come di consueto, tocca il pulsante della fotocamera e fai ciao.";
/* Header for upgrade experience */ /* Header for upgrade experience */
"UPGRADE_EXPERIENCE_VIDEO_TITLE" = "Videochiamate sicure!"; "UPGRADE_EXPERIENCE_VIDEO_TITLE" = "Videochiamate sicure!";

@ -742,7 +742,7 @@
"EDIT_TXT" = "แก้ไข"; "EDIT_TXT" = "แก้ไข";
/* body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to the Signal home page}} */ /* body of email sent to contacts when inviting to install Signal. Embeds {{link to install Signal}} and {{link to the Signal home page}} */
"EMAIL_INVITE_BODY" = "สวัสดี\n\nเมื่อไม่นานนี้ ฉันได้ใช้ Signal เพื่อรักษาการสนทนาบนไอโฟนของฉันให้เป็นส่วนตัว ฉันอยากให้คุณติดตั้งเหมือนกัน เพื่อให้เรามั่นใจได้ว่ามีแค่คุณและฉันที่สามารถอ่านข้อความของเราหรือได้ยินเสียงคุยของเรา\n\nSignal ใช้งานได้บนไอโฟนและแอนดรอยด์ โหลดเลยที่นี่: %@\n\nSignal ทำงานเหมือนแอปส่งข้อความที่คุณมีอยู่ เราสามารถส่งรูปและวิดีโอ โทรออก และเริ่มแชตกลุ่ม สิ่งที่ดีที่สุดคือไม่มีใครคนอื่นเห็นสิ่งเหล่านี้ แม้แต่ผู้คนที่สร้าง Signal ก็จะไม่เห็น!\n\nคุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Open Whisper Systems ผู้สร้าง Signal ได้ที่นี่: %@"; "EMAIL_INVITE_BODY" = "สวัสดี\n\nเมื่อไม่นานนี้ ฉันได้ใช้ Signal เพื่อรักษาการสนทนาบน iPhone ของฉันให้เป็นส่วนตัว ฉันอยากให้คุณติดตั้งเหมือนกัน เพื่อให้เรามั่นใจได้ว่ามีแค่คุณและฉันที่สามารถอ่านข้อความของเราหรือได้ยินเสียงคุยของเรา\n\nSignal ใช้งานได้บน iPhone และ Android โหลดเลยที่นี่: %@\n\nSignal ทำงานเหมือนแอปส่งข้อความที่คุณมีอยู่ เราสามารถส่งรูปและวิดีโอ โทรออก และเริ่มแชตกลุ่ม สิ่งที่ดีที่สุดคือไม่มีใครคนอื่นเห็นสิ่งเหล่านี้ แม้แต่ผู้คนที่สร้าง Signal ก็จะไม่เห็น!\n\nคุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Open Whisper Systems ผู้สร้าง Signal ได้ที่นี่: %@";
/* subject of email sent to contacts when inviting to install Signal */ /* subject of email sent to contacts when inviting to install Signal */
"EMAIL_INVITE_SUBJECT" = "เปลี่ยนมาใช้ Signal กันเถอะ"; "EMAIL_INVITE_SUBJECT" = "เปลี่ยนมาใช้ Signal กันเถอะ";
@ -1464,7 +1464,7 @@
"PHONE_NUMBER_TYPE_HOME_FAX" = "แฟกซ์ที่บ้าน"; "PHONE_NUMBER_TYPE_HOME_FAX" = "แฟกซ์ที่บ้าน";
/* Label for 'iPhone' phone numbers. */ /* Label for 'iPhone' phone numbers. */
"PHONE_NUMBER_TYPE_IPHONE" = "ไอโฟน"; "PHONE_NUMBER_TYPE_IPHONE" = "iPhone";
/* Label for 'Main' phone numbers. */ /* Label for 'Main' phone numbers. */
"PHONE_NUMBER_TYPE_MAIN" = "หลัก"; "PHONE_NUMBER_TYPE_MAIN" = "หลัก";
@ -1761,13 +1761,13 @@
"RETRY_BUTTON_TEXT" = "ลองใหม่"; "RETRY_BUTTON_TEXT" = "ลองใหม่";
/* button title to confirm adding a recipient to a group when their safety number has recently changed */ /* button title to confirm adding a recipient to a group when their safety number has recently changed */
"SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION" = "เพิ่มไปที่กลุ่มเสมอ"; "SAFETY_NUMBER_CHANGED_CONFIRM_ADD_TO_GROUP_ACTION" = "ยืนยันที่จะเพิ่มไปที่กลุ่ม";
/* alert button text to confirm placing an outgoing call after the recipients Safety Number has changed. */ /* alert button text to confirm placing an outgoing call after the recipients Safety Number has changed. */
"SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION" = "โทรเสมอ"; "SAFETY_NUMBER_CHANGED_CONFIRM_CALL_ACTION" = "ยืนยันที่จะโทร";
/* button title to confirm sending to a recipient whose safety number recently changed */ /* button title to confirm sending to a recipient whose safety number recently changed */
"SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION" = "ส่งเสมอ"; "SAFETY_NUMBER_CHANGED_CONFIRM_SEND_ACTION" = "ยืนยันที่จะส่ง";
/* Snippet to share {{safety number}} with a friend. sent e.g. via SMS */ /* Snippet to share {{safety number}} with a friend. sent e.g. via SMS */
"SAFETY_NUMBER_SHARE_FORMAT" = "รหัสความปลอดภัย Signal ของเรา:\n%@"; "SAFETY_NUMBER_SHARE_FORMAT" = "รหัสความปลอดภัย Signal ของเรา:\n%@";

@ -249,7 +249,7 @@
"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT" = "%@ engellendi"; "BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT" = "%@ engellendi";
/* The title of the 'user blocked' alert. */ /* The title of the 'user blocked' alert. */
"BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE" = "Kullanıcı Engellenmiş"; "BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE" = "Kullanıcı Engellendi";
/* The message of the 'You can't block yourself' alert. */ /* The message of the 'You can't block yourself' alert. */
"BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_MESSAGE" = "Kendinizi engelleyemezsiniz."; "BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_MESSAGE" = "Kendinizi engelleyemezsiniz.";
@ -324,7 +324,7 @@
"CALL_VIEW_HANGUP_LABEL" = "Aramayı sonlandır"; "CALL_VIEW_HANGUP_LABEL" = "Aramayı sonlandır";
/* Accessibility label for muting the microphone */ /* Accessibility label for muting the microphone */
"CALL_VIEW_MUTE_LABEL" = "Sessiz"; "CALL_VIEW_MUTE_LABEL" = "Sessize al";
/* Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy. */ /* Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy. */
"CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL" = "Eğer ayarlarınızı değiştirirseniz gelen aramaları kilit ekranınızdan yanıtlayabilir ve gelen aramalardaki ismi ve numarayı görebilirsiniz.\n\nDetaylar için gizlilik ayarlarına göz atın."; "CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL" = "Eğer ayarlarınızı değiştirirseniz gelen aramaları kilit ekranınızdan yanıtlayabilir ve gelen aramalardaki ismi ve numarayı görebilirsiniz.\n\nDetaylar için gizlilik ayarlarına göz atın.";
@ -703,7 +703,7 @@
"DOMAIN_FRONTING_COUNTRY_VIEW_SECTION_HEADER" = "Sansür Atlatma Lokasyonu"; "DOMAIN_FRONTING_COUNTRY_VIEW_SECTION_HEADER" = "Sansür Atlatma Lokasyonu";
/* Alert body for when the user has just tried to edit a contacts after declining to give Signal contacts permissions */ /* Alert body for when the user has just tried to edit a contacts after declining to give Signal contacts permissions */
"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY" = "Ayarlar uygulamasından erişim verebilirsiniz"; "EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_BODY" = "Ayarlar uygulamasından erişim verebilirsiniz.";
/* Alert title for when the user has just tried to edit a contacts after declining to give Signal contacts permissions */ /* Alert title for when the user has just tried to edit a contacts after declining to give Signal contacts permissions */
"EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_TITLE" = "Signal Kişi Bilgilerini Düzenlemek İçin Kişi Erişimine İhtiyacı Var"; "EDIT_CONTACT_WITHOUT_CONTACTS_PERMISSION_ALERT_TITLE" = "Signal Kişi Bilgilerini Düzenlemek İçin Kişi Erişimine İhtiyacı Var";
@ -802,10 +802,10 @@
"ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Bir Kayıt Kilidi PIN'i giriniz. Bu telefon numarasıyla Signal'e tekrar kaydolduğunuzda bu PIN kodunu girmeniz istenecektir."; "ENABLE_2FA_VIEW_SELECT_PIN_INSTRUCTIONS" = "Bir Kayıt Kilidi PIN'i giriniz. Bu telefon numarasıyla Signal'e tekrar kaydolduğunuzda bu PIN kodunu girmeniz istenecektir.";
/* Indicates that user has 'two factor auth pin' disabled. */ /* Indicates that user has 'two factor auth pin' disabled. */
"ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "Arttırılmış güvenlik için, bu telefon numarasıyla Signal'e tekrar kaydolduğunuzda sorulmak üzere bir kayıt kilidi PIN'i aktifleştirin."; "ENABLE_2FA_VIEW_STATUS_DISABLED_INSTRUCTIONS" = "Daha fazla güvenlik için, bu telefon numarası Signal'e tekrar kaydedilirken sorulacak olan Kayıt Kilidi PIN'ini etkinleştirin.";
/* Indicates that user has 'two factor auth pin' enabled. */ /* Indicates that user has 'two factor auth pin' enabled. */
"ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "Kayıt Kilidi aktifleştirildi. Bu numarayla Signal'e tekrar kaydolduğunuzda PIN kodunuzu girmeniz gerekecek."; "ENABLE_2FA_VIEW_STATUS_ENABLED_INSTRUCTIONS" = "Kayıt Kilidi etkinleştirildi. Numaranızla Signal'e tekrar kaydolurken PIN kodunuzu girmeniz gerekecektir.";
/* Title for the 'enable two factor auth PIN' views. */ /* Title for the 'enable two factor auth PIN' views. */
"ENABLE_2FA_VIEW_TITLE" = "Kayıt Kilidi"; "ENABLE_2FA_VIEW_TITLE" = "Kayıt Kilidi";
@ -832,7 +832,7 @@
"ERROR_DESCRIPTION_MESSAGE_SEND_FAILED_DUE_TO_FAILED_ATTACHMENT_WRITE" = "Eklenti yazımı başarısız olduğundan dolayı gönderilemedi."; "ERROR_DESCRIPTION_MESSAGE_SEND_FAILED_DUE_TO_FAILED_ATTACHMENT_WRITE" = "Eklenti yazımı başarısız olduğundan dolayı gönderilemedi.";
/* Generic error used whenever Signal can't contact the server */ /* Generic error used whenever Signal can't contact the server */
"ERROR_DESCRIPTION_NO_INTERNET" = "Sinyal internete bağlanamadı. Lütfen başka bir WiFi ağından deneyin veya mobil veri kullanın."; "ERROR_DESCRIPTION_NO_INTERNET" = "Signal İnternet'e bağlanamadı. Lütfen farklı bir WiFi ağından veya mobil veriden tekrar deneyin.";
/* Error indicating that an outgoing message had no valid recipients. */ /* Error indicating that an outgoing message had no valid recipients. */
"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS" = "Mesaj gönderimi geçerli alıcı olmadığından başarısız oldu."; "ERROR_DESCRIPTION_NO_VALID_RECIPIENTS" = "Mesaj gönderimi geçerli alıcı olmadığından başarısız oldu.";
@ -979,7 +979,7 @@
"GROUP_MEMBERS_SECTION_TITLE_MEMBERS" = "Üyeler"; "GROUP_MEMBERS_SECTION_TITLE_MEMBERS" = "Üyeler";
/* Title for the 'no longer verified' section of the 'group members' view. */ /* Title for the 'no longer verified' section of the 'group members' view. */
"GROUP_MEMBERS_SECTION_TITLE_NO_LONGER_VERIFIED" = "Artık Doğrulanmış değil"; "GROUP_MEMBERS_SECTION_TITLE_NO_LONGER_VERIFIED" = "Artık Doğrulanmış Değil";
/* Button label for the 'send message to group member' button */ /* Button label for the 'send message to group member' button */
"GROUP_MEMBERS_SEND_MESSAGE" = "Mesaj Gönder"; "GROUP_MEMBERS_SEND_MESSAGE" = "Mesaj Gönder";
@ -1075,7 +1075,7 @@
"INVITE_FRIENDS_PICKER_TITLE" = "Arkadaş Davet Et"; "INVITE_FRIENDS_PICKER_TITLE" = "Arkadaş Davet Et";
/* Alert warning that sending an invite to multiple users will create a group message whose recipients will be able to see each other. */ /* Alert warning that sending an invite to multiple users will create a group message whose recipients will be able to see each other. */
"INVITE_WARNING_MULTIPLE_INVITES_BY_TEXT" = "Aynı anda birden çok kullanıcıyı davet etmek, alıcıların birbirlerini görebilecekleri bir grup mesajı gönderir."; "INVITE_WARNING_MULTIPLE_INVITES_BY_TEXT" = "Aynı anda birden fazla kullanıcıyı davet etmek, alıcıların birbirlerini görebilecekleri bir grup mesajı gönderir.";
/* Slider label embeds {{TIME_AMOUNT}}, e.g. '2 hours'. See *_TIME_AMOUNT strings for examples. */ /* Slider label embeds {{TIME_AMOUNT}}, e.g. '2 hours'. See *_TIME_AMOUNT strings for examples. */
"KEEP_MESSAGES_DURATION" = "Mesajlar %@ geçtikten sonra kayboluyor."; "KEEP_MESSAGES_DURATION" = "Mesajlar %@ geçtikten sonra kayboluyor.";
@ -1090,7 +1090,7 @@
"LEAVE_GROUP_ACTION" = "Grupdan ayrıl"; "LEAVE_GROUP_ACTION" = "Grupdan ayrıl";
/* report an invalid linking code */ /* report an invalid linking code */
"LINK_DEVICE_INVALID_CODE_BODY" = "Bu QR kodu geçerli değil, bağlamak istediğiniz cihazda görüntülenen QR kodunu taradığınızdan emin olun."; "LINK_DEVICE_INVALID_CODE_BODY" = "Bu karekod geçerli değil, bağlamak istediğiniz cihazda görüntülenen karekodu taradığınızdan emin olun.";
/* report an invalid linking code */ /* report an invalid linking code */
"LINK_DEVICE_INVALID_CODE_TITLE" = "Cihaz Bağlanması Başarısız Oldu"; "LINK_DEVICE_INVALID_CODE_TITLE" = "Cihaz Bağlanması Başarısız Oldu";
@ -1521,7 +1521,7 @@
"PRIVACY_VERIFICATION_FAILED_NO_SAFETY_NUMBERS_IN_CLIPBOARD" = "Signal, panonuzda herhangi bir güvenlik numarası bulamadı. Doğru şekilde kopyaladınız mı?"; "PRIVACY_VERIFICATION_FAILED_NO_SAFETY_NUMBERS_IN_CLIPBOARD" = "Signal, panonuzda herhangi bir güvenlik numarası bulamadı. Doğru şekilde kopyaladınız mı?";
/* Alert body when verifying with {{contact name}} */ /* Alert body when verifying with {{contact name}} */
"PRIVACY_VERIFICATION_FAILED_THEY_HAVE_WRONG_KEY_FOR_ME" = "Signal kullanıcılarının her çifti ayrı bir güvenlik numarası paylaşıyor. %@ *sizin* emniyet numaranızı gösterdiğini tekrar kontrol edin."; "PRIVACY_VERIFICATION_FAILED_THEY_HAVE_WRONG_KEY_FOR_ME" = "Signal kullanıcılarının her çifti ayrı bir güvenlik numarası paylaşır. %@ *size* özel olan güvenlik numarasını görüntülüyor olduğunu kontrol edin.";
/* alert body */ /* alert body */
"PRIVACY_VERIFICATION_FAILED_WITH_OLD_LOCAL_VERSION" = "Signal'in eski bir sürümünü kullanıyorsunuz. Doğrulamadan önce güncellemeniz gerekiyor."; "PRIVACY_VERIFICATION_FAILED_WITH_OLD_LOCAL_VERSION" = "Signal'in eski bir sürümünü kullanıyorsunuz. Doğrulamadan önce güncellemeniz gerekiyor.";
@ -2049,7 +2049,7 @@
"SETTINGS_SCREEN_SECURITY_DETAIL" = "Uygulama geçişleri esnasında Signal önizlemelerinin görülmez."; "SETTINGS_SCREEN_SECURITY_DETAIL" = "Uygulama geçişleri esnasında Signal önizlemelerinin görülmez.";
/* Settings table section footer. */ /* Settings table section footer. */
"SETTINGS_SECTION_CALL_KIT_DESCRIPTION" = "IOS Çağrı Entegrasyonu, Signal çağrılarını kilit ekranınızda ve sistemin arama geçmişinde gösterir. İsteğe bağlı olarak kişinin adını ve numarasını da gösterebilirsiniz. ICloud etkinleştirilirse, bu arama geçmişi Apple ile paylaşılacaktır."; "SETTINGS_SECTION_CALL_KIT_DESCRIPTION" = "IOS Çağrı Entegrasyonu, Signal çağrılarını kilit ekranınızda ve sistemin arama geçmişinde gösterir. İsteğe bağlı olarak kişinin adını ve numarasını da gösterebilirsiniz. ICloud etkinleştirilmiş ise, bu arama geçmişi Apple ile paylaşılacaktır.";
/* Label for the notifications section of conversation settings view. */ /* Label for the notifications section of conversation settings view. */
"SETTINGS_SECTION_NOTIFICATIONS" = "Bildirimler"; "SETTINGS_SECTION_NOTIFICATIONS" = "Bildirimler";
@ -2238,7 +2238,7 @@
"UPDATE_GROUP_CANT_REMOVE_MEMBERS_ALERT_TITLE" = "İzin Verilmiyor"; "UPDATE_GROUP_CANT_REMOVE_MEMBERS_ALERT_TITLE" = "İzin Verilmiyor";
/* Description of CallKit to upgrading (existing) users */ /* Description of CallKit to upgrading (existing) users */
"UPGRADE_EXPERIENCE_CALLKIT_DESCRIPTION" = "IOS çağrı entegrasyonu ile kilit ekranınızdan gelen aramaları cevaplamak kolaydır. Varsayılan olarak arayanı anonimleştiririz, bu yüzden de özeldir."; "UPGRADE_EXPERIENCE_CALLKIT_DESCRIPTION" = "IOS çağrı entegrasyonu ile kilit ekranınızdan gelen aramaları cevaplamak kolaydır. Varsayılan olarak arayan bilgilerini saklarız.";
/* button label shown once when when user upgrades app, in context of call kit */ /* button label shown once when when user upgrades app, in context of call kit */
"UPGRADE_EXPERIENCE_CALLKIT_PRIVACY_SETTINGS_BUTTON" = "Daha fazlasını gizlilik ayarlarınızdan öğrenin."; "UPGRADE_EXPERIENCE_CALLKIT_PRIVACY_SETTINGS_BUTTON" = "Daha fazlasını gizlilik ayarlarınızdan öğrenin.";
@ -2247,7 +2247,7 @@
"UPGRADE_EXPERIENCE_CALLKIT_TITLE" = "Cevaplamak için Sadece Kaydırın"; "UPGRADE_EXPERIENCE_CALLKIT_TITLE" = "Cevaplamak için Sadece Kaydırın";
/* Description for notification audio customization */ /* Description for notification audio customization */
"UPGRADE_EXPERIENCE_INTRODUCING_NOTIFICATION_AUDIO_DESCRIPTION" = "Artık varsayılan ve konuşma başına bildirim seslerini seçebilirsiniz ve aramalar her sistem kişisi için seçtiğiniz zil sesine uygun olacaktır."; "UPGRADE_EXPERIENCE_INTRODUCING_NOTIFICATION_AUDIO_DESCRIPTION" = "Artık varsayılan ve sohbet başına bildirim seslerini seçebilirsiniz ve aramalar her sistem kişisi için seçtiğiniz zil sesine uygun olacaktır.";
/* button label shown one time, after upgrade */ /* button label shown one time, after upgrade */
"UPGRADE_EXPERIENCE_INTRODUCING_NOTIFICATION_AUDIO_SETTINGS_BUTTON" = "Bildirim Ayarlarını Gözden Geçirin"; "UPGRADE_EXPERIENCE_INTRODUCING_NOTIFICATION_AUDIO_SETTINGS_BUTTON" = "Bildirim Ayarlarını Gözden Geçirin";

@ -133,35 +133,17 @@ NS_ASSUME_NONNULL_BEGIN
if (@available(iOS 11.0, *)) { if (@available(iOS 11.0, *)) {
if (OWSWindowManager.sharedManager.hasCall) { if (OWSWindowManager.sharedManager.hasCall) {
if (UIDevice.currentDevice.isIPhoneX) { self.additionalSafeAreaInsets = UIEdgeInsetsMake(20, 0, 0, 0);
// iPhoneX computes status bar height differently.
// IOS_DEVICE_CONSTANT
self.additionalSafeAreaInsets = UIEdgeInsetsMake(navbar.navbarWithoutStatusHeight + 20, 0, 0, 0);
} else {
self.additionalSafeAreaInsets
= UIEdgeInsetsMake(navbar.navbarWithoutStatusHeight + CurrentAppContext().statusBarHeight, 0, 0, 0);
}
} else { } else {
self.additionalSafeAreaInsets = UIEdgeInsetsZero; self.additionalSafeAreaInsets = UIEdgeInsetsZero;
} }
// in iOS11 we have to ensure the navbar frame *in* layoutSubviews. // in iOS11 we have to ensure the navbar frame *in* layoutSubviews.
[navbar layoutSubviews]; [navbar layoutSubviews];
} else { } else {
// Pre iOS11 we size the navbar, and position it vertically once. // in iOS9/10 we only need to size the navbar once
[navbar sizeToFit]; [navbar sizeToFit];
[navbar layoutIfNeeded];
if (OWSWindowManager.sharedManager.hasCall) {
CGRect oldFrame = navbar.frame;
CGRect newFrame = oldFrame;
newFrame.size.height = navbar.callBannerHeight;
navbar.frame = newFrame;
} else {
CGRect oldFrame = navbar.frame;
CGRect newFrame
= CGRectMake(oldFrame.origin.x, navbar.statusBarHeight, oldFrame.size.width, oldFrame.size.height);
navbar.frame = newFrame;
}
// Since the navbar's frame was updated, we need to be sure our child VC's // Since the navbar's frame was updated, we need to be sure our child VC's
// container view is updated. // container view is updated.

@ -94,11 +94,18 @@ public class OWSNavigationBar: UINavigationBar {
if #available(iOS 11, *) { if #available(iOS 11, *) {
return super.sizeThatFits(size) return super.sizeThatFits(size)
} else { } else if #available(iOS 10, *) {
// pre iOS11, sizeThatFits is repeatedly called to determine how much space to reserve for that navbar. // iOS10
// sizeThatFits is repeatedly called to determine how much space to reserve for that navbar.
// That is, increasing this causes the child view controller to be pushed down. // That is, increasing this causes the child view controller to be pushed down.
// (as of iOS11, this is not used and instead we use additionalSafeAreaInsets) // (as of iOS11, this is not used and instead we use additionalSafeAreaInsets)
return CGSize(width: fullWidth, height: navbarWithoutStatusHeight + statusBarHeight) return CGSize(width: fullWidth, height: navbarWithoutStatusHeight + statusBarHeight)
} else {
// iOS9
// sizeThatFits is repeatedly called to determine how much space to reserve for that navbar.
// That is, increasing this causes the child view controller to be pushed down.
// (as of iOS11, this is not used and instead we use additionalSafeAreaInsets)
return CGSize(width: fullWidth, height: navbarWithoutStatusHeight + callBannerHeight + 20)
} }
} }
@ -108,15 +115,16 @@ public class OWSNavigationBar: UINavigationBar {
return return
} }
guard #available(iOS 11, *) else {
super.layoutSubviews()
return
}
self.frame = CGRect(x: 0, y: callBannerHeight, width: fullWidth, height: navbarWithoutStatusHeight) self.frame = CGRect(x: 0, y: callBannerHeight, width: fullWidth, height: navbarWithoutStatusHeight)
self.bounds = CGRect(x: 0, y: 0, width: fullWidth, height: navbarWithoutStatusHeight) self.bounds = CGRect(x: 0, y: 0, width: fullWidth, height: navbarWithoutStatusHeight)
super.layoutSubviews() super.layoutSubviews()
guard #available(iOS 11, *) else {
return
}
// This is only necessary on iOS11, which has some private views within that lay outside of the navbar. // This is only necessary on iOS11, which has some private views within that lay outside of the navbar.
// They aren't actually visible behind the call status bar, but they looks strange during present/dismiss // They aren't actually visible behind the call status bar, but they looks strange during present/dismiss
// animations for modal VC's // animations for modal VC's

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.28.0</string> <string>2.28.0</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>2.28.0.13</string> <string>2.28.0.15</string>
<key>ITSAppUsesNonExemptEncryption</key> <key>ITSAppUsesNonExemptEncryption</key>
<false/> <false/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>

Loading…
Cancel
Save