Categories
Android

Photo manipulation using Kotlin

How to simplify it

Adding photos from a gallery or camera has become one of the most popular features in Android nowadays. However, to me, when I was a junior developer starting a project from scratch, after researching existing articles on the web, the topic has seemed quite tricky. Having this in mind, I wanted to try and simplify this subject as much as it was possible.

A sample project for this tutorial can be found on Github repository: https://github.com/Crystal-Pigeon/photo-manipulation.

So, if you are someone who has come across this project demand by using Kotlin programming language, keep on reading. I hope I succeeded in making it easier for you.

Project Setup

First of all, to enable manipulating with photos, we need to add next two lines in our AndroidManifest.xml file, in order to have access to internal and external storage on our mobile device:

<code class="language-xml">
&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
&lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</code>

In my project, I have one activity named MainActivity, and one fragment named PhotoFragment. In the fragment’s layout resource file, it is important to have an ImageView that will display the selected image.

Implementation

So now we have an ImageView with id iv_photo (the name is optional), and button with id btn_change_photo,  which is important so that we can access it from code.

In our fragment, it is important to have two request codes, based on which we can make a difference whether the user has picked a photo or captured a photo. I’ll explain this in more detail later in the text.

<code class="language-kotlin">
private val PICK_IMAGE = 1
private val TAKE_PHOTO = 2
</code>

To display a dialog that allows us to choose whether we want to pick an existing image from the gallery or we want to take the picture, we need to add a click listener to our Button in the PhotoFragment. Then, we create an array of options that we want to offer to the user – he can choose to pick a photo from the gallery or to take the photo. When the user clicks on one of those two items, the variable holds information about which option is clicked and based on that information, it calls the appropriate method. 

<code class="language-kotlin">
btn_change_photo.setOnClickListener {
   val items = arrayOf("Pick photo", "Take photo")
   AlertDialog.Builder(context)
       .setTitle("Pick from:")
       .setItems(items) { dialog: DialogInterface?, which: Int ->
           when (which) {
               0 -> this.pickPhoto(PICK_IMAGE)
               1 -> context?.let { context -> takePhoto(TAKE_PHOTO, context) }
           }
       }
       .show()
}
</code>

If the user selects the Pick photo option, method pickPhoto is called and PICK_IMAGE request code is being sent as an argument.

<code class="language-kotlin">
private fun pickPhoto(code: Int) {
   Intent(
       Intent.ACTION_PICK,
       MediaStore.Images.Media.EXTERNAL_CONTENT_URI
   ).apply {
       startActivityForResult(Intent.createChooser(this, getString(R.string.pick_image)), code)
   }
}
</code>

In pickPhoto method, we work with Intents. Intents are the way components communicate with each other. It opens the Gallery app and allows the user to pick a photo, after which we create Intent with action ACTION_PICK. Then we call startActivityForResult, in which we pass created intent and request code. This will allow executing the rest of our code once the photo is picked from the gallery. 

After the user is done with picking a photo from the gallery, the method onActivityResult is called in our fragment.

<code class="language-kotlin">
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {
       if (data != null) {
           val imageUri = data.data
           if (imageUri != null) {
               cropRequest(imageUri)
           }
       }
super.onActivityResult(requestCode, resultCode, data)
   }
</code>

This is where our previously created PICK_IMAGE request code comes to rescue. Here we check if the user has picked an image from the gallery. We can access image uri by calling data.data field, and after that, we call cropRequest method, in which we pass image uri. 

If you don’t want to implement cropping, this is where you can set picked image to ImageView. 

In order to cropping images work as expected, first we need to add dependency to build.gradle (app):

<code class="language-kotlin">
//Image cropper library
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
</code>

… and CropImageActivity to our AndroidManifest.xml:

<code class="language-xml">
&lt;activity
   android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
   android:theme="@style/Base.Theme.AppCompat">
</code>

The reason why i chose to use this Image cropper library is to avoid problem with automatic photo rotation which occurs on certain Android devices.

In ProfileSettingsFragment, we must create a cropRequest method which receives image uri.

<code class="language-kotlin">
private fun cropRequest(uri: Uri) {
   CropImage.activity(uri).setCropMenuCropButtonTitle("Select")
       .setGuidelines(CropImageView.Guidelines.ON)
       .setMultiTouchEnabled(true)
       .start(activity as MainActivity)
}
</code>

CropImageActivity allows users to crop images as they want. After the user finishes cropping, MainActivity is being called, which is why we need the onActivityResult method in MainActivity also – to handle the cropped image. Here, we check if the user is finished with cropping the image, and then we process the image. To display the cropped image in PhotoFragment, we call the method from fragment and pass selected images uri.

<code class="language-kotlin">
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
       val result = CropImage.getActivityResult(data)
       val inputStream: InputStream
       if (resultCode == Activity.RESULT_OK) {
           try {
               contentResolver.openInputStream(result.uri)?.let {
                   inputStream = it
                   result.uri?.let {
                       val fragment =
                           nav_host_fragment.childFragmentManager.fragments[0] as PhotoFragment
                       fragment.addPhoto(it)
                   }
               }
           } catch (e: IOException) {
               e.printStackTrace()
               Toast.makeText(this, R.string.unable_to_open_image, Toast.LENGTH_SHORT).show()
           } catch (ex: Exception) {
               ex.printStackTrace()
           }
       }
   }
   super.onActivityResult(requestCode, resultCode, data)
}
</code>

To display uri inside ImageView, we can use Glide library, which we should add in build.gradle (app)

<code class="language-kotlin">
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
</code>

Method for displaying photo in ImageView looks like follows:

<code class="language-kotlin">
fun addPhoto(uri: Uri) {
   context?.let {
       Glide.with(it)
           .load(uri).circleCrop()
           .into(iv_photo)
   }
}
</code>

That is the full process of picking an image from the gallery explained. But, what if the user wants to take a photo using the camera? Let’s go back to our dialog in which the user can choose to pick a photo from the gallery or capture one using a camera. If he chooses a second option, the method takePhoto is being called, and we pass our request code and context.

<code class="language-kotlin">
private var currentPhotoPath: String? = null
private fun takePhoto(code: Int, context: Context) {
   Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
       takePictureIntent.resolveActivity(context.packageManager)?.also {
           val photoFile: File? = try {
               createImageFile(context)
           } catch (ex: IOException) {
               null
           }
           photoFile?.also {
               val photoURI: Uri = FileProvider.getUriForFile(
                   context,
                   "com.crystalpigeon.photo_manipulation_app.fileprovider",
                   it
               )
               takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
               startActivityForResult(takePictureIntent, code)
           }
       }
   }
}

private fun createImageFile(context: Context): File {
   val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
   val storageDir: File? = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
   return File.createTempFile(
       "JPEG_${timeStamp}_",
       ".jpg",
       storageDir
   ).apply {
       currentPhotoPath = absolutePath
   }
}
</code>

In the takePhoto method, we create an Intent that will open the Camera application for taking the photo. Once a user takes the photo, onActivityResult method in our fragment is being called. But, before that, when the user takes the photo, for that photo we need to create file, in order to have access to the original photo, and not just the thumbnail. For this to work, we need to add file_paths.xml file in res -> xml folder, in which we specify root path and external path for our file.

File_paths.xml:

<code class="language-xml">
&lt;xml version="1.0" encoding="utf-8"?>
&lt;paths>
   &lt;root-path name="root" path="." />
   &lt;external-files-path name="my_images" path="Android/data/com.crystalpigeon.photo_manipulation_app/files/Pictures" />
&lt;/paths>
</code>

It is important to notice that the path variable should have your application’s package name.

Also, we must add the next few lines of code to AndroidManifest.xml. But keep in mind that here you also have to specify your package name:

<code class="language-xml">
&lt;provider
   android:name="androidx.core.content.FileProvider"
   android:authorities="com.crystalpigeon.photo_manipulation_app.fileprovider"
   android:exported="false"
   android:grantUriPermissions="true">
   &lt;meta-data
       android:name="android.support.FILE_PROVIDER_PATHS"
       android:resource="@xml/file_paths"/>
&lt;/provider>
</code>

Back to our onActivityResult method in PhotoFragment. Here we only need to add one more condition in order to proceed with the photo taken using the camera. While the file was being created in the createImageFile method, we saved absolutePath in our variable currentPhotoPath. Here, we just check if that currentPhotoPath contains some value, and if it does, we create File using that path, we create uri from file and call the cropRequest method which we pass created uri. This is our onActivityResult method now:

<code class="language-kotlin">
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
   if (requestCode == PICK_IMAGE && resultCode == Activity.RESULT_OK) {
       if (data != null) {
           val imageUri = data.data
           if (imageUri != null) {
               cropRequest(imageUri)
           }
       }
   } else if (requestCode == TAKE_PHOTO && resultCode == Activity.RESULT_OK) {
       if (currentPhotoPath != null) {
           val myFile = File(currentPhotoPath as String)
           val imgUri = Uri.fromFile(myFile)
           cropRequest(imgUri)
       }
   }
   super.onActivityResult(requestCode, resultCode, data)
}
</code>

Everything else remains the same – the cropRequest method calls CropImage activity. After the user finishes cropping, the onActivityResult method in MainActivity is called, and there we process the cropped image and send it back to PhotoFragment.

And that’s it. I hope someone finds this article useful for working with images in future Android projects.

Categories
iOS

Tutorial: Create a custom alert view

8 steps to your own UIAlertViewController

The UIAlertViewController is a common and simple-to-use UI component that serves for asking users to enter some data or to notify them about certain events. Unfortunately, this class cannot be customized and that’s why, in this tutorial, I will show you how to create your own completely custom UIAlertViewController.

This is what you are going to get:

The code for the project can be seen on:

https://github.com/Crystal-Pigeon/CustomAlert

These are steps you’ll have to take:

  1. Create the UI
  2. Create the class and connect the UI with the class
  3. Present the alert
  4. Cancel the alert
  5. Make the background darker
  6. Move the alert when the keyboard gets shown
  7. Enable the OK button
  8. Pass data from the alert to the ViewController

Create the UI

Create a xib file

The first step is to create a xib (XML Interface Builder) file. In this file you can design your custom UIView, similarly to how you design custom UIViewControllers through storyboards. To create this file right click on your project in the project navigator and click new file. Choose the View template and click next. Give a name to your custom alert view and click next.

Create the layout

Open the newly created xib file. Click on the view and open the Attributes Inspector. Change size from inferred to freeform. Now you can resize the view, set it so that it has approximately the intended size.

Create the layout through the interface builder. You can create whatever UI you need. I created a simple view that contains a title, a textfield, a label with a switch, and two buttons.

Create the class and connect the UI with the class

Create a swift file

To add some logic to the created view, you need to create a corresponding swift file. Right-click on your project in the project navigator and click the new file. Choose Swift file. Name this file the same as you named your xib file.

Create a UIView subclass

In that file create a subclass of UIView. This class will represent your custom alert.


import UIKit

class AlertView: UIView {
 
}

Open the xib file, click on the view and open the Identity Inspector. Set the class to the newly created class.

Now you can connect IBOutlets by dragging the views from the xib file to the swift file.


// MARK: – IBOutlets
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var configurationNameTextField: UITextField!
@IBOutlet weak var switchButton: UISwitch!
@IBOutlet weak var cancelButton: UIButton!
@IBOutlet weak var okButton: UIButton!

Create initial methods

Create a method in which you will perform the basic setup of your view. In this example the background color of the alert view is set to white, a light gray border with a width of 1 is added, and a corner radius is set to 4. Also, the okButton is initially disabled.

<code class="language-swift">
    private func setupView() {
    self.backgroundColor = .white
    self.layer.borderColor = UIColor.lightGray.cgColor
    self.layer.borderWidth = 1
    self.layer.cornerRadius = 4
    self.okButton.isEnabled = false
}
</code>

Create a class method which will be called from the ViewController where you will instantiate this alert. If you don’t know, class methods are the same as static methods, but they can be overridden by subclasses, whereas static methods can never be overridden. The reason why this method is a class method and not a regular method is that this method will be called to create a new instance, which means that it cannot be called on some instance which is the case with regular methods.

This method creates the alert from the specified nib file and calls the basic setup method. Make sure that the parameter nibName is the same as the name of your xib file. If you’re wondering what a nib(NeXTSTEP Interface Builder) is, it is essentially the same as xib, it’s just that the xib file is used while developing, whereas nib files are produced when you create a build.

<code class="language-swift">
class func instanceFromNib() -> AlertView {
    let view = UINib(nibName: "AlertView", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! AlertView
    view.setupView()
    return view
} 
</code>

Present the alert

To be able to show the alert view on a certain screen we will have to create an instance of the AlertView class. Add a lazy instance of the AlertView to the ViewController that will use it.

A lazy modifier ensures that the initial value will not be calculated until the first time this property gets called. This modifier is usually used when the initial value of a property requires complex computation and therefore should not be initialized if it will not be used. That is the case with our custom alert. There is a possibility that the user will not need it.

A closure is being used to initialize this property. It may look like a computed property but this value is calculated only once, which is different in the case of using a computed property.

In the closure, we will call the instanceFromNib class method that we previously created and set the translatedAutoresizingMaskIntoConstraints property to false. This will allow us to create auto layout constraints for the alert.

<code class="language-swift">
private lazy var alertView: AlertView = {
    let view = AlertView.instanceFromNib()
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()
</code>

When you want to show the alert on the screen add it as a subview to the main view of the view controller and add constraints. I set the alert in the vertical center of the screen and put 10 point spacing from the right and left edge of the screen.

<code class="language-swift">
@IBAction func openAlert(_ sender: Any) {
      self.view.addSubview(alertView)
    NSLayoutConstraint.activate([
        alertView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 10),
        alertView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10),
            alertView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0)
    ])
}
</code>
And now a simple AlertView is created.

… But the cancel button does not work.

Let’s fix it.

Cancel the alert

A great practice to make your custom views reusable in different ViewControllers is to create a delegate protocol. That way, any ViewController that conforms to that protocol will be able to use this alert. Create the delegate protocol and declare a method for removing the alert. 

<code class="language-swift">
protocol AlertViewDelegate {
    func removeAlert(sender: AlertView)
}
</code>

Add an optional delegate property to your alert class. This property has to be public because it will be initialized in the ViewController where the alert gets used.

<code class="language-swift">
// MARK: - Properties
var delegate: AlertViewDelegate?
</code> 

Drag an IBAction from the cancel button and call the removeAlert method of the delegate.

<code class="language-swift">
@IBAction func cancel(_ sender: Any) {
    self.delegate?.removeAlert(sender: self)
}
</code>  

The ViewController should implement the alertViewDelegate protocol. All you have to do is remove the alert from superview.

<code class="language-swift">
extension ViewController: AlertViewDelegate {
    func removeAlert(sender: AlertView) {
        sender.removeFromSuperview()
    }
}
</code>

Set the delegate property of the alert to self when initializing it in the ViewController.

<code class="language-swift">
private lazy var alertView: AlertView = {
    let view = AlertView.instanceFromNib()
    view.translatesAutoresizingMaskIntoConstraints = false
    view.delegate = self
    return view
}()
</code>

Ok, the cancel button now works, but would it not be nice if the background got a little darker so that the alert stands out more?

Make the background darker

Create a UIView called backgroundView in the ViewController. Set the background color and the alpha to your linking. Also set the translatesAutoresizingMaskIntoConstraints property to true, so that we can add our own constraints.

<code class="language-swift">
private lazy var backgroundView: UIView = {
    let view = UIView()
    view.backgroundColor = .black
    view.alpha = 0.5
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()
</code>

Just before the code for showing the alert view add this code. First we will add the background as a subview and then pin the background to the edges of the view.

<code class="language-swift">
self.view.addSubview(backgroundView)
NSLayoutConstraint.activate([
            backgroundView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
            backgroundView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0),
            backgroundView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
            backgroundView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0)
        ])
</code>

Also, you will have to remove the background view when the alert gets canceled. Add this line of code in the view controllers implementation of the AlertViewDelegate protocol’s method removeAlert()

<code class="language-swift">
self.backgroundView.removeFromSuperview()
</code>
Now the alert stands out much better.

But how can a user now click on cancel when the keyboard is shown?

Let’s add code to fix this case.

Move the alert when the keyboard gets shown

We could move the alert up by adding a constant to the constraint that centers the alert view vertically. But right now that constraint is not reachable anywhere in the class. Therefore, let’s create a property that will represent that constraint.

Create a constraint property

Declare a new property alertViewConstraint in the view controller.

<code class="language-swift">
var alertViewConstraint: NSLayoutConstraint!
</code>

Instantiate it in viewDidLoad method. This constraint defines that the alert is centered vertically in the view controller.

<code class="language-swift">
override func viewDidLoad() {
    super.viewDidLoad()
    self.alertViewConstraint = NSLayoutConstraint(item: self.alertView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: 0)
}
</code>

In the method where you show the alert replace this:

<code class="language-swift">
NSLayoutConstraint.activate([
    alertView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 10),
    alertView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10),
    alertView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0)
])
</code>

… With this:

<code class="language-swift">
NSLayoutConstraint.activate([
    alertView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 10),
    alertView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -10),
    alertViewConstraint
])
</code>

The alert should work the same as it did before these changes.

Move the alert view

Next, create two methods. The first one will be called when the keyboard gets shown and in this method, we will raise the alert view up by 100 points.

The second method will be called when the keyboard disappears from the screen, and the alert will be put back in its original position.

You can move the keyboard by fewer or more points, it’s up to you.

<code class="language-swift">
@objc func keyboardWillShow(notification: NSNotification) {
    self.alertViewConstraint.constant = -100
}
   
@objc func keyboardWillHide(notification: NSNotification) {
    self.alertViewConstraint.constant = 0
}
</code>

In the viewdidLoad method add observers for keyboardwillhide and keyboard will show events. And call the method that will set the tap gesture on the screen.

<code class="language-swift">
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
</code>

Hide keyboard when the user taps anywhere on the screen

Add this code to hide the keyboard when the user touches anywhere on the screen.

<code class="language-swift">
func hideKeyboardWhenTappedAround() {
    let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    tap.cancelsTouchesInView = false
    self.view.addGestureRecognizer(tap)
    }
    
@objc func dismissKeyboard() {
    self.view.endEditing(true)
    }
</code>

In viewDidLoad method call the hidekeyboardWhenTappedAround method.

And here’s the final result you’ll get:

Enable the OK button

You should decide when the ok button should be enabled based on your business logic. In this example, the button should be enabled only when there is some text in the text field.

Firstly, extend the String class and add a new property that will check if the string is blank. The reason why I created a new property instead of using the well-known isEmpty property of String is that if the string contains just whitespaces the isEmpty property will return true and that is not what I want here.

<code class="language-swift">
extension String {
    var isBlank: Bool {
        return allSatisfy({ $0.isWhitespace })
    }
}
</code>

Secondly, create a method that will enable the button if the textfield is not blank and disable the button when the textfield is blank.

<code class="language-swift">
@objc private func editingChanged() {
    if self.configurationNameTextField.text!.isBlank {
        self.okButton.isEnabled = false
    } else {
        self.okButton.isEnabled = true
    }
}
</code>

Lastly, add this line to setupView method. Whenever any change happens to the textfield the method editingChanged will get called.

<code class="language-swift">
self.configurationNameTextField.addTarget(self, action: #selector(editingChanged), for: .editingChanged)
</code>
Now the alert view looks like this:

The last thing to do is to transfer data to the view controller.

Pass data from the alert to the ViewController

Add a new method to the delegate protocol. This method will pass data from the alert to the alert’s delegate.

<code class="language-swift">
protocol AlertViewDelegate {
    func removeAlert(sender: AlertView)
    func handleData(name: String, isAllowed: Bool)
}
</code>

Implement the method in the ViewController. In this example, the data will be shown on two labels in the ViewController.

<code class="language-swift">
func handleData(name: String, isAllowed: Bool) {
    configurationName.text = name
    if isAllowed {
        notificationsAllowedLabel.text = "Notifications are allowed"
    } else {
        notificationsAllowedLabel.text = "Notifications are not allowed"
    }
}
</code>

Drag and IBAction from the ok button in the storyboard to the class code. First, call the removeAlert method from the delegate because the alert should disappear from the screen after the user has clicked ok, and then call the handleData methods from the delegate.

<code class="language-swift">
@IBAction func ok(_ sender: Any) {
    self.delegate?.removeAlert(sender: self)
    self.delegate?.handleData(name: self.configurationNameTextField.text!, isAllowed: switchButton.isOn)
}
</code>
Congratulations! Your alert is finished!
Categories
Business

What made me a better leader

Challenges I faced in my early leadership career

I believe that most leaders when they were children did not use to say „leader“ when asked What would you like to be when you grow up?

The same was with me. As a child, I wanted to be an astronomer, but still, I focused on software engineering. Neither of those two professions specifically directed me towards leadership. However, during my schooling, I went to a competition in entrepreneurship and innovation. I was on the team with four, at the time unknown people. I did not impose myself to be a leader of the team, it happened instinctively and I led a team of people who have been professionals in areas such as economics, marketing, design… I enjoyed watching everyone working as a team to achieve one common goal – victory. Together we reached that goal, we won. Even then, not knowing it, I faced what was one of the main challenges in the leadership world. And that is how to lead people of different profiles, characteristics, and natures.

I recently read a great book on emotional intelligence in leadership written by the outstanding psychologist Dejan Zivkovic. Some of the conclusions he brought to light in his book I found extremely useful. That’s why I think is important to share some of them with you. I would like to start by highlighting the importance of leadership styles because it is these styles that can help leaders when working with different profiles of people.

  • Visionary style – When it comes to leadership, people in most cases imagine a leader as a person having this style. The feature of this style is that the leader has a vision and uses empathy to inspire people in the team to follow that vision and to believe in it. He is doing his best for that vision to be the goal of each individual, but also the goal of the whole team.
  • Affiliate style – A style in which the leader shows that he cares about the people in the team, and does his best to build a great relationship with each member individually. It’s crucial to cultivate empathy for each other among all team members. An affiliate leader inspires others with his example and shows his employees how their work contributes to achieving the goal.
  • Democratic style – Wants to involve the whole team in making important decisions, always asks for the opinion of team members trying to solve the problem together, and knows how to listen to his teammates.
  • Coaching style – A leader who is also a mentor, closely related to the profession in which he leads people. He leads others to find their strengths and weaknesses and to push their limits. „Coach“ mainly directs to what should be tried when solving problems but never tells solutions.
  • Tempo dictating style* – A leader with this style sets high standards and goals for himself and the whole team. He is focused on the quality of work and constant progress.

    *all of the mentioned styles were originally defined by Daniel Goleman.

It can look as if these styles are very similar or even the same. This is probably because when we imagine an ideal leader, we imagine him practicing each of the aforementioned styles. And I would agree with that.

As one of the founders and leaders at Crystal Pigeon, I do my best to master each of the styles above. I do this so my people can trust me, that they can enjoy while working with me, but also so that we can reach our common goal.

When I founded the company and started my career as a software engineer, I was a technical mentor to two people. In the beginning, my main task was to train and guide them technically so that they would become independent as soon as possible and so that we could distribute responsibilities as soon as possible. That’s when I got to know the coaching style. In the meantime, I realized that without a visionary style, I would not have been able to gather a team and inspire them to work with me.

As time went on, the members progressed differently. Each team member was showing individual abilities, and each of them had something to be predominantly good at.

I started to wonder how was it possible that one person, let’s call her Ruby, fails to solve problem X while a person, let’s call her Diamond, solves that problem like out of a hall. On the other hand, when a Y problem arises, Ruby enjoys solving it, while the same is unbelievably boring and stressful for Diamond. I realized that the key is the diversity in personalities.

Imagine that on the one hand, you are leading Diamond, an extremely talented person who needs to be directed towards the goal. At the same time, you are leading Ruby, a very creative person, who knows what the goal is and does her best to reach that goal. She is persistent but lacks a lot of technical experience and psychological support for personal development. If these two people were on the same team, working on the same projects, how would you balance their progress and task completion?

This is when my challenges on the path to a good leader begun.

I intuitively started my leadership career with a coaching style, and as time passed by, it became a sort of a habit for me.

The coaching-style started to lose its effect with Ruby because she often wandered to find a solution. That resulted in losing will, motivation, and results getting weaker. With Diamond, the coaching style continued to be effective as she progressed at her own pace. Still, I decided to try a democratic style within the whole team and let them make decisions for the problems that are in front of them. I wanted to encourage their creativity, and that turned out well at first because they got the impression that they were a part of what they were creating. They felt like they are not only there to solve the problem but to contribute with their ideas and decisions.

However, the problem with this approach was that sometimes the team was afraid because of the presumption that the leader was not sure of his decisions and therefore leaves it to the team to make a decision. Besides that, at times it was very stressful for the team to make decisions. I figured it was necessary to adjust style usage, so I used the democratic style only on adequate occasions. The tempo-dictating style proved to be great in moments when there was a lot of work to do. It allows the team to see and feel the progress, and each individual feels his value. This style should be applied in moderation, as it can often be stressful and lead the burnout.

If I said that the solution came of its own accord, I would be lying. It took lots of experience in leading, and we had to go through all these situations together, as a team, to realize what the solution is – applying different styles, at different times, and adjusting them to different people. Even today, I study and work on choosing the right style at the right time. I often succeed, but I still make mistakes.

However, besides the two people I mentioned above, there are other Crystals in our company that I work with and have to maintain a good and friendly relationship with. When I started to bring in people from the other fields I was not able to mentor them, because I did not have enough experience in their field. That is the time when you have to make decisions jointly. I had to be able to direct them towards the goal and then listen to them and believe they are the ones who will find a solution to any problem that arises in front of them.

I am not a leader with a lifetime of experience behind me, but the one thing I know is that every leader must master the visionary and affiliative style, and should constantly apply and improve them. The leader must be there for his people, take care of them, and sacrifice. That’s how he gains trust and how he gets the same from his people. A leader must be a visionary, he must know the path he leads his people so that they feel safe and see clearly where they are traveling.


Lead your team so that everyone enjoys and progresses because after all, that is the most important thing of them all.

Categories
All

How to effectively work from home

11+ tips you can easily implement in day to day routine

If you work from home, you probably often feel like your workday is monotonous. Sometimes you might lack the will and motivation, so you find it difficult to sit and work, or you feel like there are too many distractions around. In Crystal Pigeon, we have a remote work culture, so we feel you. The good thing is we do know stuff about the work-from-home lifestyle, so go ahead and see what are 11 of our golden work-from-home productivity advice.

Obviously, each individual will encounter different obstacles, given that we all have different lifestyles and do different types of work. However, there are some universal rules for everyone who does not work in the office. Whether you were always working from home, as a freelancer or in a team, or this new pandemic situation got you stuck in an unfamiliar situation, here you can find some practical advice you can implement in your day to day routine.

1. Set-up routine and schedule that suits your needs

First of all, you should take the time to realize and determine the daily rhythm and schedule that suits you best. You can read all the advice and researches on productivity in the world, but if the thought of waking up at 5.30 gives you nightmares, you shouldn’t even consider considering it. When you realize what you want your day to look like, you should set realistic expectations for daily accomplishments and do your best to stick to them.

Whatever you decide on, we recommend having an organized structure of the day. Maintaining a regular schedule provides day structure, but also helps you stay motivated. You don’t have to be strict – changing the time and the place from time to time could boost your productivity, but we recommend that your daily routine has some established elements. We work according to the established structure, from 9 am to 3 pm, because our team members unanimously decided so. If this seems monotonous, you could change your working hours by the days of the week, or the weeks in a month. To avoid monotony, it is good to determine the end of working hours and then change your location – go out and indulge yourself in some physical activity.

2. How to start aka. use coffee as a moral support

Think about what is the thing you can implement in your daily routine that can physically lead you to your workspace. Maybe it is coming back from a workout session, or dressing up in something you would normally go to work or a meeting? For the most disciplined ones, it can be just a clock indicating the time defined for starting with the work. If you don’t need to start in the morning, you can be creative about your routine… maybe it would suit you to firstly recharge your batteries at some social gathering, with family, or by taking a walk in nature?

Routine consists of rituals, so you should use rituals to make you sit and work. Actually, this is a pretty simple thing to do. For example, one of my rituals is coffee making. After I’m done with my morning routine (which ends with me having breakfast) I make myself my favorite coffee, take it to my desk and open my computer. My coffee is my moral support for begging work.

There is one trick regarding starting to work. It’s about stopping in the middle of something at the end of the working day. Allegedly this could make it easier to jump into the task the next day. We heard that Ernest Hemingway would try to leave in the middle of a paragraph at the end of the day so it would be easier for him to start writing the next day. It is a psychological thing – it is easier to start off when you know where you are going.

3. Bare desk = bright work?

There might be some saying stating that clear space means a clean mind, and we go by it. Clean your room, your desk, and make sure you have everything you need – on your desk, in your home office, and your home. 

Your working space should be comfy and you should enjoy being there. Except for tidiness, it should meet other requirements. Equip yourself with good desktop, mouse, printer, software, or whatever you need to do your job properly. If you need silence, make sure you have it. Make sure you are comfortable, especially make sure your chair is good for your posture. No one can be productive enough while having back pain. Think ahead of what are you going to eat, so that being hungry can’t make you stop in the middle of the work.

Decluttering can mentally prepare us for work activities so you could also use it as one of the rituals (as we wrote in the last paragraph). There is one thing to bear in mind – clean your space, but be careful you don’t get too involved in it. Tiding up could sometimes be used as a tool for procrastination.

4. Draw a line between private and work-related stuff

The line between business and private is very easily crossed while working from home. If you do your best not to mesh these two up, work will be much more productive. One way to do this is to find a way to physically separate these two. If you have the opportunity, make a separate place to work in your home, even if it is only a corner you’ll use exclusively for work.

Some of us who work remotely can function better in a public place. For some, this means they can focus better if they do not have the freedom to go to sit on the couch or pick up the phone. For such people, a good office could be public libraries, parks, coffee shops, restaurants, and similar places.

If you don’t live alone, let your family or roommates know that you are not available to communicate and do housework during working hours, except, perhaps, during breaks.

It is very important to define working hours, otherwise, there will always be something waiting for you to finish. We choose to work 6 hours a day, as it is known that shorter working hours boost productivity levels.

5. Your office is in your house, but your life is not your work

Just because your office happens to be in the same place you live, doesn’t mean that your day should be all about your work. We face this challenge all the time – how not to work when our laptop is available 24/7 and we always have an option to finish some stuff we’d left behind. We noticed that it was a problem for the other members of the team as well, so we defined working hours more clearly.

One trick that might help when we remember that we needed to do something or some creative solution pops into our minds during our free time. Instead of sitting at the computer and doing it, just write it down in a reminder for tomorrow. It takes 5 minutes, it makes you feel more relaxed and prepared for the next day. The best way to do this might be making sticky notes on the desktop, so reminders appear tomorrow as soon as you turn on the laptop.When you work 8 hours a day or more, it often turns into unproductive work. It is natural to simply lose the will to work at some point. So be careful not to overwork yourself. There is one thing that can help you stop working – schedule free-time activities immediately after work. That’s how you’ll know that you have to finish, as other activities are waiting. These days we enjoy riding bikes right after work. It combines three beautiful things – being in nature, physical activity, and socializing.

6. Respect your breaks as you respect your working-hours

This is pretty similar to the previous one, and we know you hear this annoyingly often, but here’s once again: take regular breaks. Newest researches showed that the best work-pause intervals are 52 minutes of work followed by a 17-minute break. Breaks don’t need to have any particular form – you can do whatever you enjoy doing, whether it is stretching, going for a walk, snacking, reading news, or watching favorite series. The only important thing is for your brain to relax.If it’s hard for you not to be around the computer during your break, you can use an app to keep you locked out of the computer for some time. Check out TimeOut for Mac or Smart Break for Windows. Just don’t do your job while you are on a break!

7. Make that extra effort not to feel lonely

For some, especially extroverts, sitting alone in the house could be a huge disadvantage. Lack of interpersonal relationships is inevitable, so you should put in an extra effort to see and talk to other people. Humans are social beings and it is normal to seek human contact.

We as a team are connected through Discord, the platform for messaging and video calls. We do our best to maintain contacts as much as possible. Our team leaders try to encourage each team member to communicate with others as much as possible, both through work-related topics and others.

Our 7th golden advice is to set up some kind of schedule for coffees or at least some online meetings with your colleagues, clients, or work peers. As long as your relationship with your superiors is concerned, you could set up a routine of making some kind of reports about the tasks you’ve accomplished that day. This could also be good for your productivity, motivation, and feeling of accomplishment.

For example, we found that music is a really good remedy for feelings of loneliness and monotony. As we are connected through Discord, we practice listening to music on Spotify together. It is a great opportunity to have fun and connect with your coworkers.

8. Multitasking is not an option

Sorry for ruining this for you, but please, just focus on one thing at a time. We understand it is tempting to do more things at once, but it is proven that multitasking significantly reduces productivity. Define time for small and big tasks and do them separately. Don’t try to code, design, or write while answering e-mails, phone calls, or coworkers’ questions. Don’t try to cook or feed your dog while trying to find the best creative solution for the current project. Try to avoid online distractions once you sit down to work. Turn the silent mode on, and put your phone away. 

One trick that might help you is to make a to-do list, but by mixing the schedule of big and small tasks. Set two small ones, check them off the list and you’ll be more motivated to do the third – the big one. Let that big one be followed by two small ones. This works well all the time.

9. Celebrate your wins

When you finish your work for the day, set aside 15 minutes to appreciate the things you’ve done. Check off the items on the daily to-do list. Think of what you did, instead of what you didn’t get to accomplish. You can also take notes about your accomplishments, it could help in keeping you motivated. And don’t forget to treat yourself.

10. Work on yourself

Working from home can often be much more demanding than working in an office. It requires certain qualities that are not so necessary when a person works in an office.

First of all, a person who works remotely must possess working habits. Work-in-pajamas lifestyle can make you unproductive if you are not self-disciplined and responsible. That being said, developing qualities such as self-discipline can help a lot.

Another thing you could work on is organizational skills. The organization is a productivity booster! Discipline doesn’t make much sense without organization and vice versa. When a person organizes his working hours, then it’s easier to know when you should focus on work, and when is the time to check up on social media, e-mail, or text a friend.

11. Stop thinking and get to work

Did you hear about Mel Robbins and her 5-second rule? You have loads of literature and videos on this online. In short, The 5 Second Rule is simple:

When you feel yourself hesitate before doing something that you know you should do,
count 5-4-3-2-1-GO and move towards action.

This is how you can prevent your mind from working against you. You can start before your mind starts to make all sorts of thoughts and excuses.

So what should you do? Just start counting backward to yourself: 5-4-3-2-1. And just start.

Is everyone in their positions? OK then, ready, set, go!


Things to remember:

  • Meet Routine and Schedule, they are your friends
  • The workplace is for work, and work only
  • Every work, no matter how big or small, should be appreciated and deserves to be rewarded. So treat yourself!

Things to avoid:

  • Burnout – if you were wondering if you should, take that break!
  • Isolation and disconnection
  • Multitasking

Crystal Pigeon originals:

  • Get yourself a pet to cheer you up
  • Make music your ally
  • Bike it away!
  • Find inspiration in nature

Categories
All

How we built a multiplayer game in 12 days

As a mobile apps development agency, we usually work with startups. Through various projects, we experienced what it’s like to start from the initial idea and get to the point where we have happy customers that use our product.

During the pandemic, we got an opportunity to develop an Easter mobile application, a game in which people could compete in duels between their Easter eggs. We liked the idea, but the deadline was a thing that really got us worried. However, we decided to do our best and take on this challenge.

Being one of the mobile team leaders I will try to guide you throughout the phases we went through and decisions we had to make while developing our easter game Egg Smash. Small projects are always good for learning as we can easily see the whole picture set in a short period. We learned a lot from this project, both as a team as well as individuals, so I hope you will learn something from it, too.

1. Use your time wisely

During the life cycle of such a project, a lot of things can come your way. The biggest obstacle is, of course, the time. If you don’t use it effectively, you can lose the interest of end customers, and in the end, money. 

In order to use the time you have wisely you have to make a good plan. When making the plan, try to split the time out on the main phases. Phases of our work process were these:

  1. Deciding to start the project 
  2. Discussing with stakeholders
  3. Defining specification
  4. Defining design 
  5. Development
  6. Fixing bugs
  7. Preparing marketing strategy
  8. Releasing the app and connecting with customers
  9. Celebrating
  10. Learning from users responses

2. Get your goals right!

Why is this step important? Well-defined, achievable goals will lead you through all your decisions, they’ll define your work roadmap. Having in mind why you started will affect and make all of the decision making easier, so take the time to write those goals down. If you follow simple rules of the SMART criteria, you’ll get rid of the fear of missing something out. There is a lot of sources you can find on defining your criteria and this is how we did it:

Create a game that will allow users to decorate easter eggs and use them to compete in fights with their friends and family who are not physically present. And create it until Easter.

Specific – We were specific about what is the must;

Measurable – We had responses from media and customers; 

Achievable – We had a well-established team, experienced in mobile development and marketing;

Relevant – It was relevant to us, as it synced with our company goals, as we like to experiment and learn from being invested in such interesting projects. It was also relevant for our community, as it made the holiday more enjoyable during the pandemic.

Time-bound – We were on a pretty strict schedule, but we had it well planned and under control.

3. Put the idea in writing

I’m sure you keep a lot of ideas in your head and I know that sharing those ideas in a way that others understand you can sometimes be challenging. Writing down the specifications can be energy-consuming for everyone involved.

To make things easier we defined three main domains of the app. Every part needed to fulfill our main goal.

Onboarding

Decorating an egg

Game

You should be aware that you are not able to know everything ahead, so keep it simple, and always have the goal in mind. You will polish everything in the design process.

4. Discuss idea productively

After you define your main idea, you need to discuss how it is going to work with as many stakeholders as possible. In my opinion, these are the most important parties you should include:

  • Initial idea owner
  • Potential customer 
  • Designer
  • Developers
  • Marketing team

The discussion needs to be productive and aligned with the goal you defined at the beginning. This can be tricky, considering that each person has their own, specific ideas and wishes. And yes, I know we have to be agile, so this is the point where you want to reconsider previous points in your writings. Teamed up with the designer, you’ll become one more step closer to your final product.

5. Find designer in yourself 

At the beginning the designer creates a basic design system, and a color palette. What you need to do is to make as many iterations with the designer to get everything done, and it is best to do it through real-time collaboration.

The software we used was Figma. Figma helped us get involved in the design process while we were fully remote. You have something on your mind but don’t know how to say it? Draw a simple wireframe with this simple tool and let the designer do the rest!. Your goal here is to define structure and get a bigger picture of the application, without spending too much time on the details.

After we made the prototype, we came back again with all stakeholders. In this process, we determined what was most important for each of them.

  • For the marketing team, it was important to match visuals for social networks and other media, and that URL of the game can be easily shared
  • For potential customer 
    • That Egg fights look realistic, which means we had to have more animations and details included
    • That Eggs look entertaining, which means we need to include various options for egg decoration

6. Find balance and beat the perfectionism

As a team leader, I had to determine how much effort we needed to implement in improving the app and still be able to make compromises that are important for the customer and, of course, to keep up with the tight schedule.

When we made the main design changes, we became sure there will not be any major changes further. As the app progressed, our priority became making the development as efficient as possible and getting the marketing team aligned with new visuals.

7. Sprint like a Bolt

As we had what was sure, the process of development could go parallelly with the minor design changes and marketing preparations. We defined two mini sprints – the first one was to create an MVP app starting on April the 3rd, while the second one was bound to start on April 9th. The next goal was to test, fix bugs, implement monetization, and extra features that will enhance UX.

We used SCRUM methodology (you can find a lot of resources on SCRUM methodology online), and these are it’s key points that helped us work effectively while being remote:

  • We always had daily meetings at the same time. That helped us sync iOS and Android platforms, share knowledge, and adapt to changes.
  • Using VivifyScrum we had everything we needed to set the visual representation of our progress.

Besides these, our big advantage is that we work together on different projects at the same time. Beyond the fact that we work together, we also studied together, so we build our team through different situations.

8. Just do it

When you get to the point to release your app, Google, and especially Apple can have specific rules in the review process. This time Google put us in a tough position. It announced that, due to Covid-19, the review process takes 7 days. We were left with only 3 days to develop the app that will fulfill the initial goal, and the hard decision was in front of us. Our thought was that if we are going to miss the release date on April 12th, there is no point to even try and release it. As this project was too exciting to give up that easily, we came up with the idea to make the simplest version of the app, to wait for the release, and to hope that update will be much faster. So that’s what we did. Fortunately, the app got released in 5 days and every succeeding update was live in the few hours over the night.

9. Deal with important mistakes

While programmers were working on developing the app, the marketing team did an excellent job. When the app was ready, the marketing plan was already on the table. Reactions started coming our way and most of them were the positive ones. There will always be some bugs, but bear in mind that you must resist fixing everything immediately. Only the critical ones, ones that are breaking the goal set at the beginning are something your team has to fix as soon as possible. That is what affects most of the users, so it is the only thing that must be addressed urgently. When the app was released we acknowledged we made a mistake while making improvements. It turned out we created a more critical bug that affected first users. We had to respond to the user so they could write proper feedback or make some workaround. Luckily it was fixed before Easter and everyone got their chance to be at the top of the leaderboard with the hardest egg!

10. Smash the eggs!

We, as the Crystal Pigeon team, believe that a job well done must be appreciated. After a finished work, don’t forget to take a deep breath, look back at the work process, acknowledge what you’ve done well and what mistakes were made, congratulate your team on a success and celebrate. And never forget to thank everyone who supported you. 

I will use this opportunity to thank the watfoi organization and the whole design and development team of 7 people who worked as one and made this happen!

Categories
iOS

Why we chose Texture to layout our UI elements

I remember the first time I heard about Texture. It was introduced to me at an early stage in my career as an iOS developer, and just at the moment when I finally got my head wrapped around the idea of how to work with UIKit and its storyboards. Was I excited to try out something new? Yes. Did I think I was ready for such a challenge at the moment? I don’t think I did. But was it worth it? It most definitely was!

Now, let me introduce you to the library we chose to incorporate into our layout routine.

Texture

Each method of building your UI has its advantages and disadvantages, and this one is no exception. One thing I can tell you straight away is that if you are looking for something that will fast forward the process of creating your app’s layout, or make your project smaller, this is not a solution for you. Anyways, you might get a little bit disappointed at first, but I promise you, it pays off later.

Texture requires you to build your layout just like you are building everything else when developing a mobile app – by writing code.  Yes, you read that right. So instead of dragging and dropping your components to the view, you will define them and arrange them in the class.

It is an iOS framework whose main purpose is to optimize your app by making user interfaces thread-safe. What this means is that you will be able to move all your views and view hierarchies on background threads, where you will prepare them before presenting them. This is the main reason why we love using it, as they make our apps faster, and leave the main thread available to focus on the execution of the app’s logic and data management, as well as to immediately respond to user interaction events.

However, Texture is not the only library that’s been developed to set up your layout programmatically. SnapKit is another example of such a library and the idea behind it was to simplify auto layout in iOS app development. Then why did we still chose Texture? Because, even though SnapKit is a library for itself, and it is not an integral part of Swift programing language, it still works with UIViews and uses UIKit to layout its components, thus throws off the app’s performance which is the exact thing we want to avoid.

Texture vs UIKit

Let’s start this comparison with the most obvious difference.

As you probably already know, storyboards let you build your layout by dragging the components onto the view itself, so the most noticeable difference between Texture and storyboards is that, when developing your app with Texture, there is no way to know how your layout will look until you run the app itself. At least at the beginning. 

However, when it comes to the components that Texture works with, there are a lot of similarities with the UIKit. Let me explain why.

Texture’s basic unit is node, from which all other nodes inherit. It represents an abstract over the UIView which is an abstract over the CALayer. Therefore if you know how to work with views, then you already know how to use nodes as well. Of course, in case you want to access node’s view or layer itself, you can do so by calling node.view or node.layer, since they are underlying views, just keep in mind that you have to perform those calls on the main thread.

Here are some examples of nodes and node containers and their equivalents in UIKit.

TextureUIKit
ASDisplayNodeUIView
ASTextNodeUILabel
ASImageNodeUIImageView
ASCellNodeUITableViewCell and UICollectionViewCell
TextureUIKit
ASViewControllerUIViewController
ASTableNodeUITableView
ASCollectionNodeUICollectionView
ASPagerNodeUIPageViewController

Texture vs SwiftUI

SwiftUI is an innovative way to build the UI of your app that uses a flexible box layout system and allows you to see the changes you make instantly on the preview as you type, as well as to see the change you make to preview immediately in your code. Many of its parts directly build on top of the existing UIKit components, but many other parts don’t, as they are new controls rendered by SwiftUI.

When compared to Texture and UIKit, SwiftUI seems to offer the best of both worlds, since it combines the technique of writing your layout through the code and previewing the changes you made so you can keep track of your UI elements the whole time.

Still, the main question remains: Is the advantage of the preview that SwiftUI brings to the table worth sacrificing the overall performance of the app since it also builds and runs its UI on the main thread?

What does this difference mean to us?

Using Texture has allowed us to bring out the quality of the apps we offer, making them more responsive and faster. It has taught us how to think beyond the fact that we have to lay out a bunch of elements on the screen. Also, it made us visualize our work, and see the components before they are put onto the screen. In the end, it showed us how to become more precise and focused, especially when it comes to details we did not think mattered as much.

When it comes to user interaction, now we can make our apps run more smoothly and we have the tool to customize all sorts of things meeting our or client’s likings.

Summary

One of the main things I learned while using Texture is that patience and creativity are the keys to improving layout. In case you were asking yourself why these two of all things, it’s because Google doesn’t know everything. Sure, it will help you in 95% of the time, but those 5% will also occur. And when that moment comes, you’ll need to combine your knowledge and the creative side of your brain to come up with a unique solution for your problem. On your way to finding the solution the patience will join the game as you will need it throughout your journey. 

Of course, if you prefer, you can always add a third party library and solve the problem, but trust me, it will feel much better if you come up with the solution on your own. Considering how adding another library may slow the app down, the result will be more satisfying, especially for the client.

All in all, I hope you found this post interesting and that it taught you something new. I urge you to give it a shot. Try it out and see if it fits your style of app development. Even if you don’t end up liking it, you will for sure learn something new and acquire new experience.