diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 8fc720b8..6a7ba75d 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -24,10 +24,10 @@ I have: #### Expected result +**What is the expected output?** -What is the expected output? +**What do you see instead?** -What do you see instead? Upload screenshots via drag&drop if needed and apply resizing: `` diff --git a/.travis.yml b/.travis.yml index 74b79b85..41f1aaaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ android: - tools - tools # TODO https://github.com/travis-ci/travis-ci/issues/6193 - platform-tools - - build-tools-24.0.1 + - build-tools-24.0.2 - android-24 - extra-android-m2repository before_cache: diff --git a/LICENSE.md b/LICENSE.md index d1628af1..a9a829ca 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -14,6 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. -# Splashscreen-Images +# Miscellaneous -The splashscreen images can be found on [flickr](https://www.flickr.com/photos/129581906@N06/sets/72157651933980136/with/16594947123/). +We took some inspiration and code from LeafPic. Go check it out, its free software as well! +https://github.com/HoraApps/LeafPic \ No newline at end of file diff --git a/README.md b/README.md index a2696020..3ef91253 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ [![F-Droid](https://f-droid.org/wiki/images/0/06/F-Droid-button_get-it-on.png)](https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android) -[![Build Status](https://travis-ci.org/Diaspora-for-Android/diaspora-android.svg?branch=master)](https://travis-ci.org/Diaspora-for-Android/diaspora-android) +[![Build Status](https://travis-ci.org/Diaspora-for-Android/diaspora-android.svg?branch=master)](https://travis-ci.org/Diaspora-for-Android/diaspora-android) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/diaspora-for-android/localized.svg)](https://crowdin.com/project/diaspora-for-android) -[![Join the chat at https://gitter.im/Diaspora-for-Android/diaspora-android](https://badges.gitter.im/Diaspora-for-Android/diaspora-android.svg)](https://gitter.im/Diaspora-for-Android/diaspora-android?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Chat - FreeNode IRC](https://img.shields.io/badge/chat-on%20freenode-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/?nick=user-dfa|?#diaspora-for-android) +[![Chat - Gitter](https://img.shields.io/badge/chat-on%20gitter-blue.svg)](https://gitter.im/Diaspora-for-Android/diaspora-android) # Diaspora for Android @@ -15,28 +16,31 @@ This is an unofficial webview based client for the community-run, distributed so ## Contributions We are always open for any kind of contribution. (PR's, bug reports, feature requests, translations, ..) -If you got any questions feel free to join our XMPP/Jabber conference at `diaspora-android@conference.jabberhead.tk` or [Gitter](https://gitter.im/Diaspora-for-Android/diaspora-android). -Note that the main project members are mostly busy with their job/university/school and may not react or start coding immediately. +If you got any questions feel free to contact us on IRC, XMPP or Gitter. You can start chatting by clicking on the [blue chat badges](#badgers) listed on top. -We use Crowdin to translate Diaspora for Android. Join our project here: -If your desired language is not listed please contact the maintainers/owner. +We use Crowdin to translate Diaspora for Android. Join our project here: . If your desired language is not listed please contact the maintainers/owner. + +Note that the main project members are working on this project for free during leisure time, are mostly busy with their job/university/school, and may not react or start coding immediately. ### License -It's released under GNU GENERAL PUBLIC LICENSE (see [LICENCE](https://github.com/Diaspora-for-Android/diaspora-android/blob/master/LICENSE.md)). +Diaspora for Android is released under GNU GENERAL PUBLIC LICENSE (see [LICENCE](https://github.com/Diaspora-for-Android/diaspora-android/blob/master/LICENSE.md)). ### WebApp -The app is developed as an WebApp because currently Diaspora doesn't have an API that can be used to create a native interface to retrieve the user's data, publications, direct messages and so on, that's why there are only WebApps for Diaspora out there. +The app is developed as a WebApp because currently Diaspora doesn't have an API that can be used to create a native interface to retrieve the user's data, publications, direct messages and so on. That's why there are only WebApps for Diaspora out there. [Stay tuned on Diaspora* Issues](https://github.com/diaspora/diaspora/labels/api) about API. -Why a WebApp is better than using the mobile site on a browser? +Why is a WebApp better than using the mobile site on a browser? Basically it provides better integration with the system (events coming into and going out of the app), notifications, customized interface and functions and a nice little icon that takes you directly to your favorite social network :) ### Device Requirements -The minimum version supported is Jelly Bean, Android v4.2.0 / API 17 +The minimum Android version supported is Jelly Bean, Android v4.2.0 / API 17 ### App Permissions -It requires access to the Internet and to external storage to be able to upload photos when creating a new post and for taking screenshots. +Diaspora for Android requires access to the Internet and to external storage to be able to upload photos when creating a new post and for taking screenshots. ## Maintainers -- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.github.io)) -- vanitasvitae ([GitHub](https://github.com/vanitasvitae)) +- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.github.io), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c)) +- vanitasvitae ([GitHub](https://github.com/vanitasvitae), [Diaspora](https://pod.geraspora.de/people/bbd7af90fbec013213e34860008dbc6c)) + +## Acknowledgements +- We took some inspiration and code from [LeafPic](https://github.com/HoraApps/LeafPic), big thanks to Donald Shtjefni and the LeafPic Team! diff --git a/SCREENSHOTS.md b/SCREENSHOTS.md index 368da74a..8f443531 100644 --- a/SCREENSHOTS.md +++ b/SCREENSHOTS.md @@ -1,14 +1,24 @@ - - - - + + + + - - - - + + + + + + + + + + + + + +
diff --git a/app/build.gradle b/app/build.gradle index 4cb94656..377e44b7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,14 +3,14 @@ apply plugin: 'android-apt' android { compileSdkVersion 24 - buildToolsVersion "24.0.1" + buildToolsVersion "24.0.2" defaultConfig { applicationId "com.github.dfa.diaspora_android" minSdkVersion 17 targetSdkVersion 24 versionCode 8 - versionName "0.1.6" + versionName "0.1.6-next" } buildTypes { release { @@ -31,6 +31,13 @@ android { } } +repositories { + maven { + //Color picker + url "http://dl.bintray.com/dasar/maven" + } +} + dependencies { // Sub-Projects //compile project(':subprojectFromRoot') @@ -40,15 +47,16 @@ dependencies { testCompile 'junit:junit:4.12' // Android standard libs - compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:appcompat-v7:24.2.1' compile 'com.android.support:design:24.1.0' //Don't u dare to upd8! - compile 'com.android.support:support-v4:24.2.0' - compile "com.android.support:customtabs:24.2.0" + compile 'com.android.support:support-v4:24.2.1' + compile "com.android.support:customtabs:24.2.1" // More libraries compile 'com.jakewharton:butterknife:8.0.1' compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1' compile 'info.guardianproject.netcipher:netcipher-webkit:2.0.0-alpha1' + compile(group: 'uz.shift', name: 'colorpicker', version: '0.5', ext: 'aar') //Color picker apt 'com.jakewharton:butterknife-compiler:8.0.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2ef6cc59..1fa2f2e4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,53 +11,41 @@ android:icon="@drawable/ic_launcher" android:name="com.github.dfa.diaspora_android.App" android:label="@string/app_name" - android:theme="@style/AppTheme" > + android:theme="@style/DiasporaLight" > + - - - - - - - - - - - - + android:exported="false" /> + + + + + + + + + @@ -255,9 +243,7 @@ - + + \ No newline at end of file diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/AboutActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/AboutActivity.java index 4d8e2ecd..424a1d22 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/AboutActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/AboutActivity.java @@ -31,9 +31,10 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; @@ -43,10 +44,14 @@ import android.widget.Toast; 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.fragment.ThemedFragment; import com.github.dfa.diaspora_android.ui.HtmlTextView; +import com.github.dfa.diaspora_android.ui.IntellihideToolbarActivityListener; import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; import com.github.dfa.diaspora_android.util.Helpers; import com.github.dfa.diaspora_android.util.Log; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; import java.util.Observable; import java.util.Observer; @@ -57,17 +62,24 @@ import butterknife.ButterKnife; /** * Activity that holds some fragments that show information about the app in a tab layout */ -public class AboutActivity extends AppCompatActivity { +public class AboutActivity extends ThemedActivity +implements IntellihideToolbarActivityListener { private SectionsPagerAdapter mSectionsPagerAdapter; private ViewPager mViewPager; + @BindView(R.id.about__appbar) + AppBarLayout appBarLayout; + @BindView(R.id.main__topbar) protected Toolbar toolbar; - @BindView(R.id.linearlayout) + @BindView(R.id.appbar_linear_layout) protected LinearLayout linearLayout; + @BindView(R.id.tabs) + protected TabLayout tabLayout; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -87,23 +99,58 @@ public class AboutActivity extends AppCompatActivity { mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. - mViewPager = (ViewPager) findViewById(R.id.container); + mViewPager = ButterKnife.findById(this, R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter); - TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); tabLayout.setupWithViewPager(mViewPager); + } - //Apply intellihide - if (!((App) getApplication()).getSettings().isIntellihideToolbars()) { - AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) linearLayout.getLayoutParams(); - params.setScrollFlags(0); + @Override + public void onResume() { + super.onResume(); + if(getAppSettings().isIntellihideToolbars()) { + this.enableToolbarHiding(); + } else { + this.disableToolbarHiding(); } } + @Override + protected void applyColorToViews() { + ThemeHelper.updateToolbarColor(toolbar); + ThemeHelper.updateTabLayoutColor(tabLayout); + ThemeHelper.setPrimaryColorAsBackground(linearLayout); + } + + @Override + public void enableToolbarHiding() { + AppLog.d(this, "Enable Intellihide"); + AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) linearLayout.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) linearLayout.getLayoutParams(); + params.setScrollFlags(0); // clear all scroll flags + appBarLayout.setExpanded(true, true); + } + /** * Fragment that shows general information about the app */ - public static class AboutFragment extends Fragment { + public static class AboutFragment extends ThemedFragment { + + public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.AboutFragment"; + + @BindView(R.id.fragment_about__about_text) + TextView aboutText; + + @BindView(R.id.fragment_about__app_version) + TextView appVersion; public AboutFragment() { } @@ -112,8 +159,7 @@ public class AboutActivity extends AppCompatActivity { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.about__fragment_about, container, false); - TextView appVersion = (TextView) rootView.findViewById(R.id.fragment_about__app_version); - + ButterKnife.bind(this, rootView); if (isAdded()) { try { PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); @@ -125,18 +171,42 @@ public class AboutActivity extends AppCompatActivity { } return rootView; } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateTextViewColor(aboutText); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } } /** * Fragment that shows information about the license of the app and used 3rd party libraries */ - public static class LicenseFragment extends Fragment { + public static class LicenseFragment extends ThemedFragment { + public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.LicenseFragment"; + @BindView(R.id.fragment_license__licensetext) HtmlTextView textLicenseBox; @BindView(R.id.fragment_license__3rdparty) HtmlTextView textLicense3partyBox; + private String accentColor; + public LicenseFragment() { } @@ -146,7 +216,7 @@ public class AboutActivity extends AppCompatActivity { View rootView = inflater.inflate(R.layout.about__fragment_license, container, false); ButterKnife.bind(this, rootView); final Context context = rootView.getContext(); - accentColor = Helpers.hexColorFromRessourceColor(context, R.color.colorAccent); + accentColor = Helpers.colorToHex(ThemeHelper.getAccentColor()); textLicenseBox.setTextFormatted(getString(R.string.fragment_license__license_content, getMaintainersHtml(context), @@ -160,8 +230,6 @@ public class AboutActivity extends AppCompatActivity { return rootView; } - private String accentColor; - public String getContributorsHtml(Context context) { String text = Helpers.readTextfileFromRawRessource(context, R.raw.contributors, "* ", "
"); @@ -187,13 +255,52 @@ public class AboutActivity extends AppCompatActivity { text = text.replace("NEWENTRY", "* "); return text; } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateTextViewColor(textLicense3partyBox); + ThemeHelper.updateTextViewColor(textLicenseBox); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } } /** * Fragment that shows debug information like app version, pod version... */ public static class DebugFragment extends Fragment implements Observer { - private TextView logBox; + public static final String TAG = "com.github.dfa.diaspora_android.AboutActivity.DebugFragment"; + + @BindView(R.id.fragment_debug__package_name) + TextView packageName; + + @BindView(R.id.fragment_debug__app_version) + TextView appVersion; + + @BindView(R.id.fragment_debug__android_version) + TextView osVersion; + + @BindView(R.id.fragment_debug__device_name) + TextView deviceName; + + @BindView(R.id.fragment_debug__pod_domain) + TextView podDomain; + + @BindView(R.id.fragment_debug__log_box) + TextView logBox; public DebugFragment() { } @@ -202,16 +309,10 @@ public class AboutActivity extends AppCompatActivity { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.about__fragment_debug, container, false); - TextView packageName = (TextView) rootView.findViewById(R.id.fragment_debug__package_name); - TextView appVersion = (TextView) rootView.findViewById(R.id.fragment_debug__app_version); - TextView osVersion = (TextView) rootView.findViewById(R.id.fragment_debug__android_version); - TextView deviceName = (TextView) rootView.findViewById(R.id.fragment_debug__device_name); - TextView podDomain = (TextView) rootView.findViewById(R.id.fragment_debug__pod_domain); - logBox = (TextView) rootView.findViewById(R.id.fragment_debug__log_box); + ButterKnife.bind(this, rootView); logBox.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { - AppLog.d(this, "Long click registered"); if (isAdded()) { ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("DEBUG_LOG", Log.getLogBuffer()); @@ -229,14 +330,14 @@ public class AboutActivity extends AppCompatActivity { if (isAdded()) { try { PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); - AppSettings settings = ((App) getActivity().getApplication()).getSettings(); - + AppSettings appSettings = ((App) getActivity().getApplication()).getSettings(); + DiasporaUrlHelper urls = new DiasporaUrlHelper(appSettings); packageName.setText(pInfo.packageName); appVersion.setText(getString(R.string.fragment_debug__app_version, pInfo.versionName + " (" + pInfo.versionCode + ")")); osVersion.setText(getString(R.string.fragment_debug__android_version, Build.VERSION.RELEASE)); deviceName.setText(getString(R.string.fragment_debug__device_name, Build.MANUFACTURER + " " + Build.MODEL)); - podDomain.setText(getString(R.string.fragment_debug__pod_domain, settings.getPodDomain())); + podDomain.setText(getString(R.string.fragment_debug__pod_domain, urls.getPodUrl())); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java index 32e9c33e..56a80ad4 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java @@ -25,7 +25,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.res.Configuration; import android.graphics.drawable.LayerDrawable; import android.net.Uri; import android.os.Bundle; @@ -41,7 +40,6 @@ import android.support.v4.content.LocalBroadcastManager; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.Toolbar; import android.view.KeyEvent; @@ -55,6 +53,7 @@ import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -62,24 +61,31 @@ 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.data.PodUserProfile; +import com.github.dfa.diaspora_android.fragment.BrowserFragment; import com.github.dfa.diaspora_android.fragment.CustomFragment; -import com.github.dfa.diaspora_android.fragment.StreamFragment; +import com.github.dfa.diaspora_android.fragment.DiasporaStreamFragment; +import com.github.dfa.diaspora_android.fragment.HashtagListFragment; +import com.github.dfa.diaspora_android.fragment.PodSelectionFragment; import com.github.dfa.diaspora_android.listener.WebUserProfileChangedListener; import com.github.dfa.diaspora_android.receiver.OpenExternalLinkReceiver; +import com.github.dfa.diaspora_android.util.ProxyHandler; import com.github.dfa.diaspora_android.receiver.UpdateTitleReceiver; import com.github.dfa.diaspora_android.ui.BadgeDrawable; +import com.github.dfa.diaspora_android.ui.IntellihideToolbarActivityListener; import com.github.dfa.diaspora_android.util.AppLog; import com.github.dfa.diaspora_android.util.CustomTabHelpers.CustomTabActivityHelper; import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; -import com.github.dfa.diaspora_android.util.Helpers; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; import com.github.dfa.diaspora_android.util.WebHelper; import butterknife.BindView; import butterknife.ButterKnife; -import butterknife.OnClick; -public class MainActivity extends AppCompatActivity - implements NavigationView.OnNavigationItemSelectedListener, WebUserProfileChangedListener, CustomTabActivityHelper.ConnectionCallback { +public class MainActivity extends ThemedActivity + implements NavigationView.OnNavigationItemSelectedListener, + WebUserProfileChangedListener, + CustomTabActivityHelper.ConnectionCallback, + IntellihideToolbarActivityListener { public static final int REQUEST_CODE_ASK_PERMISSIONS = 123; @@ -92,7 +98,6 @@ public class MainActivity extends AppCompatActivity public static final String ACTION_CHANGE_ACCOUNT = "com.github.dfa.diaspora_android.MainActivity.change_account"; public static final String ACTION_CLEAR_CACHE = "com.github.dfa.diaspora_android.MainActivity.clear_cache"; public static final String ACTION_UPDATE_TITLE_FROM_URL = "com.github.dfa.diaspora_android.MainActivity.set_title"; - public static final String ACTION_RELOAD_ACTIVITY = "com.github.dfa.diaspora_android.MainActivity.reload_activity"; public static final String URL_MESSAGE = "URL_MESSAGE"; public static final String EXTRA_URL = "com.github.dfa.diaspora_android.extra_url"; public static final String CONTENT_HASHTAG = "content://com.github.dfa.diaspora_android.mainactivity/"; @@ -113,6 +118,9 @@ public class MainActivity extends AppCompatActivity /** * UI Bindings */ + @BindView(R.id.main__appbar) + AppBarLayout appBarLayout; + @BindView(R.id.main__topbar) Toolbar toolbarTop; @@ -128,12 +136,17 @@ public class MainActivity extends AppCompatActivity @BindView(R.id.main__navdrawer) DrawerLayout navDrawer; + RelativeLayout navDrawerLayout; + LinearLayout navProfilePictureArea; + // NavHeader cannot be bound by Butterknife private TextView navheaderTitle; private TextView navheaderDescription; private ImageView navheaderImage; + private String textToBeShared; + /** * END UI Bindings @@ -158,38 +171,58 @@ public class MainActivity extends AppCompatActivity urls = new DiasporaUrlHelper(appSettings); customTabActivityHelper = new CustomTabActivityHelper(); customTabActivityHelper.setConnectionCallback(this); + ProxyHandler.getInstance().updateProxySettings(this); fm = getSupportFragmentManager(); - StreamFragment sf = getStreamFragment(); - fm.beginTransaction().replace(R.id.fragment_container, sf, StreamFragment.TAG).commit(); - sf.onCreateBottomOptionsMenu(toolbarBottom.getMenu(), getMenuInflater()); - - setupUI(savedInstanceState); + setupUI(); brOpenExternalLink = new OpenExternalLinkReceiver(this); brSetTitle = new UpdateTitleReceiver(app, urls, new UpdateTitleReceiver.TitleCallback() { @Override public void setTitle(int rId) { - MainActivity.this.setTitle(rId); + CustomFragment top = getTopFragment(); + if (top != null && top.getFragmentTag().equals(DiasporaStreamFragment.TAG)) { + MainActivity.this.setTitle(rId); + } } @Override public void setTitle(String title) { - MainActivity.this.setTitle(title); + CustomFragment top = getTopFragment(); + if (top != null && top.getFragmentTag().equals(DiasporaStreamFragment.TAG)) { + MainActivity.this.setTitle(title); + } } }); + + if (!appSettings.hasPodDomain()) { + AppLog.d(this, "We have no pod. Show PodSelectionFragment"); + showFragment(getFragment(PodSelectionFragment.TAG)); + } else { + AppLog.d(this, "Pod found. Handle intents."); + //Handle intent + Intent intent = getIntent(); + if (intent != null && intent.getAction() != null) { + handleIntent(intent); + } else { + openDiasporaUrl(urls.getStreamUrl()); + } + } } - private void setupUI(Bundle savedInstanceState) { + /** + * Setup the user interface. Set up both toolbars and initialize the snackbars. + * Initialize the navigation drawer and apply intellihide settings. + */ + private void setupUI() { AppLog.i(this, "setupUI()"); // Setup toolbar setSupportActionBar(toolbarTop); - getMenuInflater().inflate(R.menu.main__menu_bottom, toolbarBottom.getMenu()); toolbarBottom.setOnMenuItemClickListener(new ActionMenuView.OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { - CustomFragment topFrag = (CustomFragment) getTopFragment(); - return MainActivity.this.onOptionsItemSelected(item) || (topFrag != null && topFrag.onOptionsItemSelected(item)); + CustomFragment top = getTopFragment(); + return MainActivity.this.onOptionsItemSelected(item) || (top != null && top.onOptionsItemSelected(item)); } }); setTitle(R.string.app_name); @@ -208,43 +241,79 @@ public class MainActivity extends AppCompatActivity // Load app settings setupNavigationSlider(); - - if (!appSettings.isIntellihideToolbars()) { - AppLog.v(this, "Disable intelligent hiding of toolbars"); - AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbarTop.getLayoutParams(); - params.setScrollFlags(0); // clear all scroll flags - } - AppLog.v(this, "UI successfully set up"); - handleIntent(getIntent()); } + /** + * Show DiasporaStreamFragment if necessary and load URL url + * + * @param url URL to load in the DiasporaStreamFragment + */ public void openDiasporaUrl(String url) { - StreamFragment streamFragment = getStreamFragment(); - if(!streamFragment.isVisible()) { - AppLog.d(this, "StreamFragment not visible"); - fm.beginTransaction().replace(R.id.fragment_container, streamFragment, StreamFragment.TAG).commit(); - streamFragment.onCreateBottomOptionsMenu(toolbarBottom.getMenu(), getMenuInflater()); - } + AppLog.v(this, "openDiasporaUrl()"); + DiasporaStreamFragment streamFragment = (DiasporaStreamFragment) getFragment(DiasporaStreamFragment.TAG); + showFragment(streamFragment); streamFragment.loadUrl(url); } - public StreamFragment getStreamFragment() { - StreamFragment streamFragment = (StreamFragment) fm.findFragmentByTag(StreamFragment.TAG); - if(streamFragment == null) { - AppLog.d(this, "StreamFragment was null"); - streamFragment = new StreamFragment(); + /** + * Get an instance of the CustomFragment with the tag fragmentTag. + * If there was no instance so far, create a new one and add it to the FragmentManagers pool. + * If there is no Fragment with the corresponding Tag, return the top fragment. + * + * @param fragmentTag tag + * @return corresponding Fragment + */ + protected CustomFragment getFragment(String fragmentTag) { + CustomFragment fragment = (CustomFragment) fm.findFragmentByTag(fragmentTag); + if (fragment != null) { + return fragment; + } else { + switch (fragmentTag) { + case DiasporaStreamFragment.TAG: + DiasporaStreamFragment dsf = new DiasporaStreamFragment(); + fm.beginTransaction().add(dsf, fragmentTag).commit(); + return dsf; + case BrowserFragment.TAG: + BrowserFragment bf = new BrowserFragment(); + fm.beginTransaction().add(bf, fragmentTag).commit(); + return bf; + case HashtagListFragment.TAG: + HashtagListFragment hlf = new HashtagListFragment(); + fm.beginTransaction().add(hlf, fragmentTag).commit(); + return hlf; + case PodSelectionFragment.TAG: + PodSelectionFragment psf = new PodSelectionFragment(); + fm.beginTransaction().add(psf, fragmentTag).commit(); + return psf; + default: + AppLog.e(this, "Invalid Fragment Tag: " + fragmentTag + + "\nAdd Fragments Tag to getFragment()'s switch case."); + return getTopFragment(); + } } - return streamFragment; } - @Override - public void onConfigurationChanged(Configuration newConfig) { - AppLog.i(this, "onConfigurationChanged()"); - - super.onConfigurationChanged(newConfig); + /** + * Show the Fragment fragment in R.id.fragment_container. If the fragment was already visible, do nothing. + * + * @param fragment Fragment to show + */ + protected void showFragment(CustomFragment fragment) { + AppLog.v(this, "showFragment()"); + CustomFragment currentTop = (CustomFragment) fm.findFragmentById(R.id.fragment_container); + if (currentTop == null || !currentTop.getFragmentTag().equals(fragment.getFragmentTag())) { + AppLog.v(this, "Fragment was not visible. Replace it."); + fm.beginTransaction().addToBackStack(null).replace(R.id.fragment_container, fragment, fragment.getFragmentTag()).commit(); + invalidateOptionsMenu(); + } else { + AppLog.v(this, "Fragment was already visible. Do nothing."); + } } + /** + * Initialize the navigation slider + */ private void setupNavigationSlider() { ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, navDrawer, toolbarTop, R.string.navigation_drawer_open, R.string.navigation_drawer_close); @@ -255,9 +324,10 @@ public class MainActivity extends AppCompatActivity navView.setNavigationItemSelectedListener(this); View navHeader = navView.getHeaderView(0); - LinearLayout navheaderProfileSection = ButterKnife.findById(navHeader, R.id.nav_profile_picture); + navProfilePictureArea = ButterKnife.findById(navHeader, R.id.nav_profile_picture); + navDrawerLayout = ButterKnife.findById(navHeader, R.id.nav_drawer); //Handle clicks on profile picture - navheaderProfileSection.setOnClickListener(new View.OnClickListener() { + navProfilePictureArea.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { navDrawer.closeDrawer(GravityCompat.START); @@ -294,34 +364,39 @@ public class MainActivity extends AppCompatActivity } } } + updateNavigationViewEntryVisibilities(); + } - // Set visibility + protected void updateNavigationViewEntryVisibilities() { Menu navMenu = navView.getMenu(); navMenu.findItem(R.id.nav_exit).setVisible(appSettings.isVisibleInNavExit()); navMenu.findItem(R.id.nav_activities).setVisible(appSettings.isVisibleInNavActivities()); navMenu.findItem(R.id.nav_aspects).setVisible(appSettings.isVisibleInNavAspects()); navMenu.findItem(R.id.nav_commented).setVisible(appSettings.isVisibleInNavCommented()); navMenu.findItem(R.id.nav_followed_tags).setVisible(appSettings.isVisibleInNavFollowed_tags()); - navMenu.findItem(R.id.nav_help_license).setVisible(appSettings.isVisibleInNavHelp_license()); + navMenu.findItem(R.id.nav_about).setVisible(appSettings.isVisibleInNavHelp_license()); navMenu.findItem(R.id.nav_liked).setVisible(appSettings.isVisibleInNavLiked()); navMenu.findItem(R.id.nav_mentions).setVisible(appSettings.isVisibleInNavMentions()); navMenu.findItem(R.id.nav_profile).setVisible(appSettings.isVisibleInNavProfile()); navMenu.findItem(R.id.nav_public).setVisible(appSettings.isVisibleInNavPublic_activities()); } - @OnClick(R.id.main__topbar) - public void onToolBarClicked(View view) { - AppLog.i(this, "onToolBarClicked()"); - onNavigationItemSelected(navView.getMenu().findItem(R.id.nav_stream)); - } - + /** + * Forward incoming intents to handleIntent() + * + * @param intent incoming + */ @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - handleIntent(intent); } + /** + * Handle intents and execute intent specific actions + * + * @param intent intent to get handled + */ private void handleIntent(Intent intent) { AppLog.i(this, "handleIntent()"); if (intent == null) { @@ -333,7 +408,9 @@ public class MainActivity extends AppCompatActivity String type = intent.getType(); String loadUrl = null; AppLog.v(this, "Action: " + action + " Type: " + type); - if (ACTION_OPEN_URL.equals(action)) { + if (Intent.ACTION_MAIN.equals(action)) { + loadUrl = urls.getStreamUrl(); + } else if (ACTION_OPEN_URL.equals(action)) { loadUrl = intent.getStringExtra(URL_MESSAGE); } else if (Intent.ACTION_VIEW.equals(action) && intent.getDataString() != null) { Uri data = intent.getData(); @@ -342,18 +419,15 @@ public class MainActivity extends AppCompatActivity return; } else { loadUrl = intent.getDataString(); + AppLog.v(this, "Intent has a delicious URL for us: " + loadUrl); } } else if (ACTION_CHANGE_ACCOUNT.equals(action)) { - AppLog.v(this, "Reset pod data and animate to PodSelectionActivity"); - app.resetPodData(getStreamFragment().getWebView()); - Helpers.animateToActivity(MainActivity.this, PodSelectionActivity.class, true); + AppLog.v(this, "Reset pod data and show PodSelectionFragment"); + app.resetPodData(((DiasporaStreamFragment) getFragment(DiasporaStreamFragment.TAG)).getWebView()); + showFragment(getFragment(PodSelectionFragment.TAG)); } else if (ACTION_CLEAR_CACHE.equals(action)) { AppLog.v(this, "Clear WebView cache"); - getStreamFragment().getWebView().clearCache(true); - } else if (ACTION_RELOAD_ACTIVITY.equals(action)) { - AppLog.v(this, "Recreate activity"); - recreate(); - return; + ((DiasporaStreamFragment) getFragment(DiasporaStreamFragment.TAG)).getWebView().clearCache(true); } else if (Intent.ACTION_SEND.equals(action) && type != null) { switch (type) { case "text/plain": @@ -368,7 +442,8 @@ public class MainActivity extends AppCompatActivity break; } } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { - //TODO: Implement and add filter to manifest + /* TODO: Implement and add filter to manifest */ + return; } if (loadUrl != null) { @@ -377,33 +452,35 @@ public class MainActivity extends AppCompatActivity } } + /** + * Handle activity results + * + * @param requestCode reqCode + * @param resultCode resCode + * @param data data + */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - AppLog.d(this, "onActivityResult(): "+requestCode); + AppLog.v(this, "onActivityResult(): " + requestCode); super.onActivityResult(requestCode, resultCode, data); } - @Override - protected void onSaveInstanceState(Bundle outState) { - AppLog.v(this, "onSaveInstanceState()"); - super.onSaveInstanceState(outState); - } - - @Override - protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { - AppLog.v(this, "onRestoreInstanceState()"); - super.onRestoreInstanceState(savedInstanceState); - } - - private Fragment getTopFragment() { - for(Fragment f : fm.getFragments()) { - if(f.isVisible()) { - return f; - } + /** + * Return the fragment which is currently displayed in R.id.fragment_container + * + * @return top fragment or null if there is none displayed + */ + private CustomFragment getTopFragment() { + Fragment top = fm.findFragmentById(R.id.fragment_container); + if (top != null) { + return (CustomFragment) top; } return null; } + /** + * Handle presses on the back button + */ @Override public void onBackPressed() { AppLog.v(this, "onBackPressed()"); @@ -411,15 +488,20 @@ public class MainActivity extends AppCompatActivity navDrawer.closeDrawer(navView); return; } - CustomFragment top = (CustomFragment) getTopFragment(); - if(top != null) { - AppLog.d(this, "Top Fragment is not null"); - if(!top.onBackPressed()) { - AppLog.d(this, "Top Fragment.onBackPressed was false"); - //TODO: Go back in Fragment backstack + CustomFragment top = getTopFragment(); + if (top != null) { + AppLog.v(this, "Top Fragment is not null"); + if (!top.onBackPressed()) { + AppLog.v(this, "Top Fragment.onBackPressed was false"); + AppLog.v(this, "BackStackEntryCount: " + fm.getBackStackEntryCount()); + if (fm.getBackStackEntryCount() > 0) { + fm.popBackStack(); + } else { + snackbarExitApp.show(); + } return; } else { - AppLog.d(this, "Top Fragment.onBackPressed was true"); + AppLog.v(this, "Top Fragment.onBackPressed was true"); return; } } @@ -457,15 +539,53 @@ public class MainActivity extends AppCompatActivity AppLog.v(this, "Register BroadcastReceivers"); LocalBroadcastManager.getInstance(this).registerReceiver(brSetTitle, new IntentFilter(ACTION_UPDATE_TITLE_FROM_URL)); LocalBroadcastManager.getInstance(this).registerReceiver(brOpenExternalLink, new IntentFilter(ACTION_OPEN_EXTERNAL_URL)); + this.appSettings = getAppSettings(); + if (appSettings.isIntellihideToolbars()) { + this.enableToolbarHiding(); + } else { + this.disableToolbarHiding(); + } + updateNavigationViewEntryVisibilities(); } + /** + * Clear and repopulate top and bottom toolbar. + * Also add menu items of the displayed fragment + * + * @param menu top toolbar + * @return boolean + */ @Override public boolean onCreateOptionsMenu(Menu menu) { AppLog.v(this, "onCreateOptionsMenu()"); - getMenuInflater().inflate(R.menu.main__menu_top, menu); + //Clear the menus + menu.clear(); + toolbarBottom.getMenu().clear(); + toolbarBottom.setVisibility(View.VISIBLE); + + CustomFragment top = getTopFragment(); + if (top != null) { + //Are we displaying a Fragment other than PodSelectionFragment? + if (!top.getFragmentTag().equals(PodSelectionFragment.TAG)) { + getMenuInflater().inflate(R.menu.main__menu_top, menu); + getMenuInflater().inflate(R.menu.main__menu_bottom, toolbarBottom.getMenu()); + top.onCreateBottomOptionsMenu(toolbarBottom.getMenu(), getMenuInflater()); + } + //PodSelectionFragment + else { + //Hide bottom toolbar + toolbarBottom.setVisibility(View.GONE); + } + } return true; } + /** + * Set the notification and messages counter in the top toolbar + * + * @param menu menu + * @return boolean + */ @Override public boolean onPrepareOptionsMenu(Menu menu) { MenuItem item; @@ -482,6 +602,12 @@ public class MainActivity extends AppCompatActivity return super.onPrepareOptionsMenu(menu); } + /** + * Handle clicks on the optionsmenu + * + * @param item item + * @return boolean + */ @Override public boolean onOptionsItemSelected(MenuItem item) { AppLog.i(this, "onOptionsItemSelected()"); @@ -575,18 +701,33 @@ public class MainActivity extends AppCompatActivity return super.onOptionsItemSelected(item); } + /** + * Update the profile name in the navigation slider + * + * @param name name + */ @Override public void onUserProfileNameChanged(String name) { AppLog.i(this, "onUserProfileNameChanged()"); navheaderTitle.setText(name); } + /** + * Update the profile picture in the navigation slider + * + * @param avatarUrl url of the new profile pic + */ @Override public void onUserProfileAvatarChanged(String avatarUrl) { AppLog.i(this, "onUserProfileAvatarChanged()"); app.getAvatarImageLoader().startImageDownload(navheaderImage, avatarUrl); } + /** + * Handle hashtag clicks. Open the new-post-url and inject the clicked hashtag into the post-editor + * + * @param intent intent + */ private void handleHashtag(Intent intent) { AppLog.v(this, "handleHashtag()"); try { @@ -597,15 +738,19 @@ public class MainActivity extends AppCompatActivity openDiasporaUrl(urls.getNewPostUrl()); } + /** + * Open the new-post-url and inject text that was shared into the app into the post editors text field + * + * @param intent shareTextIntent + */ private void handleSendText(Intent intent) { AppLog.v(this, "handleSendText()"); try { setSharedTexts(null, intent.getStringExtra(Intent.EXTRA_TEXT)); + openDiasporaUrl(urls.getNewPostUrl()); } catch (Exception e) { AppLog.e(this, e.toString()); } - openDiasporaUrl(urls.getBlankUrl()); - openDiasporaUrl(urls.getNewPostUrl()); } /** @@ -617,11 +762,10 @@ public class MainActivity extends AppCompatActivity AppLog.v(this, "handleSendSubject()"); try { setSharedTexts(intent.getStringExtra(Intent.EXTRA_SUBJECT), intent.getStringExtra(Intent.EXTRA_TEXT)); + openDiasporaUrl(urls.getNewPostUrl()); } catch (Exception e) { AppLog.e(this, e.toString()); } - openDiasporaUrl(urls.getBlankUrl()); //TODO: Necessary? - openDiasporaUrl(urls.getNewPostUrl()); } /** @@ -645,26 +789,36 @@ public class MainActivity extends AppCompatActivity if (sharedSubject != null) { AppLog.v(this, "Append subject to shared text"); String escapedSubject = WebHelper.escapeHtmlText(WebHelper.replaceUrlWithMarkdown(sharedSubject)); - getStreamFragment().setTextToBeShared("**" + escapedSubject + "** " + escapedBody); + AppLog.v(this, "Set shared text; Subject: \"" + escapedSubject + "\" Body: \"" + escapedBody + "\""); + textToBeShared = "**" + escapedSubject + "** " + escapedBody; } else { AppLog.v(this, "Set shared text; Subject: \"" + sharedSubject + "\" Body: \"" + sharedBody + "\""); - getStreamFragment().setTextToBeShared(escapedBody); + textToBeShared = escapedBody; } } - //TODO: Implement? + /** + * Share an image shared to the app via diaspora + * + * @param intent shareImageIntent + */ + //TODO: Implement some day private void handleSendImage(Intent intent) { AppLog.i(this, "handleSendImage()"); final Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (imageUri != null) { AppLog.v(this, "imageUri is not null. Handle shared image"); - // TODO: Update UI to reflect text being shared } else { AppLog.w(this, "imageUri is null. Cannot precede."); } Toast.makeText(this, "Not yet implemented.", Toast.LENGTH_SHORT).show(); } + /** + * Invalidate the top toolbar to update the notification counter + * + * @param notificationCount new notification count + */ @Override public void onNotificationCountChanged(int notificationCount) { AppLog.i(this, "onNotificationCountChanged()"); @@ -672,6 +826,11 @@ public class MainActivity extends AppCompatActivity invalidateOptionsMenu(); } + /** + * Invalidate the top toolbar to update the unread messages counter + * + * @param unreadMessageCount new unread messages count + */ @Override public void onUnreadMessageCountChanged(int unreadMessageCount) { AppLog.i(this, "onUnreadMessageCountChanged()"); @@ -681,8 +840,8 @@ public class MainActivity extends AppCompatActivity @Override public void onCustomTabsConnected() { - if(customTabsSession == null) { - AppLog.i(this, "CustomTabs warmup: "+customTabActivityHelper.warmup(0)); + if (customTabsSession == null) { + AppLog.i(this, "CustomTabs warmup: " + customTabActivityHelper.warmup(0)); customTabsSession = customTabActivityHelper.getSession(); } } @@ -716,23 +875,17 @@ public class MainActivity extends AppCompatActivity } break; - //TODO: Replace with fragment case R.id.nav_followed_tags: { - if (WebHelper.isOnline(MainActivity.this)) { - openDiasporaUrl(urls.getBlankUrl()); - WebHelper.showFollowedTagsList(getStreamFragment().getWebView(), app); - setTitle(R.string.nav_followed_tags); - } else { - snackbarNoInternet.show(); - } + showFragment(getFragment(HashtagListFragment.TAG)); } break; //TODO: Replace with fragment case R.id.nav_aspects: { + DiasporaStreamFragment stream = (DiasporaStreamFragment) getFragment(DiasporaStreamFragment.TAG); if (WebHelper.isOnline(MainActivity.this)) { openDiasporaUrl(DiasporaUrlHelper.URL_BLANK); - WebHelper.showAspectList(getStreamFragment().getWebView(), app); + WebHelper.showAspectList(stream.getWebView(), app); setTitle(R.string.aspects); } else { snackbarNoInternet.show(); @@ -796,7 +949,7 @@ public class MainActivity extends AppCompatActivity } break; - case R.id.nav_help_license: { + case R.id.nav_about: { startActivity(new Intent(MainActivity.this, AboutActivity.class)); } break; @@ -806,6 +959,13 @@ public class MainActivity extends AppCompatActivity return true; } + /** + * React to results of requestPermission + * + * @param requestCode resCode + * @param permissions requested permissions + * @param grantResults granted results + */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { @@ -824,4 +984,47 @@ public class MainActivity extends AppCompatActivity grantResults); } } + + /** + * Return the string that will be shared into the new-post-editor + * + * @return String + */ + public String getTextToBeShared() { + return textToBeShared; + } + + /** + * Set the string that will be shared into the new-post-editor + * + * @param textToBeShared + */ + public void setTextToBeShared(String textToBeShared) { + this.textToBeShared = textToBeShared; + } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateToolbarColor(toolbarTop); + ThemeHelper.updateActionMenuViewColor(toolbarBottom); + navDrawerLayout.setBackgroundColor(appSettings.getPrimaryColor()); + navProfilePictureArea.setBackgroundColor(appSettings.getPrimaryColor()); + } + + @Override + public void enableToolbarHiding() { + AppLog.d(this, "Enable Intellihide"); + AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbarTop.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) toolbarTop.getLayoutParams(); + params.setScrollFlags(0); // clear all scroll flags + appBarLayout.setExpanded(true, true); + } } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/SettingsActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/SettingsActivity.java index 88f13171..89ec73d5 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/SettingsActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/SettingsActivity.java @@ -1,55 +1,83 @@ /* This file is part of the Diaspora for Android. - Diaspora for Android is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Diaspora for Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with the Diaspora for Android. - If not, see . */ 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.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +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.util.theming.ColorPalette; +import com.github.dfa.diaspora_android.util.ProxyHandler; import com.github.dfa.diaspora_android.util.AppLog; +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 */ -public class SettingsActivity extends AppCompatActivity { - private boolean activityRestartRequired; +public class SettingsActivity extends ThemedActivity implements IntellihideToolbarActivityListener { + @BindView(R.id.settings__appbar) + protected AppBarLayout appBarLayout; + + @BindView(R.id.settings__toolbar) + protected Toolbar toolbar; + + private ProxyHandler.ProxySettings oldProxySettings; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ActionBar toolbar = getSupportActionBar(); - if (toolbar != null) - toolbar.setDisplayHomeAsUpEnabled(true); - getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + setContentView(R.layout.settings__activity); + ButterKnife.bind(this); + setSupportActionBar(toolbar); + toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24px)); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SettingsActivity.this.onBackPressed(); + } + }); + oldProxySettings = getAppSettings().getProxySettings(); + getFragmentManager().beginTransaction().replace(R.id.settings__fragment_container, new SettingsFragment()).commit(); } @Override @@ -63,8 +91,26 @@ public class SettingsActivity extends AppCompatActivity { } } - private void setActivityRestartRequired() { - this.activityRestartRequired = true; + @Override + protected void applyColorToViews() { + 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 { @@ -78,12 +124,12 @@ public class SettingsActivity extends AppCompatActivity { sharedPreferences.registerOnSharedPreferenceChangeListener(this); setPreferenceSummaries(); sharedPreferences.edit().putBoolean(getString(R.string.pref_key__proxy_was_enabled), - sharedPreferences.getBoolean(getString(R.string.pref_key__proxy_enabled), false)).apply(); + sharedPreferences.getBoolean(getString(R.string.pref_key__http_proxy_enabled), false)).apply(); } private void setPreferenceSummaries() { String[] editTextKeys = new String[]{ - getString(R.string.pref_key__proxy_host), getString(R.string.pref_key__proxy_port) + 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); @@ -94,15 +140,12 @@ public class SettingsActivity extends AppCompatActivity { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { updatePreference(findPreference(key)); - if (key != null && isAdded() && (key.equals(getString(R.string.pref_key__clear_cache)) || - key.equals(getString(R.string.pref_key__font_size)) || - key.equals(getString(R.string.pref_key__load_images)) || - key.equals(getString(R.string.pref_key__intellihide_toolbars)) || - key.equals(getString(R.string.pref_key__proxy_enabled)) || - key.equals(getString(R.string.pref_key__proxy_host)) || - key.equals(getString(R.string.pref_key__proxy_port)) || - key.startsWith("pref_key__visibility_nav__"))) { - ((SettingsActivity) getActivity()).setActivityRestartRequired(); + 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(); + } } } @@ -123,9 +166,31 @@ public class SettingsActivity extends AppCompatActivity { @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); - String podDomain = ((App) getActivity().getApplication()).getSettings().getPodDomain(); + String podDomain = appSettings.getPodDomain(); + 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, "https://" + podDomain + "/user/edit"); @@ -158,6 +223,17 @@ public class SettingsActivity extends AppCompatActivity { .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; @@ -171,6 +247,71 @@ public class SettingsActivity extends AppCompatActivity { } 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 @@ -185,11 +326,21 @@ public class SettingsActivity extends AppCompatActivity { @Override protected void onStop() { - super.onStop(); - if (activityRestartRequired) { - Intent intent = new Intent(this, MainActivity.class); - intent.setAction(MainActivity.ACTION_RELOAD_ACTIVITY); - startActivity(intent); + ProxyHandler.ProxySettings newProxySettings = getAppSettings().getProxySettings(); + if(!oldProxySettings.equals(newProxySettings)) { + AppLog.d(this, "ProxySettings changed."); + //Proxy on-off? => Restart app + if(oldProxySettings.isEnabled() && !newProxySettings.isEnabled()) { + Intent restartActivity = new Intent(SettingsActivity.this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(SettingsActivity.this, 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT); + AlarmManager mgr = (AlarmManager) SettingsActivity.this.getSystemService(Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent); + System.exit(0); + } //Proxy changed? => Update + else { + ProxyHandler.getInstance().updateProxySettings(this); + } } + super.onStop(); } } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/SplashActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/SplashActivity.java deleted file mode 100644 index 0eeccd3c..00000000 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/SplashActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of the Diaspora for Android. - - Diaspora for Android is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Diaspora for Android is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the Diaspora for Android. - - If not, see . - */ - -package com.github.dfa.diaspora_android.activity; - -import android.os.Bundle; -import android.os.Handler; -import android.support.v7.app.AppCompatActivity; - -import com.github.dfa.diaspora_android.App; -import com.github.dfa.diaspora_android.R; -import com.github.dfa.diaspora_android.util.Helpers; - -import butterknife.ButterKnife; - - -public class SplashActivity extends AppCompatActivity { - private App app; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.splash__activity); - ButterKnife.bind(this); - app = (App) getApplication(); - - int delay = getResources().getInteger(R.integer.splash_delay); - new Handler().postDelayed(startActivityRunnable, delay); - } - - private final Runnable startActivityRunnable = new Runnable() { - public void run() { - boolean hasPodDomain = app.getSettings().hasPodDomain(); - Helpers.animateToActivity(SplashActivity.this, - hasPodDomain ? MainActivity.class : PodSelectionActivity.class, - true - ); - } - }; -} 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 new file mode 100644 index 00000000..840b1964 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/ThemedActivity.java @@ -0,0 +1,78 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.activity; + +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.graphics.drawable.BitmapDrawable; +import android.os.Build; +import android.support.v7.app.AppCompatActivity; + +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.theming.ThemeHelper; + +/** + * Activity that supports color schemes + * Created by vanitas on 06.10.16. + */ + +public abstract class ThemedActivity extends AppCompatActivity { + + protected AppSettings getAppSettings() { + return ((App)getApplication()).getSettings(); + } + + @Override + protected void onResume() { + super.onResume(); + ThemeHelper.getInstance(getAppSettings()); + updateStatusBarColor(); + updateRecentAppColor(); + applyColorToViews(); + } + protected abstract void applyColorToViews(); + + /** + * Update color of the status bar + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private void updateStatusBarColor() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getWindow().setStatusBarColor(ThemeHelper.getPrimaryDarkColor()); + } + } + + /** + * Update primary color in recent apps overview + */ + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private void updateRecentAppColor(){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BitmapDrawable drawable = ((BitmapDrawable) getDrawable(R.drawable.ic_launcher)); + if(drawable != null) { + setTaskDescription(new ActivityManager.TaskDescription( + getResources().getString(R.string.app_name), + drawable.getBitmap(), + getAppSettings().getPrimaryColor())); + } + } + } +} 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 da5839c9..b6cb17b2 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 @@ -1,19 +1,15 @@ /* This file is part of the Diaspora for Android. - Diaspora for Android is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Diaspora for Android is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with the Diaspora for Android. - If not, see . */ package com.github.dfa.diaspora_android.data; @@ -23,6 +19,7 @@ import android.content.Context; import android.content.SharedPreferences; import com.github.dfa.diaspora_android.R; +import com.github.dfa.diaspora_android.util.ProxyHandler; /** * Settings @@ -202,7 +199,7 @@ public class AppSettings { @SuppressLint("CommitPrefEdits") public void setProxyEnabled(boolean enabled) { //commit instead of apply because the app is likely to be killed before apply is called. - prefApp.edit().putBoolean(context.getString(R.string.pref_key__proxy_enabled), enabled).commit(); + prefApp.edit().putBoolean(context.getString(R.string.pref_key__http_proxy_enabled), enabled).commit(); } /** @@ -211,7 +208,7 @@ public class AppSettings { * @return whether proxy is enabled or not */ public boolean isProxyEnabled() { - return getBoolean(prefApp, R.string.pref_key__proxy_enabled, false); + return getBoolean(prefApp, R.string.pref_key__http_proxy_enabled, false); } public boolean wasProxyEnabled() { @@ -235,9 +232,12 @@ public class AppSettings { * @return proxy host */ public String getProxyHost() { - return getString(prefApp, R.string.pref_key__proxy_host, ""); + return getString(prefApp, R.string.pref_key__http_proxy_host, ""); } + public void setProxyHttpHost(String value) { + setString(prefApp, R.string.pref_key__http_proxy_host, value); + } /** * Default value: 0 * @@ -245,13 +245,21 @@ public class AppSettings { */ public int getProxyPort() { try { - return Integer.parseInt(getString(prefApp, R.string.pref_key__proxy_port, "0")); + return Integer.parseInt(getString(prefApp, R.string.pref_key__http_proxy_port, "0")); } catch (Exception e) { - setString(prefApp, R.string.pref_key__proxy_port, "0"); + setString(prefApp, R.string.pref_key__http_proxy_port, "0"); return 0; } } + public void setProxyHttpPort(int value) { + setInt(prefApp, R.string.pref_key__http_proxy_port, value); + } + + public ProxyHandler.ProxySettings getProxySettings() { + return new ProxyHandler.ProxySettings(isProxyEnabled(), getProxyHost(), getProxyPort()); + } + public boolean isIntellihideToolbars() { return getBoolean(prefApp, R.string.pref_key__intellihide_toolbars, false); } @@ -307,4 +315,36 @@ public class AppSettings { public boolean isVisibleInNavProfile() { return getBoolean(prefApp, R.string.pref_key__visibility_nav__profile, false); } -} + + public void setPrimaryColorSettings(int base, int shade) { + setInt(prefApp, R.string.pref_key__primary_color_base, base); + setInt(prefApp, R.string.pref_key__primary_color_shade, shade); + } + + public int[] getPrimaryColorSettings() { + return new int[]{ + getInt(prefApp, R.string.pref_key__primary_color_base, context.getResources().getColor(R.color.md_blue_500)), + getInt(prefApp, R.string.pref_key__primary_color_shade, context.getResources().getColor(R.color.primary)) + }; + } + + public int getPrimaryColor() { + return getInt(prefApp, R.string.pref_key__primary_color_shade, context.getResources().getColor(R.color.primary)); + } + + public void setAccentColorSettings(int base, int shade) { + setInt(prefApp, R.string.pref_key__accent_color_base, base); + setInt(prefApp, R.string.pref_key__accent_color_shade, shade); + } + + public int[] getAccentColorSettings() { + return new int[]{ + getInt(prefApp, R.string.pref_key__accent_color_base, context.getResources().getColor(R.color.md_deep_orange_500)), + getInt(prefApp, R.string.pref_key__accent_color_shade, context.getResources().getColor(R.color.accent)) + }; + } + + public int getAccentColor() { + return getInt(prefApp, R.string.pref_key__accent_color_shade, context.getResources().getColor(R.color.accent)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/WebViewFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/BrowserFragment.java similarity index 56% rename from app/src/main/java/com/github/dfa/diaspora_android/fragment/WebViewFragment.java rename to app/src/main/java/com/github/dfa/diaspora_android/fragment/BrowserFragment.java index 4f6b9bfb..9213ca9f 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/fragment/WebViewFragment.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/BrowserFragment.java @@ -1,9 +1,24 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.fragment; import android.Manifest; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -11,23 +26,27 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.os.Environment; -import android.os.StrictMode; import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; +import android.view.ViewGroup; import android.webkit.WebSettings; import android.webkit.WebView; -import android.webkit.WebViewClient; import android.widget.ProgressBar; -import android.widget.Toast; import com.github.dfa.diaspora_android.App; import com.github.dfa.diaspora_android.R; import com.github.dfa.diaspora_android.activity.MainActivity; import com.github.dfa.diaspora_android.data.AppSettings; +import com.github.dfa.diaspora_android.util.ProxyHandler; import com.github.dfa.diaspora_android.ui.ContextMenuWebView; -import com.github.dfa.diaspora_android.ui.CustomWebViewClient; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.webview.CustomWebViewClient; +import com.github.dfa.diaspora_android.webview.ProgressBarWebChromeClient; import java.io.File; import java.io.FileOutputStream; @@ -38,42 +57,73 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import info.guardianproject.netcipher.NetCipher; -import info.guardianproject.netcipher.webkit.WebkitProxy; - /** - * Fragment that contains a WebView with a bunch of functionality - * Created by vanitas on 21.09.16. + * Fragment with a webView and a ProgressBar. + * This Fragment retains its instance. + * Created by vanitas on 26.09.16. */ -public abstract class WebViewFragment extends CustomFragment { +public class BrowserFragment extends ThemedFragment { + public static final String TAG = "com.github.dfa.diaspora_android.BrowserFragment"; - protected WebSettings webSettings; - protected WebViewClient webViewClient; + protected View rootLayout; protected ContextMenuWebView webView; protected ProgressBar progressBar; protected AppSettings appSettings; + protected CustomWebViewClient webViewClient; + protected WebSettings webSettings; - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); + protected String pendingUrl; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + AppLog.d(this, "onCreateView()"); + if(rootLayout == null) { + rootLayout = inflater.inflate(R.layout.browser__fragment, container, false); + } + return rootLayout; } - protected void setup(ContextMenuWebView webView, final ProgressBar progressBar, AppSettings appSettings) { - this.appSettings = appSettings; - this.webSettings = webView.getSettings(); - this.webView = webView; - this.progressBar = progressBar; + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + AppLog.d(this, "onViewCreated()"); + super.onViewCreated(view, savedInstanceState); - if (appSettings.isProxyEnabled()) { - if (!setProxy(appSettings.getProxyHost(), appSettings.getProxyPort())) { - AppLog.e(this, "Could not enable Proxy"); - Toast.makeText(getContext(), R.string.toast_set_proxy_failed, Toast.LENGTH_SHORT).show(); - } - } else if (appSettings.wasProxyEnabled()) { - resetProxy(); + if(this.appSettings == null) { + this.appSettings = ((App) getActivity().getApplication()).getSettings(); } - webSettings.setJavaScriptEnabled(true); + if(this.webView == null) { + this.webView = (ContextMenuWebView) view.findViewById(R.id.webView); + this.applyWebViewSettings(); + ProxyHandler.getInstance().addWebView(webView); + } + + if(this.progressBar == null) { + this.progressBar = (ProgressBar) view.findViewById(R.id.progressBar); + } + + if(pendingUrl != null) { + loadUrl(pendingUrl); + pendingUrl = null; + } + + webView.setParentActivity(getActivity()); + + this.setRetainInstance(true); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + if (getRetainInstance() && rootLayout.getParent() instanceof ViewGroup) { + ((ViewGroup) rootLayout.getParent()).removeView(rootLayout); + } + } + + private void applyWebViewSettings() { + this.webSettings = webView.getSettings(); webSettings.setAllowFileAccess(false); webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true); @@ -91,102 +141,20 @@ public abstract class WebViewFragment extends CustomFragment { //webView.setParentActivity(this); webView.setOverScrollMode(WebView.OVER_SCROLL_ALWAYS); - //Set proxy - if (appSettings.isProxyEnabled()) { - if (!setProxy(appSettings.getProxyHost(), appSettings.getProxyPort())) { - AppLog.d(this, "Could not enable Proxy"); - Toast.makeText(getContext(), R.string.toast_set_proxy_failed, Toast.LENGTH_SHORT).show(); - } - } else if (appSettings.wasProxyEnabled()) { - resetProxy(); - } - - /* - * WebViewClient - */ this.webViewClient = new CustomWebViewClient((App) getActivity().getApplication(), webView); webView.setWebViewClient(webViewClient); + webView.setWebChromeClient(new ProgressBarWebChromeClient(webView, progressBar)); } - /** - * Set proxy according to arguments. host must not be "" or null, port must be positive. - * Return true on success and update appSettings' proxy related values. - * - * @param host proxy host (eg. localhost or 127.0.0.1) - * @param port proxy port (eg. 8118) - * @return success - * @throws IllegalArgumentException if arguments do not fit specifications above - */ - private boolean setProxy(final String host, final int port) { - AppLog.i(this, "StreamFragment.setProxy()"); - if (host != null && !host.equals("") && port >= 0) { - AppLog.i(this, "Set proxy to "+host+":"+port); - //Temporary change thread policy - AppLog.v(this, "Set temporary ThreadPolicy"); - StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); - StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(tmp); - - AppLog.v(this, "Apply NetCipher proxy settings"); - NetCipher.setProxy(host, port); //Proxy for HttpsUrlConnections - try { - //Proxy for the webview - AppLog.v(this, "Apply Webkit proxy settings"); - WebkitProxy.setProxy(MainActivity.class.getName(), getContext().getApplicationContext(), null, host, port); - } catch (Exception e) { - AppLog.e(this, "Could not apply WebKit proxy settings:\n"+e.toString()); - } - AppLog.v(this, "Save changes in appSettings"); - appSettings.setProxyEnabled(true); - appSettings.setProxyWasEnabled(true); - - AppLog.v(this, "Reset old ThreadPolicy"); - StrictMode.setThreadPolicy(old); - AppLog.i(this, "Success! Reload WebView"); - webView.reload(); - return true; - } else { - AppLog.e(this, "Invalid proxy configuration. Host: "+host+" Port: "+port+"\nRefuse to set proxy"); - return false; + @Override + public void onResume() { + super.onResume(); + if(webView != null) { + webSettings.setMinimumFontSize(appSettings.getMinimumFontSize()); + webSettings.setLoadsImagesAutomatically(appSettings.isLoadImages()); } } - private boolean setProxy() { - return setProxy(appSettings.getProxyHost(), appSettings.getProxyPort()); - } - - private void resetProxy() { - AppLog.i(this, "StreamFragment.resetProxy()"); - AppLog.v(this, "write changes to appSettings"); - appSettings.setProxyEnabled(false); - appSettings.setProxyWasEnabled(false); - - //Temporary change thread policy - AppLog.v(this, "Set temporary ThreadPolicy"); - StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); - StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(tmp); - - AppLog.v(this, "clear NetCipher proxy"); - NetCipher.clearProxy(); - try { - AppLog.v(this, "clear WebKit proxy"); - WebkitProxy.resetProxy(MainActivity.class.getName(), getContext()); - } catch (Exception e) { - AppLog.e(this, "Could not clear WebKit proxy:\n"+e.toString()); - } - AppLog.v(this, "Reset old ThreadPolicy"); - StrictMode.setThreadPolicy(old); - - //Restart app - AppLog.i(this, "Success! Restart app due to proxy reset"); - Intent restartActivity = new Intent(getContext(), MainActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT); - AlarmManager mgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); - mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent); - System.exit(0); - } - @SuppressWarnings("ResultOfMethodCallIgnored") protected boolean makeScreenshotOfWebView(boolean hasToShareScreenshot) { AppLog.i(this, "StreamFragment.makeScreenshotOfWebView()"); @@ -270,6 +238,15 @@ public abstract class WebViewFragment extends CustomFragment { } @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do here */ + } + public boolean onBackPressed() { if(webView.canGoBack()) { webView.goBack(); @@ -279,20 +256,36 @@ public abstract class WebViewFragment extends CustomFragment { } public void loadUrl(String url) { - AppLog.v(this, "loadUrl("+url+")"); - getWebView().loadUrlNew(url); + if(getWebView() != null) { + AppLog.v(this, "loadUrl(): load "+url); + getWebView().loadUrlNew(url); + } else { + AppLog.v(this, "loadUrl(): WebView null: Set pending url to "+url); + pendingUrl = url; + } } public String getUrl() { - return getWebView().getUrl(); + if(getWebView() != null) { + return getWebView().getUrl(); + } else { + return pendingUrl; + } } public void reloadUrl() { AppLog.v(this, "reloadUrl()"); - getWebView().reload(); + if(getWebView() != null) { + getWebView().reload(); + } } public ContextMenuWebView getWebView() { return this.webView; } + + @Override + protected void applyColorToViews() { + ThemeHelper.updateProgressBarColor(progressBar); + } } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/CustomFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/CustomFragment.java index 255370cc..3673d739 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/fragment/CustomFragment.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/CustomFragment.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.fragment; import android.os.Bundle; @@ -12,6 +30,8 @@ import android.view.MenuInflater; public abstract class CustomFragment extends Fragment { + public static final String TAG = "com.github.dfa.diaspora_android.CustomFragment"; + /** * We have an optionsMenu * @param savedInstanceState state diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/StreamFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/DiasporaStreamFragment.java similarity index 54% rename from app/src/main/java/com/github/dfa/diaspora_android/fragment/StreamFragment.java rename to app/src/main/java/com/github/dfa/diaspora_android/fragment/DiasporaStreamFragment.java index 4f735b5c..d10b4e6d 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/fragment/StreamFragment.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/DiasporaStreamFragment.java @@ -1,7 +1,26 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.fragment; import android.Manifest; import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; @@ -12,23 +31,21 @@ import android.os.Bundle; import android.provider.MediaStore; import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; import android.webkit.JavascriptInterface; import android.webkit.ValueCallback; import android.webkit.WebChromeClient; import android.webkit.WebView; -import android.widget.ProgressBar; import com.github.dfa.diaspora_android.App; import com.github.dfa.diaspora_android.R; import com.github.dfa.diaspora_android.activity.MainActivity; import com.github.dfa.diaspora_android.data.PodUserProfile; -import com.github.dfa.diaspora_android.ui.ContextMenuWebView; +import com.github.dfa.diaspora_android.webview.DiasporaStreamWebChromeClient; +import com.github.dfa.diaspora_android.webview.FileUploadWebChromeClient; import com.github.dfa.diaspora_android.util.AppLog; import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; import com.github.dfa.diaspora_android.util.Helpers; @@ -40,161 +57,33 @@ import java.io.File; import java.io.IOException; /** - * Fragment that contains a WebView displaying the stream of the user - * Created by vanitas on 21.09.16. + * Fragment that displays the Stream of the diaspora* user + * Created by vanitas on 26.09.16. */ -public class StreamFragment extends WebViewFragment { +public class DiasporaStreamFragment extends BrowserFragment { public static final String TAG = "com.github.dfa.diaspora_android.StreamFragment"; - private DiasporaUrlHelper urls; + protected DiasporaUrlHelper urls; private ValueCallback imageUploadFilePathCallbackNew; private ValueCallback imageUploadFilePathCallbackOld; private String mCameraPhotoPath; - protected String textToBeShared; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - AppLog.d(this, "onCreateView()"); - return inflater.inflate(R.layout.stream__fragment, container, false); - } + @SuppressLint("SetJavaScriptEnabled") @Override public void onViewCreated(View view, Bundle savedInstanceState) { - AppLog.d(this, "onViewCreated()"); super.onViewCreated(view, savedInstanceState); - this.webView = (ContextMenuWebView) view.findViewById(R.id.webView); - this.progressBar = (ProgressBar) view.findViewById(R.id.progressBar); - this.appSettings = ((App) getActivity().getApplication()).getSettings(); this.urls = new DiasporaUrlHelper(appSettings); + webView.setWebChromeClient(new DiasporaStreamWebChromeClient(webView, progressBar, fileUploadCallback, sharedTextCallback)); - this.setup( - webView, - progressBar, - appSettings); - - // Setup WebView + webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new JavaScriptInterface(), "AndroidBridge"); - - if(webView.getUrl() == null) { - loadUrl(urls.getPodUrl()); + if(((MainActivity)getActivity()).getTextToBeShared() != null) { + loadUrl(urls.getNewPostUrl()); + } else if(webView.getUrl() == null) { + loadUrl(urls.getStreamUrl()); } - - //Set WebChromeClient - webView.setWebChromeClient(new WebChromeClient() { - final ProgressBar pb = progressBar; - - public void onProgressChanged(WebView wv, int progress) { - pb.setProgress(progress); - - if (progress > 0 && progress <= 60) { - WebHelper.getUserProfile(wv); - WebHelper.optimizeMobileSiteLayout(wv); - } - - if (progress > 60) { - WebHelper.optimizeMobileSiteLayout(wv); - - if (textToBeShared != null) { - AppLog.d(this, "Share text into webView"); - WebHelper.shareTextIntoWebView(wv, textToBeShared); - } - } - - progressBar.setVisibility(progress == 100 ? View.GONE : View.VISIBLE); - } - - //For Android 4.1/4.2 only. DO NOT REMOVE! - @SuppressWarnings("unused") - protected void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) - { - AppLog.v(this, "openFileChooser(ValCallback, String, String"); - //imageUploadFilePathCallbackOld = uploadMsg; - Intent intent = new Intent(); - intent.setType("image/*"); - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.putExtra("return-data", true); - intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); - AppLog.v(this, "startActivityForResult"); - startActivityForResult(Intent.createChooser(intent, "Select Picture"), MainActivity.INPUT_FILE_REQUEST_CODE_OLD); - } - - @Override - public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { - if(Build.VERSION.SDK_INT >= 23) { - int hasWRITE_EXTERNAL_STORAGE = getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); - if (hasWRITE_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) { - if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { - new AlertDialog.Builder(getContext()) - .setMessage(R.string.permissions_image) - .setNegativeButton(android.R.string.no, null) - .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (android.os.Build.VERSION.SDK_INT >= 23) - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - MainActivity.REQUEST_CODE_ASK_PERMISSIONS); - } - }) - .show(); - return false; - } - requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, - MainActivity.REQUEST_CODE_ASK_PERMISSIONS); - return false; - } - } - AppLog.d(this, "onOpenFileChooser"); - if (imageUploadFilePathCallbackNew != null) imageUploadFilePathCallbackNew.onReceiveValue(null); - imageUploadFilePathCallbackNew = filePathCallback; - Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - if (takePictureIntent.resolveActivity(getContext().getPackageManager()) != null) { - // Create the File where the photo should go - File photoFile; - try { - photoFile = Helpers.createImageFile(); - takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath); - } catch (IOException ex) { - AppLog.e(this, "ERROR creating temp file: "+ ex.toString()); - // Error occurred while creating the File - Snackbar.make(webView, R.string.unable_to_load_image, Snackbar.LENGTH_LONG).show(); - return false; - } - // Continue only if the File was successfully created - if (photoFile != null) { - mCameraPhotoPath = "file:" + photoFile.getAbsolutePath(); - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, - Uri.fromFile(photoFile)); - } else { - takePictureIntent = null; - } - } - Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); - contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); - contentSelectionIntent.setType("image/*"); - Intent[] intentArray; - if (takePictureIntent != null) { - intentArray = new Intent[]{takePictureIntent}; - } else { - intentArray = new Intent[0]; - } - Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); - chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); - chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); - AppLog.d(this, "startActivityForResult"); - startActivityForResult(chooserIntent, MainActivity.INPUT_FILE_REQUEST_CODE_NEW); - return true; - } - }); - - this.setRetainInstance(true); - } - - @Override - public String getFragmentTag() { - return TAG; } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { @@ -213,7 +102,7 @@ public class StreamFragment extends WebViewFragment { switch (requestCode) { case MainActivity.INPUT_FILE_REQUEST_CODE_NEW: case MainActivity.INPUT_FILE_REQUEST_CODE_OLD: - AppLog.d(this, "INPUT_FILE_REQUEST_CODE: "+requestCode); + AppLog.v(this, "INPUT_FILE_REQUEST_CODE: "+requestCode); onImageUploadResult(requestCode, resultCode, data); return; } @@ -267,16 +156,6 @@ public class StreamFragment extends WebViewFragment { return super.onOptionsItemSelected(item); } - @Override - public ContextMenuWebView getWebView() { - AppLog.d(this, "getWebView: "+(this.webView != null)); - return this.webView; - } - - public void setTextToBeShared(String text) { - this.textToBeShared = text; - } - public void onImageUploadResult(int requestCode, int resultCode, Intent data) { AppLog.d(this, "onImageUploadResult"); switch (requestCode) { @@ -344,7 +223,102 @@ public class StreamFragment extends WebViewFragment { } } + protected DiasporaStreamWebChromeClient.SharedTextCallback sharedTextCallback = new DiasporaStreamWebChromeClient.SharedTextCallback() { + @Override + public String getSharedText() { + return ((MainActivity)getActivity()).getTextToBeShared(); + } + @Override + public void setSharedText(String shared) { + ((MainActivity)getActivity()).setTextToBeShared(shared); + } + }; + + protected FileUploadWebChromeClient.FileUploadCallback fileUploadCallback = new FileUploadWebChromeClient.FileUploadCallback() { + @Override + public boolean imageUpload(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { + if(Build.VERSION.SDK_INT >= 23) { + int hasWRITE_EXTERNAL_STORAGE = getActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (hasWRITE_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) { + if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + new AlertDialog.Builder(getContext()) + .setMessage(R.string.permissions_image) + .setNegativeButton(android.R.string.no, null) + .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (android.os.Build.VERSION.SDK_INT >= 23) + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MainActivity.REQUEST_CODE_ASK_PERMISSIONS); + } + }) + .show(); + return false; + } + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MainActivity.REQUEST_CODE_ASK_PERMISSIONS); + return false; + } + } + AppLog.v(this, "onOpenFileChooser"); + if (imageUploadFilePathCallbackNew != null) imageUploadFilePathCallbackNew.onReceiveValue(null); + imageUploadFilePathCallbackNew = filePathCallback; + Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + if (takePictureIntent.resolveActivity(getContext().getPackageManager()) != null) { + // Create the File where the photo should go + File photoFile; + try { + photoFile = Helpers.createImageFile(); + takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath); + } catch (IOException ex) { + AppLog.e(this, "ERROR creating temp file: "+ ex.toString()); + // Error occurred while creating the File + Snackbar.make(webView, R.string.unable_to_load_image, Snackbar.LENGTH_LONG).show(); + return false; + } + // Continue only if the File was successfully created + if (photoFile != null) { + mCameraPhotoPath = "file:" + photoFile.getAbsolutePath(); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, + Uri.fromFile(photoFile)); + } else { + takePictureIntent = null; + } + } + Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); + contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); + contentSelectionIntent.setType("image/*"); + Intent[] intentArray; + if (takePictureIntent != null) { + intentArray = new Intent[]{takePictureIntent}; + } else { + intentArray = new Intent[0]; + } + Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); + chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); + chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); + AppLog.d(this, "startActivityForResult"); + startActivityForResult(chooserIntent, MainActivity.INPUT_FILE_REQUEST_CODE_NEW); + return true; + } + + @Override + public void legacyImageUpload(ValueCallback uploadMsg, String acceptType, String capture) { + AppLog.v(this, "openFileChooser(ValCallback, String, String"); + imageUploadFilePathCallbackOld = uploadMsg; + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + intent.putExtra("return-data", true); + intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); + AppLog.v(this, "startActivityForResult"); + startActivityForResult(Intent.createChooser(intent, "Select Picture"), MainActivity.INPUT_FILE_REQUEST_CODE_OLD); + } + }; + private class JavaScriptInterface { + @SuppressWarnings("unused") @JavascriptInterface public void setUserProfile(final String webMessage) throws JSONException { PodUserProfile pup = ((App)getActivity().getApplication()).getPodUserProfile(); @@ -357,9 +331,15 @@ public class StreamFragment extends WebViewFragment { } } + @SuppressWarnings("unused") @JavascriptInterface public void contentHasBeenShared() { - textToBeShared = null; + ((MainActivity)getActivity()).setTextToBeShared(null); } } + + @Override + public String getFragmentTag() { + return TAG; + } } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/HashtagListFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/HashtagListFragment.java new file mode 100644 index 00000000..104d6951 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/HashtagListFragment.java @@ -0,0 +1,146 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.fragment; + +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +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.MainActivity; +import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; + +/** + * Fragment that shows a list of the Hashtags the user follows + * Created by vanitas on 29.09.16. + */ + +public class HashtagListFragment extends CustomFragment { + + public static final String TAG = "com.github.dfa.diaspora_android.HashtagListFragment"; + + protected RecyclerView followedTagsRecyclerView; + protected String[] followedTags; + protected App app; + protected DiasporaUrlHelper urls; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + AppLog.d(this, "onCreateView()"); + return inflater.inflate(R.layout.hashtag_list__fragment, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + this.followedTagsRecyclerView = (RecyclerView) view.findViewById(R.id.fragment_followed_tags__recycler_view); + this.app = (App) getActivity().getApplication(); + this.urls = new DiasporaUrlHelper(app.getSettings()); + + followedTags = app.getPodUserProfile().getFollowedTags(); + followedTagsRecyclerView.setHasFixedSize(true); + followedTagsRecyclerView.setNestedScrollingEnabled(false); + + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this.getContext()); + followedTagsRecyclerView.setLayoutManager(layoutManager); + + final FollowedTagsAdapter adapter = new FollowedTagsAdapter(followedTags, onHashtagClickListener); + followedTagsRecyclerView.setAdapter(adapter); + + //Set window title + getActivity().setTitle(R.string.nav_followed_tags); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } + + protected View.OnClickListener onHashtagClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + int itemPosition = followedTagsRecyclerView.getChildLayoutPosition(view); + if(itemPosition > -1 && itemPosition < followedTags.length) { + String tag = followedTags[itemPosition]; + ((MainActivity)getActivity()).openDiasporaUrl(urls.getSearchTagsUrl(tag)); + } + } + }; + + public static class FollowedTagsAdapter extends RecyclerView.Adapter { + private String[] followedTagsList; + private View.OnClickListener itemClickListener; + + public static class ViewHolder extends RecyclerView.ViewHolder { + // each data item is just a string in this case + public TextView title; + + public ViewHolder(View v) { + super(v); + title = (TextView) v.findViewById(R.id.recycler_view__list_item__text); + } + } + + // Provide a suitable constructor (depends on the kind of dataset) + public FollowedTagsAdapter(String[] tags, View.OnClickListener itemClickListener) { + this.followedTagsList = tags; + this.itemClickListener = itemClickListener; + } + + @Override + public FollowedTagsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.recycler_view__list_item, parent, false); + v.setOnClickListener(itemClickListener); + return new ViewHolder(v); + } + + // Replace the contents of a view (invoked by the layout manager) + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + + holder.title.setText(followedTagsList[position]); + + } + + // Return the size of your dataset (invoked by the layout manager) + @Override + public int getItemCount() { + return followedTagsList.length; + } + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/PodSelectionActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/PodSelectionFragment.java similarity index 61% rename from app/src/main/java/com/github/dfa/diaspora_android/activity/PodSelectionActivity.java rename to app/src/main/java/com/github/dfa/diaspora_android/fragment/PodSelectionFragment.java index 57103f6b..9a2ad317 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/PodSelectionActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/PodSelectionFragment.java @@ -16,7 +16,7 @@ If not, see . */ -package com.github.dfa.diaspora_android.activity; +package com.github.dfa.diaspora_android.fragment; import android.app.AlertDialog; import android.content.BroadcastReceiver; @@ -28,64 +28,103 @@ import android.os.Build; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v4.content.LocalBroadcastManager; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.SpannableString; import android.text.TextWatcher; import android.text.util.Linkify; +import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.webkit.CookieManager; +import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; +import android.widget.ImageView; import android.widget.ListView; import com.github.dfa.diaspora_android.App; import com.github.dfa.diaspora_android.R; +import com.github.dfa.diaspora_android.activity.MainActivity; +import com.github.dfa.diaspora_android.data.AppSettings; import com.github.dfa.diaspora_android.task.GetPodsService; -import com.github.dfa.diaspora_android.util.Helpers; +import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; import com.github.dfa.diaspora_android.util.WebHelper; import java.util.ArrayList; -import butterknife.BindView; -import butterknife.ButterKnife; -import butterknife.OnClick; -import butterknife.OnItemClick; +/** + * Fragment that lets the user choose a Pod + * Created by vanitas on 01.10.16. + */ +public class PodSelectionFragment extends CustomFragment { + public static final String TAG = "com.github.dfa.diaspora_android.PodSelectionFragment"; -public class PodSelectionActivity extends AppCompatActivity { - private App app; + protected EditText editFilter; + protected ListView listPods; + protected ImageView selectPodButton; - @BindView(R.id.podselection__edit_filter) - EditText editFilter; - - @BindView(R.id.podselection__listpods) - ListView listPods; - - @BindView(R.id.main__topbar) - Toolbar toolbar; + protected App app; + protected AppSettings appSettings; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.podselection__activity); - ButterKnife.bind(this); - app = (App) getApplication(); - setSupportActionBar(toolbar); - - - listPods.setTextFilterEnabled(true); - setListedPods(app.getSettings().getPreviousPodlist()); - LocalBroadcastManager.getInstance(this).registerReceiver(podListReceiver, new IntentFilter(GetPodsService.MESSAGE_PODS_RECEIVED)); - - if (!WebHelper.isOnline(PodSelectionActivity.this)) { - Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show(); - } + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + AppLog.d(this, "onCreateView()"); + return inflater.inflate(R.layout.podselection__fragment, container, false); } + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + this.app = (App) getActivity().getApplication(); + this.appSettings = app.getSettings(); + + this.editFilter = (EditText) view.findViewById(R.id.podselection__edit_filter); + this.listPods = (ListView) view.findViewById(R.id.podselection__listpods); + this.selectPodButton = (ImageView) view.findViewById(R.id.podselection__button_select_pod); + + listPods.setTextFilterEnabled(true); + listPods.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + showPodConfirmationDialog((String) listPods.getAdapter().getItem(i)); + } + }); + setListedPods(appSettings.getPreviousPodlist()); + LocalBroadcastManager.getInstance(getContext()).registerReceiver(podListReceiver, new IntentFilter(GetPodsService.MESSAGE_PODS_RECEIVED)); + if (!WebHelper.isOnline(getContext())) { + Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show(); + } + selectPodButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (editFilter.getText().length() > 4 && editFilter.getText().toString().contains("")) { + showPodConfirmationDialog(editFilter.getText().toString()); + } else { + Snackbar.make(listPods, R.string.valid_pod, Snackbar.LENGTH_LONG).show(); + } + } + }); + } + + @Override + public String getFragmentTag() { + return TAG; + } + + @Override + public void onCreateBottomOptionsMenu(Menu menu, MenuInflater inflater) { + /* Nothing to do */ + } + + @Override + public boolean onBackPressed() { + return false; + } private final BroadcastReceiver podListReceiver = new BroadcastReceiver() { @Override @@ -104,20 +143,11 @@ public class PodSelectionActivity extends AppCompatActivity { } }; - @OnClick(R.id.podselection__button_select_pod) - public void onButtonSelectPodClicked(View view) { - if (editFilter.getText().length() > 4 && editFilter.getText().toString().contains("")) { - showPodConfirmationDialog(editFilter.getText().toString()); - } else { - Snackbar.make(listPods, R.string.valid_pod, Snackbar.LENGTH_LONG).show(); - } - } - @Override - protected void onResume() { + public void onResume() { super.onResume(); - Intent i = new Intent(PodSelectionActivity.this, GetPodsService.class); - startService(i); + Intent i = new Intent(getContext(), GetPodsService.class); + getContext().startService(i); } @@ -128,7 +158,7 @@ public class PodSelectionActivity extends AppCompatActivity { } final ArrayAdapter adapter = new ArrayAdapter<>( - PodSelectionActivity.this, + getContext(), android.R.layout.simple_list_item_1, listedPodsList); @@ -154,24 +184,19 @@ public class PodSelectionActivity extends AppCompatActivity { }); } - @OnItemClick(R.id.podselection__listpods) - public void onListPodsItemClicked(int position) { - showPodConfirmationDialog((String) listPods.getAdapter().getItem(position)); - } - private void showPodConfirmationDialog(final String selectedPod) { // Make a clickable link final SpannableString dialogMessage = new SpannableString(getString(R.string.confirm_pod, selectedPod)); Linkify.addLinks(dialogMessage, Linkify.ALL); // Check if online - if (!WebHelper.isOnline(PodSelectionActivity.this)) { + if (!WebHelper.isOnline(getContext())) { Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show(); return; } // Show dialog - new AlertDialog.Builder(PodSelectionActivity.this) + new AlertDialog.Builder(getContext()) .setTitle(getString(R.string.confirmation)) .setMessage(dialogMessage) .setPositiveButton(android.R.string.yes, @@ -201,40 +226,28 @@ public class PodSelectionActivity extends AppCompatActivity { e.printStackTrace(); } - Helpers.animateToActivity(this, MainActivity.class, true); - } - - - @Override - public void onBackPressed() { - Snackbar.make(listPods, R.string.confirm_exit, Snackbar.LENGTH_LONG) - .setAction(android.R.string.yes, new View.OnClickListener() { - public void onClick(View view) { - finish(); - } - }) - .show(); + ((MainActivity)getActivity()).openDiasporaUrl(new DiasporaUrlHelper(appSettings).getPodUrl()); } @Override - protected void onDestroy() { - LocalBroadcastManager.getInstance(this).unregisterReceiver(podListReceiver); + public void onDestroy() { + LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(podListReceiver); super.onDestroy(); } @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.podselection__menu, menu); - return true; + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.podselection__menu, menu); + super.onCreateOptionsMenu(menu, inflater); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_reload: { - if (WebHelper.isOnline(PodSelectionActivity.this)) { - Intent i = new Intent(PodSelectionActivity.this, GetPodsService.class); - startService(i); + if (WebHelper.isOnline(getContext())) { + Intent i = new Intent(getContext(), GetPodsService.class); + getContext().startService(i); return true; } else { Snackbar.make(listPods, R.string.no_internet, Snackbar.LENGTH_LONG).show(); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedFragment.java new file mode 100644 index 00000000..ca3f3965 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/fragment/ThemedFragment.java @@ -0,0 +1,43 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.fragment; + +import com.github.dfa.diaspora_android.App; +import com.github.dfa.diaspora_android.data.AppSettings; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; + +/** + * Fragment that supports color schemes + * Created by vanitas on 06.10.16. + */ + +public abstract class ThemedFragment extends CustomFragment { + protected AppSettings getAppSettings() { + return ((App)getActivity().getApplication()).getSettings(); + } + + protected abstract void applyColorToViews(); + + @Override + public void onResume() { + super.onResume(); + ThemeHelper.getInstance(getAppSettings()); + applyColorToViews(); + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/receiver/OpenExternalLinkReceiver.java b/app/src/main/java/com/github/dfa/diaspora_android/receiver/OpenExternalLinkReceiver.java index 3373d074..41ef57a5 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/receiver/OpenExternalLinkReceiver.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/receiver/OpenExternalLinkReceiver.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.receiver; import android.app.Activity; @@ -15,7 +33,7 @@ import com.github.dfa.diaspora_android.data.AppSettings; import com.github.dfa.diaspora_android.util.AppLog; import com.github.dfa.diaspora_android.util.CustomTabHelpers.BrowserFallback; import com.github.dfa.diaspora_android.util.CustomTabHelpers.CustomTabActivityHelper; -import com.github.dfa.diaspora_android.util.Helpers; +import com.github.dfa.diaspora_android.util.theming.ThemeHelper; /** * BroadcastReceiver that opens links in a Chrome CustomTab @@ -30,9 +48,10 @@ public class OpenExternalLinkReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent receiveIntent) { - AppSettings settings = new AppSettings(c); + AppSettings appSettings = new AppSettings(c); + ThemeHelper.getInstance(appSettings); - AppLog.v(this, "OpenExternalLinkReceiver.onReceive(): url"); + AppLog.v(this, "OpenExternalLinkReceiver.onReceive(): url"); Uri url = null; try { @@ -43,10 +62,10 @@ public class OpenExternalLinkReceiver extends BroadcastReceiver { return; } - if (settings.isChromeCustomTabsEnabled()) { + if (appSettings.isChromeCustomTabsEnabled()) { // Setup Chrome Custom Tab CustomTabsIntent.Builder customTab = new CustomTabsIntent.Builder(); - customTab.setToolbarColor(Helpers.getColorFromRessource(c, R.color.colorPrimary)); + customTab.setToolbarColor(ThemeHelper.getPrimaryColor()); customTab.addDefaultShareMenuItem(); Bitmap backButtonIcon = BitmapFactory.decodeResource(c.getResources(), R.drawable.chrome_custom_tab__back); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/receiver/UpdateTitleReceiver.java b/app/src/main/java/com/github/dfa/diaspora_android/receiver/UpdateTitleReceiver.java index bb30421a..ca8eda16 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/receiver/UpdateTitleReceiver.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/receiver/UpdateTitleReceiver.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.receiver; import android.content.BroadcastReceiver; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/BadgeDrawable.java b/app/src/main/java/com/github/dfa/diaspora_android/ui/BadgeDrawable.java index 03460aa9..370b822f 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/ui/BadgeDrawable.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/ui/BadgeDrawable.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.ui; import android.content.Context; @@ -30,7 +48,7 @@ public class BadgeDrawable extends Drawable { float textSize = context.getResources().getDimension(R.dimen.textsize_badge_count); badgeBackground = new Paint(); - badgeBackground.setColor(ContextCompat.getColor(context.getApplicationContext(), R.color.accent)); + badgeBackground.setColor(ContextCompat.getColor(context.getApplicationContext(), R.color.md_deep_orange_650)); badgeBackground.setAntiAlias(true); badgeBackground.setStyle(Paint.Style.FILL); badgeStroke = new Paint(); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java b/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java index adac6fd2..3be4ce63 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java @@ -123,22 +123,49 @@ public class ContextMenuWebView extends NestedWebView { case ID_SHARE_IMAGE: if (url != null) { - final Uri local = Uri.parse(Environment.getExternalStorageDirectory() + "/Pictures/Diaspora/" + System.currentTimeMillis() + ".png"); - new ImageDownloadTask(null, local.getPath()) { - @Override - protected void onPostExecute(Bitmap result) { - Uri myUri = Uri.fromFile(new File(local.getPath())); - Intent sharingIntent = new Intent(); - sharingIntent.setAction(Intent.ACTION_SEND); - sharingIntent.putExtra(Intent.EXTRA_STREAM, myUri); - sharingIntent.setType("image/png"); - sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - context.startActivity(Intent.createChooser(sharingIntent, "Share image using")); + boolean writeToStoragePermitted = true; + if (android.os.Build.VERSION.SDK_INT >= 23) { + int hasWRITE_EXTERNAL_STORAGE = parentActivity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (hasWRITE_EXTERNAL_STORAGE != PackageManager.PERMISSION_GRANTED) { + writeToStoragePermitted = false; + if (!parentActivity.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + new AlertDialog.Builder(parentActivity) + .setMessage(R.string.permissions_image) + .setPositiveButton(context.getText(android.R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (android.os.Build.VERSION.SDK_INT >= 23) + parentActivity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MainActivity.REQUEST_CODE__ACCESS_EXTERNAL_STORAGE); + } + }) + .setNegativeButton(context.getText(android.R.string.no), null) + .show(); + } else { + parentActivity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MainActivity.REQUEST_CODE__ACCESS_EXTERNAL_STORAGE); + } } - }.execute(url); + } + if (writeToStoragePermitted) { + final Uri local = Uri.parse(Environment.getExternalStorageDirectory() + "/Pictures/Diaspora/" + System.currentTimeMillis() + ".png"); + new ImageDownloadTask(null, local.getPath()) { + @Override + protected void onPostExecute(Bitmap result) { + Uri myUri = Uri.fromFile(new File(local.getPath())); + Intent sharingIntent = new Intent(); + sharingIntent.setAction(Intent.ACTION_SEND); + sharingIntent.putExtra(Intent.EXTRA_STREAM, myUri); + sharingIntent.setType("image/png"); + sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + context.startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.action_share_dotdotdot))); + } + }.execute(url); + } } else { Toast.makeText(context, "Cannot share image: url is null", Toast.LENGTH_SHORT).show(); } + break; case ID_IMAGE_EXTERNAL_BROWSER: diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/IntellihideToolbarActivityListener.java b/app/src/main/java/com/github/dfa/diaspora_android/ui/IntellihideToolbarActivityListener.java new file mode 100644 index 00000000..61b68a2e --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/ui/IntellihideToolbarActivityListener.java @@ -0,0 +1,14 @@ +package com.github.dfa.diaspora_android.ui; + +import android.support.design.widget.AppBarLayout; + +/** + * interface that adds options to control intellihide of toolbars to the Activity + * Created by vanitas on 08.10.16. + */ + +public interface IntellihideToolbarActivityListener { + int toolbarDefaultScrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS | AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP; + void enableToolbarHiding(); + void disableToolbarHiding(); +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/AppLog.java b/app/src/main/java/com/github/dfa/diaspora_android/util/AppLog.java index 171bbd6c..178cd008 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/AppLog.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/AppLog.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.util; /** diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/BrowserFallback.java b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/BrowserFallback.java index a4bdd930..4e70f1c0 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/BrowserFallback.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/BrowserFallback.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.util.CustomTabHelpers; import android.app.Activity; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabActivityHelper.java b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabActivityHelper.java index 2ab3fc3b..b515adcc 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabActivityHelper.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabActivityHelper.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.util.CustomTabHelpers; import android.app.Activity; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabsHelper.java b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabsHelper.java index 6ab577af..c1b9c546 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabsHelper.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/CustomTabHelpers/CustomTabsHelper.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.util.CustomTabHelpers; import android.content.Context; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/Helpers.java b/app/src/main/java/com/github/dfa/diaspora_android/util/Helpers.java index 830380ec..2c4ba62b 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/Helpers.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/Helpers.java @@ -113,6 +113,10 @@ public class Helpers { return "#" + Integer.toHexString(context.getResources().getColor(idColor) & 0x00ffffff); } + public static String colorToHex(int color) { + return "#" + Integer.toHexString(color & 0x00ffffff); + } + public static void printBundle(Bundle savedInstanceState, String k) { if (savedInstanceState != null) { for (String key : savedInstanceState.keySet()) { diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/Log.java b/app/src/main/java/com/github/dfa/diaspora_android/util/Log.java index ad0791e7..f8743b1d 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/Log.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/Log.java @@ -1,3 +1,21 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ package com.github.dfa.diaspora_android.util; import com.github.dfa.diaspora_android.data.AppSettings; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java b/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java new file mode 100644 index 00000000..a2cbf924 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java @@ -0,0 +1,135 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.util; + +import android.content.Context; +import android.os.StrictMode; +import android.webkit.WebView; + +import com.github.dfa.diaspora_android.activity.MainActivity; +import com.github.dfa.diaspora_android.data.AppSettings; + +import java.util.ArrayList; + +import info.guardianproject.netcipher.NetCipher; +import info.guardianproject.netcipher.webkit.WebkitProxy; + +/** + * Proxy Handler that applies proxy settings of the app to webviews etc. + * Created by vanitas on 10.10.16. + */ + +public class ProxyHandler { + private static ProxyHandler instance; + private ArrayList webViews; + + + private ProxyHandler() { + /* Singleton, yo? */ + this.webViews = new ArrayList<>(); + } + + public static ProxyHandler getInstance() { + if(instance == null) { + instance = new ProxyHandler(); + } + return instance; + } + + public void updateProxySettings(Context context) { + AppLog.d(this, "UpdateProxySettings()"); + AppSettings appSettings = new AppSettings(context); + StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); + StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(tmp); + if (appSettings.isProxyEnabled()) { + //Update NetCipher + NetCipher.setProxy(appSettings.getProxyHost(), appSettings.getProxyPort()); + //Update webviews + for (WebView wv : webViews) { + if (wv != null) { + try { + WebkitProxy.setProxy(MainActivity.class.getName(), context.getApplicationContext(), wv, appSettings.getProxyHost(), appSettings.getProxyPort()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + StrictMode.setThreadPolicy(old); + } + + public void addWebView(WebView wv) { + AppLog.d(this, "AddWebView"); + if(wv != null && !webViews.contains(wv)) { + webViews.add(wv); + updateWebViewProxySettings(wv, wv.getContext()); + } + } + + private void updateWebViewProxySettings(WebView wv, Context context) { + AppLog.d(this, "UpdateWebViewProxySettings()"); + AppSettings appSettings = new AppSettings(context); + StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); + StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(tmp); + if(appSettings.isProxyEnabled()) { + if (wv != null) { + try { + WebkitProxy.setProxy(MainActivity.class.getName(), context.getApplicationContext(), wv, appSettings.getProxyHost(), appSettings.getProxyPort()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + StrictMode.setThreadPolicy(old); + } + + public static class ProxySettings { + private final boolean enabled; + private final String host; + private final int port; + + public ProxySettings(boolean enabled, String host, int port) { + this.enabled = enabled; + this.host = host; + this.port = port; + } + + public boolean isEnabled() { + return enabled; + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + @Override + public boolean equals(Object other) { + return (other instanceof ProxySettings) && + enabled == ((ProxySettings) other).isEnabled() && + host.equals(((ProxySettings) other).getHost()) && + port == ((ProxySettings) other).getPort(); + } + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/WebHelper.java b/app/src/main/java/com/github/dfa/diaspora_android/util/WebHelper.java index 691481be..ba760d7b 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/WebHelper.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/WebHelper.java @@ -62,7 +62,7 @@ public class WebHelper { public static void optimizeMobileSiteLayout(final WebView wv) { wv.loadUrl("javascript: ( function() {" + " if (document.documentElement == null || document.documentElement.style == null) { return; }" + - " document.documentElement.style.paddingBottom = '260px';" + + " document.documentElement.style.paddingBottom = '50px';" + " document.getElementById('main').style.paddingTop = '5px';" + " if(document.getElementById('main_nav')) {" + " document.getElementById('main_nav').parentNode.removeChild(" + diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ColorPalette.java b/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ColorPalette.java new file mode 100644 index 00000000..16f02b90 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ColorPalette.java @@ -0,0 +1,288 @@ +package com.github.dfa.diaspora_android.util.theming; + +import android.content.Context; +import android.graphics.Color; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.ColorUtils; + +import com.github.dfa.diaspora_android.R; + +/** + * Created by dnld on 24/02/16. + */ +public class ColorPalette { + + public static int[] getAccentColors(Context context){ + return new int[]{ + ContextCompat.getColor(context, R.color.md_red_500), + ContextCompat.getColor(context, R.color.md_purple_500), + ContextCompat.getColor(context, R.color.md_deep_purple_500), + ContextCompat.getColor(context, R.color.md_blue_500), + ContextCompat.getColor(context, R.color.md_light_blue_500), + ContextCompat.getColor(context, R.color.md_cyan_500), + ContextCompat.getColor(context, R.color.md_teal_500), + ContextCompat.getColor(context, R.color.md_green_500), + ContextCompat.getColor(context, R.color.md_yellow_500), + ContextCompat.getColor(context, R.color.md_orange_500), + ContextCompat.getColor(context, R.color.md_deep_orange_500), + ContextCompat.getColor(context, R.color.md_brown_500), + ContextCompat.getColor(context, R.color.md_blue_grey_500), + }; + } + + public static int getObscuredColor(int c){ + float[] hsv = new float[3]; + int color = c; + Color.colorToHSV(color, hsv); + hsv[2] *= 0.85f; // value component + color = Color.HSVToColor(hsv); + return color; + } + + public static int getTransparentColor(int color, int alpha){ + return ColorUtils.setAlphaComponent(color, alpha); + } + + public static int[] getTransparencyShadows(int color) { + int[] shadows = new int[10]; + for (int i=0; i<10;i++) + shadows[i]= (ColorPalette.getTransparentColor(color, ((100-(i*10))*255) /100)); + return shadows; + } + + public static int[] getBaseColors(Context context) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_red_500), + ContextCompat.getColor(context, R.color.md_pink_500), + ContextCompat.getColor(context, R.color.md_purple_500), + ContextCompat.getColor(context, R.color.md_deep_purple_500), + ContextCompat.getColor(context, R.color.md_indigo_500), + ContextCompat.getColor(context, R.color.md_blue_500), + ContextCompat.getColor(context, R.color.md_light_blue_500), + ContextCompat.getColor(context, R.color.md_cyan_500), + ContextCompat.getColor(context, R.color.md_teal_500), + ContextCompat.getColor(context, R.color.md_green_500), + ContextCompat.getColor(context, R.color.md_light_green_500), + ContextCompat.getColor(context, R.color.md_lime_500), + ContextCompat.getColor(context, R.color.md_yellow_500), + ContextCompat.getColor(context, R.color.md_amber_500), + ContextCompat.getColor(context, R.color.md_orange_500), + ContextCompat.getColor(context, R.color.md_deep_orange_500), + ContextCompat.getColor(context, R.color.md_brown_500), + ContextCompat.getColor(context, R.color.md_blue_grey_500), + ContextCompat.getColor(context, R.color.md_grey_500) + }; + } + + public static int[] getColors(Context context, int c) { + if (c == ContextCompat.getColor(context, R.color.md_red_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_red_200), + ContextCompat.getColor(context, R.color.md_red_300), + ContextCompat.getColor(context, R.color.md_red_400), + ContextCompat.getColor(context, R.color.md_red_500), + ContextCompat.getColor(context, R.color.md_red_600), + ContextCompat.getColor(context, R.color.md_red_700), + ContextCompat.getColor(context, R.color.md_red_800), + ContextCompat.getColor(context, R.color.md_red_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_pink_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_pink_200), + ContextCompat.getColor(context, R.color.md_pink_300), + ContextCompat.getColor(context, R.color.md_pink_400), + ContextCompat.getColor(context, R.color.md_pink_500), + ContextCompat.getColor(context, R.color.md_pink_600), + ContextCompat.getColor(context, R.color.md_pink_700), + ContextCompat.getColor(context, R.color.md_pink_800), + ContextCompat.getColor(context, R.color.md_pink_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_purple_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_purple_200), + ContextCompat.getColor(context, R.color.md_purple_300), + ContextCompat.getColor(context, R.color.md_purple_400), + ContextCompat.getColor(context, R.color.md_purple_500), + ContextCompat.getColor(context, R.color.md_purple_600), + ContextCompat.getColor(context, R.color.md_purple_700), + ContextCompat.getColor(context, R.color.md_purple_800), + ContextCompat.getColor(context, R.color.md_purple_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_deep_purple_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_deep_purple_200), + ContextCompat.getColor(context, R.color.md_deep_purple_300), + ContextCompat.getColor(context, R.color.md_deep_purple_400), + ContextCompat.getColor(context, R.color.md_deep_purple_500), + ContextCompat.getColor(context, R.color.md_deep_purple_600), + ContextCompat.getColor(context, R.color.md_deep_purple_700), + ContextCompat.getColor(context, R.color.md_deep_purple_800), + ContextCompat.getColor(context, R.color.md_deep_purple_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_indigo_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_indigo_200), + ContextCompat.getColor(context, R.color.md_indigo_300), + ContextCompat.getColor(context, R.color.md_indigo_400), + ContextCompat.getColor(context, R.color.md_indigo_500), + ContextCompat.getColor(context, R.color.md_indigo_600), + ContextCompat.getColor(context, R.color.md_indigo_700), + ContextCompat.getColor(context, R.color.md_indigo_800), + ContextCompat.getColor(context, R.color.md_indigo_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_blue_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_blue_200), + ContextCompat.getColor(context, R.color.md_blue_300), + ContextCompat.getColor(context, R.color.md_blue_400), + ContextCompat.getColor(context, R.color.md_blue_500), + ContextCompat.getColor(context, R.color.md_blue_600), + ContextCompat.getColor(context, R.color.md_blue_650), + ContextCompat.getColor(context, R.color.md_blue_700), + ContextCompat.getColor(context, R.color.md_blue_750), + ContextCompat.getColor(context, R.color.md_blue_800), + ContextCompat.getColor(context, R.color.md_blue_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_light_blue_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_light_blue_200), + ContextCompat.getColor(context, R.color.md_light_blue_300), + ContextCompat.getColor(context, R.color.md_light_blue_400), + ContextCompat.getColor(context, R.color.md_light_blue_500), + ContextCompat.getColor(context, R.color.md_light_blue_600), + ContextCompat.getColor(context, R.color.md_light_blue_700), + ContextCompat.getColor(context, R.color.md_light_blue_800), + ContextCompat.getColor(context, R.color.md_light_blue_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_cyan_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_cyan_200), + ContextCompat.getColor(context, R.color.md_cyan_300), + ContextCompat.getColor(context, R.color.md_cyan_400), + ContextCompat.getColor(context, R.color.md_cyan_500), + ContextCompat.getColor(context, R.color.md_cyan_600), + ContextCompat.getColor(context, R.color.md_cyan_700), + ContextCompat.getColor(context, R.color.md_cyan_800), + ContextCompat.getColor(context, R.color.md_cyan_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_teal_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_teal_200), + ContextCompat.getColor(context, R.color.md_teal_300), + ContextCompat.getColor(context, R.color.md_teal_400), + ContextCompat.getColor(context, R.color.md_teal_500), + ContextCompat.getColor(context, R.color.md_teal_600), + ContextCompat.getColor(context, R.color.md_teal_700), + ContextCompat.getColor(context, R.color.md_teal_800), + ContextCompat.getColor(context, R.color.md_teal_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_green_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_green_200), + ContextCompat.getColor(context, R.color.md_green_300), + ContextCompat.getColor(context, R.color.md_green_400), + ContextCompat.getColor(context, R.color.md_green_500), + ContextCompat.getColor(context, R.color.md_green_600), + ContextCompat.getColor(context, R.color.md_green_700), + ContextCompat.getColor(context, R.color.md_green_800), + ContextCompat.getColor(context, R.color.md_green_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_light_green_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_light_green_200), + ContextCompat.getColor(context, R.color.md_light_green_300), + ContextCompat.getColor(context, R.color.md_light_green_400), + ContextCompat.getColor(context, R.color.md_light_green_500), + ContextCompat.getColor(context, R.color.md_light_green_600), + ContextCompat.getColor(context, R.color.md_light_green_700), + ContextCompat.getColor(context, R.color.md_light_green_800), + ContextCompat.getColor(context, R.color.md_light_green_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_lime_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_lime_200), + ContextCompat.getColor(context, R.color.md_lime_300), + ContextCompat.getColor(context, R.color.md_lime_400), + ContextCompat.getColor(context, R.color.md_lime_500), + ContextCompat.getColor(context, R.color.md_lime_600), + ContextCompat.getColor(context, R.color.md_lime_700), + ContextCompat.getColor(context, R.color.md_lime_800), + ContextCompat.getColor(context, R.color.md_lime_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_yellow_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_yellow_400), + ContextCompat.getColor(context, R.color.md_yellow_500), + ContextCompat.getColor(context, R.color.md_yellow_600), + ContextCompat.getColor(context, R.color.md_yellow_700), + ContextCompat.getColor(context, R.color.md_yellow_800), + ContextCompat.getColor(context, R.color.md_yellow_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_amber_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_amber_200), + ContextCompat.getColor(context, R.color.md_amber_300), + ContextCompat.getColor(context, R.color.md_amber_400), + ContextCompat.getColor(context, R.color.md_amber_500), + ContextCompat.getColor(context, R.color.md_amber_600), + ContextCompat.getColor(context, R.color.md_amber_700), + ContextCompat.getColor(context, R.color.md_amber_800), + ContextCompat.getColor(context, R.color.md_amber_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_orange_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_orange_200), + ContextCompat.getColor(context, R.color.md_orange_300), + ContextCompat.getColor(context, R.color.md_orange_400), + ContextCompat.getColor(context, R.color.md_orange_500), + ContextCompat.getColor(context, R.color.md_orange_600), + ContextCompat.getColor(context, R.color.md_orange_700), + ContextCompat.getColor(context, R.color.md_orange_800), + ContextCompat.getColor(context, R.color.md_orange_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_deep_orange_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_deep_orange_200), + ContextCompat.getColor(context, R.color.md_deep_orange_300), + ContextCompat.getColor(context, R.color.md_deep_orange_400), + ContextCompat.getColor(context, R.color.md_deep_orange_500), + ContextCompat.getColor(context, R.color.md_deep_orange_600), + ContextCompat.getColor(context, R.color.md_deep_orange_650), + ContextCompat.getColor(context, R.color.md_deep_orange_700), + ContextCompat.getColor(context, R.color.md_deep_orange_800), + ContextCompat.getColor(context, R.color.md_deep_orange_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_brown_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_brown_200), + ContextCompat.getColor(context, R.color.md_brown_300), + ContextCompat.getColor(context, R.color.md_brown_400), + ContextCompat.getColor(context, R.color.md_brown_500), + ContextCompat.getColor(context, R.color.md_brown_600), + ContextCompat.getColor(context, R.color.md_brown_700), + ContextCompat.getColor(context, R.color.md_brown_800), + ContextCompat.getColor(context, R.color.md_brown_900) + }; + } else if (c == ContextCompat.getColor(context, R.color.md_grey_500)) { + return new int[]{ + ContextCompat.getColor(context, R.color.md_grey_400), + ContextCompat.getColor(context, R.color.md_grey_500), + ContextCompat.getColor(context, R.color.md_grey_600), + ContextCompat.getColor(context, R.color.md_grey_700), + ContextCompat.getColor(context, R.color.md_grey_800), + ContextCompat.getColor(context, R.color.md_grey_900), + Color.parseColor("#000000") + }; + } else { + return new int[]{ + ContextCompat.getColor(context, R.color.md_blue_grey_300), + ContextCompat.getColor(context, R.color.md_blue_grey_400), + ContextCompat.getColor(context, R.color.md_blue_grey_500), + ContextCompat.getColor(context, R.color.md_blue_grey_600), + ContextCompat.getColor(context, R.color.md_blue_grey_700), + ContextCompat.getColor(context, R.color.md_blue_grey_800), + ContextCompat.getColor(context, R.color.md_blue_grey_900) + }; + } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..2900663a --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/theming/ThemeHelper.java @@ -0,0 +1,128 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + This class is inspired by org.horasapps.LeafPic + */ +package com.github.dfa.diaspora_android.util.theming; + +import android.graphics.PorterDuff; +import android.graphics.drawable.ColorDrawable; +import android.support.design.widget.TabLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.ActionMenuView; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.github.dfa.diaspora_android.data.AppSettings; + +/** + * Singleton that can be used to color views + * Created by vanitas on 06.10.16. + */ + +public class ThemeHelper { + private AppSettings appSettings; + private static ThemeHelper instance; + + private ThemeHelper(AppSettings appSettings) { + this.appSettings = appSettings; + } + + public static ThemeHelper getInstance(AppSettings appSettings) { + if(instance == null) { + instance = new ThemeHelper(appSettings); + } + return instance; + } + + public static ThemeHelper getInstance() { + if(instance == null) throw new IllegalStateException("ThemeHelper must be initialized using getInstance(AppSettings) before it can be used!"); + return instance; + } + + public static void updateEditTextColor(EditText editText) { + if(editText != null) { + editText.setHighlightColor(getInstance().appSettings.getAccentColor()); + } + } + + public static void updateCheckBoxColor(CheckBox checkBox) { + if(checkBox != null) { + checkBox.setHighlightColor(getInstance().appSettings.getAccentColor()); + } + } + + public static void updateTabLayoutColor(TabLayout tabLayout) { + if(tabLayout != null) { + tabLayout.setBackgroundColor(getInstance().appSettings.getPrimaryColor()); + tabLayout.setSelectedTabIndicatorColor(getInstance().appSettings.getAccentColor()); + } + } + + public static void updateTextViewColor(TextView textView) { + if(textView != null) { + textView.setHighlightColor(getInstance().appSettings.getAccentColor()); + textView.setLinkTextColor(getInstance().appSettings.getAccentColor()); + } + } + + public static void updateToolbarColor(Toolbar toolbar) { + if(toolbar != null) { + toolbar.setBackgroundColor(getInstance().appSettings.getPrimaryColor()); + } + } + + public static void updateActionMenuViewColor(ActionMenuView actionMenuView) { + if(actionMenuView != null) { + actionMenuView.setBackgroundColor(getInstance().appSettings.getPrimaryColor()); + } + } + + public static int getPrimaryColor() { + return getInstance().appSettings.getPrimaryColor(); + } + + public static int getAccentColor() { + return getInstance().appSettings.getAccentColor(); + } + + public static void setPrimaryColorAsBackground(View view) { + if(view != null) { + view.setBackgroundColor(getPrimaryColor()); + } + } + + public static int getPrimaryDarkColor() { + return ColorPalette.getObscuredColor(getPrimaryColor()); + } + + public static void updateActionBarColor(ActionBar actionBar) { + if(actionBar != null) { + actionBar.setBackgroundDrawable(new ColorDrawable(getInstance().appSettings.getPrimaryColor())); + } + } + + public static void updateProgressBarColor(ProgressBar progressBar) { + if(progressBar != null && progressBar.getProgressDrawable() != null) { + progressBar.getProgressDrawable().setColorFilter(getAccentColor(), PorterDuff.Mode.SRC_IN); + } + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/CustomWebViewClient.java b/app/src/main/java/com/github/dfa/diaspora_android/webview/CustomWebViewClient.java similarity index 95% rename from app/src/main/java/com/github/dfa/diaspora_android/ui/CustomWebViewClient.java rename to app/src/main/java/com/github/dfa/diaspora_android/webview/CustomWebViewClient.java index 8e31a15c..914abcbb 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/ui/CustomWebViewClient.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/webview/CustomWebViewClient.java @@ -16,7 +16,7 @@ If not, see . */ -package com.github.dfa.diaspora_android.ui; +package com.github.dfa.diaspora_android.webview; import android.content.Intent; import android.net.Uri; @@ -37,6 +37,7 @@ public class CustomWebViewClient extends WebViewClient { this.webView = webView; } + //Open non-diaspora links in customtab/external browser public boolean shouldOverrideUrlLoading(WebView view, String url) { if (!url.contains(app.getSettings().getPodDomain())) { Intent i = new Intent(MainActivity.ACTION_OPEN_EXTERNAL_URL); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/webview/DiasporaStreamWebChromeClient.java b/app/src/main/java/com/github/dfa/diaspora_android/webview/DiasporaStreamWebChromeClient.java new file mode 100644 index 00000000..f3572e97 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/webview/DiasporaStreamWebChromeClient.java @@ -0,0 +1,62 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.webview; + +import android.webkit.WebView; +import android.widget.ProgressBar; + +import com.github.dfa.diaspora_android.util.AppLog; +import com.github.dfa.diaspora_android.util.WebHelper; + +/** + * Created by vanitas on 26.09.16. + */ + +public class DiasporaStreamWebChromeClient extends FileUploadWebChromeClient { + protected SharedTextCallback sharedTextCallback; + + public DiasporaStreamWebChromeClient(WebView webView, ProgressBar progressBar, FileUploadCallback fileUploadCallback, SharedTextCallback callback) { + super(webView, progressBar, fileUploadCallback); + this.sharedTextCallback = callback; + } + + @Override + public void onProgressChanged(WebView wv, int progress) { + super.onProgressChanged(wv, progress); + if (progress > 0 && progress <= 60) { + WebHelper.getUserProfile(wv); + WebHelper.optimizeMobileSiteLayout(wv); + } + + if (progress > 60) { + WebHelper.optimizeMobileSiteLayout(wv); + + String textToBeShared = sharedTextCallback.getSharedText(); + if (textToBeShared != null) { + AppLog.d(this, "Share text into webView"); + WebHelper.shareTextIntoWebView(wv, textToBeShared); + } + } + } + + public interface SharedTextCallback { + String getSharedText(); + void setSharedText(String shared); + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/webview/FileUploadWebChromeClient.java b/app/src/main/java/com/github/dfa/diaspora_android/webview/FileUploadWebChromeClient.java new file mode 100644 index 00000000..a730182e --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/webview/FileUploadWebChromeClient.java @@ -0,0 +1,59 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.webview; + +import android.net.Uri; +import android.webkit.ValueCallback; +import android.webkit.WebView; +import android.widget.ProgressBar; + +/** + * Created by vanitas on 26.09.16. + */ + +public class FileUploadWebChromeClient extends ProgressBarWebChromeClient { + protected FileUploadCallback fileUploadCallback; + + public FileUploadWebChromeClient(WebView webView, ProgressBar progressBar, FileUploadCallback fileUploadCallback) { + super(webView, progressBar); + this.fileUploadCallback = fileUploadCallback; + } + + @Override + public void onProgressChanged(WebView wv, int progress) { + super.onProgressChanged(wv, progress); + } + + //For Android 4.1/4.2 only. DO NOT REMOVE! + @SuppressWarnings("unused") + protected void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) + { + fileUploadCallback.legacyImageUpload(uploadMsg, acceptType, capture); + } + + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + return fileUploadCallback.imageUpload(webView, filePathCallback, fileChooserParams); + } + + public interface FileUploadCallback { + boolean imageUpload(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams); + void legacyImageUpload(ValueCallback uploadMsg, String acceptType, String capture); + } +} diff --git a/app/src/main/java/com/github/dfa/diaspora_android/webview/ProgressBarWebChromeClient.java b/app/src/main/java/com/github/dfa/diaspora_android/webview/ProgressBarWebChromeClient.java new file mode 100644 index 00000000..ec5c7b41 --- /dev/null +++ b/app/src/main/java/com/github/dfa/diaspora_android/webview/ProgressBarWebChromeClient.java @@ -0,0 +1,44 @@ +/* + This file is part of the Diaspora for Android. + + Diaspora for Android is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Diaspora for Android is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Diaspora for Android. + + If not, see . + */ +package com.github.dfa.diaspora_android.webview; + +import android.view.View; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.widget.ProgressBar; + +/** + * WebChromeClient that connects the ProgressBar and the WebView and updates the progress of the progressBar. + * Created by vanitas on 26.09.16. + */ + +public class ProgressBarWebChromeClient extends WebChromeClient { + protected final ProgressBar progressBar; + protected final WebView webView; + + public ProgressBarWebChromeClient(WebView webView, ProgressBar progressBar) { + this.webView = webView; + this.progressBar = progressBar; + } + + public void onProgressChanged(WebView wv, int progress) { + progressBar.setProgress(progress); + progressBar.setVisibility(progress == 100 ? View.GONE : View.VISIBLE); + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 00000000..11f95124 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-ldpi/ic_launcher.png b/app/src/main/res/drawable-ldpi/ic_launcher.png new file mode 100644 index 00000000..8e89a6a9 Binary files /dev/null and b/app/src/main/res/drawable-ldpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 00000000..b356e40a Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 00000000..5055f6cf Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..2001d858 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..0d77fa66 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/drawable/ic_launcher.xml b/app/src/main/res/drawable/ic_launcher.xml deleted file mode 100644 index 4d66007f..00000000 --- a/app/src/main/res/drawable/ic_launcher.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/progressbar.xml b/app/src/main/res/drawable/progressbar.xml index 44815b57..2a6e82ec 100644 --- a/app/src/main/res/drawable/progressbar.xml +++ b/app/src/main/res/drawable/progressbar.xml @@ -1,5 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tor_onion.xml b/app/src/main/res/drawable/tor_onion.xml new file mode 100644 index 00000000..7df39ce0 --- /dev/null +++ b/app/src/main/res/drawable/tor_onion.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/about__activity.xml b/app/src/main/res/layout/about__activity.xml index 34de3bfd..6e17bd47 100644 --- a/app/src/main/res/layout/about__activity.xml +++ b/app/src/main/res/layout/about__activity.xml @@ -1,5 +1,6 @@ - @@ -17,7 +18,7 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/hashtag_list__fragment.xml b/app/src/main/res/layout/hashtag_list__fragment.xml new file mode 100644 index 00000000..94df572b --- /dev/null +++ b/app/src/main/res/layout/hashtag_list__fragment.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/main__app_bar.xml b/app/src/main/res/layout/main__app_bar.xml index 8d217e2b..c81b49ae 100644 --- a/app/src/main/res/layout/main__app_bar.xml +++ b/app/src/main/res/layout/main__app_bar.xml @@ -8,9 +8,9 @@ tools:context=".activity.MainActivity"> diff --git a/app/src/main/res/layout/main__nav_header.xml b/app/src/main/res/layout/main__nav_header.xml index 146f8703..dfd33c01 100644 --- a/app/src/main/res/layout/main__nav_header.xml +++ b/app/src/main/res/layout/main__nav_header.xml @@ -1,5 +1,6 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/podselection__fragment.xml b/app/src/main/res/layout/podselection__fragment.xml new file mode 100644 index 00000000..b8e39ac4 --- /dev/null +++ b/app/src/main/res/layout/podselection__fragment.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/recycler_view__list_item.xml b/app/src/main/res/layout/recycler_view__list_item.xml new file mode 100644 index 00000000..764467e7 --- /dev/null +++ b/app/src/main/res/layout/recycler_view__list_item.xml @@ -0,0 +1,23 @@ + + + + + + \ 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 new file mode 100644 index 00000000..c126650b --- /dev/null +++ b/app/src/main/res/layout/settings__activity.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/splash__activity.xml b/app/src/main/res/layout/splash__activity.xml deleted file mode 100644 index 5f65f563..00000000 --- a/app/src/main/res/layout/splash__activity.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/menu/main__navdrawer.xml b/app/src/main/res/menu/main__navdrawer.xml index 25a2f7a9..56323eb8 100644 --- a/app/src/main/res/menu/main__navdrawer.xml +++ b/app/src/main/res/menu/main__navdrawer.xml @@ -61,7 +61,7 @@ android:title="@string/settings" /> diff --git a/app/src/main/res/menu/podselection__menu.xml b/app/src/main/res/menu/podselection__menu.xml index 1c33e1c9..8b498aa3 100644 --- a/app/src/main/res/menu/podselection__menu.xml +++ b/app/src/main/res/menu/podselection__menu.xml @@ -1,7 +1,5 @@ + xmlns:app="http://schemas.android.com/apk/res-auto"> Navigations Slider Konfiguration der Sichtbarkeit von Einträgen im Navigation-Slider Sichtbarkeit der Einträge + + Farbschema + Einstellungen des Farbdesigns + Primärfarbe + Färbung der Werkzeugleisten + Akzentfarbe + Färbung der Details Schriftgröße @@ -21,13 +28,14 @@ Lade Bilder Deaktiviere das Laden von Bildern, um den Datenverbrauch zu verringern + Proxy Aktiviere Netzwerkproxy - Nutze einen Proxyserver, um Firewalls zu umgehen - Host - Port + Nutze einen Proxyserver, um Firewalls zu umgehen + Host + Port Chrome Custom Tabs - Externe Links mit Chrome Custom Tabs öffnen. Für dieses Feature muss Chromium oder Google Chrome installiert sein + Externe Links mit Chrome Custom Tabs öffnen. Chromium oder Google Chrome muss für dieses Feature installiert sein.\nWICHTIGER HINWEIS: Chrome Custom Tabs verwenden die konfigurierten Proxy-Server nicht! Persönliche Einstellungen Öffne die Einstellungen deines Diaspora Accounts diff --git a/app/src/main/res/values-es/strings-preferences.xml b/app/src/main/res/values-es/strings-preferences.xml index 6a6b67c1..9cab7553 100644 --- a/app/src/main/res/values-es/strings-preferences.xml +++ b/app/src/main/res/values-es/strings-preferences.xml @@ -22,9 +22,9 @@ Desactivar la carga de de imágenes a datos móviles seguros Activar Proxy - El tráfico proxificado de Diaspora para evitar firewalls.\nPuede necesitar reiniciarse - Anfitrión - Puerto + El tráfico proxificado de Diaspora para evitar firewalls.\nPuede necesitar reiniciarse + Anfitrión + Puerto Configuración personal diff --git a/app/src/main/res/values-fr/strings-preferences.xml b/app/src/main/res/values-fr/strings-preferences.xml index 48b8d71d..f48dffe9 100644 --- a/app/src/main/res/values-fr/strings-preferences.xml +++ b/app/src/main/res/values-fr/strings-preferences.xml @@ -21,13 +21,13 @@ Charger les images Désactiver le chargements des images pour préserver la data mobile + Proxy Activer Proxy - Serveur Proxy.\n(Nécessite un redémarrage) - Hôte - Port + Serveur Proxy.\n(Nécessite un redémarrage) + Hôte + Port Onglets personnalisés de Chrome - Ouvrir les liens externes avec les onglets personnalisés. Chromium ou Google Chrome doit être installé pour cette fonctionnalité Paramètres personnels Ouvrir vos paramètres de compte diaspora diff --git a/app/src/main/res/values-it/strings-preferences.xml b/app/src/main/res/values-it/strings-preferences.xml index 01fbf921..5ba1e1df 100644 --- a/app/src/main/res/values-it/strings-preferences.xml +++ b/app/src/main/res/values-it/strings-preferences.xml @@ -21,11 +21,13 @@ Carica immagini Disabilita il caricamento delle immagini per risparmiare la rete dati + Proxy Attiva proxy - Traffico del proxy di Diaspora per bypassare i firewall.\nPuò essere necessario il riavvio dell\'app - Host - Porta + Traffico del proxy di Diaspora per bypassare i firewall.\nPuò essere necessario il riavvio dell\'app + Host + Porta + Schede personalizzate di Chrome Impostazioni personali Apri le impostazioni del tuo account Diaspora diff --git a/app/src/main/res/values-ja/strings-preferences.xml b/app/src/main/res/values-ja/strings-preferences.xml index 909ff218..fd414294 100644 --- a/app/src/main/res/values-ja/strings-preferences.xml +++ b/app/src/main/res/values-ja/strings-preferences.xml @@ -21,13 +21,13 @@ 画像の読み込み 安全なモバイルデータのため、画像の読み込みを無効にします + プロキシ プロキシを有効にする - Diaspora の通信をプロキシして、ファイアウォールに回避します。\n再起動が必要になることがあります - ホスト - ポート + Diaspora の通信をプロキシして、ファイアウォールに回避します。\n再起動が必要になることがあります + ホスト + ポート Chrome カスタムタブ - Chrome カスタム タブで外部リンクを開きます。この機能は Chromium または Google Chrome をインストールする必要があります 個人用設定 Diaspora アカウント設定を開きます diff --git a/app/src/main/res/values-ml/strings-preferences.xml b/app/src/main/res/values-ml/strings-preferences.xml index 390a9139..decc542a 100644 --- a/app/src/main/res/values-ml/strings-preferences.xml +++ b/app/src/main/res/values-ml/strings-preferences.xml @@ -22,9 +22,9 @@ മൊബൈൽ ഡാറ്റ ഉപഭോഗം കുറയ്ക്കാനായി ചിത്രങ്ങൾ ലോഡ് ചെയ്യാതിരിക്കുക പ്രോക്സി അനുവദിക്കൂ - ഫയർവാളുകളെ മറികടക്കാൻ ഡയസ്പോറ ട്രാഫിക് പ്രോക്സി ചെയ്യൂ.\nപുനരാരംഭിക്കേണ്ടി വന്നേക്കാം - ആഥിതേയൻ - പോർട്ട് + ഫയർവാളുകളെ മറികടക്കാൻ ഡയസ്പോറ ട്രാഫിക് പ്രോക്സി ചെയ്യൂ.\nപുനരാരംഭിക്കേണ്ടി വന്നേക്കാം + ആഥിതേയൻ + പോർട്ട് സ്വകാര്യ സജ്ജീകരണങ്ങൾ diff --git a/app/src/main/res/values-nl/strings-preferences.xml b/app/src/main/res/values-nl/strings-preferences.xml index 47b807ca..8526b891 100644 --- a/app/src/main/res/values-nl/strings-preferences.xml +++ b/app/src/main/res/values-nl/strings-preferences.xml @@ -21,9 +21,9 @@ Afbeelding laden uitschakelen om mobiele data te besparen Proxy inschakelen - Gebruik een Proxy voor Diaspora om de firewalls te omzeilen.\nRestart nodig - Host - Poort + Gebruik een Proxy voor Diaspora om de firewalls te omzeilen.\nRestart nodig + Host + Poort Persoonlijke instellingen diff --git a/app/src/main/res/values-pt-rBR/strings-preferences.xml b/app/src/main/res/values-pt-rBR/strings-preferences.xml index ee8eebc8..1fbd4608 100644 --- a/app/src/main/res/values-pt-rBR/strings-preferences.xml +++ b/app/src/main/res/values-pt-rBR/strings-preferences.xml @@ -22,9 +22,9 @@ Desabilitar o carregamento de imagens para economizar seus créditos Habilitar o Proxy - Usar proxy para o tráfego da diáspora para contornar firewalls.\nPode requerer reinicialização - Servidor - Porta + Usar proxy para o tráfego da diáspora para contornar firewalls.\nPode requerer reinicialização + Servidor + Porta Configurações pessoais diff --git a/app/src/main/res/values-ru/strings-preferences.xml b/app/src/main/res/values-ru/strings-preferences.xml index 3bc04e85..0b924029 100644 --- a/app/src/main/res/values-ru/strings-preferences.xml +++ b/app/src/main/res/values-ru/strings-preferences.xml @@ -22,9 +22,9 @@ Отключить загрузку изображений для экономии траффика Использовать прокси - Перенаправить трафик Диаспоры в обход брандмауэров.\nМожет потребовать перезапуска - Хост - Порт + Перенаправить трафик Диаспоры в обход брандмауэров.\nМожет потребовать перезапуска + Хост + Порт Личные настройки diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index e18d571e..5b55f978 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -1,6 +1,6 @@ > - - +