mirror of
https://github.com/MatomoCamp/matomocamp-companion-android.git
synced 2024-09-19 16:13:46 +02:00
Replace custom widgets with Material components for SnackBar, NavigationView, FAB and TabLayout
This commit is contained in:
parent
a7a62ebd15
commit
961a6b0c8e
26 changed files with 258 additions and 1311 deletions
|
@ -26,6 +26,7 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation ('androidx.preference:preference:1.1.0-alpha01') {
|
||||
|
|
|
@ -11,42 +11,36 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.browser.customtabs.CustomTabsIntent;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.core.widget.TextViewCompat;
|
||||
import androidx.core.view.OnApplyWindowInsetsListener;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
@ -64,7 +58,6 @@ import be.digitalia.fosdem.fragments.LiveFragment;
|
|||
import be.digitalia.fosdem.fragments.MapFragment;
|
||||
import be.digitalia.fosdem.fragments.PersonsListFragment;
|
||||
import be.digitalia.fosdem.fragments.TracksFragment;
|
||||
import be.digitalia.fosdem.widgets.AdapterLinearLayout;
|
||||
|
||||
/**
|
||||
* Main entry point of the application. Allows to switch between section fragments and update the database.
|
||||
|
@ -77,41 +70,33 @@ public class MainActivity extends AppCompatActivity {
|
|||
public static final String ACTION_SHORTCUT_LIVE = BuildConfig.APPLICATION_ID + ".intent.action.SHORTCUT_LIVE";
|
||||
|
||||
private enum Section {
|
||||
TRACKS(TracksFragment.class, R.string.menu_tracks, R.drawable.ic_event_grey600_24dp, true, true),
|
||||
BOOKMARKS(BookmarksListFragment.class, R.string.menu_bookmarks, R.drawable.ic_bookmark_grey600_24dp, false, false),
|
||||
LIVE(LiveFragment.class, R.string.menu_live, R.drawable.ic_play_circle_outline_grey600_24dp, true, false),
|
||||
SPEAKERS(PersonsListFragment.class, R.string.menu_speakers, R.drawable.ic_people_grey600_24dp, false, false),
|
||||
MAP(MapFragment.class, R.string.menu_map, R.drawable.ic_map_grey600_24dp, false, false);
|
||||
TRACKS(R.id.menu_tracks, TracksFragment.class, true, true),
|
||||
BOOKMARKS(R.id.menu_bookmarks, BookmarksListFragment.class, false, false),
|
||||
LIVE(R.id.menu_live, LiveFragment.class, true, false),
|
||||
SPEAKERS(R.id.menu_speakers, PersonsListFragment.class, false, false),
|
||||
MAP(R.id.menu_map, MapFragment.class, false, false);
|
||||
|
||||
private final int menuItemId;
|
||||
private final String fragmentClassName;
|
||||
private final int titleResId;
|
||||
private final int iconResId;
|
||||
private final boolean extendsAppBar;
|
||||
private final boolean keep;
|
||||
|
||||
Section(Class<? extends Fragment> fragmentClass, int titleResId, int iconResId,
|
||||
boolean extendsAppBar, boolean keep) {
|
||||
Section(@IdRes int menuItemId, Class<? extends Fragment> fragmentClass, boolean extendsAppBar, boolean keep) {
|
||||
this.menuItemId = menuItemId;
|
||||
this.fragmentClassName = fragmentClass.getName();
|
||||
this.titleResId = titleResId;
|
||||
this.iconResId = iconResId;
|
||||
this.extendsAppBar = extendsAppBar;
|
||||
this.keep = keep;
|
||||
}
|
||||
|
||||
@IdRes
|
||||
public int getMenuItemId() {
|
||||
return menuItemId;
|
||||
}
|
||||
|
||||
public String getFragmentClassName() {
|
||||
return fragmentClassName;
|
||||
}
|
||||
|
||||
@StringRes
|
||||
public int getTitleResId() {
|
||||
return titleResId;
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
public int getIconResId() {
|
||||
return iconResId;
|
||||
}
|
||||
|
||||
public boolean extendsAppBar() {
|
||||
return extendsAppBar;
|
||||
}
|
||||
|
@ -119,12 +104,21 @@ public class MainActivity extends AppCompatActivity {
|
|||
public boolean shouldKeep() {
|
||||
return keep;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Section fromMenuItemId(@IdRes int menuItemId) {
|
||||
for (Section section : Section.values()) {
|
||||
if (section.menuItemId == menuItemId) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final long DATABASE_VALIDITY_DURATION = DateUtils.DAY_IN_MILLIS;
|
||||
private static final long DOWNLOAD_REMINDER_SNOOZE_DURATION = DateUtils.DAY_IN_MILLIS;
|
||||
private static final String PREF_LAST_DOWNLOAD_REMINDER_TIME = "last_download_reminder_time";
|
||||
private static final String STATE_CURRENT_SECTION = "current_section";
|
||||
|
||||
private static final String LAST_UPDATE_DATE_FORMAT = "d MMM yyyy kk:mm:ss";
|
||||
|
||||
|
@ -133,13 +127,12 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
// Main menu
|
||||
Section currentSection;
|
||||
int pendingMenuSection = -1;
|
||||
int pendingMenuFooter = -1;
|
||||
MenuItem pendingNavigationMenuItem = null;
|
||||
DrawerLayout drawerLayout;
|
||||
private ActionBarDrawerToggle drawerToggle;
|
||||
View mainMenu;
|
||||
private NavigationView navigationView;
|
||||
private TextView lastUpdateTextView;
|
||||
private MainMenuAdapter menuAdapter;
|
||||
|
||||
private MenuItem searchMenuItem;
|
||||
|
||||
|
@ -162,7 +155,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
default:
|
||||
message = getResources().getQuantityString(R.plurals.events_download_completed, result, result);
|
||||
}
|
||||
Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(findViewById(R.id.content), message, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -251,8 +244,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
public void onDrawerStateChanged(int newState) {
|
||||
super.onDrawerStateChanged(newState);
|
||||
if (newState == DrawerLayout.STATE_DRAGGING) {
|
||||
pendingMenuSection = -1;
|
||||
pendingMenuFooter = -1;
|
||||
pendingNavigationMenuItem = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,13 +258,9 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
public void onDrawerClosed(View drawerView) {
|
||||
super.onDrawerClosed(drawerView);
|
||||
if (pendingMenuSection != -1) {
|
||||
selectMenuSection(pendingMenuSection);
|
||||
pendingMenuSection = -1;
|
||||
}
|
||||
if (pendingMenuFooter != -1) {
|
||||
selectMenuFooter(pendingMenuFooter);
|
||||
pendingMenuFooter = -1;
|
||||
if (pendingNavigationMenuItem != null) {
|
||||
handleNavigationMenuItem(pendingNavigationMenuItem);
|
||||
pendingNavigationMenuItem = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -284,11 +272,22 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
// Setup Main menu
|
||||
mainMenu = findViewById(R.id.main_menu);
|
||||
final AdapterLinearLayout sectionsList = findViewById(R.id.sections);
|
||||
menuAdapter = new MainMenuAdapter(getLayoutInflater());
|
||||
sectionsList.setAdapter(menuAdapter);
|
||||
mainMenu.findViewById(R.id.settings).setOnClickListener(menuFooterClickListener);
|
||||
mainMenu.findViewById(R.id.volunteer).setOnClickListener(menuFooterClickListener);
|
||||
// Forward window insets to NavigationView
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mainMenu, new OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
|
||||
return insets;
|
||||
}
|
||||
});
|
||||
navigationView = findViewById(R.id.nav_view);
|
||||
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
|
||||
pendingNavigationMenuItem = menuItem;
|
||||
drawerLayout.closeDrawer(mainMenu);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(scheduleRefreshedReceiver, new IntentFilter(DatabaseManager.ACTION_SCHEDULE_REFRESHED));
|
||||
|
||||
|
@ -296,8 +295,8 @@ public class MainActivity extends AppCompatActivity {
|
|||
lastUpdateTextView = mainMenu.findViewById(R.id.last_update);
|
||||
updateLastUpdateTime();
|
||||
|
||||
// Restore current section
|
||||
if (savedInstanceState == null) {
|
||||
// Select initial section
|
||||
currentSection = Section.TRACKS;
|
||||
String action = getIntent().getAction();
|
||||
if (action != null) {
|
||||
|
@ -310,33 +309,18 @@ public class MainActivity extends AppCompatActivity {
|
|||
break;
|
||||
}
|
||||
}
|
||||
navigationView.setCheckedItem(currentSection.getMenuItemId());
|
||||
|
||||
String fragmentClassName = currentSection.getFragmentClassName();
|
||||
Fragment f = Fragment.instantiate(this, fragmentClassName);
|
||||
getSupportFragmentManager().beginTransaction().add(R.id.content, f, fragmentClassName).commit();
|
||||
} else {
|
||||
currentSection = Section.values()[savedInstanceState.getInt(STATE_CURRENT_SECTION)];
|
||||
}
|
||||
// Ensure the current section is visible in the menu
|
||||
sectionsList.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (sectionsList.getChildCount() > currentSection.ordinal()) {
|
||||
ScrollView mainMenuScrollView = findViewById(R.id.main_menu_scroll);
|
||||
int requiredScroll = sectionsList.getTop()
|
||||
+ sectionsList.getChildAt(currentSection.ordinal()).getBottom()
|
||||
- mainMenuScrollView.getHeight();
|
||||
mainMenuScrollView.scrollTo(0, Math.max(0, requiredScroll));
|
||||
}
|
||||
}
|
||||
});
|
||||
updateActionBar();
|
||||
}
|
||||
|
||||
private void updateActionBar() {
|
||||
setTitle(currentSection.getTitleResId());
|
||||
private void updateActionBar(@NonNull Section section, @NonNull MenuItem menuItem) {
|
||||
setTitle(menuItem.getTitle());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
toolbar.setElevation(currentSection.extendsAppBar()
|
||||
toolbar.setElevation(section.extendsAppBar()
|
||||
? 0f : getResources().getDimension(R.dimen.toolbar_elevation));
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +337,17 @@ public class MainActivity extends AppCompatActivity {
|
|||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
drawerToggle.syncState();
|
||||
|
||||
// Restore current section from NavigationView
|
||||
final MenuItem menuItem = navigationView.getCheckedItem();
|
||||
if (menuItem != null) {
|
||||
if (currentSection == null) {
|
||||
currentSection = Section.fromMenuItemId(menuItem.getItemId());
|
||||
}
|
||||
if (currentSection != null) {
|
||||
updateActionBar(currentSection, menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -367,10 +362,13 @@ public class MainActivity extends AppCompatActivity {
|
|||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
// Ensure no fragment transaction attempt will occur after onSaveInstanceState()
|
||||
pendingMenuSection = -1;
|
||||
pendingMenuFooter = -1;
|
||||
if (pendingNavigationMenuItem != null) {
|
||||
pendingNavigationMenuItem = null;
|
||||
if (currentSection != null) {
|
||||
navigationView.setCheckedItem(currentSection.getMenuItemId());
|
||||
}
|
||||
}
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(STATE_CURRENT_SECTION, currentSection.ordinal());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -473,69 +471,32 @@ public class MainActivity extends AppCompatActivity {
|
|||
|
||||
// MAIN MENU
|
||||
|
||||
private class MainMenuAdapter extends AdapterLinearLayout.Adapter<Section> {
|
||||
|
||||
private final Section[] sections = Section.values();
|
||||
private final LayoutInflater inflater;
|
||||
private final int currentSectionForegroundColor;
|
||||
|
||||
public MainMenuAdapter(LayoutInflater inflater) {
|
||||
this.inflater = inflater;
|
||||
// Select the primary color to tint the current section
|
||||
TypedArray a = getTheme().obtainStyledAttributes(new int[]{R.attr.colorPrimary});
|
||||
try {
|
||||
currentSectionForegroundColor = a.getColor(0, Color.TRANSPARENT);
|
||||
} finally {
|
||||
a.recycle();
|
||||
void handleNavigationMenuItem(@NonNull MenuItem menuItem) {
|
||||
final int menuItemId = menuItem.getItemId();
|
||||
final Section section = Section.fromMenuItemId(menuItemId);
|
||||
if (section != null) {
|
||||
selectMenuSection(section, menuItem);
|
||||
} else {
|
||||
switch (menuItemId) {
|
||||
case R.id.menu_settings:
|
||||
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
|
||||
overridePendingTransition(R.anim.slide_in_right, R.anim.partial_zoom_out);
|
||||
break;
|
||||
case R.id.menu_volunteer:
|
||||
try {
|
||||
new CustomTabsIntent.Builder()
|
||||
.setToolbarColor(ContextCompat.getColor(this, R.color.color_primary))
|
||||
.setShowTitle(true)
|
||||
.build()
|
||||
.launchUrl(this, Uri.parse(FosdemUrls.getVolunteer()));
|
||||
} catch (ActivityNotFoundException ignore) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return sections.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Section getItem(int position) {
|
||||
return sections[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = inflater.inflate(R.layout.item_main_menu, parent, false);
|
||||
convertView.setOnClickListener(sectionClickListener);
|
||||
}
|
||||
|
||||
Section section = getItem(position);
|
||||
convertView.setSelected(section == currentSection);
|
||||
|
||||
TextView tv = convertView.findViewById(R.id.section_text);
|
||||
SpannableString sectionTitle = new SpannableString(getString(section.getTitleResId()));
|
||||
Drawable sectionIcon = AppCompatResources.getDrawable(MainActivity.this, section.getIconResId());
|
||||
if (section == currentSection) {
|
||||
// Special color for the current section
|
||||
sectionTitle.setSpan(new ForegroundColorSpan(currentSectionForegroundColor), 0, sectionTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
// We need to mutate the drawable before applying the ColorFilter, or else all the similar drawable instances will be tinted.
|
||||
sectionIcon.mutate().setColorFilter(currentSectionForegroundColor, PorterDuff.Mode.SRC_IN);
|
||||
}
|
||||
tv.setText(sectionTitle);
|
||||
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(tv, sectionIcon, null, null, null);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
final View.OnClickListener sectionClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
pendingMenuSection = ((ViewGroup) view.getParent()).indexOfChild(view);
|
||||
drawerLayout.closeDrawer(mainMenu);
|
||||
}
|
||||
};
|
||||
|
||||
void selectMenuSection(int position) {
|
||||
Section section = menuAdapter.getItem(position);
|
||||
void selectMenuSection(@NonNull Section section, @NonNull MenuItem menuItem) {
|
||||
if (section != currentSection) {
|
||||
// Switch to new section
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
|
@ -558,36 +519,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
ft.commit();
|
||||
|
||||
currentSection = section;
|
||||
updateActionBar();
|
||||
menuAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private final View.OnClickListener menuFooterClickListener = new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
pendingMenuFooter = view.getId();
|
||||
drawerLayout.closeDrawer(mainMenu);
|
||||
}
|
||||
};
|
||||
|
||||
void selectMenuFooter(int id) {
|
||||
switch (id) {
|
||||
case R.id.settings:
|
||||
startActivity(new Intent(MainActivity.this, SettingsActivity.class));
|
||||
overridePendingTransition(R.anim.slide_in_right, R.anim.partial_zoom_out);
|
||||
break;
|
||||
case R.id.volunteer:
|
||||
try {
|
||||
new CustomTabsIntent.Builder()
|
||||
.setToolbarColor(ContextCompat.getColor(this, R.color.color_primary))
|
||||
.setShowTitle(true)
|
||||
.build()
|
||||
.launchUrl(this, Uri.parse(FosdemUrls.getVolunteer()));
|
||||
} catch (ActivityNotFoundException ignore) {
|
||||
}
|
||||
break;
|
||||
updateActionBar(section, menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
@ -369,7 +370,7 @@ public class EventDetailsFragment extends Fragment {
|
|||
try {
|
||||
startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(getActivity(), R.string.calendar_not_found, Toast.LENGTH_LONG).show();
|
||||
Snackbar.make(getView(), R.string.calendar_not_found, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
@ -13,13 +15,12 @@ import androidx.fragment.app.FragmentPagerAdapter;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import be.digitalia.fosdem.R;
|
||||
import be.digitalia.fosdem.widgets.SlidingTabLayout;
|
||||
|
||||
public class LiveFragment extends Fragment implements RecycledViewPoolProvider {
|
||||
|
||||
static class ViewHolder {
|
||||
ViewPager pager;
|
||||
SlidingTabLayout slidingTabs;
|
||||
TabLayout tabs;
|
||||
RecyclerView.RecycledViewPool recycledViewPool;
|
||||
}
|
||||
|
||||
|
@ -32,8 +33,8 @@ public class LiveFragment extends Fragment implements RecycledViewPoolProvider {
|
|||
holder = new ViewHolder();
|
||||
holder.pager = view.findViewById(R.id.pager);
|
||||
holder.pager.setAdapter(new LivePagerAdapter(getChildFragmentManager(), getResources()));
|
||||
holder.slidingTabs = view.findViewById(R.id.sliding_tabs);
|
||||
holder.slidingTabs.setViewPager(holder.pager);
|
||||
holder.tabs = view.findViewById(R.id.tabs);
|
||||
holder.tabs.setupWithViewPager(holder.pager, false);
|
||||
holder.recycledViewPool = new RecyclerView.RecycledViewPool();
|
||||
|
||||
return view;
|
||||
|
|
|
@ -7,6 +7,8 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -20,7 +22,6 @@ import androidx.viewpager.widget.ViewPager;
|
|||
import be.digitalia.fosdem.R;
|
||||
import be.digitalia.fosdem.db.DatabaseManager;
|
||||
import be.digitalia.fosdem.model.Day;
|
||||
import be.digitalia.fosdem.widgets.SlidingTabLayout;
|
||||
|
||||
public class TracksFragment extends Fragment implements RecycledViewPoolProvider, Observer<List<Day>> {
|
||||
|
||||
|
@ -28,7 +29,7 @@ public class TracksFragment extends Fragment implements RecycledViewPoolProvider
|
|||
View contentView;
|
||||
View emptyView;
|
||||
ViewPager pager;
|
||||
SlidingTabLayout slidingTabs;
|
||||
TabLayout tabs;
|
||||
DaysAdapter daysAdapter;
|
||||
RecyclerView.RecycledViewPool recycledViewPool;
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ public class TracksFragment extends Fragment implements RecycledViewPoolProvider
|
|||
holder.contentView = view.findViewById(R.id.content);
|
||||
holder.emptyView = view.findViewById(android.R.id.empty);
|
||||
holder.pager = view.findViewById(R.id.pager);
|
||||
holder.slidingTabs = view.findViewById(R.id.sliding_tabs);
|
||||
holder.tabs = view.findViewById(R.id.tabs);
|
||||
holder.daysAdapter = new DaysAdapter(getChildFragmentManager());
|
||||
holder.recycledViewPool = new RecyclerView.RecycledViewPool();
|
||||
|
||||
|
@ -108,7 +109,7 @@ public class TracksFragment extends Fragment implements RecycledViewPoolProvider
|
|||
holder.emptyView.setVisibility(View.GONE);
|
||||
if (holder.pager.getAdapter() == null) {
|
||||
holder.pager.setAdapter(holder.daysAdapter);
|
||||
holder.slidingTabs.setViewPager(holder.pager);
|
||||
holder.tabs.setupWithViewPager(holder.pager);
|
||||
}
|
||||
if (savedCurrentPage != -1) {
|
||||
holder.pager.setCurrentItem(Math.min(savedCurrentPage, totalPages - 1), false);
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
package be.digitalia.fosdem.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObservable;
|
||||
import android.database.DataSetObserver;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
/**
|
||||
* Vertical LinearLayout populated by a special adapter.
|
||||
*
|
||||
* @author Christophe Beyls
|
||||
*/
|
||||
public class AdapterLinearLayout extends LinearLayout {
|
||||
|
||||
/**
|
||||
* Implement this Adapter to populate the layout.
|
||||
* Call notifyDataSetChanged() to update it.
|
||||
*/
|
||||
public static abstract class Adapter<T> {
|
||||
|
||||
final DataSetObservable mDataSetObservable = new DataSetObservable();
|
||||
|
||||
public void notifyDataSetChanged() {
|
||||
mDataSetObservable.notifyChanged();
|
||||
}
|
||||
|
||||
public abstract int getCount();
|
||||
|
||||
public abstract T getItem(int position);
|
||||
|
||||
public abstract View getView(int position, View convertView, ViewGroup parent);
|
||||
}
|
||||
|
||||
class AdapterLinearLayoutDataSetObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
populateFromAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
private Adapter mAdapter;
|
||||
private AdapterLinearLayoutDataSetObserver mDataSetObserver;
|
||||
|
||||
|
||||
public AdapterLinearLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AdapterLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setOrientation(VERTICAL);
|
||||
}
|
||||
|
||||
public void setAdapter(Adapter adapter) {
|
||||
if (mAdapter == adapter) {
|
||||
return;
|
||||
}
|
||||
if (mAdapter != null && mDataSetObserver != null) {
|
||||
mAdapter.mDataSetObservable.unregisterObserver(mDataSetObserver);
|
||||
}
|
||||
removeAllViews();
|
||||
mAdapter = adapter;
|
||||
if (adapter != null && mDataSetObserver != null) {
|
||||
populateFromAdapter();
|
||||
adapter.mDataSetObservable.registerObserver(mDataSetObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mDataSetObserver = new AdapterLinearLayoutDataSetObserver();
|
||||
if (mAdapter != null) {
|
||||
populateFromAdapter();
|
||||
mAdapter.mDataSetObservable.registerObserver(mDataSetObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if ((mAdapter != null) && (mDataSetObserver != null)) {
|
||||
mAdapter.mDataSetObservable.unregisterObserver(mDataSetObserver);
|
||||
}
|
||||
mDataSetObserver = null;
|
||||
}
|
||||
|
||||
void populateFromAdapter() {
|
||||
final Adapter adapter = mAdapter;
|
||||
final int currentCount = getChildCount();
|
||||
final int newCount = adapter.getCount();
|
||||
final int commonCount = Math.min(currentCount, newCount);
|
||||
// 1. Update common views
|
||||
for (int i = 0; i < commonCount; ++i) {
|
||||
final View currentView = getChildAt(i);
|
||||
final View newView = adapter.getView(i, currentView, this);
|
||||
if (currentView != newView) {
|
||||
// Edge case: View is not recycled
|
||||
removeViewAt(i);
|
||||
addView(newView, i);
|
||||
}
|
||||
}
|
||||
// 2a. Add missing views
|
||||
for (int i = commonCount; i < newCount; ++i) {
|
||||
addView(adapter.getView(i, null, this));
|
||||
}
|
||||
// 2b. Remove extra views (starting from the end to avoid array copies)
|
||||
for (int i = currentCount - 1; i >= commonCount; --i) {
|
||||
removeViewAt(i);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package be.digitalia.fosdem.widgets;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.LinearLayoutCompat;
|
||||
import be.digitalia.fosdem.R;
|
||||
|
||||
public class ForegroundLinearLayout extends LinearLayoutCompat {
|
||||
|
||||
private Drawable mForeground;
|
||||
|
||||
private final Rect mSelfBounds = new Rect();
|
||||
|
||||
private final Rect mOverlayBounds = new Rect();
|
||||
|
||||
private int mForegroundGravity = Gravity.FILL;
|
||||
|
||||
protected boolean mForegroundInPadding = true;
|
||||
|
||||
boolean mForegroundBoundsChanged = false;
|
||||
|
||||
public ForegroundLinearLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ForegroundLinearLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout,
|
||||
defStyle, 0);
|
||||
|
||||
mForegroundGravity = a.getInt(
|
||||
R.styleable.ForegroundLinearLayout_android_foregroundGravity, mForegroundGravity);
|
||||
|
||||
final Drawable d = a.getDrawable(R.styleable.ForegroundLinearLayout_android_foreground);
|
||||
if (d != null) {
|
||||
setForeground(d);
|
||||
}
|
||||
|
||||
mForegroundInPadding = a.getBoolean(
|
||||
R.styleable.ForegroundLinearLayout_foregroundInsidePadding, true);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes how the foreground is positioned.
|
||||
*
|
||||
* @return foreground gravity.
|
||||
* @see #setForegroundGravity(int)
|
||||
*/
|
||||
public int getForegroundGravity() {
|
||||
return mForegroundGravity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes how the foreground is positioned. Defaults to START and TOP.
|
||||
*
|
||||
* @param foregroundGravity See {@link Gravity}
|
||||
* @see #getForegroundGravity()
|
||||
*/
|
||||
public void setForegroundGravity(int foregroundGravity) {
|
||||
if (mForegroundGravity != foregroundGravity) {
|
||||
if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
|
||||
foregroundGravity |= Gravity.START;
|
||||
}
|
||||
|
||||
if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
|
||||
foregroundGravity |= Gravity.TOP;
|
||||
}
|
||||
|
||||
mForegroundGravity = foregroundGravity;
|
||||
|
||||
if (mForegroundGravity == Gravity.FILL && mForeground != null) {
|
||||
Rect padding = new Rect();
|
||||
mForeground.getPadding(padding);
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean verifyDrawable(@NonNull Drawable who) {
|
||||
return super.verifyDrawable(who) || (who == mForeground);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jumpDrawablesToCurrentState() {
|
||||
super.jumpDrawablesToCurrentState();
|
||||
if (mForeground != null) {
|
||||
mForeground.jumpToCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawableStateChanged() {
|
||||
super.drawableStateChanged();
|
||||
if (mForeground != null && mForeground.isStateful()) {
|
||||
mForeground.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply a Drawable that is to be rendered on top of all of the child
|
||||
* views in the frame layout. Any padding in the Drawable will be taken
|
||||
* into account by ensuring that the children are inset to be placed
|
||||
* inside of the padding area.
|
||||
*
|
||||
* @param drawable The Drawable to be drawn on top of the children.
|
||||
*/
|
||||
public void setForeground(Drawable drawable) {
|
||||
if (mForeground != drawable) {
|
||||
if (mForeground != null) {
|
||||
mForeground.setCallback(null);
|
||||
unscheduleDrawable(mForeground);
|
||||
}
|
||||
|
||||
mForeground = drawable;
|
||||
|
||||
if (drawable != null) {
|
||||
setWillNotDraw(false);
|
||||
drawable.setCallback(this);
|
||||
if (drawable.isStateful()) {
|
||||
drawable.setState(getDrawableState());
|
||||
}
|
||||
if (mForegroundGravity == Gravity.FILL) {
|
||||
Rect padding = new Rect();
|
||||
drawable.getPadding(padding);
|
||||
}
|
||||
} else {
|
||||
setWillNotDraw(true);
|
||||
}
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the drawable used as the foreground of this FrameLayout. The
|
||||
* foreground drawable, if non-null, is always drawn on top of the children.
|
||||
*
|
||||
* @return A Drawable or null if no foreground was set.
|
||||
*/
|
||||
public Drawable getForeground() {
|
||||
return mForeground;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
mForegroundBoundsChanged |= changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
mForegroundBoundsChanged = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
|
||||
if (mForeground != null) {
|
||||
final Drawable foreground = mForeground;
|
||||
|
||||
if (mForegroundBoundsChanged) {
|
||||
mForegroundBoundsChanged = false;
|
||||
final Rect selfBounds = mSelfBounds;
|
||||
final Rect overlayBounds = mOverlayBounds;
|
||||
|
||||
final int w = getRight() - getLeft();
|
||||
final int h = getBottom() - getTop();
|
||||
|
||||
if (mForegroundInPadding) {
|
||||
selfBounds.set(0, 0, w, h);
|
||||
} else {
|
||||
selfBounds.set(getPaddingLeft(), getPaddingTop(),
|
||||
w - getPaddingRight(), h - getPaddingBottom());
|
||||
}
|
||||
|
||||
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
|
||||
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
|
||||
foreground.setBounds(overlayBounds);
|
||||
}
|
||||
|
||||
foreground.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void drawableHotspotChanged(float x, float y) {
|
||||
super.drawableHotspotChanged(x, y);
|
||||
if (mForeground != null) {
|
||||
mForeground.setHotspot(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package be.digitalia.fosdem.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import be.digitalia.fosdem.R;
|
||||
|
||||
public class ScrimInsetsFrameLayout extends FrameLayout {
|
||||
Drawable mInsetForeground;
|
||||
Rect mInsets;
|
||||
private Rect mTempRect = new Rect();
|
||||
|
||||
public ScrimInsetsFrameLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.ScrimInsetsFrameLayout, defStyleAttr,
|
||||
R.style.Widget_Design_ScrimInsetsFrameLayout);
|
||||
mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground);
|
||||
a.recycle();
|
||||
setWillNotDraw(true); // No need to draw until the insets are adjusted
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this,
|
||||
new androidx.core.view.OnApplyWindowInsetsListener() {
|
||||
@Override
|
||||
public WindowInsetsCompat onApplyWindowInsets(View v,
|
||||
WindowInsetsCompat insets) {
|
||||
if (null == mInsets) {
|
||||
mInsets = new Rect();
|
||||
}
|
||||
mInsets.set(insets.getSystemWindowInsetLeft(),
|
||||
insets.getSystemWindowInsetTop(),
|
||||
insets.getSystemWindowInsetRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
setWillNotDraw(mInsets.isEmpty() || mInsetForeground == null);
|
||||
ViewCompat.postInvalidateOnAnimation(ScrimInsetsFrameLayout.this);
|
||||
return insets.consumeSystemWindowInsets();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
if (mInsets != null && mInsetForeground != null) {
|
||||
int sc = canvas.save();
|
||||
canvas.translate(getScrollX(), getScrollY());
|
||||
// Top
|
||||
mTempRect.set(0, 0, width, mInsets.top);
|
||||
mInsetForeground.setBounds(mTempRect);
|
||||
mInsetForeground.draw(canvas);
|
||||
// Bottom
|
||||
mTempRect.set(0, height - mInsets.bottom, width, height);
|
||||
mInsetForeground.setBounds(mTempRect);
|
||||
mInsetForeground.draw(canvas);
|
||||
// Left
|
||||
mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
|
||||
mInsetForeground.setBounds(mTempRect);
|
||||
mInsetForeground.draw(canvas);
|
||||
// Right
|
||||
mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
|
||||
mInsetForeground.setBounds(mTempRect);
|
||||
mInsetForeground.draw(canvas);
|
||||
canvas.restoreToCount(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mInsetForeground != null) {
|
||||
mInsetForeground.setCallback(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mInsetForeground != null) {
|
||||
mInsetForeground.setCallback(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,424 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Chris Banes
|
||||
* Copyright 2016 Christophe Beyls
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package be.digitalia.fosdem.widgets;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
import be.digitalia.fosdem.R;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SlidingTabLayout extends HorizontalScrollView {
|
||||
|
||||
public interface TabListener {
|
||||
|
||||
void onTabSelected(int pos);
|
||||
|
||||
void onTabReSelected(int pos);
|
||||
|
||||
}
|
||||
|
||||
private static final int[][] TAB_COLOR_STATES = new int[][]{SELECTED_STATE_SET, EMPTY_STATE_SET};
|
||||
|
||||
private int mTitleOffset;
|
||||
|
||||
private int mTabViewLayoutId;
|
||||
private int mTabViewTextViewId;
|
||||
private boolean mDistributeEvenly;
|
||||
|
||||
private ColorStateList mTextColor;
|
||||
|
||||
ViewPager mViewPager;
|
||||
PagerAdapter mAdapter;
|
||||
private final InternalViewPagerListener mPageChangeListener = new InternalViewPagerListener();
|
||||
private final PagerAdapterObserver mPagerAdapterObserver = new PagerAdapterObserver();
|
||||
|
||||
TabListener mTabListener;
|
||||
|
||||
final SlidingTabStrip mTabStrip;
|
||||
|
||||
public SlidingTabLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
// Disable the Scroll Bar
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
// Make sure that the Tab Strips fills this View
|
||||
setFillViewport(true);
|
||||
|
||||
mTabStrip = new SlidingTabStrip(context);
|
||||
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabLayout,
|
||||
defStyle, R.style.SlidingTabLayout);
|
||||
|
||||
mTabStrip.setSelectedIndicatorHeight(a.getDimensionPixelSize(R.styleable.SlidingTabLayout_indicatorHeight, 0));
|
||||
mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.SlidingTabLayout_indicatorColor, 0));
|
||||
mTextColor = a.getColorStateList(R.styleable.SlidingTabLayout_textColor);
|
||||
if ((mTextColor != null) && a.hasValue(R.styleable.SlidingTabLayout_selectedTextColor)) {
|
||||
setTabTextColors(mTextColor.getDefaultColor(), a.getColor(R.styleable.SlidingTabLayout_selectedTextColor, 0));
|
||||
}
|
||||
setContentInsetStart(a.getDimensionPixelSize(R.styleable.SlidingTabLayout_contentInsetStart, 0));
|
||||
setDistributeEvenly(a.getBoolean(R.styleable.SlidingTabLayout_distributeEvenly, false));
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setContentInsetStart(int offset) {
|
||||
mTitleOffset = offset;
|
||||
mTabStrip.setPadding(offset, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void setDistributeEvenly(boolean distributeEvenly) {
|
||||
mDistributeEvenly = distributeEvenly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color to be used for indicating the selected tab.
|
||||
* This will override the style color.
|
||||
*/
|
||||
public void setSelectedTabIndicatorColor(@ColorInt int color) {
|
||||
mTabStrip.setSelectedIndicatorColor(color);
|
||||
}
|
||||
|
||||
public void setSelectedTabIndicatorHeight(int height) {
|
||||
mTabStrip.setSelectedIndicatorHeight(height);
|
||||
}
|
||||
|
||||
public void setTabTextColors(ColorStateList color) {
|
||||
mTextColor = color;
|
||||
}
|
||||
|
||||
public void setTabTextColors(@ColorInt int normalColor, @ColorInt int selectedColor) {
|
||||
mTextColor = createColorStateList(normalColor, selectedColor);
|
||||
}
|
||||
|
||||
private static ColorStateList createColorStateList(int defaultColor, int selectedColor) {
|
||||
final int[] colors = new int[]{selectedColor, defaultColor};
|
||||
return new ColorStateList(TAB_COLOR_STATES, colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom layout to be inflated for the tab views.
|
||||
*
|
||||
* @param layoutResId Layout id to be inflated
|
||||
* @param textViewId id of the {@link TextView} in the inflated view
|
||||
*/
|
||||
public void setCustomTabView(@LayoutRes int layoutResId, @IdRes int textViewId) {
|
||||
mTabViewLayoutId = layoutResId;
|
||||
mTabViewTextViewId = textViewId;
|
||||
}
|
||||
|
||||
public void setTabListener(TabListener tabListener) {
|
||||
mTabListener = tabListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the associated view pager. The ViewPager must have an adapter set.
|
||||
* The SlidingTabLayout will then listen for changes and update the tabs automatically.
|
||||
*/
|
||||
public void setViewPager(ViewPager viewPager) {
|
||||
if (mViewPager != null) {
|
||||
mViewPager.removeOnPageChangeListener(mPageChangeListener);
|
||||
mAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
|
||||
}
|
||||
if (viewPager != null) {
|
||||
PagerAdapter adapter = viewPager.getAdapter();
|
||||
if (adapter == null) {
|
||||
throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
|
||||
}
|
||||
mViewPager = viewPager;
|
||||
mAdapter = adapter;
|
||||
mPageChangeListener.reset();
|
||||
viewPager.addOnPageChangeListener(mPageChangeListener);
|
||||
adapter.registerDataSetObserver(mPagerAdapterObserver);
|
||||
} else {
|
||||
mViewPager = null;
|
||||
mAdapter = null;
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
void notifyDataSetChanged() {
|
||||
mTabStrip.removeAllViews();
|
||||
if (mViewPager != null) {
|
||||
populateTabStrip();
|
||||
}
|
||||
}
|
||||
|
||||
static void setSelectedCompat(View view, boolean selected) {
|
||||
final boolean becomeSelected = selected && !view.isSelected();
|
||||
view.setSelected(selected);
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN && becomeSelected) {
|
||||
// Pre-JB we need to manually send the TYPE_VIEW_SELECTED event
|
||||
view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
|
||||
}
|
||||
}
|
||||
|
||||
private void populateTabStrip() {
|
||||
final int adapterCount = mAdapter.getCount();
|
||||
final View.OnClickListener tabClickListener = new TabClickListener();
|
||||
final LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
final int currentItem = mViewPager.getCurrentItem();
|
||||
|
||||
for (int i = 0; i < adapterCount; i++) {
|
||||
View tabView;
|
||||
TextView tabTitleView;
|
||||
|
||||
if (mTabViewLayoutId != 0) {
|
||||
// If there is a custom tab view layout id set, try and inflate it
|
||||
tabView = inflater.inflate(mTabViewLayoutId, mTabStrip, false);
|
||||
tabTitleView = tabView.findViewById(mTabViewTextViewId);
|
||||
if (tabTitleView == null) {
|
||||
tabTitleView = (TextView) tabView;
|
||||
}
|
||||
} else {
|
||||
// Inflate our default tab layout
|
||||
tabView = inflater.inflate(R.layout.widget_sliding_tab_layout_text, mTabStrip, false);
|
||||
tabTitleView = (TextView) tabView;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
// Emulate Roboto Medium in previous Android versions
|
||||
tabTitleView.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
}
|
||||
}
|
||||
if (mTextColor != null) {
|
||||
tabTitleView.setTextColor(mTextColor);
|
||||
}
|
||||
|
||||
if (mDistributeEvenly) {
|
||||
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
|
||||
lp.width = 0;
|
||||
lp.weight = 1;
|
||||
}
|
||||
|
||||
tabTitleView.setText(mAdapter.getPageTitle(i));
|
||||
tabView.setFocusable(true);
|
||||
tabView.setOnClickListener(tabClickListener);
|
||||
|
||||
mTabStrip.addView(tabView);
|
||||
if (i == currentItem) {
|
||||
setSelectedCompat(tabView, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mViewPager != null) {
|
||||
scrollToTab(mViewPager.getCurrentItem(), 0);
|
||||
}
|
||||
announceSelectedTab(hasWindowFocus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||
super.onWindowFocusChanged(hasWindowFocus);
|
||||
announceSelectedTab(hasWindowFocus);
|
||||
}
|
||||
|
||||
private void announceSelectedTab(boolean hasWindowFocus) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && hasWindowFocus) {
|
||||
getHandler().post(new Runnable() {
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
@Override
|
||||
public void run() {
|
||||
if (mViewPager != null && mAdapter != null && mAdapter.getCount() > 0) {
|
||||
CharSequence pageTitle = mAdapter.getPageTitle(mViewPager.getCurrentItem());
|
||||
if (!TextUtils.isEmpty(pageTitle)) {
|
||||
announceForAccessibility(pageTitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void scrollToTab(int tabIndex, float positionOffset) {
|
||||
final int tabStripChildCount = mTabStrip.getChildCount();
|
||||
if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
View selectedChild = mTabStrip.getChildAt(tabIndex);
|
||||
if (selectedChild != null) {
|
||||
int targetScrollX = selectedChild.getLeft() +
|
||||
Math.round(positionOffset * selectedChild.getWidth()) - mTitleOffset;
|
||||
|
||||
scrollTo(targetScrollX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
|
||||
private int mScrollState;
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
int tabStripChildCount = mTabStrip.getChildCount();
|
||||
if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTabStrip.onViewPagerPageChanged(position, positionOffset);
|
||||
|
||||
|
||||
scrollToTab(position, positionOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
mScrollState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
|
||||
mTabStrip.onViewPagerPageChanged(position, 0f);
|
||||
scrollToTab(position, 0);
|
||||
}
|
||||
final int childCount = mTabStrip.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
setSelectedCompat(mTabStrip.getChildAt(i), position == i);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
mScrollState = ViewPager.SCROLL_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
class PagerAdapterObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
class TabClickListener implements View.OnClickListener {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
final int childCount = mTabStrip.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if (v == mTabStrip.getChildAt(i)) {
|
||||
final int previousPos = mViewPager.getCurrentItem();
|
||||
mViewPager.setCurrentItem(i);
|
||||
|
||||
if (mTabListener != null) {
|
||||
if (previousPos != i) {
|
||||
mTabListener.onTabSelected(i);
|
||||
} else {
|
||||
mTabListener.onTabReSelected(i);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class SlidingTabStrip extends LinearLayout {
|
||||
|
||||
private int mSelectedIndicatorHeight;
|
||||
private final Paint mSelectedIndicatorPaint;
|
||||
|
||||
private int mSelectedPosition;
|
||||
private float mSelectionOffset;
|
||||
|
||||
SlidingTabStrip(Context context) {
|
||||
super(context);
|
||||
setWillNotDraw(false);
|
||||
mSelectedIndicatorPaint = new Paint();
|
||||
}
|
||||
|
||||
void setSelectedIndicatorColor(@ColorInt int color) {
|
||||
mSelectedIndicatorPaint.setColor(color);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setSelectedIndicatorHeight(int height) {
|
||||
mSelectedIndicatorHeight = height;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void onViewPagerPageChanged(int position, float positionOffset) {
|
||||
mSelectedPosition = position;
|
||||
mSelectionOffset = positionOffset;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
final int height = getHeight();
|
||||
final int childCount = getChildCount();
|
||||
|
||||
// Thick colored underline below the current selection
|
||||
if (childCount > 0) {
|
||||
View selectedTitle = getChildAt(mSelectedPosition);
|
||||
int left = selectedTitle.getLeft();
|
||||
int right = selectedTitle.getRight();
|
||||
|
||||
if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
|
||||
// Draw the selection partway between the tabs
|
||||
View nextTitle = getChildAt(mSelectedPosition + 1);
|
||||
left = (int) (mSelectionOffset * nextTitle.getLeft() +
|
||||
(1.0f - mSelectionOffset) * left);
|
||||
right = (int) (mSelectionOffset * nextTitle.getRight() +
|
||||
(1.0f - mSelectionOffset) * right);
|
||||
}
|
||||
|
||||
canvas.drawRect(left, height - mSelectedIndicatorHeight, right,
|
||||
height, mSelectedIndicatorPaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_enabled="true"
|
||||
android:state_pressed="true">
|
||||
<objectAnimator
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:propertyName="translationZ"
|
||||
android:valueTo="@dimen/fab_press_translation_z"
|
||||
android:valueType="floatType"/>
|
||||
</item>
|
||||
<item>
|
||||
<objectAnimator
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:propertyName="translationZ"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType"/>
|
||||
</item>
|
||||
</selector>
|
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/fab_background_highlighted" android:state_pressed="true"/>
|
||||
<item android:drawable="@drawable/fab_background_highlighted" android:state_focused="true"/>
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/color_accent"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/color_accent"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="@color/ripple_material_dark"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -1,52 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge 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"
|
||||
tools:context=".activities.TrackScheduleActivity">
|
||||
<androidx.coordinatorlayout.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"
|
||||
tools:context=".activities.TrackScheduleActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<FrameLayout
|
||||
android:id="@+id/schedule"
|
||||
android:layout_width="@dimen/schedule_column_width"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginTop="128dp" />
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Toolbar.Fosdem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:elevation="4dp"
|
||||
android:gravity="top"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/schedule"
|
||||
android:layout_width="@dimen/schedule_column_width"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="start"
|
||||
android:layout_weight="1"/>
|
||||
</LinearLayout>
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
style="@style/Toolbar.Fosdem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:elevation="4dp"
|
||||
android:gravity="top" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/event"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/detail_card_view_margin_bottom"
|
||||
android:layout_marginEnd="@dimen/detail_card_view_margin_end"
|
||||
android:layout_marginLeft="@dimen/detail_card_view_margin_start"
|
||||
android:layout_marginRight="@dimen/detail_card_view_margin_end"
|
||||
android:layout_marginStart="@dimen/detail_card_view_margin_start"
|
||||
android:layout_marginLeft="@dimen/detail_card_view_margin_start"
|
||||
android:layout_marginTop="@dimen/detail_card_view_margin_top"
|
||||
app:cardElevation="@dimen/detail_card_view_elevation"/>
|
||||
android:layout_marginEnd="@dimen/detail_card_view_margin_end"
|
||||
android:layout_marginRight="@dimen/detail_card_view_margin_end"
|
||||
android:layout_marginBottom="@dimen/detail_card_view_margin_bottom"
|
||||
app:cardElevation="@dimen/detail_card_view_elevation"
|
||||
app:cardPreventCornerOverlap="false" />
|
||||
|
||||
<ImageView
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
style="@style/FloatingActionButton"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="100dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/detail_fab_margin_end"
|
||||
android:layout_marginRight="@dimen/detail_fab_margin_end"
|
||||
android:contentDescription="@string/add_bookmark"
|
||||
app:srcCompat="@drawable/ic_bookmark_outline_white_24dp"/>
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark"
|
||||
app:fabSize="normal"
|
||||
app:layout_anchor="@+id/toolbar"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:srcCompat="@drawable/ic_bookmark_outline_white_24dp" />
|
||||
|
||||
</merge>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,18 +1,15 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<be.digitalia.fosdem.widgets.SlidingTabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
style="@style/SlidingTabs"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
style="@style/Tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/toolbar_elevation"
|
||||
app:contentInsetStart="0dp"
|
||||
app:distributeEvenly="true"/>
|
||||
android:elevation="@dimen/toolbar_elevation"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/pager"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -9,12 +10,13 @@
|
|||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<be.digitalia.fosdem.widgets.SlidingTabLayout
|
||||
android:id="@+id/sliding_tabs"
|
||||
style="@style/SlidingTabs"
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
style="@style/Tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="@dimen/toolbar_elevation"/>
|
||||
android:elevation="@dimen/toolbar_elevation"
|
||||
app:tabMode="scrollable"/>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/pager"
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<be.digitalia.fosdem.widgets.ScrimInsetsFrameLayout
|
||||
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:id="@+id/main_menu"
|
||||
android:layout_width="@dimen/main_menu_width"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:background="@color/main_menu_background"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/main_menu_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/main_menu_footer_height">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/main_menu_header_height"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:padding="@dimen/main_menu_padding"
|
||||
android:scaleType="center"
|
||||
app:srcCompat="@drawable/fosdem_title"/>
|
||||
|
||||
<be.digitalia.fosdem.widgets.AdapterLinearLayout
|
||||
android:id="@+id/sections"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<View
|
||||
style="@style/SeparatorLine"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settings"
|
||||
style="@style/MainMenuItem"
|
||||
android:text="@string/settings"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/volunteer"
|
||||
style="@style/MainMenuItem"
|
||||
android:text="@string/volunteer"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_update"
|
||||
style="@style/TextAppearance.AppCompat.Caption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/main_menu_footer_height"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/main_menu_footer_background"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:lines="1"
|
||||
android:padding="4dp"
|
||||
tools:text="DB last updated: 1 jan. 2015 13:37:00"/>
|
||||
|
||||
</be.digitalia.fosdem.widgets.ScrimInsetsFrameLayout>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<be.digitalia.fosdem.widgets.ForegroundLinearLayout
|
||||
<com.google.android.material.internal.ForegroundLinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -46,4 +46,4 @@
|
|||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
tools:text="Saturday, 09:30 - 09:55 | Janson"/>
|
||||
|
||||
</be.digitalia.fosdem.widgets.ForegroundLinearLayout>
|
||||
</com.google.android.material.internal.ForegroundLinearLayout>
|
|
@ -1,5 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
android:id="@+id/section_text"
|
||||
style="@style/MainMenuItem"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"/>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<be.digitalia.fosdem.widgets.PhotoViewDrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<be.digitalia.fosdem.widgets.PhotoViewDrawerLayout 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:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -10,7 +10,7 @@
|
|||
|
||||
<!-- Main content view -->
|
||||
|
||||
<FrameLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -23,13 +23,13 @@
|
|||
android:id="@+id/toolbar"
|
||||
style="@style/Toolbar.Fosdem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -42,12 +42,46 @@
|
|||
android:layout_marginTop="-7dp"
|
||||
android:max="100"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<!-- Navigation drawer -->
|
||||
|
||||
<include layout="@layout/include_navigation_drawer"/>
|
||||
<FrameLayout
|
||||
android:id="@+id/main_menu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/main_menu_footer_height"
|
||||
android:background="@color/main_menu_background"
|
||||
android:fitsSystemWindows="true"
|
||||
app:elevation="0dp"
|
||||
app:headerLayout="@layout/navigation_header"
|
||||
app:menu="@menu/main_navigation" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_update"
|
||||
style="@style/TextAppearance.AppCompat.Caption"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/main_menu_footer_height"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/main_menu_footer_background"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:lines="1"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingRight="4dp"
|
||||
tools:text="DB last updated: 1 jan. 2015 13:37:00" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</be.digitalia.fosdem.widgets.PhotoViewDrawerLayout>
|
9
app/src/main/res/layout/navigation_header.xml
Normal file
9
app/src/main/res/layout/navigation_header.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/main_menu_header_height"
|
||||
android:contentDescription="@string/app_name"
|
||||
android:padding="@dimen/main_menu_padding"
|
||||
android:scaleType="center"
|
||||
app:srcCompat="@drawable/fosdem_title" />
|
37
app/src/main/res/menu/main_navigation.xml
Normal file
37
app/src/main/res/menu/main_navigation.xml
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group
|
||||
android:id="@+id/menu_group_sections"
|
||||
android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/menu_tracks"
|
||||
android:icon="@drawable/ic_event_grey600_24dp"
|
||||
android:title="@string/menu_tracks" />
|
||||
<item
|
||||
android:id="@+id/menu_bookmarks"
|
||||
android:icon="@drawable/ic_bookmark_grey600_24dp"
|
||||
android:title="@string/menu_bookmarks" />
|
||||
<item
|
||||
android:id="@+id/menu_live"
|
||||
android:icon="@drawable/ic_play_circle_outline_grey600_24dp"
|
||||
android:title="@string/menu_live" />
|
||||
<item
|
||||
android:id="@+id/menu_speakers"
|
||||
android:icon="@drawable/ic_people_grey600_24dp"
|
||||
android:title="@string/menu_speakers" />
|
||||
<item
|
||||
android:id="@+id/menu_map"
|
||||
android:icon="@drawable/ic_map_grey600_24dp"
|
||||
android:title="@string/menu_map" />
|
||||
</group>
|
||||
<group
|
||||
android:id="@+id/menu_group_extras"
|
||||
android:checkableBehavior="none">
|
||||
<item
|
||||
android:id="@+id/menu_settings"
|
||||
android:title="@string/settings" />
|
||||
<item
|
||||
android:id="@+id/menu_volunteer"
|
||||
android:title="@string/volunteer" />
|
||||
</group>
|
||||
</menu>
|
|
@ -6,5 +6,6 @@
|
|||
<dimen name="detail_card_view_margin_end">96dp</dimen>
|
||||
<dimen name="detail_card_view_margin_top">64dp</dimen>
|
||||
<dimen name="detail_card_view_margin_bottom">0dp</dimen>
|
||||
<dimen name="detail_fab_margin_end">20dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -10,11 +10,4 @@
|
|||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<!-- Styles -->
|
||||
|
||||
<style name="FloatingActionButton" parent="FloatingActionButtonBase">
|
||||
<item name="android:elevation">@dimen/fab_elevation</item>
|
||||
<item name="android:stateListAnimator">@animator/fab_state_list</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
|
@ -5,34 +5,6 @@
|
|||
<attr name="activatedBackgroundIndicator" format="reference"/>
|
||||
<attr name="recyclerViewStyle" format="reference"/>
|
||||
|
||||
<declare-styleable name="SlidingTabLayout">
|
||||
<attr name="indicatorColor" format="color"/>
|
||||
<attr name="indicatorHeight" format="dimension"/>
|
||||
<attr name="textColor" format="color|reference"/>
|
||||
<attr name="selectedTextColor" format="color"/>
|
||||
<attr name="contentInsetStart"/>
|
||||
<attr name="distributeEvenly" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
<style name="SlidingTabLayout" parent="android:Widget">
|
||||
<item name="indicatorColor">?attr/colorAccent</item>
|
||||
<item name="indicatorHeight">2dp</item>
|
||||
<item name="textColor">?android:textColorSecondary</item>
|
||||
<item name="selectedTextColor">?android:textColorPrimary</item>
|
||||
<item name="contentInsetStart">24dp</item>
|
||||
<item name="distributeEvenly">false</item>
|
||||
</style>
|
||||
|
||||
<declare-styleable name="ScrimInsetsFrameLayout">
|
||||
<attr name="insetForeground" format="color|reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ForegroundLinearLayout">
|
||||
<attr name="android:foreground"/>
|
||||
<attr name="android:foregroundGravity"/>
|
||||
<attr name="foregroundInsidePadding" format="boolean"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="PrimaryTextColors">
|
||||
<attr name="android:textColorPrimary"/>
|
||||
<attr name="android:textColorPrimaryInverse"/>
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<dimen name="main_menu_width">260dp</dimen>
|
||||
<dimen name="main_menu_header_height">128dp</dimen>
|
||||
<dimen name="main_menu_padding">16dp</dimen>
|
||||
<dimen name="main_menu_drawable_padding">32dp</dimen>
|
||||
<dimen name="main_menu_item_height">48dp</dimen>
|
||||
<dimen name="main_menu_footer_height">32dp</dimen>
|
||||
<dimen name="list_item_padding">8dp</dimen>
|
||||
<dimen name="content_margin">16dp</dimen>
|
||||
<dimen name="toolbar_elevation">8dp</dimen>
|
||||
<dimen name="schedule_column_width">360dp</dimen>
|
||||
<dimen name="detail_card_view_elevation">6dp</dimen>
|
||||
<!-- Enlarge the card view by 7dp left & right and 10dp top & bottom
|
||||
to compensate for the compatibility padding of the 6dp elevation -->
|
||||
<dimen name="detail_card_view_margin_start">353dp</dimen>
|
||||
<dimen name="detail_card_view_margin_end">89dp</dimen>
|
||||
<dimen name="detail_card_view_margin_top">54dp</dimen>
|
||||
<dimen name="detail_card_view_margin_bottom">-10dp</dimen>
|
||||
<dimen name="fab_diameter">56dp</dimen>
|
||||
<dimen name="fab_elevation">8dp</dimen>
|
||||
<dimen name="fab_press_translation_z">6dp</dimen>
|
||||
<!-- Enlarge the card view by 6dp left & right and 9dp top & bottom
|
||||
to compensate for the compatibility padding of the elevation -->
|
||||
<dimen name="detail_card_view_margin_start">354dp</dimen>
|
||||
<dimen name="detail_card_view_margin_end">90dp</dimen>
|
||||
<dimen name="detail_card_view_margin_top">55dp</dimen>
|
||||
<dimen name="detail_card_view_margin_bottom">-9dp</dimen>
|
||||
<dimen name="detail_fab_margin_end">8dp</dimen>
|
||||
|
||||
</resources>
|
|
@ -64,38 +64,12 @@
|
|||
<item name="android:scrollbars">vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Design.ScrimInsetsFrameLayout" parent="">
|
||||
<item name="insetForeground">#4000</item>
|
||||
</style>
|
||||
|
||||
<style name="MainMenuItem" parent="TextAppearance.AppCompat.Body2">
|
||||
<item name="android:background">@drawable/menu_item_background</item>
|
||||
<item name="android:focusable">true</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">@dimen/main_menu_item_height</item>
|
||||
<item name="android:gravity">start|center_vertical</item>
|
||||
<item name="android:paddingLeft">@dimen/main_menu_padding</item>
|
||||
<item name="android:paddingStart" tools:ignore="NewApi">@dimen/main_menu_padding</item>
|
||||
<item name="android:drawablePadding">@dimen/main_menu_drawable_padding</item>
|
||||
</style>
|
||||
|
||||
<style name="SlidingTabs" parent="SlidingTabLayout">
|
||||
<style name="Tabs" parent="Widget.Design.TabLayout">
|
||||
<item name="android:theme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
<item name="android:background">?attr/colorPrimary</item>
|
||||
<item name="indicatorColor">@android:color/white</item>
|
||||
<item name="tabIndicatorColor">@android:color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="FloatingActionButtonBase">
|
||||
<item name="android:layout_width">@dimen/fab_diameter</item>
|
||||
<item name="android:layout_height">@dimen/fab_diameter</item>
|
||||
<item name="android:background">@drawable/fab_background</item>
|
||||
<item name="android:scaleType">center</item>
|
||||
<item name="android:clickable">true</item>
|
||||
<item name="android:focusable">true</item>
|
||||
</style>
|
||||
|
||||
<style name="FloatingActionButton" parent="FloatingActionButtonBase"/>
|
||||
|
||||
<style name="SeparatorLine">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">1dp</item>
|
||||
|
|
Loading…
Reference in a new issue