This question already has an answer here:

I have 2 labels: errorLabel, where errors are stored lblUsernameGlobal, where Usernames are stored

Master Page File:

                <asp:LoginView runat="server" ViewStateMode="Disabled">
                    <AnonymousTemplate>
                        <ul class="nav navbar-nav navbar-right">
                            <asp:DropDownList ID="lstSprache" AutoPostBack="true" Visible="true" runat="server" >
                                <asp:ListItem>Deutsch</asp:ListItem>
                                <asp:ListItem>Berndeutsch</asp:ListItem>
                                <asp:ListItem>Englisch</asp:ListItem>
                            </asp:DropDownList>
                            <li><asp:Label ID = "lblUsernameGlobal" runat = "server" Text=""></asp:Label></li> {...}
            <asp:Label ID="errorLabel" runat="server" Text=""></asp:Label>
            <p>&copy; <%: DateTime.Now.Year %></p>
        </div>
    </div>
</form>

Login.aspx.cs:

protected void btnLogin_Click(object sender, EventArgs e)
    {
        username = txtBenutzername.Text;
        passwort = txtPasswort.Text;
        Label errorLabel = (Label)Master.FindControl("errorLabel");
        Label lblUsernameGlobal = (Label)Master.FindControl("lblUsernameGlobal");
        if (lblUsernameGlobal != null)
        {
            lblUsernameGlobal.Text = "BlaBla";
        }
        else
        {
            try
            {
                lblUsernameGlobal.Text = "BlaBla";
                errorLabel.Text = "Label nicht gefunden";
            }
            catch (Exception ex)
            {
                errorLabel.Text = ex.Message;
            }
        }
        if (username != "" && passwort != "")
        {
            //errorLabel.Text = dbConnect.SelectBenutzerSpecific(username, passwort);
            //lblUsernameGlobal.Text = username;
            //errorLabel.Text = username;
        }
        else
        {
            errorLabel.Text = "Invalid!";
        }
    }

After loads and loads of testing I have yet to find out, why the lblUsernameGlobal doesn't work. I can work with the errorlabel, but as soon as I try to reference the lblUsernameGlobal I get a NullReference. How can I reference lblUsernameGlobal without getting a NullReference?

I did some research but I could not find an appropriate answer regarding the following question.

I don't use the interface builder to generate my views so every control is defined programmatically like so :

let loginButton: UIButton = {
  let button = UIBUtton()
  button.setTitle("Title", forState: .Normal)
  // adding some properties to my button
  return button
}()

Then I add it to the view of my ViewController like that :

self.view.addSubview(loginButton)

And I add some constraints with the Visual Format Language

For example :

self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat
_("V:|[v0(25)]|", options:NSLayoutFormatOptions(), metrics: nil, 
_views: ["v0":loginButton]))

It works really well and I prefer it that way(over the IB) but the main issue is that I end up with really big ViewController classes as I define every controls in the ViewControllers classes.

I guess I should have all the controls declarations, constraints,... in a separate file but I can't find how to do that.

I tried to create a separate class, for example LoginView, which contains all the controls, and a function setupViews(superView: UIView) that adds subviews to the superView parameter and specify constraints. Then in the viewDidLoad() method of my ViewController, I instantiate this class (LoginView) and execute the setupView(superView: self.view). It looks like this :

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let loginView = LoginView()
        loginView.setupViews(self.view)

    }
}

I am pretty sure this is not the way to go. It also causes problems when I try to addTarget to some of my controls.

My question, what is the best way to do it, following the MVC pattern. Thank you very much !

EDIT 1 :

As asked in the comments, here is the implementation of the LoginView class (I only kept few controls/constraints to keep it short but it is the same process for every other one)

import UIKit

class LoginView {

 let superView: UIView?

 init(tempSuperView: UIView){
  superView = tempSuperView
 }

 let usernameTextField: UITextField = {
  let textField = UITextField()
  textField.translatesAutoresizingMaskIntoConstraints = false
  textField.textColor = UIColor.whiteColor()

  return textField
 }()

 let loginButton: UIButton = {
  let button = UIButton()
  button.translatesAutoresizingMaskIntoConstraints = false
  button.setTitle("Login", forState: .Normal)

 return button
 }()

 //some more controls definition

 func setupViews() -> Void {

 superView!.addSubview(usernameTextField)
 superView!.addSubview(loginButton)

 superView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat
_("V:|-150-[v0(50)]", options:NSLayoutFormatOptions(), metrics: nil, 
_views: ["v0":usernameTextField]))
 superView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat
_("H:|-150-[v0(25)]", options:NSLayoutFormatOptions(), metrics: nil, 
_views: ["v0":usernameTextField]))

 //same for the button
 }
}

Here is my ViewController :

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let loginView = LoginView(tempSuperView: self.view)
        loginView.setupViews()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

I am using FBSDKLoginButton in my app, everything working well, only difference I found out that when ever I try to add the button using the code, it adds up Facebook login button with text "Login with facebook" and when ever I try to put the button through the storyboard it shows "Login" only.

I want to to put the button through storyboard, can I change the style to one which I get through code.

Thanx for helping!!!

        let loginView : FBSDKLoginButton = FBSDKLoginButton()
        self.view.addSubview(loginView)
        loginView.center = self.view.center
        loginView.readPermissions = ["public_profile", "email", "user_friends"]
        loginView.addTarget(self, action: "loginFb:", forControlEvents: UIControlEvents.TouchUpInside)

I have not been able to implement the Facebook button on a Scenexxx.m, I write:

-(void)viewdidLoad 
{
FBLoginView *loginView = [[FBLoginView alloc] init]; 
loginView.center = self.view.center; 
[self.view addSubview:loginView]; 
}

But Warning with loginView with this Warning: Property 'view' not found on object of type 'Scenexxx.m'

Please help me.

I'm creating an app. I've done some basic stuff so far, removed the main storyboard and added some components to the main viewcontroller with code and cartography for constraints

basically nothing is clickable, i have UITextFields that can't be focused and buttons that can't be clicked.

why this is happening? thanks

import UIKit
import Cartography

class LoginViewController: BaseViewController {

    var identifierField: UITextField!
    var passwordField: UITextField!

    override func loadUI() {
        view.clipsToBounds = true
        view.backgroundColor = UIColor.colorPrimary()

        let logoText = UILabel()

        let loginView = UIView()

        logoText.attributedText = NSMutableAttributedString.init(string: NSLocalizedString("APP_NAME", comment: ""))
        logoText.font = UIFont.boldSystemFontOfSize(32.0)

        self.view.addSubview(logoText)

        constrain(logoText, self.view) {
            logo, mainView in
            logo.top == mainView.top + 50
            logo.centerX == mainView.centerX
        }

        identifierField = UITextField()
        identifierField.borderStyle = .Line
        identifierField.placeholder = NSLocalizedString("USER_IDENTIFIER_PLACEHOLDER", comment: "")
        identifierField.textColor = UIColor.whiteColor()


        passwordField = UITextField()
        passwordField.borderStyle = .Line
        passwordField.placeholder = NSLocalizedString("PASSWORD_PLACEHOLDER", comment: "")
        passwordField.textColor = UIColor.whiteColor()


        let loginButton = UIButton()
        loginButton.setTitle(NSLocalizedString("LOGIN", comment: ""), forState: .Normal)

        let registrationButton = UIButton()
        registrationButton.setTitle(NSLocalizedString("REGISTER", comment: ""), forState: .Normal)
        registrationButton.addTarget(self, action: #selector(onRegistrationClicked(_:)), forControlEvents: .TouchUpInside)

        loginView.addSubview(identifierField)
        loginView.addSubview(passwordField)
        loginView.addSubview(loginButton)
        loginView.addSubview(registrationButton)

        view.addSubview(loginView)

        constrain(loginView, logoText, self.view) {
            loginView, logo, mainView in

            loginView.top == logo.bottom + 30
            loginView.width == mainView.width - 30
            loginView.centerX == mainView.centerX
        }

        constrain(loginView, identifierField, passwordField, loginButton, registrationButton) {
            loginView, identifierField, passwordField, loginButton, registrationButton in
            identifierField.top == loginView.top + 30
            identifierField.centerX == loginView.centerX
            identifierField.width == loginView.width

            passwordField.top == identifierField.bottom + 20
            passwordField.centerX == loginView.centerX
            passwordField.width == loginView.width

            loginButton.top == passwordField.bottom + 20
            loginButton.centerX == loginView.centerX
            loginButton.width == loginView.width

            registrationButton.top == loginButton.bottom + 20
            registrationButton.centerX == loginView.centerX
            registrationButton.width == loginView.width
        }
    }

    func onRegistrationClicked(sender: UIButton) {
        print("Register clicked")
        navigationController?.pushViewController(RegistrationViewController(), animated: true)
    }
}

I have a subView named loginView and within that a few other elements, namely loginButton and loginUsername

I am trying to programatically add a Facebook login button that has constraints relative to loginButton, loginView and loginUsername

Here is my code

self.loginView.addSubview(facebookLoginButton)

let facebookLoginButtonTopConstraint = NSLayoutConstraint(
      item: facebookLoginButton, 
      attribute: NSLayoutAttribute.Top, 
      relatedBy: NSLayoutRelation.Equal, 
      toItem: loginButton, 
      attribute: NSLayoutAttribute.Bottom, 
      multiplier: 1, 
      constant: 8
)

let facebookLoginButtonLeadingConstraint = NSLayoutConstraint(
      item: facebookLoginButton, 
      attribute: NSLayoutAttribute.Leading, 
      relatedBy: NSLayoutRelation.Equal, 
      toItem: loginView, 
      attribute: NSLayoutAttribute.Leading, 
      multiplier: 1, 
      constant: 8
)

let facebookLoginButtonWidthConstraint = NSLayoutConstraint(
      item: facebookLoginButton, 
      attribute: NSLayoutAttribute.Width, 
      relatedBy: NSLayoutRelation.Equal, 
      toItem: loginUsername, 
      attribute: NSLayoutAttribute.Width, 
      multiplier: 1, 
      constant: 0
)

self.loginView.addConstraints([
      facebookLoginButtonTopConstraint, 
      facebookLoginButtonLeadingConstraint
])
self.facebookLoginButton.addConstraint(facebookLoginButtonWidthConstraint)

This code is going in my viewDidLoad method. The error I'm getting is:

The view hierarchy is not prepared for the constraint: When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.

Any help greatly appreciated, thanks!

I'm trying to customize the PFLogInViewController and make the background a animated gif , something like that : https://medium.com/swift-programming/ios-make-an-awesome-video-background-view-objective-c-swift-318e1d71d0a2 . That's my code :

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *rs = [[NSString alloc]initWithFormat:@"%d", (arc4random()%4)+1] ;
    NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@%@",@"login_bk_" , rs] ofType:@"gif"];
    NSData *gif = [NSData dataWithContentsOfFile:filePath];

    UIWebView *webViewBG = [[UIWebView alloc] initWithFrame:self.logInView.frame];
    [webViewBG loadData:gif MIMEType:@"image/gif" textEncodingName:nil baseURL:nil];
    webViewBG.userInteractionEnabled = NO;
    [self.logInView setLogo:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"waho text"]]];
    [self.logInView.logInButton setTitle:@"Entrar" forState:UIControlStateNormal];
    self.logInView.usernameField.placeholder = @"Usuário" ;
    self.logInView.passwordField.placeholder = @"******" ;
    [self.logInView.passwordForgottenButton setTitle:@"Esqueceu a senha?" forState:UIControlStateNormal];
    self.logInView.signUpButton.titleLabel.text = @"Cadastrar-se" ;
    [self.logInView addSubview:webViewBG];

}

Thank you !

I use FBLoginView in my app and I want to Fetch UserInfo in another UIViewController.

I've read the document and it said "using multiple FBLoginView instances in different parts of your app"

I've write some code and it works fine. But I'm not sure if I did it right.

So... Here is what I've done:

LoginView

- (void)viewDidLoad {
[super viewDidLoad];
self.LoginView.readPermissions = @[@"public_profile",@"email",@"user_friends",@"user_birthday"];
self.LoginView.delegate = self;
}

- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView{
if (FBSession.activeSession.isOpen) {
    NSLog(@"login");
    [self dismissViewControllerAnimated:YES completion:nil];
}
}

anotherUIViewController

- (void)viewDidLoad {
[super viewDidLoad];
FBLoginView *fb = [[FBLoginView alloc]init];
fb.delegate = self;

}

-(void)viewDidAppear:(BOOL)animated{
if (!FBSession.activeSession.isOpen){
    [self presentViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"LoginView"] animated:YES completion:nil];
}
}

-(void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user{
self.ProfilePic.profileID = user.objectID;
self.nameLabel.text = user.name;
}

Did anybody face the same issue as I am?

I am trying to test a LoginPresenter, and I am using Mockito for the mocks. Mockito doesnt let me verify a method invocation on the SUT so I have to mock its dependencies and verify their methods have been called by the LoginPresenter.

I got to the following situation:

LoginPresenter has a method called attemptLogin:

private void attemptLogin(String username, String password) {
    new LoginNetworkOperation(username, password).execute();
}

I have to mock LoginNetworkOperation and using Mockito, verify the method invocation on execute().

@Test
public void testWhenUserNameAndPasswordAreEnteredShouldAttemptLogin() throws Exception {
    LoginView loginView = Mockito.mock(LoginView.class);
    LoginNetworkOperation loginNetworkOperation = Mockito.mock(LoginNetworkOperation.class);
    Mockito.when(loginView.getUserName()).thenReturn("George");
    Mockito.when(loginView.getPassword()).thenReturn("aaaaaa");
    loginPresenter.setLoginView(loginView);
    loginPresenter.onLoginClicked();
    Mockito.verify(loginNetworkOperation.execute());
}

However, how do I make LoginPresenter use the mocked LoginNetworkOperation instead of the one it creates in the attemptLogin method? I need to change the design of LoginPresenter to use a member variable, and provide a setter for it, which is suboptimal because a local variable in the method is plenty, as it is used only there.

Am I going about this whole thing wrong?

Initially, I wanted to verify that LoginPresenter's attemptLogin is called, but Mockito can only verify mocked objects' methods and I cannot spy on LoginPresenter because it is final (generated by AndroidAnnotations)

I have a simple login form which looks like this.

enter image description here

When the keyboard appears in portrait, it doesn't interfere with the controls. But In landscape it pretty much covers everything.

enter image description here enter image description here

So I decided to add a UIScrollView and when the keyboard appears, push the controls up to be visible.

My first try was using the IB. I added a scrollview first and pinned it to the superview from all 4 sides. Then I added the login controls on top of it and added the same constraints to them as I had before. But when I run it, it's messed up. I'm getting multiple auto layout errors as well.

enter image description here enter image description here

I think the main cause for all these is the error Scroll View has ambiguous scrollable content height.

enter image description here

Since the IB failed me, I set out to add a scrollview programmatically.

import UIKit

class LoginViewController: UIViewController {

    @IBOutlet private var loginView: UIView!

    private var scrollView: UIScrollView!

    override func viewDidLoad() {
        super.viewDidLoad()

        registerForKeyboardNotifications()
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        scrollView = UIScrollView(frame: view.bounds)
        scrollView.backgroundColor = UIColor.brownColor()
        scrollView.scrollEnabled = true

        view.insertSubview(scrollView, atIndex: 0)


        // Adding a tap gesture to the scroll view to dismiss the keyboard
        let tapGestureForView = UITapGestureRecognizer(target: self, action: "dismissKeyboard:")
        tapGestureForView.cancelsTouchesInView = false
        scrollView.addGestureRecognizer(tapGestureForView)
    }

    // MARK: - Keyboard Handling
    func dismissKeyboard(recognizer: UIGestureRecognizer) {
        view.endEditing(true)
    }

    func registerForKeyboardNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
    }

    // If the loginView is covered by the keyboard, get the height of the view portion that is covered, add 20 points to it and scroll it up.
    func keyboardWasShown(notification: NSNotification) {
        var info = notification.userInfo!
        var keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as NSValue).CGRectValue()
        var loginFormFrame: CGRect = view.convertRect(loginView.frame, fromView: nil)
        var coveredFrame: CGRect = CGRectIntersection(loginFormFrame, keyboardFrame)

        scrollView.setContentOffset(CGPointMake(0, coveredFrame.height + 20), animated: true)
    }

    func keyboardWillBeHidden(notification: NSNotification) {
        scrollView.contentOffset = CGPointZero
    }
}

I initialize a scrollview and insert it below the loginView in the viewDidAppear method. As you can see below it gets added successfully. But there's a problem in the landscape. The scrollview doesn't resize itself to fit the landscape screen (I set the scrollview's background color to brown to see if its working correctly). The rest of the code handles the keyboard showing/hiding and pushing the loginView up to the visible area. This code has been tested before and it works but not in this case. Must be because the issue with the scrollview resizing in the landscape orientation.

enter image description here enter image description here

Then I tried setting constraints to the scrollview programmatically to pin it to all sides instead of defining a frame.

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    scrollView = UIScrollView()
    scrollView.backgroundColor = UIColor.brownColor()
    scrollView.scrollEnabled = true

    let leadingSpaceToSuperview = NSLayoutConstraint(item: scrollView, attribute: .Leading, relatedBy: .Equal, toItem: scrollView.superview, attribute: .Leading, multiplier: 1, constant: 0)
    let trailingSpaceToSuperview = NSLayoutConstraint(item: scrollView, attribute: .Trailing, relatedBy: .Equal, toItem: scrollView.superview, attribute: .Trailing, multiplier: 1, constant: 0)
    let topSpaceToSuperview = NSLayoutConstraint(item: scrollView, attribute: .Top, relatedBy: .Equal, toItem: scrollView.superview, attribute: .Top, multiplier: 1, constant: 0)
    let bottomSpaceToSuperview = NSLayoutConstraint(item: scrollView, attribute: .Bottom, relatedBy: .Equal, toItem: scrollView.superview, attribute: .Bottom, multiplier: 1, constant: 0)

    scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
    scrollView.addConstraints([leadingSpaceToSuperview, trailingSpaceToSuperview, topSpaceToSuperview, bottomSpaceToSuperview])

    println("\(scrollView.bounds.width) -\(scrollView.bounds.height)") // returns 0 for both width and height
    view.insertSubview(scrollView, atIndex: 0)


    // Adding a tap gesture to the scroll view to dismiss the keyboard
    let tapGestureForView = UITapGestureRecognizer(target: self, action: "dismissKeyboard:")
    tapGestureForView.cancelsTouchesInView = false
    scrollView.addGestureRecognizer(tapGestureForView)
}

But then the scrollview doesn't appear at all!

I'm asking for either of the following solutions.

  • How to create the same layout as I have at first but with a scrollview through IB without the autolayout errors.

or

  • What am I doing wrong when adding the scrollview programmatically?

I'd really appreciate any help. I also uploaded a test Xcode project with this issue to Dropbox.

Thank you.

I've been playing around with the MVP pattern for a few weeks now and I've come to the point where I need context to start a service and access Shared Preferences.

I've read that the purpose of MVP is to decouple the view from the logic and having context within a Presenter may defeat that purpose (correct me if I'm wrong on this).

Currently, I have a LoginActivity that looks something like this:

LoginActivity.java

public class LoginActivity extends Activity implements ILoginView {

private final String LOG_TAG = "LOGIN_ACTIVITY";

@Inject
ILoginPresenter mPresenter;
@Bind(R.id.edit_login_password)
EditText editLoginPassword;
@Bind(R.id.edit_login_username)
EditText editLoginUsername;
@Bind(R.id.progress)
ProgressBar mProgressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    MyApplication.getObjectGraphPresenters().inject(this);
    mPresenter.setLoginView(this, getApplicationContext());
}

@Override
public void onStart() {
    mPresenter.onStart();
    ButterKnife.bind(this);
    super.onStart();
}

@Override
public void onResume() {
    mPresenter.onResume();
    super.onResume();
}

@Override
public void onPause() {
    mPresenter.onPause();
    super.onPause();
}

@Override
public void onStop() {
    mPresenter.onStop();
    super.onStop();
}

@Override
public void onDestroy() {
    ButterKnife.unbind(this);
    super.onDestroy();
}

@OnClick(R.id.button_login)
public void onClickLogin(View view) {
    mPresenter.validateCredentials(editLoginUsername.getText().toString(),
            editLoginPassword.getText().toString());
}

@Override public void showProgress() { mProgressBar.setVisibility(View.VISIBLE); }

@Override public void hideProgress() {
    mProgressBar.setVisibility(View.GONE);
}

@Override public void setUsernameError() { editLoginUsername.setError("Username Error"); }

@Override public void setPasswordError() { editLoginPassword.setError("Password Error"); }

@Override public void navigateToHome() {
    startActivity(new Intent(this, HomeActivity.class));
    finish();
}

Presenter Interface ILoginPresenter.java

public interface ILoginPresenter {
public void validateCredentials(String username, String password);


public void onUsernameError();

public void onPasswordError();

public void onSuccess(LoginEvent event);

public void setLoginView(ILoginView loginView, Context context);

public void onResume();

public void onPause();

public void onStart();

public void onStop();
}

Lastly, my Presenter:

LoginPresenterImpl.java

public class LoginPresenterImpl implements ILoginPresenter {

@Inject
Bus bus;

private final String LOG_TAG = "LOGIN_PRESENTER";
private ILoginView loginView;
private Context context;
private LoginInteractorImpl loginInteractor;

public LoginPresenterImpl() {
    MyApplication.getObjectGraph().inject(this);
    this.loginInteractor = new LoginInteractorImpl();
}

/**
 * This method is set by the activity so that way we have context of the interface
 * for the activity while being able to inject this presenter into the activity.
 *
 * @param loginView
 */
@Override
public void setLoginView(ILoginView loginView, Context context) {
    this.loginView = loginView;
    this.context = context;

    if(SessionUtil.isLoggedIn(this.context)) {
        Log.i(LOG_TAG, "User logged in already");
        this.loginView.navigateToHome();
    }
}

@Override
public void validateCredentials(String username, String password) {
    loginView.showProgress();
    loginInteractor.login(username, password, this);
}

@Override
public void onUsernameError() {
    loginView.setUsernameError();
    loginView.hideProgress();
}

@Override
public void onPasswordError() {
    loginView.setPasswordError();
    loginView.hideProgress();
}

@Subscribe
@Override
public void onSuccess(LoginEvent event) {
    if (event.getIsSuccess()) {
        SharedPreferences.Editor editor =
                context.getSharedPreferences(SharedPrefs.LOGIN_PREFERENCES
                        .isLoggedIn, 0).edit();
        editor.putString("logged_in", "true");
        editor.commit();

        loginView.navigateToHome();
        loginView.hideProgress();
    }
}

@Override
public void onStart() {
    bus.register(this);
}

@Override
public void onStop() {
    bus.unregister(this);

}

@Override
public void onPause() {

}

@Override
public void onResume() {
}

As you can see, I passed the context from the Activity into my Presenter just so I can access the Shared Preferences. I'm quite worried about passing the context into my presenter. Is this an okay thing to do? Or should I be doing it some other way?