No more use of butterknife

This commit is contained in:
ligi 2016-10-28 17:49:00 +02:00
parent 6f969f4217
commit 5c2a1e743e
No known key found for this signature in database
GPG key ID: 8E81894010ABF23D
18 changed files with 249 additions and 306 deletions

5
Jenkinsfile vendored
View file

@ -1,3 +1,4 @@
node {
def flavorCombination='WithMapsWithAnalyticsForPlay'
@ -11,8 +12,8 @@ node {
} catch(err) {
currentBuild.result = FAILURE
} finally {
publishHTML(target:[allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "android/build/spoon-output/${flavorCombination}DebugAndroidTest", reportFiles: 'index.html', reportName: 'Spoon'])
step([$class: 'JUnitResultArchiver', testResults: 'android/build/spoon-output/*/junit-reports/*.xml'])
publishHTML(target:[allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "android/build/spoon", reportFiles: '*/debug/index.html', reportName: 'Spoon'])
step([$class: 'JUnitResultArchiver', testResults: 'android/build/spoon/*/debug/junit-reports/*.xml'])
}
}

View file

@ -16,7 +16,7 @@ buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'de.felixschulze.gradle:gradle-spoon-plugin:2.7.3'
classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
classpath 'de.mobilej.unmock:UnMockPlugin:0.5.0'
@ -27,7 +27,7 @@ buildscript {
apply plugin: 'android-sdk-manager'
apply plugin: 'com.android.application'
apply plugin: 'de.felixschulze.gradle.spoon'
apply plugin: 'spoon'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
@ -118,7 +118,6 @@ android {
dependencies {
kapt "com.google.dagger:dagger-compiler:$dagger_version"
kapt "com.jakewharton:butterknife-compiler:$butterknife_version"
provided 'org.glassfish:javax.annotation:10.0-b28'
@ -156,7 +155,6 @@ dependencies {
compile 'net.lingala.zip4j:zip4j:1.3.2'
compile "com.jakewharton:butterknife:$butterknife_version"
compile 'com.jakewharton.threetenabp:threetenabp:1.0.4'
compile 'org.greenrobot:eventbus:3.0.0'
@ -214,6 +212,7 @@ dependencies {
spoon {
debug = true
grantAllPermissions = true
}

View file

@ -11,4 +11,8 @@ public class TestApp extends App {
return (TestComponent) App.component();
}
@Override
public void installLeakCanary() {
}
}

View file

@ -3,7 +3,6 @@ package org.ligi.passandroid;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.widget.ImageView;
import butterknife.ButterKnife;
import com.squareup.spoon.Spoon;
import java.util.UUID;
import javax.inject.Inject;
@ -85,7 +84,7 @@ public class TheFullscreenBarcodeActivity {
rule.launchActivity(null);
onView(withId(R.id.fullscreen_barcode)).check(matches(isDisplayed()));
final ImageView viewById = ButterKnife.findById(rule.getActivity(), R.id.fullscreen_barcode);
final ImageView viewById = (ImageView) rule.getActivity().findViewById(R.id.fullscreen_barcode);
BitmapDrawable bitmapDrawable = (BitmapDrawable) viewById.getDrawable();
final Bitmap bitmap = bitmapDrawable.getBitmap();

View file

@ -1,7 +1,6 @@
package org.ligi.passandroid;
import android.annotation.TargetApi;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import java.util.ArrayList;
import javax.inject.Inject;
@ -75,7 +74,7 @@ public class ThePassViewActivity {
onView(withId(R.id.date)).check(matches(isDisplayed()));
}
@MediumTest
@Test
public void testLinkToCalendarIsThereWhenPassbookHasDate() {
act_pass.setCalendarTimespan(new PassImpl.TimeSpan(ZonedDateTime.now(), null, null));
rule.launchActivity(null);

View file

@ -19,13 +19,17 @@ public class App extends Application {
component = createComponent();
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
LeakCanary.install(this);
installLeakCanary();
AndroidThreeTen.init(this);
initTraceDroid();
AppCompatDelegate.setDefaultNightMode(component.settings().getNightMode());
}
public void installLeakCanary() {
LeakCanary.install(this);
}
public AppComponent createComponent() {
return DaggerAppComponent.builder().appModule(new AppModule(this)).trackerModule(new TrackerModule(this)).build();
}

View file

@ -47,7 +47,7 @@ class PassImpl(override val id: String) : Pass {
override var calendarTimespan: TimeSpan? = null
override var fields: List<PassField> = ArrayList()
override var fields: MutableList<PassField> = ArrayList()
override var locations: List<PassLocation> = ArrayList()

View file

@ -5,7 +5,6 @@ import android.support.v7.app.AlertDialog
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import butterknife.ButterKnife
import org.ligi.passandroid.R
import org.ligi.passandroid.helper.MoveHelper
import org.ligi.passandroid.model.PassStore
@ -39,7 +38,6 @@ internal class MoveToNewTopicUI(private val context: Activity, private val passS
move(newTopicEditText.text.toString())
}
}
ButterKnife.bind(this, dialog)
val oldTopic = passStore.classifier.getTopic(pass, "")

View file

@ -1,101 +0,0 @@
package org.ligi.passandroid.ui;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.design.widget.NavigationView;
import android.util.AttributeSet;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import javax.inject.Inject;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.ligi.axt.AXT;
import org.ligi.passandroid.App;
import org.ligi.passandroid.R;
import org.ligi.passandroid.events.PassStoreChangeEvent;
import org.ligi.passandroid.model.PassStore;
public class PassNavigationView extends NavigationView {
@BindView(R.id.pass_count_header)
TextView passCountTextView;
@BindView(R.id.topic_count_header)
TextView topicCountTextView;
@Inject
PassStore passStore;
@Inject
EventBus bus;
public PassNavigationView(Context context, AttributeSet attrs) {
super(context, attrs);
setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_plus:
AXT.at(getContext()).startCommonIntent().openUrl("https://plus.google.com/communities/116353894782342292067");
return true;
case R.id.menu_github:
AXT.at(getContext()).startCommonIntent().openUrl("https://github.com/ligi/PassAndroid");
return true;
case R.id.menu_share:
AXT.at(getContext()).startCommonIntent().shareUrl(getMarketUrl());
return true;
case R.id.menu_beta:
AXT.at(getContext()).startCommonIntent().openUrl("https://play.google.com/apps/testing/org.ligi.passandroid");
return true;
case R.id.menu_settings:
AXT.at(getContext()).startCommonIntent().activityFromClass(PreferenceActivity.class);
return true;
}
return false;
}
});
}
@Override
public View inflateHeaderView(@LayoutRes int res) {
final View view = super.inflateHeaderView(res);
ButterKnife.bind(this, view);
App.component().inject(this);
bus.register(this);
onPassStoreChangeEvent(PassStoreChangeEvent.INSTANCE);
return view;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
bus.unregister(this);
}
private String getMarketUrl() {
return getContext().getString(R.string.market_url, getContext().getPackageName());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPassStoreChangeEvent(PassStoreChangeEvent passStoreChangeEvent) {
final int passCount = passStore.getPassMap().size();
passCountTextView.setText(getContext().getString(R.string.passes_nav, passCount));
final int topicCount = passStore.getClassifier().getTopics().size();
topicCountTextView.setText(getContext().getString(R.string.categories_nav, topicCount));
}
}

View file

@ -0,0 +1,89 @@
package org.ligi.passandroid.ui
import android.content.Context
import android.support.annotation.LayoutRes
import android.support.design.widget.NavigationView
import android.util.AttributeSet
import android.view.View
import kotlinx.android.synthetic.main.navigation_drawer_header.view.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.ligi.axt.AXT
import org.ligi.passandroid.App
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.model.PassStore
import javax.inject.Inject
class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView(context, attrs) {
@Inject
lateinit internal var passStore: PassStore
@Inject
lateinit internal var bus: EventBus
init {
setNavigationItemSelectedListener(OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.menu_plus -> {
AXT.at(getContext()).startCommonIntent().openUrl("https://plus.google.com/communities/116353894782342292067")
return@OnNavigationItemSelectedListener true
}
R.id.menu_github -> {
AXT.at(getContext()).startCommonIntent().openUrl("https://github.com/ligi/PassAndroid")
return@OnNavigationItemSelectedListener true
}
R.id.menu_share -> {
AXT.at(getContext()).startCommonIntent().shareUrl(marketUrl)
return@OnNavigationItemSelectedListener true
}
R.id.menu_beta -> {
AXT.at(getContext()).startCommonIntent().openUrl("https://play.google.com/apps/testing/org.ligi.passandroid")
return@OnNavigationItemSelectedListener true
}
R.id.menu_settings -> {
AXT.at(getContext()).startCommonIntent().activityFromClass(PreferenceActivity::class.java)
return@OnNavigationItemSelectedListener true
}
}
false
})
}
override fun inflateHeaderView(@LayoutRes res: Int): View {
val view = super.inflateHeaderView(res)
App.component().inject(this)
bus.register(this)
onPassStoreChangeEvent(PassStoreChangeEvent)
return view
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
bus.unregister(this)
}
private val marketUrl: String
get() = context.getString(R.string.market_url, context.packageName)
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPassStoreChangeEvent(passStoreChangeEvent: PassStoreChangeEvent) {
val passCount = passStore.passMap.size
getHeaderView(0).pass_count_header.text = context.getString(R.string.passes_nav, passCount)
val topicCount = passStore.classifier.getTopics().size
getHeaderView(0).topic_count_header.text = context.getString(R.string.categories_nav, topicCount)
}
}

View file

@ -1,119 +0,0 @@
package org.ligi.passandroid.ui.edit;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.TextInputEditText;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import java.util.List;
import org.ligi.axt.simplifications.SimpleTextWatcher;
import org.ligi.passandroid.R;
import org.ligi.passandroid.model.pass.PassField;
public class FieldsEditFragment extends PassandroidFragment {
private final static String ARGUMENT_KEY = "KEY";
private boolean isEditingHiddenFields;
public static FieldsEditFragment create(boolean primary) {
final FieldsEditFragment fieldsEditFragment = new FieldsEditFragment();
final Bundle args = new Bundle();
args.putBoolean(ARGUMENT_KEY, primary);
fieldsEditFragment.setArguments(args);
return fieldsEditFragment;
}
@BindView(R.id.fields_container)
ViewGroup viewGroup;
@BindView(R.id.add_field)
Button addFieldButton;
@OnClick(R.id.add_field)
void onAddField() {
final PassField passField = new PassField(null, null, null, isEditingHiddenFields);
addField(passField);
getPass().getFields().add(passField);
}
private LayoutInflater inflater;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
this.inflater = inflater;
final View inflate = inflater.inflate(R.layout.edit_fields, container, false);
ButterKnife.bind(this, inflate);
isEditingHiddenFields = getArguments().getBoolean(ARGUMENT_KEY);
if (isEditingHiddenFields) {
addFieldButton.setText(R.string.add_back_fields);
} else {
addFieldButton.setText(R.string.add_front_field);
}
for (final PassField passField : getPass().getFields()) {
if (passField.getHide() == isEditingHiddenFields) {
addField(passField);
}
}
return inflate;
}
public void addField(final PassField passField) {
final ViewGroup child = (ViewGroup) inflater.inflate(R.layout.edit_field, viewGroup, false);
new FieldView(child).apply(passField, getPass().getFields());
viewGroup.addView(child);
}
class FieldView {
@BindView(R.id.label_field_edit)
TextInputEditText labelEdit;
@BindView(R.id.value_field_edit)
TextInputEditText valueEdit;
@BindView(R.id.delete_button)
ImageButton deleteButton;
FieldView(final ViewGroup container) {
ButterKnife.bind(this, container);
}
public void apply(final PassField passField, final List<PassField> fields) {
labelEdit.setText(passField.getLabel());
valueEdit.setText(passField.getValue());
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
((View) (v.getParent())).setVisibility(View.GONE);
fields.remove(passField);
}
});
valueEdit.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void afterTextChanged(final Editable s) {
passField.setValue(s.toString());
}
});
labelEdit.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void afterTextChanged(final Editable s) {
passField.setLabel(s.toString());
}
});
}
}
}

View file

@ -0,0 +1,88 @@
package org.ligi.passandroid.ui.edit
import android.os.Bundle
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.edit_field.view.*
import kotlinx.android.synthetic.main.edit_fields.view.*
import org.ligi.axt.simplifications.SimpleTextWatcher
import org.ligi.passandroid.R
import org.ligi.passandroid.model.pass.PassField
class FieldsEditFragment : PassandroidFragment() {
private var isEditingHiddenFields: Boolean = false
private lateinit var inflater: LayoutInflater
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
this.inflater = inflater
val inflate = inflater.inflate(R.layout.edit_fields, container, false)
isEditingHiddenFields = arguments.getBoolean(ARGUMENT_KEY)
if (isEditingHiddenFields) {
inflate.add_field.setText(R.string.add_back_fields)
} else {
inflate.add_field.setText(R.string.add_front_field)
}
for (passField in pass.fields) {
if (passField.hide == isEditingHiddenFields) {
addField(passField, inflate.fields_container)
}
}
inflate.add_field.setOnClickListener {
val passField = PassField(null, null, null, isEditingHiddenFields)
addField(passField, inflate.fields_container)
pass.fields.add(passField)
}
return inflate
}
fun addField(passField: PassField, viewGroup: ViewGroup) {
val child = inflater.inflate(R.layout.edit_field, viewGroup, false) as ViewGroup
FieldView(child).apply(passField, pass.fields)
viewGroup.addView(child)
}
internal inner class FieldView(val container: ViewGroup) {
fun apply(passField: PassField, fields: MutableList<PassField>) {
container.label_field_edit.setText(passField.label)
container.value_field_edit.setText(passField.value)
container.delete_button.setOnClickListener { v ->
(v.parent as View).visibility = View.GONE
fields.remove(passField)
}
container.value_field_edit.addTextChangedListener(object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) {
passField.value = s.toString()
}
})
container.label_field_edit.addTextChangedListener(object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) {
passField.label = s.toString()
}
})
}
}
companion object {
private val ARGUMENT_KEY = "KEY"
fun create(primary: Boolean): FieldsEditFragment {
val fieldsEditFragment = FieldsEditFragment()
val args = Bundle()
args.putBoolean(ARGUMENT_KEY, primary)
fieldsEditFragment.arguments = args
return fieldsEditFragment
}
}
}

View file

@ -1,42 +0,0 @@
package org.ligi.passandroid.ui.views;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import butterknife.ButterKnife;
import org.ligi.passandroid.R;
import org.ligi.passandroid.helper.CategoryHelper;
import org.ligi.passandroid.model.pass.PassType;
public class BaseCategoryIndicatorView extends LinearLayout {
private ImageView topImageView;
public BaseCategoryIndicatorView(Context context, AttributeSet attrs) {
this(context,attrs,R.layout.category_indicator_base);
}
public BaseCategoryIndicatorView(Context context, AttributeSet attrs, @LayoutRes final int layout) {
super(context, attrs);
LayoutInflater.from(context).inflate(layout, this, true);
topImageView = ButterKnife.findById(this,R.id.topImageView);
}
public void setImageByCategory(PassType category) {
if (category == null) {
topImageView.setVisibility(View.GONE);
} else {
topImageView.setVisibility(View.VISIBLE);
topImageView.setImageResource(CategoryHelper.INSTANCE.getCategoryTopImageRes(category));
}
}
public void setAccentColor(int color) {
setBackgroundColor(color);
}
}

View file

@ -0,0 +1,32 @@
package org.ligi.passandroid.ui.views
import android.content.Context
import android.support.annotation.LayoutRes
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import kotlinx.android.synthetic.main.category_indicator_base.view.*
import org.ligi.passandroid.R
import org.ligi.passandroid.helper.CategoryHelper
import org.ligi.passandroid.model.pass.PassType
open class BaseCategoryIndicatorView @JvmOverloads constructor(context: Context, attrs: AttributeSet, @LayoutRes val layoutRes: Int = R.layout.category_indicator_base) : LinearLayout(context, attrs) {
override fun onFinishInflate() {
super.onFinishInflate()
LayoutInflater.from(context).inflate(layoutRes, this, true)
}
fun setImageByCategory(category: PassType?) {
if (category == null) {
topImageView.visibility = View.GONE
} else {
topImageView.visibility = View.VISIBLE
topImageView.setImageResource(CategoryHelper.getCategoryTopImageRes(category))
}
}
fun setAccentColor(color: Int) = setBackgroundColor(color)
}

View file

@ -1,23 +0,0 @@
package org.ligi.passandroid.ui.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.widget.ImageView;
import butterknife.ButterKnife;
import org.ligi.passandroid.R;
public class CategoryIndicatorViewWithIcon extends BaseCategoryIndicatorView {
private ImageView iconImageView;
public CategoryIndicatorViewWithIcon(Context context, AttributeSet attrs) {
super(context, attrs, R.layout.category_indicator);
iconImageView = ButterKnife.findById(this, R.id.iconImageView);
}
public void setIcon(final Bitmap iconBitmap) {
iconImageView.setImageBitmap(iconBitmap);
}
}

View file

@ -0,0 +1,15 @@
package org.ligi.passandroid.ui.views
import android.content.Context
import android.graphics.Bitmap
import android.util.AttributeSet
import kotlinx.android.synthetic.main.category_indicator.view.*
import org.ligi.passandroid.R
class CategoryIndicatorViewWithIcon(context: Context, attrs: AttributeSet) : BaseCategoryIndicatorView(context, attrs, R.layout.category_indicator) {
fun setIcon(iconBitmap: Bitmap) {
iconImageView.setImageBitmap(iconBitmap)
}
}

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/fields_container"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
@ -23,7 +23,7 @@
android:minWidth="64dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:hint="label"
/>
/>
</android.support.design.widget.TextInputLayout>
@ -35,7 +35,7 @@
android:minWidth="64dp"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:hint="value"
/>
/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>

View file

@ -30,7 +30,7 @@ class TheAppleStyleQuirkCorrector {
fun testThatDateIsExtracted() {
val pass = PassImpl(UUID.randomUUID().toString())
pass.fields = listOf(PassField("date", "foo", DATE_PROBE, false))
pass.fields = mutableListOf(PassField("date", "foo", DATE_PROBE, false))
tested.correctQuirks(pass)
@ -41,7 +41,7 @@ class TheAppleStyleQuirkCorrector {
fun testThatInvalidDateIsIgnored() {
val pass = PassImpl(UUID.randomUUID().toString())
pass.fields = listOf(PassField("date", "foo", "invalid", false))
pass.fields = mutableListOf(PassField("date", "foo", "invalid", false))
tested.correctQuirks(pass)
@ -52,7 +52,7 @@ class TheAppleStyleQuirkCorrector {
fun testThatDateIsExtractedAfterWrongDatesBefore() {
val pass = PassImpl(UUID.randomUUID().toString())
pass.fields = listOf(PassField("date", "foo", "invalid", false),PassField("date", "foo", DATE_PROBE, false))
pass.fields = mutableListOf(PassField("date", "foo", "invalid", false), PassField("date", "foo", DATE_PROBE, false))
tested.correctQuirks(pass)