/* * ************************************************************************* * NetworkBrowseFragment.java * ************************************************************************** * Copyright © 2015 VLC authors and VideoLAN * Author: Geoffrey Métais * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * *************************************************************************** */ package org.videolan.vlc.gui.tv.browser; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.Parcelable; import android.support.v17.leanback.app.BrowseFragment; import android.support.v17.leanback.widget.ArrayObjectAdapter; import android.support.v17.leanback.widget.HeaderItem; import android.support.v17.leanback.widget.ListRow; import android.support.v17.leanback.widget.ListRowPresenter; import android.support.v17.leanback.widget.OnItemViewClickedListener; import android.support.v17.leanback.widget.OnItemViewSelectedListener; import android.support.v17.leanback.widget.Presenter; import android.support.v17.leanback.widget.Row; import android.support.v17.leanback.widget.RowPresenter; import android.support.v4.util.ArrayMap; import org.videolan.libvlc.Media; import org.videolan.libvlc.util.MediaBrowser; import org.videolan.vlc.MediaWrapper; import org.videolan.vlc.R; import org.videolan.vlc.VLCApplication; import org.videolan.vlc.gui.audio.MediaComparators; import org.videolan.vlc.gui.browser.BaseBrowserFragment; import org.videolan.vlc.gui.tv.CardPresenter; import org.videolan.vlc.gui.tv.DetailsActivity; import org.videolan.vlc.gui.tv.MediaItemDetails; import org.videolan.vlc.gui.tv.TvUtil; import org.videolan.vlc.gui.tv.browser.interfaces.BrowserActivityInterface; import org.videolan.vlc.gui.tv.browser.interfaces.BrowserFragmentInterface; import org.videolan.vlc.util.VLCInstance; import org.videolan.vlc.util.WeakHandler; import java.util.ArrayList; import java.util.Collections; import java.util.Map; import java.util.TreeMap; public class NetworkBrowserFragment extends BrowseFragment implements BrowserFragmentInterface, MediaBrowser.EventListener, OnItemViewSelectedListener, OnItemViewClickedListener { public static final String TAG = "VLC/NetworkBrowserFragment"; public static final String SELECTED_ITEM = "selected"; public static int UPDATE_DISPLAY = 1; ArrayObjectAdapter mAdapter = new ArrayObjectAdapter(new ListRowPresenter()); private MediaBrowser mMediaBrowser; private MediaWrapper mItemSelected; protected Map<String, ListItem> mMediaItemMap = new ArrayMap<String, ListItem>(); private NetworkHandler mHandler = new NetworkHandler(this); private Uri mUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null){ String mrl = savedInstanceState.getString(BaseBrowserFragment.KEY_MRL); if (mrl != null) mUri = Uri.parse(mrl); mItemSelected = savedInstanceState.getParcelable(SELECTED_ITEM); } else { Intent intent = getActivity().getIntent(); if (intent != null && intent.hasExtra(BaseBrowserFragment.KEY_MRL)) mUri = Uri.parse(intent.getStringExtra(BaseBrowserFragment.KEY_MRL)); } setOnItemViewClickedListener(this); setOnItemViewSelectedListener(this); setAdapter(mAdapter); // UI setting setHeadersState(HEADERS_ENABLED); setBrandColor(getResources().getColor(R.color.orange800)); } public void onResume() { super.onResume(); if (mAdapter.size() == 0) { browse(); } } public void onPause(){ super.onPause(); if (mMediaBrowser != null) { mMediaBrowser.release(); mMediaBrowser = null; } ((BrowserActivityInterface)getActivity()).updateEmptyView(false); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mUri != null) outState.putString(BaseBrowserFragment.KEY_MRL, mUri.toString()); if (mItemSelected != null) { outState.putParcelable(SELECTED_ITEM, mItemSelected); } } private void browse() { mMediaBrowser = new MediaBrowser(VLCInstance.get(), this); if (mMediaBrowser != null) { if (mUri != null) mMediaBrowser.browse(mUri); else mMediaBrowser.discoverNetworkShares(); ((BrowserActivityInterface)getActivity()).showProgress(true); } } @Override public void refresh() { mAdapter.clear(); browse(); } private void sort(){ VLCApplication.runBackground(new Runnable() { @Override public void run() { mMediaItemMap = new TreeMap<>(mMediaItemMap); //sort sections for (ListItem item : mMediaItemMap.values()) { Collections.sort(item.mediaList, MediaComparators.byName); } mHandler.sendEmptyMessage(UPDATE_DISPLAY); } }); } @Override public void updateList() { mAdapter.clear(); ArrayObjectAdapter adapter; HeaderItem header; for (ListItem item : mMediaItemMap.values()){ adapter = new ArrayObjectAdapter(new CardPresenter(getActivity())); header = new HeaderItem(0, item.Letter); adapter.addAll(0, item.mediaList); mAdapter.add(new ListRow(header, adapter)); } ((BrowserActivityInterface)getActivity()).updateEmptyView(mAdapter.size() == 0); } private void addMedia(Media media){ addMedia(new MediaWrapper(media)); } private void addMedia(MediaWrapper media){ int type = media.getType(); if (type != MediaWrapper.TYPE_AUDIO && type != MediaWrapper.TYPE_VIDEO && type != MediaWrapper.TYPE_DIR) return; String letter = media.getTitle().substring(0, 1).toUpperCase(); if (mMediaItemMap.containsKey(letter)){ mMediaItemMap.get(letter).mediaList.add(media); } else { ListItem item = new ListItem(letter, media); mMediaItemMap.put(letter, item); } } public void onMediaAdded(int index, Media media) { addMedia(media); if (mUri == null) { // we are at root level sort(); } ((BrowserActivityInterface)getActivity()).showProgress(false); } public void onMediaRemoved(int index, Media media) {} public void onBrowseEnd() { ((BrowserActivityInterface)getActivity()).showProgress(false); ((BrowserActivityInterface)getActivity()).updateEmptyView(mAdapter.size() == 0); sort(); } public void showDetails() { if (mItemSelected == null) return; if (mItemSelected.getType() == MediaWrapper.TYPE_DIR) { Intent intent = new Intent(getActivity(), DetailsActivity.class); // pass the item information intent.putExtra("media", mItemSelected); intent.putExtra("item", (Parcelable) new MediaItemDetails(mItemSelected.getTitle(), mItemSelected.getArtist(), mItemSelected.getAlbum(), mItemSelected.getLocation())); startActivity(intent); } } @Override public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { mItemSelected = (MediaWrapper)item; } @Override public void onItemClicked(Presenter.ViewHolder viewHolder, Object item, RowPresenter.ViewHolder viewHolder1, Row row) { TvUtil.openMedia(getActivity(), item, null); } public static class ListItem { public String Letter; public ArrayList<MediaWrapper> mediaList; public ListItem(String letter, MediaWrapper MediaWrapper) { mediaList = new ArrayList<MediaWrapper>(); if (MediaWrapper != null) mediaList.add(MediaWrapper); Letter = letter; } } private class NetworkHandler extends WeakHandler<NetworkBrowserFragment> { public NetworkHandler(NetworkBrowserFragment owner) { super(owner); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); NetworkBrowserFragment owner = getOwner(); if (owner != null && msg.what == UPDATE_DISPLAY) owner.updateList(); } } }