From b1e227a2c0c22823a978d62ef4676e097d21bd28 Mon Sep 17 00:00:00 2001 From: Steven Schoen Date: Fri, 13 Jan 2017 05:25:31 -0500 Subject: [PATCH] Redo TV Files view to be a stack of folders, similar to phone --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 4 +- .../stevenschoen/putionew/LoginActivity.java | 1 - .../putionew/files/FolderFragment.kt | 2 +- .../putionew/files/FolderLoader.kt | 39 +++--- .../putionew/fragments/AboutFragment.java | 14 -- .../putionew/tv/HorizontalStackLayout.kt | 43 ++++++ .../stevenschoen/putionew/tv/TvActivity.java | 64 --------- .../stevenschoen/putionew/tv/TvActivity.kt | 98 ++++++++++++++ .../putionew/tv/TvFolderFragment.kt | 124 ++++++++++++++++++ .../putionew/tv/TvGridFragment.java | 122 ----------------- .../putionew/tv/TvPutioFileCardPresenter.java | 81 ------------ .../putionew/tv/TvPutioFileCardPresenter.kt | 68 ++++++++++ app/src/main/res/layout/tv_activity.xml | 22 ++-- app/src/main/res/values/colors_putio.xml | 2 + app/src/main/res/values/dimens.xml | 3 + app/src/main/res/values/styles_tv.xml | 16 +++ 17 files changed, 388 insertions(+), 319 deletions(-) create mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/HorizontalStackLayout.kt delete mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.java create mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.kt create mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvFolderFragment.kt delete mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvGridFragment.java delete mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.java create mode 100644 app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.kt create mode 100644 app/src/main/res/values/styles_tv.xml diff --git a/app/build.gradle b/app/build.gradle index 78fa7a57..173d2826 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,8 +24,8 @@ android { applicationId 'com.stevenschoen.putionew' minSdkVersion 19 targetSdkVersion 25 - versionCode 111 - versionName '4.0.9' + versionCode 112 + versionName '4.1-beta1' multiDexEnabled true } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47b74781..18de6a7b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -186,7 +186,7 @@ + android:theme="@style/Theme.Putio.Tv"> @@ -196,7 +196,7 @@ + android:theme="@style/Theme.Putio.Tv"/> \ No newline at end of file diff --git a/app/src/main/java/com/stevenschoen/putionew/LoginActivity.java b/app/src/main/java/com/stevenschoen/putionew/LoginActivity.java index 90cdfb96..946f5c03 100644 --- a/app/src/main/java/com/stevenschoen/putionew/LoginActivity.java +++ b/app/src/main/java/com/stevenschoen/putionew/LoginActivity.java @@ -194,7 +194,6 @@ void saveTokenFromWeb(final String url) { private void saveToken(String token) { sharedPrefs.edit().putString("token", token).commit(); Toast.makeText(this, R.string.loginsuccess, Toast.LENGTH_SHORT).show(); - setResult(RESULT_OK); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.removeAllCookie(); diff --git a/app/src/main/java/com/stevenschoen/putionew/files/FolderFragment.kt b/app/src/main/java/com/stevenschoen/putionew/files/FolderFragment.kt index d56126c3..aa624bc8 100644 --- a/app/src/main/java/com/stevenschoen/putionew/files/FolderFragment.kt +++ b/app/src/main/java/com/stevenschoen/putionew/files/FolderFragment.kt @@ -118,7 +118,7 @@ class FolderFragment : FileListFragment() { error.printStackTrace() Toast.makeText(context, R.string.network_error, Toast.LENGTH_SHORT).show() }) - folderLoader!!.getCachedFile() + folderLoader!!.publishCachedFileIfNeeded() folderLoader!!.refreshFolder(onlyIfStaleOrEmpty = true) updateViewState() } diff --git a/app/src/main/java/com/stevenschoen/putionew/files/FolderLoader.kt b/app/src/main/java/com/stevenschoen/putionew/files/FolderLoader.kt index fba280c6..cbc2845b 100644 --- a/app/src/main/java/com/stevenschoen/putionew/files/FolderLoader.kt +++ b/app/src/main/java/com/stevenschoen/putionew/files/FolderLoader.kt @@ -22,39 +22,36 @@ import java.io.IOException class FolderLoader(context: Context, private val folder: PutioFile) : PutioBaseLoader(context) { - val diskCache = DiskCache() + val diskCache by lazy { DiskCache() } private val folderSubject = BehaviorSubject.create() fun folder() = folderSubject.observeOn(AndroidSchedulers.mainThread()) - fun getCachedFile() { - Observable.fromCallable { - if (diskCache.isCached(folder.id)) { - return@fromCallable diskCache.getCached(folder.id) - } else { - return@fromCallable null - } + fun publishCachedFileIfNeeded() { + fun isNeeded() = (!folderSubject.hasValue() || !folderSubject.value.fresh) + if (isNeeded()) { + Observable.fromCallable { return@fromCallable if (diskCache.isCached(folder.id)) diskCache.getCached(folder.id) else null } + .subscribeOn(Schedulers.io()) + .filter { it != null } + .subscribe({ cachedResponse -> + cachedResponse!! + if (isNeeded()) { + folderSubject.onNext(FolderResponse(false, cachedResponse.parent, cachedResponse.files)) + } + }, { error -> + error.printStackTrace() + diskCache.deleteCached(folder.id) + }) } - .filter { it != null } - .subscribeOn(Schedulers.io()) - .subscribe({ cachedResponse -> - cachedResponse!! - if (!folderSubject.hasValue() || !folderSubject.value.fresh) { - folderSubject.onNext(FolderResponse(false, cachedResponse.parent, cachedResponse.files)) - } - }, { error -> - error.printStackTrace() - diskCache.deleteCached(folder.id) - }) } var refreshSubscription: Subscription? = null - fun refreshFolder(onlyIfStaleOrEmpty: Boolean = false) { + fun refreshFolder(onlyIfStaleOrEmpty: Boolean = false, cache: Boolean = true) { if (onlyIfStaleOrEmpty && (hasFresh() || isRefreshing())) return refreshSubscription?.unsubscribe() refreshSubscription = api.files(folder.id).subscribe({ response -> refreshSubscription = null - diskCache.cache(response) + if (cache) diskCache.cache(response) folderSubject.onNext(FolderResponse(true, response.parent, response.files)) }, { error -> refreshSubscription = null diff --git a/app/src/main/java/com/stevenschoen/putionew/fragments/AboutFragment.java b/app/src/main/java/com/stevenschoen/putionew/fragments/AboutFragment.java index bb86d6d5..668f617b 100644 --- a/app/src/main/java/com/stevenschoen/putionew/fragments/AboutFragment.java +++ b/app/src/main/java/com/stevenschoen/putionew/fragments/AboutFragment.java @@ -5,16 +5,13 @@ import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.support.v4.app.NavUtils; import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.stevenschoen.putionew.PutioActivity; import com.stevenschoen.putionew.R; public class AboutFragment extends Fragment { @@ -46,15 +43,4 @@ public void onClick(View v) { return view; } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - Intent homeIntent = new Intent(getActivity(), PutioActivity.class); - NavUtils.navigateUpTo(getActivity(), homeIntent); - return true; - } - return (super.onOptionsItemSelected(menuItem)); - } } \ No newline at end of file diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/HorizontalStackLayout.kt b/app/src/main/java/com/stevenschoen/putionew/tv/HorizontalStackLayout.kt new file mode 100644 index 00000000..1af618e7 --- /dev/null +++ b/app/src/main/java/com/stevenschoen/putionew/tv/HorizontalStackLayout.kt @@ -0,0 +1,43 @@ +package com.stevenschoen.putionew.tv + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup +import com.stevenschoen.putionew.R +import com.stevenschoen.putionew.UIUtils + +class HorizontalStackLayout : ViewGroup { + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) + + val layerOffset by lazy { resources.getDimensionPixelSize(R.dimen.tv_layer_offset) } + val layerElevation by lazy { resources.getDimension(R.dimen.tv_layer_elevation) } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + val childLeft = paddingLeft; + val childTop = paddingTop; + val childRight = measuredWidth - paddingRight; + val childBottom = measuredHeight - paddingBottom; + val childWidth = childRight - childLeft; + val childHeight = childBottom - childTop; + + for (i in 0..childCount - 1) { + val child = getChildAt(i) + val offset = (i * layerOffset) + child.measure(MeasureSpec.makeMeasureSpec(childWidth - offset, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)); + child.layout(childLeft + offset, childTop, childRight, childBottom) + if (UIUtils.hasLollipop()) { + child.elevation = (i * layerElevation) + } + } + } + + // Hacky, but without it sometimes the d-pad can go to the wrong page and become stuck + override fun focusSearch(focused: View?, direction: Int): View? { + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.java b/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.java deleted file mode 100644 index 34eac996..00000000 --- a/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.stevenschoen.putionew.tv; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; - -import com.stevenschoen.putionew.LoginActivity; -import com.stevenschoen.putionew.PutioApplication; -import com.stevenschoen.putionew.PutioUtils; -import com.stevenschoen.putionew.R; - -/** - * Created by simonreggiani on 15-01-10. - */ -public class TvActivity extends FragmentActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - PutioApplication application = (PutioApplication) getApplication(); - if (application.isLoggedIn()) { - init(); - } else { - Intent setupIntent = new Intent(this, LoginActivity.class); - startActivityForResult(setupIntent, 0); - } - - } - - private void init() { - setContentView(R.layout.tv_activity); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK) { - try { - ((PutioApplication) getApplication()).buildUtils(); - } catch (PutioUtils.NoTokenException e) { - e.printStackTrace(); - } - - init(); - } else { - finish(); - } - } - - @Override - public void onBackPressed() { - Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.tv_grid_fragment); - if (fragment != null && fragment instanceof TvGridFragment) { - TvGridFragment tvGridFragment = (TvGridFragment) fragment; - if (tvGridFragment.isRootFolder()) { - super.onBackPressed(); - } else { - tvGridFragment.goBack(); - } - } - } -} diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.kt b/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.kt new file mode 100644 index 00000000..30576172 --- /dev/null +++ b/app/src/main/java/com/stevenschoen/putionew/tv/TvActivity.kt @@ -0,0 +1,98 @@ +package com.stevenschoen.putionew.tv + +import android.content.Intent +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentActivity +import com.stevenschoen.putionew.LoginActivity +import com.stevenschoen.putionew.PutioApplication +import com.stevenschoen.putionew.R +import com.stevenschoen.putionew.model.files.PutioFile +import rx.subjects.BehaviorSubject +import java.util.* + +class TvActivity : FragmentActivity() { + + companion object { + fun makeFolderFragTag(folder: PutioFile) = "folder_${folder.id}" + } + + val displayedFolders = ArrayList() + val folders by lazy { BehaviorSubject.create>(listOf(PutioFile.makeRootFolder(resources))) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val application = application as PutioApplication + if (application.isLoggedIn) { + init() + } else { + val setupIntent = Intent(this, LoginActivity::class.java) + startActivity(setupIntent) + finish() + return + } + } + + fun init() { + setContentView(R.layout.tv_activity) + + val stackView = findViewById(R.id.tv_stack) as HorizontalStackLayout + + fun addFolder(folder: PutioFile) { + supportFragmentManager.beginTransaction() + .add(R.id.tv_stack, TvFolderFragment.newInstance(this@TvActivity, folder), makeFolderFragTag(folder)) + .commitNow() + displayedFolders.add(folder) + } + + fun removeLastFolder() { + val lastFolder = displayedFolders.last() + supportFragmentManager.beginTransaction() + .remove(supportFragmentManager.findFragmentByTag(makeFolderFragTag(lastFolder))) + .commitNow() + displayedFolders.removeAt(displayedFolders.lastIndex) + } + + addFolder(PutioFile.makeRootFolder(resources)) + + folders.subscribe { newFolders -> + while (displayedFolders.size > newFolders.size) { + removeLastFolder() + } + for ((index, newFolder) in newFolders.withIndex()) { + if (index <= displayedFolders.lastIndex) { + val displayedFolder = displayedFolders[index] + if (newFolder.id != displayedFolder.id) { + (index..displayedFolders.lastIndex).forEach { removeLastFolder() } + } + } else { + addFolder(newFolder) + } + } + getLastFolderFragment().requestFocusWhenPossible = true + } + } + + override fun onAttachFragment(fragment: Fragment) { + super.onAttachFragment(fragment) + if (fragment is TvFolderFragment) { + fragment.onFolderSelected = { folder -> + folders.onNext(folders.value.plus(folder)) + } + } + } + + fun getLastFolderFragment() = supportFragmentManager.findFragmentByTag(makeFolderFragTag(displayedFolders.last())) as TvFolderFragment + + override fun onBackPressed() { + if (displayedFolders.size > 1) { + val lastFolderFragment = supportFragmentManager.findFragmentByTag(makeFolderFragTag(displayedFolders.last())) + if (lastFolderFragment != null && lastFolderFragment is TvFolderFragment) { + folders.onNext(folders.value.dropLast(1)) + } + } else { + super.onBackPressed() + } + } +} diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvFolderFragment.kt b/app/src/main/java/com/stevenschoen/putionew/tv/TvFolderFragment.kt new file mode 100644 index 00000000..bb26effa --- /dev/null +++ b/app/src/main/java/com/stevenschoen/putionew/tv/TvFolderFragment.kt @@ -0,0 +1,124 @@ +package com.stevenschoen.putionew.tv + +import android.content.Context +import android.os.Bundle +import android.support.v17.leanback.app.VerticalGridSupportFragment +import android.support.v17.leanback.widget.ArrayObjectAdapter +import android.support.v17.leanback.widget.OnItemViewClickedListener +import android.support.v17.leanback.widget.VerticalGridPresenter +import android.support.v4.app.Fragment +import android.support.v4.content.ContextCompat +import android.transition.Slide +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import android.widget.Toast +import com.stevenschoen.putionew.R +import com.stevenschoen.putionew.UIUtils +import com.stevenschoen.putionew.files.FolderLoader +import com.stevenschoen.putionew.model.files.PutioFile +import rx.android.schedulers.AndroidSchedulers + +class TvFolderFragment : VerticalGridSupportFragment() { + + companion object { + private const val EXTRA_FOLDER = "folder" + + private const val NUM_COLUMNS = 3 + + fun newInstance(context: Context, folder: PutioFile): TvFolderFragment { + return Fragment.instantiate(context, TvFolderFragment::class.java.name, Bundle().apply { + putParcelable(EXTRA_FOLDER, folder) + }) as TvFolderFragment + } + } + + var onFolderSelected: ((folder: PutioFile) -> Unit)? = null + var requestFocusWhenPossible: Boolean = false + set(value) { + if (value && isVisible) { + view!!.apply { + post { + requestFocus() + } + } + } else { + field = value + } + } + + private var arrayAdapter: ArrayObjectAdapter? = null + private val folder by lazy { arguments.getParcelable(EXTRA_FOLDER)!! } + lateinit private var loader: FolderLoader + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (UIUtils.hasLollipop()) { + enterTransition = Slide(Gravity.END) + exitTransition = Slide(Gravity.END) + } + + title = folder.name + + gridPresenter = GridPresenter() + + arrayAdapter = ArrayObjectAdapter(TvPutioFileCardPresenter()) + adapter = arrayAdapter + + onItemViewClickedListener = OnItemViewClickedListener { itemViewHolder, item, rowViewHolder, row -> + if (item is PutioFile) { + if (item.isFolder) { + onFolderSelected?.invoke(item) + } else { + playVideo(item) + } + } + } + } + + override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return super.onCreateView(inflater, container, savedInstanceState)!!.apply { + setBackgroundColor(ContextCompat.getColor(context, R.color.putio_tv_background)) + + if (requestFocusWhenPossible) { + post { + requestFocus() + } + requestFocusWhenPossible = false + } + } + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + loader = FolderLoader.get(loaderManager, context, folder) + loader.refreshFolder(onlyIfStaleOrEmpty = true, cache = false) + loader.folder() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe({ + populateGrid(it.files) + }, { error -> + Toast.makeText(context, R.string.network_error, Toast.LENGTH_SHORT).show() + }) + } + + private fun playVideo(file: PutioFile) { + TvPlaybackOverlayActivity.launch(activity, file) + } + + private fun populateGrid(files: List) { + arrayAdapter!!.clear() + arrayAdapter!!.addAll(0, files.filter { it.isFolder || it.isMedia }) + } + + inner class GridPresenter : VerticalGridPresenter() { + + init { + numberOfColumns = NUM_COLUMNS + } + } +} diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvGridFragment.java b/app/src/main/java/com/stevenschoen/putionew/tv/TvGridFragment.java deleted file mode 100644 index a5d8f36a..00000000 --- a/app/src/main/java/com/stevenschoen/putionew/tv/TvGridFragment.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.stevenschoen.putionew.tv; - -import android.os.Bundle; -import android.support.v17.leanback.widget.ArrayObjectAdapter; -import android.support.v17.leanback.widget.OnItemViewClickedListener; -import android.support.v17.leanback.widget.Presenter; -import android.support.v17.leanback.widget.Row; -import android.support.v17.leanback.widget.RowPresenter; -import android.support.v17.leanback.widget.VerticalGridPresenter; - -import com.stevenschoen.putionew.PutioApplication; -import com.stevenschoen.putionew.PutioUtils; -import com.stevenschoen.putionew.R; -import com.stevenschoen.putionew.model.files.PutioFile; -import com.stevenschoen.putionew.model.responses.FilesListResponse; - -import java.util.ArrayList; -import java.util.List; - -import rx.functions.Action1; - -/** - * Created by simonreggiani on 15-01-11. - */ -public class TvGridFragment extends android.support.v17.leanback.app.VerticalGridSupportFragment { - - private static final int NUM_COLUMNS = 3; - - private ArrayObjectAdapter mAdapter; - private PutioUtils mUtils; - private PutioFile mCurrentFolder; - private long mCurrentFolderId = 0; - private List mCurrentFiles; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setTitle(getString(R.string.putio)); - - mUtils = ((PutioApplication) getActivity().getApplication()).getPutioUtils(); - - setupFragment(); - } - - private void setupFragment() { - VerticalGridPresenter gridPresenter = new VerticalGridPresenter(); - gridPresenter.setNumberOfColumns(NUM_COLUMNS); - setGridPresenter(gridPresenter); - - mAdapter = new ArrayObjectAdapter(new TvPutioFileCardPresenter()); - - setAdapter(mAdapter); - - setOnItemViewClickedListener(new OnItemViewClickedListener() { - @Override - public void onItemClicked(Presenter.ViewHolder viewHolder, Object o, RowPresenter.ViewHolder viewHolder2, Row row) { - if (o instanceof PutioFile) { - PutioFile file = (PutioFile) o; - if (file.isFolder()) { - loadFolder(file); - } else { - playVideo(file); - } - } - } - }); - - loadFiles(); - } - - private void loadFolder(PutioFile folder) { - mCurrentFolderId = folder.getId(); - loadFiles(); - } - - private void playVideo(PutioFile file) { - TvPlaybackOverlayActivity.launch(getActivity(), file); - } - - private void loadFiles() { - mUtils.getRestInterface().files(mCurrentFolderId) - .subscribe(new Action1() { - @Override - public void call(FilesListResponse filesListResponse) { - populateGrid(filesListResponse.getFiles(), filesListResponse.getParent()); - } - }, new Action1() { - @Override - public void call(Throwable throwable) { - throwable.printStackTrace(); - } - }); - } - - private void populateGrid(List files, PutioFile parent) { - // filter only folders and media files - List onlyMediaAndFolders = new ArrayList<>(files.size()); - for (PutioFile file : files) { - if (file.isFolder() || file.isMedia()) { - onlyMediaAndFolders.add(file); - } - } - - // only refresh if changes - if (!onlyMediaAndFolders.equals(mCurrentFiles)) { - mCurrentFolder = parent; - mCurrentFiles = onlyMediaAndFolders; - mAdapter.clear(); - mAdapter.addAll(0, mCurrentFiles); - } - } - - public boolean isRootFolder() { - return mCurrentFolderId == 0; - } - - public void goBack() { - mCurrentFolderId = mCurrentFolder.getParentId(); - loadFiles(); - } -} diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.java b/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.java deleted file mode 100644 index 4315cf51..00000000 --- a/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * 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 com.stevenschoen.putionew.tv; - -import android.content.Context; -import android.support.v17.leanback.widget.ImageCardView; -import android.support.v17.leanback.widget.Presenter; -import android.util.Log; -import android.view.ViewGroup; -import android.widget.ImageView; - -import com.squareup.picasso.Picasso; -import com.stevenschoen.putionew.R; -import com.stevenschoen.putionew.model.files.PutioFile; - -/* - * A TvPutFileCardPresenter is used to generate Views and bind Objects to them on demand. - * It contains an Image CardView - */ -public class TvPutioFileCardPresenter extends Presenter { - private static final String TAG = "TvPutFileCardPresenter"; - - private static Context mContext; - private static int CARD_WIDTH = 500; - private static int CARD_HEIGHT = 176; - - @Override - public ViewHolder onCreateViewHolder(ViewGroup parent) { - Log.d(TAG, "onCreateViewHolder"); - mContext = parent.getContext(); - - ImageCardView cardView = new ImageCardView(mContext); - cardView.setFocusable(true); - cardView.setFocusableInTouchMode(true); - return new ViewHolder(cardView); - } - - @Override - public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { - PutioFile file = (PutioFile) item; - ImageCardView cardView = (ImageCardView) viewHolder.view; - - cardView.setTitleText(file.getName()); - //cardView.setContentText(PutioUtils.humanReadableByteCount(file.size, false)); - cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT); - ImageView mainImageView = cardView.getMainImageView(); - if (file.isFolder()) { - cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE); - Picasso.with(mContext).load(R.drawable.ic_putio_folder_accent).into(mainImageView); - } else { - cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP); - Picasso.with(mContext).load(file.getScreenshot()).into(mainImageView); - } - - if (file.isAccessed()) { - cardView.setBadgeImage(mContext.getResources().getDrawable(R.drawable.ic_fileinfo_accessed)); - // weird bug with fade mask, remove it for now -// cardView.findViewById(android.support.v17.leanback.R.id.fade_mask).setVisibility(View.GONE); - } - } - - @Override - public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { - ImageCardView cardView = (ImageCardView) viewHolder.view; - // Remove references to images so that the garbage collector can free up memory - cardView.setBadgeImage(null); - cardView.setMainImage(null); - } -} diff --git a/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.kt b/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.kt new file mode 100644 index 00000000..4bd1e612 --- /dev/null +++ b/app/src/main/java/com/stevenschoen/putionew/tv/TvPutioFileCardPresenter.kt @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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 com.stevenschoen.putionew.tv + +import android.support.v17.leanback.widget.ImageCardView +import android.support.v17.leanback.widget.Presenter +import android.support.v4.content.ContextCompat +import android.view.ViewGroup +import android.widget.ImageView +import com.squareup.picasso.Picasso +import com.stevenschoen.putionew.R +import com.stevenschoen.putionew.model.files.PutioFile + +class TvPutioFileCardPresenter : Presenter() { + + companion object { + private val CARD_WIDTH = 500 + private val CARD_HEIGHT = 176 + } + + override fun onCreateViewHolder(parent: ViewGroup): Presenter.ViewHolder { + val cardView = ImageCardView(parent.context) + cardView.isFocusable = true + cardView.isFocusableInTouchMode = true + return Presenter.ViewHolder(cardView) + } + + override fun onBindViewHolder(viewHolder: Presenter.ViewHolder, item: Any) { + val file = item as PutioFile + val cardView = viewHolder.view as ImageCardView + + cardView.titleText = file.name + //cardView.setContentText(PutioUtils.humanReadableByteCount(file.size, false)); + cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT) + val mainImageView = cardView.mainImageView + if (file.isFolder) { + cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE) + Picasso.with(mainImageView.context).cancelRequest(mainImageView) + mainImageView.setImageResource(R.drawable.ic_putio_folder_accent) + } else { + cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP) + Picasso.with(mainImageView.context).load(file.screenshot).into(mainImageView) + } + + if (file.isAccessed) { + cardView.badgeImage = ContextCompat.getDrawable(cardView.context, R.drawable.ic_fileinfo_accessed) + } + } + + override fun onUnbindViewHolder(viewHolder: Presenter.ViewHolder) { + val cardView = viewHolder.view as ImageCardView + // Remove references to images so that the garbage collector can free up memory + cardView.badgeImage = null + cardView.mainImage = null + } +} diff --git a/app/src/main/res/layout/tv_activity.xml b/app/src/main/res/layout/tv_activity.xml index 38742dd7..613512a2 100644 --- a/app/src/main/res/layout/tv_activity.xml +++ b/app/src/main/res/layout/tv_activity.xml @@ -1,13 +1,13 @@ - + - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors_putio.xml b/app/src/main/res/values/colors_putio.xml index 800af7ad..0142f971 100644 --- a/app/src/main/res/values/colors_putio.xml +++ b/app/src/main/res/values/colors_putio.xml @@ -11,4 +11,6 @@ #FF4040 #1f000000 + + #202020 \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 3c81cdce..4a812b8d 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -16,4 +16,7 @@ 8dp 8dp + + 40dp + 6dp \ No newline at end of file diff --git a/app/src/main/res/values/styles_tv.xml b/app/src/main/res/values/styles_tv.xml new file mode 100644 index 00000000..3d250a61 --- /dev/null +++ b/app/src/main/res/values/styles_tv.xml @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file