This commit is contained in:
Yuriy Liskov 2020-08-25 20:43:13 +03:00
parent 1df3c0ea49
commit 369afd78cd
996 changed files with 478 additions and 245 deletions

6
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "SharedUtils"]
path = SharedUtils
url = https://github.com/yuliskov/SharedUtils
[submodule "SharedModules"]
path = SharedModules
url = https://github.com/yuliskov/SharedModules
[submodule "MediaServiceCore"]
path = MediaServiceCore
url = https://github.com/yuliskov/MediaServiceCore

@ -1 +1 @@
Subproject commit 2a01572410979075538af75a63933fd3517a456b
Subproject commit a20c7c7edc29b8d6bb6bb0097a7c68cd7af09fc6

@ -1 +1 @@
Subproject commit 29b44e7cd765e3cf9e601144f48988f71e8ae6fd
Subproject commit 02f9856f08fa3a38a783282ab5eb3134fab62fe9

View File

@ -0,0 +1,27 @@
package com.liskovsoft.smartyoutubetv2.common.mvp.models;
public class Header {
private int mId;
private String mTitle;
public Header(int id, String title) {
mId = id;
mTitle = title;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.model;
package com.liskovsoft.smartyoutubetv2.common.mvp.models;
import android.media.MediaDescription;
import android.os.Parcel;

View File

@ -0,0 +1,71 @@
package com.liskovsoft.smartyoutubetv2.common.mvp.models;
import com.liskovsoft.mediaserviceinterfaces.data.MediaGroup;
import com.liskovsoft.mediaserviceinterfaces.data.MediaItem;
import java.util.ArrayList;
import java.util.List;
public class VideoGroup {
private int mId;
private String mTitle;
private List<Video> mVideos;
public static VideoGroup from(MediaGroup mediaGroup) {
VideoGroup videoGroup = new VideoGroup();
videoGroup.mId = mediaGroup.hashCode(); // TODO: replace with real id
videoGroup.mTitle = mediaGroup.getTitle();
videoGroup.mVideos = new ArrayList<>();
for (MediaItem item : mediaGroup.getMediaItems()) {
long id = item.getId();
String title = item.getTitle();
String category = item.getContentType();
String desc = item.getDescription();
String videoUrl = item.getMediaUrl();
String bgImageUrl = item.getBackgroundImageUrl();
String cardImageUrl = item.getCardImageUrl();
String studio = item.getDescription();
// Build a Video object to be processed.
Video video = new Video.VideoBuilder()
.id(id)
.title(title)
.category(category)
.description(desc)
.videoUrl(videoUrl)
.bgImageUrl(bgImageUrl)
.cardImageUrl(cardImageUrl)
.studio(studio)
.build();
videoGroup.mVideos.add(video);
}
return videoGroup;
}
public List<Video> getVideos() {
return mVideos;
}
public void setVideos(List<Video> videos) {
mVideos = videos;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public int getId() {
return mId;
}
public void setId(int id) {
mId = id;
}
}

View File

@ -1,26 +1,32 @@
package com.liskovsoft.smartyoutubetv2.common.presenters;
package com.liskovsoft.smartyoutubetv2.common.mvp.presenters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import com.liskovsoft.mediaserviceinterfaces.data.MediaGroup;
import com.liskovsoft.mediaserviceinterfaces.MediaGroupManager;
import com.liskovsoft.mediaserviceinterfaces.MediaService;
import com.liskovsoft.mediaserviceinterfaces.data.MediaGroup;
import com.liskovsoft.sharedutils.mylogger.Log;
import com.liskovsoft.smartyoutubetv2.common.R;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Header;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.VideoGroup;
import com.liskovsoft.smartyoutubetv2.common.mvp.views.MainView;
import com.liskovsoft.smartyoutubetv2.common.prefs.AppPrefs;
import com.liskovsoft.smartyoutubetv2.common.views.MainView;
import com.liskovsoft.youtubeapi.service.YouTubeMediaService;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class MainPresenter extends Presenter<MainView> {
public class MainPresenter extends PresenterBase<MainView> {
private static final String TAG = MainPresenter.class.getSimpleName();
@SuppressLint("StaticFieldLeak")
private static MainPresenter sInstance;
private final Handler mHandler = new Handler();
private final Context mContext;
private final ArrayList<MediaGroup> mMediaGroups;
private final Map<Integer, Header> mHeaders = new HashMap<>();
private MainPresenter(Context context) {
mMediaGroups = new ArrayList<>();
@ -43,9 +49,15 @@ public class MainPresenter extends Presenter<MainView> {
}
}
initHeaders();
loadHomeData();
}
private void initHeaders() {
mHeaders.put(MediaGroup.TYPE_HOME, new Header(MediaGroup.TYPE_HOME, mContext.getString(R.string.home_header)));
}
// TODO: implement Android TV channels
//private void updateRecommendations() {
// Intent recommendationIntent = new Intent(mContext, UpdateRecommendationsService.class);
// mContext.startService(recommendationIntent);
@ -56,7 +68,7 @@ public class MainPresenter extends Presenter<MainView> {
MediaService service = YouTubeMediaService.instance();
MediaGroupManager mediaGroupManager = service.getMediaGroupManager();
mediaGroupManager.getHomeGroupObserve()
mediaGroupManager.getHomeObserve()
.subscribeOn(Schedulers.newThread())
.subscribe(nextMediaGroup -> {
@ -67,7 +79,7 @@ public class MainPresenter extends Presenter<MainView> {
for (MediaGroup mediaGroup : nextMediaGroup) {
for (MainView view : mViews) {
view.addHomeGroup(mediaGroup);
view.updateRow(VideoGroup.from(mediaGroup), mHeaders.get(MediaGroup.TYPE_HOME));
}
mMediaGroups.add(mediaGroup);
@ -82,8 +94,13 @@ public class MainPresenter extends Presenter<MainView> {
mediaGroupManager.continueGroupObserve(mediaGroup)
.subscribeOn(Schedulers.newThread())
.subscribe(nextMediaGroup -> {
if (nextMediaGroup == null) {
Log.e(TAG, "Next Home groups are empty");
return;
}
for (MainView view : mViews) {
view.continueHomeGroup(mediaGroup);
view.updateRow(VideoGroup.from(nextMediaGroup), mHeaders.get(MediaGroup.TYPE_HOME));
}
});
}

View File

@ -1,11 +1,11 @@
package com.liskovsoft.smartyoutubetv2.common.presenters;
package com.liskovsoft.smartyoutubetv2.common.mvp.presenters;
import android.annotation.SuppressLint;
import android.content.Context;
import com.liskovsoft.smartyoutubetv2.common.prefs.AppPrefs;
import com.liskovsoft.smartyoutubetv2.common.views.OnboardingView;
import com.liskovsoft.smartyoutubetv2.common.mvp.views.OnboardingView;
public class OnboardingPresenter extends Presenter<OnboardingView> {
public class OnboardingPresenter extends PresenterBase<OnboardingView> {
@SuppressLint("StaticFieldLeak")
private static OnboardingPresenter sInstance;
private final Context mContext;

View File

@ -1,9 +1,9 @@
package com.liskovsoft.smartyoutubetv2.common.presenters;
package com.liskovsoft.smartyoutubetv2.common.mvp.presenters;
import java.util.ArrayList;
import java.util.List;
public abstract class Presenter<T> {
public abstract class PresenterBase<T> {
protected final List<T> mViews = new ArrayList<T>();
public void subscribe(T view) {

View File

@ -0,0 +1,12 @@
package com.liskovsoft.smartyoutubetv2.common.mvp.views;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Header;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.VideoGroup;
public interface MainView {
void updateRow(VideoGroup group, Header header);
void updateGrid(VideoGroup group, Header header);
void clearRow(Header header);
void clearGrid(Header header);
void showOnboarding();
}

View File

@ -1,4 +1,4 @@
package com.liskovsoft.smartyoutubetv2.common.views;
package com.liskovsoft.smartyoutubetv2.common.mvp.views;
public interface OnboardingView {
void finishOnboarding();

View File

@ -1,9 +0,0 @@
package com.liskovsoft.smartyoutubetv2.common.views;
import com.liskovsoft.mediaserviceinterfaces.data.MediaGroup;
public interface MainView {
void addHomeGroup(MediaGroup homeGroup);
void continueHomeGroup(MediaGroup homeGroup);
void showOnboarding();
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="home_header">Home</string>
</resources>

View File

@ -1,4 +1,4 @@
include ':tvapp', ':common'
include ':smartyoutubetv2', ':common'
def rootDir = settingsDir

View File

@ -7,11 +7,11 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import com.liskovsoft.smartyoutubetv2.tv.data.FetchVideoService;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract.VideoEntry;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoDbBuilder;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoDbHelper;
import com.liskovsoft.smartyoutubetv2.tv.data.old.FetchVideoService;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract.VideoEntry;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoDbBuilder;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoDbHelper;
import org.json.JSONArray;
import org.json.JSONException;

View File

@ -4,7 +4,7 @@ import android.media.MediaDescription;
import android.net.Uri;
import android.os.Parcel;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -60,7 +60,7 @@
android:theme="@style/Theme.Leanback"
tools:ignore="GoogleAppIndexingWarning,LockedOrientationActivity,UnusedAttribute">
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.MainActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.main.MainActivity"
android:icon="@drawable/videos_by_google_banner"
android:label="@string/app_name"
android:logo="@drawable/videos_by_google_banner"
@ -87,7 +87,7 @@
<meta-data android:name="android.app.default_searchable"
android:value=".ui.VideoDetailsActivity" />
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.VideoDetailsActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity"
android:exported="true"
android:screenOrientation="landscape"
android:theme="@style/Theme.Leanback.Details">
@ -104,26 +104,26 @@
android:resource="@xml/searchable" />
</activity>
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.PlaybackActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.playback.PlaybackActivity"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|layoutDirection"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:screenOrientation="landscape"/>
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.VerticalGridActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.old.VerticalGridActivity"
android:exported="true"
android:parentActivityName="com.liskovsoft.smartyoutubetv2.tv.ui.MainActivity"
android:parentActivityName="com.liskovsoft.smartyoutubetv2.tv.ui.main.MainActivity"
android:screenOrientation="landscape"
android:theme="@style/Theme.Leanback.VerticalGrid" />
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.SearchActivity" />
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.search.SearchActivity" />
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.GuidedStepActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.old.GuidedStepActivity"
android:screenOrientation="landscape"
android:theme="@style/Theme.Example.Leanback.GuidedStep" />
<!-- Provides search suggestions for keywords against video metadata. -->
<provider
android:name="com.liskovsoft.smartyoutubetv2.tv.data.VideoProvider"
android:name="com.liskovsoft.smartyoutubetv2.tv.data.old.VideoProvider"
android:authorities="${packageName}"
android:permission="${applicationId}.ACCESS_VIDEO_DATA"
android:exported="true">
@ -133,7 +133,7 @@
</provider>
<receiver
android:name="com.liskovsoft.smartyoutubetv2.tv.recommendation.RecommendationReceiver"
android:name="com.liskovsoft.smartyoutubetv2.tv.recommendation.old.RecommendationReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
@ -142,24 +142,24 @@
</receiver>
<service
android:name="com.liskovsoft.smartyoutubetv2.tv.data.FetchVideoService"
android:name="com.liskovsoft.smartyoutubetv2.tv.data.old.FetchVideoService"
android:exported="false" />
<service
android:name="com.liskovsoft.smartyoutubetv2.tv.recommendation.UpdateRecommendationsService"
android:name="com.liskovsoft.smartyoutubetv2.tv.recommendation.old.UpdateRecommendationsService"
android:enabled="true" />
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.OnboardingActivity"
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.onboarding.OnboardingActivity"
android:enabled="true"
android:exported="true"
android:screenOrientation="landscape"
android:theme="@style/Theme.Leanback.Onboarding" />
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.SettingsActivity"
<activity android:name="com.liskovsoft.smartyoutubetv2.tv.ui.old.SettingsActivity"
android:exported="true"
android:screenOrientation="landscape"
android:theme="@style/LeanbackPreferences"
/>
<activity
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.AuthenticationActivity"
android:name="com.liskovsoft.smartyoutubetv2.tv.ui.old.AuthenticationActivity"
android:screenOrientation="landscape"
android:theme="@style/Theme.Example.Leanback.GuidedStep" />
</application>

View File

@ -0,0 +1,36 @@
package com.liskovsoft.smartyoutubetv2.tv.adapter;
import androidx.leanback.widget.ObjectAdapter;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.VideoGroup;
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
import java.util.List;
public class VideoGroupObjectAdapter extends ObjectAdapter {
private static final String TAG = VideoGroupObjectAdapter.class.getSimpleName();
private final List<Video> mMediaItems;
private final VideoGroup mMediaGroup;
public VideoGroupObjectAdapter(VideoGroup videoGroup) {
super(new CardPresenter());
mMediaGroup = videoGroup;
mMediaItems = videoGroup.getVideos();
}
@Override
public int size() {
return mMediaItems.size();
}
@Override
public Object get(int position) {
return mMediaItems.get(position);
}
public void append(VideoGroup mediaTab) {
if (mMediaItems != null && mediaTab != null) {
mMediaItems.addAll(mediaTab.getVideos());
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.data;
package com.liskovsoft.smartyoutubetv2.tv.data.old;
import android.app.IntentService;
import android.content.ContentValues;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.data;
package com.liskovsoft.smartyoutubetv2.tv.data.old;
import android.app.SearchManager;
import android.content.ContentResolver;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.data;
package com.liskovsoft.smartyoutubetv2.tv.data.old;
import android.content.ContentValues;
import android.content.Context;

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.data;
package com.liskovsoft.smartyoutubetv2.tv.data.old;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract.VideoEntry;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract.VideoEntry;
/**
* VideoDbHelper manages the creation and upgrade of the database used in this sample.

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.data;
package com.liskovsoft.smartyoutubetv2.tv.data.old;
import android.app.SearchManager;
import android.content.ContentProvider;

View File

@ -1,4 +1,4 @@
package com.liskovsoft.smartyoutubetv2.tv.mobile;
package com.liskovsoft.smartyoutubetv2.tv.mobile.old;
import android.app.Activity;
import android.os.Bundle;

View File

@ -16,6 +16,8 @@
package com.liskovsoft.smartyoutubetv2.tv.model;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import java.util.ArrayList;
import java.util.List;

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.model;
package com.liskovsoft.smartyoutubetv2.tv.model.old;
import android.database.Cursor;
import androidx.leanback.database.CursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
/**
* VideoCursorMapper maps a database Cursor to a Video object.

View File

@ -27,7 +27,7 @@ import android.view.ViewGroup;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
/*
* A CardPresenter is used to generate Views and bind Objects to them on demand.

View File

@ -18,7 +18,7 @@ package com.liskovsoft.smartyoutubetv2.tv.presenter;
import androidx.leanback.widget.AbstractDetailsDescriptionPresenter;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter {

View File

@ -25,7 +25,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.MainFragment;
import com.liskovsoft.smartyoutubetv2.tv.ui.main.MainFragment;
public class GridItemPresenter extends Presenter {
private final MainFragment mainFragment;

View File

@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
import androidx.core.content.ContextCompat;
import androidx.leanback.widget.HeaderItem;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.PageRow;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.RowHeaderPresenter;
import android.view.LayoutInflater;
@ -50,7 +51,14 @@ public class IconHeaderItemPresenter extends RowHeaderPresenter {
@Override
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
HeaderItem headerItem = ((ListRow) item).getHeaderItem();
HeaderItem headerItem;
if (item instanceof PageRow) {
headerItem = ((PageRow) item).getHeaderItem();
} else {
headerItem = ((ListRow) item).getHeaderItem();
}
View rootView = viewHolder.view;
rootView.setFocusable(true);

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.recommendation;
package com.liskovsoft.smartyoutubetv2.tv.recommendation.old;
import android.app.AlarmManager;
import android.app.PendingIntent;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.recommendation;
package com.liskovsoft.smartyoutubetv2.tv.recommendation.old;
import android.app.IntentService;
import android.app.Notification;
@ -33,10 +33,10 @@ import android.util.Log;
import com.bumptech.glide.Glide;
import com.liskovsoft.smartyoutubetv2.tv.BuildConfig;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.ui.VideoDetailsActivity;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity;
import java.util.concurrent.ExecutionException;

View File

@ -1,7 +1,8 @@
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.base;
import android.content.Intent;
import androidx.fragment.app.FragmentActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.search.SearchActivity;
/**
* This parent class contains common methods that run in every activity such as search.

View File

@ -0,0 +1,6 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.main;
import androidx.fragment.app.Fragment;
public class GridFragment extends Fragment {
}

View File

@ -0,0 +1,17 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.main;
import android.os.Bundle;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.base.LeanbackActivity;
/*
* MainActivity class that loads MainFragment.
*/
public class MainActivity extends LeanbackActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

View File

@ -1,4 +1,4 @@
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.main;
import android.content.Context;
import android.content.Intent;
@ -12,6 +12,7 @@ import android.view.View;
import android.widget.Toast;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.leanback.app.BackgroundManager;
import androidx.leanback.app.BrowseSupportFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
@ -21,6 +22,7 @@ import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.ListRowPresenter;
import androidx.leanback.widget.OnItemViewClickedListener;
import androidx.leanback.widget.OnItemViewSelectedListener;
import androidx.leanback.widget.PageRow;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.PresenterSelector;
import androidx.leanback.widget.Row;
@ -29,15 +31,21 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Header;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.VideoGroup;
import com.liskovsoft.smartyoutubetv2.common.mvp.presenters.MainPresenter;
import com.liskovsoft.smartyoutubetv2.common.mvp.views.MainView;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.adapter.MediaGroupObjectAdapter;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.presenter.GridItemPresenter;
import com.liskovsoft.smartyoutubetv2.tv.presenter.IconHeaderItemPresenter;
import com.liskovsoft.mediaserviceinterfaces.data.MediaGroup;
import com.liskovsoft.sharedutils.mylogger.Log;
import com.liskovsoft.smartyoutubetv2.common.presenters.MainPresenter;
import com.liskovsoft.smartyoutubetv2.common.views.MainView;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.BrowseErrorFragment;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.GuidedStepActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.SettingsActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VerticalGridActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.onboarding.OnboardingActivity;
import com.liskovsoft.smartyoutubetv2.tv.ui.search.SearchActivity;
import java.util.HashMap;
import java.util.Map;
@ -56,16 +64,15 @@ public class MainFragment extends BrowseSupportFragment implements MainView {
private Uri mBackgroundURI;
private BackgroundManager mBackgroundManager;
// Maps a Loader Id to its Adapter.
private Map<Integer, MediaGroupObjectAdapter> mMediaGroupAdapters;
private MainPresenter mPresenter;
private Map<Integer, Header> mHeaders;
private PageRowFragmentFactory mPageRowFragmentFactory;
@Override
public void onAttach(Context context) {
super.onAttach(context);
// Each adapter is used to render a specific row of videos in the MainFragment.
mMediaGroupAdapters = new HashMap<>();
mHeaders = new HashMap<>();
mPresenter = MainPresenter.instance(context.getApplicationContext());
mPresenter.subscribe(this);
}
@ -87,6 +94,9 @@ public class MainFragment extends BrowseSupportFragment implements MainView {
mCategoryRowAdapter = new ArrayObjectAdapter(new ListRowPresenter());
setAdapter(mCategoryRowAdapter);
mPageRowFragmentFactory = new PageRowFragmentFactory(mBackgroundManager);
getMainFragmentRegistry().registerFragment(PageRow.class, mPageRowFragmentFactory);
initRowAdapters();
}
@ -261,45 +271,106 @@ public class MainFragment extends BrowseSupportFragment implements MainView {
}
@Override
public void addHomeGroup(MediaGroup homeGroup) {
// Create header for this category.
String category = homeGroup.getTitle();
if (category == null) {
category = getString(R.string.no_title);
public void updateRow(VideoGroup group, Header header) {
if (mHeaders.get(header.getId()) == null) {
mHeaders.put(header.getId(), header);
createMultiRowHeader(header);
}
HeaderItem header = new HeaderItem(category);
int mediaGroupId = homeGroup.hashCode(); // Create unique int from category.
MediaGroupObjectAdapter existingAdapter = mMediaGroupAdapters.get(mediaGroupId);
if (existingAdapter == null) {
MediaGroupObjectAdapter mediaGroupAdapter = new MediaGroupObjectAdapter(homeGroup);
mMediaGroupAdapters.put(mediaGroupId, mediaGroupAdapter);
ListRow row = new ListRow(header, mediaGroupAdapter);
mCategoryRowAdapter.add(row);
} else {
ListRow row = new ListRow(header, existingAdapter);
mCategoryRowAdapter.add(row);
}
mPageRowFragmentFactory.updateRow(group, header);
}
@Override
public void continueHomeGroup(MediaGroup homeGroup) {
MediaGroupObjectAdapter adapter = mMediaGroupAdapters.get(homeGroup.hashCode());
if (adapter != null) {
adapter.append(homeGroup);
} else {
Log.e(TAG, "Cant't continue home group " + homeGroup.getTitle());
}
private void createMultiRowHeader(Header header) {
HeaderItem headerItem = new MultiRowHeaderItem(header.getId(), header.getTitle());
PageRow pageRow = new PageRow(headerItem);
mCategoryRowAdapter.add(pageRow);
}
@Override
public void showOnboarding() {
startActivity(new Intent(getContext(), OnboardingActivity.class));
}
@Override
public void updateGrid(VideoGroup group, Header header) {
// TODO: not implemented
}
@Override
public void clearRow(Header header) {
// TODO: not implemented
}
@Override
public void clearGrid(Header header) {
// TODO: not implemented
}
private static class PageRowFragmentFactory extends BrowseSupportFragment.FragmentFactory<Fragment> {
private final BackgroundManager mBackgroundManager;
private final Map<Integer, Fragment> mFragments;
PageRowFragmentFactory(BackgroundManager backgroundManager) {
mBackgroundManager = backgroundManager;
mFragments = new HashMap<>();
}
@Override
public Fragment createFragment(Object rowObj) {
Row row = (Row) rowObj;
mBackgroundManager.setDrawable(null);
HeaderItem headerItem = row.getHeaderItem();
Fragment fragment = null;
if (headerItem instanceof MultiRowHeaderItem) {
fragment = new MultiRowFragment();
} else if (headerItem instanceof GridHeaderItem) {
fragment = new GridFragment();
}
if (fragment != null) {
mFragments.put((int) headerItem.getId(), fragment);
return fragment;
}
throw new IllegalArgumentException(String.format("Invalid row %s", rowObj));
}
public void updateRow(VideoGroup group, Header header) {
Fragment fragment = mFragments.get(header.getId());
if (fragment == null) {
throw new IllegalStateException("Page row fragment not initialized");
}
if (fragment instanceof MultiRowFragment) {
MultiRowFragment rowFragment = (MultiRowFragment) fragment;
rowFragment.updateRow(group);
} else {
throw new IllegalStateException("Page row fragment has incompatible type");
}
}
}
private static class MultiRowHeaderItem extends HeaderItem {
public MultiRowHeaderItem(long id, String name) {
super(id, name);
}
public MultiRowHeaderItem(String name) {
super(name);
}
}
private static class GridHeaderItem extends HeaderItem {
public GridHeaderItem(long id, String name) {
super(id, name);
}
public GridHeaderItem(String name) {
super(name);
}
}
}

View File

@ -0,0 +1,54 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.main;
import android.os.Bundle;
import android.widget.Toast;
import androidx.leanback.app.RowsSupportFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
import androidx.leanback.widget.HeaderItem;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.ListRowPresenter;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.VideoGroup;
import com.liskovsoft.smartyoutubetv2.tv.adapter.VideoGroupObjectAdapter;
import java.util.HashMap;
import java.util.Map;
public class MultiRowFragment extends RowsSupportFragment {
private final ArrayObjectAdapter mRowsAdapter;
private final Map<Integer, VideoGroupObjectAdapter> mMediaGroupAdapters;
public MultiRowFragment() {
mMediaGroupAdapters = new HashMap<>();
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
setAdapter(mRowsAdapter);
setOnItemViewClickedListener((itemViewHolder, item, rowViewHolder, row) -> {
Toast.makeText(getActivity(), "Implement click handler", Toast.LENGTH_SHORT).show();
});
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getMainFragmentAdapter().getFragmentHost().notifyDataReady(getMainFragmentAdapter());
}
public void updateRow(VideoGroup group) {
HeaderItem rowHeader = new HeaderItem(group.getTitle());
int mediaGroupId = group.getId(); // Create unique int from category.
VideoGroupObjectAdapter existingAdapter = mMediaGroupAdapters.get(mediaGroupId);
if (existingAdapter == null) {
VideoGroupObjectAdapter mediaGroupAdapter = new VideoGroupObjectAdapter(group);
mMediaGroupAdapters.put(mediaGroupId, mediaGroupAdapter);
ListRow row = new ListRow(rowHeader, mediaGroupAdapter);
mRowsAdapter.add(row);
} else {
existingAdapter.append(group); // continue row
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.app.Activity;
import android.graphics.drawable.Drawable;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.content.res.Resources;
import android.os.Bundle;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.content.Context;
import android.graphics.drawable.Drawable;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.app.Activity;
import android.os.Bundle;

View File

@ -12,7 +12,7 @@
* the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.content.Intent;
import android.os.Bundle;

View File

@ -14,11 +14,12 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.os.Bundle;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.base.LeanbackActivity;
/*
* VerticalGridActivity that loads VerticalGridFragment

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.content.Intent;
import android.database.Cursor;
@ -36,10 +36,11 @@ import androidx.loader.content.Loader;
import android.view.View;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
import com.liskovsoft.smartyoutubetv2.tv.ui.search.SearchActivity;
/*
* VerticalGridFragment shows a grid of videos that can be scrolled vertically.

View File

@ -14,11 +14,12 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.os.Bundle;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.base.LeanbackActivity;
/*
* Details activity class that loads VideoDetailsFragment class

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.old;
import android.app.NotificationManager;
import android.content.Context;
@ -62,11 +62,12 @@ import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
import com.liskovsoft.smartyoutubetv2.tv.presenter.DetailsDescriptionPresenter;
import com.liskovsoft.smartyoutubetv2.tv.ui.playback.PlaybackActivity;
/*
* VideoDetailsFragment extends DetailsFragment, a Wrapper fragment for leanback details screens.

View File

@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.onboarding;
import android.os.Bundle;
import androidx.fragment.app.FragmentActivity;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.common.presenters.OnboardingPresenter;
import com.liskovsoft.smartyoutubetv2.common.mvp.presenters.OnboardingPresenter;
/*
* OnboardingActivity for OnboardingFragment

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.onboarding;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@ -31,8 +31,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.common.presenters.OnboardingPresenter;
import com.liskovsoft.smartyoutubetv2.common.views.OnboardingView;
import com.liskovsoft.smartyoutubetv2.common.mvp.presenters.OnboardingPresenter;
import com.liskovsoft.smartyoutubetv2.common.mvp.views.OnboardingView;
import java.util.ArrayList;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.playback;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
@ -22,6 +22,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.base.LeanbackActivity;
/**
* Loads PlaybackFragment and delegates input from a game controller.

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.playback;
import android.annotation.TargetApi;
import android.content.Intent;
@ -41,10 +41,10 @@ import androidx.loader.content.CursorLoader;
import androidx.loader.content.Loader;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.model.Playlist;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.player.VideoPlayerGlue;
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
import com.google.android.exoplayer2.ExoPlayerFactory;
@ -61,8 +61,9 @@ import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity;
import static com.liskovsoft.smartyoutubetv2.tv.ui.PlaybackFragment.VideoLoaderCallbacks.RELATED_VIDEOS_LOADER;
import static com.liskovsoft.smartyoutubetv2.tv.ui.playback.PlaybackFragment.VideoLoaderCallbacks.RELATED_VIDEOS_LOADER;
/**
* Plays selected video, loads playlist and related videos, and delegates playback to {@link

View File

@ -14,13 +14,14 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.search;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.base.LeanbackActivity;
/*
* SearchActivity for SearchFragment

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.liskovsoft.smartyoutubetv2.tv.ui;
package com.liskovsoft.smartyoutubetv2.tv.ui.search;
import android.Manifest;
import android.app.Activity;
@ -48,10 +48,11 @@ import android.widget.Toast;
import com.liskovsoft.smartyoutubetv2.tv.BuildConfig;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.data.VideoContract;
import com.liskovsoft.smartyoutubetv2.tv.model.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.data.old.VideoContract;
import com.liskovsoft.smartyoutubetv2.common.mvp.models.Video;
import com.liskovsoft.smartyoutubetv2.tv.model.old.VideoCursorMapper;
import com.liskovsoft.smartyoutubetv2.tv.presenter.CardPresenter;
import com.liskovsoft.smartyoutubetv2.tv.ui.old.VideoDetailsActivity;
/*
* This class demonstrates how to do in-app search

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 707 B

View File

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 535 B

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Some files were not shown because too many files have changed in this diff Show More