diff --git a/app/build.gradle b/app/build.gradle index f539362af..f30ea1d65 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,9 +9,8 @@ android { defaultConfig { minSdk 21 targetSdk 31 - versionCode 21 - versionName "beta-21" - + versionCode 385 + versionName "3.0.0-beta-22" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" @@ -27,13 +26,13 @@ android { } productFlavors { fdroid { - applicationId "fr.gouv.etalab.mastodon.test" + applicationId "fr.gouv.etalab.mastodon" buildConfigField "boolean", "DONATIONS", "true" buildConfigField "boolean", "push", "false" flavor = "fdroid" } playstore { - applicationId "app.fedilab.android.test" + applicationId "app.fedilab.android" buildConfigField "boolean", "DONATIONS", "false" buildConfigField "boolean", "push", "true" flavor = "playstore" @@ -98,8 +97,8 @@ dependencies { implementation project(path: ':cropper') annotationProcessor "com.github.bumptech.glide:compiler:4.12.0" implementation 'jp.wasabeef:glide-transformations:4.3.0' - implementation 'com.github.penfeizhou.android.animation:apng:2.17.0' - implementation 'com.github.penfeizhou.android.animation:gif:2.17.0' + implementation 'com.github.penfeizhou.android.animation:apng:2.22.0' + implementation 'com.github.penfeizhou.android.animation:gif:2.22.0' implementation 'com.google.android.exoplayer:exoplayer:2.16.1' implementation 'com.github.piasy:rxandroidaudio:1.7.0' implementation 'com.github.piasy:AudioProcessor:1.7.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 40873aeab..4f6b36d70 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -108,6 +108,12 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:label="@string/action_about" android:theme="@style/AppThemeBar" /> + + Helper.openBrowser(AboutActivity.this, "https://www.paypal.me/Mastalab")); - + binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(AboutActivity.this)); if (BuildConfig.DONATIONS) { binding.aboutSupportPaypal.setVisibility(View.VISIBLE); } else { binding.aboutSupportPaypal.setVisibility(View.GONE); } + binding.accountFollow.setImageResource(R.drawable.ic_baseline_person_add_24); binding.aboutWebsite.setOnClickListener(v -> Helper.openBrowser(AboutActivity.this, "https://fedilab.app")); CrossActionHelper.fetchRemoteAccount(AboutActivity.this, "@apps@toot.fedilab.app", new CrossActionHelper.Callback() { @Override diff --git a/app/src/main/java/app/fedilab/android/activities/PartnerShipActivity.java b/app/src/main/java/app/fedilab/android/activities/PartnerShipActivity.java new file mode 100644 index 000000000..3e17e6786 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/activities/PartnerShipActivity.java @@ -0,0 +1,139 @@ +package app.fedilab.android.activities; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * 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. + * + * Fedilab 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 Fedilab; if not, + * see . */ + + +import android.content.Intent; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; +import android.os.Bundle; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.appcompat.app.ActionBar; +import androidx.core.app.ActivityOptionsCompat; +import androidx.core.content.ContextCompat; +import androidx.lifecycle.ViewModelProvider; + +import java.util.ArrayList; +import java.util.List; + +import app.fedilab.android.R; +import app.fedilab.android.client.entities.api.Account; +import app.fedilab.android.client.entities.api.Status; +import app.fedilab.android.databinding.ActivityPartnershipBinding; +import app.fedilab.android.helper.CrossActionHelper; +import app.fedilab.android.helper.Helper; +import app.fedilab.android.helper.MastodonHelper; +import app.fedilab.android.helper.ThemeHelper; +import app.fedilab.android.viewmodel.mastodon.AccountsVM; + + +public class PartnerShipActivity extends BaseActivity { + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ThemeHelper.applyThemeBar(this); + ActivityPartnershipBinding binding = ActivityPartnershipBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + if (getSupportActionBar() != null) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setBackgroundDrawable(new ColorDrawable(ContextCompat.getColor(this, R.color.cyanea_primary))); + } + + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE); + assert inflater != null; + View view = inflater.inflate(R.layout.simple_bar, new LinearLayout(PartnerShipActivity.this), false); + view.setBackground(new ColorDrawable(ContextCompat.getColor(PartnerShipActivity.this, R.color.cyanea_primary))); + actionBar.setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); + ImageView toolbar_close = actionBar.getCustomView().findViewById(R.id.toolbar_close); + TextView toolbar_title = actionBar.getCustomView().findViewById(R.id.toolbar_title); + toolbar_close.setOnClickListener(v -> finish()); + toolbar_title.setText(R.string.action_partnership); + } + + TextView about_partnership = findViewById(R.id.about_partnership); + about_partnership.setMovementMethod(LinkMovementMethod.getInstance()); + + binding.mastohostLogo.setOnClickListener(v -> { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://masto.host")); + startActivity(browserIntent); + }); + binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(PartnerShipActivity.this)); + setTitle(R.string.action_partnership); + binding.accountFollow.setImageResource(R.drawable.ic_baseline_person_add_24); + CrossActionHelper.fetchRemoteAccount(PartnerShipActivity.this, "@mastohost@mastodon.social", new CrossActionHelper.Callback() { + @Override + public void federatedStatus(Status status) { + + } + + @Override + public void federatedAccount(Account account) { + if (account != null && account.username.equalsIgnoreCase("mastohost")) { + binding.acccountContainer.setVisibility(View.VISIBLE); + MastodonHelper.loadPPMastodon(binding.accountPp, account); + binding.accountDn.setText(account.display_name); + binding.accountUn.setText(account.acct); + binding.accountPp.setOnClickListener(v -> { + Intent intent = new Intent(PartnerShipActivity.this, ProfileActivity.class); + Bundle b = new Bundle(); + b.putSerializable(Helper.ARG_ACCOUNT, account); + intent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation(PartnerShipActivity.this, binding.accountPp, getString(R.string.activity_porfile_pp)); + startActivity(intent, options.toBundle()); + }); + AccountsVM accountsVM = new ViewModelProvider(PartnerShipActivity.this).get(AccountsVM.class); + List ids = new ArrayList<>(); + ids.add(account.id); + accountsVM.getRelationships(MainActivity.currentInstance, MainActivity.currentToken, ids) + .observe(PartnerShipActivity.this, relationShips -> { + if (relationShips != null && relationShips.size() > 0) { + if (!relationShips.get(0).following) { + binding.accountFollow.setVisibility(View.VISIBLE); + binding.accountFollow.setOnClickListener(v -> accountsVM.follow(MainActivity.currentInstance, MainActivity.currentToken, account.id, true, false) + .observe(PartnerShipActivity.this, relationShip -> binding.accountFollow.setVisibility(View.GONE))); + } + } + }); + } + } + }); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 1a131c75f..e73afa80b 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -536,7 +536,7 @@ public class ProfileActivity extends BaseActivity { private void updateAccount() { //The value for account is from same server so id can be used - if (account.id.equals(BaseMainActivity.accountWeakReference.get().user_id)) { + if (BaseMainActivity.accountWeakReference.get() != null && account.id.equals(BaseMainActivity.accountWeakReference.get().user_id)) { binding.accountFollow.setVisibility(View.GONE); binding.headerEditProfile.setVisibility(View.VISIBLE); binding.headerEditProfile.bringToFront(); @@ -563,20 +563,7 @@ public class ProfileActivity extends BaseActivity { }); } } - int[][] states = new int[][]{ - new int[]{android.R.attr.state_enabled}, // enabled - new int[]{-android.R.attr.state_enabled}, // disabled - new int[]{-android.R.attr.state_checked}, // unchecked - new int[]{android.R.attr.state_pressed} // pressed - }; - - int[] colors = new int[]{ - ContextCompat.getColor(ProfileActivity.this, R.color.mastodonC4), - ContextCompat.getColor(ProfileActivity.this, R.color.mastodonC4___), - ContextCompat.getColor(ProfileActivity.this, R.color.mastodonC4), - ContextCompat.getColor(ProfileActivity.this, R.color.mastodonC4) - }; - binding.accountFollow.setBackgroundTintList(new ColorStateList(states, colors)); + binding.accountFollow.setBackgroundTintList(ThemeHelper.getButtonActionColorStateList(ProfileActivity.this)); binding.accountFollow.setEnabled(true); //Visibility depending of the relationship if (relationship != null) { diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index 04599fbba..b3ab96800 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -151,6 +151,7 @@ public class Helper { public static final String INSTANCE_SOCIAL_KEY = "jGj9gW3z9ptyIpB8CMGhAlTlslcemMV6AgoiImfw3vPP98birAJTHOWiu5ZWfCkLvcaLsFZw9e3Pb7TIwkbIyrj3z6S7r2oE6uy6EFHvls3YtapP8QKNZ980p9RfzTb4"; public static final String WEBSITE_VALUE = "https://fedilab.app"; + public static final String OLD_DB_NAME = "mastodon_etalab_db"; public static final String RECEIVE_TOAST_MESSAGE = "RECEIVE_TOAST_MESSAGE"; public static final String RECEIVE_TOAST_TYPE = "RECEIVE_TOAST_TYPE"; @@ -1572,4 +1573,28 @@ public class Helper { }).start(); } } + + + public static void transfertIfExist(Context context) { + File dbFile = context.getDatabasePath(OLD_DB_NAME); + if (!dbFile.exists()) { + return; + } + int version = -1; + try { + SQLiteDatabase sqlDb = SQLiteDatabase.openDatabase + (context.getDatabasePath(OLD_DB_NAME).getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY); + version = sqlDb.getVersion(); + } catch (Exception ignored) { + } + try { + if (version == -1) { + version = 38; + } + SQLiteDatabase oldDb = Sqlite.getInstance(context.getApplicationContext(), OLD_DB_NAME, null, version).open(); + + } catch (Exception ignored) { + } + context.deleteDatabase(OLD_DB_NAME); + } } diff --git a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java index 2886b5529..8b5397b81 100644 --- a/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/PinnedTimelineHelper.java @@ -263,10 +263,13 @@ public class PinnedTimelineHelper { try { //If some menu items have been hidden we should not create tab for them bottomMenuDb = new BottomMenu(context).getAllBottomMenu(MainActivity.accountWeakReference.get()); - if (bottomMenuDb != null && bottomMenuDb.bottom_menu != null) { - for (BottomMenu.MenuItem menuItem : bottomMenuDb.bottom_menu) { - if (!menuItem.visible) { - toRemove++; + if (bottomMenuDb != null) { + List menuItemList = bottomMenuDb.bottom_menu; + if (menuItemList != null) { + for (BottomMenu.MenuItem menuItem : menuItemList) { + if (!menuItem.visible) { + toRemove++; + } } } } diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index faefd557e..f5204a674 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -710,8 +710,8 @@ public class SpannableHelper { } catch (Exception ignored) { } } else { - Drawable drawable = Drawable.createFromPath(file.getAbsolutePath()); try { + Drawable drawable = Drawable.createFromPath(file.getAbsolutePath()); drawable.setBounds(0, 0, (int) convertDpToPixel(20, context), (int) convertDpToPixel(20, context)); drawable.setVisible(true, true); imageSpan = new ImageSpan(drawable); diff --git a/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java b/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java index 5ceefee6d..cbdab195c 100644 --- a/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/ThemeHelper.java @@ -282,6 +282,24 @@ public class ThemeHelper { return new ColorStateList(states, colors); } + public static ColorStateList getButtonActionColorStateList(Context context) { + int[][] states = new int[][]{ + new int[]{android.R.attr.state_enabled}, // enabled + new int[]{-android.R.attr.state_enabled}, // disabled + new int[]{-android.R.attr.state_checked}, // unchecked + new int[]{android.R.attr.state_pressed} // pressed + }; + int alphaColor = ColorUtils.setAlphaComponent(ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference), 0x33); + int color = ContextCompat.getColor(context, R.color.cyanea_accent_dark_reference); + int[] colors = new int[]{ + color, + alphaColor, + color, + color + }; + return new ColorStateList(states, colors); + } + /** * Allow to set colors for having description on media diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 6da903954..7f0189163 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -149,8 +149,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. private int getPosition(Status status) { int position = 0; boolean found = false; + if (status.id == null) { + return -1; + } for (Status _status : statuses) { - if (_status.id.compareTo(status.id) == 0) { + if (_status.id != null && _status.id.compareTo(status.id) == 0) { found = true; break; } diff --git a/app/src/main/res/drawable/ic_baseline_account_circle_24.xml b/app/src/main/res/drawable/ic_baseline_account_circle_24.xml new file mode 100644 index 000000000..0b3fa82b1 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_account_circle_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/mastohost.png b/app/src/main/res/drawable/mastohost.png new file mode 100644 index 000000000..f67e795cf Binary files /dev/null and b/app/src/main/res/drawable/mastohost.png differ diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index bd9f11acd..643aa2c08 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -61,8 +61,11 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index cdbc7e8e1..87296e933 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -50,5 +50,10 @@ android:id="@+id/nav_about" android:icon="@drawable/ic_baseline_info_24" android:title="@string/action_about" /> + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e194a070d..a01062705 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -542,7 +542,7 @@ Follow instance You already follow this instance! The instance is followed! - Masto.host is our Mastodon hosting partner.\n\nWith this partnership they provide me free hosting for Mastalab\'s instance and in exchange I promote them in here.\n\nTo be clear, there is no money involved or tracking of users. I needed an instance for testing, we talked and agreed on this.\n\nGo check them out if you want to run your own Mastodon instance. + Masto.host is our Mastodon hosting partner.\n\nWith this partnership they provide me free hosting for Fedilab\'s instance and in exchange I promote them in here.\n\nTo be clear, there is no money involved or tracking of users. I needed an instance for testing, we talked and agreed on this.\n\nGo check them out if you want to run your own Mastodon instance. Partnerships Information