From 06c8b06febe431c4f9a9b6e0b3a6715e32e5c12f Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Sun, 16 Oct 2016 02:43:38 +0200 Subject: [PATCH] Reimplemented the settings to allow customization with colors --- app/build.gradle | 3 +- app/src/main/AndroidManifest.xml | 5 + .../activity/AboutActivity.java | 2 +- .../activity/MainActivity.java | 16 +- .../activity/SettingsActivity.java | 301 +---------------- .../activity/ThemedActivity.java | 2 +- .../diaspora_android/data/AppSettings.java | 101 +++++- .../fragment/SettingsFragment__Debugging.java | 102 ++++++ .../SettingsFragment__NavigationSlider.java | 177 ++++++++++ .../fragment/SettingsFragment__Overview.java | 318 ++++++++++++++++++ .../fragment/SettingsFragment__Proxy.java | 172 ++++++++++ .../SettingsFragment__ThemeColors.java | 176 ++++++++++ .../fragment/ThemedSettingsFragment.java | 23 ++ .../util/theming/ThemeHelper.java | 59 +++- app/src/main/res/drawable/circle.xml | 4 + ...gs__activity.xml => settings_activity.xml} | 2 +- .../settings_activity__dialog_font_size.xml | 6 + .../settings_activity__dialog_proxy.xml | 5 + .../layout/settings_activity__overview.xml | 67 ++++ .../settings_activity__section_appearance.xml | 200 +++++++++++ .../settings_activity__section_more.xml | 33 ++ .../settings_activity__section_network.xml | 85 +++++ ...ettings_activity__section_pod_settings.xml | 93 +++++ ...ettings_activity__subsection_debugging.xml | 97 ++++++ ...ttings_activity__subsection_nav_slider.xml | 266 +++++++++++++++ .../settings_activity__subsection_proxy.xml | 142 ++++++++ .../settings_activity__subsection_theming.xml | 104 ++++++ app/src/main/res/values/color.xml | 2 + app/src/main/res/values/dimens.xml | 5 + build.gradle | 2 +- 30 files changed, 2270 insertions(+), 300 deletions(-) create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Debugging.java create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__NavigationSlider.java create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Overview.java create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Proxy.java create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__ThemeColors.java create mode 100644 app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedSettingsFragment.java create mode 100644 app/src/main/res/drawable/circle.xml rename app/src/main/res/layout/{settings__activity.xml => settings_activity.xml} (96%) create mode 100644 app/src/main/res/layout/settings_activity__dialog_font_size.xml create mode 100644 app/src/main/res/layout/settings_activity__dialog_proxy.xml create mode 100644 app/src/main/res/layout/settings_activity__overview.xml create mode 100644 app/src/main/res/layout/settings_activity__section_appearance.xml create mode 100644 app/src/main/res/layout/settings_activity__section_more.xml create mode 100644 app/src/main/res/layout/settings_activity__section_network.xml create mode 100644 app/src/main/res/layout/settings_activity__section_pod_settings.xml create mode 100644 app/src/main/res/layout/settings_activity__subsection_debugging.xml create mode 100644 app/src/main/res/layout/settings_activity__subsection_nav_slider.xml create mode 100644 app/src/main/res/layout/settings_activity__subsection_proxy.xml create mode 100644 app/src/main/res/layout/settings_activity__subsection_theming.xml diff --git a/app/build.gradle b/app/build.gradle index e580b2dc..4d4074c2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,7 +50,8 @@ dependencies { compile 'com.android.support:appcompat-v7:24.2.1' compile 'com.android.support:design:24.1.0' //Don't update. Broken up to 24.2.1 compile 'com.android.support:support-v4:24.2.1' - compile "com.android.support:customtabs:24.2.1" + compile 'com.android.support:customtabs:24.2.1' + compile 'com.android.support:cardview-v7:24.2.1' // More libraries compile 'com.jakewharton:butterknife:8.0.1' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1c0486e4..a5c0ec2f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,6 +33,11 @@ android:label="@string/about_activity__title_about_app" android:theme="@style/DiasporaLight.NoActionBar"/> + + . - */ package com.github.dfa.diaspora_android.activity; import android.app.AlarmManager; -import android.app.AlertDialog; import android.app.PendingIntent; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Build; import android.os.Bundle; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; import android.support.design.widget.AppBarLayout; import android.support.v7.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.MenuItem; import android.view.View; -import android.view.Window; -import android.widget.FrameLayout; -import android.widget.TextView; -import com.github.dfa.diaspora_android.App; import com.github.dfa.diaspora_android.R; -import com.github.dfa.diaspora_android.data.AppSettings; -import com.github.dfa.diaspora_android.ui.IntellihideToolbarActivityListener; +import com.github.dfa.diaspora_android.fragment.SettingsFragment__Overview; import com.github.dfa.diaspora_android.util.AppLog; -import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; import com.github.dfa.diaspora_android.util.ProxyHandler; -import com.github.dfa.diaspora_android.util.theming.ColorPalette; import com.github.dfa.diaspora_android.util.theming.ThemeHelper; import butterknife.BindView; import butterknife.ButterKnife; -import uz.shift.colorpicker.LineColorPicker; -import uz.shift.colorpicker.OnColorChangedListener; + /** - * @author vanitas + * SettingsActivity + * Created by vanitas on 15.10.16. */ -public class SettingsActivity extends ThemedActivity implements IntellihideToolbarActivityListener { + +public class SettingsActivity extends ThemedActivity { + + //Toolbar @BindView(R.id.settings__appbar) protected AppBarLayout appBarLayout; @@ -64,12 +35,11 @@ public class SettingsActivity extends ThemedActivity implements IntellihideToolb private ProxyHandler.ProxySettings oldProxySettings; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.settings__activity); + public void onCreate(Bundle b) { + super.onCreate(b); + this.setContentView(R.layout.settings_activity); ButterKnife.bind(this); + toolbar.setTitle(R.string.settings); setSupportActionBar(toolbar); toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24px)); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @@ -79,255 +49,16 @@ public class SettingsActivity extends ThemedActivity implements IntellihideToolb } }); oldProxySettings = getAppSettings().getProxySettings(); - getFragmentManager().beginTransaction().replace(R.id.settings__fragment_container, new SettingsFragment()).commit(); + getSupportFragmentManager().beginTransaction().replace( + R.id.settings__fragment_container, new SettingsFragment__Overview(), SettingsFragment__Overview.TAG).commit(); } @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case android.R.id.home: - onBackPressed(); - return true; - default: - return super.onOptionsItemSelected(menuItem); - } - } - - @Override - protected void applyColorToViews() { + public void applyColorToViews() { + //Toolbar ThemeHelper.updateToolbarColor(toolbar); } - @Override - public void enableToolbarHiding() { - AppLog.d(this, "Enable Intellihide"); - AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); - //scroll|enterAlways|snap - params.setScrollFlags(toolbarDefaultScrollFlags); - appBarLayout.setExpanded(true, true); - } - - @Override - public void disableToolbarHiding() { - AppLog.d(this, "Disable Intellihide"); - AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams(); - params.setScrollFlags(0); // clear all scroll flags - appBarLayout.setExpanded(true, true); - } - - public static class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private SharedPreferences sharedPreferences; - - public void onCreate(Bundle savedInstances) { - super.onCreate(savedInstances); - getPreferenceManager().setSharedPreferencesName("app"); - addPreferencesFromResource(R.xml.preferences); - sharedPreferences = getPreferenceScreen().getSharedPreferences(); - sharedPreferences.registerOnSharedPreferenceChangeListener(this); - setPreferenceSummaries(); - sharedPreferences.edit().putBoolean(getString(R.string.pref_key__proxy_was_enabled), - sharedPreferences.getBoolean(getString(R.string.pref_key__http_proxy_enabled), false)).apply(); - } - - private void setPreferenceSummaries() { - String[] editTextKeys = new String[]{ - getString(R.string.pref_key__http_proxy_host), getString(R.string.pref_key__http_proxy_port) - }; - for (String key : editTextKeys) { - EditTextPreference p = (EditTextPreference) findPreference(key); - p.setSummary(p.getText()); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - updatePreference(findPreference(key)); - if(isAdded()) { - if (key.equals(getString(R.string.pref_key__intellihide_toolbars))) { - if (sharedPreferences.getBoolean(getString(R.string.pref_key__intellihide_toolbars), false)) { - ((SettingsActivity) getActivity()).enableToolbarHiding(); - } else { - ((SettingsActivity) getActivity()).disableToolbarHiding(); - } - } - } - } - - private void updatePreference(Preference preference) { - if (preference == null) { - return; - } - if (preference instanceof EditTextPreference) { - EditTextPreference textPref = (EditTextPreference) preference; - textPref.setSummary(textPref.getText()); - return; - } - if (preference instanceof ListPreference) { - ListPreference listPref = (ListPreference) preference; - listPref.setSummary(listPref.getEntry()); - } - } - - @Override - public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) { - App app = ((App) getActivity().getApplication()); - AppSettings appSettings = app.getSettings(); - if (Build.VERSION.SDK_INT >= 21) { - if (preference instanceof PreferenceScreen && ((PreferenceScreen) preference).getDialog() != null) { - Window window = ((PreferenceScreen) preference).getDialog().getWindow(); - if (window != null) { - window.setStatusBarColor(ThemeHelper.getPrimaryDarkColor()); - } - } - } - - Intent intent = new Intent(getActivity(), MainActivity.class); - DiasporaUrlHelper diasporaUrlHelper = new DiasporaUrlHelper(app.getSettings()); - - switch (preference.getTitleRes()) { - case R.string.pref_title__primary_color: { - showColorPickerDialog(1); - intent = null; - break; - } - case R.string.pref_title__accent_color: { - showColorPickerDialog(2); - intent = null; - break; - } - case R.string.pref_title__personal_settings: { - intent.setAction(MainActivity.ACTION_OPEN_URL); - intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getPersonalSettingsUrl()); - break; - } - case R.string.pref_title__manage_tags: { - intent.setAction(MainActivity.ACTION_OPEN_URL); - intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getManageTagsUrl()); - break; - } - case R.string.pref_title__manage_contacts: { - intent.setAction(MainActivity.ACTION_OPEN_URL); - intent.putExtra(MainActivity.URL_MESSAGE, diasporaUrlHelper.getManageContactsUrl()); - break; - } - case R.string.pref_title__change_account: { - new AlertDialog.Builder(getActivity()) - .setTitle(getString(R.string.confirmation)) - .setMessage(getString(R.string.pref_warning__change_account)) - .setNegativeButton(android.R.string.no, null) - .setPositiveButton(android.R.string.yes, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - Intent intent = new Intent(getActivity(), MainActivity.class); - intent.setAction(MainActivity.ACTION_CHANGE_ACCOUNT); - startActivity(intent); - getActivity().finish(); - } - }) - .show(); - return true; - } - case R.string.pref_title__http_proxy_load_tor_preset: { - ((EditTextPreference) findPreference(getString(R.string.pref_key__http_proxy_host))).setText("127.0.0.1"); - ((EditTextPreference) findPreference(getString(R.string.pref_key__http_proxy_port))).setText("8118"); - return true; - } - - case R.string.pref_title__clear_cache: { - intent.setAction(MainActivity.ACTION_CLEAR_CACHE); - break; - } - - default: { - intent = null; - break; - } - } - if (intent != null) { - startActivity(intent); - getActivity().finish(); - return true; - } - return super.onPreferenceTreeClick(screen, preference); - } - - /** - * Show a colorPicker Dialog - * - * @param type 1 -> Primary Color, 2 -> Accent Color - */ - public void showColorPickerDialog(final int type) { - final AppSettings appSettings = ((App) getActivity().getApplication()).getSettings(); - final Context context = getActivity(); - - //Inflate dialog layout - LayoutInflater inflater = getActivity().getLayoutInflater(); - View dialogLayout = inflater.inflate(R.layout.color_picker__dialog, null); - final android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(context); - builder.setView(dialogLayout); - - final FrameLayout titleBackground = (FrameLayout) dialogLayout.findViewById(R.id.color_picker_dialog__title_background); - final TextView title = (TextView) dialogLayout.findViewById(R.id.color_picker_dialog__title); - final LineColorPicker base = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_dialog__base_picker); - final LineColorPicker shade = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_dialog__shade_picker); - - title.setText(type == 1 ? R.string.pref_title__primary_color : R.string.pref_title__accent_color); - title.setTextColor(getResources().getColor(R.color.white)); - final int[] current = (type == 1 ? appSettings.getPrimaryColorSettings() : appSettings.getAccentColorSettings()); - base.setColors((type == 1 ? ColorPalette.getBaseColors(context) : ColorPalette.getAccentColors(context))); - base.setSelectedColor(current[0]); - shade.setColors(ColorPalette.getColors(context, current[0])); - shade.setSelectedColor(current[1]); - titleBackground.setBackgroundColor(shade.getColor()); - base.setOnColorChangedListener(new OnColorChangedListener() { - @Override - public void onColorChanged(int i) { - AppLog.d(this, "Selected Base color changed: " + i); - shade.setColors(ColorPalette.getColors(context, i)); - titleBackground.setBackgroundColor(i); - if (i == current[0]) { - shade.setSelectedColor(current[1]); - titleBackground.setBackgroundColor(shade.getColor()); - } - } - }); - shade.setOnColorChangedListener(new OnColorChangedListener() { - @Override - public void onColorChanged(int i) { - titleBackground.setBackgroundColor(i); - } - }); - - //Build dialog - builder - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (type == 1) { - appSettings.setPrimaryColorSettings(base.getColor(), shade.getColor()); - if (Build.VERSION.SDK_INT >= 21) { - getActivity().getWindow().setStatusBarColor(ThemeHelper.getPrimaryDarkColor()); - } - ((ThemedActivity) getActivity()).applyColorToViews(); - } else { - appSettings.setAccentColorSettings(base.getColor(), shade.getColor()); - } - } - }).show(); - } - } - - @Override - protected void onPause() { - super.onPause(); - - // Reset logging - AppSettings settings = new AppSettings(getApplicationContext()); - AppLog.setLoggingEnabled(settings.isLoggingEnabled()); - AppLog.setLoggingSpamEnabled(settings.isLoggingSpamEnabled()); - } - @Override protected void onStop() { ProxyHandler.ProxySettings newProxySettings = getAppSettings().getProxySettings(); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/ThemedActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/ThemedActivity.java index aba3c1c0..301469f6 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/ThemedActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/ThemedActivity.java @@ -49,7 +49,7 @@ public abstract class ThemedActivity extends AppCompatActivity { applyColorToViews(); } - protected abstract void applyColorToViews(); + public abstract void applyColorToViews(); /** * Update color of the status bar diff --git a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java index 6c50b176..c593d0cf 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java @@ -111,6 +111,10 @@ public class AppSettings { return getBoolean(prefApp, R.string.pref_key__load_images, true); } + public void setLoadImages(boolean b) { + setBool(prefApp, R.string.pref_key__load_images, b); + } + public int getMinimumFontSize() { switch (getString(prefApp, R.string.pref_key__font_size, "")) { case "huge": @@ -125,6 +129,37 @@ public class AppSettings { } } + public String getMinimumFontSizeString() { + String[] values = context.getResources().getStringArray(R.array.pref_entries_values__font_size); + String[] titles = context.getResources().getStringArray(R.array.pref_entries__font_size); + String current = getString(prefApp, R.string.pref_key__font_size, "normal"); + for(int i=0; i adapterView, View view, int i, long l) { + getAppSettings().setMinimumFontSizeIndex(i); + hintFontSize.setText(getAppSettings().getMinimumFontSizeString()); + dialog.dismiss(); + } + }); + dialog.show(); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + /** Appearance */ + case R.id.settings_activity__theme_colors: + getFragmentManager().beginTransaction() + .addToBackStack(null) + .replace(R.id.settings__fragment_container, new SettingsFragment__ThemeColors(), SettingsFragment__ThemeColors.TAG).commit(); + break; + case R.id.settings_activity__navigation_slider: + getFragmentManager().beginTransaction().addToBackStack(null) + .replace(R.id.settings__fragment_container, new SettingsFragment__NavigationSlider(), SettingsFragment__NavigationSlider.TAG).commit(); + break; + case R.id.settings_activity__font_size: + showFontSizeDialog(); + break; + case R.id.settings_activity__intellihide_toolbars: + case R.id.settings_activity__intellihide_toolbars_checkbox: + checkboxIntellihide.setChecked(!getAppSettings().isIntellihideToolbars()); + getAppSettings().setIntellihideToolbars(!getAppSettings().isIntellihideToolbars()); + break; + case R.id.settings_activity__extended_notifications: + case R.id.settings_activity__extended_notifications_checkbox: + checkboxExtendedNotifications.setChecked(!getAppSettings().isExtendedNotifications()); + getAppSettings().setExtendedNotifications(!getAppSettings().isExtendedNotifications()); + break; + case R.id.settings_activity__append_shared_via_app: + case R.id.settings_activity__append_shared_via_app_checkbox: + checkboxAppendSharedViaApp.setChecked(!getAppSettings().isAppendSharedViaApp()); + getAppSettings().setAppendSharedViaApp(!getAppSettings().isAppendSharedViaApp()); + break; + case R.id.settings_activity__chrome_custom_tabs: + case R.id.settings_activity__chrome_custom_tabs_checkbox: + checkboxCustomTabs.setChecked(!getAppSettings().isChromeCustomTabsEnabled()); + getAppSettings().setChromeCustomTabsEnabled(!getAppSettings().isChromeCustomTabsEnabled()); + break; + /** Pod Settings */ + case R.id.settings_activity__personal_settings: { + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.setAction(MainActivity.ACTION_OPEN_URL); + intent.putExtra(MainActivity.URL_MESSAGE, urls.getPersonalSettingsUrl()); + startActivity(intent); + getActivity().finish(); + break; + } + case R.id.settings_activity__manage_tags: { + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.setAction(MainActivity.ACTION_OPEN_URL); + intent.putExtra(MainActivity.URL_MESSAGE, urls.getManageTagsUrl()); + startActivity(intent); + getActivity().finish(); + break; + } + case R.id.settings_activity__manage_contacts: { + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.setAction(MainActivity.ACTION_OPEN_URL); + intent.putExtra(MainActivity.URL_MESSAGE, urls.getManageContactsUrl()); + startActivity(intent); + getActivity().finish(); + break; + } + case R.id.settings_activity__change_account: { + new android.app.AlertDialog.Builder(getActivity()) + .setTitle(getString(R.string.confirmation)) + .setMessage(getString(R.string.pref_warning__change_account)) + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.setAction(MainActivity.ACTION_CHANGE_ACCOUNT); + startActivity(intent); + getActivity().finish(); + } + }) + .show(); + } + /** Network */ + case R.id.settings_activity__load_images: + case R.id.settings_activity__load_images_checkbox: + checkboxLoadImages.setChecked(!getAppSettings().isLoadImages()); + getAppSettings().setLoadImages(!getAppSettings().isLoadImages()); + break; + case R.id.settings_activity__clear_cache: { + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.setAction(MainActivity.ACTION_CLEAR_CACHE); + getActivity().sendBroadcast(intent); + getActivity().finish(); + break; + } + case R.id.settings_activity__proxy_settings: + getFragmentManager().beginTransaction().addToBackStack(null) + .replace(R.id.settings__fragment_container, new SettingsFragment__Proxy(), SettingsFragment__Proxy.TAG).commit(); + break; + /** More */ + case R.id.settings_activity__debugging: + getFragmentManager().beginTransaction().addToBackStack(null) + .replace(R.id.settings__fragment_container, new SettingsFragment__Debugging(), SettingsFragment__Debugging.TAG).commit(); + break; + } + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Proxy.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Proxy.java new file mode 100644 index 00000000..c720d502 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__Proxy.java @@ -0,0 +1,172 @@ +package com.github.dfa.diaspora_android.fragment; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v7.app.AlertDialog; +import android.text.InputType; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.github.dfa.diaspora_android.R; +import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * SettingsFragment that contains some proxy related settings + * Created by vanitas on 16.10.16. + */ + +public class SettingsFragment__Proxy extends ThemedSettingsFragment { + public static final String TAG = "com.github.dfa.diaspora_android.SettingsFragment__Proxy"; + + @BindView(R.id.settings_activity__header_network__proxy) + protected TextView titleProxy; + + @BindView(R.id.settings_activity__proxy_activated) + protected RelativeLayout optionProxyActivated; + + @BindView(R.id.settings_activity__proxy_activated_checkbox) + protected CheckBox checkboxProxyActivated; + + @BindView(R.id.settings_activity__proxy_host) + protected LinearLayout optionProxyHost; + + @BindView(R.id.settings_activity__proxy_host_hint) + protected TextView hintProxyHost; + + @BindView(R.id.settings_activity__proxy_port) + protected LinearLayout optionProxyPort; + + @BindView(R.id.settings_activity__proxy_port_hint) + protected TextView hintProxyPort; + + @BindView(R.id.settings_activity__proxy_orbot_preset) + protected RelativeLayout optionProxyOrbotPreset; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + AppLog.d(this, "onCreateView()"); + View layout = inflater.inflate(R.layout.settings_activity__subsection_proxy, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateTitleColor(titleProxy); + ThemeHelper.updateCheckBoxColor(checkboxProxyActivated); + optionProxyHost.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + optionProxyPort.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + optionProxyOrbotPreset.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + } + + @Override + protected void applySettingsToViews() { + checkboxProxyActivated.setChecked(getAppSettings().isProxyEnabled()); + optionProxyHost.setEnabled(getAppSettings().isProxyEnabled()); + hintProxyHost.setText(getAppSettings().getProxyHost()); + optionProxyPort.setEnabled(getAppSettings().isProxyEnabled()); + hintProxyPort.setText(""+getAppSettings().getProxyPort()); + optionProxyOrbotPreset.setEnabled(getAppSettings().isProxyEnabled()); + } + + @Override + protected void setOnClickListenersOnViews() { + optionProxyActivated.setOnClickListener(this); + checkboxProxyActivated.setOnClickListener(this); + optionProxyHost.setOnClickListener(this); + optionProxyPort.setOnClickListener(this); + optionProxyOrbotPreset.setOnClickListener(this); + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.settings_activity__proxy_activated: + case R.id.settings_activity__proxy_activated_checkbox: + boolean proxyEnabled = !getAppSettings().isProxyEnabled(); + checkboxProxyActivated.setChecked(proxyEnabled); + getAppSettings().setProxyEnabled(proxyEnabled); + optionProxyHost.setEnabled(proxyEnabled); + optionProxyPort.setEnabled(proxyEnabled); + optionProxyOrbotPreset.setEnabled(proxyEnabled); + optionProxyHost.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + optionProxyPort.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + optionProxyOrbotPreset.setVisibility(getAppSettings().isProxyEnabled() ? View.VISIBLE : View.GONE); + break; + case R.id.settings_activity__proxy_host: + showProxyHostDialog(); + break; + case R.id.settings_activity__proxy_port: + showProxyPortDialog(); + break; + case R.id.settings_activity__proxy_orbot_preset: + final String presetHost = "localhost"; + final int presetPort = 8118; + getAppSettings().setProxyHttpHost(presetHost); + hintProxyHost.setText(presetHost); + getAppSettings().setProxyHttpPort(presetPort); + hintProxyPort.setText(""+presetPort); + break; + } + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } + + protected void showProxyHostDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + final EditText input = (EditText) getLayoutInflater(null).inflate(R.layout.settings_activity__dialog_proxy, null, false); + input.setInputType(InputType.TYPE_CLASS_TEXT); + input.setText(getAppSettings().getProxyHost()); + ThemeHelper.updateEditTextColor(input); + builder.setTitle(R.string.pref_title__http_proxy_host) + .setView(input).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + getAppSettings().setProxyHttpHost(input.getText().toString()); + hintProxyHost.setText(input.getText()); + } + }).setNegativeButton(android.R.string.cancel, null).show(); + } + + protected void showProxyPortDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + final EditText input = (EditText) getLayoutInflater(null).inflate(R.layout.settings_activity__dialog_proxy, null, false); + input.setInputType(InputType.TYPE_CLASS_NUMBER); + input.setText(""+getAppSettings().getProxyPort()); + ThemeHelper.updateEditTextColor(input); + builder.setTitle(R.string.pref_title__http_proxy_port) + .setView(input).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + getAppSettings().setProxyHttpPort(Integer.parseInt(input.getText().toString())); + hintProxyPort.setText(input.getText()); + } + }).setNegativeButton(android.R.string.cancel, null).show(); + } + +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__ThemeColors.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__ThemeColors.java new file mode 100644 index 00000000..f2e82803 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/SettingsFragment__ThemeColors.java @@ -0,0 +1,176 @@ +package com.github.dfa.diaspora_android.fragment; + +import android.content.Context; +import android.content.DialogInterface; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.github.dfa.diaspora_android.App; +import com.github.dfa.diaspora_android.R; +import com.github.dfa.diaspora_android.activity.ThemedActivity; +import com.github.dfa.diaspora_android.data.AppSettings; +import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.theming.ColorPalette; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; + +import butterknife.BindView; +import butterknife.ButterKnife; +import uz.shift.colorpicker.LineColorPicker; +import uz.shift.colorpicker.OnColorChangedListener; + +/** + * SettingsFragment that contains Theme and Color related settings + * Created by vanitas on 15.10.16. + */ + +public class SettingsFragment__ThemeColors extends ThemedSettingsFragment { + public static final String TAG = "com.github.dfa.diaspora_android.SettingsFragment__ThemeColors"; + + @BindView(R.id.settings_activity__header_appearance__theme_and_colors) + protected TextView titleThemeColors; + + @BindView(R.id.settings_activity__theme_colors__primary_color) + protected RelativeLayout optionPrimaryColor; + + @BindView(R.id.settings_activity__theme_colors__primary_color__preview) + protected ImageView previewPrimaryColor; + + @BindView(R.id.settings_activity__theme_colors__accent_color) + protected RelativeLayout optionAccentColor; + + @BindView(R.id.settings_activity__theme_colors__accent_color__preview) + protected ImageView previewAccentColor; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + AppLog.d(this, "onCreateView()"); + View layout = inflater.inflate(R.layout.settings_activity__subsection_theming, container, false); + ButterKnife.bind(this, layout); + return layout; + } + + protected void applySettingsToViews() { + ThemeHelper.updatePrimaryColorPreview(previewPrimaryColor); + ThemeHelper.updateAccentColorPreview(previewAccentColor); + } + + protected void setOnClickListenersOnViews() { + optionPrimaryColor.setOnClickListener(this); + previewPrimaryColor.setOnClickListener(this); + optionAccentColor.setOnClickListener(this); + previewAccentColor.setOnClickListener(this); + } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateTitleColor(titleThemeColors); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.settings_activity__theme_colors__primary_color: + case R.id.settings_activity__theme_colors__primary_color__preview: + showColorPickerDialog(1); + break; + case R.id.settings_activity__theme_colors__accent_color: + case R.id.settings_activity__theme_colors__accent_color__preview: + showColorPickerDialog(2); + break; + } + } + + /** + * Show a colorPicker Dialog + * + * @param type 1 -> Primary Color, 2 -> Accent Color + */ + public void showColorPickerDialog(final int type) { + final AppSettings appSettings = ((App) getActivity().getApplication()).getSettings(); + final Context context = getActivity(); + + //Inflate dialog layout + LayoutInflater inflater = getActivity().getLayoutInflater(); + View dialogLayout = inflater.inflate(R.layout.color_picker__dialog, null); + final android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(context); + builder.setView(dialogLayout); + + final FrameLayout titleBackground = (FrameLayout) dialogLayout.findViewById(R.id.color_picker_dialog__title_background); + final TextView title = (TextView) dialogLayout.findViewById(R.id.color_picker_dialog__title); + final LineColorPicker base = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_dialog__base_picker); + final LineColorPicker shade = (LineColorPicker) dialogLayout.findViewById(R.id.color_picker_dialog__shade_picker); + + title.setText(type == 1 ? R.string.pref_title__primary_color : R.string.pref_title__accent_color); + title.setTextColor(getResources().getColor(R.color.white)); + final int[] current = (type == 1 ? appSettings.getPrimaryColorSettings() : appSettings.getAccentColorSettings()); + base.setColors((type == 1 ? ColorPalette.getBaseColors(context) : ColorPalette.getAccentColors(context))); + base.setSelectedColor(current[0]); + shade.setColors(ColorPalette.getColors(context, current[0])); + shade.setSelectedColor(current[1]); + titleBackground.setBackgroundColor(shade.getColor()); + base.setOnColorChangedListener(new OnColorChangedListener() { + @Override + public void onColorChanged(int i) { + AppLog.d(this, "Selected Base color changed: " + i); + shade.setColors(ColorPalette.getColors(context, i)); + titleBackground.setBackgroundColor(i); + if (i == current[0]) { + shade.setSelectedColor(current[1]); + titleBackground.setBackgroundColor(shade.getColor()); + } else { + shade.setSelectedColor(i); + } + } + }); + shade.setOnColorChangedListener(new OnColorChangedListener() { + @Override + public void onColorChanged(int i) { + titleBackground.setBackgroundColor(i); + } + }); + + //Build dialog + builder + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (type == 1) { + appSettings.setPrimaryColorSettings(base.getColor(), shade.getColor()); + if (Build.VERSION.SDK_INT >= 21) { + getActivity().getWindow().setStatusBarColor(ThemeHelper.getPrimaryDarkColor()); + } + ((ThemedActivity) getActivity()).applyColorToViews(); + } else { + appSettings.setAccentColorSettings(base.getColor(), shade.getColor()); + } + applyColorToViews(); + applySettingsToViews(); + } + }).show(); + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedSettingsFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedSettingsFragment.java new file mode 100644 index 00000000..e9c73600 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedSettingsFragment.java @@ -0,0 +1,23 @@ +package com.github.dfa.diaspora_android.fragment; + +import android.os.Bundle; +import android.view.View; + +/** + * Created by vanitas on 16.10.16. + */ + +public abstract class ThemedSettingsFragment extends ThemedFragment implements View.OnClickListener { + + @Override + public void onViewCreated(View layout, Bundle savedInstanceState) { + super.onViewCreated(layout, savedInstanceState); + applyColorToViews(); + applySettingsToViews(); + setOnClickListenersOnViews(); + } + + protected abstract void applyColorToViews(); + protected abstract void applySettingsToViews(); + protected abstract void setOnClickListenersOnViews(); +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ThemeHelper.java b/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ThemeHelper.java index d23c3785..1f4a8ca9 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ThemeHelper.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ThemeHelper.java @@ -19,19 +19,31 @@ */ package com.github.dfa.diaspora_android.util.theming; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.support.design.widget.TabLayout; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.CompoundButtonCompat; import android.support.v7.app.ActionBar; import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.github.dfa.diaspora_android.App; +import com.github.dfa.diaspora_android.R; import com.github.dfa.diaspora_android.data.AppSettings; +import com.github.dfa.diaspora_android.util.AppLog; /** * Singleton that can be used to color views @@ -67,7 +79,9 @@ public class ThemeHelper { public static void updateCheckBoxColor(CheckBox checkBox) { if (checkBox != null) { - checkBox.setHighlightColor(getInstance().appSettings.getAccentColor()); + int states[][] = {{android.R.attr.state_checked}, {}}; + int colors[] = {ThemeHelper.getAccentColor(), getNeutralGreyColor()}; + CompoundButtonCompat.setButtonTintList(checkBox, new ColorStateList(states, colors)); } } @@ -82,6 +96,14 @@ public class ThemeHelper { if (textView != null) { textView.setHighlightColor(getInstance().appSettings.getAccentColor()); textView.setLinkTextColor(getInstance().appSettings.getAccentColor()); + } else { + Log.d("ThemeHelper", "TextView is null!"); + } + } + + public static void updateTitleColor(TextView textView) { + if(textView != null) { + textView.setTextColor(getInstance().appSettings.getAccentColor()); } } @@ -91,6 +113,12 @@ public class ThemeHelper { } } + public static void setToolbarColor(Toolbar toolbar, int color) { + if(toolbar != null) { + toolbar.setBackgroundColor(color); + } + } + public static void updateActionMenuViewColor(ActionMenuView actionMenuView) { if (actionMenuView != null) { actionMenuView.setBackgroundColor(getInstance().appSettings.getPrimaryColor()); @@ -115,10 +143,8 @@ public class ThemeHelper { return ColorPalette.getObscuredColor(getPrimaryColor()); } - public static void updateActionBarColor(ActionBar actionBar) { - if (actionBar != null) { - actionBar.setBackgroundDrawable(new ColorDrawable(getInstance().appSettings.getPrimaryColor())); - } + public static int getNeutralGreyColor() { + return ContextCompat.getColor(getInstance().appSettings.getApplicationContext(), R.color.md_grey_800); } public static void updateProgressBarColor(ProgressBar progressBar) { @@ -126,4 +152,27 @@ public class ThemeHelper { progressBar.getProgressDrawable().setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_IN); } } + + public static void updateAccentColorPreview(ImageView imageView) { + if(imageView != null) { + Drawable circle = imageView.getDrawable(); + if(circle != null) { + circle.setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_ATOP); + imageView.setImageDrawable(circle); + } + } + } + + public static void updatePrimaryColorPreview(ImageView imageView) { + if(imageView != null) { + Drawable circle = imageView.getDrawable(); + if(circle != null) { + circle.setColorFilter(getPrimaryColor(), PorterDuff.Mode.SRC_ATOP); + } + } + } + + public static void setViewEnabled(View v, boolean enabled) { + v.setBackgroundColor(getInstance().appSettings.getApplicationContext().getResources().getColor(enabled ? R.color.white : R.color.layout_disabled)); + } } diff --git a/app/src/main/res/drawable/circle.xml b/app/src/main/res/drawable/circle.xml new file mode 100644 index 00000000..f944640b --- /dev/null +++ b/app/src/main/res/drawable/circle.xml @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings__activity.xml b/app/src/main/res/layout/settings_activity.xml similarity index 96% rename from app/src/main/res/layout/settings__activity.xml rename to app/src/main/res/layout/settings_activity.xml index 99cd2afe..129bb787 100644 --- a/app/src/main/res/layout/settings__activity.xml +++ b/app/src/main/res/layout/settings_activity.xml @@ -22,7 +22,7 @@ diff --git a/app/src/main/res/layout/settings_activity__dialog_font_size.xml b/app/src/main/res/layout/settings_activity__dialog_font_size.xml new file mode 100644 index 00000000..8ac20a25 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__dialog_font_size.xml @@ -0,0 +1,6 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__dialog_proxy.xml b/app/src/main/res/layout/settings_activity__dialog_proxy.xml new file mode 100644 index 00000000..8f59e5e2 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__dialog_proxy.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__overview.xml b/app/src/main/res/layout/settings_activity__overview.xml new file mode 100644 index 00000000..b6b741e6 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__overview.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__section_appearance.xml b/app/src/main/res/layout/settings_activity__section_appearance.xml new file mode 100644 index 00000000..c6445747 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__section_appearance.xml @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__section_more.xml b/app/src/main/res/layout/settings_activity__section_more.xml new file mode 100644 index 00000000..7ae93dc0 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__section_more.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__section_network.xml b/app/src/main/res/layout/settings_activity__section_network.xml new file mode 100644 index 00000000..10f8bd17 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__section_network.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__section_pod_settings.xml b/app/src/main/res/layout/settings_activity__section_pod_settings.xml new file mode 100644 index 00000000..f2eba166 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__section_pod_settings.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__subsection_debugging.xml b/app/src/main/res/layout/settings_activity__subsection_debugging.xml new file mode 100644 index 00000000..a8f4690b --- /dev/null +++ b/app/src/main/res/layout/settings_activity__subsection_debugging.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__subsection_nav_slider.xml b/app/src/main/res/layout/settings_activity__subsection_nav_slider.xml new file mode 100644 index 00000000..21a25606 --- /dev/null +++ b/app/src/main/res/layout/settings_activity__subsection_nav_slider.xml @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__subsection_proxy.xml b/app/src/main/res/layout/settings_activity__subsection_proxy.xml new file mode 100644 index 00000000..fcc10b4a --- /dev/null +++ b/app/src/main/res/layout/settings_activity__subsection_proxy.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity__subsection_theming.xml b/app/src/main/res/layout/settings_activity__subsection_theming.xml new file mode 100644 index 00000000..356fe4fe --- /dev/null +++ b/app/src/main/res/layout/settings_activity__subsection_theming.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index 7f16c9e6..795bb000 100644 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -15,6 +15,8 @@ #B6B6B6 + #b6b6b6 + #ffffff #000000 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 35131109..493c5982 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -15,4 +15,9 @@ 11sp + + 5dp + 5dp + 10dp + 5dp diff --git a/build.gradle b/build.gradle index 54903cde..d4c9c424 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' + classpath 'com.android.tools.build:gradle:2.2.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' // NOTE: Do not place your application dependencies here; they belong