mirror of https://github.com/oxen-io/session-ios
Started refactoring the conversation image picker screens
Fixed a bug where returning from the background on the conversation screen would result in the input view being hidden Refactored the PhotoCollectionPickerViewController to use the SettingsTableViewController convention Updated the SettingsTableViewModel to worked based on Combine instead of the DatabaseObservable so it's more reusable for non-db casespull/672/head
parent
face9da02b
commit
c707a2f80c
@ -1,138 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Photos
|
||||
import PromiseKit
|
||||
|
||||
protocol PhotoCollectionPickerDelegate: AnyObject {
|
||||
func photoCollectionPicker(_ photoCollectionPicker: PhotoCollectionPickerController, didPickCollection collection: PhotoCollection)
|
||||
}
|
||||
|
||||
class PhotoCollectionPickerController: OWSTableViewController, PhotoLibraryDelegate {
|
||||
|
||||
private weak var collectionDelegate: PhotoCollectionPickerDelegate?
|
||||
|
||||
private let library: PhotoLibrary
|
||||
private var photoCollections: [PhotoCollection]
|
||||
|
||||
required init(library: PhotoLibrary,
|
||||
collectionDelegate: PhotoCollectionPickerDelegate) {
|
||||
self.library = library
|
||||
self.photoCollections = library.allPhotoCollections()
|
||||
self.collectionDelegate = collectionDelegate
|
||||
super.init()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: View Lifecycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = .white
|
||||
tableView.backgroundColor = .white
|
||||
tableView.separatorColor = .clear
|
||||
|
||||
library.add(delegate: self)
|
||||
|
||||
updateContents()
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
private func updateContents() {
|
||||
photoCollections = library.allPhotoCollections()
|
||||
|
||||
let sectionItems = photoCollections.map { collection in
|
||||
return OWSTableItem(customCellBlock: { self.buildTableCell(collection: collection) },
|
||||
customRowHeight: UITableView.automaticDimension,
|
||||
actionBlock: { [weak self] in
|
||||
guard let strongSelf = self else { return }
|
||||
strongSelf.didSelectCollection(collection: collection)
|
||||
})
|
||||
}
|
||||
|
||||
let section = OWSTableSection(title: nil, items: sectionItems)
|
||||
let contents = OWSTableContents()
|
||||
contents.addSection(section)
|
||||
self.contents = contents
|
||||
}
|
||||
|
||||
private let numberFormatter: NumberFormatter = NumberFormatter()
|
||||
|
||||
private func buildTableCell(collection: PhotoCollection) -> UITableViewCell {
|
||||
let cell = OWSTableItem.newCell()
|
||||
|
||||
cell.backgroundColor = .white
|
||||
cell.contentView.backgroundColor = .white
|
||||
cell.selectedBackgroundView?.backgroundColor = UIColor(white: 0.2, alpha: 1)
|
||||
|
||||
let contents = collection.contents()
|
||||
|
||||
let titleLabel = UILabel()
|
||||
titleLabel.text = collection.localizedTitle()
|
||||
titleLabel.font = .systemFont(ofSize: Values.mediumFontSize)
|
||||
titleLabel.textColor = .black
|
||||
|
||||
let countLabel = UILabel()
|
||||
countLabel.text = numberFormatter.string(for: contents.assetCount)
|
||||
countLabel.font = .systemFont(ofSize: Values.smallFontSize)
|
||||
countLabel.textColor = .black
|
||||
|
||||
let textStack = UIStackView(arrangedSubviews: [titleLabel, countLabel])
|
||||
textStack.axis = .vertical
|
||||
textStack.alignment = .leading
|
||||
textStack.spacing = 2
|
||||
|
||||
let imageView = UIImageView()
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
imageView.clipsToBounds = true
|
||||
let kImageSize = 80
|
||||
imageView.autoSetDimensions(to: CGSize(width: kImageSize, height: kImageSize))
|
||||
|
||||
let hStackView = UIStackView(arrangedSubviews: [imageView, textStack])
|
||||
hStackView.axis = .horizontal
|
||||
hStackView.alignment = .center
|
||||
hStackView.spacing = Values.mediumSpacing
|
||||
|
||||
let photoMediaSize = PhotoMediaSize(thumbnailSize: CGSize(width: kImageSize, height: kImageSize))
|
||||
if let assetItem = contents.lastAssetItem(photoMediaSize: photoMediaSize) {
|
||||
assetItem.asyncThumbnail { [weak imageView] image in
|
||||
AssertIsOnMainThread()
|
||||
|
||||
guard let imageView = imageView else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let image = image else {
|
||||
owsFailDebug("image was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
imageView.image = image
|
||||
}
|
||||
}
|
||||
|
||||
cell.contentView.addSubview(hStackView)
|
||||
hStackView.ows_autoPinToSuperviewMargins()
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
func didSelectCollection(collection: PhotoCollection) {
|
||||
collectionDelegate?.photoCollectionPicker(self, didPickCollection: collection)
|
||||
}
|
||||
|
||||
// MARK: PhotoLibraryDelegate
|
||||
|
||||
func photoLibraryDidChange(_ photoLibrary: PhotoLibrary) {
|
||||
updateContents()
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import GRDB
|
||||
import DifferenceKit
|
||||
import SessionUIKit
|
||||
import SessionMessagingKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
class PhotoCollectionPickerViewModel: SettingsTableViewModel<NoNav, PhotoCollectionPickerViewModel.Section, PhotoCollectionPickerViewModel.Item> {
|
||||
// MARK: - Config
|
||||
|
||||
public enum Section: SettingSection {
|
||||
case content
|
||||
}
|
||||
|
||||
public struct Item: Equatable, Hashable, Differentiable {
|
||||
let id: String
|
||||
}
|
||||
|
||||
private let library: PhotoLibrary
|
||||
private let onCollectionSelected: (PhotoCollection) -> Void
|
||||
private var photoCollections: CurrentValueSubject<[PhotoCollection], Error>
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
init(library: PhotoLibrary, onCollectionSelected: @escaping (PhotoCollection) -> Void) {
|
||||
self.library = library
|
||||
self.onCollectionSelected = onCollectionSelected
|
||||
self.photoCollections = CurrentValueSubject(library.allPhotoCollections())
|
||||
}
|
||||
|
||||
// MARK: - Content
|
||||
|
||||
override var title: String { "NOTIFICATIONS_STYLE_SOUND_TITLE".localized() }
|
||||
|
||||
private var _settingsData: [SectionModel] = []
|
||||
public override var settingsData: [SectionModel] { _settingsData }
|
||||
public override var observableSettingsData: ObservableData { _observableSettingsData }
|
||||
|
||||
private lazy var _observableSettingsData: ObservableData = {
|
||||
self.photoCollections
|
||||
.map { collections in
|
||||
[
|
||||
SectionModel(
|
||||
model: .content,
|
||||
elements: collections.map { collection in
|
||||
let contents: PhotoCollectionContents = collection.contents()
|
||||
let photoMediaSize: PhotoMediaSize = PhotoMediaSize(
|
||||
thumbnailSize: CGSize(width: IconSize.large.size, height: IconSize.large.size)
|
||||
)
|
||||
let lastAssetItem: PhotoPickerAssetItem? = contents.lastAssetItem(photoMediaSize: photoMediaSize)
|
||||
|
||||
return SettingInfo(
|
||||
id: Item(id: collection.id),
|
||||
iconSize: .large,
|
||||
iconSetter: { imageView in
|
||||
// Note: We need to capture 'lastAssetItem' otherwise it'll be released and we won't
|
||||
// be able to load the thumbnail
|
||||
lastAssetItem?.asyncThumbnail { [weak imageView] image in
|
||||
imageView?.image = image
|
||||
}
|
||||
},
|
||||
title: collection.localizedTitle(),
|
||||
subtitle: "\(contents.assetCount)",
|
||||
action: .trigger(showChevron: false) { [weak self] in
|
||||
self?.onCollectionSelected(collection)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
.removeDuplicates()
|
||||
.eraseToAnyPublisher()
|
||||
}()
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
public override func updateSettings(_ updatedSettings: [SectionModel]) {
|
||||
self._settingsData = updatedSettings
|
||||
}
|
||||
|
||||
// MARK: PhotoLibraryDelegate
|
||||
|
||||
func photoLibraryDidChange(_ photoLibrary: PhotoLibrary) {
|
||||
self.photoCollections.send(library.allPhotoCollections())
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalUtilitiesKit/OWSViewController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern const CGFloat kOWSTable_DefaultCellHeight;
|
||||
|
||||
@class OWSTableItem;
|
||||
@class OWSTableSection;
|
||||
|
||||
@interface OWSTableContents : NSObject
|
||||
|
||||
@property (nonatomic) NSString *title;
|
||||
@property (nonatomic, nullable) NSInteger (^sectionForSectionIndexTitleBlock)(NSString *title, NSInteger index);
|
||||
@property (nonatomic, nullable) NSArray<NSString *> * (^sectionIndexTitlesForTableViewBlock)(void);
|
||||
|
||||
@property (nonatomic, readonly) NSArray<OWSTableSection *> *sections;
|
||||
- (void)addSection:(OWSTableSection *)section;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableSection : NSObject
|
||||
|
||||
@property (nonatomic, nullable) NSString *headerTitle;
|
||||
@property (nonatomic, nullable) NSString *footerTitle;
|
||||
|
||||
@property (nonatomic, nullable) UIView *customHeaderView;
|
||||
@property (nonatomic, nullable) UIView *customFooterView;
|
||||
@property (nonatomic, nullable) NSNumber *customHeaderHeight;
|
||||
@property (nonatomic, nullable) NSNumber *customFooterHeight;
|
||||
|
||||
+ (OWSTableSection *)sectionWithTitle:(nullable NSString *)title items:(NSArray<OWSTableItem *> *)items;
|
||||
|
||||
- (void)addItem:(OWSTableItem *)item;
|
||||
|
||||
- (NSUInteger)itemCount;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef void (^OWSTableActionBlock)(void);
|
||||
typedef void (^OWSTableSubPageBlock)(UIViewController *viewController);
|
||||
typedef UITableViewCell *_Nonnull (^OWSTableCustomCellBlock)(void);
|
||||
typedef BOOL (^OWSTableSwitchBlock)(void);
|
||||
|
||||
@interface OWSTableItem : NSObject
|
||||
|
||||
@property (nonatomic, weak) UIViewController *tableViewController;
|
||||
|
||||
+ (UITableViewCell *)newCell;
|
||||
+ (void)configureCell:(UITableViewCell *)cell;
|
||||
|
||||
+ (OWSTableItem *)itemWithTitle:(NSString *)title
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock NS_SWIFT_NAME(init(title:actionBlock:));
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCell:(UITableViewCell *)customCell
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCellBlock:(OWSTableCustomCellBlock)customCellBlock
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCellBlock:(OWSTableCustomCellBlock)customCellBlock
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
detailText:(NSString *)detailText
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
detailText:(NSString *)detailText
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)checkmarkItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)checkmarkItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)itemWithText:(NSString *)text
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
accessoryType:(UITableViewCellAccessoryType)accessoryType;
|
||||
|
||||
+ (OWSTableItem *)subPageItemWithText:(NSString *)text actionBlock:(nullable OWSTableSubPageBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)subPageItemWithText:(NSString *)text
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableSubPageBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)actionItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)actionItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)softCenterLabelItemWithText:(NSString *)text;
|
||||
|
||||
+ (OWSTableItem *)softCenterLabelItemWithText:(NSString *)text customRowHeight:(CGFloat)customRowHeight;
|
||||
|
||||
+ (OWSTableItem *)labelItemWithText:(NSString *)text;
|
||||
|
||||
+ (OWSTableItem *)labelItemWithText:(NSString *)text accessoryText:(NSString *)accessoryText;
|
||||
|
||||
+ (OWSTableItem *)longDisclosureItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector;
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
isEnabledBlock:(OWSTableSwitchBlock)isEnabledBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector;
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
isEnabledBlock:(OWSTableSwitchBlock)isEnabledBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector;
|
||||
|
||||
- (nullable UITableViewCell *)customCell;
|
||||
- (NSNumber *)customRowHeight;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@protocol OWSTableViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)tableViewWillBeginDragging;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableViewController : OWSViewController
|
||||
|
||||
@property (nonatomic, weak) id<OWSTableViewControllerDelegate> delegate;
|
||||
|
||||
@property (nonatomic) OWSTableContents *contents;
|
||||
@property (nonatomic, readonly) UITableView *tableView;
|
||||
|
||||
@property (nonatomic) UITableViewStyle tableViewStyle;
|
||||
|
||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
#pragma mark - Presentation
|
||||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController;
|
||||
|
||||
- (void)applyTheme;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -1,820 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSTableViewController.h"
|
||||
#import "OWSNavigationController.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
|
||||
#import <SessionUIKit/SessionUIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
const CGFloat kOWSTable_DefaultCellHeight = 45.f;
|
||||
|
||||
@interface OWSTableContents ()
|
||||
|
||||
@property (nonatomic) NSMutableArray<OWSTableSection *> *sections;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableContents
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_sections = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addSection:(OWSTableSection *)section
|
||||
{
|
||||
OWSAssertDebug(section);
|
||||
|
||||
[_sections addObject:section];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableSection ()
|
||||
|
||||
@property (nonatomic) NSMutableArray<OWSTableItem *> *items;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableSection
|
||||
|
||||
+ (OWSTableSection *)sectionWithTitle:(nullable NSString *)title items:(NSArray<OWSTableItem *> *)items
|
||||
{
|
||||
OWSTableSection *section = [OWSTableSection new];
|
||||
section.headerTitle = title;
|
||||
section.items = [items mutableCopy];
|
||||
return section;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_items = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addItem:(OWSTableItem *)item
|
||||
{
|
||||
OWSAssertDebug(item);
|
||||
|
||||
[_items addObject:item];
|
||||
}
|
||||
|
||||
- (NSUInteger)itemCount
|
||||
{
|
||||
return _items.count;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableItem ()
|
||||
|
||||
@property (nonatomic, nullable) NSString *title;
|
||||
@property (nonatomic, nullable) OWSTableActionBlock actionBlock;
|
||||
|
||||
@property (nonatomic) OWSTableCustomCellBlock customCellBlock;
|
||||
@property (nonatomic) UITableViewCell *customCell;
|
||||
@property (nonatomic) NSNumber *customRowHeight;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableItem
|
||||
|
||||
+ (UITableViewCell *)newCell
|
||||
{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
[self configureCell:cell];
|
||||
return cell;
|
||||
}
|
||||
|
||||
+ (void)configureCell:(UITableViewCell *)cell
|
||||
{
|
||||
cell.backgroundColor = LKColors.cellBackground;
|
||||
cell.contentView.backgroundColor = UIColor.clearColor;
|
||||
|
||||
cell.textLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
|
||||
cell.textLabel.textColor = LKColors.text;
|
||||
cell.detailTextLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
|
||||
cell.detailTextLabel.textColor = LKColors.text;
|
||||
|
||||
UIView *selectedBackgroundView = [UIView new];
|
||||
selectedBackgroundView.backgroundColor = LKColors.cellSelected;
|
||||
cell.selectedBackgroundView = selectedBackgroundView;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithTitle:(NSString *)title actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(title.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.title = title;
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCell:(UITableViewCell *)customCell
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(customCell);
|
||||
OWSAssertDebug(customRowHeight > 0 || customRowHeight == UITableViewAutomaticDimension);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.customCell = customCell;
|
||||
item.customRowHeight = @(customRowHeight);
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCellBlock:(OWSTableCustomCellBlock)customCellBlock
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(customRowHeight > 0 || customRowHeight == UITableViewAutomaticDimension);
|
||||
|
||||
OWSTableItem *item = [self itemWithCustomCellBlock:customCellBlock actionBlock:actionBlock];
|
||||
item.customRowHeight = @(customRowHeight);
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithCustomCellBlock:(OWSTableCustomCellBlock)customCellBlock
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(customCellBlock);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.customCellBlock = customCellBlock;
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self itemWithText:text actionBlock:actionBlock accessoryType:UITableViewCellAccessoryDisclosureIndicator];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self itemWithText:text
|
||||
accessibilityIdentifier:accessibilityIdentifier
|
||||
actionBlock:actionBlock
|
||||
accessoryType:UITableViewCellAccessoryNone];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)checkmarkItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self checkmarkItemWithText:text accessibilityIdentifier:nil actionBlock:actionBlock];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)checkmarkItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
{
|
||||
return [self itemWithText:text
|
||||
accessibilityIdentifier:accessibilityIdentifier
|
||||
actionBlock:actionBlock
|
||||
accessoryType:UITableViewCellAccessoryCheckmark];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithText:(NSString *)text
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
accessoryType:(UITableViewCellAccessoryType)accessoryType
|
||||
{
|
||||
return [self itemWithText:text accessibilityIdentifier:nil actionBlock:actionBlock accessoryType:accessoryType];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)itemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
accessoryType:(UITableViewCellAccessoryType)accessoryType
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(actionBlock);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
cell.accessoryType = accessoryType;
|
||||
cell.accessibilityIdentifier = accessibilityIdentifier;
|
||||
cell.tintColor = LKColors.accent;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self disclosureItemWithText:text
|
||||
accessibilityIdentifier:nil
|
||||
customRowHeight:customRowHeight
|
||||
actionBlock:actionBlock];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(customRowHeight > 0 || customRowHeight == UITableViewAutomaticDimension);
|
||||
|
||||
OWSTableItem *item =
|
||||
[self disclosureItemWithText:text accessibilityIdentifier:accessibilityIdentifier actionBlock:actionBlock];
|
||||
item.customRowHeight = @(customRowHeight);
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
detailText:(NSString *)detailText
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self disclosureItemWithText:text detailText:detailText accessibilityIdentifier:nil actionBlock:actionBlock];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)disclosureItemWithText:(NSString *)text
|
||||
detailText:(NSString *)detailText
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(actionBlock);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
|
||||
reuseIdentifier:@"UITableViewCellStyleValue1"];
|
||||
[OWSTableItem configureCell:cell];
|
||||
cell.textLabel.text = text;
|
||||
cell.detailTextLabel.text = detailText;
|
||||
cell.accessibilityIdentifier = accessibilityIdentifier;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)subPageItemWithText:(NSString *)text actionBlock:(nullable OWSTableSubPageBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(actionBlock);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
__weak OWSTableItem *weakItem = item;
|
||||
item.actionBlock = ^{
|
||||
OWSTableItem *strongItem = weakItem;
|
||||
OWSAssertDebug(strongItem);
|
||||
OWSAssertDebug(strongItem.tableViewController);
|
||||
|
||||
if (actionBlock) {
|
||||
actionBlock(strongItem.tableViewController);
|
||||
}
|
||||
};
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)subPageItemWithText:(NSString *)text
|
||||
customRowHeight:(CGFloat)customRowHeight
|
||||
actionBlock:(nullable OWSTableSubPageBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(customRowHeight > 0 || customRowHeight == UITableViewAutomaticDimension);
|
||||
|
||||
OWSTableItem *item = [self subPageItemWithText:text actionBlock:actionBlock];
|
||||
item.customRowHeight = @(customRowHeight);
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)actionItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
return [self actionItemWithText:text accessibilityIdentifier:nil actionBlock:actionBlock];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)actionItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
actionBlock:(nullable OWSTableActionBlock)actionBlock;
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(actionBlock);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.actionBlock = actionBlock;
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
cell.accessibilityIdentifier = accessibilityIdentifier;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)softCenterLabelItemWithText:(NSString *)text
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
// These cells look quite different.
|
||||
//
|
||||
// Smaller font.
|
||||
cell.textLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
|
||||
// Soft color.
|
||||
// TODO: Theme, review with design.
|
||||
cell.textLabel.textColor = LKColors.text;
|
||||
// Centered.
|
||||
cell.textLabel.textAlignment = NSTextAlignmentCenter;
|
||||
cell.userInteractionEnabled = NO;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)softCenterLabelItemWithText:(NSString *)text customRowHeight:(CGFloat)customRowHeight
|
||||
{
|
||||
OWSAssertDebug(customRowHeight > 0 || customRowHeight == UITableViewAutomaticDimension);
|
||||
|
||||
OWSTableItem *item = [self softCenterLabelItemWithText:text];
|
||||
item.customRowHeight = @(customRowHeight);
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)labelItemWithText:(NSString *)text
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
cell.userInteractionEnabled = NO;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)labelItemWithText:(NSString *)text accessoryText:(NSString *)accessoryText
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(accessoryText.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
|
||||
UILabel *accessoryLabel = [UILabel new];
|
||||
accessoryLabel.text = accessoryText;
|
||||
accessoryLabel.textColor = LKColors.text;
|
||||
accessoryLabel.font = [UIFont systemFontOfSize:LKValues.mediumFontSize];
|
||||
accessoryLabel.textAlignment = NSTextAlignmentRight;
|
||||
[accessoryLabel sizeToFit];
|
||||
cell.accessoryView = accessoryLabel;
|
||||
|
||||
cell.userInteractionEnabled = NO;
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)longDisclosureItemWithText:(NSString *)text actionBlock:(nullable OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
|
||||
cell.textLabel.text = text;
|
||||
cell.textLabel.numberOfLines = 0;
|
||||
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
|
||||
return cell;
|
||||
};
|
||||
item.customRowHeight = @(UITableViewAutomaticDimension);
|
||||
item.actionBlock = actionBlock;
|
||||
return item;
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector
|
||||
{
|
||||
return [self switchItemWithText:text
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
isEnabledBlock:^{
|
||||
return YES;
|
||||
}
|
||||
target:target
|
||||
selector:selector];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
isEnabledBlock:(OWSTableSwitchBlock)isEnabledBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector
|
||||
{
|
||||
return [self switchItemWithText:text
|
||||
accessibilityIdentifier:nil
|
||||
isOnBlock:isOnBlock
|
||||
isEnabledBlock:isEnabledBlock
|
||||
target:target
|
||||
selector:selector];
|
||||
}
|
||||
|
||||
+ (OWSTableItem *)switchItemWithText:(NSString *)text
|
||||
accessibilityIdentifier:(nullable NSString *)accessibilityIdentifier
|
||||
isOnBlock:(OWSTableSwitchBlock)isOnBlock
|
||||
isEnabledBlock:(OWSTableSwitchBlock)isEnabledBlock
|
||||
target:(id)target
|
||||
selector:(SEL)selector
|
||||
{
|
||||
OWSAssertDebug(text.length > 0);
|
||||
OWSAssertDebug(target);
|
||||
OWSAssertDebug(selector);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
__weak id weakTarget = target;
|
||||
item.customCellBlock = ^{
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.textLabel.text = text;
|
||||
|
||||
UISwitch *cellSwitch = [UISwitch new];
|
||||
cell.accessoryView = cellSwitch;
|
||||
cellSwitch.onTintColor = LKColors.accent;
|
||||
[cellSwitch setOn:isOnBlock()];
|
||||
[cellSwitch addTarget:weakTarget action:selector forControlEvents:UIControlEventValueChanged];
|
||||
cellSwitch.enabled = isEnabledBlock();
|
||||
cellSwitch.accessibilityIdentifier = accessibilityIdentifier;
|
||||
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
||||
return cell;
|
||||
};
|
||||
return item;
|
||||
}
|
||||
|
||||
- (nullable UITableViewCell *)customCell
|
||||
{
|
||||
if (_customCell) {
|
||||
return _customCell;
|
||||
}
|
||||
if (_customCellBlock) {
|
||||
return _customCellBlock();
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableViewController () <UITableViewDelegate, UITableViewDataSource>
|
||||
|
||||
@property (nonatomic) UITableView *tableView;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
NSString *const kOWSTableCellIdentifier = @"kOWSTableCellIdentifier";
|
||||
|
||||
@implementation OWSTableViewController
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
[self owsTableCommonInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
[self owsTableCommonInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
[self owsTableCommonInit];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)owsTableCommonInit
|
||||
{
|
||||
_contents = [OWSTableContents new];
|
||||
self.tableViewStyle = UITableViewStyleGrouped;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
OWSAssertDebug(self.contents);
|
||||
|
||||
if (self.contents.title.length > 0) {
|
||||
self.title = self.contents.title;
|
||||
}
|
||||
|
||||
self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:self.tableViewStyle];
|
||||
self.tableView.delegate = self;
|
||||
self.tableView.dataSource = self;
|
||||
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
|
||||
[self.view addSubview:self.tableView];
|
||||
|
||||
if ([self.tableView applyScrollViewInsetsFix]) {
|
||||
// if applyScrollViewInsetsFix disables contentInsetAdjustmentBehavior,
|
||||
// we need to pin to the top and bottom layout guides since UIKit
|
||||
// won't adjust our content insets.
|
||||
[self.tableView autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0];
|
||||
[self.tableView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.view withOffset:0];
|
||||
[self.tableView autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
|
||||
[self.tableView autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
|
||||
|
||||
// We don't need a top or bottom insets, since we pin to the top and bottom layout guides.
|
||||
self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
} else {
|
||||
[self.tableView autoPinEdgesToSuperviewEdges];
|
||||
}
|
||||
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kOWSTableCellIdentifier];
|
||||
|
||||
[self applyTheme];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
}
|
||||
|
||||
- (OWSTableSection *)sectionForIndex:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSAssertDebug(self.contents);
|
||||
OWSAssertDebug(sectionIndex >= 0 && sectionIndex < (NSInteger)self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger)sectionIndex];
|
||||
return section;
|
||||
}
|
||||
|
||||
- (OWSTableItem *)itemForIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSAssertDebug(self.contents);
|
||||
OWSAssertDebug(indexPath.section >= 0 && indexPath.section < (NSInteger)self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger)indexPath.section];
|
||||
OWSAssertDebug(indexPath.item >= 0 && indexPath.item < (NSInteger)section.items.count);
|
||||
OWSTableItem *item = section.items[(NSUInteger)indexPath.item];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
- (void)setContents:(OWSTableContents *)contents
|
||||
{
|
||||
OWSAssertDebug(contents);
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
_contents = contents;
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
OWSAssertDebug(self.contents);
|
||||
return (NSInteger)self.contents.sections.count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
OWSAssertDebug(section.items);
|
||||
return (NSInteger)section.items.count;
|
||||
}
|
||||
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.headerTitle;
|
||||
}
|
||||
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.footerTitle;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
|
||||
item.tableViewController = self;
|
||||
|
||||
UITableViewCell *customCell = [item customCell];
|
||||
if (customCell) {
|
||||
return customCell;
|
||||
}
|
||||
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kOWSTableCellIdentifier];
|
||||
OWSAssertDebug(cell);
|
||||
[OWSTableItem configureCell:cell];
|
||||
|
||||
cell.textLabel.text = item.title;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
if (item.customRowHeight) {
|
||||
return [item.customRowHeight floatValue];
|
||||
}
|
||||
return kOWSTable_DefaultCellHeight;
|
||||
}
|
||||
|
||||
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.customHeaderView;
|
||||
}
|
||||
|
||||
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.customFooterView;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *_Nullable section = [self sectionForIndex:sectionIndex];
|
||||
|
||||
if (!section) {
|
||||
OWSFailDebug(@"Section index out of bounds.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (section.customHeaderHeight) {
|
||||
return [section.customHeaderHeight floatValue];
|
||||
} else if (section.headerTitle.length > 0) {
|
||||
return UITableViewAutomaticDimension;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *_Nullable section = [self sectionForIndex:sectionIndex];
|
||||
if (!section) {
|
||||
OWSFailDebug(@"Section index out of bounds.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (section.customFooterHeight) {
|
||||
OWSAssertDebug([section.customFooterHeight floatValue] > 0);
|
||||
return [section.customFooterHeight floatValue];
|
||||
} else if (section.footerTitle.length > 0) {
|
||||
return UITableViewAutomaticDimension;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Called before the user changes the selection. Return a new indexPath, or nil, to change the proposed selection.
|
||||
- (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
if (!item.actionBlock) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return indexPath;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
if (item.actionBlock) {
|
||||
item.actionBlock();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Index
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
|
||||
{
|
||||
if (self.contents.sectionForSectionIndexTitleBlock) {
|
||||
return self.contents.sectionForSectionIndexTitleBlock(title, index);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView
|
||||
{
|
||||
if (self.contents.sectionIndexTitlesForTableViewBlock) {
|
||||
return self.contents.sectionIndexTitlesForTableViewBlock();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Presentation
|
||||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssertDebug(fromViewController);
|
||||
|
||||
OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:self];
|
||||
self.navigationItem.leftBarButtonItem =
|
||||
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
|
||||
target:self
|
||||
action:@selector(donePressed:)];
|
||||
|
||||
[fromViewController presentViewController:navigationController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)donePressed:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
|
||||
{
|
||||
[self.delegate tableViewWillBeginDragging];
|
||||
}
|
||||
|
||||
- (void)applyTheme
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
self.view.backgroundColor = LKColors.navigationBarBackground;
|
||||
self.tableView.backgroundColor = LKColors.navigationBarBackground;
|
||||
self.tableView.separatorColor = LKColors.separator;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
Loading…
Reference in New Issue