DevDrawer

Additional

Language
Kotlin
Version
1.0.3 (Nov 2, 2018)
Created
Aug 6, 2018
Updated
Nov 2, 2018 (Retired)
Owner
Anton Kozyriatskyi (antonKozyriatskyi)
Contributor
Anton Kozyriatskyi (antonKozyriatskyi)
1
Activity
Badge
Generate
Download
Source code
APK file

Advertising

DevDrawer

Library that allows you to easily put various views into a side drawer, for controlling options you may need to change while developing your app (e.g. switch between production and dev urls or enabling/disabling logging) into a side drawer.

It actually just wraps your activity's root layout into a android.support.v4.widget.DrawerLayout.

How to use

In your activity or fragment call:

val settingsView: View = // inflate your view 
DevDrawer.attachTo(this /*activity*/, gravity = Gravity.END, contentView = settingsView)

Parameters

  • activity - activity, where to put drawer.
  • gravity - drawer's gravity. Must be one of Gravity.END, Gravity.START, Gravity.LEFT, Gravity.RIGHT. Default is Gravity.END
  • contentView - view, that will be put in drawer
  • optionsBody - function, that will be called on

Kotlin DSL builder

If you're using Kotlin, you can create layout with nice DSL:

// Create options
val devOptions = devOptions {

    checkbox {
        text = "Enable logging"

        onCheckedChange { isChecked -> showToast("Logging enabled: $isChecked") }
    }
    
    switch {
        text = "God mode"
        onCheckedChange { isChecked -> showToast("God mode switched: $isChecked") }
    }
    
    button {
        text = "Crash"
        onClick { throw Exception("Intended crash") }
    }
    
    spinner {
        item { "Auto" }
        addItem("Dark") // another way to add item to a spinner
        item { "Light" }
        
        onItemSelected { item, position -> showToast("$item at $position") }
    }
}

// And then pass options to the `attachView` function
DevDrawer.attachTo(this, gravity = Gravity.END, contentView = devOptions.view)

Or you can combine that steps into one:

DevDrawer.attachTo(this, gravity = Gravity.END) {

    checkbox {
            text = "Enable logging"
            onCheckedChange { isChecked -> showToast("Logging enabled: $isChecked") }
        }
        
        switch {
            text = "God mode"
            onCheckedChange { isChecked -> showToast("God mode switched: $isChecked") }
        }
        
        button {
            text = "Crash"
            onClick { throw Exception("Intended crash") }
        }
        
        spinner {
            item { "Auto" }
            addItem("Dark")
            item { "Light" }
            
            onItemSelected { item, position -> showToast("$item at $position") }
        }
}

Available DevOptions

Visit Creating custom option section, if you lack some options

ButtonOption

button(text = "Dangerous button") {
   text = "Dangerous button" // Title can also be set via property, this applies to all options that have text
   onClick { showToast("$title clicked") }
}

CheckBoxOption

checkbox {
    text = "Enable logging"
    onCheckedChange { isChecked -> showToast("Logging enabled: $isChecked") }
}

EditTextOption

editText {
     text = "localhost"
     hint = "Server url"
     onTextChanged { newText -> showToast(newText.toString()) }
}

RadioOption and RadioGroupOption

radioGroup {
    radioButton(isChecked = true) {
        text = "Send real requests"
    }
    radioButton {
        text = "Show error responses only"
    }
    radioButton(title = "Show success responses only")
    
    onCheckedChange { option ->
        showToast("${option.text} selected")
    }
}

SpinnerOption

spinner(mode = Spinner.MODE_DROPDOWN) {
    item { "Auto" }
    addItem("Dark") // another way to add item to a spinner
    item { "Light" }
    
    onItemSelected { item, position -> showToast("$item at $position") }
}

SwitchOption

switch {
    text = "God mode"
    isChecked = true
    
    onCheckedChange { isChecked -> showToast("God mode switched: $isChecked") }
}

TextOption

text { text = "Theme" }

ToggleOption

toggle {
    text = "Network state"
    textOn = "Connected"
    textOff = "Disconnected"
    onCheckedChange { isChecked -> showToast("Network: $isChecked") }
}

SeekbarOption

seekbar {
    progress = 5
    maxProgress = 10
    onProgressChanged { progress, fromUser -> showToast("Progress: $progress") }
}

ViewOption

Allows you to put any view in DevDrawer

view {
    val image = ImageView(this@DslDrawerActivity)
    image.setImageResource(R.mipmap.ic_launcher)
    image.setBackgroundColor(Color.BLACK)
    image
}

Section

Section allows you to group options related to some category. It actually just adds divider, text under divider (title) then views you specified in clojure and closing divider (optionally).

section(addClosingDivider = false) {
    title = "Network settings"

    toggle {
        text = "Network state"
        textOn = "Connected"
        textOff = "Disconnected"
        onCheckedChange { isChecked -> showToast("Network: $isChecked") }
    }

    editText {
        text = "localhost"
        hint = "Server url"
        onTextChanged { text -> showToast(text.toString()) }
    }

    checkbox {
        text = "Mock responses"
        onCheckedChange { isChecked -> showToast("Mock responses enabled: $isChecked") }
    }

    radioGroup {
        radioButton(isChecked = true) {
            text = "Send real requests"
        }
        radioButton {
            text = "Show error responses only"
        }
        radioButton(title = "Show success responses only")

        onCheckedChange { option -> showToast("${option.text} selected") }
    }
}

Divider

Basically it's just a view with specified height (default is 1dp), color (default is Color.LTGRAY) and width equal to parent's width.

divider {
    thickness = 1
    color = Color.LTGRAY
}

Creating custom option

If library doesn't provide you with option you need, you can create your own option by subclassing DevOption and overriding it's view: View property.

Example

Let's create FloatingActionButtonOption which is not included in library by default.

class FloatingActionButtonOption(context: Context) : DevOption(context) {

    override val view = FloatingActionButton(context)
    
    fun setImageResource(@DrawableRes id: Int) {
        view.setImageResource(id)
    }
    
    fun onClick(listener: (view: View) -> Unit) {
        view.setOnClickListener(listener)
    }
}

That's it! But for more convenient usage it'll be good to add builder function to DevOptions class.

fun DevOptions.fab(block: FloatingActionButtonOption.() -> Unit): FloatingActionButtonOption {
   val option = FloatingActionButtonOption(context)
   option.block()

   addOption(option)

   return option
}

So the callsite now looks like this:

DevDrawer.attachTo(this) {
    fab {
        setImageResource(R.mipmap.ic_launcher)
        onClick { showToast("FAB") }
    }
}

Code from this example can be found here FloatingActionButtonOption

Download

Add this in your root build.gradle at the end of repositories in allprojects section:

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

Then add this dependency to your module-level build.gradle in dependencies section:

implementation 'com.github.antonKozyriatskyi:DevDrawer:1.0.3'

License

   Copyright 2018 Anton Kozyriatskyi

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.