Merge pull request #1071 from TebbeUbben/new-design

TabLayout + NavigationDrawer
This commit is contained in:
AdrianLxM 2018-06-04 23:53:42 +02:00 committed by GitHub
commit 4998ebae89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 364 additions and 665 deletions

View file

@ -32,11 +32,10 @@
android:icon="${appIcon}" android:icon="${appIcon}"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme.NoActionBar">
<activity android:name=".MainActivity"> <activity android:name=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
@ -171,7 +170,10 @@
android:name=".setupwizard.SetupWizardActivity" android:name=".setupwizard.SetupWizardActivity"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@style/AppTheme.SetupWizard" android:theme="@style/AppTheme.SetupWizard"
android:label="@string/title_activity_setup_wizard"></activity> android:label="@string/title_activity_setup_wizard" />
<activity android:name=".SingleFragmentActivity"
android:theme="@style/AppTheme" />
</application> </application>
</manifest> </manifest>

View file

@ -1,30 +1,35 @@
package info.nightscout.androidaps; package info.nightscout.androidaps;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.Toolbar;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.MenuInflater; import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
@ -37,7 +42,6 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.events.EventAppExit; import info.nightscout.androidaps.events.EventAppExit;
import info.nightscout.androidaps.events.EventFeatureRunning; import info.nightscout.androidaps.events.EventFeatureRunning;
import info.nightscout.androidaps.events.EventPreferenceChange;
import info.nightscout.androidaps.events.EventRefreshGui; import info.nightscout.androidaps.events.EventRefreshGui;
import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
@ -45,7 +49,6 @@ import info.nightscout.androidaps.plugins.Food.FoodPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock; import info.nightscout.androidaps.plugins.Overview.events.EventSetWakeLock;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin; import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.setupwizard.SetupWizardActivity; import info.nightscout.androidaps.setupwizard.SetupWizardActivity;
import info.nightscout.androidaps.tabs.SlidingTabLayout;
import info.nightscout.androidaps.tabs.TabPageAdapter; import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.AndroidPermission; import info.nightscout.utils.AndroidPermission;
import info.nightscout.utils.ImportExportPrefs; import info.nightscout.utils.ImportExportPrefs;
@ -55,13 +58,15 @@ import info.nightscout.utils.OKDialog;
import info.nightscout.utils.PasswordProtection; import info.nightscout.utils.PasswordProtection;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
public class MainActivity extends AppCompatActivity implements View.OnClickListener { public class MainActivity extends AppCompatActivity {
private static Logger log = LoggerFactory.getLogger(MainActivity.class); private static Logger log = LoggerFactory.getLogger(MainActivity.class);
ImageButton menuButton;
protected PowerManager.WakeLock mWakeLock; protected PowerManager.WakeLock mWakeLock;
private ActionBarDrawerToggle actionBarDrawerToggle;
private MenuItem pluginPreferencesMenuItem;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -71,16 +76,54 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
Iconify.with(new FontAwesomeModule()); Iconify.with(new FontAwesomeModule());
LocaleHelper.onCreate(this, "en"); LocaleHelper.onCreate(this, "en");
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
menuButton = (ImageButton) findViewById(R.id.overview_menuButton); setSupportActionBar(findViewById(R.id.toolbar));
menuButton.setOnClickListener(this); getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.open_navigation, R.string.close_navigation);
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false))); onStatusEvent(new EventSetWakeLock(SP.getBoolean("lockscreen", false)));
doMigrations(); doMigrations();
registerBus(); registerBus();
setUpTabs(false); setupTabs();
setupViews(false);
final ViewPager viewPager = findViewById(R.id.pager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
checkPluginPreferences(viewPager);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void checkPluginPreferences(ViewPager viewPager) {
if (pluginPreferencesMenuItem == null) return;
if (((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem()).getPreferencesId() != -1)
pluginPreferencesMenuItem.setEnabled(true);
else pluginPreferencesMenuItem.setEnabled(false);
}
@Override
public void onPostCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onPostCreate(savedInstanceState, persistentState);
actionBarDrawerToggle.syncState();
} }
@Override @Override
@ -127,39 +170,75 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
public void onStatusEvent(final EventRefreshGui ev) { public void onStatusEvent(final EventRefreshGui ev) {
String lang = SP.getString("language", "en"); String lang = SP.getString("language", "en");
LocaleHelper.setLocale(getApplicationContext(), lang); LocaleHelper.setLocale(getApplicationContext(), lang);
runOnUiThread(new Runnable() { runOnUiThread(() -> {
@Override if (ev.recreate) {
public void run() { recreate();
if (ev.recreate) { } else {
recreate(); try { // activity may be destroyed
} else { setupTabs();
try { // activity may be destroyed setupViews(true);
setUpTabs(true); } catch (IllegalStateException e) {
} catch (IllegalStateException e) { log.error("Unhandled exception", e);
log.error("Unhandled exception", e);
}
} }
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false);
if (lockScreen)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} }
boolean lockScreen = BuildConfig.NSCLIENTOLNY && SP.getBoolean("lockscreen", false);
if (lockScreen)
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
else
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}); });
} }
private void setUpTabs(boolean switchToLast) { private void setupViews(boolean switchToLast) {
TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this); TabPageAdapter pageAdapter = new TabPageAdapter(getSupportFragmentManager(), this);
NavigationView navigationView = findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(menuItem -> {
Log.d("asdasdasdsada", "ASFASFASFSFASF");
return true;
});
Menu menu = navigationView.getMenu();
menu.clear();
for (PluginBase p : MainApp.getPluginsList()) { for (PluginBase p : MainApp.getPluginsList()) {
pageAdapter.registerNewFragment(p); pageAdapter.registerNewFragment(p);
if (p.hasFragment() && !p.isFragmentVisible() && p.isEnabled(p.pluginDescription.getType())) {
MenuItem menuItem = menu.add(p.getName());
menuItem.setCheckable(true);
menuItem.setOnMenuItemClickListener(item -> {
Intent intent = new Intent(this, SingleFragmentActivity.class);
intent.putExtra("plugin", MainApp.getPluginsList().indexOf(p));
startActivity(intent);
return true;
});
}
} }
ViewPager mPager = (ViewPager) findViewById(R.id.pager); ViewPager mPager = findViewById(R.id.pager);
mPager.setAdapter(pageAdapter); mPager.setAdapter(pageAdapter);
SlidingTabLayout mTabs = (SlidingTabLayout) findViewById(R.id.tabs);
mTabs.setViewPager(mPager);
if (switchToLast) if (switchToLast)
mPager.setCurrentItem(pageAdapter.getCount() - 1, false); mPager.setCurrentItem(pageAdapter.getCount() - 1, false);
checkPluginPreferences(mPager);
}
private void setupTabs() {
ViewPager viewPager = findViewById(R.id.pager);
TabLayout normalTabs = findViewById(R.id.tabs_normal);
normalTabs.setupWithViewPager(viewPager, true);
TabLayout compactTabs = findViewById(R.id.tabs_compact);
compactTabs.setupWithViewPager(viewPager, true);
Toolbar toolbar = findViewById(R.id.toolbar);
if (SP.getBoolean("short_tabtitles", false)) {
normalTabs.setVisibility(View.GONE);
compactTabs.setVisibility(View.VISIBLE);
toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT, (int) getResources().getDimension(R.dimen.compact_height)));
} else {
normalTabs.setVisibility(View.VISIBLE);
compactTabs.setVisibility(View.GONE);
TypedValue typedValue = new TypedValue();
if (getTheme().resolveAttribute(R.attr.actionBarSize, typedValue, true)) {
toolbar.setLayoutParams(new LinearLayout.LayoutParams(Toolbar.LayoutParams.MATCH_PARENT,
TypedValue.complexToDimensionPixelSize(typedValue.data, getResources().getDisplayMetrics())));
}
}
} }
private void registerBus() { private void registerBus() {
@ -257,99 +336,96 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
@Override @Override
public void onClick(final View v) { public boolean onCreateOptionsMenu(Menu menu) {
final Activity activity = this; getMenuInflater().inflate(R.menu.menu_main, menu);
switch (v.getId()) { pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences);
case R.id.overview_menuButton: checkPluginPreferences(findViewById(R.id.pager));
PopupMenu popup = new PopupMenu(v.getContext(), v); return true;
MenuInflater inflater = popup.getMenuInflater(); }
inflater.inflate(R.menu.menu_main, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override
@Override public boolean onOptionsItemSelected(MenuItem item) {
public boolean onMenuItemClick(MenuItem item) { int id = item.getItemId();
int id = item.getItemId(); switch (id) {
switch (id) { case R.id.nav_preferences:
case R.id.nav_preferences: PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
PasswordProtection.QueryPassword(v.getContext(), R.string.settings_password, "settings_password", new Runnable() { Intent i = new Intent(this, PreferencesActivity.class);
@Override i.putExtra("id", -1);
public void run() { startActivity(i);
Intent i = new Intent(v.getContext(), PreferencesActivity.class); }, null);
i.putExtra("id", -1); return true;
startActivity(i); case R.id.nav_historybrowser:
} startActivity(new Intent(this, HistoryBrowseActivity.class));
}, null); return true;
break; case R.id.nav_setupwizard:
case R.id.nav_historybrowser: startActivity(new Intent(this, SetupWizardActivity.class));
startActivity(new Intent(v.getContext(), HistoryBrowseActivity.class)); return true;
break; case R.id.nav_resetdb:
case R.id.nav_setupwizard: new AlertDialog.Builder(this)
startActivity(new Intent(v.getContext(), SetupWizardActivity.class)); .setTitle(R.string.nav_resetdb)
break; .setMessage(R.string.reset_db_confirm)
case R.id.nav_resetdb: .setNegativeButton(android.R.string.cancel, null)
new AlertDialog.Builder(v.getContext()) .setPositiveButton(android.R.string.ok, (dialog, which) -> {
.setTitle(R.string.nav_resetdb) MainApp.getDbHelper().resetDatabases();
.setMessage(R.string.reset_db_confirm) // should be handled by Plugin-Interface and
.setNegativeButton(android.R.string.cancel, null) // additional service interface and plugin registry
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { FoodPlugin.getPlugin().getService().resetFood();
@Override TreatmentsPlugin.getPlugin().getService().resetTreatments();
public void onClick(DialogInterface dialog, int which) { })
MainApp.getDbHelper().resetDatabases(); .create()
// should be handled by Plugin-Interface and .show();
// additional service interface and plugin registry return true;
FoodPlugin.getPlugin().getService().resetFood(); case R.id.nav_export:
TreatmentsPlugin.getPlugin().getService().resetTreatments(); ImportExportPrefs.verifyStoragePermissions(this);
} ImportExportPrefs.exportSharedPreferences(this);
}) return true;
.create() case R.id.nav_import:
.show(); ImportExportPrefs.verifyStoragePermissions(this);
break; ImportExportPrefs.importSharedPreferences(this);
case R.id.nav_export: return true;
ImportExportPrefs.verifyStoragePermissions(activity); case R.id.nav_show_logcat:
ImportExportPrefs.exportSharedPreferences(activity); LogDialog.showLogcat(this);
break; return true;
case R.id.nav_import: case R.id.nav_about:
ImportExportPrefs.verifyStoragePermissions(activity); AlertDialog.Builder builder = new AlertDialog.Builder(this);
ImportExportPrefs.importSharedPreferences(activity); builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION);
break; if (Config.NSCLIENT || Config.G5UPLOADER)
case R.id.nav_show_logcat: builder.setIcon(R.mipmap.yellowowl);
LogDialog.showLogcat(v.getContext()); else
break; builder.setIcon(R.mipmap.blueowl);
case R.id.nav_about: String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext()); message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n";
builder.setTitle(MainApp.gs(R.string.app_name) + " " + BuildConfig.VERSION); message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName;
if (Config.NSCLIENT || Config.G5UPLOADER) if (MainApp.engineeringMode)
builder.setIcon(R.mipmap.yellowowl); message += "\n" + MainApp.gs(R.string.engineering_mode_enabled);
else message += MainApp.gs(R.string.about_link_urls);
builder.setIcon(R.mipmap.blueowl); final SpannableString messageSpanned = new SpannableString(message);
String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
message += "Flavor: " + BuildConfig.FLAVOR + BuildConfig.BUILD_TYPE + "\n"; builder.setMessage(messageSpanned);
message += MainApp.gs(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; builder.setPositiveButton(MainApp.gs(R.string.ok), null);
if (MainApp.engineeringMode) AlertDialog alertDialog = builder.create();
message += "\n" + MainApp.gs(R.string.engineering_mode_enabled); alertDialog.show();
message += MainApp.gs(R.string.about_link_urls); ((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
final SpannableString messageSpanned = new SpannableString(message); return true;
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS); case R.id.nav_exit:
builder.setMessage(messageSpanned); log.debug("Exiting");
builder.setPositiveButton(MainApp.gs(R.string.ok), null); MainApp.instance().stopKeepAliveService();
AlertDialog alertDialog = builder.create(); MainApp.bus().post(new EventAppExit());
alertDialog.show(); MainApp.closeDbHelper();
((TextView) alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); finish();
break; System.runFinalization();
case R.id.nav_exit: System.exit(0);
log.debug("Exiting"); return true;
MainApp.instance().stopKeepAliveService(); case R.id.nav_plugin_preferences:
MainApp.bus().post(new EventAppExit()); ViewPager viewPager = findViewById(R.id.pager);
MainApp.closeDbHelper(); final PluginBase plugin = ((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem());
finish(); PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
System.runFinalization(); Intent i = new Intent(this, PreferencesActivity.class);
System.exit(0); i.putExtra("id", plugin.getPreferencesId());
break; startActivity(i);
} }, null);
return false; return true;
}
});
popup.show();
break;
} }
return actionBarDrawerToggle.onOptionsItemSelected(item);
} }
} }

View file

@ -0,0 +1,59 @@
package info.nightscout.androidaps;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.tabs.TabPageAdapter;
import info.nightscout.utils.PasswordProtection;
public class SingleFragmentActivity extends AppCompatActivity {
private PluginBase plugin;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_fragment);
this.plugin = MainApp.getPluginsList().get(getIntent().getIntExtra("plugin", -1));
setTitle(plugin.getName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout,
Fragment.instantiate(this, plugin.pluginDescription.getFragmentClass())).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
else if (item.getItemId() == R.id.nav_plugin_preferences) {
PasswordProtection.QueryPassword(this, R.string.settings_password, "settings_password", () -> {
Intent i = new Intent(this, PreferencesActivity.class);
i.putExtra("id", plugin.getPreferencesId());
startActivity(i);
}, null);
return true;
}
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (plugin.getPreferencesId() != -1)
getMenuInflater().inflate(R.menu.menu_single_fragment, menu);
return super.onCreateOptionsMenu(menu);
}
}

View file

@ -87,9 +87,9 @@ public class ConfigBuilderPlugin extends PluginBase {
super(new PluginDescription() super(new PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.GENERAL)
.fragmentClass(ConfigBuilderFragment.class.getName()) .fragmentClass(ConfigBuilderFragment.class.getName())
.showInList(false) .showInList(true)
.alwaysEnabled(true) .alwaysEnabled(true)
.alwayVisible(true) .alwayVisible(false)
.pluginName(R.string.configbuilder) .pluginName(R.string.configbuilder)
.shortName(R.string.configbuilder_shortname) .shortName(R.string.configbuilder_shortname)
); );

View file

@ -1,322 +0,0 @@
package info.nightscout.androidaps.tabs;/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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.
*/
import android.content.Context;
import android.graphics.Typeface;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
import info.nightscout.androidaps.R;
/**
* To be used with ViewPager to provide a tab indicator component which give constant feedback as to
* the user's scroll progress.
* <p>
* To use the component, simply add it to your view hierarchy. Then in your
* {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
* {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
* <p>
* The colors can be customized in two ways. The first and simplest is to provide an array of colors
* via {@link #setSelectedIndicatorColors(int...)}. The
* alternative is via the {@link TabColorizer} interface which provides you complete control over
* which color is used for any individual position.
* <p>
* The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
* providing the layout ID of your custom layout.
*/
public class SlidingTabLayout extends HorizontalScrollView {
/**
* Allows complete control over the colors drawn in the tab layout. Set with
* {@link #setCustomTabColorizer(TabColorizer)}.
*/
public interface TabColorizer {
/**
* @return return the color of the indicator used when {@code position} is selected.
*/
int getIndicatorColor(int position);
}
private static final int TITLE_OFFSET_DIPS = 24;
private static final int TAB_VIEW_PADDING_DIPS = 9;
private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
private int mTitleOffset;
private int mTabViewLayoutId;
private int mTabViewTextViewId;
private boolean mDistributeEvenly;
private ViewPager mViewPager;
private SparseArray<String> mContentDescriptions = new SparseArray<String>();
private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
private 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);
mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
mTabStrip = new SlidingTabStrip(context);
addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
setBackgroundColor(context.getResources().getColor(R.color.tabBgColor));
}
/**
* Set the custom {@link TabColorizer} to be used.
*
* If you only require simple custmisation then you can use
* {@link #setSelectedIndicatorColors(int...)} to achieve
* similar effects.
*/
public void setCustomTabColorizer(TabColorizer tabColorizer) {
mTabStrip.setCustomTabColorizer(tabColorizer);
}
public void setDistributeEvenly(boolean distributeEvenly) {
mDistributeEvenly = distributeEvenly;
}
/**
* Sets the colors to be used for indicating the selected tab. These colors are treated as a
* circular array. Providing one color will mean that all tabs are indicated with the same color.
*/
public void setSelectedIndicatorColors(int... colors) {
mTabStrip.setSelectedIndicatorColors(colors);
}
/**
* Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
* required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
* that the layout can update it's scroll position correctly.
*
* @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
*/
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
mViewPagerPageChangeListener = listener;
}
/**
* 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(int layoutResId, int textViewId) {
mTabViewLayoutId = layoutResId;
mTabViewTextViewId = textViewId;
}
/**
* Sets the associated view pager. Note that the assumption here is that the pager content
* (number of tabs and tab titles) does not change after this call has been made.
*/
public void setViewPager(ViewPager viewPager) {
mTabStrip.removeAllViews();
mViewPager = viewPager;
if (viewPager != null) {
viewPager.setOnPageChangeListener(new InternalViewPagerListener());
populateTabStrip();
}
}
/**
* Create a default view to be used for tabs. This is called if a custom tab view is not set via
* {@link #setCustomTabView(int, int)}.
*/
protected TextView createDefaultTabView(Context context) {
TextView textView = new TextView(context);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
textView.setTypeface(Typeface.DEFAULT_BOLD);
textView.setLayoutParams(new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
TypedValue outValue = new TypedValue();
getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
outValue, true);
textView.setBackgroundResource(outValue.resourceId);
textView.setAllCaps(true);
int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
textView.setPadding(padding, padding, padding, padding);
return textView;
}
private void populateTabStrip() {
final PagerAdapter adapter = mViewPager.getAdapter();
final View.OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (mTabViewLayoutId != 0) {
// If there is a custom tab view layout id set, try and inflate it
tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
false);
tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
}
if (tabView == null) {
tabView = createDefaultTabView(getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
if (mDistributeEvenly) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) tabView.getLayoutParams();
lp.width = 0;
lp.weight = 1;
}
tabTitleView.setText(adapter.getPageTitle(i));
tabView.setOnClickListener(tabClickListener);
String desc = mContentDescriptions.get(i, null);
if (desc != null) {
tabView.setContentDescription(desc);
}
mTabStrip.addView(tabView);
if (i == mViewPager.getCurrentItem()) {
tabView.setSelected(true);
}
}
}
public void setContentDescription(int i, String desc) {
mContentDescriptions.put(i, desc);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mViewPager != null) {
scrollToTab(mViewPager.getCurrentItem(), 0);
}
}
private void scrollToTab(int tabIndex, int 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() + positionOffset;
if (tabIndex > 0 || positionOffset > 0) {
// If we're not at the first child and are mid-scroll, make sure we obey the offset
targetScrollX -= mTitleOffset;
}
scrollTo(targetScrollX, 0);
}
}
private 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);
View selectedTitle = mTabStrip.getChildAt(position);
int extraOffset = (selectedTitle != null)
? (int) (positionOffset * selectedTitle.getWidth())
: 0;
scrollToTab(position, extraOffset);
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
positionOffsetPixels);
}
}
@Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageScrollStateChanged(state);
}
}
@Override
public void onPageSelected(int position) {
if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
mTabStrip.onViewPagerPageChanged(position, 0f);
scrollToTab(position, 0);
}
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
mTabStrip.getChildAt(i).setSelected(position == i);
}
if (mViewPagerPageChangeListener != null) {
mViewPagerPageChangeListener.onPageSelected(position);
}
}
}
private class TabClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
for (int i = 0; i < mTabStrip.getChildCount(); i++) {
if (v == mTabStrip.getChildAt(i)) {
mViewPager.setCurrentItem(i);
return;
}
}
}
}
}

View file

@ -1,165 +0,0 @@
package info.nightscout.androidaps.tabs;/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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.
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
class SlidingTabStrip extends LinearLayout {
private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 0;
private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 3;
private final int mBottomBorderThickness;
private final Paint mBottomBorderPaint;
private final int mSelectedIndicatorThickness;
private final Paint mSelectedIndicatorPaint;
private int mSelectedPosition;
private float mSelectionOffset;
private SlidingTabLayout.TabColorizer mCustomTabColorizer;
private final SimpleTabColorizer mDefaultTabColorizer;
SlidingTabStrip(Context context) {
this(context, null);
}
SlidingTabStrip(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
final float density = getResources().getDisplayMetrics().density;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.colorForeground, outValue, true);
final int themeForegroundColor = outValue.data;
int defaultBottomBorderColor = setColorAlpha(themeForegroundColor,
DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
mDefaultTabColorizer = new SimpleTabColorizer();
mDefaultTabColorizer.setIndicatorColors(MainApp.gc(R.color.tabBgColorSelected));
mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
mBottomBorderPaint = new Paint();
mBottomBorderPaint.setColor(defaultBottomBorderColor);
mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
mSelectedIndicatorPaint = new Paint();
}
void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
mCustomTabColorizer = customTabColorizer;
invalidate();
}
void setSelectedIndicatorColors(int... colors) {
// Make sure that the custom colorizer is removed
mCustomTabColorizer = null;
mDefaultTabColorizer.setIndicatorColors(colors);
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();
final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
? mCustomTabColorizer
: mDefaultTabColorizer;
// Thick colored underline below the current selection
if (childCount > 0) {
View selectedTitle = getChildAt(mSelectedPosition);
int left = selectedTitle.getLeft();
int right = selectedTitle.getRight();
int color = tabColorizer.getIndicatorColor(mSelectedPosition);
if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
if (color != nextColor) {
color = blendColors(nextColor, color, mSelectionOffset);
}
// 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);
}
mSelectedIndicatorPaint.setColor(color);
canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
height, mSelectedIndicatorPaint);
}
// Thin underline along the entire bottom edge
canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
}
/**
* Set the alpha value of the {@code color} to be the given {@code alpha} value.
*/
private static int setColorAlpha(int color, byte alpha) {
return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
}
/**
* Blend {@code color1} and {@code color2} using the given ratio.
*
* @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
* 0.0 will return {@code color2}.
*/
private static int blendColors(int color1, int color2, float ratio) {
final float inverseRation = 1f - ratio;
float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
return Color.rgb((int) r, (int) g, (int) b);
}
private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
private int[] mIndicatorColors;
@Override
public final int getIndicatorColor(int position) {
return mIndicatorColors[position % mIndicatorColors.length];
}
void setIndicatorColors(int... colors) {
mIndicatorColors = colors;
}
}
}

View file

@ -39,6 +39,10 @@ public class TabPageAdapter extends FragmentStatePagerAdapter {
return Fragment.instantiate(context, visibleFragmentList.get(position).pluginDescription.getFragmentClass()); return Fragment.instantiate(context, visibleFragmentList.get(position).pluginDescription.getFragmentClass());
} }
public PluginBase getPluginAt(int position) {
return visibleFragmentList.get(position);
}
@Override @Override
public void finishUpdate(ViewGroup container) { public void finishUpdate(ViewGroup container) {
try{ try{

View file

@ -1,46 +1,59 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<RelativeLayout <android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:contentInsetEndWithActions="48dp"
app:contentInsetStartWithNavigation="48dp"
android:elevation="4dp">
<LinearLayout <android.support.design.widget.TabLayout
android:id="@+id/tabs_normal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:background="@android:color/transparent"
app:tabIndicatorColor="#FFFFFF"
app:tabMode="scrollable" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs_compact"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
app:tabMinWidth="0dp"
app:tabPadding="0dp"
app:tabIndicatorColor="#FFFFFF"
app:tabMode="scrollable" />
</android.support.v7.widget.Toolbar>
<info.nightscout.androidaps.tabs.SlidingTabLayout <android.support.v4.widget.DrawerLayout
android:id="@+id/tabs" android:id="@+id/drawer_layout"
android:layout_width="match_parent" android:layout_weight="1"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:layout_marginBottom="10dp" android:layout_height="0dp">
android:paddingEnd="30dp" />
<android.support.v4.view.ViewPager <android.support.v4.view.ViewPager
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent" />
android:layout_weight="1" />
</LinearLayout> <android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:itemBackground="?selectableItemBackground"
app:itemTextColor="#FFFFFF"
android:layout_gravity="start" />
</android.support.v4.widget.DrawerLayout>
<ImageButton </LinearLayout>
android:id="@+id/overview_menuButton"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:background="@color/tabBgColor"
android:paddingTop="5dp"
app:srcCompat="@drawable/ic_more_vert_black_24dp" />
</RelativeLayout>
</android.support.v4.widget.DrawerLayout>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

View file

@ -1,31 +1,45 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"> tools:context=".MainActivity">
<item <item
android:id="@+id/nav_preferences" android:id="@+id/nav_preferences"
app:showAsAction="never"
android:title="@string/nav_preferences" /> android:title="@string/nav_preferences" />
<item
android:id="@+id/nav_plugin_preferences"
app:showAsAction="never"
android:title="@string/nav_plugin_preferences" />
<item <item
android:id="@+id/nav_historybrowser" android:id="@+id/nav_historybrowser"
app:showAsAction="never"
android:title="@string/nav_historybrowser" /> android:title="@string/nav_historybrowser" />
<item <item
android:id="@+id/nav_setupwizard" android:id="@+id/nav_setupwizard"
app:showAsAction="never"
android:title="@string/nav_setupwizard" /> android:title="@string/nav_setupwizard" />
<item <item
android:id="@+id/nav_resetdb" android:id="@+id/nav_resetdb"
app:showAsAction="never"
android:title="@string/nav_resetdb" /> android:title="@string/nav_resetdb" />
<item <item
android:id="@+id/nav_export" android:id="@+id/nav_export"
app:showAsAction="never"
android:title="@string/nav_export" /> android:title="@string/nav_export" />
<item <item
android:id="@+id/nav_import" android:id="@+id/nav_import"
app:showAsAction="never"
android:title="@string/nav_import" /> android:title="@string/nav_import" />
<item <item
android:id="@+id/nav_show_logcat" android:id="@+id/nav_show_logcat"
app:showAsAction="never"
android:title="@string/nav_show_logcat" /> android:title="@string/nav_show_logcat" />
<item <item
android:id="@+id/nav_about" android:id="@+id/nav_about"
app:showAsAction="never"
android:title="@string/nav_about" /> android:title="@string/nav_about" />
<item <item
android:id="@+id/nav_exit" android:id="@+id/nav_exit"
app:showAsAction="never"
android:title="@string/nav_exit" /> android:title="@string/nav_exit" />
</menu> </menu>

View file

@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<item
android:id="@+id/nav_plugin_preferences"
app:showAsAction="ifRoom"
android:icon="@drawable/ic_settings"
android:title="@string/nav_plugin_preferences" />
</menu>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.base">
</style>
</resources>

View file

@ -37,9 +37,9 @@
<color name="tempTargetDisabledBackground">#303F9F</color> <color name="tempTargetDisabledBackground">#303F9F</color>
<color name="colorPrimary">#3F51B5</color> <color name="colorPrimary">#212121</color>
<color name="colorPrimaryDark">#303F9F</color> <color name="colorPrimaryDark">#000000</color>
<color name="colorAccent">#FF4081</color> <color name="colorAccent">#009688</color>
<color name="colorInitializingBorder">#00695c</color> <color name="colorInitializingBorder">#00695c</color>
<color name="cardColorBackground">#121212</color> <color name="cardColorBackground">#121212</color>

View file

@ -2,4 +2,5 @@
<!-- Default screen margins, per the Android Design guidelines. --> <!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="compact_height">30dp</dimen>
</resources> </resources>

View file

@ -1089,4 +1089,7 @@
<string name="request">Request</string> <string name="request">Request</string>
<string name="insulinsourcesetup">Configure Insulin plugin</string> <string name="insulinsourcesetup">Configure Insulin plugin</string>
<string name="exit">Exit</string> <string name="exit">Exit</string>
<string name="open_navigation">Open navigation</string>
<string name="close_navigation">Close navigation</string>
<string name="nav_plugin_preferences">Plugin preferences</string>
</resources> </resources>

View file

@ -1,8 +1,12 @@
<resources> <resources>
<!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat">
<style name="AppTheme" parent="android:Theme.Material"> <item name="colorPrimary">@color/colorPrimary</item>
<!-- Customize your theme here. --> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>