diff --git a/build.gradle b/build.gradle index efcd6c458..6b5a0dcc6 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ subprojects { KPreferences : '0.9.7', Kovenant : '3.3.0', ParcelablePlease : '1.0.2', - Chameleon : '0.9.22', + Chameleon : '0.9.23', UniqR : '0.9.4', SQLiteQB : '0.9.15', Glide : '3.7.0', diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/BadgeView.java b/twidere/src/main/java/org/mariotaku/twidere/view/BadgeView.java deleted file mode 100644 index a50f4f3bf..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/BadgeView.java +++ /dev/null @@ -1,91 +0,0 @@ -package org.mariotaku.twidere.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint.Align; -import android.graphics.Rect; -import android.text.TextPaint; -import android.util.AttributeSet; -import android.view.View; - -import org.mariotaku.twidere.R; - -/** - * Created by mariotaku on 14/11/16. - */ -public class BadgeView extends View { - - private final TextPaint mTextPaint; - private String mText; - private float mTextX, mTextY; - private Rect mTextBounds; - - public BadgeView(Context context) { - this(context, null); - } - - public BadgeView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public BadgeView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BadgeView); - setColor(a.getColor(R.styleable.BadgeView_android_textColor, Color.WHITE)); - setText(a.getString(R.styleable.BadgeView_android_text)); - a.recycle(); - mTextPaint.setTextAlign(Align.CENTER); - mTextBounds = new Rect(); - } - - - public void setColor(int color) { - mTextPaint.setColor(color); - invalidate(); - } - - public void setText(String text) { - mText = text; - updateTextPosition(); - invalidate(); - } - - @Override - protected void onSizeChanged(int w, int h, int oldW, int oldH) { - super.onSizeChanged(w, h, oldW, oldH); - final int hPadding = (int) (Math.round(w * (Math.pow(2, 0.5f) - 1)) / 2); - final int vPadding = (int) (Math.round(h * (Math.pow(2, 0.5f) - 1)) / 2); - setPadding(hPadding, vPadding, hPadding, vPadding); - updateTextPosition(); - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (!mTextBounds.isEmpty()) { - canvas.drawText(mText, mTextX, mTextY, mTextPaint); - } - } - - private void updateTextPosition() { - final int width = getWidth(), height = getHeight(); - if (width == 0 || height == 0) return; - final float contentWidth = width - getPaddingLeft() - getPaddingRight(); - final float contentHeight = height - getPaddingTop() - getPaddingBottom(); - - if (mText != null) { - mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds); - final float scale = Math.min(contentWidth / mTextBounds.width(), contentHeight / mTextBounds.height()); - mTextPaint.setTextSize(Math.min(height / 2, mTextPaint.getTextSize() * scale)); - mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBounds); - mTextX = contentWidth / 2 + getPaddingLeft(); - mTextY = contentHeight / 2 + getPaddingTop() + mTextBounds.height() / 2; - } else { - mTextBounds.setEmpty(); - } - } -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/TabPagerIndicator.java b/twidere/src/main/java/org/mariotaku/twidere/view/TabPagerIndicator.java index abdf8f121..f8b860c95 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/view/TabPagerIndicator.java +++ b/twidere/src/main/java/org/mariotaku/twidere/view/TabPagerIndicator.java @@ -47,7 +47,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C private final TabLayoutManager mLayoutManager; private final ExtendedDividerItemDecoration mItemDecoration; private ViewPager mViewPager; - private PagerAdapter mPagerProvider; + private TabProvider mTabProvider; private OnPageChangeListener mPageChangeListener; private int mOption; @@ -84,6 +84,10 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C mItemDecoration.setDecorationStart(0); mItemDecoration.setDecorationEndOffset(1); a.recycle(); + + if (isInEditMode()) { + mTabProvider = new DemoTabProvider(); + } } public int getCount() { @@ -168,18 +172,18 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C private void dispatchTabClick(int position) { final int currentItem = getCurrentItem(); setCurrentItem(position); - if (mPagerProvider instanceof TabListener) { + if (mTabProvider instanceof TabListener) { if (currentItem != position) { - ((TabListener) mPagerProvider).onPageSelected(position); + ((TabListener) mTabProvider).onPageSelected(position); } else { - ((TabListener) mPagerProvider).onPageReselected(position); + ((TabListener) mTabProvider).onPageReselected(position); } } } private boolean dispatchTabLongClick(int position) { - if (mPagerProvider instanceof TabListener) { - return ((TabListener) mPagerProvider).onTabLongClick(position); + if (mTabProvider instanceof TabListener) { + return ((TabListener) mTabProvider).onTabLongClick(position); } return false; } @@ -210,7 +214,7 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C throw new IllegalArgumentException(); } mViewPager = view; - mPagerProvider = adapter; + mTabProvider = (TabProvider) adapter; view.addOnPageChangeListener(this); mIndicatorAdapter.setTabProvider((TabProvider) adapter); } @@ -580,4 +584,27 @@ public class TabPagerIndicator extends RecyclerView implements PagerIndicator, C mTabProvider = tabProvider; } } + + private static class DemoTabProvider implements TabProvider { + + @Override + public int getCount() { + return 4; + } + + @Override + public Drawable getPageIcon(int position) { + return null; + } + + @Override + public CharSequence getPageTitle(int position) { + return "Title " + position; + } + + @Override + public float getPageWidth(int position) { + return 1; + } + } } diff --git a/twidere/src/main/kotlin/android/support/design/widget/CoordinatorLayoutAccessor.kt b/twidere/src/main/kotlin/android/support/design/widget/CoordinatorLayoutAccessor.kt new file mode 100644 index 000000000..08cb04a43 --- /dev/null +++ b/twidere/src/main/kotlin/android/support/design/widget/CoordinatorLayoutAccessor.kt @@ -0,0 +1,25 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package android.support.design.widget + +import android.support.v4.view.WindowInsetsCompat + +val CoordinatorLayout.lastWindowInsetsCompat: WindowInsetsCompat? + get() = lastWindowInsets \ No newline at end of file diff --git a/twidere/src/main/kotlin/android/support/design/widget/PublicHeaderBehavior.kt b/twidere/src/main/kotlin/android/support/design/widget/PublicHeaderBehavior.kt new file mode 100644 index 000000000..5ce5319aa --- /dev/null +++ b/twidere/src/main/kotlin/android/support/design/widget/PublicHeaderBehavior.kt @@ -0,0 +1,55 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package android.support.design.widget + +import android.content.Context +import android.util.AttributeSet +import android.view.View + +internal open class PublicHeaderBehavior(context: Context, attrs: AttributeSet? = null) : HeaderBehavior(context, attrs) { + + internal override fun getScrollRangeForDragFling(view: V): Int { + return super.getScrollRangeForDragFling(view) + } + + internal override fun getMaxDragOffset(view: V): Int { + return super.getMaxDragOffset(view) + } + + internal override fun setHeaderTopBottomOffset(parent: CoordinatorLayout, header: V, newOffset: Int, minOffset: Int, maxOffset: Int): Int { + return super.setHeaderTopBottomOffset(parent, header, newOffset, minOffset, maxOffset) + } + + internal override fun setHeaderTopBottomOffset(parent: CoordinatorLayout, header: V, newOffset: Int): Int { + return super.setHeaderTopBottomOffset(parent, header, newOffset) + } + + internal override fun getTopBottomOffsetForScrollingSibling(): Int { + return super.getTopBottomOffsetForScrollingSibling() + } + + internal override fun onFlingFinished(parent: CoordinatorLayout?, layout: V) { + super.onFlingFinished(parent, layout) + } + + internal override fun canDragView(view: V): Boolean { + return super.canDragView(view) + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/ktextension/WindowInsetsExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/ktextension/WindowInsetsExtensions.kt index 6b0b64117..686c099ea 100644 --- a/twidere/src/main/kotlin/org/mariotaku/ktextension/WindowInsetsExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/ktextension/WindowInsetsExtensions.kt @@ -26,8 +26,7 @@ import android.support.v4.view.WindowInsetsCompat import android.view.WindowInsets inline val WindowInsetsCompat.systemWindowInsets: Rect - get() = Rect(systemWindowInsetLeft, systemWindowInsetTop, systemWindowInsetRight, - systemWindowInsetBottom) + get() = Rect().also { getSystemWindowInsets(it) } fun WindowInsetsCompat.getSystemWindowInsets(rect: Rect) { rect.set(systemWindowInsetLeft, systemWindowInsetTop, systemWindowInsetRight, diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index bb4650271..36977f7dc 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -861,7 +861,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener val displayDoneIcon = isAccountSelectorVisible if (single != null) { - accountsCount.setText(null) + accountsCount.text = null if (displayDoneIcon) { Glide.clear(accountProfileImage) @@ -878,7 +878,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener accountProfileImage.setBorderColor(single.color) } else { - accountsCount.setText(accounts.size.toString()) + accountsCount.text = accounts.size.toString() Glide.clear(accountProfileImage) if (displayDoneIcon) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/view/CoordinatorLayoutExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/view/CoordinatorLayoutExtensions.kt new file mode 100644 index 000000000..f67d8fe72 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/view/CoordinatorLayoutExtensions.kt @@ -0,0 +1,41 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.extension.view + +import android.support.design.widget.CoordinatorLayout +import android.support.design.widget.lastWindowInsetsCompat +import android.view.View +import android.view.ViewGroup + +fun CoordinatorLayout.measureChildIgnoringInsets(child: View, parentWidthMeasureSpec: Int, + widthUsed: Int, parentHeightMeasureSpec: Int, heightUsed: Int): Boolean { + val lastInsets = lastWindowInsetsCompat ?: return false + + val lp = child.layoutParams as ViewGroup.MarginLayoutParams + + val childWidthMeasureSpec = ViewGroup.getChildMeasureSpec(parentWidthMeasureSpec + + lastInsets.systemWindowInsetLeft + lastInsets.systemWindowInsetRight, + paddingLeft + paddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width) + val childHeightMeasureSpec = ViewGroup.getChildMeasureSpec(parentHeightMeasureSpec + + lastInsets.systemWindowInsetTop + lastInsets.systemWindowInsetBottom, + paddingTop + paddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height) + child.measure(childWidthMeasureSpec, childHeightMeasureSpec) + return true +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserFragment.kt index eebfb9be7..54ab4d3c4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserFragment.kt @@ -56,7 +56,6 @@ import android.support.v4.content.Loader import android.support.v4.content.pm.ShortcutManagerCompat import android.support.v4.content.res.ResourcesCompat import android.support.v4.graphics.ColorUtils -import android.support.v4.view.OnApplyWindowInsetsListener import android.support.v4.view.ViewCompat import android.support.v4.view.ViewPager.OnPageChangeListener import android.support.v4.view.WindowCompat @@ -74,11 +73,11 @@ import android.view.animation.AnimationUtils import android.widget.TextView import android.widget.Toast import com.squareup.otto.Subscribe -import kotlinx.android.synthetic.main.fragment_user.* -import kotlinx.android.synthetic.main.fragment_user.view.* +import kotlinx.android.synthetic.main.fragment_user2.* +import kotlinx.android.synthetic.main.fragment_user2.view.* import kotlinx.android.synthetic.main.header_user.* import kotlinx.android.synthetic.main.header_user.view.* -import kotlinx.android.synthetic.main.layout_content_pages_common.* +import kotlinx.android.synthetic.main.layout_content_fragment_common.* import nl.komponents.kovenant.task import nl.komponents.kovenant.then import nl.komponents.kovenant.ui.alwaysUi @@ -142,22 +141,20 @@ import org.mariotaku.twidere.util.menu.TwidereMenuInfo import org.mariotaku.twidere.util.shortcut.ShortcutCreator import org.mariotaku.twidere.util.support.ActivitySupport import org.mariotaku.twidere.util.support.ActivitySupport.TaskDescriptionCompat -import org.mariotaku.twidere.util.support.ViewSupport import org.mariotaku.twidere.util.support.WindowSupport -import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback import org.mariotaku.twidere.view.TabPagerIndicator import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener import java.lang.ref.WeakReference import java.util.* class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, - OnSizeChangedListener, OnTouchListener, DrawerCallback, SupportFragmentCallback, + OnSizeChangedListener, OnTouchListener, SupportFragmentCallback, SystemWindowInsetsCallback, RefreshScrollTopInterface, OnPageChangeListener, KeyboardShortcutCallback, UserColorChangedListener, UserNicknameChangedListener, IToolBarSupportFragment, AbsContentRecyclerViewFragment.RefreshCompleteListener { override val toolbar: Toolbar - get() = profileContentContainer.toolbar + get() = coordinatorLayout.toolbar private lateinit var profileBirthdayBanner: View private lateinit var actionBarBackground: ActionBarDrawable @@ -221,6 +218,10 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, val userKey = args.getParcelable(EXTRA_USER_KEY) val screenName = args.getString(EXTRA_SCREEN_NAME) if (user == null && (!omitIntentExtra || !args.containsKey(EXTRA_USER))) { + errorContainer.visibility = View.GONE + progressContainer.visibility = View.VISIBLE + errorText.text = null + errorText.visibility = View.GONE } val user = this@UserFragment.user val loadFromCache = user == null || !user.is_cache && user.key.maybeEquals(userKey) @@ -237,6 +238,8 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, val activity = activity ?: return if (data.data != null) { val user = data.data + errorContainer.visibility = View.GONE + progressContainer.visibility = View.GONE val account: AccountDetails = data.extras.getParcelable(EXTRA_ACCOUNT) displayUser(user, account) if (user.is_cache) { @@ -249,11 +252,17 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, } updateOptionsMenuVisibility() } else if (user?.is_cache == true) { + errorContainer.visibility = View.GONE + progressContainer.visibility = View.GONE displayUser(user, account) updateOptionsMenuVisibility() } else { if (data.hasException()) { + errorText.text = data.exception?.getErrorMessage(activity) + errorText.visibility = View.VISIBLE } + errorContainer.visibility = View.VISIBLE + progressContainer.visibility = View.GONE displayUser(null, null) updateOptionsMenuVisibility() } @@ -288,18 +297,15 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, relationship.blocked_by -> { pagesErrorContainer.visibility = View.GONE pagesErrorText.text = null - pagesContent.visibility = View.VISIBLE } !relationship.following && user.hide_protected_contents -> { pagesErrorContainer.visibility = View.VISIBLE pagesErrorText.setText(R.string.user_protected_summary) pagesErrorIcon.setImageResource(R.drawable.ic_info_locked) - pagesContent.visibility = View.GONE } else -> { pagesErrorContainer.visibility = View.GONE pagesErrorText.text = null - pagesContent.visibility = View.VISIBLE } } when { @@ -324,32 +330,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, followContainer.follow.visibility = View.VISIBLE } - override fun canScroll(dy: Float): Boolean { - val fragment = currentVisibleFragment - return fragment is DrawerCallback && fragment.canScroll(dy) - } - - override fun cancelTouch() { - val fragment = currentVisibleFragment - if (fragment is DrawerCallback) { - fragment.cancelTouch() - } - } - - override fun fling(velocity: Float) { - val fragment = currentVisibleFragment - if (fragment is DrawerCallback) { - fragment.fling(velocity) - } - } - - override fun isScrollContent(x: Float, y: Float): Boolean { - val v = viewPager - val location = IntArray(2) - v.getLocationInWindow(location) - return x >= location[0] && x <= location[0] + v.width - && y >= location[1] && y <= location[1] + v.height - } override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { @@ -363,29 +343,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, } - override fun scrollBy(dy: Float) { - val fragment = currentVisibleFragment - if (fragment is DrawerCallback) { - fragment.scrollBy(dy) - } - } - - override fun shouldLayoutHeaderBottom(): Boolean { - val drawer = userProfileDrawer ?: return false - return drawer.headerTop - drawer.paddingTop <= 0 - } - - override fun topChanged(top: Int) { - val drawer = userProfileDrawer ?: return - val offset = drawer.paddingTop - top - updateScrollOffset(offset) - - val fragment = currentVisibleFragment - if (fragment is DrawerCallback) { - fragment.topChanged(top) - } - } - @UiThread fun displayUser(user: ParcelableUser?, account: AccountDetails?) { val activity = activity ?: return @@ -399,15 +356,18 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, return } val adapter = pagerAdapter - for (i in 0 until adapter.count) { - val sf = adapter.instantiateItem(viewPager, i) as? AbsTimelineFragment - sf?.reloadAll() + (0 until adapter.count).forEach { i -> + val sf = adapter.instantiateItem(viewPager, i) as? AbsTimelineFragment ?: return@forEach + if (sf.view == null) return@forEach + sf.reloadAll() } profileImage.visibility = View.VISIBLE val resources = resources val lm = loaderManager lm.destroyLoader(LOADER_ID_USER) lm.destroyLoader(LOADER_ID_FRIENDSHIP) + errorContainer.visibility = View.GONE + progressContainer.visibility = View.GONE this.user = user profileImage.setBorderColor(if (user.color != 0) user.color else Color.WHITE) followContainer.drawEnd(user.account_color) @@ -525,7 +485,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, url.movementMethod = null - updateTitleAlpha() activity.invalidateOptionsMenu() updateSubtitle() } @@ -633,11 +592,12 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_user, container, false) + return inflater.inflate(R.layout.fragment_user2, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) + linkHandlerTitle = null val activity = activity nameFirst = preferences[nameFirstKey] cardBackgroundColor = ThemeUtils.getCardBackgroundColor(activity, @@ -656,35 +616,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, NdefMessage(arrayOf(NdefRecord.createUri(LinkCreator.getUserWebLink(user)))) }) - - userFragmentView.windowInsetsListener = OnApplyWindowInsetsListener listener@ { _, insets -> - insets.getSystemWindowInsets(systemWindowsInsets) - val top = insets.systemWindowInsetTop - profileContentContainer.setPadding(0, top, 0, 0) - profileBannerSpace.statusBarHeight = top - - if (profileBannerSpace.toolbarHeight == 0) { - var toolbarHeight = toolbar.measuredHeight - if (toolbarHeight == 0) { - toolbarHeight = ThemeUtils.getActionBarHeight(context) - } - profileBannerSpace.toolbarHeight = toolbarHeight - } - updateRefreshProgressOffset() - return@listener insets - } - - profileContentContainer.onSizeChangedListener = object : OnSizeChangedListener { - override fun onSizeChanged(view: View, w: Int, h: Int, oldw: Int, oldh: Int) { - val toolbarHeight = toolbar.measuredHeight - userProfileDrawer.setPadding(0, toolbarHeight, 0, 0) - profileBannerSpace.toolbarHeight = toolbarHeight - } - - } - - userProfileDrawer.setDrawerCallback(this) - pagerAdapter = SupportTabsAdapter(activity, childFragmentManager) viewPager.offscreenPageLimit = 3 @@ -704,12 +635,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, profileBanner.onSizeChangedListener = this profileBannerSpace.setOnTouchListener(this) - userProfileSwipeLayout.setOnRefreshListener { - if (!triggerRefresh()) { - userProfileSwipeLayout.isRefreshing = false - } - } - profileNameBackground.setBackgroundColor(cardBackgroundColor) toolbarTabs.setBackgroundColor(cardBackgroundColor) @@ -850,13 +775,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, intent.putExtras(extras) menu.removeGroup(MENU_GROUP_USER_EXTENSION) MenuUtils.addIntentToMenu(activity, menu, intent, MENU_GROUP_USER_EXTENSION) - val drawer = userProfileDrawer - if (drawer != null) { - val offset = drawer.paddingTop - drawer.headerTop - previousActionBarItemIsDark = 0 - previousTabItemIsDark = 0 - updateScrollOffset(offset) - } } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -1132,7 +1050,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, actionBar.subtitle = null } } - updateTitleAlpha() } private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, @@ -1173,7 +1090,9 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, activity.supportRequestWindowFeature(Window.FEATURE_NO_TITLE) activity.supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_MODE_OVERLAY) } - WindowSupport.setStatusBarColor(activity.window, Color.TRANSPARENT) + val window = activity.window + window.requestFeature(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + WindowSupport.setStatusBarColor(window, Color.TRANSPARENT) return true } @@ -1327,19 +1246,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, } override fun onRefreshComplete(fragment: AbsContentRecyclerViewFragment<*, *>) { - userProfileSwipeLayout.isRefreshing = false - } - - private fun updateRefreshProgressOffset() { - val insets = this.systemWindowsInsets - if (insets.top == 0 || userProfileSwipeLayout == null || userProfileSwipeLayout.isRefreshing) { - return - } - val progressCircleDiameter = userProfileSwipeLayout.progressCircleDiameter - if (progressCircleDiameter == 0) return - val progressViewStart = 0 - progressCircleDiameter - val progressViewEnd = profileBannerSpace.toolbarHeight + resources.getDimensionPixelSize(R.dimen.element_spacing_normal) - userProfileSwipeLayout.setProgressViewOffset(false, progressViewStart, progressViewEnd) } private fun getFriendship() { @@ -1398,12 +1304,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, profileBanner.setBackgroundColor(color) toolbarTabs.setBackgroundColor(primaryColor) - - val drawer = userProfileDrawer - if (drawer != null) { - val offset = drawer.paddingTop - drawer.headerTop - updateScrollOffset(offset) - } } private fun setupBaseActionBar() { @@ -1483,7 +1383,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, val statusBarColor = sArgbEvaluator.evaluate(factor, 0xA0000000.toInt(), ChameleonUtils.darkenColor(primaryColorDark)) as Int val window = activity.window - userFragmentView.statusBarColor = statusBarColor WindowSupport.setLightStatusBar(window, ThemeUtils.isLightColor(statusBarColor)) val stackedTabColor = primaryColor @@ -1501,10 +1400,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, this.outlineAlphaFactor = tabOutlineAlphaFactor } - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - windowOverlay.alpha = factor * tabOutlineAlphaFactor - } - val currentTabColor = sArgbEvaluator.evaluate(tabOutlineAlphaFactor, stackedTabColor, cardBackgroundColor) as Int @@ -1533,8 +1428,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, ThemeUtils.applyToolbarItemColor(activity, toolbar, currentActionBarColor) } previousActionBarItemIsDark = if (actionItemIsDark) 1 else -1 - - updateTitleAlpha() } override var controlBarOffset: Float @@ -1545,21 +1438,6 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener, get() = 0 - private fun updateTitleAlpha() { - val location = IntArray(2) - nameContainer.name.getLocationInWindow(location) - val nameShowingRatio = (userProfileDrawer.paddingTop - location[1]) / nameContainer.name.height.toFloat() - val textAlpha = nameShowingRatio.coerceIn(0f, 1f) - val titleView = ViewSupport.findViewByText(toolbar, toolbar.title) - if (titleView != null) { - titleView.alpha = textAlpha - } - val subtitleView = ViewSupport.findViewByText(toolbar, toolbar.subtitle) - if (subtitleView != null) { - subtitleView.alpha = textAlpha - } - } - private fun ParcelableRelationship.check(user: ParcelableUser): Boolean { if (account_key != user.account_key) { return false diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/BadgeView.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/BadgeView.kt new file mode 100644 index 000000000..a27a7c746 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/BadgeView.kt @@ -0,0 +1,98 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint.Align +import android.graphics.Rect +import android.support.v4.graphics.ColorUtils +import android.text.TextPaint +import android.util.AttributeSet +import android.view.View +import org.mariotaku.twidere.R + +class BadgeView(context: Context, attrs: AttributeSet? = null) : View(context, attrs) { + + var text: String? = null + set(value) { + field = value + updateTextPosition() + invalidate() + } + var color: Int + get() = ColorUtils.setAlphaComponent(textPaint.color, textPaint.alpha) + set(value) { + textPaint.color = ColorUtils.setAlphaComponent(value, 0xFF) + textPaint.alpha = Color.alpha(value) + invalidate() + } + + private val textPaint = TextPaint(TextPaint.ANTI_ALIAS_FLAG) + private var textX: Float = 0.toFloat() + private var textY: Float = 0.toFloat() + private val textBounds: Rect + + init { + val a = context.obtainStyledAttributes(attrs, R.styleable.BadgeView) + color = a.getColor(R.styleable.BadgeView_android_textColor, Color.WHITE) + text = a.getString(R.styleable.BadgeView_android_text) + a.recycle() + textPaint.textAlign = Align.CENTER + textBounds = Rect() + } + + override fun onSizeChanged(w: Int, h: Int, oldW: Int, oldH: Int) { + super.onSizeChanged(w, h, oldW, oldH) + val hPadding = (Math.round(w * (Math.pow(2.0, 0.5) - 1)) / 2).toInt() + val vPadding = (Math.round(h * (Math.pow(2.0, 0.5) - 1)) / 2).toInt() + setPadding(hPadding, vPadding, hPadding, vPadding) + updateTextPosition() + invalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + if (!textBounds.isEmpty) { + canvas.drawText(text, textX, textY, textPaint) + } + } + + private fun updateTextPosition() { + val width = width + val height = height + if (width == 0 || height == 0) return + val contentWidth = (width - paddingLeft - paddingRight).toFloat() + val contentHeight = (height - paddingTop - paddingBottom).toFloat() + + val text = this.text + if (text != null) { + textPaint.getTextBounds(text, 0, text.length, textBounds) + val scale = Math.min(contentWidth / textBounds.width(), contentHeight / textBounds.height()) + textPaint.textSize = Math.min((height / 2).toFloat(), textPaint.textSize * scale) + textPaint.getTextBounds(text, 0, text.length, textBounds) + textX = contentWidth / 2 + paddingLeft + textY = contentHeight / 2 + paddingTop.toFloat() + (textBounds.height() / 2).toFloat() + } else { + textBounds.setEmpty() + } + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/BannerBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/BannerBehavior.kt new file mode 100644 index 000000000..8be54e978 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/BannerBehavior.kt @@ -0,0 +1,32 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view.behavior.userprofile + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.util.AttributeSet +import android.view.View + +internal class BannerBehavior(context: Context, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior(context, attrs) { + override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean { + child.layout(0, 0, child.measuredWidth, child.measuredHeight) + return true + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/DetailsBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/DetailsBehavior.kt new file mode 100644 index 000000000..a7207fe53 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/DetailsBehavior.kt @@ -0,0 +1,72 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view.behavior.userprofile + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.support.design.widget.PublicHeaderBehavior +import android.support.v4.view.WindowInsetsCompat +import android.util.AttributeSet +import android.view.View +import org.mariotaku.twidere.R +import org.mariotaku.twidere.extension.view.measureChildIgnoringInsets + +internal class DetailsBehavior(context: Context, attrs: AttributeSet? = null) : PublicHeaderBehavior(context, attrs) { + + override fun onMeasureChild(parent: CoordinatorLayout, child: View, + parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, + heightUsed: Int): Boolean { + return parent.measureChildIgnoringInsets(child, parentWidthMeasureSpec, widthUsed, + parentHeightMeasureSpec, heightUsed) + } + + override fun onLayoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int): Boolean { + return super.onLayoutChild(parent, child, layoutDirection) + } + + override fun onApplyWindowInsets(coordinatorLayout: CoordinatorLayout, child: View, insets: WindowInsetsCompat): WindowInsetsCompat { + return super.onApplyWindowInsets(coordinatorLayout, child, insets) + } + + override fun layoutChild(parent: CoordinatorLayout, child: View, layoutDirection: Int) { + child.layout(0, 0, child.measuredWidth, child.measuredHeight) + } + + override fun getScrollRangeForDragFling(view: View): Int { + val parent = view.parent as CoordinatorLayout + val toolbar = parent.findViewById(R.id.toolbar) + return super.getScrollRangeForDragFling(view) - toolbar.bottom + } + + override fun getMaxDragOffset(view: View): Int { + val parent = view.parent as CoordinatorLayout + val toolbar = parent.findViewById(R.id.toolbar) + return super.getMaxDragOffset(view) + toolbar.bottom + } + + override fun canDragView(view: View): Boolean { + return true + } + + override fun getTopBottomOffsetForScrollingSibling(): Int { + return super.getTopBottomOffsetForScrollingSibling() + } + +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/PagerBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/PagerBehavior.kt new file mode 100644 index 000000000..234bf47d4 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/PagerBehavior.kt @@ -0,0 +1,37 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view.behavior.userprofile + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.support.v4.view.ViewPager +import android.util.AttributeSet +import org.mariotaku.twidere.extension.view.measureChildIgnoringInsets + +internal class PagerBehavior(context: Context?, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior(context, attrs) { + + override fun onMeasureChild(parent: CoordinatorLayout, child: ViewPager, + parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, + heightUsed: Int): Boolean { + return parent.measureChildIgnoringInsets(child, parentWidthMeasureSpec, widthUsed, + parentHeightMeasureSpec, heightUsed) + } + +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/TabBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/TabBehavior.kt new file mode 100644 index 000000000..116583fed --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/TabBehavior.kt @@ -0,0 +1,46 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view.behavior.userprofile + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.support.design.widget.PublicHeaderBehavior +import android.util.AttributeSet +import android.view.View +import org.mariotaku.twidere.R +import org.mariotaku.twidere.view.TabPagerIndicator + +internal class TabBehavior(context: Context, attrs: AttributeSet? = null) : PublicHeaderBehavior(context, attrs) { + + override fun layoutDependsOn(parent: CoordinatorLayout, child: TabPagerIndicator, dependency: View): Boolean { + return dependency.id == R.id.profileHeader + } + + override fun onLayoutChild(parent: CoordinatorLayout, child: TabPagerIndicator, layoutDirection: Int): Boolean { + val profileHeader = parent.getDependencies(child).first() + child.layout(0, profileHeader.bottom, child.measuredWidth, profileHeader.bottom + child.measuredHeight) + return true + } + + override fun onDependentViewChanged(parent: CoordinatorLayout, child: TabPagerIndicator, dependency: View): Boolean { + child.requestLayout() + return true + } +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/ToolbarBehavior.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/ToolbarBehavior.kt new file mode 100644 index 000000000..033a4e16e --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/behavior/userprofile/ToolbarBehavior.kt @@ -0,0 +1,29 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package org.mariotaku.twidere.view.behavior.userprofile + +import android.content.Context +import android.support.design.widget.CoordinatorLayout +import android.support.v7.widget.Toolbar +import android.util.AttributeSet + +internal class ToolbarBehavior(context: Context?, attrs: AttributeSet? = null) : CoordinatorLayout.Behavior(context, attrs) { + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt index 4bbf31b58..5a1b9db9a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt @@ -144,7 +144,7 @@ class ActivityTitleSummaryViewHolder( if (users.size > profileImageViews.size) { val moreNumber = users.size - profileImageViews.size profileImageMoreNumber.visibility = View.VISIBLE - profileImageMoreNumber.setText(moreNumber.toString()) + profileImageMoreNumber.text = moreNumber.toString() } else { profileImageMoreNumber.visibility = View.GONE } diff --git a/twidere/src/main/res/layout/fragment_toolbar_tab_pages.xml b/twidere/src/main/res/layout/fragment_toolbar_tab_pages.xml index 8b92c0901..c2c0b05aa 100644 --- a/twidere/src/main/res/layout/fragment_toolbar_tab_pages.xml +++ b/twidere/src/main/res/layout/fragment_toolbar_tab_pages.xml @@ -42,7 +42,10 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?actionBarSize" - app:popupTheme="?actionBarPopupTheme"/> + app:popupTheme="?actionBarPopupTheme" + tools:backgroundTint="@color/branding_color" + tools:navigationIcon="@drawable/ic_action_back" + tools:title="Twidere"/> + + + + + + android:layout_height="match_parent" + android:fitsSystemWindows="true" + app:statusBarBackground="@android:color/transparent" + tools:theme="@style/Theme.Twidere.NoActionBar"> + + + android:layout_gravity="top" + app:layout_behavior="org.mariotaku.twidere.view.behavior.userprofile.BannerBehavior"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/twidere/src/main/res/layout/layout_content_fragment_common.xml b/twidere/src/main/res/layout/layout_content_fragment_common.xml index 5180c1d85..72ccba4e3 100644 --- a/twidere/src/main/res/layout/layout_content_fragment_common.xml +++ b/twidere/src/main/res/layout/layout_content_fragment_common.xml @@ -43,7 +43,8 @@ android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" - android:visibility="gone"> + android:visibility="gone" + tools:visibility="gone"> + android:textAppearance="?android:textAppearanceMedium" + tools:text="Error message"/> \ No newline at end of file diff --git a/twidere/src/main/res/values-v21/themes.xml b/twidere/src/main/res/values-v21/themes.xml index 7b13ca2cd..e1109931a 100644 --- a/twidere/src/main/res/values-v21/themes.xml +++ b/twidere/src/main/res/values-v21/themes.xml @@ -27,4 +27,9 @@ @style/Theme.Twidere.Dark.Launcher @style/Theme.Twidere.Light.Launcher + + \ No newline at end of file diff --git a/twidere/src/main/res/values/themes.xml b/twidere/src/main/res/values/themes.xml index 5bbbbe360..4721001ef 100644 --- a/twidere/src/main/res/values/themes.xml +++ b/twidere/src/main/res/values/themes.xml @@ -20,6 +20,7 @@ @style/Theme.Twidere.Dark.NoActionBar @style/Theme.Twidere.Light.NoActionBar + > +