NewFiveFour | Blog | Portfolio


Linux: Use TLP to save three hours of laptop battery

Install Linux Advanced Power Management:

add-apt-repository ppa:linrunner/tlp
apt-get update
apt-get install tlp tlp-rdw
tlp start

That should save your about two or three hours.

Disabling your touch screen is done via xinput. I disabled my touchscreen and touchscreen pen whatever that is.

Issue xinput -list and then xinput disable 100, where 100 is the the ID you found in xinput. That saves very little normally, but may be worth a go.

unix

Swift 3 and iOS: Form data and multipart uploads with URLRequest

If you want to upload an image to a server, an image from the photo gallery or camera for example, you often use a multipart request.

First create a POST Request as normal, with with a boundary string created via a UUID request and the content type as multipart/form-data with the boundary string.

var r  = URLRequest(url: URL(string: "https://prospero.uatproxy.cdlis.co.uk/prospero/DocumentUpload.ajax")!)
r.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
r.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

We must now create the http body. We use the below function, passing in parameters as a dictionary with strings, the boundary string we created, data from the UIImage, a mime-type and the filename for the image.

r.httpBody = createBody(parameters: params,
                        boundary: boundary,
                        data: UIImageJPEGRepresentation(chosenImage, 0.7)!,
                        mimeType: "image/jpg",
                        filename: "hello.jpg")

The createBody method first loops over the parameters dictionary, adding them to the body as a Content-Disposition with the boundary.

Finally, it adds the image as data, with the filename, the mime-type and with the boundary as before.

func createBody(parameters: [String: String],
                boundary: String,
                data: Data,
                mimeType: String,
                filename: String) -> Data {
    let body = NSMutableData()

    let boundaryPrefix = "--\(boundary)\r\n"

    for (key, value) in parameters {
        body.appendString(boundaryPrefix)
        body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
        body.appendString("\(value)\r\n")
    }

    body.appendString(boundaryPrefix)
    body.appendString("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n")
    body.appendString("Content-Type: \(mimeType)\r\n\r\n")
    body.append(data)
    body.appendString("\r\n")
    body.appendString("--".appending(boundary.appending("--")))

    return body as Data
}

The appendString doesn’t exist on a NSMutableData. It’s a helper extension as defined below:

extension NSMutableData {
    func appendString(_ string: String) {
        let data = string.data(using: String.Encoding.utf8, allowLossyConversion: false)
        append(data!)
    }
}

Now we have the URLRequest we can send it off as usual.

swift ios ios-urlrequest

Android: Style Toolbar/ActionBar and centre text

In recent support library updates, we have the Toolbar to use instead of the standard ActionBar to style via various properties in your style xml files.

You add this manually to your layout XML file.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  xmlns:tools="http://schemas.android.com/tools">
  <android.support.v7.widget.Toolbar
      android:id="@+id/toolbar"
      android:layout_alignParentTop="true"
      android:layout_width="match_parent"
      android:layout_height="?attr/actionBarSize"
      android:background="@color/toolbar_background"
      >
  ...

If you want to centre the title text, for example, you now just add a normal TextView and centre align it.

      <TextView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:textColor="@color/toolbar_text"
          android:gravity="center"
          tools:text="Some title"
          android:id="@+id/toolbar_text"
          style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"/>

Obviously this is a lot to put at the top of every activity, you can instead place it in a separate layout file and use an include directive:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include android:id="@+id/toolbar_layout"
        layout="@layout/toolbar_layout" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/toolbar_layout">
...

In order to give this the title of your activity, you add this code in your onStart() method, or anywhere after the layout has been inflated:

TextView toolbarText = (TextView) findViewById(R.id.toolbar_text);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if(toolbarText!=null && toolbar!=null) {
    toolbarText.setText(getTitle());
    setSupportActionBar(toolbar);
}

This will grab our toolbar, grab the text view which will hold our title, set the text on our text view and set the toolbar as our ActionBar.

Now when options menu etc, it will appear in that toolbar.

android android-toolbar

Android: Hiding the FAB and nested scroll events in CoordinatorLayout

The CoordinatorLayout helps you deal with nested scroll events from certain children, RecyclerView in our case.

If we place a RecyclerView and a FloatingActionBar in a CoordinatorLayout, we can tell the FAB to hide when we get a nested scroll event from the RecyclerView.

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coord"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rec_view"
        android:background="@android:color/holo_green_dark"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        >
    </android.support.v7.widget.RecyclerView>
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/star_big_on"
        app:layout_behavior="com.example.blar.myapplication.ScrollAwareFABBehavior"
        app:layout_anchorGravity="bottom|right|end"
        />
</android.support.design.widget.CoordinatorLayout

Note the FAB has app:layout_behavior pointing to a class. Let’s look at that now.

public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingActionButton>  {
  public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
    super();
  }

  @Override
  public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                                     final View directTargetChild, final View target, final int nestedScrollAxes) {
    return true;
  }

  @Override
  public void onNestedScroll(final CoordinatorLayout coordinatorLayout,
      final FloatingActionButton child,
      final View target, final int dxConsumed, final int dyConsumed,
      final int dxUnconsumed, final int dyUnconsumed) {
    super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,dxUnconsumed, dyUnconsumed);
    if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
      child.hide();
    } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
      child.show();
    }
  }
}

The first onStartNestedScroll method asks if we want to respond to a scroll event that happened in the CoordinatorLayout. We’re saying yes, but usually you say only on vertical scroll or what have you.

The the next onNestedScroll method, actually either hides or shows the FAB depending on the direction of scroll.

Each method have default implementations that return false and does nothing respectively.

android android-coordinatorlayout

Swift 3 and iOS: Choose an image with UIImagePickerController

If you want to use an image from your iOS device, you’ll want to use this. First put Privacy - Photo Library Usage Description with a string description into your Info.plist file.

Next define let picker = UIImagePickerController() and in your viewDidLoad() set its delegate as picker.delegate = self.

You can start it using:

  picker.allowsEditing = false
  picker.sourceType = .photoLibrary
  self.present(picker, animated: true, completion: nil)

Since we’ve made our class the delegate, you need to make the class use these protocols: UIImagePickerControllerDelegate, UINavigationControllerDelegate.

And we define two methods, one that dismisses the popup and another that grabs our image:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
    // use the image
    dismiss(animated: true, completion: nil)
}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
    dismiss(animated: true, completion: nil)
}

If you want to use the camera instead of the photo album, change your initialisation code to:

picker.allowsEditing = false
picker.sourceType = .camera
picker.cameraCaptureMode = .photo
swift ios

Page 3 of 77
Previous Next