Upgraded butterknife to 8.8.1 (#524)

Refactored MusicListFragment and PVRListFragment to use AbstractTabsFragment
Fixed scrolling in a nested scroll view using espresso
Fixed issue with setting and checking Kodi major version
master
Martijn Brekhof 5 years ago committed by Synced Synapse
parent 2f2791a795
commit 2ed968456a

@ -119,7 +119,8 @@ dependencies {
compile "com.android.support:design:${supportLibVersion}"
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.2'
compile 'com.jakewharton:butterknife:6.1.0'
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'de.greenrobot:eventbus:2.4.0'

@ -20,8 +20,8 @@
# Butterknife
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepnames class * { @butterknife.InjectView *;}
-keep class **$$ViewBinder { *; }
-keepnames class * { @butterknife.BindView *;}
# Jackson
-dontskipnonpubliclibraryclassmembers

@ -0,0 +1,78 @@
/*
* Copyright 2018 Martijn Brekhof. All rights reserved.
*
* 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.
*/
package org.xbmc.kore.testhelpers.action;
import android.graphics.Rect;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.espresso.util.HumanReadables;
import android.support.v4.widget.NestedScrollView;
import android.view.View;
import org.hamcrest.Matcher;
import org.xbmc.kore.utils.LogUtils;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
/**
* Modified version of {@link android.support.test.espresso.action.ScrollToAction} to support
* NestedScrollView.
* TODO Check future versions of {@link android.support.test.espresso.action.ScrollToAction} to see if support for NestedScrollView has been added
*/
public class NestedScrollTo implements ViewAction {
private final static String TAG = LogUtils.makeLogTag(NestedScrollTo.class);
@Override
public Matcher<View> getConstraints() {
return allOf(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE), isDescendantOfA(anyOf(
isAssignableFrom(NestedScrollView.class))));
}
@Override
public String getDescription() {
return "nested scroll to";
}
@Override
public void perform(UiController uiController, View view) {
if (isDisplayingAtLeast(90).matches(view)) {
LogUtils.LOGI(TAG, "View is already displayed. Returning.");
return;
}
Rect rect = new Rect();
view.getDrawingRect(rect);
if (!view.requestRectangleOnScreen(rect, true /* immediate */)) {
LogUtils.LOGW(TAG, "Scrolling to view was requested, but none of the parents scrolled.");
}
uiController.loopMainThreadUntilIdle();
if (!isDisplayingAtLeast(90).matches(view)) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException(
"Scrolling to view was attempted, but the view is not displayed"))
.build();
}
}
}

@ -22,6 +22,7 @@ import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.ScrollToAction;
import android.support.test.espresso.util.HumanReadables;
import android.support.test.espresso.util.TreeIterables;
import android.view.View;
@ -50,6 +51,19 @@ public final class ViewActions {
return actionWithAssertions(new ClearFocus());
}
/**
* Returns an action that scrolls to the view in a nested scroll view.<br>
* <br>
* View preconditions:
* <ul>
* <li>must be a descendant of NestedScrollView
* <li>must have visibility set to View.VISIBLE
* <ul></ul>
*/
public static ViewAction nestedScrollTo() {
return actionWithAssertions(new NestedScrollTo());
}
public interface CheckStatus {
boolean check(View v);
}

@ -76,7 +76,7 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
private static PlayerHandler playerHandler;
private static ApplicationHandler applicationHandler;
private static InputHandler inputHandler;
private int kodiMajorVersion = HostInfo.DEFAULT_KODI_VERSION_MAJOR;
private HostInfo hostInfo;
@BeforeClass
@ -120,7 +120,7 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
hostInfo = Database.addHost(context, server.getHostName(),
HostConnection.PROTOCOL_TCP, HostInfo.DEFAULT_HTTP_PORT,
server.getPort(), useEventServer);
server.getPort(), useEventServer, kodiMajorVersion);
//Allow each test to change the host info
configureHostInfo(hostInfo);
@ -164,6 +164,17 @@ abstract public class AbstractTestClass<T extends AppCompatActivity> {
return null;
}
/**
* Use this to set the major version of Kodi.
* <br/>
* NOTE: be sure to call this before {@link #setUp()} is called to have the version correctly
* set in the database.
* @param kodiMajorVersion
*/
protected void setKodiMajorVersion(int kodiMajorVersion) {
this.kodiMajorVersion = kodiMajorVersion;
}
public static PlayerHandler getPlayerHandler() {
return playerHandler;
}

@ -18,6 +18,7 @@ package org.xbmc.kore.tests.ui.music;
import android.app.Activity;
import android.content.Context;
import android.os.SystemClock;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
@ -180,6 +181,7 @@ public class RestoreSearchQueryViewPagerTest extends AbstractTestClass<MusicActi
clickAlbumsTab();
EspressoTestUtils.rotateDevice(activity);
EspressoTestUtils.clickMenuItem(activity, activity.getString(R.string.action_search), R.id.action_search);
Espresso.closeSoftKeyboard();
EspressoTestUtils.checkTextInSearchQuery("");
EspressoTestUtils.checkListMatchesSearchQuery("", ALBUM_COMPLETE_LIST_SIZE, R.id.list);

@ -64,7 +64,7 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
@Override
protected void configureHostInfo(HostInfo hostInfo) {
hostInfo.setKodiVersionMajor(17);
}
@BeforeClass
@ -74,6 +74,12 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
mockEventServer.start();
}
@Override
public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V17_KRYPTON);
super.setUp();
}
@After
public void resetState() {
mockEventServer.reset();

@ -69,6 +69,12 @@ public class KodiPreV17Tests extends AbstractTestClass<RemoteActivity> {
mockEventServer.start();
}
@Override
public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V16_JARVIS);
super.setUp();
}
@After
public void resetState() {
mockEventServer.reset();

@ -55,6 +55,12 @@ public class ButtonTests extends AbstractTestClass<RemoteActivity> {
hostInfo.setKodiVersionMajor(17);
}
@Override
public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V17_KRYPTON);
super.setUp();
}
@Test
public void leftControlPadButtonTest() throws InterruptedException {
onView(withId(R.id.left)).perform(click());

@ -53,6 +53,12 @@ public class KodiPreV17Tests extends AbstractTestClass<RemoteActivity> {
hostInfo.setKodiVersionMajor(16);
}
@Override
public void setUp() throws Throwable {
setKodiMajorVersion(HostInfo.KODI_V16_JARVIS);
super.setUp();
}
@Test
public void infoControlPadButtonLongClickTest() throws InterruptedException {
onView(withId(R.id.info)).perform(longClick());

@ -28,13 +28,13 @@ import org.xbmc.kore.ui.sections.video.TVShowsActivity;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.xbmc.kore.testhelpers.action.ViewActions.nestedScrollTo;
public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity> {
@ -79,7 +79,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void setActionBarTitleOnNextEpisode() {
EspressoTestUtils.clickAdapterViewItem(1, R.id.list);
onView( withId(R.id.next_episode_list)).perform( scrollTo(), click());
onView( withId(R.id.next_episode_list)).perform( nestedScrollTo(), click());
onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.default_toolbar))))
.check(matches(withText("3")));
@ -96,7 +96,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void setActionBarTitleOnSeasonList() {
EspressoTestUtils.clickAdapterViewItem(0, R.id.list);
onView( withId(R.id.seasons_list)).perform( scrollTo(), click());
onView( withId(R.id.seasons_list)).perform( nestedScrollTo(), click());
onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.default_toolbar))))
.check(matches(withText("Season 01")));
@ -114,7 +114,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void setActionBarTitleOnSeasonListEpisode() {
EspressoTestUtils.clickAdapterViewItem(0, R.id.list);
onView( withId(R.id.seasons_list)).perform( scrollTo(), click());
onView( withId(R.id.seasons_list)).perform( nestedScrollTo(), click());
EspressoTestUtils.selectListItemAndCheckActionbarTitle(0, R.id.list, "11.22.63");
}
@ -145,7 +145,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void restoreActionBarTitleSeasonListOnConfigurationStateChanged() {
EspressoTestUtils.clickAdapterViewItem(0, R.id.list);
onView( withId(R.id.seasons_list)).perform( scrollTo(), click());
onView( withId(R.id.seasons_list)).perform( nestedScrollTo(), click());
EspressoTestUtils.rotateDevice(mActivityRule.getActivity());
onView(allOf(instanceOf(TextView.class), withParent(withId(R.id.default_toolbar))))
@ -165,7 +165,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void restoreActionBarTitleSeasonListEpisodeOnConfigurationStateChanged() {
EspressoTestUtils.clickAdapterViewItem(0, R.id.list);
onView( withId(R.id.seasons_list)).perform( scrollTo(), click());
onView( withId(R.id.seasons_list)).perform( nestedScrollTo(), click());
EspressoTestUtils.selectListItemRotateDeviceAndCheckActionbarTitle(0, R.id.list,
"11.22.63",
mActivityRule.getActivity());
@ -183,7 +183,7 @@ public class TVShowsActivityTests extends BaseMediaActivityTests<TVShowsActivity
@Test
public void restoreActionBarTitleNextEpisodeOnConfigurationStateChanged() {
EspressoTestUtils.clickAdapterViewItem(1, R.id.list);
onView( withId(R.id.next_episode_list)).perform( scrollTo() );
onView( withId(R.id.next_episode_list)).perform( nestedScrollTo() );
onView( withText("You'll See the Sparkle")).perform( click() );
EspressoTestUtils.rotateDevice(mActivityRule.getActivity());

@ -300,11 +300,11 @@ public class HostInfo {
}
public boolean isGothamOrLater() {
return kodiVersionMajor > KODI_V13_GOTHAM;
return kodiVersionMajor >= KODI_V13_GOTHAM;
}
public boolean isKryptonOrLater() {
return kodiVersionMajor > KODI_V17_KRYPTON;
return kodiVersionMajor >= KODI_V17_KRYPTON;
}
/**

@ -70,7 +70,8 @@ import java.util.Locale;
import at.blogc.android.views.ExpandableTextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
import static android.view.View.GONE;
@ -83,29 +84,29 @@ abstract public class AbstractInfoFragment extends AbstractFragment
private static final String BUNDLE_KEY_APIMETHOD_PENDING = "pending_apimethod";
// Detail views
@InjectView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
@InjectView(R.id.media_panel) NestedScrollView panelScrollView;
@InjectView(R.id.art) ImageView artImageView;
@InjectView(R.id.poster) ImageView posterImageView;
@InjectView(R.id.media_title) TextView titleTextView;
@InjectView(R.id.media_undertitle) TextView underTitleTextView;
@InjectView(R.id.rating_container) LinearLayout ratingContainer;
@InjectView(R.id.rating) TextView ratingTextView;
@InjectView(R.id.rating_votes) TextView ratingVotesTextView;
@InjectView(R.id.max_rating) TextView maxRatingTextView;
@InjectView(R.id.media_details_right) TextView detailsRightTextView;
@InjectView(R.id.media_details) LinearLayout mediaDetailsContainer;
@InjectView(R.id.media_action_download) ImageButton downloadButton;
@InjectView(R.id.media_action_pin_unpin) ImageButton pinUnpinButton;
@InjectView(R.id.media_action_add_to_playlist) ImageButton addToPlaylistButton;
@InjectView(R.id.media_action_seen) ImageButton seenButton;
@InjectView(R.id.media_action_go_to_imdb) ImageButton imdbButton;
@InjectView(R.id.media_actions_bar) LinearLayout mediaActionsBar;
@InjectView(R.id.media_description) ExpandableTextView descriptionExpandableTextView;
@InjectView(R.id.media_description_container) LinearLayout descriptionContainer;
@InjectView(R.id.show_all) ImageView expansionImage;
@InjectView(R.id.fab) FABSpeedDial fabButton;
@InjectView(R.id.exit_transition_view) View exitTransitionView;
@BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.media_panel) NestedScrollView panelScrollView;
@BindView(R.id.art) ImageView artImageView;
@BindView(R.id.poster) ImageView posterImageView;
@BindView(R.id.media_title) TextView titleTextView;
@BindView(R.id.media_undertitle) TextView underTitleTextView;
@BindView(R.id.rating_container) LinearLayout ratingContainer;
@BindView(R.id.rating) TextView ratingTextView;
@BindView(R.id.rating_votes) TextView ratingVotesTextView;
@BindView(R.id.max_rating) TextView maxRatingTextView;
@BindView(R.id.media_details_right) TextView detailsRightTextView;
@BindView(R.id.media_details) LinearLayout mediaDetailsContainer;
@BindView(R.id.media_action_download) ImageButton downloadButton;
@BindView(R.id.media_action_pin_unpin) ImageButton pinUnpinButton;
@BindView(R.id.media_action_add_to_playlist) ImageButton addToPlaylistButton;
@BindView(R.id.media_action_seen) ImageButton seenButton;
@BindView(R.id.media_action_go_to_imdb) ImageButton imdbButton;
@BindView(R.id.media_actions_bar) LinearLayout mediaActionsBar;
@BindView(R.id.media_description) ExpandableTextView descriptionExpandableTextView;
@BindView(R.id.media_description_container) LinearLayout descriptionContainer;
@BindView(R.id.show_all) ImageView expansionImage;
@BindView(R.id.fab) FABSpeedDial fabButton;
@BindView(R.id.exit_transition_view) View exitTransitionView;
private HostManager hostManager;
private HostInfo hostInfo;
@ -113,6 +114,7 @@ abstract public class AbstractInfoFragment extends AbstractFragment
private RefreshItem refreshItem;
private boolean expandDescription;
private int methodId;
private Unbinder unbinder;
/**
* Handler on which to post RPC callbacks
@ -146,7 +148,7 @@ abstract public class AbstractInfoFragment extends AbstractFragment
}
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_info, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
Resources resources = getActivity().getResources();
@ -244,6 +246,12 @@ abstract public class AbstractInfoFragment extends AbstractFragment
SyncUtils.disconnectFromLibrarySyncService(getActivity(), serviceConnection);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

@ -41,7 +41,8 @@ import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.Utils;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
public abstract class AbstractListFragment extends Fragment implements
SwipeRefreshLayout.OnRefreshListener {
@ -51,10 +52,11 @@ public abstract class AbstractListFragment extends Fragment implements
private final String BUNDLE_SAVEDINSTANCE_LISTPOSITION = "lposition";
private boolean gridViewUsesMultipleColumns;
private Unbinder unbinder;
protected @InjectView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
@InjectView(R.id.list) GridView gridView;
@InjectView(android.R.id.empty) TextView emptyView;
protected @BindView(R.id.swipe_refresh_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.list) GridView gridView;
@BindView(android.R.id.empty) TextView emptyView;
abstract protected AdapterView.OnItemClickListener createOnItemClickListener();
abstract protected BaseAdapter createAdapter();
@ -70,7 +72,7 @@ public abstract class AbstractListFragment extends Fragment implements
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_generic_media_list, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
swipeRefreshLayout.setOnRefreshListener(this);
@ -113,6 +115,12 @@ public abstract class AbstractListFragment extends Fragment implements
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);

@ -31,15 +31,18 @@ import org.xbmc.kore.utils.SharedElementTransition;
import org.xbmc.kore.utils.TabsAdapter;
import org.xbmc.kore.utils.UIUtils;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.Unbinder;
abstract public class AbstractTabsFragment extends AbstractFragment
implements SharedElementTransition.SharedElement {
private static final String TAG = LogUtils.makeLogTag(AbstractTabsFragment.class);
@InjectView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip;
@InjectView(R.id.pager) ViewPager viewPager;
@BindView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip;
@BindView(R.id.pager) ViewPager viewPager;
private Unbinder unbinder;
/**
* Use {@link #setDataHolder(AbstractInfoFragment.DataHolder)} to provide the required info
@ -58,7 +61,7 @@ abstract public class AbstractTabsFragment extends AbstractFragment
}
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_default_view_pager, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
viewPager.setAdapter(createTabsAdapter(getDataHolder()));
pagerTabStrip.setViewPager(viewPager);
@ -72,6 +75,12 @@ abstract public class AbstractTabsFragment extends AbstractFragment
setHasOptionsMenu(false);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public boolean isSharedElementVisible() {
View view = getView();
@ -92,6 +101,10 @@ abstract public class AbstractTabsFragment extends AbstractFragment
return false;
}
protected ViewPager getViewPager() {
return viewPager;
}
/**
* Called to get the TabsAdapter that should be connected to the ViewPager
* @param dataHolder the data passed to the *DetailsFragment

@ -59,7 +59,7 @@ import org.xbmc.kore.utils.UIUtils;
import org.xbmc.kore.utils.Utils;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
public abstract class BaseMediaActivity extends BaseActivity
implements HostConnectionObserver.ApplicationEventsObserver,
@ -71,7 +71,7 @@ public abstract class BaseMediaActivity extends BaseActivity
private static final String NAVICON_ISARROW = "navstate";
private static final String ACTIONBAR_TITLE = "actionbartitle";
@InjectView(R.id.now_playing_panel) NowPlayingPanel nowPlayingPanel;
@BindView(R.id.now_playing_panel) NowPlayingPanel nowPlayingPanel;
private NavigationDrawerFragment navigationDrawerFragment;
private SharedElementTransition sharedElementTransition = new SharedElementTransition();
@ -111,7 +111,7 @@ public abstract class BaseMediaActivity extends BaseActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_generic_media);
ButterKnife.inject(this);
ButterKnife.bind(this);
// Set up the drawer.
navigationDrawerFragment = (NavigationDrawerFragment)getSupportFragmentManager()

@ -26,7 +26,8 @@ import org.xbmc.kore.ui.widgets.VolumeLevelIndicator;
import org.xbmc.kore.utils.LogUtils;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
public class VolumeControllerDialogFragmentListener extends AppCompatDialogFragment
implements HostConnectionObserver.ApplicationEventsObserver,
@ -35,13 +36,11 @@ public class VolumeControllerDialogFragmentListener extends AppCompatDialogFragm
private static final String TAG = LogUtils.makeLogTag(VolumeControllerDialogFragmentListener.class);
private static final int AUTO_DISMISS_DELAY = 2000;
@InjectView(R.id.npp_volume_mute)
HighlightButton volumeMuteButton;
@InjectView(R.id.npp_volume_muted_indicator)
HighlightButton volumeMutedIndicatorButton;
@InjectView(R.id.npp_volume_level_indicator)
VolumeLevelIndicator volumeLevelIndicator;
@BindView(R.id.npp_volume_mute) HighlightButton volumeMuteButton;
@BindView(R.id.npp_volume_muted_indicator) HighlightButton volumeMutedIndicatorButton;
@BindView(R.id.npp_volume_level_indicator) VolumeLevelIndicator volumeLevelIndicator;
private Unbinder unbinder;
private Handler callbackHandler = new Handler();
private HostManager hostManager = null;
private ApiCallback<Integer> defaultIntActionCallback = ApiMethod.getDefaultActionCallback();
@ -100,7 +99,7 @@ public class VolumeControllerDialogFragmentListener extends AppCompatDialogFragm
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.volume_controller_dialog, container, false);
ButterKnife.inject(this, rootView);
unbinder = ButterKnife.bind(this, rootView);
return rootView;
}
@ -123,6 +122,12 @@ public class VolumeControllerDialogFragmentListener extends AppCompatDialogFragm
delayedDismissDialog();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
private void registerObserver() {
HostConnectionObserver hostConnectionObserver = hostManager.getHostConnectionObserver();
if (hostConnectionObserver == null) {

@ -26,43 +26,32 @@ import com.astuetz.PagerSlidingTabStrip;
import org.xbmc.kore.R;
import org.xbmc.kore.ui.AbstractCursorListFragment;
import org.xbmc.kore.ui.AbstractFragment;
import org.xbmc.kore.ui.AbstractTabsFragment;
import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.TabsAdapter;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
/**
* Container for the various music lists
*/
public class MusicListFragment extends Fragment {
public class MusicListFragment extends AbstractTabsFragment {
private static final String TAG = LogUtils.makeLogTag(MusicListFragment.class);
private TabsAdapter tabsAdapter;
private int currentItem;
@InjectView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip;
@InjectView(R.id.pager) ViewPager viewPager;
private TabsAdapter tabsAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_default_view_pager, container, false);
ButterKnife.inject(this, root);
tabsAdapter = new TabsAdapter(getActivity(), getChildFragmentManager())
.addTab(ArtistListFragment.class, getArguments(), R.string.artists, 1)
.addTab(AlbumListFragment.class, getArguments(), R.string.albums, 2)
.addTab(AudioGenresListFragment.class, getArguments(), R.string.genres, 3)
.addTab(SongsListFragment.class, getArguments(), R.string.songs, 4)
.addTab(MusicVideoListFragment.class, getArguments(), R.string.music_videos, 5);
View view = super.onCreateView(inflater, container, savedInstanceState);
if (view == null)
return view;
viewPager.setAdapter(tabsAdapter);
pagerTabStrip.setViewPager(viewPager);
currentItem = getViewPager().getCurrentItem();
currentItem = viewPager.getCurrentItem();
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
getViewPager().addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
@ -75,14 +64,15 @@ public class MusicListFragment extends Fragment {
if (f != null) {
f.saveSearchState();
}
currentItem = viewPager.getCurrentItem();
currentItem = getViewPager().getCurrentItem();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
return root;
return view;
}
@Override
@ -90,4 +80,15 @@ public class MusicListFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(false);
}
@Override
protected TabsAdapter createTabsAdapter(DataHolder dataHolder) {
tabsAdapter = new TabsAdapter(getActivity(), getChildFragmentManager())
.addTab(ArtistListFragment.class, getArguments(), R.string.artists, 1)
.addTab(AlbumListFragment.class, getArguments(), R.string.albums, 2)
.addTab(AudioGenresListFragment.class, getArguments(), R.string.genres, 3)
.addTab(SongsListFragment.class, getArguments(), R.string.songs, 4)
.addTab(MusicVideoListFragment.class, getArguments(), R.string.music_videos, 5);
return tabsAdapter;
}
}

@ -17,54 +17,31 @@ package org.xbmc.kore.ui.sections.file;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.astuetz.PagerSlidingTabStrip;
import org.xbmc.kore.R;
import org.xbmc.kore.jsonrpc.method.Files;
import org.xbmc.kore.ui.AbstractTabsFragment;
import org.xbmc.kore.ui.OnBackPressedListener;
import org.xbmc.kore.utils.TabsAdapter;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* Manages the viewpager of files
*/
public class FileListFragment extends Fragment
public class FileListFragment extends AbstractTabsFragment
implements OnBackPressedListener {
@InjectView(R.id.pager_tab_strip) PagerSlidingTabStrip pagerTabStrip;
@InjectView(R.id.pager) ViewPager viewPager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_media_list, container, false);
ButterKnife.inject(this, root);
protected TabsAdapter createTabsAdapter(DataHolder dataHolder) {
Bundle videoFileListArgs = new Bundle();
videoFileListArgs.putString(MediaFileListFragment.MEDIA_TYPE, Files.Media.VIDEO);
Bundle musicFileListArgs = new Bundle();
musicFileListArgs.putString(MediaFileListFragment.MEDIA_TYPE, Files.Media.MUSIC);
Bundle pictureFileListArgs = new Bundle();
pictureFileListArgs.putString(MediaFileListFragment.MEDIA_TYPE, Files.Media.PICTURES);
TabsAdapter tabsAdapter = new TabsAdapter(getActivity(), getChildFragmentManager())
return new TabsAdapter(getActivity(), getChildFragmentManager())
.addTab(MediaFileListFragment.class, videoFileListArgs, R.string.video, 1)
.addTab(MediaFileListFragment.class, musicFileListArgs, R.string.music, 2)
.addTab(MediaFileListFragment.class, pictureFileListArgs, R.string.pictures, 3);
viewPager.setAdapter(tabsAdapter);
pagerTabStrip.setViewPager(viewPager);
return root;
}
@Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(false);
}
@Override
@ -81,8 +58,8 @@ public class FileListFragment extends Fragment
@Override
public boolean onBackPressed() {
// Tell current fragment to move up one directory, if possible
MediaFileListFragment curPage = (MediaFileListFragment)((TabsAdapter)viewPager.getAdapter())
.getStoredFragment(viewPager.getCurrentItem());
MediaFileListFragment curPage = (MediaFileListFragment)((TabsAdapter)getViewPager().getAdapter())
.getStoredFragment(getViewPager().getCurrentItem());
if ((curPage != null) && !curPage.atRootDirectory()) {
curPage.onBackPressed();
return true;

@ -50,7 +50,8 @@ import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
/**
* Fragment that searchs foor XBMCs using Zeroconf
@ -75,19 +76,20 @@ public class AddHostFragmentZeroconf extends Fragment {
}
private AddHostZeroconfListener listener;
private Unbinder unbinder;
@InjectView(R.id.search_host_title) TextView titleTextView;
@InjectView(R.id.search_host_message) TextView messageTextView;
@InjectView(R.id.next) Button nextButton;
@InjectView(R.id.previous) Button previousButton;
@BindView(R.id.search_host_title) TextView titleTextView;
@BindView(R.id.search_host_message) TextView messageTextView;
@BindView(R.id.next) Button nextButton;
@BindView(R.id.previous) Button previousButton;
@InjectView(R.id.progress_bar) ProgressBar progressBar;
@InjectView(R.id.list) GridView hostListGridView;
@BindView(R.id.progress_bar) ProgressBar progressBar;
@BindView(R.id.list) GridView hostListGridView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_add_host_zeroconf, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
return root;
}
@ -112,6 +114,12 @@ public class AddHostFragmentZeroconf extends Fragment {
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
// Whether the user cancelled the search
private boolean searchCancelled = false;
private final Object lock = new Object();

@ -47,7 +47,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
/**
* Fragment that presents the welcome message
@ -84,18 +85,19 @@ public class HostFragmentManualConfiguration extends Fragment {
public static String CANCEL_BUTTON_LABEL_ARG = PREFIX + ".cancel_button_label";
private HostManualConfigurationListener listener;
private ProgressDialog progressDialog;
@InjectView(R.id.xbmc_name) EditText xbmcNameEditText;
@InjectView(R.id.xbmc_ip_address) EditText xbmcIpAddressEditText;
@InjectView(R.id.xbmc_http_port) EditText xbmcHttpPortEditText;
@InjectView(R.id.xbmc_tcp_port) EditText xbmcTcpPortEditText;
@InjectView(R.id.xbmc_username) EditText xbmcUsernameEditText;
@InjectView(R.id.xbmc_password) EditText xbmcPasswordEditText;
@InjectView(R.id.xbmc_mac_address) EditText xbmcMacAddressEditText;
@InjectView(R.id.xbmc_wol_port) EditText xbmcWolPortEditText;
@InjectView(R.id.xbmc_use_tcp) CheckBox xbmcUseTcpCheckbox;
@InjectView(R.id.xbmc_use_event_server) CheckBox xbmcUseEventServerCheckbox;
@InjectView(R.id.xbmc_event_server_port) EditText xbmcEventServerPortEditText;
private Unbinder unbinder;
@BindView(R.id.xbmc_name) EditText xbmcNameEditText;
@BindView(R.id.xbmc_ip_address) EditText xbmcIpAddressEditText;
@BindView(R.id.xbmc_http_port) EditText xbmcHttpPortEditText;
@BindView(R.id.xbmc_tcp_port) EditText xbmcTcpPortEditText;
@BindView(R.id.xbmc_username) EditText xbmcUsernameEditText;
@BindView(R.id.xbmc_password) EditText xbmcPasswordEditText;
@BindView(R.id.xbmc_mac_address) EditText xbmcMacAddressEditText;
@BindView(R.id.xbmc_wol_port) EditText xbmcWolPortEditText;
@BindView(R.id.xbmc_use_tcp) CheckBox xbmcUseTcpCheckbox;
@BindView(R.id.xbmc_use_event_server) CheckBox xbmcUseEventServerCheckbox;
@BindView(R.id.xbmc_event_server_port) EditText xbmcEventServerPortEditText;
// Handler for callbacks
final Handler handler = new Handler();
@ -103,7 +105,7 @@ public class HostFragmentManualConfiguration extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_add_host_manual_configuration, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
// By default, use TCP
xbmcUseTcpCheckbox.setChecked(true);
@ -215,6 +217,12 @@ public class HostFragmentManualConfiguration extends Fragment {
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
private static boolean isValidPort(int port) {
return port > 0 && port <= 65535;
}

@ -53,8 +53,9 @@ import java.util.ArrayList;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Fragment to manage the list oof registered hosts.
@ -65,11 +66,11 @@ public class HostListFragment extends Fragment {
private ArrayList<HostInfoRow> hostInfoRows = new ArrayList<HostInfoRow>();
private HostListAdapter adapter = null;
private Context context;
private Unbinder unbinder;
private Handler callbackHandler = new Handler();
@InjectView(R.id.list) GridView hostGridView;
@InjectView(R.id.action_add_host) Button addHostButton;
@BindView(R.id.list) GridView hostGridView;
@BindView(R.id.action_add_host) Button addHostButton;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -81,7 +82,7 @@ public class HostListFragment extends Fragment {
context = inflater.getContext();
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_host_list, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
// Get the host list
// TODO: This is being done synchronously !!!
@ -160,6 +161,12 @@ public class HostListFragment extends Fragment {
super.onPause();
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
/**
* Pings the host to checks it status.
* <br/>

@ -66,8 +66,9 @@ import java.util.ArrayList;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Unbinder;
/**
* Now playing view
@ -128,39 +129,41 @@ public class NowPlayingFragment extends Fragment
private ApiCallback<Integer> defaultIntActionCallback = ApiMethod.getDefaultActionCallback();
private ApiCallback<Boolean> defaultBooleanActionCallback = ApiMethod.getDefaultActionCallback();
private Unbinder unbinder;
/**
* Injectable views
*/
@InjectView(R.id.play) ImageButton playButton;
@BindView(R.id.play) ImageButton playButton;
@InjectView(R.id.volume_mute) HighlightButton volumeMuteButton;
@InjectView(R.id.shuffle) HighlightButton shuffleButton;
@InjectView(R.id.repeat) RepeatModeButton repeatButton;
@InjectView(R.id.overflow) ImageButton overflowButton;
@BindView(R.id.volume_mute) HighlightButton volumeMuteButton;
@BindView(R.id.shuffle) HighlightButton shuffleButton;
@BindView(R.id.repeat) RepeatModeButton repeatButton;
@BindView(R.id.overflow) ImageButton overflowButton;
@InjectView(R.id.info_panel) RelativeLayout infoPanel;
@InjectView(R.id.media_panel) ScrollView mediaPanel;
@BindView(R.id.info_panel) RelativeLayout infoPanel;
@BindView(R.id.media_panel) ScrollView mediaPanel;
@InjectView(R.id.info_title) TextView infoTitle;
@InjectView(R.id.info_message) TextView infoMessage;
@BindView(R.id.info_title) TextView infoTitle;
@BindView(R.id.info_message) TextView infoMessage;
@InjectView(R.id.art) ImageView mediaArt;
@InjectView(R.id.poster) ImageView mediaPoster;
@BindView(R.id.art) ImageView mediaArt;
@BindView(R.id.poster) ImageView mediaPoster;
@InjectView(R.id.media_title) TextView mediaTitle;
@InjectView(R.id.media_undertitle) TextView mediaUndertitle;
@InjectView(R.id.progress_info) MediaProgressIndicator mediaProgressIndicator;
@BindView(R.id.media_title) TextView mediaTitle;
@BindView(R.id.media_undertitle) TextView mediaUndertitle;
@BindView(R.id.progress_info) MediaProgressIndicator mediaProgressIndicator;
@InjectView(R.id.volume_level_indicator) VolumeLevelIndicator volumeLevelIndicator;
@BindView(R.id.volume_level_indicator) VolumeLevelIndicator volumeLevelIndicator;
@InjectView(R.id.rating) TextView mediaRating;
@InjectView(R.id.max_rating) TextView mediaMaxRating;
@InjectView(R.id.year) TextView mediaYear;
@InjectView(R.id.genres) TextView mediaGenreSeason;
@InjectView(R.id.rating_votes) TextView mediaRatingVotes;
@BindView(R.id.rating) TextView mediaRating;
@BindView(R.id.max_rating) TextView mediaMaxRating;
@BindView(R.id.year) TextView mediaYear;
@BindView(R.id.genres) TextView mediaGenreSeason;
@BindView(R.id.rating_votes) TextView mediaRatingVotes;
@InjectView(R.id.media_description) TextView mediaDescription;
@InjectView(R.id.cast_list) GridLayout videoCastList;
@BindView(R.id.media_description) TextView mediaDescription;
@BindView(R.id.cast_list) GridLayout videoCastList;
@Override
public void onAttach(Activity activity) {
@ -183,7 +186,7 @@ public class NowPlayingFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_now_playing, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
volumeLevelIndicator.setOnVolumeChangeListener(new VolumeLevelIndicator.OnVolumeChangeListener() {
@Override
@ -244,6 +247,12 @@ public class NowPlayingFragment extends Fragment
hostConnectionObserver.unregisterApplicationObserver(this);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
/**
* Default callback for methods that don't return anything
*/

@ -57,7 +57,8 @@ import org.xbmc.kore.utils.Utils;
import java.util.List;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.Unbinder;
/**
* Playlist view
@ -96,14 +97,16 @@ public class PlaylistFragment extends Fragment
*/
private PlayListAdapter playListAdapter;
private Unbinder unbinder;
/**
* Injectable views
*/
@InjectView(R.id.info_panel) RelativeLayout infoPanel;
@InjectView(R.id.playlist) DynamicListView playlistListView;
@BindView(R.id.info_panel) RelativeLayout infoPanel;
@BindView(R.id.playlist) DynamicListView playlistListView;
@InjectView(R.id.info_title) TextView infoTitle;
@InjectView(R.id.info_message) TextView infoMessage;
@BindView(R.id.info_title) TextView infoTitle;
@BindView(R.id.info_message) TextView infoMessage;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -115,7 +118,7 @@ public class PlaylistFragment extends Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_playlist, container, false);
ButterKnife.inject(this, root);
unbinder = ButterKnife.bind(this, root);
playListAdapter = new PlayListAdapter();
playlistListView.setAdapter(playListAdapter);
@ -157,6 +160,12 @@ public class PlaylistFragment extends Fragment
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {

@ -53,9 +53,9 @@ import org.xbmc.kore.service.ConnectionObserversManagerService;
import org.xbmc.kore.ui.BaseActivity;
import org.xbmc.kore.ui.generic.NavigationDrawerFragment;
import org.xbmc.kore.ui.generic.SendTextDialogFragment;
import org.xbmc.kore.ui.generic.VolumeControllerDialogFragmentListener;
import org.xbmc.kore.ui.sections.hosts.AddHostActivity;
import org.xbmc.kore.ui.views.CirclePageIndicator;
import org.xbmc.kore.ui.generic.VolumeControllerDialogFragmentListener;
import org.xbmc.kore.utils.LogUtils;
import org.xbmc.kore.utils.TabsAdapter;
import org.xbmc.kore.utils.UIUtils;
@ -69,8 +69,8 @@ import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class RemoteActivity extends BaseActivity
@ -100,10 +100,10 @@ public class RemoteActivity extends BaseActivity
private Future<Void> awaitingShare;
@InjectView(R.id.background_image) ImageView backgroundImage;
@InjectView(R.id.pager_indicator) CirclePageIndicator pageIndicator;
@InjectView(R.id.pager) ViewPager viewPager;
@InjectView(R.id.default_toolbar) Toolbar toolbar;
@BindView(R.id.background_image) ImageView backgroundImage;
@BindView(R.id.pager_indicator) CirclePageIndicator pageIndicator;
@BindView(R.id.pager) ViewPager viewPager;
@BindView(R.id.default_toolbar) Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -113,7 +113,7 @@ public class RemoteActivity extends BaseActivity
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
setContentView(R.layout.activity_remote);
ButterKnife.inject(this);
ButterKnife.bind(this);
hostManager = HostManager.getInstance(this);

@ -19,6 +19,7 @@ import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
@ -56,9 +57,10 @@ import java.util.HashSet;
import java.util.Set;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Optional;
import butterknife.Unbinder;
/**
* Remote view
@ -119,38 +121,38 @@ public class RemoteFragment extends Fragment
private final ApiMethod<String> contextButtonAction = new Input.ExecuteAction(Input.ExecuteAction.CONTEXTMENU);
private final ApiMethod<String> osdButtonAction = new Input.ExecuteAction(Input.ExecuteAction.OSD);
@InjectView(R.id.info_panel) RelativeLayout infoPanel;
@InjectView(R.id.media_panel) RelativeLayout mediaPanel;
@InjectView(R.id.remote) ControlPad controlPad;
@BindView(R.id.info_panel) RelativeLayout infoPanel;
@BindView(R.id.media_panel) RelativeLayout mediaPanel;
@BindView(R.id.remote) ControlPad controlPad;
@InjectView(R.id.info_title) TextView infoTitle;
@InjectView(R.id.info_message) TextView infoMessage;
@BindView(R.id.info_title) TextView infoTitle;
@BindView(R.id.info_message) TextView infoMessage;
@InjectView(R.id.button_bar) LinearLayout buttonBarPanel;
@BindView(R.id.button_bar) LinearLayout buttonBarPanel;
/**
* Buttons
*/
@Optional @InjectView(R.id.home) ImageButton homeButton;
@Optional @InjectView(R.id.movies) ImageButton moviesButton;
@Optional @InjectView(R.id.tv_shows) ImageButton tvShowsButton;
@Optional @InjectView(R.id.music) ImageButton musicButton;
@Optional @InjectView(R.id.pvr) ImageButton pvrButton;
@Optional @InjectView(R.id.pictures) ImageButton picturesButton;
@Optional @InjectView(R.id.videos) ImageButton videosButton;
//@Optional @InjectView(R.id.favourites) ImageButton favouritesButton;
@Optional @InjectView(R.id.addons) ImageButton addonsButton;
@Optional @InjectView(R.id.weather) ImageButton weatherButton;
@Optional @InjectView(R.id.system) ImageButton systemButton;
@InjectView(R.id.art) ImageView thumbnail;
@InjectView(R.id.title) TextView nowPlayingTitle;
@InjectView(R.id.details) TextView nowPlayingDetails;
@InjectView(R.id.play) ImageButton playButton;
@InjectView(R.id.