reduced memory usage

This commit is contained in:
Mariotaku Lee 2017-02-19 22:29:08 +08:00
parent 1cac394c27
commit 2507d91949
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
15 changed files with 338 additions and 51 deletions

View File

@ -16,13 +16,11 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest
package="org.mariotaku.twidere"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
-->
<manifest package="org.mariotaku.twidere"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:installLocation="internalOnly">
<uses-sdk tools:overrideLibrary="android.support.customtabs,net.ypresto.androidtranscoder"/>
@ -75,7 +73,6 @@
<!-- Used for account sync -->
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="org.mariotaku.twidere.permission.SHORTEN_STATUS"/>
<uses-permission android:name="org.mariotaku.twidere.permission.UPLOAD_MEDIA"/>
<uses-permission android:name="org.mariotaku.twidere.permission.SYNC_TIMELINE"/>
@ -165,10 +162,10 @@
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts"/>
</activity>
<activity
android:name=".activity.MainHondaJOJOActivity"
@ -185,10 +182,10 @@
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts"/>
</activity>
<activity
android:name=".activity.HomeActivity"
@ -527,7 +524,6 @@
android:label="@string/title_premium_features_name"
android:parentActivityName=".activity.HomeActivity"
android:theme="@style/Theme.Twidere">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.HomeActivity"/>
@ -557,6 +553,7 @@
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator"/>
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/account_authenticator"/>
@ -569,11 +566,11 @@
<intent-filter>
<action android:name="android.content.SyncAdapter"/>
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter"/>
</service>
<service
android:name=".nyan.NyanWallpaperService"
android:enabled="false"

View File

@ -1,6 +1,7 @@
package org.mariotaku.twidere.extension.model
import android.content.Context
import android.widget.ImageView
import org.mariotaku.twidere.R
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableMessage
@ -9,6 +10,7 @@ import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationTyp
import org.mariotaku.twidere.model.ParcelableMessageConversation.ExtrasType
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.message.conversation.TwitterOfficialConversationExtras
import org.mariotaku.twidere.util.MediaLoaderWrapper
import org.mariotaku.twidere.util.UserColorNameManager
fun ParcelableMessageConversation.applyFrom(message: ParcelableMessage, details: AccountDetails) {
@ -49,6 +51,19 @@ fun ParcelableMessageConversation.getSummaryText(context: Context, manager: User
text_unescaped, this)
}
fun ParcelableMessageConversation.displayAvatarTo(mediaLoader: MediaLoaderWrapper, view: ImageView) {
if (conversation_type == ConversationType.ONE_TO_ONE) {
val user = this.user
if (user != null) {
mediaLoader.displayProfileImage(view, user)
} else {
mediaLoader.displayProfileImage(view, null)
}
} else {
mediaLoader.displayGroupConversationAvatar(view, conversation_avatar)
}
}
val ParcelableMessageConversation.user: ParcelableUser?
get() {
val userKey = if (is_outgoing) recipient_key else sender_key

View File

@ -88,6 +88,7 @@ import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
import org.mariotaku.microblog.library.twitter.model.Paging
import org.mariotaku.microblog.library.twitter.model.UserList
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.AccountSelectorActivity
@ -148,7 +149,9 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
override val toolbar: Toolbar
get() = profileContentContainer.toolbar
private var actionBarBackground: ActionBarDrawable? = null
private lateinit var profileBirthdayBanner: View
private lateinit var actionBarBackground: ActionBarDrawable
private lateinit var pagerAdapter: SupportTabsAdapter
// Data fields
@ -527,9 +530,16 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val currentMonth = cal.get(Calendar.MONTH)
val currentDay = cal.get(Calendar.DAY_OF_MONTH)
cal.timeInMillis = user.created_at
if (cal.get(Calendar.MONTH) == currentMonth && cal.get(Calendar.DAY_OF_MONTH) == currentDay && !hideBirthdayView) {
profileBirthdayBanner.visibility = View.VISIBLE
} else {
val twitterversary = cal.get(Calendar.MONTH) == currentMonth && cal.get(Calendar.DAY_OF_MONTH) == currentDay
if ((BuildConfig.DEBUG || twitterversary) && !hideBirthdayView) {
if (profileBirthdayStub != null) {
profileBirthdayBanner = profileBirthdayStub.inflate()
profileBirthdayBanner.setOnClickListener(this)
} else {
profileBirthdayBanner.visibility = View.VISIBLE
}
} else if (profileBirthdayStub == null) {
profileBirthdayBanner.visibility = View.GONE
}
updateTitleAlpha()
@ -700,7 +710,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
followersContainer.setOnClickListener(this)
friendsContainer.setOnClickListener(this)
errorIcon.setOnClickListener(this)
profileBirthdayBanner.setOnClickListener(this)
profileBanner.setOnSizeChangedListener(this)
profileBannerSpace.setOnTouchListener(this)
@ -712,6 +721,8 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val actionBarElevation = ThemeUtils.getSupportActionBarElevation(activity)
ViewCompat.setElevation(toolbarTabs, actionBarElevation)
actionBarBackground = ActionBarDrawable(ResourcesCompat.getDrawable(activity.resources,
R.drawable.shadow_user_banner_action_bar, null)!!)
setupBaseActionBar()
setupViewStyle()
setupUserPages()
@ -1254,7 +1265,7 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
if (profileBirthdayBanner.visibility == View.VISIBLE) {
if (profileBirthdayStub == null && profileBirthdayBanner.visibility == View.VISIBLE) {
return profileBirthdayBanner.dispatchTouchEvent(event)
}
return profileBanner.dispatchTouchEvent(event)
@ -1342,8 +1353,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
private fun setupBaseActionBar() {
val activity = activity as? LinkHandlerActivity ?: return
val actionBar = activity.supportActionBar ?: return
val shadow = ResourcesCompat.getDrawable(activity.resources, R.drawable.shadow_user_banner_action_bar, null)!!
actionBarBackground = ActionBarDrawable(shadow)
if (!ThemeUtils.isWindowFloating(activity) && ThemeUtils.isTransparentBackground(activity.currentThemeBackgroundOption)) {
// mActionBarBackground.setAlpha(ThemeUtils.getActionBarAlpha(linkHandler.getCurrentThemeBackgroundAlpha()));
profileBanner.alpha = activity.currentThemeBackgroundAlpha / 255f
@ -1397,7 +1406,9 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val factor = (if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat()).coerceIn(0f, 1f)
profileBannerContainer.translationY = (-offset).toFloat()
profileBanner.translationY = (offset / 2).toFloat()
profileBirthdayBanner.translationY = (offset / 2).toFloat()
if (profileBirthdayStub == null) {
profileBirthdayBanner.translationY = (offset / 2).toFloat()
}
val activity = activity as BaseActivity
@ -1487,8 +1498,8 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
private class ActionBarDrawable(shadow: Drawable) : LayerDrawable(arrayOf(shadow, ActionBarColorDrawable.create(true))) {
private val shadowDrawable: Drawable
private val colorDrawable: ColorDrawable
private val shadowDrawable = getDrawable(0)
private val colorDrawable = getDrawable(1) as ColorDrawable
private var alphaValue: Int = 0
var factor: Float = 0f
@ -1511,8 +1522,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
}
init {
shadowDrawable = getDrawable(0)
colorDrawable = getDrawable(1) as ColorDrawable
alpha = 0xFF
updateValue()
}

View File

@ -19,10 +19,34 @@
package org.mariotaku.twidere.fragment.message
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import android.support.v7.widget.Toolbar
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.activity_home_content.view.*
import kotlinx.android.synthetic.main.fragment_messages_conversation_info.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.fragment.BaseFragment
import org.mariotaku.twidere.fragment.iface.IToolBarSupportFragment
/**
* Created by mariotaku on 2017/2/15.
*/
class MessageConversationInfoFragment : BaseFragment()
class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment {
override val controlBarHeight: Int get() = toolbar.measuredHeight
override var controlBarOffset: Float = 0f
override val toolbar: Toolbar
get() = toolbarLayout.toolbar
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_messages_conversation_info, container, false)
}
override fun setupWindow(activity: FragmentActivity): Boolean {
return false
}
}

View File

@ -28,6 +28,7 @@ import android.os.Bundle
import android.support.v4.app.FragmentActivity
import android.support.v4.app.LoaderManager
import android.support.v4.content.Loader
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.FixedLinearLayoutManager
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
@ -38,7 +39,10 @@ import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.activity_premium_dashboard.*
import kotlinx.android.synthetic.main.fragment_messages_conversation.*
import kotlinx.android.synthetic.main.fragment_messages_conversation.view.*
import kotlinx.android.synthetic.main.layout_toolbar_message_conversation_title.*
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.empty
import org.mariotaku.ktextension.set
@ -56,10 +60,8 @@ import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_CONVERSATION_ID
import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.extension.model.getConversationName
import org.mariotaku.twidere.extension.model.getSummaryText
import org.mariotaku.twidere.extension.model.isOfficial
import org.mariotaku.twidere.extension.model.readOnly
import org.mariotaku.twidere.constant.profileImageStyleKey
import org.mariotaku.twidere.extension.model.*
import org.mariotaku.twidere.fragment.AbsContentListRecyclerViewFragment
import org.mariotaku.twidere.fragment.EditAltTextDialogFragment
import org.mariotaku.twidere.fragment.iface.IToolBarSupportFragment
@ -162,6 +164,15 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
openMediaPicker()
}
val activity = this.activity
if (activity is AppCompatActivity) {
activity.supportActionBar?.setDisplayShowTitleEnabled(false)
}
val theme = Chameleon.getOverrideTheme(context, activity)
conversationName.setTextColor(ChameleonUtils.getColorDependent(theme.colorToolbar))
conversationAvatar.style = preferences[profileImageStyleKey]
// No refresh for this fragment
refreshEnabled = false
adapter.loadMoreSupportedPosition = ILoadMoreSupportAdapter.NONE
@ -429,12 +440,16 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
private fun updateConversationStatus() {
val conversation = adapter.conversation ?: return
activity.title = conversation.getConversationName(context, userColorNameManager,
val name = conversation.getConversationName(context, userColorNameManager,
preferences[nameFirstKey]).first
activity.title = name
val readOnly = conversation.readOnly
addMedia.isEnabled = !readOnly
sendMessage.isEnabled = !readOnly
editText.isEnabled = !readOnly
conversationName.text = name
conversation.displayAvatarTo(mediaLoader, conversationAvatar)
}
internal class AddMediaTask(

View File

@ -24,10 +24,10 @@ import android.view.View
import kotlinx.android.synthetic.main.list_item_message_entry.view.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.MessagesEntriesAdapter
import org.mariotaku.twidere.extension.model.displayAvatarTo
import org.mariotaku.twidere.extension.model.getConversationName
import org.mariotaku.twidere.extension.model.getSummaryText
import org.mariotaku.twidere.extension.model.timestamp
import org.mariotaku.twidere.extension.model.user
import org.mariotaku.twidere.model.ParcelableMessageConversation
import org.mariotaku.twidere.model.ParcelableMessageConversation.ConversationType
@ -71,18 +71,11 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
stateIndicator.visibility = View.GONE
}
if (conversation.conversation_type == ConversationType.ONE_TO_ONE) {
val user = conversation.user
if (user != null) {
adapter.mediaLoader.displayProfileImage(profileImage, user)
} else {
adapter.mediaLoader.displayProfileImage(profileImage, null)
// TODO display default profile image
}
typeIndicator.visibility = View.GONE
} else {
adapter.mediaLoader.displayGroupConversationAvatar(profileImage, conversation.conversation_avatar)
typeIndicator.visibility = View.VISIBLE
}
conversation.displayAvatarTo(adapter.mediaLoader, profileImage)
if (conversation.unread_count > 0) {
unreadCount.visibility = View.VISIBLE
unreadCount.text = conversation.unread_count.toString()

View File

@ -166,8 +166,12 @@
android:layout_alignParentTop="true"
android:background="?colorToolbar"
android:elevation="@dimen/toolbar_elevation"
app:contentInsetStart="0dp"
app:popupTheme="?actionBarPopupTheme"
tools:elevation="0dp"/>
tools:elevation="0dp">
<include layout="@layout/layout_toolbar_message_conversation_title"/>
</android.support.v7.widget.Toolbar>
<View
android:id="@+id/windowOverlay"

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/toolbarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="@string/large_text"/>
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/element_spacing_large"
android:src="@drawable/ic_action_edit"
app:layout_anchor="@+id/appBar"
app:layout_anchorGravity="bottom|end"
tools:backgroundTint="?colorAccent"/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -41,18 +41,13 @@
app:bannerAspectRatio="@fraction/aspect_ratio_profile_banner"
tools:src="@drawable/nyan_stars_background"/>
<FrameLayout
android:id="@+id/profileBirthdayBanner"
<ViewStub
android:id="@+id/profileBirthdayStub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/profileBanner"
android:layout_alignTop="@+id/profileBanner"
android:visibility="gone">
<org.mariotaku.twidere.view.BirthdayView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
android:layout="@layout/layout_user_profile_birthday_stub"/>
</RelativeLayout>
<org.mariotaku.twidere.view.ExtendedRelativeLayout

View File

@ -80,7 +80,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"/>
android:visibility="gone"
tools:indeterminateDrawable="@android:color/transparent"/>
</FrameLayout>

View File

@ -32,7 +32,9 @@
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_gravity="center"
android:padding="@dimen/element_spacing_xsmall"/>
android:padding="@dimen/element_spacing_xsmall"
tools:indeterminateDrawable="@android:color/transparent"
tools:progressDrawable="@android:color/transparent"/>
</FrameLayout>
<LinearLayout

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout
android:id="@+id/conversationTitleContainer"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:orientation="horizontal"
tools:layout_height="?actionBarSize">
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/conversationAvatar"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_margin="@dimen/element_spacing_normal"
android:layout_weight="0"
tools:src="@drawable/ic_profile_image_default_group"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:layout_weight="1"
android:gravity="center_vertical">
<org.mariotaku.twidere.view.FixedTextView
android:id="@+id/conversationName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="?android:textColorPrimary"
tools:text="Conversation name"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Twidere - Twitter client for Android
~
~ Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<FrameLayout
android:id="@+id/profileBirthdayBanner"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.mariotaku.twidere.view.BirthdayView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>

View File

@ -110,4 +110,5 @@
<dimen name="toolbar_elevation">8dp</dimen>
<dimen name="unread_indicator_size">16dp</dimen>
<dimen name="text_margin">16dp</dimen>
</resources>

View File

@ -1220,4 +1220,94 @@
<string name="users_statuses">User\'s tweets</string>
<string name="vibration">Vibration</string>
<string name="title_activity_scrolling">ScrollingActivity</string>
<string name="large_text">
"Material is the metaphor.\n\n"
"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 "
"technologically advanced and open to imagination and magic.\n"
"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 "
"flexibility of the material creates new affordances that supercede those in the physical "
"world, without breaking the rules of physics.\n"
"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 "
"seams, divides space, and indicates moving parts.\n\n"
"Bold, graphic, intentional.\n\n"
"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 "
"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 "
"interface that immerse the user in the experience.\n"
"An emphasis on user actions makes core functionality immediately apparent and provides "
"waypoints for the user.\n\n"
"Motion provides meaning.\n\n"
"Motion respects and reinforces the user as the prime mover. Primary user actions are "
"inflection points that initiate motion, transforming the whole design.\n"
"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.\n"
"Motion is meaningful and appropriate, serving to focus attention and maintain continuity. "
"Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n"
"3D world.\n\n"
"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 "
"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.\n"
"On the web, the z-axis is used for layering and not for perspective. The 3D world is "
"emulated by manipulating the y-axis.\n\n"
"Light and shadow.\n\n"
"Within the material environment, virtual lights illuminate the scene. Key lights create "
"directional shadows, while ambient light creates soft shadows from all angles.\n"
"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 "
"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.\n\n"
"Resting elevation.\n\n"
"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 "
"elevation as soon as possible.\n\n"
"Component elevations.\n\n"
"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).\n"
"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).\n\n"
"Responsive elevation and dynamic elevation offsets.\n\n"
"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 "
"changes are consistently implemented using dynamic elevation offsets.\n"
"Dynamic elevation offsets are the goal elevation that a component moves towards, relative "
"to the components resting state. They ensure that elevation changes are consistent "
"across actions and component types. For example, all components that lift on press have "
"the same elevation change relative to their resting elevation.\n"
"Once the input event is completed or cancelled, the component will return to its resting "
"elevation.\n\n"
"Avoiding elevation interference.\n\n"
"Components with responsive elevations may encounter other components as they move between "
"their resting elevations and dynamic elevation offsets. Because material cannot pass "
"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.\n"
"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 "
"user picks up a card, or it can move if a snackbar appears.\n"
"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 wont interfere "
"when a user tries to pick up one of cards.\n\n"
</string>
</resources>