NewFiveFour | Blog | Portfolio


Bash: functions and arguments

A function is easily defined in a script as somename() { echo "blar" } which you then call via somename.

You can pass parameters like somename "hi there" and with the definition somename() { echo ${1}!! }.

bash

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

Page 3 of 77
Previous Next