mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-09-28 15:08:50 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
8ed86261ef
@ -8,8 +8,8 @@ android {
|
|||||||
applicationId "org.schabi.newpipe"
|
applicationId "org.schabi.newpipe"
|
||||||
minSdkVersion 15
|
minSdkVersion 15
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
versionCode 24
|
versionCode 25
|
||||||
versionName "0.8.10"
|
versionName "0.8.11"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
@ -32,10 +32,10 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
compile 'com.android.support:appcompat-v7:25.1.1'
|
compile 'com.android.support:appcompat-v7:25.2.0'
|
||||||
compile 'com.android.support:support-v4:25.1.1'
|
compile 'com.android.support:support-v4:25.2.0'
|
||||||
compile 'com.android.support:design:25.1.1'
|
compile 'com.android.support:design:25.2.0'
|
||||||
compile 'com.android.support:recyclerview-v7:25.1.1'
|
compile 'com.android.support:recyclerview-v7:25.2.0'
|
||||||
compile 'org.jsoup:jsoup:1.8.3'
|
compile 'org.jsoup:jsoup:1.8.3'
|
||||||
compile 'org.mozilla:rhino:1.7.7'
|
compile 'org.mozilla:rhino:1.7.7'
|
||||||
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
compile 'info.guardianproject.netcipher:netcipher:1.2'
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
android:logo="@mipmap/ic_launcher"
|
android:logo="@mipmap/ic_launcher"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
@ -34,53 +33,6 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value=".MainActivity" />
|
android:value=".MainActivity" />
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
|
||||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="http" />
|
|
||||||
<data android:scheme="https" />
|
|
||||||
<data android:host="youtube.com" />
|
|
||||||
<data android:host="m.youtube.com" />
|
|
||||||
<data android:host="www.youtube.com" />
|
|
||||||
<data android:pathPrefix="/v/" />
|
|
||||||
<data android:pathPrefix="/watch" />
|
|
||||||
<data android:pathPrefix="/attribution_link" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
|
||||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="http" />
|
|
||||||
<data android:scheme="https" />
|
|
||||||
<data android:host="youtu.be" />
|
|
||||||
<data android:pathPrefix="/" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
|
||||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
|
|
||||||
<data android:scheme="vnd.youtube" />
|
|
||||||
<data android:scheme="vnd.youtube.launch" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.SEND" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<data android:mimeType="text/plain" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".player.PlayVideoActivity"
|
android:name=".player.PlayVideoActivity"
|
||||||
@ -149,16 +101,11 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="com.nononsenseapps.filepicker.FilePickerActivity"
|
android:name="com.nononsenseapps.filepicker.FilePickerActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/FilePickerTheme"
|
android:launchMode="singleTop"
|
||||||
android:launchMode="singleTop">
|
android:theme="@style/FilePickerTheme"/>
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ChannelActivity"
|
android:name=".ChannelActivity"
|
||||||
android:label="@string/title_activity_channel"
|
android:launchMode="singleTask" />
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:theme="@style/AppTheme.NoActionBar" />
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ReCaptchaActivity"
|
android:name=".ReCaptchaActivity"
|
||||||
android:label="@string/reCaptchaActivity" />
|
android:label="@string/reCaptchaActivity" />
|
||||||
@ -170,8 +117,64 @@
|
|||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/provider_paths"/>
|
android:resource="@xml/provider_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<activity android:name=".RouterActivity"
|
||||||
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="youtube.com" />
|
||||||
|
<data android:host="m.youtube.com" />
|
||||||
|
<data android:host="www.youtube.com" />
|
||||||
|
<!-- video prefix -->
|
||||||
|
<data android:pathPrefix="/v/" />
|
||||||
|
<data android:pathPrefix="/watch" />
|
||||||
|
<data android:pathPrefix="/attribution_link" />
|
||||||
|
<!-- channel prefix -->
|
||||||
|
<data android:pathPrefix="/channel/"/>
|
||||||
|
<data android:pathPrefix="/user/"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="http" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="youtu.be" />
|
||||||
|
<data android:pathPrefix="/" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
|
||||||
|
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="vnd.youtube" />
|
||||||
|
<data android:scheme="vnd.youtube.launch" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
|
<data android:mimeType="text/plain" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -1,31 +1,24 @@
|
|||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.design.widget.CollapsingToolbarLayout;
|
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.widget.Button;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
|
|
||||||
import org.schabi.newpipe.detail.VideoItemDetailActivity;
|
|
||||||
import org.schabi.newpipe.detail.VideoItemDetailFragment;
|
import org.schabi.newpipe.detail.VideoItemDetailFragment;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
@ -36,13 +29,12 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
|||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
import org.schabi.newpipe.util.NavStack;
|
import org.schabi.newpipe.util.NavStack;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK;
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
import static android.os.Build.VERSION.SDK_INT;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||||
@ -75,38 +67,36 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
private ImageLoader imageLoader = ImageLoader.getInstance();
|
||||||
private InfoListAdapter infoListAdapter = null;
|
private InfoListAdapter infoListAdapter = null;
|
||||||
|
|
||||||
|
private String subS = "";
|
||||||
|
|
||||||
|
ProgressBar progressBar = null;
|
||||||
|
ImageView channelBanner = null;
|
||||||
|
ImageView avatarView = null;
|
||||||
|
TextView titleView = null;
|
||||||
|
TextView subscirberView = null;
|
||||||
|
Button subscriberButton = null;
|
||||||
|
View subscriberLayout = null;
|
||||||
|
|
||||||
|
View header = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
ThemeHelper.setTheme(this, true);
|
||||||
//since we set themeing we have to set translucent statusBar by hand
|
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme_NoActionBar);
|
|
||||||
}
|
|
||||||
setTranslucentStatusBar(getWindow());
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_channel);
|
setContentView(R.layout.activity_channel);
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
rootView = findViewById(android.R.id.content);
|
||||||
rootView = findViewById(R.id.rootView);
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
if(savedInstanceState == null) {
|
|
||||||
Intent i = getIntent();
|
|
||||||
channelUrl = i.getStringExtra(NavStack.URL);
|
|
||||||
serviceId = i.getIntExtra(NavStack.SERVICE_ID, -1);
|
|
||||||
} else {
|
|
||||||
channelUrl = savedInstanceState.getString(NavStack.URL);
|
|
||||||
serviceId = savedInstanceState.getInt(NavStack.SERVICE_ID);
|
|
||||||
NavStack.getInstance()
|
|
||||||
.restoreSavedInstanceState(savedInstanceState);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
getSupportActionBar().setDisplayShowTitleEnabled(true);
|
||||||
|
|
||||||
infoListAdapter = new InfoListAdapter(this, rootView);
|
infoListAdapter = new InfoListAdapter(this, rootView);
|
||||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.channel_streams_view);
|
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.channel_streams_view);
|
||||||
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||||
recyclerView.setLayoutManager(layoutManager);
|
recyclerView.setLayoutManager(layoutManager);
|
||||||
|
header = getLayoutInflater().inflate(R.layout.channel_header, recyclerView, false);
|
||||||
|
infoListAdapter.setHeader(header);
|
||||||
|
infoListAdapter.setFooter(
|
||||||
|
getLayoutInflater().inflate(R.layout.pignate_footer, recyclerView, false));
|
||||||
recyclerView.setAdapter(infoListAdapter);
|
recyclerView.setAdapter(infoListAdapter);
|
||||||
infoListAdapter.setOnStreamInfoItemSelectedListener(
|
infoListAdapter.setOnStreamInfoItemSelectedListener(
|
||||||
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
||||||
@ -140,6 +130,36 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
subS = getString(R.string.subscriber);
|
||||||
|
|
||||||
|
progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
||||||
|
channelBanner = (ImageView) header.findViewById(R.id.channel_banner_image);
|
||||||
|
avatarView = (ImageView) header.findViewById(R.id.channel_avatar_view);
|
||||||
|
titleView = (TextView) header.findViewById(R.id.channel_title_view);
|
||||||
|
subscirberView = (TextView) header.findViewById(R.id.channel_subscriber_view);
|
||||||
|
subscriberButton = (Button) header.findViewById(R.id.channel_subscribe_button);
|
||||||
|
subscriberLayout = header.findViewById(R.id.channel_subscriber_layout);
|
||||||
|
|
||||||
|
if(savedInstanceState == null) {
|
||||||
|
handleIntent(getIntent());
|
||||||
|
} else {
|
||||||
|
channelUrl = savedInstanceState.getString(NavStack.URL);
|
||||||
|
serviceId = savedInstanceState.getInt(NavStack.SERVICE_ID);
|
||||||
|
NavStack.getInstance()
|
||||||
|
.restoreSavedInstanceState(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNewIntent(Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
handleIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIntent(Intent i) {
|
||||||
|
channelUrl = i.getStringExtra(NavStack.URL);
|
||||||
|
serviceId = i.getIntExtra(NavStack.SERVICE_ID, -1);
|
||||||
requestData(false);
|
requestData(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,33 +173,36 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateUi(final ChannelInfo info) {
|
private void updateUi(final ChannelInfo info) {
|
||||||
CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout);
|
findViewById(R.id.channel_header_layout).setVisibility(View.VISIBLE);
|
||||||
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
|
|
||||||
ImageView channelBanner = (ImageView) findViewById(R.id.channel_banner_image);
|
|
||||||
final FloatingActionButton feedButton = (FloatingActionButton) findViewById(R.id.channel_rss_fab);
|
|
||||||
ImageView avatarView = (ImageView) findViewById(R.id.channel_avatar_view);
|
|
||||||
ImageView haloView = (ImageView) findViewById(R.id.channel_avatar_halo);
|
|
||||||
|
|
||||||
progressBar.setVisibility(View.GONE);
|
progressBar.setVisibility(View.GONE);
|
||||||
|
|
||||||
if(info.channel_name != null && !info.channel_name.isEmpty()) {
|
if(info.channel_name != null && !info.channel_name.isEmpty()) {
|
||||||
ctl.setTitle(info.channel_name);
|
getSupportActionBar().setTitle(info.channel_name);
|
||||||
|
titleView.setText(info.channel_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info.banner_url != null && !info.banner_url.isEmpty()) {
|
if(info.banner_url != null && !info.banner_url.isEmpty()) {
|
||||||
imageLoader.displayImage(info.banner_url, channelBanner,
|
imageLoader.displayImage(info.banner_url, channelBanner,
|
||||||
new ImageErrorLoadingListener(this, rootView ,info.service_id));
|
new ImageErrorLoadingListener(this, rootView ,info.service_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info.avatar_url != null && !info.avatar_url.isEmpty()) {
|
if(info.avatar_url != null && !info.avatar_url.isEmpty()) {
|
||||||
avatarView.setVisibility(View.VISIBLE);
|
avatarView.setVisibility(View.VISIBLE);
|
||||||
haloView.setVisibility(View.VISIBLE);
|
|
||||||
imageLoader.displayImage(info.avatar_url, avatarView,
|
imageLoader.displayImage(info.avatar_url, avatarView,
|
||||||
new ImageErrorLoadingListener(this, rootView ,info.service_id));
|
new ImageErrorLoadingListener(this, rootView ,info.service_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(info.subscriberCount != -1) {
|
||||||
|
subscirberView.setText(buildSubscriberString(info.subscriberCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
if((info.feed_url != null && !info.feed_url.isEmpty()) ||
|
||||||
|
(info.subscriberCount != -1)) {
|
||||||
|
subscriberLayout.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
if(info.feed_url != null && !info.feed_url.isEmpty()) {
|
if(info.feed_url != null && !info.feed_url.isEmpty()) {
|
||||||
feedButton.setOnClickListener(new View.OnClickListener() {
|
subscriberButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
Log.d(TAG, info.feed_url);
|
Log.d(TAG, info.feed_url);
|
||||||
@ -188,8 +211,9 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
feedButton.setVisibility(View.GONE);
|
subscriberButton.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addVideos(final ChannelInfo info) {
|
private void addVideos(final ChannelInfo info) {
|
||||||
@ -209,6 +233,22 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
private void requestData(final boolean onlyVideos) {
|
private void requestData(final boolean onlyVideos) {
|
||||||
// start processing
|
// start processing
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
|
if(!onlyVideos) {
|
||||||
|
//delete already displayed content
|
||||||
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
|
infoListAdapter.clearSteamItemList();
|
||||||
|
pageNumber = 0;
|
||||||
|
subscriberLayout.setVisibility(View.GONE);
|
||||||
|
titleView.setText("");
|
||||||
|
getSupportActionBar().setTitle("");
|
||||||
|
if (SDK_INT >= 21) {
|
||||||
|
channelBanner.setImageDrawable(getDrawable(R.drawable.channel_banner));
|
||||||
|
avatarView.setImageDrawable(getDrawable(R.drawable.buddy));
|
||||||
|
}
|
||||||
|
infoListAdapter.showFooter(false);
|
||||||
|
}
|
||||||
|
|
||||||
Thread channelExtractorThread = new Thread(new Runnable() {
|
Thread channelExtractorThread = new Thread(new Runnable() {
|
||||||
Handler h = new Handler();
|
Handler h = new Handler();
|
||||||
|
|
||||||
@ -229,8 +269,12 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
if(!onlyVideos) {
|
if(!onlyVideos) {
|
||||||
updateUi(info);
|
updateUi(info);
|
||||||
|
infoListAdapter.showFooter(true);
|
||||||
}
|
}
|
||||||
hasNextPage = info.hasNextPage;
|
hasNextPage = info.hasNextPage;
|
||||||
|
if(!hasNextPage) {
|
||||||
|
infoListAdapter.showFooter(false);
|
||||||
|
}
|
||||||
addVideos(info);
|
addVideos(info);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -297,30 +341,6 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
channelExtractorThread.start();
|
channelExtractorThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// fix transparent statusbar fuckup (fuck google why can't they just leave something that worked
|
|
||||||
// as it is, and everyone gets happy)
|
|
||||||
public static void setTranslucentStatusBar(Window window) {
|
|
||||||
if (window == null) return;
|
|
||||||
int sdkInt = Build.VERSION.SDK_INT;
|
|
||||||
if (sdkInt >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
setTranslucentStatusBarLollipop(window);
|
|
||||||
} else if (sdkInt >= Build.VERSION_CODES.KITKAT) {
|
|
||||||
setTranslucentStatusBarKiKat(window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
private static void setTranslucentStatusBarLollipop(Window window) {
|
|
||||||
window.setStatusBarColor(
|
|
||||||
ContextCompat.getColor(window.getContext(), android.R.color.transparent));
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
private static void setTranslucentStatusBarKiKat(Window window) {
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
try {
|
try {
|
||||||
@ -331,4 +351,54 @@ public class ChannelActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
super.onCreateOptionsMenu(menu);
|
||||||
|
getMenuInflater().inflate(R.menu.menu_channel, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
super.onOptionsItemSelected(item);
|
||||||
|
switch(item.getItemId()) {
|
||||||
|
case R.id.action_settings: {
|
||||||
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case R.id.menu_item_openInBrowser: {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(Uri.parse(channelUrl));
|
||||||
|
|
||||||
|
startActivity(Intent.createChooser(intent, getString(R.string.choose_browser)));
|
||||||
|
}
|
||||||
|
case R.id.menu_item_share:
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(Intent.ACTION_SEND);
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, channelUrl);
|
||||||
|
intent.setType("text/plain");
|
||||||
|
startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
|
||||||
|
case android.R.id.home:
|
||||||
|
NavStack.getInstance().openMainActivity(this);
|
||||||
|
default:
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildSubscriberString(long count) {
|
||||||
|
String out = "";
|
||||||
|
if(count >= 1000000000){
|
||||||
|
out += Long.toString((count/1000000000)%1000)+".";
|
||||||
|
}
|
||||||
|
if(count>=1000000){
|
||||||
|
out += Long.toString((count/1000000)%1000) + ".";
|
||||||
|
}
|
||||||
|
if(count>=1000){
|
||||||
|
out += Long.toString((count/1000)%1000)+".";
|
||||||
|
}
|
||||||
|
out += Long.toString(count%1000) + " " + subS;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,17 @@ package org.schabi.newpipe;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.os.Bundle;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.download.DownloadActivity;
|
import org.schabi.newpipe.download.DownloadActivity;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 02.08.16.
|
* Created by Christian Schabesberger on 02.08.16.
|
||||||
@ -36,13 +34,15 @@ import org.schabi.newpipe.util.PermissionHelper;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MainActivity extends ThemableActivity {
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
private Fragment mainFragment = null;
|
private Fragment mainFragment = null;
|
||||||
private static final String TAG = MainActivity.class.toString();
|
private static final String TAG = MainActivity.class.toString();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
ThemeHelper.setTheme(this, true);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||||
mainFragment = getSupportFragmentManager()
|
mainFragment = getSupportFragmentManager()
|
||||||
@ -53,7 +53,6 @@ public class MainActivity extends ThemableActivity {
|
|||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
|
||||||
inflater.inflate(R.menu.main_menu, menu);
|
inflater.inflate(R.menu.main_menu, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
158
app/src/main/java/org/schabi/newpipe/RouterActivity.java
Normal file
158
app/src/main/java/org/schabi/newpipe/RouterActivity.java
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.detail.VideoItemDetailActivity;
|
||||||
|
import org.schabi.newpipe.detail.VideoItemDetailFragment;
|
||||||
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
|
import org.schabi.newpipe.util.NavStack;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
||||||
|
* RouterActivity .java is part of NewPipe.
|
||||||
|
*
|
||||||
|
* OpenHitboxStreams 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 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* OpenHitboxStreams 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 OpenHitboxStreams. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Acitivty is designed to route share/open intents to the specified service, and
|
||||||
|
* to the part of the service which can handle the url.
|
||||||
|
*/
|
||||||
|
public class RouterActivity extends Activity {
|
||||||
|
private static final String TAG = RouterActivity.class.toString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes invisible separators (\p{Z}) and punctuation characters including
|
||||||
|
* brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
handleIntent(getIntent());
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String removeHeadingGibberish(final String input) {
|
||||||
|
int start = 0;
|
||||||
|
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
||||||
|
if (!input.substring(i, i + 1).matches("\\p{L}")) {
|
||||||
|
start = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input.substring(start, input.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String trim(final String input) {
|
||||||
|
if (input == null || input.length() < 1) {
|
||||||
|
return input;
|
||||||
|
} else {
|
||||||
|
String output = input;
|
||||||
|
while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
|
||||||
|
output = output.substring(1);
|
||||||
|
}
|
||||||
|
while (output.length() > 0
|
||||||
|
&& output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
|
||||||
|
output = output.substring(0, output.length() - 1);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all Strings which look remotely like URLs from a text.
|
||||||
|
* Used if NewPipe was called through share menu.
|
||||||
|
*
|
||||||
|
* @param sharedText text to scan for URLs.
|
||||||
|
* @return potential URLs
|
||||||
|
*/
|
||||||
|
private String[] getUris(final String sharedText) {
|
||||||
|
final Collection<String> result = new HashSet<>();
|
||||||
|
if (sharedText != null) {
|
||||||
|
final String[] array = sharedText.split("\\p{Space}");
|
||||||
|
for (String s : array) {
|
||||||
|
s = trim(s);
|
||||||
|
if (s.length() != 0) {
|
||||||
|
if (s.matches(".+://.+")) {
|
||||||
|
result.add(removeHeadingGibberish(s));
|
||||||
|
} else if (s.matches(".+\\..+")) {
|
||||||
|
result.add("http://" + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toArray(new String[result.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIntent(Intent intent) {
|
||||||
|
String videoUrl = "";
|
||||||
|
StreamingService service = null;
|
||||||
|
|
||||||
|
// first gather data and find service
|
||||||
|
if (intent.getData() != null) {
|
||||||
|
// this means the video was called though another app
|
||||||
|
videoUrl = intent.getData().toString();
|
||||||
|
} else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
||||||
|
//this means that vidoe was called through share menu
|
||||||
|
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
videoUrl = getUris(extraText)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
service = NewPipe.getServiceByUrl(videoUrl);
|
||||||
|
if(service == null) {
|
||||||
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
Intent callIntent = new Intent();
|
||||||
|
switch(service.getLinkTypeByUrl(videoUrl)) {
|
||||||
|
case CHANNEL:
|
||||||
|
callIntent.setClass(this, ChannelActivity.class);
|
||||||
|
break;
|
||||||
|
case STREAM:
|
||||||
|
callIntent.setClass(this, VideoItemDetailActivity.class);
|
||||||
|
callIntent.putExtra(VideoItemDetailFragment.AUTO_PLAY,
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.getBoolean(
|
||||||
|
getString(R.string.autoplay_through_intent_key), false));
|
||||||
|
break;
|
||||||
|
case PLAYLIST:
|
||||||
|
Log.e(TAG, "NOT YET DEFINED");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callIntent.putExtra(NavStack.URL, videoUrl);
|
||||||
|
callIntent.putExtra(NavStack.SERVICE_ID, service.getServiceId());
|
||||||
|
startActivity(callIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,17 @@
|
|||||||
package org.schabi.newpipe.detail;
|
package org.schabi.newpipe.detail;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v4.app.NavUtils;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.App;
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.MainActivity;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.ThemableActivity;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.NavStack;
|
import org.schabi.newpipe.util.NavStack;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
import static android.os.Build.VERSION.SDK_INT;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,15 +32,7 @@ import static android.os.Build.VERSION.SDK_INT;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class VideoItemDetailActivity extends ThemableActivity {
|
public class VideoItemDetailActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes invisible separators (\p{Z}) and punctuation characters including
|
|
||||||
* brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
|
|
||||||
* more details.
|
|
||||||
*/
|
|
||||||
private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
|
|
||||||
|
|
||||||
private static final String TAG = VideoItemDetailActivity.class.toString();
|
private static final String TAG = VideoItemDetailActivity.class.toString();
|
||||||
|
|
||||||
private VideoItemDetailFragment fragment;
|
private VideoItemDetailFragment fragment;
|
||||||
@ -62,6 +42,7 @@ public class VideoItemDetailActivity extends ThemableActivity {
|
|||||||
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
ThemeHelper.setTheme(this, true);
|
||||||
setContentView(R.layout.activity_videoitem_detail);
|
setContentView(R.layout.activity_videoitem_detail);
|
||||||
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||||
// Show the Up button in the action bar.
|
// Show the Up button in the action bar.
|
||||||
@ -104,27 +85,13 @@ public class VideoItemDetailActivity extends ThemableActivity {
|
|||||||
private void handleIntent(Intent intent) {
|
private void handleIntent(Intent intent) {
|
||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
boolean autoplay = false;
|
boolean autoplay = false;
|
||||||
if (intent.getData() != null) {
|
|
||||||
// this means the video was called though another app
|
videoUrl = intent.getStringExtra(NavStack.URL);
|
||||||
videoUrl = intent.getData().toString();
|
currentStreamingService = intent.getIntExtra(NavStack.SERVICE_ID, -1);
|
||||||
currentStreamingService = getServiceIdByUrl(videoUrl);
|
if(intent.hasExtra(VideoItemDetailFragment.AUTO_PLAY)) {
|
||||||
if(currentStreamingService == -1) {
|
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
|
||||||
Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
|
intent.getBooleanExtra(VideoItemDetailFragment.AUTO_PLAY, false));
|
||||||
.show();
|
|
||||||
}
|
|
||||||
autoplay = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
.getBoolean(getString(R.string.autoplay_through_intent_key), false);
|
|
||||||
} else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
|
||||||
//this means that vidoe was called through share menu
|
|
||||||
String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
|
||||||
videoUrl = getUris(extraText)[0];
|
|
||||||
currentStreamingService = getServiceIdByUrl(videoUrl);
|
|
||||||
} else {
|
|
||||||
//this is if the video was called through another NewPipe activity
|
|
||||||
videoUrl = intent.getStringExtra(NavStack.URL);
|
|
||||||
currentStreamingService = intent.getIntExtra(NavStack.SERVICE_ID, -1);
|
|
||||||
}
|
}
|
||||||
arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, autoplay);
|
|
||||||
arguments.putString(NavStack.URL, videoUrl);
|
arguments.putString(NavStack.URL, videoUrl);
|
||||||
arguments.putInt(NavStack.SERVICE_ID, currentStreamingService);
|
arguments.putInt(NavStack.SERVICE_ID, currentStreamingService);
|
||||||
addFragment(arguments);
|
addFragment(arguments);
|
||||||
@ -185,69 +152,4 @@ public class VideoItemDetailActivity extends ThemableActivity {
|
|||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all Strings which look remotely like URLs from a text.
|
|
||||||
* Used if NewPipe was called through share menu.
|
|
||||||
*
|
|
||||||
* @param sharedText text to scan for URLs.
|
|
||||||
* @return potential URLs
|
|
||||||
*/
|
|
||||||
private String[] getUris(final String sharedText) {
|
|
||||||
final Collection<String> result = new HashSet<>();
|
|
||||||
if (sharedText != null) {
|
|
||||||
final String[] array = sharedText.split("\\p{Space}");
|
|
||||||
for (String s : array) {
|
|
||||||
s = trim(s);
|
|
||||||
if (s.length() != 0) {
|
|
||||||
if (s.matches(".+://.+")) {
|
|
||||||
result.add(removeHeadingGibberish(s));
|
|
||||||
} else if (s.matches(".+\\..+")) {
|
|
||||||
result.add("http://" + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toArray(new String[result.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String removeHeadingGibberish(final String input) {
|
|
||||||
int start = 0;
|
|
||||||
for (int i = input.indexOf("://") - 1; i >= 0; i--) {
|
|
||||||
if (!input.substring(i, i + 1).matches("\\p{L}")) {
|
|
||||||
start = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return input.substring(start, input.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String trim(final String input) {
|
|
||||||
if (input == null || input.length() < 1) {
|
|
||||||
return input;
|
|
||||||
} else {
|
|
||||||
String output = input;
|
|
||||||
while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
|
|
||||||
output = output.substring(1);
|
|
||||||
}
|
|
||||||
while (output.length() > 0
|
|
||||||
&& output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
|
|
||||||
output = output.substring(0, output.length() - 1);
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getServiceIdByUrl(String url) {
|
|
||||||
StreamingService[] serviceList = NewPipe.getServices();
|
|
||||||
int service = -1;
|
|
||||||
for (int i = 0; i < serviceList.length; i++) {
|
|
||||||
if (serviceList[i].getStreamUrlIdHandlerInstance().acceptUrl(videoUrl)) {
|
|
||||||
service = i;
|
|
||||||
//videoExtractor = ServiceList.getService(i).getExtractorInstance();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return service;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import android.widget.RelativeLayout;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
|
||||||
import com.google.android.exoplayer.util.Util;
|
import com.google.android.exoplayer.util.Util;
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
@ -797,8 +798,11 @@ public class VideoItemDetailFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
super.onOptionsItemSelected(item);
|
if(!actionBarHandler.onItemSelected(item)) {
|
||||||
return actionBarHandler.onItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnInvokeCreateOptionsMenuListener(OnInvokeCreateOptionsMenuListener listener) {
|
public void setOnInvokeCreateOptionsMenuListener(OnInvokeCreateOptionsMenuListener listener) {
|
||||||
|
@ -3,18 +3,15 @@ package org.schabi.newpipe.download;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.FragmentTransaction;
|
import android.app.FragmentTransaction;
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
@ -28,32 +25,28 @@ import android.widget.SeekBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.schabi.newpipe.ThemableActivity;
|
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import us.shandian.giga.get.DownloadManager;
|
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.ui.fragment.AllMissionsFragment;
|
import us.shandian.giga.ui.fragment.AllMissionsFragment;
|
||||||
import us.shandian.giga.ui.fragment.MissionsFragment;
|
import us.shandian.giga.ui.fragment.MissionsFragment;
|
||||||
import us.shandian.giga.util.CrashHandler;
|
import us.shandian.giga.util.CrashHandler;
|
||||||
import us.shandian.giga.util.Utility;
|
import us.shandian.giga.util.Utility;
|
||||||
|
|
||||||
public class DownloadActivity extends ThemableActivity implements AdapterView.OnItemClickListener{
|
public class DownloadActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
|
||||||
|
|
||||||
public static final String INTENT_DOWNLOAD = "us.shandian.giga.intent.DOWNLOAD";
|
public static final String INTENT_DOWNLOAD = "us.shandian.giga.intent.DOWNLOAD";
|
||||||
|
|
||||||
public static final String INTENT_LIST = "us.shandian.giga.intent.LIST";
|
public static final String INTENT_LIST = "us.shandian.giga.intent.LIST";
|
||||||
|
|
||||||
private static final String TAG = DownloadActivity.class.toString();
|
|
||||||
public static final String THREADS = "threads";
|
public static final String THREADS = "threads";
|
||||||
|
private static final String TAG = DownloadActivity.class.toString();
|
||||||
|
|
||||||
private MissionsFragment mFragment;
|
private MissionsFragment mFragment;
|
||||||
|
|
||||||
|
|
||||||
@ -72,9 +65,9 @@ public class DownloadActivity extends ThemableActivity implements AdapterView.On
|
|||||||
startService(i);
|
startService(i);
|
||||||
|
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
ThemeHelper.setTheme(this, true);
|
||||||
setContentView(R.layout.activity_downloader);
|
setContentView(R.layout.activity_downloader);
|
||||||
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
|
||||||
// its ok if this fails, we will catch that error later, and send it as report
|
// its ok if this fails, we will catch that error later, and send it as report
|
||||||
|
@ -54,6 +54,7 @@ public abstract class ChannelExtractor {
|
|||||||
public abstract String getBannerUrl() throws ParsingException;
|
public abstract String getBannerUrl() throws ParsingException;
|
||||||
public abstract String getFeedUrl() throws ParsingException;
|
public abstract String getFeedUrl() throws ParsingException;
|
||||||
public abstract StreamInfoItemCollector getStreams() throws ParsingException;
|
public abstract StreamInfoItemCollector getStreams() throws ParsingException;
|
||||||
|
public abstract long getSubscriberCount() throws ParsingException;
|
||||||
public abstract boolean hasNextPage() throws ParsingException;
|
public abstract boolean hasNextPage() throws ParsingException;
|
||||||
public int getServiceId() {
|
public int getServiceId() {
|
||||||
return serviceId;
|
return serviceId;
|
||||||
|
@ -29,8 +29,6 @@ import java.util.Vector;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class ChannelInfo {
|
public class ChannelInfo {
|
||||||
|
|
||||||
|
|
||||||
public void addException(Exception e) {
|
public void addException(Exception e) {
|
||||||
errors.add(e);
|
errors.add(e);
|
||||||
}
|
}
|
||||||
@ -66,6 +64,11 @@ public class ChannelInfo {
|
|||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
info.errors.add(e);
|
info.errors.add(e);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
info.subscriberCount = extractor.getSubscriberCount();
|
||||||
|
} catch (Exception e) {
|
||||||
|
info.errors.add(e);
|
||||||
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -76,6 +79,7 @@ public class ChannelInfo {
|
|||||||
public String banner_url = "";
|
public String banner_url = "";
|
||||||
public String feed_url = "";
|
public String feed_url = "";
|
||||||
public List<InfoItem> related_streams = null;
|
public List<InfoItem> related_streams = null;
|
||||||
|
public long subscriberCount = -1;
|
||||||
public boolean hasNextPage = false;
|
public boolean hasNextPage = false;
|
||||||
|
|
||||||
public List<Throwable> errors = new Vector<>();
|
public List<Throwable> errors = new Vector<>();
|
||||||
|
@ -55,6 +55,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
private static String avatarUrl = "";
|
private static String avatarUrl = "";
|
||||||
private static String bannerUrl = "";
|
private static String bannerUrl = "";
|
||||||
private static String feedUrl = "";
|
private static String feedUrl = "";
|
||||||
|
private static long subscriberCount = -1;
|
||||||
// the fist page is html all other pages are ajax. Every new page can be requested by sending
|
// the fist page is html all other pages are ajax. Every new page can be requested by sending
|
||||||
// this request url.
|
// this request url.
|
||||||
private static String nextPageUrl = "";
|
private static String nextPageUrl = "";
|
||||||
@ -153,7 +154,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
@Override
|
@Override
|
||||||
public StreamInfoItemCollector getStreams() throws ParsingException {
|
public StreamInfoItemCollector getStreams() throws ParsingException {
|
||||||
StreamInfoItemCollector collector = getStreamPreviewInfoCollector();
|
StreamInfoItemCollector collector = getStreamPreviewInfoCollector();
|
||||||
Element ul = null;
|
Element ul;
|
||||||
if(isAjaxPage) {
|
if(isAjaxPage) {
|
||||||
ul = doc.select("body").first();
|
ul = doc.select("body").first();
|
||||||
} else {
|
} else {
|
||||||
@ -168,6 +169,15 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
return AbstractStreamInfo.StreamType.VIDEO_STREAM;
|
return AbstractStreamInfo.StreamType.VIDEO_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAd() throws ParsingException {
|
||||||
|
if(!li.select("span[class*=\"icon-not-available\"]").isEmpty()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWebPageUrl() throws ParsingException {
|
public String getWebPageUrl() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
@ -213,9 +223,14 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
@Override
|
@Override
|
||||||
public String getUploadDate() throws ParsingException {
|
public String getUploadDate() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
return li.select("div[class=\"yt-lockup-meta\"]").first()
|
Element meta = li.select("div[class=\"yt-lockup-meta\"]").first();
|
||||||
.select("li").first()
|
Element li = meta.select("li").first();
|
||||||
.text();
|
if (li == null && meta != null) {
|
||||||
|
//this means we have a youtube red video
|
||||||
|
return "";
|
||||||
|
}else {
|
||||||
|
return li.text();
|
||||||
|
}
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
throw new ParsingException("Could not get uplaod date", e);
|
throw new ParsingException("Could not get uplaod date", e);
|
||||||
}
|
}
|
||||||
@ -230,13 +245,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
.select("li").get(1)
|
.select("li").get(1)
|
||||||
.text();
|
.text();
|
||||||
} catch (IndexOutOfBoundsException e) {
|
} catch (IndexOutOfBoundsException e) {
|
||||||
if(isLiveStream(li)) {
|
return -1;
|
||||||
// -1 for no view count
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
throw new ParsingException(
|
|
||||||
"Could not parse yt-lockup-meta although available: " + getTitle(), e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output = Parser.matchGroup1("([0-9,\\. ]*)", input)
|
output = Parser.matchGroup1("([0-9,\\. ]*)", input)
|
||||||
@ -294,6 +303,18 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
|
|||||||
return collector;
|
return collector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSubscriberCount() throws ParsingException {
|
||||||
|
Element el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]")
|
||||||
|
.first();
|
||||||
|
if(el != null) {
|
||||||
|
subscriberCount = Long.parseLong(el.text().replaceAll("\\D+",""));
|
||||||
|
} else if(el == null && subscriberCount == -1) {
|
||||||
|
throw new ParsingException("Could not get subscriber count");
|
||||||
|
}
|
||||||
|
return subscriberCount;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFeedUrl() throws ParsingException {
|
public String getFeedUrl() throws ParsingException {
|
||||||
try {
|
try {
|
||||||
|
@ -10,6 +10,7 @@ import org.mozilla.javascript.Function;
|
|||||||
import org.mozilla.javascript.ScriptableObject;
|
import org.mozilla.javascript.ScriptableObject;
|
||||||
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.FoundAdException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
import org.schabi.newpipe.extractor.stream_info.AudioStream;
|
import org.schabi.newpipe.extractor.stream_info.AudioStream;
|
||||||
@ -420,9 +421,15 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDashMpdUrl() throws ParsingException {
|
public String getDashMpdUrl() throws ParsingException {
|
||||||
/*
|
|
||||||
try {
|
try {
|
||||||
String dashManifestUrl = videoInfoPage.get("dashmpd");
|
String dashManifestUrl = "";
|
||||||
|
if(videoInfoPage != null && videoInfoPage.containsKey("dashmpd")) {
|
||||||
|
dashManifestUrl = videoInfoPage.get("dashmpd");
|
||||||
|
} else if (playerArgs.has("dashmpd")) {
|
||||||
|
dashManifestUrl = playerArgs.getString("dashmpd");
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
if(!dashManifestUrl.contains("/signature/")) {
|
if(!dashManifestUrl.contains("/signature/")) {
|
||||||
String encryptedSig = Parser.matchGroup1("/s/([a-fA-F0-9\\.]+)", dashManifestUrl);
|
String encryptedSig = Parser.matchGroup1("/s/([a-fA-F0-9\\.]+)", dashManifestUrl);
|
||||||
String decryptedSig;
|
String decryptedSig;
|
||||||
@ -435,8 +442,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||||||
throw new ParsingException(
|
throw new ParsingException(
|
||||||
"Could not get \"dashmpd\" maybe VideoInfoPage is broken.", e);
|
"Could not get \"dashmpd\" maybe VideoInfoPage is broken.", e);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -447,9 +452,17 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||||||
String encodedUrlMap;
|
String encodedUrlMap;
|
||||||
// playerArgs could be null if the video is age restricted
|
// playerArgs could be null if the video is age restricted
|
||||||
if (playerArgs == null) {
|
if (playerArgs == null) {
|
||||||
encodedUrlMap = videoInfoPage.get("adaptive_fmts");
|
if(videoInfoPage.containsKey("adaptive_fmts")) {
|
||||||
|
encodedUrlMap = videoInfoPage.get("adaptive_fmts");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
encodedUrlMap = playerArgs.getString("adaptive_fmts");
|
if(playerArgs.has("adaptive_fmts")) {
|
||||||
|
encodedUrlMap = playerArgs.getString("adaptive_fmts");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(String url_data_str : encodedUrlMap.split(",")) {
|
for(String url_data_str : encodedUrlMap.split(",")) {
|
||||||
// This loop iterates through multiple streams, therefor tags
|
// This loop iterates through multiple streams, therefor tags
|
||||||
@ -713,7 +726,16 @@ public class YoutubeStreamExtractor extends StreamExtractor {
|
|||||||
return new StreamInfoItemExtractor() {
|
return new StreamInfoItemExtractor() {
|
||||||
@Override
|
@Override
|
||||||
public AbstractStreamInfo.StreamType getStreamType() throws ParsingException {
|
public AbstractStreamInfo.StreamType getStreamType() throws ParsingException {
|
||||||
return null;
|
return AbstractStreamInfo.StreamType.VIDEO_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAd() throws ParsingException {
|
||||||
|
if(!li.select("span[class*=\"icon-not-available\"]").isEmpty()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube;
|
|||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
||||||
import org.schabi.newpipe.extractor.Parser;
|
import org.schabi.newpipe.extractor.Parser;
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.FoundAdException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
|
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
|||||||
|
|
||||||
private final Element item;
|
private final Element item;
|
||||||
|
|
||||||
public YoutubeStreamInfoItemExtractor(Element item) {
|
public YoutubeStreamInfoItemExtractor(Element item) throws FoundAdException {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +162,15 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAd() throws ParsingException {
|
||||||
|
if(!item.select("span[class*=\"icon-not-available\"]").isEmpty()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isLiveStream(Element item) {
|
private boolean isLiveStream(Element item) {
|
||||||
Element bla = item.select("span[class*=\"yt-badge-live\"]").first();
|
Element bla = item.select("span[class*=\"yt-badge-live\"]").first();
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 02.02.16.
|
* Created by Christian Schabesberger on 02.02.16.
|
||||||
@ -149,9 +148,9 @@ public class YoutubeStreamUrlIdHandler implements UrlIdHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptUrl(String videoUrl) {
|
public boolean acceptUrl(String videoUrl) {
|
||||||
videoUrl = videoUrl.toLowerCase();
|
String lowercaseUrl = videoUrl.toLowerCase();
|
||||||
if(videoUrl.contains("youtube") ||
|
if(lowercaseUrl.contains("youtube") ||
|
||||||
videoUrl.contains("youtu.be")) {
|
lowercaseUrl.contains("youtu.be")) {
|
||||||
// bad programming I know
|
// bad programming I know
|
||||||
try {
|
try {
|
||||||
getId(videoUrl);
|
getId(videoUrl);
|
||||||
|
@ -43,6 +43,9 @@ public class StreamInfoItemCollector extends InfoItemCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public StreamInfoItem extract(StreamInfoItemExtractor extractor) throws Exception {
|
public StreamInfoItem extract(StreamInfoItemExtractor extractor) throws Exception {
|
||||||
|
if(extractor.isAd()) {
|
||||||
|
throw new FoundAdException("Found ad");
|
||||||
|
}
|
||||||
|
|
||||||
StreamInfoItem resultItem = new StreamInfoItem();
|
StreamInfoItem resultItem = new StreamInfoItem();
|
||||||
// importand information
|
// importand information
|
||||||
@ -91,7 +94,7 @@ public class StreamInfoItemCollector extends InfoItemCollector {
|
|||||||
try {
|
try {
|
||||||
addItem(extract(extractor));
|
addItem(extract(extractor));
|
||||||
} catch(FoundAdException ae) {
|
} catch(FoundAdException ae) {
|
||||||
System.out.println("AD_WARNING: " + ae.getMessage());
|
//System.out.println("AD_WARNING: " + ae.getMessage());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
addError(e);
|
addError(e);
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,5 @@ public interface StreamInfoItemExtractor {
|
|||||||
String getUploadDate() throws ParsingException;
|
String getUploadDate() throws ParsingException;
|
||||||
long getViewCount() throws ParsingException;
|
long getViewCount() throws ParsingException;
|
||||||
String getThumbnailUrl() throws ParsingException;
|
String getThumbnailUrl() throws ParsingException;
|
||||||
|
boolean isAd() throws ParsingException;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ public class InfoItemBuilder {
|
|||||||
switch(info.infoType()) {
|
switch(info.infoType()) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
itemView = LayoutInflater.from(parent.getContext())
|
itemView = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.stream_item, parent, false);
|
.inflate(R.layout.stream_item, parent, false);
|
||||||
holder = new StreamInfoItemHolder(itemView);
|
holder = new StreamInfoItemHolder(itemView);
|
||||||
break;
|
break;
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
@ -202,15 +202,15 @@ public class InfoItemBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String shortSubscriber(Long viewCount){
|
public String shortSubscriber(Long count){
|
||||||
if(viewCount >= 1000000000){
|
if(count >= 1000000000){
|
||||||
return Long.toString(viewCount/1000000000)+ billion + " " + subsS;
|
return Long.toString(count/1000000000)+ billion + " " + subsS;
|
||||||
}else if(viewCount>=1000000){
|
}else if(count>=1000000){
|
||||||
return Long.toString(viewCount/1000000)+ million + " " + subsS;
|
return Long.toString(count/1000000)+ million + " " + subsS;
|
||||||
}else if(viewCount>=1000){
|
}else if(count>=1000){
|
||||||
return Long.toString(viewCount/1000)+ thousand + " " + subsS;
|
return Long.toString(count/1000)+ thousand + " " + subsS;
|
||||||
}else {
|
}else {
|
||||||
return Long.toString(viewCount)+ " " + subsS;
|
return Long.toString(count)+ " " + subsS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,27 @@ import java.util.Vector;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
private static final String TAG = InfoListAdapter.class.toString();
|
private static final String TAG = InfoListAdapter.class.toString();
|
||||||
|
|
||||||
private final InfoItemBuilder infoItemBuilder;
|
private final InfoItemBuilder infoItemBuilder;
|
||||||
private final List<InfoItem> infoItemList;
|
private final List<InfoItem> infoItemList;
|
||||||
|
private boolean showFooter = false;
|
||||||
|
private View header = null;
|
||||||
|
private View footer = null;
|
||||||
|
|
||||||
|
public class HFHolder extends RecyclerView.ViewHolder {
|
||||||
|
public HFHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
view = v;
|
||||||
|
}
|
||||||
|
public View view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showFooter(boolean show) {
|
||||||
|
showFooter = show;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public InfoListAdapter(Activity a, View rootView) {
|
public InfoListAdapter(Activity a, View rootView) {
|
||||||
infoItemBuilder = new InfoItemBuilder(a, rootView);
|
infoItemBuilder = new InfoItemBuilder(a, rootView);
|
||||||
@ -54,9 +70,9 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
|||||||
infoItemBuilder.setOnChannelInfoItemSelectedListener(listener);
|
infoItemBuilder.setOnChannelInfoItemSelectedListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInfoItemList(List<InfoItem> videos) {
|
public void addInfoItemList(List<InfoItem> data) {
|
||||||
if(videos!= null) {
|
if(data != null) {
|
||||||
infoItemList.addAll(videos);
|
infoItemList.addAll(data);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,21 +82,42 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHeader(View header) {
|
||||||
|
this.header = header;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFooter(View view) {
|
||||||
|
this.footer = view;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return infoItemList.size();
|
int cound = infoItemList.size();
|
||||||
|
if(header != null) cound++;
|
||||||
|
if(footer != null && showFooter) cound++;
|
||||||
|
return cound;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't ask why we have to do that this way... it's android accept it -.-
|
// don't ask why we have to do that this way... it's android accept it -.-
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
|
if(header != null && position == 0) {
|
||||||
|
return 0;
|
||||||
|
} else if(header != null) {
|
||||||
|
position--;
|
||||||
|
}
|
||||||
|
if(footer != null && position == infoItemList.size() && showFooter) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
switch(infoItemList.get(position).infoType()) {
|
switch(infoItemList.get(position).infoType()) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
return 0;
|
|
||||||
case CHANNEL:
|
|
||||||
return 1;
|
|
||||||
case PLAYLIST:
|
|
||||||
return 2;
|
return 2;
|
||||||
|
case CHANNEL:
|
||||||
|
return 3;
|
||||||
|
case PLAYLIST:
|
||||||
|
return 4;
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Trollolo");
|
Log.e(TAG, "Trollolo");
|
||||||
return -1;
|
return -1;
|
||||||
@ -88,15 +125,19 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InfoItemHolder onCreateViewHolder(ViewGroup parent, int type) {
|
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case 0:
|
case 0:
|
||||||
|
return new HFHolder(header);
|
||||||
|
case 1:
|
||||||
|
return new HFHolder(footer);
|
||||||
|
case 2:
|
||||||
return new StreamInfoItemHolder(LayoutInflater.from(parent.getContext())
|
return new StreamInfoItemHolder(LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.stream_item, parent, false));
|
.inflate(R.layout.stream_item, parent, false));
|
||||||
case 1:
|
case 3:
|
||||||
return new ChannelInfoItemHolder(LayoutInflater.from(parent.getContext())
|
return new ChannelInfoItemHolder(LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.channel_item, parent, false));
|
.inflate(R.layout.channel_item, parent, false));
|
||||||
case 2:
|
case 4:
|
||||||
Log.e(TAG, "Playlist is not yet implemented");
|
Log.e(TAG, "Playlist is not yet implemented");
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
@ -106,7 +147,17 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(InfoItemHolder holder, int i) {
|
public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
|
||||||
infoItemBuilder.buildByHolder(holder, infoItemList.get(i));
|
//god damen f*** ANDROID SH**
|
||||||
|
if(holder instanceof InfoItemHolder) {
|
||||||
|
if(header != null) {
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
infoItemBuilder.buildByHolder((InfoItemHolder) holder, infoItemList.get(i));
|
||||||
|
} else if(holder instanceof HFHolder && i == 0 && header != null) {
|
||||||
|
((HFHolder) holder).view = header;
|
||||||
|
} else if(holder instanceof HFHolder && i == infoItemList.size() && footer != null && showFooter) {
|
||||||
|
((HFHolder) holder).view = footer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
package org.schabi.newpipe.report;
|
package org.schabi.newpipe.report;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -8,14 +6,14 @@ import android.content.Intent;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@ -35,8 +33,8 @@ import org.schabi.newpipe.BuildConfig;
|
|||||||
import org.schabi.newpipe.Downloader;
|
import org.schabi.newpipe.Downloader;
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.ThemableActivity;
|
|
||||||
import org.schabi.newpipe.extractor.Parser;
|
import org.schabi.newpipe.extractor.Parser;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
@ -66,65 +64,12 @@ import java.util.Vector;
|
|||||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ErrorActivity extends ThemableActivity {
|
public class ErrorActivity extends AppCompatActivity {
|
||||||
public static class ErrorInfo implements Parcelable {
|
|
||||||
public int userAction;
|
|
||||||
public String request;
|
|
||||||
public String serviceName;
|
|
||||||
public int message;
|
|
||||||
|
|
||||||
public static ErrorInfo make(int userAction, String serviceName, String request, int message) {
|
|
||||||
ErrorInfo info = new ErrorInfo();
|
|
||||||
info.userAction = userAction;
|
|
||||||
info.serviceName = serviceName;
|
|
||||||
info.request = request;
|
|
||||||
info.message = message;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
|
||||||
dest.writeInt(this.userAction);
|
|
||||||
dest.writeString(this.request);
|
|
||||||
dest.writeString(this.serviceName);
|
|
||||||
dest.writeInt(this.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErrorInfo() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ErrorInfo(Parcel in) {
|
|
||||||
this.userAction = in.readInt();
|
|
||||||
this.request = in.readString();
|
|
||||||
this.serviceName = in.readString();
|
|
||||||
this.message = in.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Parcelable.Creator<ErrorInfo> CREATOR = new Parcelable.Creator<ErrorInfo>() {
|
|
||||||
@Override
|
|
||||||
public ErrorInfo createFromParcel(Parcel source) {
|
|
||||||
return new ErrorInfo(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ErrorInfo[] newArray(int size) {
|
|
||||||
return new ErrorInfo[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOG TAGS
|
// LOG TAGS
|
||||||
public static final String TAG = ErrorActivity.class.toString();
|
public static final String TAG = ErrorActivity.class.toString();
|
||||||
|
|
||||||
// BUNDLE TAGS
|
// BUNDLE TAGS
|
||||||
public static final String ERROR_INFO = "error_info";
|
public static final String ERROR_INFO = "error_info";
|
||||||
public static final String ERROR_LIST = "error_list";
|
public static final String ERROR_LIST = "error_list";
|
||||||
|
|
||||||
// MESSAGE ID
|
// MESSAGE ID
|
||||||
public static final int SEARCHED = 0;
|
public static final int SEARCHED = 0;
|
||||||
public static final int REQUESTED_STREAM = 1;
|
public static final int REQUESTED_STREAM = 1;
|
||||||
@ -134,7 +79,6 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
public static final int LOAD_IMAGE = 5;
|
public static final int LOAD_IMAGE = 5;
|
||||||
public static final int UI_ERROR = 6;
|
public static final int UI_ERROR = 6;
|
||||||
public static final int REQUESTED_CHANNEL = 7;
|
public static final int REQUESTED_CHANNEL = 7;
|
||||||
|
|
||||||
// MESSAGE STRING
|
// MESSAGE STRING
|
||||||
public static final String SEARCHED_STRING = "searched";
|
public static final String SEARCHED_STRING = "searched";
|
||||||
public static final String REQUESTED_STREAM_STRING = "requested stream";
|
public static final String REQUESTED_STREAM_STRING = "requested stream";
|
||||||
@ -144,17 +88,14 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
public static final String LOAD_IMAGE_STRING = "load image";
|
public static final String LOAD_IMAGE_STRING = "load image";
|
||||||
public static final String UI_ERROR_STRING = "ui error";
|
public static final String UI_ERROR_STRING = "ui error";
|
||||||
public static final String REQUESTED_CHANNEL_STRING = "requested channel";
|
public static final String REQUESTED_CHANNEL_STRING = "requested channel";
|
||||||
|
|
||||||
public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org";
|
public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org";
|
||||||
public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME;
|
public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME;
|
||||||
|
Thread globIpRangeThread;
|
||||||
private String[] errorList;
|
private String[] errorList;
|
||||||
private ErrorInfo errorInfo;
|
private ErrorInfo errorInfo;
|
||||||
private Class returnActivity;
|
private Class returnActivity;
|
||||||
private String currentTimeStamp;
|
private String currentTimeStamp;
|
||||||
private String globIpRange;
|
private String globIpRange;
|
||||||
Thread globIpRangeThread;
|
|
||||||
|
|
||||||
// views
|
// views
|
||||||
private TextView errorView;
|
private TextView errorView;
|
||||||
private EditText userCommentBox;
|
private EditText userCommentBox;
|
||||||
@ -243,9 +184,26 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getStackTrace(final Throwable throwable) {
|
||||||
|
final StringWriter sw = new StringWriter();
|
||||||
|
final PrintWriter pw = new PrintWriter(sw, true);
|
||||||
|
throwable.printStackTrace(pw);
|
||||||
|
return sw.getBuffer().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorList to StringList
|
||||||
|
private static String[] elToSl(List<Throwable> stackTraces) {
|
||||||
|
String[] out = new String[stackTraces.size()];
|
||||||
|
for (int i = 0; i < stackTraces.size(); i++) {
|
||||||
|
out[i] = getStackTrace(stackTraces.get(i));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
ThemeHelper.setTheme(this, true);
|
||||||
setContentView(R.layout.activity_error);
|
setContentView(R.layout.activity_error);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
@ -335,13 +293,6 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getStackTrace(final Throwable throwable) {
|
|
||||||
final StringWriter sw = new StringWriter();
|
|
||||||
final PrintWriter pw = new PrintWriter(sw, true);
|
|
||||||
throwable.printStackTrace(pw);
|
|
||||||
return sw.getBuffer().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formErrorText(String[] el) {
|
private String formErrorText(String[] el) {
|
||||||
String text = "";
|
String text = "";
|
||||||
if(el != null) {
|
if(el != null) {
|
||||||
@ -478,6 +429,56 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
return df.format(new Date());
|
return df.format(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ErrorInfo implements Parcelable {
|
||||||
|
public static final Parcelable.Creator<ErrorInfo> CREATOR = new Parcelable.Creator<ErrorInfo>() {
|
||||||
|
@Override
|
||||||
|
public ErrorInfo createFromParcel(Parcel source) {
|
||||||
|
return new ErrorInfo(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ErrorInfo[] newArray(int size) {
|
||||||
|
return new ErrorInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public int userAction;
|
||||||
|
public String request;
|
||||||
|
public String serviceName;
|
||||||
|
public int message;
|
||||||
|
|
||||||
|
public ErrorInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ErrorInfo(Parcel in) {
|
||||||
|
this.userAction = in.readInt();
|
||||||
|
this.request = in.readString();
|
||||||
|
this.serviceName = in.readString();
|
||||||
|
this.message = in.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ErrorInfo make(int userAction, String serviceName, String request, int message) {
|
||||||
|
ErrorInfo info = new ErrorInfo();
|
||||||
|
info.userAction = userAction;
|
||||||
|
info.serviceName = serviceName;
|
||||||
|
info.request = request;
|
||||||
|
info.message = message;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(this.userAction);
|
||||||
|
dest.writeString(this.request);
|
||||||
|
dest.writeString(this.serviceName);
|
||||||
|
dest.writeInt(this.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class IpRagneRequester implements Runnable {
|
private class IpRagneRequester implements Runnable {
|
||||||
Handler h = new Handler();
|
Handler h = new Handler();
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -497,8 +498,6 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class IpRageReturnRunnable implements Runnable {
|
private class IpRageReturnRunnable implements Runnable {
|
||||||
String ipRange;
|
String ipRange;
|
||||||
public IpRageReturnRunnable(String ipRange) {
|
public IpRageReturnRunnable(String ipRange) {
|
||||||
@ -514,13 +513,4 @@ public class ErrorActivity extends ThemableActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorList to StringList
|
|
||||||
private static String[] elToSl(List<Throwable> stackTraces) {
|
|
||||||
String[] out = new String[stackTraces.size()];
|
|
||||||
for(int i = 0; i < stackTraces.size(); i++) {
|
|
||||||
out[i] = getStackTrace(stackTraces.get(i));
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,6 @@ public class SearchInfoItemFragment extends Fragment {
|
|||||||
RECAPTCHA_REQUEST);
|
RECAPTCHA_REQUEST);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -221,6 +220,8 @@ public class SearchInfoItemFragment extends Fragment {
|
|||||||
|
|
||||||
infoListAdapter = new InfoListAdapter(getActivity(),
|
infoListAdapter = new InfoListAdapter(getActivity(),
|
||||||
getActivity().findViewById(android.R.id.content));
|
getActivity().findViewById(android.R.id.content));
|
||||||
|
infoListAdapter.setFooter(inflater.inflate(R.layout.pignate_footer, recyclerView, false));
|
||||||
|
infoListAdapter.showFooter(false);
|
||||||
infoListAdapter.setOnStreamInfoItemSelectedListener(
|
infoListAdapter.setOnStreamInfoItemSelectedListener(
|
||||||
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -324,6 +325,7 @@ public class SearchInfoItemFragment extends Fragment {
|
|||||||
|
|
||||||
private void search(String query) {
|
private void search(String query) {
|
||||||
infoListAdapter.clearSteamItemList();
|
infoListAdapter.clearSteamItemList();
|
||||||
|
infoListAdapter.showFooter(false);
|
||||||
pageNumber = 0;
|
pageNumber = 0;
|
||||||
searchQuery = query;
|
searchQuery = query;
|
||||||
search(query, pageNumber);
|
search(query, pageNumber);
|
||||||
@ -344,6 +346,7 @@ public class SearchInfoItemFragment extends Fragment {
|
|||||||
private void setDoneLoading() {
|
private void setDoneLoading() {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
loadingIndicator.setVisibility(View.GONE);
|
loadingIndicator.setVisibility(View.GONE);
|
||||||
|
infoListAdapter.showFooter(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,7 +5,6 @@ import android.content.Intent;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceActivity;
|
import android.preference.PreferenceActivity;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.LayoutRes;
|
import android.support.annotation.LayoutRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
@ -16,8 +15,7 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,16 +39,16 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public class SettingsActivity extends PreferenceActivity {
|
public class SettingsActivity extends PreferenceActivity {
|
||||||
private AppCompatDelegate mDelegate = null;
|
|
||||||
SettingsFragment f = new SettingsFragment();
|
SettingsFragment f = new SettingsFragment();
|
||||||
|
private AppCompatDelegate mDelegate = null;
|
||||||
|
|
||||||
|
public static void initSettings(Context context) {
|
||||||
|
NewPipeSettings.initSettings(context);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceBundle) {
|
protected void onCreate(Bundle savedInstanceBundle) {
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this)
|
ThemeHelper.setTheme(this, true);
|
||||||
.getString("theme", getResources().getString(R.string.light_theme_title)).
|
|
||||||
equals(getResources().getString(R.string.dark_theme_title))) {
|
|
||||||
setTheme(R.style.DarkTheme);
|
|
||||||
}
|
|
||||||
getDelegate().installViewFactory();
|
getDelegate().installViewFactory();
|
||||||
getDelegate().onCreate(savedInstanceBundle);
|
getDelegate().onCreate(savedInstanceBundle);
|
||||||
super.onCreate(savedInstanceBundle);
|
super.onCreate(savedInstanceBundle);
|
||||||
@ -156,8 +154,4 @@ public class SettingsActivity extends PreferenceActivity {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initSettings(Context context) {
|
|
||||||
NewPipeSettings.initSettings(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
package org.schabi.newpipe.settings;
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ListActivity;
|
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.CheckBoxPreference;
|
|
||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
import android.support.v7.app.AlertDialog;
|
||||||
|
|
||||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||||
|
|
||||||
import org.schabi.newpipe.App;
|
import org.schabi.newpipe.App;
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
import info.guardianproject.netcipher.proxy.OrbotHelper;
|
||||||
|
|
||||||
@ -48,8 +48,8 @@ import info.guardianproject.netcipher.proxy.OrbotHelper;
|
|||||||
public class SettingsFragment extends PreferenceFragment
|
public class SettingsFragment extends PreferenceFragment
|
||||||
implements SharedPreferences.OnSharedPreferenceChangeListener
|
implements SharedPreferences.OnSharedPreferenceChangeListener
|
||||||
{
|
{
|
||||||
|
public static final int REQUEST_INSTALL_ORBOT = 0x1234;
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener prefListener;
|
SharedPreferences.OnSharedPreferenceChangeListener prefListener;
|
||||||
|
|
||||||
// get keys
|
// get keys
|
||||||
String DEFAULT_RESOLUTION_PREFERENCE;
|
String DEFAULT_RESOLUTION_PREFERENCE;
|
||||||
String DEFAULT_AUDIO_FORMAT_PREFERENCE;
|
String DEFAULT_AUDIO_FORMAT_PREFERENCE;
|
||||||
@ -58,9 +58,6 @@ public class SettingsFragment extends PreferenceFragment
|
|||||||
String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
String DOWNLOAD_PATH_AUDIO_PREFERENCE;
|
||||||
String USE_TOR_KEY;
|
String USE_TOR_KEY;
|
||||||
String THEME;
|
String THEME;
|
||||||
|
|
||||||
public static final int REQUEST_INSTALL_ORBOT = 0x1234;
|
|
||||||
|
|
||||||
private ListPreference defaultResolutionPreference;
|
private ListPreference defaultResolutionPreference;
|
||||||
private ListPreference defaultAudioFormatPreference;
|
private ListPreference defaultAudioFormatPreference;
|
||||||
private ListPreference searchLanguagePreference;
|
private ListPreference searchLanguagePreference;
|
||||||
@ -98,6 +95,8 @@ public class SettingsFragment extends PreferenceFragment
|
|||||||
downloadPathAudioPreference = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
downloadPathAudioPreference = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
|
||||||
themePreference = findPreference(THEME);
|
themePreference = findPreference(THEME);
|
||||||
|
|
||||||
|
final String currentTheme = defaultPreferences.getString(THEME, "Light");
|
||||||
|
|
||||||
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||||
@ -139,8 +138,27 @@ public class SettingsFragment extends PreferenceFragment
|
|||||||
}
|
}
|
||||||
else if (key == THEME)
|
else if (key == THEME)
|
||||||
{
|
{
|
||||||
String theme = sharedPreferences.getString(THEME, "Light");
|
String selectedTheme = sharedPreferences.getString(THEME, "Light");
|
||||||
themePreference.setSummary(theme);
|
themePreference.setSummary(selectedTheme);
|
||||||
|
|
||||||
|
if(!selectedTheme.equals(currentTheme)) { // If it's not the current theme
|
||||||
|
new AlertDialog.Builder(activity)
|
||||||
|
.setTitle(R.string.restart_title)
|
||||||
|
.setMessage(R.string.msg_restart)
|
||||||
|
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
Intent intentToMain = new Intent(activity, MainActivity.class);
|
||||||
|
intentToMain.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
activity.startActivity(intentToMain);
|
||||||
|
|
||||||
|
activity.finish();
|
||||||
|
Runtime.getRuntime().exit(0);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.later, null)
|
||||||
|
.create().show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateSummary();
|
updateSummary();
|
||||||
}
|
}
|
||||||
|
31
app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
Normal file
31
app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package org.schabi.newpipe.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
public class ThemeHelper {
|
||||||
|
|
||||||
|
public static void setTheme(Context context, boolean mode) {
|
||||||
|
// mode is true for normal theme, false for no action bar theme.
|
||||||
|
|
||||||
|
String themeKey = context.getString(R.string.theme_key);
|
||||||
|
//String lightTheme = context.getResources().getString(R.string.light_theme_title);
|
||||||
|
String darkTheme = context.getResources().getString(R.string.dark_theme_title);
|
||||||
|
String blackTheme = context.getResources().getString(R.string.black_theme_title);
|
||||||
|
|
||||||
|
String sp = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getString(themeKey, context.getResources().getString(R.string.light_theme_title));
|
||||||
|
|
||||||
|
if (mode) {
|
||||||
|
if (sp.equals(darkTheme)) context.setTheme(R.style.DarkTheme);
|
||||||
|
else if (sp.equals(blackTheme)) context.setTheme(R.style.BlackTheme);
|
||||||
|
else context.setTheme(R.style.AppTheme);
|
||||||
|
} else {
|
||||||
|
if (sp.equals(darkTheme)) context.setTheme(R.style.DarkTheme_NoActionBar);
|
||||||
|
else if (sp.equals(blackTheme)) context.setTheme(R.style.BlackTheme_NoActionBar);
|
||||||
|
else context.setTheme(R.style.AppTheme_NoActionBar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
app/src/main/res/drawable-nodpi/channel_banner.png
Normal file
BIN
app/src/main/res/drawable-nodpi/channel_banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
12
app/src/main/res/drawable-v21/splash_screen.xml
Normal file
12
app/src/main/res/drawable-v21/splash_screen.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:drawable="?android:windowBackground"/>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/ic_launcher"/>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
@ -1,9 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
|
||||||
android:drawable="?android:attr/windowBackground"/>
|
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<bitmap
|
<bitmap
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
79
app/src/main/res/layout-land/channel_header.xml
Normal file
79
app/src/main/res/layout-land/channel_header.xml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/channel_header_layout"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/channel_banner_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/channel_banner"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
android:adjustViewBounds="true"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/channel_avatar_layout"
|
||||||
|
android:layout_alignTop="@id/channel_banner_image"
|
||||||
|
android:layout_width="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="60dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/channel_avatar_halo"
|
||||||
|
android:layout_width="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:src="@drawable/white_circle" />
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/channel_avatar_view"
|
||||||
|
android:layout_width="@dimen/channel_avatar_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_size"
|
||||||
|
android:src="@drawable/buddy"
|
||||||
|
android:layout_centerInParent="true"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/channel_title_view"
|
||||||
|
android:layout_below="@id/channel_banner_image"
|
||||||
|
android:layout_toEndOf="@id/channel_avatar_layout"
|
||||||
|
android:layout_toRightOf="@id/channel_avatar_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textSize="@dimen/video_item_detail_title_text_size"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/channel_subscriber_layout"
|
||||||
|
android:layout_below="@id/channel_banner_image"
|
||||||
|
android:layout_toEndOf="@id/channel_title_view"
|
||||||
|
android:layout_toRightOf="@id/channel_title_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<Button
|
||||||
|
android:id="@+id/channel_subscribe_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/subscribe"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginStart="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/channel_subscriber_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -1,81 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
android:orientation="vertical"
|
||||||
android:id="@+id/rootView"
|
android:title="Channel">
|
||||||
tools:context="org.schabi.newpipe.ChannelActivity">
|
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/channel_app_bar"
|
android:id="@+id/channel_streams_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/app_bar_height"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
android:background="?android:windowBackground"
|
||||||
android:theme="@style/AppTheme.AppBarOverlay">
|
android:scrollbars="vertical"/>
|
||||||
|
|
||||||
<android.support.design.widget.CollapsingToolbarLayout
|
|
||||||
android:id="@+id/channel_toolbar_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
app:contentScrim="@color/light_youtube_primary_color"
|
|
||||||
app:statusBarScrim="@color/light_youtube_dark_color"
|
|
||||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
|
||||||
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/channel_banner_image"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fitsSystemWindows="true"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:background="@color/light_youtube_dark_color"
|
|
||||||
app:layout_collapseMode="parallax" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/channel_avatar_halo"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="28dp"
|
|
||||||
android:layout_marginStart="28dp"
|
|
||||||
android:layout_marginTop="38dp"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:src="@drawable/white_circle"/>
|
|
||||||
|
|
||||||
<de.hdodenhof.circleimageview.CircleImageView
|
|
||||||
android:id="@+id/channel_avatar_view"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="@dimen/channel_avatar_size"
|
|
||||||
android:layout_height="@dimen/channel_avatar_size"
|
|
||||||
android:src="@drawable/buddy"
|
|
||||||
android:layout_marginLeft="30dp"
|
|
||||||
android:layout_marginStart="30dp"
|
|
||||||
android:layout_marginTop="40dp"
|
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentStart="true"/>
|
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
|
||||||
android:id="@+id/cannel_toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
app:layout_collapseMode="pin"
|
|
||||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
|
||||||
|
|
||||||
</android.support.design.widget.CollapsingToolbarLayout>
|
|
||||||
</android.support.design.widget.AppBarLayout>
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/channel_rss_fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="@dimen/fab_margin"
|
|
||||||
android:src="?attr/rss"
|
|
||||||
app:layout_anchor="@id/channel_app_bar"
|
|
||||||
app:layout_anchorGravity="bottom|end" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -87,11 +23,4 @@
|
|||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:indeterminate="true"/>
|
android:indeterminate="true"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
<android.support.v7.widget.RecyclerView
|
</RelativeLayout>
|
||||||
android:id="@+id/channel_streams_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?android:windowBackground"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
android:scrollbars="vertical"/>
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
78
app/src/main/res/layout/channel_header.xml
Normal file
78
app/src/main/res/layout/channel_header.xml
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/channel_header_layout"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/channel_banner_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/channel_banner"
|
||||||
|
android:background="@android:color/black"
|
||||||
|
android:adjustViewBounds="true"/>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/channel_avatar_layout"
|
||||||
|
android:layout_alignTop="@id/channel_banner_image"
|
||||||
|
android:layout_width="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginTop="30dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/channel_avatar_halo"
|
||||||
|
android:layout_width="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_halo_size"
|
||||||
|
android:layout_alignParentLeft="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:src="@drawable/white_circle" />
|
||||||
|
|
||||||
|
<de.hdodenhof.circleimageview.CircleImageView
|
||||||
|
android:id="@+id/channel_avatar_view"
|
||||||
|
android:layout_width="@dimen/channel_avatar_size"
|
||||||
|
android:layout_height="@dimen/channel_avatar_size"
|
||||||
|
android:src="@drawable/buddy"
|
||||||
|
android:layout_centerInParent="true"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/channel_title_view"
|
||||||
|
android:layout_below="@id/channel_banner_image"
|
||||||
|
android:layout_toEndOf="@id/channel_avatar_layout"
|
||||||
|
android:layout_toRightOf="@id/channel_avatar_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:textSize="@dimen/video_item_detail_title_text_size"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/channel_subscriber_layout"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_below="@id/channel_avatar_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<Button
|
||||||
|
android:id="@+id/channel_subscribe_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/subscribe"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginStart="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/channel_subscriber_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
15
app/src/main/res/layout/pignate_footer.xml
Normal file
15
app/src/main/res/layout/pignate_footer.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/paginate_progress_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingBottom="10dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -2,6 +2,16 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context="org.schabi.newpipe.ChannelActivity">
|
tools:context="org.schabi.newpipe.ChannelActivity">
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_item_openInBrowser"
|
||||||
|
app:showAsAction="never"
|
||||||
|
android:title="@string/open_in_browser" />
|
||||||
|
|
||||||
|
<item android:id="@+id/menu_item_share"
|
||||||
|
android:title="@string/share"
|
||||||
|
app:showAsAction="ifRoom"
|
||||||
|
android:icon="?attr/share"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_settings"
|
||||||
android:orderInCategory="100"
|
android:orderInCategory="100"
|
||||||
|
@ -175,16 +175,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -193,13 +193,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -208,13 +208,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -223,12 +223,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -237,12 +237,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -251,8 +251,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -261,10 +261,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -273,16 +273,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -291,17 +291,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -165,16 +165,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -183,13 +183,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -198,13 +198,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -213,12 +213,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -227,12 +227,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -241,8 +241,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -251,10 +251,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -263,16 +263,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -281,17 +281,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,16 +157,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -175,13 +175,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -190,13 +190,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -205,12 +205,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -219,12 +219,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -233,8 +233,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -243,10 +243,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -255,16 +255,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -273,17 +273,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,16 +170,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -188,13 +188,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -203,13 +203,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -218,12 +218,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -232,12 +232,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -246,8 +246,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -256,10 +256,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -268,16 +268,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -286,17 +286,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,16 +168,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -186,13 +186,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -201,13 +201,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -216,12 +216,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -230,12 +230,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -244,8 +244,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -254,10 +254,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -266,16 +266,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -284,17 +284,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -163,16 +163,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -181,13 +181,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -196,13 +196,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -211,12 +211,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -225,12 +225,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -239,8 +239,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -249,10 +249,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -261,16 +261,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -279,17 +279,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -164,16 +164,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -182,13 +182,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -197,13 +197,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -212,12 +212,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -226,12 +226,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -240,8 +240,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -250,10 +250,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -262,16 +262,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -280,17 +280,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,16 +161,16 @@
|
|||||||
|
|
||||||
|
|
||||||
Materiál metafora je zjednocujúci teórie racionálne priestoru a systém pohybu.
|
Materiál metafora je zjednocujúci teórie racionálne priestoru a systém pohybu.
|
||||||
Materiál je zakotvená v taktilné skutočnosti, inšpirované štúdiom papiera a atramentu, ale napriek tomu
|
Materiál je zakotvená v taktilné skutočnosti, inšpirované štúdiom papiera a atramentu, ale napriek tomu
|
||||||
technologicky pokročilé a otvorené fantáziu a mágiu.
|
technologicky pokročilé a otvorené fantáziu a mágiu.
|
||||||
|
|
||||||
Povrchy a hrany materiálu poskytujú vizuálnu pokyny, ktoré sú zakotvené v realite.
|
Povrchy a hrany materiálu poskytujú vizuálnu pokyny, ktoré sú zakotvené v realite.
|
||||||
Použitie známych hmatových vlastností, pomáha používateľom rýchlo pochopiť affordances. napriek tomu
|
Použitie známych hmatových vlastností, pomáha používateľom rýchlo pochopiť affordances. napriek tomu
|
||||||
Pružnosť materiálu vytvára nové affordances že nadradené tie fyzické
|
Pružnosť materiálu vytvára nové affordances že nadradené tie fyzické
|
||||||
svet bez toho, aby porušenie pravidiel fyziky.
|
svet bez toho, aby porušenie pravidiel fyziky.
|
||||||
|
|
||||||
Základy svetla, povrchu a pohyb sú kľúčom k dopravovanie, ako sa objekty pohybovať,
|
Základy svetla, povrchu a pohyb sú kľúčom k dopravovanie, ako sa objekty pohybovať,
|
||||||
komunikovať, a existujú v priestore a vo vzťahu k sebe navzájom. Realistické svetelné šou
|
komunikovať, a existujú v priestore a vo vzťahu k sebe navzájom. Realistické svetelné šou
|
||||||
švy, rozdeľuje priestor, a indikuje pohyblivých častí.
|
švy, rozdeľuje priestor, a indikuje pohyblivých častí.
|
||||||
|
|
||||||
|
|
||||||
@ -179,13 +179,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Foundational prvky tlače na dizajn typografie, rošty, priestor, mierka, farby,
|
Foundational prvky tlače na dizajn typografie, rošty, priestor, mierka, farby,
|
||||||
a používanie metafor riadiť vizuálne procedúry. Tieto prvky robiť oveľa viac, než potešiť
|
a používanie metafor riadiť vizuálne procedúry. Tieto prvky robiť oveľa viac, než potešiť
|
||||||
oko. Vytvárajú hierarchie, zmysel a zameranie. výber farieb úmyselné, od okraja k okraju
|
oko. Vytvárajú hierarchie, zmysel a zameranie. výber farieb úmyselné, od okraja k okraju
|
||||||
snímok, rozsiahle typografie a úmyselné biely priestor vytvoriť tučný a grafický
|
snímok, rozsiahle typografie a úmyselné biely priestor vytvoriť tučný a grafický
|
||||||
rozhranie, ktoré ponorí užívateľov v zážitku.
|
rozhranie, ktoré ponorí užívateľov v zážitku.
|
||||||
|
|
||||||
Dôraz na užívateľských akcií činí základné funkcie okamžite zrejmé a poskytuje
|
Dôraz na užívateľských akcií činí základné funkcie okamžite zrejmé a poskytuje
|
||||||
waypointy pre užívateľov.
|
waypointy pre užívateľov.
|
||||||
|
|
||||||
|
|
||||||
@ -194,13 +194,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Návrh rešpektuje a posilňuje užívateľa ako hnacia sila. Primárne akcie užívateľa sú
|
Návrh rešpektuje a posilňuje užívateľa ako hnacia sila. Primárne akcie užívateľa sú
|
||||||
inflexné body, ktoré iniciujú pohyb, transformáciu celej konštrukcie.
|
inflexné body, ktoré iniciujú pohyb, transformáciu celej konštrukcie.
|
||||||
|
|
||||||
Celá akcia prebieha v jedinom prostredí. Objekty sú prezentované užívateľovi bez toho,
|
Celá akcia prebieha v jedinom prostredí. Objekty sú prezentované užívateľovi bez toho,
|
||||||
prelomenie kontinuity skúseností, aj keď ich transformáciu a reorganizáciu.
|
prelomenie kontinuity skúseností, aj keď ich transformáciu a reorganizáciu.
|
||||||
|
|
||||||
Pohyb je zmysluplné a vhodné, slúžiace sústrediť pozornosť a zachovanie kontinuity.
|
Pohyb je zmysluplné a vhodné, slúžiace sústrediť pozornosť a zachovanie kontinuity.
|
||||||
Spätná väzba je jemné, ale napriek tomu jasné. Prechody sú ef fi točné ešte koherentné.
|
Spätná väzba je jemné, ale napriek tomu jasné. Prechody sú ef fi točné ešte koherentné.
|
||||||
|
|
||||||
|
|
||||||
@ -209,12 +209,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Materiál prostredie je 3D priestore, čo znamená, že všetky objekty majú X, Y, a Z
|
Materiál prostredie je 3D priestore, čo znamená, že všetky objekty majú X, Y, a Z
|
||||||
rozmery. Os je kolmo zarovnaný k rovine zobrazenie, s
|
rozmery. Os je kolmo zarovnaný k rovine zobrazenie, s
|
||||||
kladná os rozširuje smerom k divákovi. Každý list materiálu, umiestnené v jednom
|
kladná os rozširuje smerom k divákovi. Každý list materiálu, umiestnené v jednom
|
||||||
poloha pozdĺž osi a má štandardnú hrúbku 1DP.
|
poloha pozdĺž osi a má štandardnú hrúbku 1DP.
|
||||||
|
|
||||||
Na webe, os sa používa pre vrstvenie a nie pre perspektívy. 3D svet
|
Na webe, os sa používa pre vrstvenie a nie pre perspektívy. 3D svet
|
||||||
emuloval tým, že manipuluje os y.
|
emuloval tým, že manipuluje os y.
|
||||||
|
|
||||||
|
|
||||||
@ -223,12 +223,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
V hmotnom prostredí, virtuálne svetlá osvetľujú scénu. Kľúčové svetla vytvárajú
|
V hmotnom prostredí, virtuálne svetlá osvetľujú scénu. Kľúčové svetla vytvárajú
|
||||||
smerové tiene, zatiaľ čo okolité svetlo vytvára mäkké tiene zo všetkých strán.
|
smerové tiene, zatiaľ čo okolité svetlo vytvára mäkké tiene zo všetkých strán.
|
||||||
|
|
||||||
Tiene v hmotnom prostredí sú obsadené týmito dvoma svetelnými zdrojmi. v Android
|
Tiene v hmotnom prostredí sú obsadené týmito dvoma svetelnými zdrojmi. v Android
|
||||||
vývoj, dochádza tiene, keď sú svetelné zdroje blokované plechového materiálu, na
|
vývoj, dochádza tiene, keď sú svetelné zdroje blokované plechového materiálu, na
|
||||||
Rôzne pozície pozdĺž osi. Na webe tiene sú znázornené manipuláciou
|
Rôzne pozície pozdĺž osi. Na webe tiene sú znázornené manipuláciou
|
||||||
Iba os y. Nasledujúci príklad ukazuje kartu s výškou 6dp.
|
Iba os y. Nasledujúci príklad ukazuje kartu s výškou 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -237,8 +237,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Všetky významné objekty, bez ohľadu na ich veľkosť, majú výšku odpočíva, alebo predvolené výšku
|
Všetky významné objekty, bez ohľadu na ich veľkosť, majú výšku odpočíva, alebo predvolené výšku
|
||||||
to nič nemení. V prípade, že objekt sa mení výšku, mal by sa vrátiť do svojej pokojovej
|
to nič nemení. V prípade, že objekt sa mení výšku, mal by sa vrátiť do svojej pokojovej
|
||||||
nadmorskej výšky čo najskôr.
|
nadmorskej výšky čo najskôr.
|
||||||
|
|
||||||
|
|
||||||
@ -247,10 +247,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Pokojová nadmorská výška pre typ komponentu je konzistentné naprieč aplikáciami (napr FAB elevácie
|
Pokojová nadmorská výška pre typ komponentu je konzistentné naprieč aplikáciami (napr FAB elevácie
|
||||||
nelíši od 6dp v jednej aplikácii na 16dp v inej aplikácii).
|
nelíši od 6dp v jednej aplikácii na 16dp v inej aplikácii).
|
||||||
|
|
||||||
Zložky môžu mať rôzne pokojovej výšky medzi platformami, v závislosti od hĺbky
|
Zložky môžu mať rôzne pokojovej výšky medzi platformami, v závislosti od hĺbky
|
||||||
životného prostredia (napr televízor má väčšiu hĺbku, ako mobilný telefón alebo plochy).
|
životného prostredia (napr televízor má väčšiu hĺbku, ako mobilný telefón alebo plochy).
|
||||||
|
|
||||||
|
|
||||||
@ -259,16 +259,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Niektoré typy komponentov majú citlivejší výšku, čo znamená, že meniť výšku v odozve
|
Niektoré typy komponentov majú citlivejší výšku, čo znamená, že meniť výšku v odozve
|
||||||
na vstup používateľa (napríklad normálny priebeh, sa zameral, a lisované), alebo systémové udalosti. tieto elevácie
|
na vstup používateľa (napríklad normálny priebeh, sa zameral, a lisované), alebo systémové udalosti. tieto elevácie
|
||||||
Zmeny sa vykonávali dôsledne používať dynamické výškové posuny.
|
Zmeny sa vykonávali dôsledne používať dynamické výškové posuny.
|
||||||
|
|
||||||
Dynamické výškové posuny sú cieľom nadmorská výška, ktorá zložka sa pohybuje smerom, relatívna
|
Dynamické výškové posuny sú cieľom nadmorská výška, ktorá zložka sa pohybuje smerom, relatívna
|
||||||
do pokojového stavu súčasti. Zaisťujú, že zmeny elevácie sú v súlade
|
do pokojového stavu súčasti. Zaisťujú, že zmeny elevácie sú v súlade
|
||||||
naprieč akcií a typov komponentov. Napríklad všetky súčasti, ktoré vlek na lise majú
|
naprieč akcií a typov komponentov. Napríklad všetky súčasti, ktoré vlek na lise majú
|
||||||
rovnaká zmena prevýšenie vo vzťahu k ich prevýšenie odpočinku.
|
rovnaká zmena prevýšenie vo vzťahu k ich prevýšenie odpočinku.
|
||||||
|
|
||||||
Akonáhle je vstupná udalosť dokončenie alebo zrušená, bude zložka vráti do svojej pokojovej
|
Akonáhle je vstupná udalosť dokončenie alebo zrušená, bude zložka vráti do svojej pokojovej
|
||||||
nadmorská výška.
|
nadmorská výška.
|
||||||
|
|
||||||
|
|
||||||
@ -277,17 +277,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Zložky s citlivými nadmorských výškach môže stretnúť s ďalšími komponentmi, ako sa pohybovať medzi
|
Zložky s citlivými nadmorských výškach môže stretnúť s ďalšími komponentmi, ako sa pohybovať medzi
|
||||||
ich odpočinku vyvýšeniny a dynamické výškové odsadenie. Vzhľadom k tomu, materiál nemôže prejsť
|
ich odpočinku vyvýšeniny a dynamické výškové odsadenie. Vzhľadom k tomu, materiál nemôže prejsť
|
||||||
prostredníctvom iného materiálu, komponenty nenarušovať spolu navzájom nejakom množstvo ciest,
|
prostredníctvom iného materiálu, komponenty nenarušovať spolu navzájom nejakom množstvo ciest,
|
||||||
či už na úrovni jednotlivých komponentov alebo s použitím kompletné rozloženie aplikácie.
|
či už na úrovni jednotlivých komponentov alebo s použitím kompletné rozloženie aplikácie.
|
||||||
|
|
||||||
Na úrovni komponentov môžu zložky presunúť alebo odstrániť skôr, než spôsobia rušenie.
|
Na úrovni komponentov môžu zložky presunúť alebo odstrániť skôr, než spôsobia rušenie.
|
||||||
Napríklad tlačidlo plávajúce akcie (FAB) môžu zmiznúť alebo presunúť mimo obrazovku pred
|
Napríklad tlačidlo plávajúce akcie (FAB) môžu zmiznúť alebo presunúť mimo obrazovku pred
|
||||||
Užívateľ zdvihne kartu, alebo sa môže pohybovať, ak sa objaví snackbar.
|
Užívateľ zdvihne kartu, alebo sa môže pohybovať, ak sa objaví snackbar.
|
||||||
|
|
||||||
Na úrovni Usporiadanie, riešenie rozvrhnutie aplikácie, aby sa minimalizovalo príležitostí k rušeniu.
|
Na úrovni Usporiadanie, riešenie rozvrhnutie aplikácie, aby sa minimalizovalo príležitostí k rušeniu.
|
||||||
Napríklad, umiestnenie FAB na jednej strane prúdu niekoľkých kariet, takže FAB nebude zasahovať
|
Napríklad, umiestnenie FAB na jednej strane prúdu niekoľkých kariet, takže FAB nebude zasahovať
|
||||||
ak sa užívateľ pokúsi vyzdvihnúť jednu z kariet.
|
ak sa užívateľ pokúsi vyzdvihnúť jednu z kariet.
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,16 +170,16 @@
|
|||||||
|
|
||||||
|
|
||||||
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
A material metaphor is the unifying theory of a rationalized space and a system of motion.
|
||||||
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
The material is grounded in tactile reality, inspired by the study of paper and ink, yet
|
||||||
technologically advanced and open to imagination and magic.
|
technologically advanced and open to imagination and magic.
|
||||||
|
|
||||||
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
Surfaces and edges of the material provide visual cues that are grounded in reality. The
|
||||||
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
use of familiar tactile attributes helps users quickly understand affordances. Yet the
|
||||||
flexibility of the material creates new affordances that supercede those in the physical
|
flexibility of the material creates new affordances that supercede those in the physical
|
||||||
world, without breaking the rules of physics.
|
world, without breaking the rules of physics.
|
||||||
|
|
||||||
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
The fundamentals of light, surface, and movement are key to conveying how objects move,
|
||||||
interact, and exist in space and in relation to each other. Realistic lighting shows
|
interact, and exist in space and in relation to each other. Realistic lighting shows
|
||||||
seams, divides space, and indicates moving parts.
|
seams, divides space, and indicates moving parts.
|
||||||
|
|
||||||
|
|
||||||
@ -188,13 +188,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The foundational elements of print based design typography, grids, space, scale, color,
|
The foundational elements of print based design typography, grids, space, scale, color,
|
||||||
and use of imagery guide visual treatments. These elements do far more than please the
|
and use of imagery guide visual treatments. These elements do far more than please the
|
||||||
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge
|
||||||
imagery, large scale typography, and intentional white space create a bold and graphic
|
imagery, large scale typography, and intentional white space create a bold and graphic
|
||||||
interface that immerse the user in the experience.
|
interface that immerse the user in the experience.
|
||||||
|
|
||||||
An emphasis on user actions makes core functionality immediately apparent and provides
|
An emphasis on user actions makes core functionality immediately apparent and provides
|
||||||
waypoints for the user.
|
waypoints for the user.
|
||||||
|
|
||||||
|
|
||||||
@ -203,13 +203,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
Motion respects and reinforces the user as the prime mover. Primary user actions are
|
||||||
inflection points that initiate motion, transforming the whole design.
|
inflection points that initiate motion, transforming the whole design.
|
||||||
|
|
||||||
All action takes place in a single environment. Objects are presented to the user without
|
All action takes place in a single environment. Objects are presented to the user without
|
||||||
breaking the continuity of experience even as they transform and reorganize.
|
breaking the continuity of experience even as they transform and reorganize.
|
||||||
|
|
||||||
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
Motion is meaningful and appropriate, serving to focus attention and maintain continuity.
|
||||||
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
Feedback is subtle yet clear. Transitions are efficient yet coherent.
|
||||||
|
|
||||||
|
|
||||||
@ -218,12 +218,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The material environment is a 3D space, which means all objects have x, y, and z
|
The material environment is a 3D space, which means all objects have x, y, and z
|
||||||
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the
|
||||||
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
positive z-axis extending towards the viewer. Every sheet of material occupies a single
|
||||||
position along the z-axis and has a standard 1dp thickness.
|
position along the z-axis and has a standard 1dp thickness.
|
||||||
|
|
||||||
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
On the web, the z-axis is used for layering and not for perspective. The 3D world is
|
||||||
emulated by manipulating the y-axis.
|
emulated by manipulating the y-axis.
|
||||||
|
|
||||||
|
|
||||||
@ -232,12 +232,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Within the material environment, virtual lights illuminate the scene. Key lights create
|
Within the material environment, virtual lights illuminate the scene. Key lights create
|
||||||
directional shadows, while ambient light creates soft shadows from all angles.
|
directional shadows, while ambient light creates soft shadows from all angles.
|
||||||
|
|
||||||
Shadows in the material environment are cast by these two light sources. In Android
|
Shadows in the material environment are cast by these two light sources. In Android
|
||||||
development, shadows occur when light sources are blocked by sheets of material at
|
development, shadows occur when light sources are blocked by sheets of material at
|
||||||
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
various positions along the z-axis. On the web, shadows are depicted by manipulating the
|
||||||
y-axis only. The following example shows the card with a height of 6dp.
|
y-axis only. The following example shows the card with a height of 6dp.
|
||||||
|
|
||||||
|
|
||||||
@ -246,8 +246,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
All material objects, regardless of size, have a resting elevation, or default elevation
|
All material objects, regardless of size, have a resting elevation, or default elevation
|
||||||
that does not change. If an object changes elevation, it should return to its resting
|
that does not change. If an object changes elevation, it should return to its resting
|
||||||
elevation as soon as possible.
|
elevation as soon as possible.
|
||||||
|
|
||||||
|
|
||||||
@ -256,10 +256,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
The resting elevation for a component type is consistent across apps (e.g., FAB elevation
|
||||||
does not vary from 6dp in one app to 16dp in another app).
|
does not vary from 6dp in one app to 16dp in another app).
|
||||||
|
|
||||||
Components may have different resting elevations across platforms, depending on the depth
|
Components may have different resting elevations across platforms, depending on the depth
|
||||||
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
of the environment (e.g., TV has a greater depth than mobile or desktop).
|
||||||
|
|
||||||
|
|
||||||
@ -268,16 +268,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some component types have responsive elevation, meaning they change elevation in response
|
Some component types have responsive elevation, meaning they change elevation in response
|
||||||
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
to user input (e.g., normal, focused, and pressed) or system events. These elevation
|
||||||
changes are consistently implemented using dynamic elevation offsets.
|
changes are consistently implemented using dynamic elevation offsets.
|
||||||
|
|
||||||
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
Dynamic elevation offsets are the goal elevation that a component moves towards, relative
|
||||||
to the component’s resting state. They ensure that elevation changes are consistent
|
to the component’s resting state. They ensure that elevation changes are consistent
|
||||||
across actions and component types. For example, all components that lift on press have
|
across actions and component types. For example, all components that lift on press have
|
||||||
the same elevation change relative to their resting elevation.
|
the same elevation change relative to their resting elevation.
|
||||||
|
|
||||||
Once the input event is completed or cancelled, the component will return to its resting
|
Once the input event is completed or cancelled, the component will return to its resting
|
||||||
elevation.
|
elevation.
|
||||||
|
|
||||||
|
|
||||||
@ -286,17 +286,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Components with responsive elevations may encounter other components as they move between
|
Components with responsive elevations may encounter other components as they move between
|
||||||
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
their resting elevations and dynamic elevation offsets. Because material cannot pass
|
||||||
through other material, components avoid interfering with one another any number of ways,
|
through other material, components avoid interfering with one another any number of ways,
|
||||||
whether on a per component basis or using the entire app layout.
|
whether on a per component basis or using the entire app layout.
|
||||||
|
|
||||||
On a component level, components can move or be removed before they cause interference.
|
On a component level, components can move or be removed before they cause interference.
|
||||||
For example, a floating action button (FAB) can disappear or move off screen before a
|
For example, a floating action button (FAB) can disappear or move off screen before a
|
||||||
user picks up a card, or it can move if a snackbar appears.
|
user picks up a card, or it can move if a snackbar appears.
|
||||||
|
|
||||||
On the layout level, design your app layout to minimize opportunities for interference.
|
On the layout level, design your app layout to minimize opportunities for interference.
|
||||||
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
For example, position the FAB to one side of stream of a cards so the FAB won’t interfere
|
||||||
when a user tries to pick up one of cards.
|
when a user tries to pick up one of cards.
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,10 +29,12 @@
|
|||||||
<string-array name="theme_description_list">
|
<string-array name="theme_description_list">
|
||||||
<item>@string/light_theme_title</item>
|
<item>@string/light_theme_title</item>
|
||||||
<item>@string/dark_theme_title</item>
|
<item>@string/dark_theme_title</item>
|
||||||
|
<item>@string/black_theme_title</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="theme_list">
|
<string-array name="theme_list">
|
||||||
<item>@string/light_theme_title</item>
|
<item>@string/light_theme_title</item>
|
||||||
<item>@string/dark_theme_title</item>
|
<item>@string/dark_theme_title</item>
|
||||||
|
<item>@string/black_theme_title</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string name="default_audio_format_key" translatable="false">default_audio_format</string>
|
<string name="default_audio_format_key" translatable="false">default_audio_format</string>
|
||||||
|
@ -86,6 +86,8 @@
|
|||||||
<string name="error_report_title">Error report</string>
|
<string name="error_report_title">Error report</string>
|
||||||
<string name="all">All</string>
|
<string name="all">All</string>
|
||||||
<string name="channel">Channel</string>
|
<string name="channel">Channel</string>
|
||||||
|
<string name="yes">Yes</string>
|
||||||
|
<string name="later">Later</string>
|
||||||
|
|
||||||
<!-- error strings -->
|
<!-- error strings -->
|
||||||
<string name="general_error">Error</string>
|
<string name="general_error">Error</string>
|
||||||
@ -151,10 +153,12 @@
|
|||||||
<string name="use_exoplayer_summary">Experimental</string>
|
<string name="use_exoplayer_summary">Experimental</string>
|
||||||
<string name="videos">videos</string>
|
<string name="videos">videos</string>
|
||||||
<string name="subscriber">subscriber</string>
|
<string name="subscriber">subscriber</string>
|
||||||
|
<string name="subscribe">Subscribe</string>
|
||||||
<string name="views">views</string>
|
<string name="views">views</string>
|
||||||
<string name="short_thousand">T</string>
|
<string name="short_thousand">K</string>
|
||||||
<string name="short_million">M</string>
|
<string name="short_million">M</string>
|
||||||
<string name="short_billion">B</string>
|
<string name="short_billion">B</string>
|
||||||
|
<string name="restart_title">Restart</string>
|
||||||
|
|
||||||
<!-- Missions -->
|
<!-- Missions -->
|
||||||
<string name="start">Start</string>
|
<string name="start">Start</string>
|
||||||
@ -183,6 +187,7 @@
|
|||||||
<string name="msg_wait">Please wait…</string>
|
<string name="msg_wait">Please wait…</string>
|
||||||
<string name="msg_copied">Copied to clipboard.</string>
|
<string name="msg_copied">Copied to clipboard.</string>
|
||||||
<string name="no_available_dir">Please select an available download directory.</string>
|
<string name="no_available_dir">Please select an available download directory.</string>
|
||||||
|
<string name="msg_restart">You have to restart the application to apply the theme.\n\nDo you want to restart now?</string>
|
||||||
|
|
||||||
<!-- Checksum types -->
|
<!-- Checksum types -->
|
||||||
<string name="md5" translatable="false">MD5</string>
|
<string name="md5" translatable="false">MD5</string>
|
||||||
|
@ -49,6 +49,10 @@
|
|||||||
<item name="rss">@drawable/ic_rss_feed_black_24dp</item>
|
<item name="rss">@drawable/ic_rss_feed_black_24dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="BlackTheme" parent="DarkTheme">
|
||||||
|
<item name="android:windowBackground">@color/black</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="NewPipeActionbarTheme" parent="Widget.AppCompat.Light.ActionBar.Solid">
|
<style name="NewPipeActionbarTheme" parent="Widget.AppCompat.Light.ActionBar.Solid">
|
||||||
<item name="android:displayOptions">showHome</item>
|
<item name="android:displayOptions">showHome</item>
|
||||||
<item name="displayOptions">showHome</item>
|
<item name="displayOptions">showHome</item>
|
||||||
@ -107,6 +111,11 @@
|
|||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="BlackTheme.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
|
@ -87,6 +87,11 @@ public class YoutubeChannelExtractorTest {
|
|||||||
assertTrue("no next page link found", extractor.hasNextPage());
|
assertTrue("no next page link found", extractor.hasNextPage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSubscriberCount() throws Exception {
|
||||||
|
assertTrue("wrong subscriber count", extractor.getSubscriberCount() >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetNextPage() throws Exception {
|
public void testGetNextPage() throws Exception {
|
||||||
extractor = NewPipe.getService("Youtube")
|
extractor = NewPipe.getService("Youtube")
|
||||||
|
@ -111,9 +111,9 @@ public class YoutubeStreamUrlIdHandlerTest {
|
|||||||
|
|
||||||
assertTrue(urlIdHandler.acceptUrl("vnd.youtube:jZViOEv90dI"));
|
assertTrue(urlIdHandler.acceptUrl("vnd.youtube:jZViOEv90dI"));
|
||||||
|
|
||||||
String sharedId = "7JIArTByb3E";
|
String sharedId = "8A940MXKFmQ";
|
||||||
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId + "&feature=twitter-deep-link"));
|
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId + "&feature=twitter-deep-link"));
|
||||||
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId ));
|
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId ));
|
||||||
assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/shared?ci=7JIArTByb3E"));
|
assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/shared?ci=" + sharedId));
|
||||||
}
|
}
|
||||||
}
|
}
|
186
assets/channel_banner_desktop.svg
Normal file
186
assets/channel_banner_desktop.svg
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="2550"
|
||||||
|
height="427"
|
||||||
|
viewBox="0 0 674.68749 112.97708"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.1 r"
|
||||||
|
sodipodi:docname="channel_banner_desktop.svg"
|
||||||
|
inkscape:export-filename="/home/the-scrabi/channel_banner.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.1438037"
|
||||||
|
inkscape:cx="983.1312"
|
||||||
|
inkscape:cy="-254.76355"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1012"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-184.02291)">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 283.72686,296.99999 h 30.94953 l 81.58882,-112.97708 h -30.949 z"
|
||||||
|
id="path5067" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 221.83555,296.99999 h 30.94902 L 334.3739,184.02291 h -30.94953 z"
|
||||||
|
id="path5063" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 159.94424,296.99999 h 30.95005 L 272.4831,184.02291 h -30.95004 z"
|
||||||
|
id="path5059" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 98.052928,296.99999 H 129.00246 L 210.59128,184.02291 H 179.64175 Z"
|
||||||
|
id="path5055" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 36.161617,296.99999 H 67.111149 L 148.70048,184.02291 h -30.94953 z"
|
||||||
|
id="path5051" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 0,261.37168 v 35.62831 H 5.2193195 L 86.808653,184.02291 H 55.859121 Z"
|
||||||
|
id="path5047" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 24.917342,184.02291 H 0 v 34.50332 z"
|
||||||
|
id="path5045" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 252.7794,296.99999 h 30.94952 l 81.58935,-112.97708 h -30.95005 z"
|
||||||
|
id="path5020" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 190.88809,296.99999 h 30.94953 l 81.58932,-112.97708 h -30.94953 z"
|
||||||
|
id="path5016" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 128.99678,296.99999 h 30.94953 l 81.58933,-112.97708 h -30.95005 z"
|
||||||
|
id="path5012" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 67.105463,296.99999 H 98.054995 L 179.64381,184.02291 h -30.94953 z"
|
||||||
|
id="path5008" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 5.2141519,296.99999 H 36.163168 L 117.7525,184.02291 H 86.80297 Z"
|
||||||
|
id="path5004" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828106;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 55.861706,184.02291 H 24.912174 L 0,218.51848 v 42.8563 z"
|
||||||
|
id="path5000" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 531.30347,297 H 562.253 l 81.58881,-112.97709 h -30.949 z"
|
||||||
|
id="path5067-3" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 469.41216,297 h 30.94902 L 581.9505,184.02291 h -30.94952 z"
|
||||||
|
id="path5063-6" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 407.52085,297 H 438.4709 L 520.05971,184.02291 H 489.10967 Z"
|
||||||
|
id="path5059-7" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 345.62386,297 h 30.94953 l 81.58882,-112.97709 h -30.94953 z"
|
||||||
|
id="path5055-5" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 500.35601,297 h 30.94952 l 81.58934,-112.97709 h -30.95003 z"
|
||||||
|
id="path5020-3" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 438.4647,297 h 30.94953 l 81.58932,-112.97709 h -30.94953 z"
|
||||||
|
id="path5016-5" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 376.57339,297 h 30.94953 L 489.11225,184.02291 H 458.1622 Z"
|
||||||
|
id="path5012-6" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 314.67639,297 h 30.94953 l 81.58882,-112.97709 h -30.94953 z"
|
||||||
|
id="path5008-2" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 2475.9375 427 L 2550 427 L 2550 324.44531 L 2475.9375 427 z "
|
||||||
|
id="path5063-6-1"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 2242.0176 427 L 2358.9941 427 L 2550 162.51172 L 2550 0.53320312 L 2242.0176 427 z "
|
||||||
|
id="path5059-7-2"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="M 2358.9707 427 L 2475.9453 427 L 2550 324.45703 L 2550 162.48047 L 2358.9707 427 z "
|
||||||
|
id="path5016-5-0"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.10828107;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||||
|
d="m 562.253,297 h 30.94953 l 81.58933,-112.97709 h -30.95005 z"
|
||||||
|
id="path5012-6-9" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 16 KiB |
144
assets/channel_banner_mobild.svg
Normal file
144
assets/channel_banner_mobild.svg
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="1540"
|
||||||
|
height="427"
|
||||||
|
viewBox="0 0 407.45833 112.97708"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="0.92.1 r"
|
||||||
|
sodipodi:docname="channel_banner.svg"
|
||||||
|
inkscape:export-filename="/home/the-scrabi/channel_banner.png"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.5"
|
||||||
|
inkscape:cx="803.85939"
|
||||||
|
inkscape:cy="182.74745"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
units="px"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1012"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(0,-184.02291)">
|
||||||
|
<g
|
||||||
|
id="g5158">
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5071"
|
||||||
|
d="M 1306.2734 427 L 1423.248 427 L 1540 265.33398 L 1540 103.35547 L 1306.2734 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5067"
|
||||||
|
d="M 1072.3535 427 L 1189.3281 427 L 1497.6953 0 L 1380.7227 0 L 1072.3535 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5063"
|
||||||
|
d="M 838.43359 427 L 955.40625 427 L 1263.7754 0 L 1146.8008 0 L 838.43359 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5059"
|
||||||
|
d="M 604.51367 427 L 721.49023 427 L 1029.8574 0 L 912.88086 0 L 604.51367 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5055"
|
||||||
|
d="M 370.59375 427 L 487.56836 427 L 795.93555 0 L 678.96094 0 L 370.59375 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5051"
|
||||||
|
d="M 136.67383 427 L 253.64844 427 L 562.01758 0 L 445.04297 0 L 136.67383 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5047"
|
||||||
|
d="M 0 292.3418 L 0 427 L 19.726562 427 L 328.0957 0 L 211.12109 0 L 0 292.3418 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5045"
|
||||||
|
d="M 94.175781 0 L 0 0 L 0 130.40625 L 94.175781 0 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5028"
|
||||||
|
d="M 1423.2266 427 L 1540 427 L 1540 265.30273 L 1423.2266 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5024"
|
||||||
|
d="M 1189.3066 427 L 1306.2812 427 L 1540 103.36719 L 1540 0 L 1497.6758 0 L 1189.3066 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5020"
|
||||||
|
d="M 955.38672 427 L 1072.3613 427 L 1380.7305 0 L 1263.7539 0 L 955.38672 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5016"
|
||||||
|
d="M 721.4668 427 L 838.44141 427 L 1146.8105 0 L 1029.8359 0 L 721.4668 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5012"
|
||||||
|
d="M 487.54688 427 L 604.52148 427 L 912.89062 0 L 795.91406 0 L 487.54688 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5008"
|
||||||
|
d="M 253.62695 427 L 370.60156 427 L 678.96875 0 L 561.99414 0 L 253.62695 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5004"
|
||||||
|
d="M 19.707031 427 L 136.67969 427 L 445.04883 0 L 328.07422 0 L 19.707031 427 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
<path
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458333,0,184.02291)"
|
||||||
|
id="path5000"
|
||||||
|
d="M 211.13086 0 L 94.15625 0 L 0 130.37695 L 0 292.35352 L 211.13086 0 z "
|
||||||
|
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#999999;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.40925127;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 12 KiB |
Loading…
Reference in New Issue
Block a user