diff --git a/app/build.gradle b/app/build.gradle index b5c6c6708..15cfe9ea7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,6 +46,8 @@ android { ext.supportLibraryVersion = '27.1.1' ext.daggerVersion = '2.16' + +// if libraries are changed here, they should also be changed in LicenseActivity dependencies { implementation('com.mikepenz:materialdrawer:6.0.7@aar') { transitive = true @@ -56,6 +58,7 @@ dependencies { implementation "com.android.support:support-v13:$supportLibraryVersion" implementation "com.android.support:design:$supportLibraryVersion" implementation "com.android.support:exifinterface:$supportLibraryVersion" + implementation "com.android.support:cardview-v7:$supportLibraryVersion" implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-gson:2.4.0' implementation 'com.squareup.picasso:picasso:2.5.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e649e8a76..ca13efdc1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -99,6 +99,7 @@ + diff --git a/app/src/main/assets/LICENSE_APACHE b/app/src/main/assets/LICENSE_APACHE deleted file mode 100644 index 8e66e5790..000000000 --- a/app/src/main/assets/LICENSE_APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, -and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by -the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all -other entities that control, are controlled by, or are under common -control with that entity. For the purposes of this definition, -"control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or -otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity -exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, -including but not limited to software source code, documentation -source, and configuration files. - -"Object" form shall mean any form resulting from mechanical -transformation or translation of a Source form, including but -not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or -Object form, made available under the License, as indicated by a -copyright notice that is included in or attached to the work -(an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object -form, that is based on (or derived from) the Work and for which the -editorial revisions, annotations, elaborations, or other modifications -represent, as a whole, an original work of authorship. For the purposes -of this License, Derivative Works shall not include works that remain -separable from, or merely link (or bind by name) to the interfaces of, -the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including -the original version of the Work and any modifications or additions -to that Work or Derivative Works thereof, that is intentionally -submitted to Licensor for inclusion in the Work by the copyright owner -or by an individual or Legal Entity authorized to submit on behalf of -the copyright owner. For the purposes of this definition, "submitted" -means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, -and issue tracking systems that are managed by, or on behalf of, the -Licensor for the purpose of discussing and improving the Work, but -excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity -on behalf of whom a Contribution has been received by Licensor and -subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the -Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of -this License, each Contributor hereby grants to You a perpetual, -worldwide, non-exclusive, no-charge, royalty-free, irrevocable -(except as stated in this section) patent license to make, have made, -use, offer to sell, sell, import, and otherwise transfer the Work, -where such license applies only to those patent claims licensable -by such Contributor that are necessarily infringed by their -Contribution(s) alone or by combination of their Contribution(s) -with the Work to which such Contribution(s) was submitted. If You -institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work -or a Contribution incorporated within the Work constitutes direct -or contributory patent infringement, then any patent licenses -granted to You under this License for that Work shall terminate -as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the -Work or Derivative Works thereof in any medium, with or without -modifications, and in Source or Object form, provided that You -meet the following conditions: - -(a) You must give any other recipients of the Work or -Derivative Works a copy of this License; and - -(b) You must cause any modified files to carry prominent notices -stating that You changed the files; and - -(c) You must retain, in the Source form of any Derivative Works -that You distribute, all copyright, patent, trademark, and -attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of -the Derivative Works; and - -(d) If the Work includes a "NOTICE" text file as part of its -distribution, then any Derivative Works that You distribute must -include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not -pertain to any part of the Derivative Works, in at least one -of the following places: within a NOTICE text file distributed -as part of the Derivative Works; within the Source form or -documentation, if provided along with the Derivative Works; or, -within a display generated by the Derivative Works, if and -wherever such third-party notices normally appear. The contents -of the NOTICE file are for informational purposes only and -do not modify the License. You may add Your own attribution -notices within Derivative Works that You distribute, alongside -or as an addendum to the NOTICE text from the Work, provided -that such additional attribution notices cannot be construed -as modifying the License. - -You may add Your own copyright statement to Your modifications and -may provide additional or different license terms and conditions -for use, reproduction, or distribution of Your modifications, or -for any such Derivative Works as a whole, provided Your use, -reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, -any Contribution intentionally submitted for inclusion in the Work -by You to the Licensor shall be under the terms and conditions of -this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify -the terms of any separate license agreement you may have executed -with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade -names, trademarks, service marks, or product names of the Licensor, -except as required for reasonable and customary use in describing the -origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or -agreed to in writing, Licensor provides the Work (and each -Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied, including, without limitation, any warranties or conditions -of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A -PARTICULAR PURPOSE. You are solely responsible for determining the -appropriateness of using or redistributing the Work and assume any -risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, -whether in tort (including negligence), contract, or otherwise, -unless required by applicable law (such as deliberate and grossly -negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, -incidental, or consequential damages of any character arising as a -result of this License or out of the use or inability to use the -Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all -other commercial damages or losses), even if such Contributor -has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing -the Work or Derivative Works thereof, You may choose to offer, -and charge a fee for, acceptance of support, warranty, indemnity, -or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only -on Your own behalf and on Your sole responsibility, not on behalf -of any other Contributor, and only if You agree to indemnify, -defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason -of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following -boilerplate notice, with the fields enclosed by brackets "[]" -replaced with your own identifying information. (Don't include -the brackets!) The text should be enclosed in the appropriate -comment syntax for the file format. We also recommend that a -file or class name and description of purpose be included on the -same "printed page" as the copyright notice for easier -identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file diff --git a/app/src/main/assets/about_emojicompat.html b/app/src/main/assets/about_emojicompat.html deleted file mode 100644 index 43c5fd9e1..000000000 --- a/app/src/main/assets/about_emojicompat.html +++ /dev/null @@ -1,18 +0,0 @@ - - -

About these Emoji fonts

- In order to display other emojis than your system's default set, you'll need to download additional emoji fonts.
- The fonts currently supported are: -
    -
  • Blobmoji
    - This is a font based on the Blob emojis which have been used in stock Android from version 4.4 to 7.1.
    - They are licensed under the Apache License 2.0 - you can get a copy here.
    - Website -
  • -
  • Twemoji - This is the standard emoji set used by Masotodon. It has been developed by Twitter and is licensed under CC-BY 4.0.
    - Website -
  • -
- - \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.java b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.java deleted file mode 100644 index 4e4e47539..000000000 --- a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.keylesspalace.tusky; - -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.v7.app.ActionBar; -import android.support.v7.widget.Toolbar; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.TextView; - -import com.keylesspalace.tusky.di.Injectable; -import com.keylesspalace.tusky.entity.Account; -import com.keylesspalace.tusky.network.MastodonApi; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.List; - -import javax.inject.Inject; - -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -public class AboutActivity extends BaseActivity implements Injectable { - private Button appAccountButton; - - @Inject - public MastodonApi mastodonApi; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_about); - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setDisplayShowHomeEnabled(true); - } - - setTitle(R.string.about_title_activity); - - TextView versionTextView = findViewById(R.id.versionTV); - String versionName = BuildConfig.VERSION_NAME; - String versionFormat = getString(R.string.about_tusky_version); - versionTextView.setText(String.format(versionFormat, versionName)); - - appAccountButton = findViewById(R.id.tusky_profile_button); - appAccountButton.setOnClickListener(v -> onAccountButtonClick()); - setupAboutEmoji(); - } - - private void onAccountButtonClick() { - String appAccountId = getPrivatePreferences().getString("appAccountId", null); - if (appAccountId != null) { - viewAccount(appAccountId); - } else { - searchForAccountThenViewIt(); - } - } - - private void viewAccount(String id) { - Intent intent = AccountActivity.getIntent(this, id); - startActivity(intent); - } - - private void searchForAccountThenViewIt() { - Callback> callback = new Callback>() { - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.isSuccessful()) { - List accountList = response.body(); - if (accountList != null && !accountList.isEmpty()) { - String id = accountList.get(0).getId(); - getPrivatePreferences().edit() - .putString("appAccountId", id) - .apply(); - viewAccount(id); - } else { - onSearchFailed(); - } - } else { - onSearchFailed(); - } - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - onSearchFailed(); - } - }; - mastodonApi.searchAccounts("Tusky@mastodon.social", true, null).enqueue(callback); - } - - private void onSearchFailed() { - Snackbar.make(appAccountButton, R.string.error_generic, Snackbar.LENGTH_LONG).show(); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: { - onBackPressed(); - return true; - } - } - return super.onOptionsItemSelected(item); - } - - private void setupAboutEmoji() { - // Inflate the TextView containing the Apache 2.0 license text. - TextView apacheView = findViewById(R.id.license_apache); - BufferedReader reader = null; - try { - InputStream apacheLicense = getAssets().open("LICENSE_APACHE"); - StringBuilder builder = new StringBuilder(); - reader = new BufferedReader( - new InputStreamReader(apacheLicense, "UTF-8")); - String line; - while((line = reader.readLine()) != null) { - builder.append(line); - builder.append('\n'); - } - reader.close(); - apacheView.setText(builder); - } catch (IOException e) { - e.printStackTrace(); - } - - // Set up the button action - ImageButton expand = findViewById(R.id.about_blobmoji_expand); - expand.setOnClickListener(v -> - { - if(apacheView.getVisibility() == View.GONE) { - apacheView.setVisibility(View.VISIBLE); - ((ImageButton) v).setImageResource(R.drawable.ic_arrow_drop_up_black_24dp); - } - else { - apacheView.setVisibility(View.GONE); - ((ImageButton) v).setImageResource(R.drawable.ic_arrow_drop_down_black_24dp); - } - }); - } -} diff --git a/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt new file mode 100644 index 000000000..2d4dbcfac --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/AboutActivity.kt @@ -0,0 +1,87 @@ +package com.keylesspalace.tusky + +import android.content.Intent +import android.os.Bundle +import android.support.annotation.StringRes +import android.text.SpannableString +import android.text.SpannableStringBuilder +import android.text.method.LinkMovementMethod +import android.text.style.URLSpan +import android.text.util.Linkify +import android.view.MenuItem +import android.widget.TextView +import com.keylesspalace.tusky.di.Injectable +import com.keylesspalace.tusky.util.CustomURLSpan +import kotlinx.android.synthetic.main.activity_about.* +import kotlinx.android.synthetic.main.toolbar_basic.* + +class AboutActivity : BottomSheetActivity(), Injectable { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_about) + + setSupportActionBar(toolbar) + supportActionBar?.run { + setDisplayHomeAsUpEnabled(true) + setDisplayShowHomeEnabled(true) + } + + setTitle(R.string.about_title_activity) + + versionTextView.text = getString(R.string.about_tusky_version, BuildConfig.VERSION_NAME) + + aboutLicenseInfoTextView.setClickableTextWithoutUnderlines(R.string.about_tusky_license) + aboutWebsiteInfoTextView.setClickableTextWithoutUnderlines(R.string.about_project_site) + aboutBugsFeaturesInfoTextView.setClickableTextWithoutUnderlines(R.string.about_bug_feature_request_site) + + tuskyProfileButton.setOnClickListener { + onAccountButtonClick() + } + + aboutLicensesButton.setOnClickListener { + startActivity(Intent(this, LicenseActivity::class.java)) + } + + } + + private fun onAccountButtonClick() { + viewUrl("https://mastodon.social/@Tusky") + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + onBackPressed() + return true + } + } + return super.onOptionsItemSelected(item) + } + +} + +private fun TextView.setClickableTextWithoutUnderlines(@StringRes textId: Int) { + + val text = SpannableString(context.getText(textId)) + + Linkify.addLinks(text, Linkify.WEB_URLS) + + val builder = SpannableStringBuilder(text) + val urlSpans = text.getSpans(0, text.length, URLSpan::class.java) + for (span in urlSpans) { + val start = builder.getSpanStart(span) + val end = builder.getSpanEnd(span) + val flags = builder.getSpanFlags(span) + + val customSpan = object : CustomURLSpan(span.url) {} + + builder.removeSpan(span) + builder.setSpan(customSpan, start, end, flags) + } + + setText(builder) + linksClickable = true + movementMethod = LinkMovementMethod.getInstance() + +} diff --git a/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt new file mode 100644 index 000000000..a927e7386 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/LicenseActivity.kt @@ -0,0 +1,84 @@ +/* Copyright 2018 Conny Duck + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky 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 Tusky; if not, + * see . */ + +package com.keylesspalace.tusky + +import android.os.Bundle +import android.support.annotation.RawRes +import android.util.Log +import android.view.MenuItem +import android.widget.TextView +import com.keylesspalace.tusky.util.IOUtils +import kotlinx.android.extensions.CacheImplementation +import kotlinx.android.extensions.ContainerOptions +import kotlinx.android.synthetic.main.activity_license.* +import kotlinx.android.synthetic.main.toolbar_basic.* +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader + +class LicenseActivity : BaseActivity() { + + @ContainerOptions(cache = CacheImplementation.NO_CACHE) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_license) + + setSupportActionBar(toolbar) + supportActionBar?.run { + setDisplayHomeAsUpEnabled(true) + setDisplayShowHomeEnabled(true) + } + + setTitle(R.string.title_licenses) + + loadFileIntoTextView(R.raw.apache, licenseApacheTextView) + + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + android.R.id.home -> { + onBackPressed() + return true + } + } + return super.onOptionsItemSelected(item) + } + + private fun loadFileIntoTextView(@RawRes fileId: Int, textView: TextView) { + + val sb = StringBuilder() + + val br = BufferedReader(InputStreamReader(resources.openRawResource(fileId))) + + try { + var line: String? = br.readLine() + while (line != null) { + sb.append(line) + sb.append('\n') + line = br.readLine() + } + } catch (e: IOException) { + Log.w("LicenseActivity", e) + } + + IOUtils.closeQuietly(br) + + textView.text = sb.toString() + + } + +} diff --git a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt index 67b9c1e83..01cdab111 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/ActivitiesModule.kt @@ -86,4 +86,7 @@ abstract class ActivitiesModule { @ContributesAndroidInjector abstract fun contributesViewVideoActivity(): ViewVideoActivity + @ContributesAndroidInjector + abstract fun contributesLicenseActivity(): LicenseActivity + } \ No newline at end of file diff --git a/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt b/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt new file mode 100644 index 000000000..95b395deb --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt @@ -0,0 +1,61 @@ +/* Copyright 2018 Conny Duck + * + * This file is a part of Tusky. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Tusky 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 Tusky; if not, + * see . */ + +package com.keylesspalace.tusky.view + +import android.content.Context +import android.support.v7.widget.CardView +import android.util.AttributeSet +import com.keylesspalace.tusky.R +import com.keylesspalace.tusky.util.LinkHelper +import com.keylesspalace.tusky.util.ThemeUtils +import com.keylesspalace.tusky.util.hide +import kotlinx.android.synthetic.main.card_license.view.* + + +class LicenseCard +@JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : CardView(context, attrs, defStyleAttr) { + + + init { + inflate(context, R.layout.card_license, this) + + setCardBackgroundColor(ThemeUtils.getColor(context, android.R.attr.colorBackground)) + + val a = context.theme.obtainStyledAttributes(attrs, R.styleable.LicenseCard, 0, 0) + + val name: String? = a.getString(R.styleable.LicenseCard_name) + val license: String? = a.getString(R.styleable.LicenseCard_license) + val link: String? = a.getString(R.styleable.LicenseCard_link) + a.recycle() + + licenseCardName.text = name + licenseCardLicense.text = license + if(link.isNullOrBlank()) { + licenseCardLink.hide() + } else { + licenseCardLink.text = link + setOnClickListener { LinkHelper.openLink(link, context) } + } + + } + + +} + diff --git a/app/src/main/res/layout/about_emoji.xml b/app/src/main/res/layout/about_emoji.xml deleted file mode 100644 index 8dbeba250..000000000 --- a/app/src/main/res/layout/about_emoji.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 53beddb07..d8e9b2b29 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -8,94 +8,109 @@ - - + android:layout_gravity="center"> - - - + android:focusableInTouchMode="true" + android:gravity="center" + android:orientation="vertical" + android:paddingBottom="16dp" + android:paddingTop="16dp"> - + - + -