Skip to content

Commit

Permalink
Merge branch 'feature/EmbeddableVIPERModules' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Zarembo-Godzyatsky committed Sep 1, 2015
2 parents db8b8c6 + db7177b commit 4d99aa3
Show file tree
Hide file tree
Showing 72 changed files with 1,323 additions and 297 deletions.
@@ -0,0 +1,26 @@
//
// RamblerViperModuleFabric.h
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "RamblerViperModuleFabricProtocol.h"

/**
Универсальная фабрика для VIPER-модулей, инстанс создается в Assembly модуля с использованием инициализатора, в который передается
объект TyphoonStoryboard, а также RestorationId для ViewController этого модуля.
При вызове метода instantiateModuleFromTransitionHandler: фабрика создает инстанс ViewController из Storyboard, при этом инициализируется модуль
благодаря использованию Typhoon.
*/
@interface RamblerViperModuleFabric : NSObject<RamblerViperModuleFabricProtocol>

- (instancetype)initWithStoryboard:(UIStoryboard*)storyboard andRestorationId:(NSString*)restorationId;

@property (nonatomic,strong,readonly) UIStoryboard *storyboard;
@property (nonatomic,strong,readonly) NSString* restorationId;

@end
@@ -0,0 +1,42 @@

//
// RamblerViperModuleFabric.m
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import "RamblerViperModuleFabric.h"
#import "RamblerViperModuleFabricInstantiationPromise.h"
#import "RamblerViperModuleTransitionHandlerProtocol.h"

@interface RamblerViperModuleFabric ()

@property (nonatomic,strong) UIStoryboard *storyboard;
@property (nonatomic,strong) NSString* restorationId;

@end

@implementation RamblerViperModuleFabric

- (instancetype)initWithStoryboard:(UIStoryboard*)storyboard andRestorationId:(NSString*)restorationId {
self = [super init];
if (self) {
self.storyboard = storyboard;
self.restorationId = restorationId;
}
return self;
}

#pragma mark - RDSModuleFabricProtocol

- (id<RamblerViperModuleFabricInstantiationPromiseProtocol>)instantiateModuleFromTransitionHandler:(id<RamblerViperModuleTransitionHandlerProtocol>)transitionHandler {

id destinationViewController = [self.storyboard instantiateViewControllerWithIdentifier:self.restorationId];
RamblerViperModuleFabricInstantiationPromise * promise = [[RamblerViperModuleFabricInstantiationPromise alloc] initWithSourceViewController:transitionHandler
andDestinationViewController:destinationViewController];
return promise;
}

@end
@@ -0,0 +1,20 @@
//
// RamblerViperModuleFabricInstantiationPromise.h
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "RamblerViperModuleFabricInstantiationPromiseProtocol.h"


@interface RamblerViperModuleFabricInstantiationPromise : NSObject<RamblerViperModuleFabricInstantiationPromiseProtocol>

@property (nonatomic,strong,readonly) id sourceViewController;
@property (nonatomic,strong,readonly) id destinationViewController;

- (instancetype)initWithSourceViewController:(id)sourceViewController andDestinationViewController:(id)destinationViewController;

@end
@@ -0,0 +1,70 @@
//
// RamblerViperModuleFabricInstantiationPromise.m
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import "RamblerViperModuleFabricInstantiationPromise.h"
#import "RamblerViperEmbedModuleSegue.h"
#import "RamblerViperModuleConfigurationPromise.h"
#import "RamblerViperModuleConfiguratorHolder.h"

@interface RamblerViperModuleFabricInstantiationPromise ()

@property (nonatomic,strong) id sourceViewController;
@property (nonatomic,strong) id destinationViewController;

@end

@implementation RamblerViperModuleFabricInstantiationPromise

- (instancetype)initWithSourceViewController:(id)sourceViewController andDestinationViewController:(id)destinationViewController {
self = [super init];
if (self) {
self.sourceViewController = sourceViewController;
self.destinationViewController = destinationViewController;
}
return self;
}

#pragma mark - RDSModuleFabricInstantiationPromiseProtocol

- (id<RamblerViperModuleConfigurationPromiseProtocol>)andShow {

__weak typeof(self) wself = self;
return [self andActivateUsingBlock:^{
typeof (self) sself = wself;
UINavigationController* sourceNavigationController = [sself.sourceViewController navigationController];
[sourceNavigationController pushViewController:sself.destinationViewController
animated:YES];
}];
}
- (id<RamblerViperModuleConfigurationPromiseProtocol>)andEmbedIntoContainerView:(UIView*)containerView {

__weak typeof(self) wself = self;
return [self andActivateUsingBlock:^{
typeof(self) sself = wself;
RamblerViperEmbedModuleSegue *segue = [[RamblerViperEmbedModuleSegue alloc] initWithIdentifier:nil
source:sself.sourceViewController
destination:sself.destinationViewController];
segue.containerView = containerView;
[segue perform];
}];
}

- (id<RamblerViperModuleConfigurationPromiseProtocol>)andActivateUsingBlock:(RamblerViperModuleActivationBlock)activationBlock {

RamblerViperModuleConfigurationPromise *promise = [[RamblerViperModuleConfigurationPromise alloc] init];
id<RamblerViperModuleConfiguratorProtocol> configurator = nil;
if ([self.destinationViewController conformsToProtocol:@protocol(RamblerViperModuleConfiguratorHolder)]) {
configurator = [(id<RamblerViperModuleConfiguratorHolder>)self.destinationViewController moduleConfigurator];
}
[promise setModuleConfigurator:configurator];
promise.moduleActivationBlock = activationBlock;
return promise;
}


@end
@@ -0,0 +1,40 @@
//
// RamblerViperModuleFabricInstantiationPromiseProtocol.h
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "RamblerViperModuleConfigurationPromiseProtocol.h"
#import "RamblerViperModuleConfigurationPromise.h"

/**
Протокол промиса добавления модуля в приложение.
В текущей реализации поддерживает два варианта: добавить модуль через PUSH для вызывающего модуля и добавить модуль в View-контейнер
Каждый из методов возвращает промис конфигурации добавляемого модуля
*/
@protocol RamblerViperModuleFabricInstantiationPromiseProtocol <NSObject>

/**
Добавление модуля через вызов push в navigation controller вызывающего модуля
@return промис конфигурации добавляемого модуля
*/
- (id<RamblerViperModuleConfigurationPromiseProtocol>)andShow;
/**
Добавление модуля во View-контейнер вызываюшего модуля
@return промис конфигурации добавляемого модуля
*/
- (id<RamblerViperModuleConfigurationPromiseProtocol>)andEmbedIntoContainerView:(UIView*)containerView;

/**
Добавление модуля через блок активации. В этом блоке можно реализовать вызов Segue или иную логику активации модуля.
@return промис конфигурации добавляемого модуля
*/
- (id<RamblerViperModuleConfigurationPromiseProtocol>)andActivateUsingBlock:(RamblerViperModuleActivationBlock)activationBlock;

@end
@@ -0,0 +1,29 @@
//
// RamblerViperModuleFabricProtocol.h
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "RamblerViperModuleFabricInstantiationPromiseProtocol.h"

@protocol RamblerViperModuleTransitionHandlerProtocol;

/**
Протокол фабрики модулей VIPER, инициализирует модуль, в методе инициализации возвращает промис, который позволяет добавить модуль через
push у navigationController или через внедрение модуля с заданный View-контейнер.
*/
@protocol RamblerViperModuleFabricProtocol <NSObject>

/**
Создает промис, позволяющий добавить модуль в приложение
@param transitionHandler обработчик переходов между модулями, чаще всего это ViewController вызывающего модуля
@return промис
*/
- (id<RamblerViperModuleFabricInstantiationPromiseProtocol>)instantiateModuleFromTransitionHandler:(id<RamblerViperModuleTransitionHandlerProtocol>)transitionHandler;

@end
22 changes: 22 additions & 0 deletions Code/Viper/EmbeddableModules/RamblerViperEmbedModuleSegue.h
@@ -0,0 +1,22 @@
//
// RamblerViperEmbedModuleSegue.h
// Rambler McFlurry
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <UIKit/UIKit.h>

/**
* Специальный Segue для внедрения одних модулей в другие в контейнерный View
*/
@interface RamblerViperEmbedModuleSegue : UIStoryboardSegue

/**
View-контейнер, в который будет добавлен view встраиваемого модуля. К нему будут автоматически примерены
LayourConstraints, привязывающие границы view модуля к границам контейнера.
*/
@property (nonatomic,strong) UIView* containerView;

@end
38 changes: 38 additions & 0 deletions Code/Viper/EmbeddableModules/RamblerViperEmbedModuleSegue.m
@@ -0,0 +1,38 @@
//
// RamblerViperEmbedModuleSegue.m
// Rambler McFlurry
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import "RamblerViperEmbedModuleSegue.h"

@implementation RamblerViperEmbedModuleSegue


- (void)perform {

UIViewController *parentViewController = self.sourceViewController;
UIViewController *embeddableModuleViewController = self.destinationViewController;

[parentViewController addChildViewController:embeddableModuleViewController];
UIView *moduleView = embeddableModuleViewController.view;
[self.containerView addSubview:moduleView];

moduleView.translatesAutoresizingMaskIntoConstraints = NO;

// align moduleView from the left and right
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[moduleView]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(moduleView)]];

// align moduleView from the top and bottom
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[moduleView]-0-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(moduleView)]];
}

@end
@@ -0,0 +1,24 @@
//
// RamblerViperEmbedModuleTransitionSegueData.h
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "RamblerViperModuleTransitionSegueData.h"

/**
Объект для хранения данных при переходе между модулями через Segue. Дополнительно к родительскогому объекту
хранит контейнер для встаиваемого модуля
*/
@interface RamblerViperEmbedModuleTransitionSegueData : RamblerViperModuleTransitionSegueData

@property (nonatomic,strong,readonly) UIView *containerView;

- (instancetype)initWithSender:(id)sender
andPromise:(id<RamblerViperModuleConfigurationPromiseProtocol>)promise
andContainerView:(UIView*)containerView;

@end
@@ -0,0 +1,30 @@
//
// RamblerViperEmbedModuleTransitionSegueData.m
// Championat
//
// Created by Andrey Zarembo-Godzyatsky on 21/08/15.
// Copyright (c) 2015 Rambler DS. All rights reserved.
//

#import "RamblerViperEmbedModuleTransitionSegueData.h"

@interface RamblerViperEmbedModuleTransitionSegueData ()

@property (nonatomic,strong) UIView *containerView;

@end

@implementation RamblerViperEmbedModuleTransitionSegueData

- (instancetype)initWithSender:(id)sender
andPromise:(id<RamblerViperModuleConfigurationPromiseProtocol>)promise
andContainerView:(UIView*)containerView {

self = [super initWithSender:sender andPromise:promise];
if (self) {
self.containerView = containerView;
}
return self;
}

@end
Expand Up @@ -9,6 +9,13 @@
#import <UIKit/UIKit.h>
#import "RamblerViperModuleConfigurationPromiseProtocol.h"

/**
Блок конфигурации модуля. Необходим для сохранения оцередности вызовов конфигурации и методов модуля. Позволяет
избежать ситуации, в которой обращение ко view у viewcontroller модуля выполняется раньше, чем конфугурация модуля.
Это приводит к некорректному поведению.
*/
typedef void (^RamblerViperModuleActivationBlock)();

@protocol RamblerViperModuleConfiguratorProtocol;

/**
Expand All @@ -20,7 +27,10 @@
*/
@interface RamblerViperModuleConfigurationPromise : NSObject<RamblerViperModuleConfigurationPromiseProtocol>

/// Блок активации модуля, вызывается после конфигурации модуля
@property (nonatomic, strong) RamblerViperModuleActivationBlock moduleActivationBlock;

/// Конфигуратор модуля
@property(nonatomic,weak) id<RamblerViperModuleConfiguratorProtocol> moduleConfigurator;
@property(nonatomic, weak) id<RamblerViperModuleConfiguratorProtocol> moduleConfigurator;

@end

0 comments on commit 4d99aa3

Please sign in to comment.