forked from mirrors/Fedilab
Compare commits
37 commits
auto_cache
...
main
Author | SHA1 | Date | |
---|---|---|---|
a06fb1657d | |||
|
97ba87aba7 | ||
|
7603db8ce0 | ||
|
663e33466d | ||
|
cbed3f1ae1 | ||
|
8bdaf8d410 | ||
|
6595af849e | ||
|
4111d00025 | ||
|
f75d8258f4 | ||
|
7a11e156a5 | ||
|
8977990fea | ||
|
bc44a9be15 | ||
|
88d9bf4629 | ||
|
65706e727c | ||
|
b64fd393e9 | ||
|
2b300ceae4 | ||
|
6e4bb95dda | ||
|
440ad039be | ||
|
4c89a855c6 | ||
|
0ca53b75d2 | ||
|
91eb579e2c | ||
|
1aad4f07df | ||
|
335842c8a2 | ||
|
c10d078add | ||
|
67cdceb90e | ||
|
ddbd3f8684 | ||
|
4ae8011eff | ||
|
d61dbb0315 | ||
|
3c13bf7199 | ||
|
b19cd7c0c9 | ||
|
17438f6f5c | ||
|
f05ab805ff | ||
|
212cd9d54e | ||
|
f4437b6955 | ||
|
0e16cb1730 | ||
|
67cfa9cf01 | ||
|
7bdf2aa1ad |
63 changed files with 934 additions and 289 deletions
|
@ -13,8 +13,8 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk 21
|
minSdk 21
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 475
|
versionCode 477
|
||||||
versionName "3.16.3"
|
versionName "3.17.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
flavorDimensions "default"
|
flavorDimensions "default"
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "3.17.0",
|
||||||
|
"code": "477",
|
||||||
|
"note": "Added:\n- Peertube 2FA support\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n- More deep links detection\n- Allow to group mentions at the top (default: disabled)\n\n\nFixed:\n- Dynamic color for Android 12+\n- Missing media description for previews\n- Fix a crash when replying\n- Fix button size not changed\n- Forward tags in replies\n- Media cannot be downloaded or shared with Android 10\n- Some crashes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "3.16.4",
|
||||||
|
"code": "476",
|
||||||
|
"note": "Added:\n- Cache home in background (default disabled -> New settings category and per account) / change frequency\n- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)\n- Automatically switch between tabs when searching\n\nFixed:\n- Some crashes"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "3.16.3",
|
"version": "3.16.3",
|
||||||
"code": "475",
|
"code": "475",
|
||||||
|
|
|
@ -1811,9 +1811,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
|
||||||
* Allow to scroll to top for bottom navigation items
|
* Allow to scroll to top for bottom navigation items
|
||||||
*/
|
*/
|
||||||
private void scrollToTop() {
|
private void scrollToTop() {
|
||||||
|
int position = binding.tabLayout.getSelectedTabPosition();
|
||||||
if (binding.viewPager.getAdapter() != null) {
|
if (binding.viewPager.getAdapter() != null) {
|
||||||
Fragment fragment = (Fragment) binding.viewPager.getAdapter().instantiateItem(binding.viewPager, binding.tabLayout.getSelectedTabPosition());
|
Fragment fragment = (Fragment) binding.viewPager.getAdapter().instantiateItem(binding.viewPager, Math.max(position, 0));
|
||||||
if (fragment instanceof FragmentMastodonTimeline) {
|
if (fragment instanceof FragmentMastodonTimeline) {
|
||||||
FragmentMastodonTimeline fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
|
FragmentMastodonTimeline fragmentMastodonTimeline = ((FragmentMastodonTimeline) fragment);
|
||||||
fragmentMastodonTimeline.scrollToTop();
|
fragmentMastodonTimeline.scrollToTop();
|
||||||
|
|
|
@ -233,6 +233,10 @@ public class HashTagActivity extends BaseActivity {
|
||||||
tagTimeline.any.add(stripTag.trim());
|
tagTimeline.any.add(stripTag.trim());
|
||||||
pinnedTimeline.tagTimeline = tagTimeline;
|
pinnedTimeline.tagTimeline = tagTimeline;
|
||||||
pinned.pinnedTimelines.add(pinnedTimeline);
|
pinned.pinnedTimelines.add(pinnedTimeline);
|
||||||
|
if (pinned.instance == null || pinned.user_id == null) {
|
||||||
|
pinned.instance = MainActivity.currentInstance;
|
||||||
|
pinned.user_id = MainActivity.currentUserID;
|
||||||
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
new Pinned(HashTagActivity.this).updatePinned(pinned);
|
new Pinned(HashTagActivity.this).updatePinned(pinned);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -250,7 +250,7 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
|
||||||
int position = binding.mediaViewpager.getCurrentItem();
|
int position = binding.mediaViewpager.getCurrentItem();
|
||||||
Attachment attachment = attachments.get(position);
|
Attachment attachment = attachments.get(position);
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
|
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -836,6 +836,10 @@ public class ProfileActivity extends BaseActivity {
|
||||||
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
|
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
|
||||||
pinnedTimeline.position = pinned.pinnedTimelines.size();
|
pinnedTimeline.position = pinned.pinnedTimelines.size();
|
||||||
pinned.pinnedTimelines.add(pinnedTimeline);
|
pinned.pinnedTimelines.add(pinnedTimeline);
|
||||||
|
if (pinned.instance == null || pinned.user_id == null) {
|
||||||
|
pinned.instance = MainActivity.currentInstance;
|
||||||
|
pinned.user_id = MainActivity.currentUserID;
|
||||||
|
}
|
||||||
Pinned finalPinned = pinned;
|
Pinned finalPinned = pinned;
|
||||||
boolean finalPresent = present;
|
boolean finalPresent = present;
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
|
|
|
@ -44,6 +44,7 @@ import java.util.ArrayList;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
|
import app.fedilab.android.activities.MainActivity;
|
||||||
import app.fedilab.android.databinding.ActivityReorderTabsBinding;
|
import app.fedilab.android.databinding.ActivityReorderTabsBinding;
|
||||||
import app.fedilab.android.databinding.PopupSearchInstanceBinding;
|
import app.fedilab.android.databinding.PopupSearchInstanceBinding;
|
||||||
import app.fedilab.android.mastodon.client.entities.app.BottomMenu;
|
import app.fedilab.android.mastodon.client.entities.app.BottomMenu;
|
||||||
|
@ -261,7 +262,10 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
|
||||||
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
|
pinnedTimeline.type = Timeline.TimeLineEnum.REMOTE;
|
||||||
pinnedTimeline.position = pinned.pinnedTimelines.size();
|
pinnedTimeline.position = pinned.pinnedTimelines.size();
|
||||||
pinned.pinnedTimelines.add(pinnedTimeline);
|
pinned.pinnedTimelines.add(pinnedTimeline);
|
||||||
|
if (pinned.user_id == null || pinned.instance == null) {
|
||||||
|
pinned.user_id = MainActivity.currentUserID;
|
||||||
|
pinned.instance = MainActivity.currentInstance;
|
||||||
|
}
|
||||||
if (update) {
|
if (update) {
|
||||||
try {
|
try {
|
||||||
new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
|
new Pinned(ReorderTimelinesActivity.this).updatePinned(pinned);
|
||||||
|
|
|
@ -318,4 +318,18 @@ public interface MastodonStatusesService {
|
||||||
@Header("Authorization") String token,
|
@Header("Authorization") String token,
|
||||||
@Path("id") String id
|
@Path("id") String id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@POST("statuses/{id}/react/{name}")
|
||||||
|
Call<Void> addReaction(
|
||||||
|
@Header("Authorization") String app_token,
|
||||||
|
@Path("id") String id,
|
||||||
|
@Path("name") String name
|
||||||
|
);
|
||||||
|
|
||||||
|
@POST("statuses/{id}/unreact/{name}")
|
||||||
|
Call<Void> removeReaction(
|
||||||
|
@Header("Authorization") String app_token,
|
||||||
|
@Path("id") String id,
|
||||||
|
@Path("name") String name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import app.fedilab.android.mastodon.helper.SpannableHelper;
|
import app.fedilab.android.mastodon.helper.SpannableHelper;
|
||||||
|
import de.timfreiheit.mathjax.android.MathJaxView;
|
||||||
|
|
||||||
public class Status implements Serializable, Cloneable {
|
public class Status implements Serializable, Cloneable {
|
||||||
|
|
||||||
|
@ -108,6 +109,8 @@ public class Status implements Serializable, Cloneable {
|
||||||
public boolean cached = false;
|
public boolean cached = false;
|
||||||
@SerializedName("is_maths")
|
@SerializedName("is_maths")
|
||||||
public Boolean isMaths;
|
public Boolean isMaths;
|
||||||
|
@SerializedName("reactions")
|
||||||
|
public List<Reaction> reactions;
|
||||||
|
|
||||||
public Attachment art_attachment;
|
public Attachment art_attachment;
|
||||||
public boolean isExpended = false;
|
public boolean isExpended = false;
|
||||||
|
@ -128,6 +131,7 @@ public class Status implements Serializable, Cloneable {
|
||||||
public transient Spannable contentSpan;
|
public transient Spannable contentSpan;
|
||||||
public transient Spannable contentSpoilerSpan;
|
public transient Spannable contentSpoilerSpan;
|
||||||
public transient Spannable contentTranslateSpan;
|
public transient Spannable contentTranslateSpan;
|
||||||
|
public transient MathJaxView mathJaxView;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
|
|
|
@ -166,8 +166,8 @@ public class BottomMenu implements Serializable {
|
||||||
throw new DBException("db is null. Wrong initialization.");
|
throw new DBException("db is null. Wrong initialization.");
|
||||||
}
|
}
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(Sqlite.COL_INSTANCE, BaseMainActivity.currentInstance);
|
values.put(Sqlite.COL_INSTANCE, bottomMenu.instance);
|
||||||
values.put(Sqlite.COL_USER_ID, BaseMainActivity.currentUserID);
|
values.put(Sqlite.COL_USER_ID, bottomMenu.user_id);
|
||||||
values.put(Sqlite.COL_BOTTOM_MENU, menuItemListToStringStorage(bottomMenu.bottom_menu));
|
values.put(Sqlite.COL_BOTTOM_MENU, menuItemListToStringStorage(bottomMenu.bottom_menu));
|
||||||
//Inserts bottom
|
//Inserts bottom
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -28,7 +28,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import app.fedilab.android.BaseMainActivity;
|
|
||||||
import app.fedilab.android.mastodon.exception.DBException;
|
import app.fedilab.android.mastodon.exception.DBException;
|
||||||
import app.fedilab.android.mastodon.helper.Helper;
|
import app.fedilab.android.mastodon.helper.Helper;
|
||||||
import app.fedilab.android.sqlite.Sqlite;
|
import app.fedilab.android.sqlite.Sqlite;
|
||||||
|
@ -104,8 +103,8 @@ public class Pinned implements Serializable {
|
||||||
throw new DBException("db is null. Wrong initialization.");
|
throw new DBException("db is null. Wrong initialization.");
|
||||||
}
|
}
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(Sqlite.COL_INSTANCE, BaseMainActivity.currentInstance);
|
values.put(Sqlite.COL_INSTANCE, pinned.instance);
|
||||||
values.put(Sqlite.COL_USER_ID, BaseMainActivity.currentUserID);
|
values.put(Sqlite.COL_USER_ID, pinned.user_id);
|
||||||
values.put(Sqlite.COL_PINNED_TIMELINES, mastodonPinnedTimelinesToStringStorage(pinned.pinnedTimelines));
|
values.put(Sqlite.COL_PINNED_TIMELINES, mastodonPinnedTimelinesToStringStorage(pinned.pinnedTimelines));
|
||||||
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(new Date()));
|
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(new Date()));
|
||||||
//Inserts pinned
|
//Inserts pinned
|
||||||
|
|
|
@ -277,6 +277,7 @@ public class PinnedTimelineHelper {
|
||||||
pinnedTimeline.position = pinnedAll.pinnedTimelines.size();
|
pinnedTimeline.position = pinnedAll.pinnedTimelines.size();
|
||||||
pinnedTimeline.mastodonList = mastodonList;
|
pinnedTimeline.mastodonList = mastodonList;
|
||||||
pinnedAll.pinnedTimelines.add(pinnedTimeline);
|
pinnedAll.pinnedTimelines.add(pinnedTimeline);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
boolean exist = new Pinned(activity).pinnedExist(pinnedAll);
|
boolean exist = new Pinned(activity).pinnedExist(pinnedAll);
|
||||||
if (exist) {
|
if (exist) {
|
||||||
|
@ -304,7 +305,7 @@ public class PinnedTimelineHelper {
|
||||||
//Small hack to hide first tabs (they represent the item of the bottom menu)
|
//Small hack to hide first tabs (they represent the item of the bottom menu)
|
||||||
toRemove = itemToRemoveInBottomMenu(activity);
|
toRemove = itemToRemoveInBottomMenu(activity);
|
||||||
for (int i = 0; i < (FedilabPageAdapter.BOTTOM_TIMELINE_COUNT - toRemove); i++) {
|
for (int i = 0; i < (FedilabPageAdapter.BOTTOM_TIMELINE_COUNT - toRemove); i++) {
|
||||||
activityMainBinding.tabLayout.addTab(activityMainBinding.tabLayout.newTab());
|
activityMainBinding.tabLayout.addTab(activityMainBinding.tabLayout.newTab(), false);
|
||||||
((ViewGroup) activityMainBinding.tabLayout.getChildAt(0)).getChildAt(i).setVisibility(View.GONE);
|
((ViewGroup) activityMainBinding.tabLayout.getChildAt(0)).getChildAt(i).setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,7 +414,7 @@ public class PinnedTimelineHelper {
|
||||||
//We be used to fetch position of tabs
|
//We be used to fetch position of tabs
|
||||||
String slug = pinnedTimeline.type.getValue() + (ident != null ? "|" + ident : "");
|
String slug = pinnedTimeline.type.getValue() + (ident != null ? "|" + ident : "");
|
||||||
tab.setTag(slug);
|
tab.setTag(slug);
|
||||||
activityMainBinding.tabLayout.addTab(tab);
|
activityMainBinding.tabLayout.addTab(tab, false);
|
||||||
pinnedTimelineVisibleList.add(pinnedTimeline);
|
pinnedTimelineVisibleList.add(pinnedTimeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,6 +514,8 @@ public class SpannableHelper {
|
||||||
Matcher matcherLink = link.matcher(finalUrl);
|
Matcher matcherLink = link.matcher(finalUrl);
|
||||||
Pattern linkLong = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)(/[0-9]+)?$");
|
Pattern linkLong = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)(/[0-9]+)?$");
|
||||||
Matcher matcherLinkLong = linkLong.matcher(finalUrl);
|
Matcher matcherLinkLong = linkLong.matcher(finalUrl);
|
||||||
|
Pattern userWithoutAt = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(users/([\\w._-]*[0-9]*))/statuses/([0-9]+)");
|
||||||
|
Matcher matcherUserWithoutAt = userWithoutAt.matcher(finalUrl);
|
||||||
if (matcherLink.find() && !finalUrl.contains("medium.com")) {
|
if (matcherLink.find() && !finalUrl.contains("medium.com")) {
|
||||||
if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot
|
if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot
|
||||||
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
|
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
|
||||||
|
@ -567,6 +569,38 @@ public class SpannableHelper {
|
||||||
public void federatedStatus(Status status) {
|
public void federatedStatus(Status status) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void federatedAccount(Account account) {
|
||||||
|
Intent intent = new Intent(context, ProfileActivity.class);
|
||||||
|
Bundle b = new Bundle();
|
||||||
|
b.putSerializable(Helper.ARG_ACCOUNT, account);
|
||||||
|
intent.putExtras(b);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (matcherUserWithoutAt.find() && !finalUrl.contains("medium.com")) {
|
||||||
|
if (matcherUserWithoutAt.group(4) != null && Objects.requireNonNull(matcherUserWithoutAt.group(4)).length() > 0) { //It's a toot
|
||||||
|
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
|
||||||
|
@Override
|
||||||
|
public void federatedStatus(Status status) {
|
||||||
|
Intent intent = new Intent(context, ContextActivity.class);
|
||||||
|
intent.putExtra(Helper.ARG_STATUS, status);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void federatedAccount(Account account) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {//It's an account
|
||||||
|
CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherUserWithoutAt.group(3) + "@" + matcherUserWithoutAt.group(1), new CrossActionHelper.Callback() {
|
||||||
|
@Override
|
||||||
|
public void federatedStatus(Status status) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void federatedAccount(Account account) {
|
public void federatedAccount(Account account) {
|
||||||
Intent intent = new Intent(context, ProfileActivity.class);
|
Intent intent = new Intent(context, ProfileActivity.class);
|
||||||
|
|
|
@ -265,7 +265,7 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList
|
||||||
.setClearViewsEnabled(true)
|
.setClearViewsEnabled(true)
|
||||||
.setTransparencyEnabled(true)
|
.setTransparencyEnabled(true)
|
||||||
.build();
|
.build();
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
if (ContextCompat.checkSelfPermission(EditImageActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
|
if (ContextCompat.checkSelfPermission(EditImageActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) !=
|
||||||
PackageManager.PERMISSION_GRANTED) {
|
PackageManager.PERMISSION_GRANTED) {
|
||||||
ActivityCompat.requestPermissions(EditImageActivity.this,
|
ActivityCompat.requestPermissions(EditImageActivity.this,
|
||||||
|
|
|
@ -76,12 +76,13 @@ public class FetchHomeWorker extends Worker {
|
||||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setRepeatHome(Context context, BaseAccount account) {
|
public static void setRepeatHome(Context context, BaseAccount account, Data inputData) {
|
||||||
WorkManager.getInstance(context).cancelAllWorkByTag(Helper.WORKER_REFRESH_HOME + account.user_id + account.instance);
|
WorkManager.getInstance(context).cancelAllWorkByTag(Helper.WORKER_REFRESH_HOME + account.user_id + account.instance);
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
String value = prefs.getString(context.getString(R.string.SET_FETCH_HOME_DELAY_VALUE) + account.user_id + account.instance, "60");
|
String value = prefs.getString(context.getString(R.string.SET_FETCH_HOME_DELAY_VALUE) + account.user_id + account.instance, "60");
|
||||||
PeriodicWorkRequest notificationPeriodic = new PeriodicWorkRequest.Builder(NotificationsWorker.class, Long.parseLong(value), TimeUnit.MINUTES)
|
PeriodicWorkRequest notificationPeriodic = new PeriodicWorkRequest.Builder(FetchHomeWorker.class, Long.parseLong(value), TimeUnit.MINUTES)
|
||||||
.addTag(Helper.WORKER_REFRESH_NOTIFICATION)
|
.setInputData(inputData)
|
||||||
|
.addTag(Helper.WORKER_REFRESH_HOME + account.user_id + account.instance)
|
||||||
.build();
|
.build();
|
||||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(Helper.WORKER_REFRESH_HOME + account.user_id + account.instance, ExistingPeriodicWorkPolicy.REPLACE, notificationPeriodic);
|
WorkManager.getInstance(context).enqueueUniquePeriodicWork(Helper.WORKER_REFRESH_HOME + account.user_id + account.instance, ExistingPeriodicWorkPolicy.REPLACE, notificationPeriodic);
|
||||||
}
|
}
|
||||||
|
@ -90,17 +91,13 @@ public class FetchHomeWorker extends Worker {
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
|
public ListenableFuture<ForegroundInfo> getForegroundInfoAsync() {
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
String channelName = "Notifications";
|
String channelName = "Fetch Home";
|
||||||
String channelDescription = "Fetched notifications";
|
String channelDescription = "Fetch home messages";
|
||||||
NotificationChannel notifChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
NotificationChannel fetchHomeChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||||
notifChannel.setDescription(channelDescription);
|
fetchHomeChannel.setDescription(channelDescription);
|
||||||
notifChannel.setSound(null, null);
|
fetchHomeChannel.setSound(null, null);
|
||||||
notifChannel.setShowBadge(false);
|
fetchHomeChannel.setShowBadge(false);
|
||||||
notificationManager.createNotificationChannel(notifChannel);
|
notificationManager.createNotificationChannel(fetchHomeChannel);
|
||||||
if (notificationManager.getNotificationChannel("notifications") != null) {
|
|
||||||
notificationManager.deleteNotificationChannel("notifications");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
|
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
|
||||||
notificationBuilder.setSmallIcon(R.drawable.ic_notification)
|
notificationBuilder.setSmallIcon(R.drawable.ic_notification)
|
||||||
|
@ -115,20 +112,20 @@ public class FetchHomeWorker extends Worker {
|
||||||
@NonNull
|
@NonNull
|
||||||
private ForegroundInfo createForegroundInfo() {
|
private ForegroundInfo createForegroundInfo() {
|
||||||
if (Build.VERSION.SDK_INT >= 26) {
|
if (Build.VERSION.SDK_INT >= 26) {
|
||||||
String channelName = "Notifications";
|
String channelName = "Fetch Home";
|
||||||
String channelDescription = "Fetched notifications";
|
String channelDescription = "Fetch home messages";
|
||||||
NotificationChannel notifChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
NotificationChannel fetchHomeChannel = new NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_LOW);
|
||||||
notifChannel.setSound(null, null);
|
fetchHomeChannel.setSound(null, null);
|
||||||
notifChannel.setShowBadge(false);
|
fetchHomeChannel.setShowBadge(false);
|
||||||
notifChannel.setDescription(channelDescription);
|
fetchHomeChannel.setDescription(channelDescription);
|
||||||
notificationManager.createNotificationChannel(notifChannel);
|
notificationManager.createNotificationChannel(fetchHomeChannel);
|
||||||
|
|
||||||
}
|
}
|
||||||
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
|
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID);
|
||||||
notificationBuilder.setSmallIcon(R.drawable.ic_notification)
|
notificationBuilder.setSmallIcon(R.drawable.ic_notification)
|
||||||
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.ic_launcher_foreground))
|
.setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.ic_launcher_foreground))
|
||||||
.setContentTitle(getApplicationContext().getString(R.string.notifications))
|
.setContentTitle(getApplicationContext().getString(R.string.fetch_home_messages))
|
||||||
.setContentText(getApplicationContext().getString(R.string.fetch_notifications))
|
.setContentText(getApplicationContext().getString(R.string.set_fetch_home))
|
||||||
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
.setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||||
.setSilent(true)
|
.setSilent(true)
|
||||||
.setPriority(Notification.PRIORITY_LOW);
|
.setPriority(Notification.PRIORITY_LOW);
|
||||||
|
@ -138,10 +135,15 @@ public class FetchHomeWorker extends Worker {
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Result doWork() {
|
public Result doWork() {
|
||||||
|
|
||||||
setForegroundAsync(createForegroundInfo());
|
setForegroundAsync(createForegroundInfo());
|
||||||
|
|
||||||
|
String instance = getInputData().getString(Helper.ARG_INSTANCE);
|
||||||
|
String userId = getInputData().getString(Helper.ARG_USER_ID);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<BaseAccount> accounts = new Account(getApplicationContext()).getCrossAccounts();
|
BaseAccount account = new Account(getApplicationContext()).getUniqAccount(userId, instance);
|
||||||
for (BaseAccount account : accounts) {
|
if (account != null) {
|
||||||
try {
|
try {
|
||||||
fetchHome(getApplicationContext(), account);
|
fetchHome(getApplicationContext(), account);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -168,7 +170,7 @@ public class FetchHomeWorker extends Worker {
|
||||||
String max_id = null;
|
String max_id = null;
|
||||||
MastodonTimelinesService mastodonTimelinesService = init(account.instance);
|
MastodonTimelinesService mastodonTimelinesService = init(account.instance);
|
||||||
while (canContinue && call < max_calls) {
|
while (canContinue && call < max_calls) {
|
||||||
Call<List<Status>> homeCall = mastodonTimelinesService.getHome(account.token, account.instance, max_id, null, status_per_page, null);
|
Call<List<Status>> homeCall = mastodonTimelinesService.getHome(account.token, max_id, null, null, status_per_page, null);
|
||||||
if (homeCall != null) {
|
if (homeCall != null) {
|
||||||
Response<List<Status>> homeResponse = homeCall.execute();
|
Response<List<Status>> homeResponse = homeCall.execute();
|
||||||
if (homeResponse.isSuccessful()) {
|
if (homeResponse.isSuccessful()) {
|
||||||
|
@ -183,12 +185,7 @@ public class FetchHomeWorker extends Worker {
|
||||||
statusCache.type = Timeline.TimeLineEnum.HOME;
|
statusCache.type = Timeline.TimeLineEnum.HOME;
|
||||||
statusCache.status_id = status.id;
|
statusCache.status_id = status.id;
|
||||||
try {
|
try {
|
||||||
int inserted = statusCacheDAO.insertOrUpdate(statusCache, Timeline.TimeLineEnum.HOME.getValue());
|
statusCacheDAO.insertOrUpdate(statusCache, Timeline.TimeLineEnum.HOME.getValue());
|
||||||
//We reached already cached messages
|
|
||||||
if (inserted == 0) {
|
|
||||||
canContinue = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (DBException e) {
|
} catch (DBException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -206,9 +203,14 @@ public class FetchHomeWorker extends Worker {
|
||||||
canContinue = false;
|
canContinue = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Pause between calls (1 second)
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
call++;
|
call++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import app.fedilab.android.databinding.DrawerCacheBinding;
|
||||||
import app.fedilab.android.mastodon.client.entities.app.CacheAccount;
|
import app.fedilab.android.mastodon.client.entities.app.CacheAccount;
|
||||||
import app.fedilab.android.mastodon.helper.CacheHelper;
|
import app.fedilab.android.mastodon.helper.CacheHelper;
|
||||||
import app.fedilab.android.mastodon.helper.MastodonHelper;
|
import app.fedilab.android.mastodon.helper.MastodonHelper;
|
||||||
|
import app.fedilab.android.peertube.helper.Helper;
|
||||||
|
|
||||||
|
|
||||||
public class CacheAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
public class CacheAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
@ -61,9 +62,17 @@ public class CacheAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
CacheAccount cacheAccount = accountList.get(position);
|
CacheAccount cacheAccount = accountList.get(position);
|
||||||
AccountCacheViewHolder holder = (AccountCacheViewHolder) viewHolder;
|
AccountCacheViewHolder holder = (AccountCacheViewHolder) viewHolder;
|
||||||
MastodonHelper.loadPPMastodon(holder.binding.pp, cacheAccount.account.mastodon_account);
|
|
||||||
holder.binding.acct.setText(String.format("@%s@%s", cacheAccount.account.mastodon_account.username, cacheAccount.account.instance));
|
if (cacheAccount.account.mastodon_account != null) {
|
||||||
holder.binding.displayName.setText(cacheAccount.account.mastodon_account.display_name);
|
MastodonHelper.loadPPMastodon(holder.binding.pp, cacheAccount.account.mastodon_account);
|
||||||
|
holder.binding.acct.setText(String.format("@%s@%s", cacheAccount.account.mastodon_account.username, cacheAccount.account.instance));
|
||||||
|
holder.binding.displayName.setText(cacheAccount.account.mastodon_account.display_name);
|
||||||
|
} else if (cacheAccount.account.peertube_account != null) {
|
||||||
|
Helper.loadAvatar(context, cacheAccount.account.peertube_account, holder.binding.pp);
|
||||||
|
holder.binding.acct.setText(String.format("@%s@%s", cacheAccount.account.peertube_account.getUsername(), cacheAccount.account.instance));
|
||||||
|
holder.binding.displayName.setText(cacheAccount.account.peertube_account.getDisplayName());
|
||||||
|
}
|
||||||
|
|
||||||
CacheHelper.getTimelineValues(context, cacheAccount.account, countStatuses -> {
|
CacheHelper.getTimelineValues(context, cacheAccount.account, countStatuses -> {
|
||||||
if (countStatuses != null && countStatuses.size() == 3) {
|
if (countStatuses != null && countStatuses.size() == 3) {
|
||||||
holder.binding.homeCount.setText(String.valueOf(countStatuses.get(0)));
|
holder.binding.homeCount.setText(String.valueOf(countStatuses.get(0)));
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static app.fedilab.android.BaseMainActivity.currentAccount;
|
||||||
import static app.fedilab.android.BaseMainActivity.emojis;
|
import static app.fedilab.android.BaseMainActivity.emojis;
|
||||||
import static app.fedilab.android.BaseMainActivity.instanceInfo;
|
import static app.fedilab.android.BaseMainActivity.instanceInfo;
|
||||||
import static app.fedilab.android.mastodon.activities.ComposeActivity.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE;
|
import static app.fedilab.android.mastodon.activities.ComposeActivity.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE;
|
||||||
|
import static de.timfreiheit.mathjax.android.MathJaxConfig.Input.TeX;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
@ -127,6 +128,8 @@ import app.fedilab.android.mastodon.helper.ThemeHelper;
|
||||||
import app.fedilab.android.mastodon.imageeditor.EditImageActivity;
|
import app.fedilab.android.mastodon.imageeditor.EditImageActivity;
|
||||||
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
|
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
|
||||||
import app.fedilab.android.mastodon.viewmodel.mastodon.SearchVM;
|
import app.fedilab.android.mastodon.viewmodel.mastodon.SearchVM;
|
||||||
|
import de.timfreiheit.mathjax.android.MathJaxConfig;
|
||||||
|
import de.timfreiheit.mathjax.android.MathJaxView;
|
||||||
import es.dmoral.toasty.Toasty;
|
import es.dmoral.toasty.Toasty;
|
||||||
|
|
||||||
|
|
||||||
|
@ -311,8 +314,10 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
}
|
}
|
||||||
//Put other accounts mentioned at the bottom
|
//Put other accounts mentioned at the bottom
|
||||||
boolean capitalize = sharedpreferences.getBoolean(context.getString(R.string.SET_CAPITALIZE), true);
|
boolean capitalize = sharedpreferences.getBoolean(context.getString(R.string.SET_CAPITALIZE), true);
|
||||||
|
boolean mentionsAtTop = sharedpreferences.getBoolean(context.getString(R.string.SET_MENTIONS_AT_TOP), false);
|
||||||
|
|
||||||
if (inReplyToUser != null) {
|
if (inReplyToUser != null) {
|
||||||
if (capitalize) {
|
if (capitalize && !mentionsAtTop) {
|
||||||
statusDraft.text = inReplyToUser.acct.startsWith("@") ? inReplyToUser.acct + "\n" : "@" + inReplyToUser.acct + "\n";
|
statusDraft.text = inReplyToUser.acct.startsWith("@") ? inReplyToUser.acct + "\n" : "@" + inReplyToUser.acct + "\n";
|
||||||
} else {
|
} else {
|
||||||
statusDraft.text = inReplyToUser.acct.startsWith("@") ? inReplyToUser.acct + " " : "@" + inReplyToUser.acct + " ";
|
statusDraft.text = inReplyToUser.acct.startsWith("@") ? inReplyToUser.acct + " " : "@" + inReplyToUser.acct + " ";
|
||||||
|
@ -321,7 +326,9 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
holder.binding.content.setText(statusDraft.text);
|
holder.binding.content.setText(statusDraft.text);
|
||||||
statusDraft.cursorPosition = statusDraft.text.length();
|
statusDraft.cursorPosition = statusDraft.text.length();
|
||||||
if (statusDraft.mentions.size() > 1) {
|
if (statusDraft.mentions.size() > 1) {
|
||||||
statusDraft.text += "\n";
|
if (!mentionsAtTop) {
|
||||||
|
statusDraft.text += "\n";
|
||||||
|
}
|
||||||
for (int i = 1; i < statusDraft.mentions.size(); i++) {
|
for (int i = 1; i < statusDraft.mentions.size(); i++) {
|
||||||
String tootTemp = String.format("@%s ", statusDraft.mentions.get(i).acct);
|
String tootTemp = String.format("@%s ", statusDraft.mentions.get(i).acct);
|
||||||
statusDraft.text = String.format("%s ", (statusDraft.text + tootTemp.trim()));
|
statusDraft.text = String.format("%s ", (statusDraft.text + tootTemp.trim()));
|
||||||
|
@ -392,7 +399,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
* @param position - int position of the media in the message
|
* @param position - int position of the media in the message
|
||||||
*/
|
*/
|
||||||
private void pickupMedia(ComposeActivity.mediaType type, int position) {
|
private void pickupMedia(ComposeActivity.mediaType type, int position) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) !=
|
if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) !=
|
||||||
PackageManager.PERMISSION_GRANTED) {
|
PackageManager.PERMISSION_GRANTED) {
|
||||||
ActivityCompat.requestPermissions((Activity) context,
|
ActivityCompat.requestPermissions((Activity) context,
|
||||||
|
@ -702,19 +709,26 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
}
|
}
|
||||||
Matcher mathsPatterns = Helper.mathsComposePattern.matcher((s.toString()));
|
Matcher mathsPatterns = Helper.mathsComposePattern.matcher((s.toString()));
|
||||||
if (mathsPatterns.find()) {
|
if (mathsPatterns.find()) {
|
||||||
if (holder.binding.laTexViewContainer.getVisibility() != View.VISIBLE) {
|
if (holder.binding.laTexViewContainer.getChildCount() == 0) {
|
||||||
holder.binding.laTexViewContainer.setVisibility(View.VISIBLE);
|
MathJaxConfig mathJaxConfig = new MathJaxConfig();
|
||||||
|
mathJaxConfig.setAutomaticLinebreaks(true);
|
||||||
|
mathJaxConfig.setInput(TeX);
|
||||||
switch (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
|
switch (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
|
||||||
case Configuration.UI_MODE_NIGHT_YES:
|
case Configuration.UI_MODE_NIGHT_YES:
|
||||||
holder.binding.laTexView.setTextColor("white");
|
mathJaxConfig.setTextColor("white");
|
||||||
break;
|
break;
|
||||||
case Configuration.UI_MODE_NIGHT_NO:
|
case Configuration.UI_MODE_NIGHT_NO:
|
||||||
holder.binding.laTexView.setTextColor("black");
|
mathJaxConfig.setTextColor("black");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
statusList.get(holder.getBindingAdapterPosition()).mathJaxView = new MathJaxView(context, mathJaxConfig);
|
||||||
|
holder.binding.laTexViewContainer.addView(statusList.get(holder.getBindingAdapterPosition()).mathJaxView);
|
||||||
|
holder.binding.laTexViewContainer.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
holder.binding.laTexView.setInputText(s.toString());
|
if (statusList.get(holder.getBindingAdapterPosition()).mathJaxView != null) {
|
||||||
|
statusList.get(holder.getBindingAdapterPosition()).mathJaxView.setInputText(s.toString());
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
holder.binding.laTexViewContainer.setVisibility(View.GONE);
|
holder.binding.laTexViewContainer.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -1297,6 +1311,8 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
ComposeViewHolder holder = (ComposeViewHolder) viewHolder;
|
ComposeViewHolder holder = (ComposeViewHolder) viewHolder;
|
||||||
boolean extraFeatures = sharedpreferences.getBoolean(context.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false);
|
boolean extraFeatures = sharedpreferences.getBoolean(context.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false);
|
||||||
boolean mathsComposer = sharedpreferences.getBoolean(context.getString(R.string.SET_MATHS_COMPOSER), true);
|
boolean mathsComposer = sharedpreferences.getBoolean(context.getString(R.string.SET_MATHS_COMPOSER), true);
|
||||||
|
boolean forwardTag = sharedpreferences.getBoolean(context.getString(R.string.SET_FORWARD_TAGS_IN_REPLY), true);
|
||||||
|
|
||||||
|
|
||||||
if (mathsComposer) {
|
if (mathsComposer) {
|
||||||
holder.binding.buttonMathsComposer.setVisibility(View.VISIBLE);
|
holder.binding.buttonMathsComposer.setVisibility(View.VISIBLE);
|
||||||
|
@ -1565,13 +1581,48 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||||
currentCursorPosition = holder.getLayoutPosition();
|
currentCursorPosition = holder.getLayoutPosition();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
boolean capitalize = sharedpreferences.getBoolean(context.getString(R.string.SET_CAPITALIZE), true);
|
||||||
|
boolean mentionsAtTop = sharedpreferences.getBoolean(context.getString(R.string.SET_MENTIONS_AT_TOP), false);
|
||||||
if (statusDraft.cursorPosition <= holder.binding.content.length()) {
|
if (statusDraft.cursorPosition <= holder.binding.content.length()) {
|
||||||
holder.binding.content.setSelection(statusDraft.cursorPosition);
|
if (!mentionsAtTop) {
|
||||||
|
holder.binding.content.setSelection(statusDraft.cursorPosition);
|
||||||
|
} else {
|
||||||
|
if (capitalize && !statusDraft.text.endsWith("\n")) {
|
||||||
|
statusDraft.text += "\n";
|
||||||
|
holder.binding.content.setText(statusDraft.text);
|
||||||
|
}
|
||||||
|
holder.binding.content.setSelection(holder.binding.content.getText().length());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (statusDraft.setCursorToEnd) {
|
if (statusDraft.setCursorToEnd) {
|
||||||
statusDraft.setCursorToEnd = false;
|
statusDraft.setCursorToEnd = false;
|
||||||
holder.binding.content.setSelection(holder.binding.content.getText().length());
|
holder.binding.content.setSelection(holder.binding.content.getText().length());
|
||||||
}
|
}
|
||||||
|
if (forwardTag && position > 0 && statusDraft.text != null && !statusDraft.text.contains("#")) {
|
||||||
|
Status status = statusList.get(position - 1).reblog == null ? statusList.get(position - 1) : statusList.get(position - 1).reblog;
|
||||||
|
if (status.tags != null && status.tags.size() > 0) {
|
||||||
|
statusDraft.text += "\n\n";
|
||||||
|
int lenght = 0;
|
||||||
|
for (Tag tag : status.tags) {
|
||||||
|
statusDraft.text += "#" + tag.name + " ";
|
||||||
|
lenght += ("#" + tag.name + " ").length();
|
||||||
|
}
|
||||||
|
holder.binding.content.setText(statusDraft.text);
|
||||||
|
statusDraft.cursorPosition = statusDraft.text.length() - lenght - 3;
|
||||||
|
statusDraft.setCursorToEnd = false;
|
||||||
|
holder.binding.content.setSelection(statusDraft.text.length() - lenght - 3);
|
||||||
|
}
|
||||||
|
} else if (forwardTag && position > 0 && statusDraft.text != null && statusDraft.text.contains("#")) {
|
||||||
|
Status status = statusList.get(position - 1).reblog == null ? statusList.get(position - 1) : statusList.get(position - 1).reblog;
|
||||||
|
int lenght = 0;
|
||||||
|
for (Tag tag : status.tags) {
|
||||||
|
lenght += ("#" + tag.name + " ").length();
|
||||||
|
}
|
||||||
|
statusDraft.cursorPosition = statusDraft.text.length() - lenght - 3;
|
||||||
|
statusDraft.setCursorToEnd = false;
|
||||||
|
holder.binding.content.setSelection(statusDraft.text.length() - lenght - 3);
|
||||||
|
}
|
||||||
|
|
||||||
if (statusDraft.spoiler_text != null) {
|
if (statusDraft.spoiler_text != null) {
|
||||||
holder.binding.contentSpoiler.setText(statusDraft.spoiler_text);
|
holder.binding.contentSpoiler.setText(statusDraft.spoiler_text);
|
||||||
holder.binding.contentSpoiler.setSelection(holder.binding.contentSpoiler.getText().length());
|
holder.binding.contentSpoiler.setSelection(holder.binding.contentSpoiler.getText().length());
|
||||||
|
|
|
@ -34,6 +34,7 @@ import app.fedilab.android.mastodon.client.entities.api.Reaction;
|
||||||
import app.fedilab.android.mastodon.helper.Helper;
|
import app.fedilab.android.mastodon.helper.Helper;
|
||||||
import app.fedilab.android.mastodon.helper.ThemeHelper;
|
import app.fedilab.android.mastodon.helper.ThemeHelper;
|
||||||
import app.fedilab.android.mastodon.viewmodel.mastodon.AnnouncementsVM;
|
import app.fedilab.android.mastodon.viewmodel.mastodon.AnnouncementsVM;
|
||||||
|
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
|
||||||
import app.fedilab.android.mastodon.viewmodel.pleroma.ActionsVM;
|
import app.fedilab.android.mastodon.viewmodel.pleroma.ActionsVM;
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,18 +47,29 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti
|
||||||
private final List<Reaction> reactions;
|
private final List<Reaction> reactions;
|
||||||
private final String announcementId;
|
private final String announcementId;
|
||||||
private final boolean statusReaction;
|
private final boolean statusReaction;
|
||||||
|
private final boolean isPleroma;
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
|
|
||||||
|
ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction, boolean isPleroma) {
|
||||||
|
this.reactions = reactions;
|
||||||
|
this.announcementId = announcementId;
|
||||||
|
this.statusReaction = statusReaction;
|
||||||
|
this.isPleroma = isPleroma;
|
||||||
|
}
|
||||||
|
|
||||||
ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction) {
|
ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction) {
|
||||||
this.reactions = reactions;
|
this.reactions = reactions;
|
||||||
this.announcementId = announcementId;
|
this.announcementId = announcementId;
|
||||||
this.statusReaction = statusReaction;
|
this.statusReaction = statusReaction;
|
||||||
|
this.isPleroma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactionAdapter(String announcementId, List<Reaction> reactions) {
|
ReactionAdapter(String announcementId, List<Reaction> reactions) {
|
||||||
this.reactions = reactions;
|
this.reactions = reactions;
|
||||||
this.announcementId = announcementId;
|
this.announcementId = announcementId;
|
||||||
this.statusReaction = false;
|
this.statusReaction = false;
|
||||||
|
this.isPleroma = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -101,7 +113,7 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti
|
||||||
}
|
}
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
});
|
});
|
||||||
} else {
|
} else if (isPleroma) {
|
||||||
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
||||||
holder.binding.reactionContainer.setOnClickListener(v -> {
|
holder.binding.reactionContainer.setOnClickListener(v -> {
|
||||||
if (reaction.me) {
|
if (reaction.me) {
|
||||||
|
@ -115,6 +127,20 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti
|
||||||
}
|
}
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class);
|
||||||
|
holder.binding.reactionContainer.setOnClickListener(v -> {
|
||||||
|
if (reaction.me) {
|
||||||
|
statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name);
|
||||||
|
reaction.me = false;
|
||||||
|
reaction.count -= 1;
|
||||||
|
} else {
|
||||||
|
statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name);
|
||||||
|
reaction.me = true;
|
||||||
|
reaction.count += 1;
|
||||||
|
}
|
||||||
|
notifyItemChanged(position);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
|
import app.fedilab.android.activities.MainActivity;
|
||||||
import app.fedilab.android.databinding.DrawerReorderBinding;
|
import app.fedilab.android.databinding.DrawerReorderBinding;
|
||||||
import app.fedilab.android.mastodon.activities.ReorderTimelinesActivity;
|
import app.fedilab.android.mastodon.activities.ReorderTimelinesActivity;
|
||||||
import app.fedilab.android.mastodon.client.entities.app.BottomMenu;
|
import app.fedilab.android.mastodon.client.entities.app.BottomMenu;
|
||||||
|
@ -100,6 +101,8 @@ public class ReorderBottomMenuAdapter extends RecyclerView.Adapter<RecyclerView.
|
||||||
|
|
||||||
holder.binding.hide.setOnClickListener(v -> {
|
holder.binding.hide.setOnClickListener(v -> {
|
||||||
bottomMenu.bottom_menu.get(position).visible = !bottomMenu.bottom_menu.get(position).visible;
|
bottomMenu.bottom_menu.get(position).visible = !bottomMenu.bottom_menu.get(position).visible;
|
||||||
|
bottomMenu.user_id = MainActivity.currentUserID;
|
||||||
|
bottomMenu.instance = MainActivity.currentInstance;
|
||||||
if (bottomMenu.bottom_menu.get(position).visible) {
|
if (bottomMenu.bottom_menu.get(position).visible) {
|
||||||
holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_24);
|
holder.binding.hide.setImageResource(R.drawable.ic_baseline_visibility_24);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -50,6 +50,7 @@ import android.os.Looper;
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
@ -414,6 +415,8 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
boolean compactButtons = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COMPACT_ACTION_BUTTON), false);
|
boolean compactButtons = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COMPACT_ACTION_BUTTON), false);
|
||||||
boolean originalDateForBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_BOOST_ORIGINAL_DATE), true);
|
boolean originalDateForBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_BOOST_ORIGINAL_DATE), true);
|
||||||
boolean hideSingleMediaWithCard = sharedpreferences.getBoolean(context.getString(R.string.SET_HIDE_SINGLE_MEDIA_WITH_CARD), false);
|
boolean hideSingleMediaWithCard = sharedpreferences.getBoolean(context.getString(R.string.SET_HIDE_SINGLE_MEDIA_WITH_CARD), false);
|
||||||
|
boolean autofetch = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_FETCH_MISSING_MESSAGES), false);
|
||||||
|
|
||||||
|
|
||||||
if (compactButtons) {
|
if (compactButtons) {
|
||||||
ConstraintSet set = new ConstraintSet();
|
ConstraintSet set = new ConstraintSet();
|
||||||
|
@ -517,7 +520,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
holder.binding.quotedMessage.cardviewContainer.setVisibility(View.GONE);
|
holder.binding.quotedMessage.cardviewContainer.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentAccount != null && currentAccount.api == Account.API.PLEROMA) {
|
if (currentAccount != null && currentAccount.api == Account.API.PLEROMA || status.reactions != null) {
|
||||||
if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) {
|
if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) {
|
||||||
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
|
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
|
||||||
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions, true);
|
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions, true);
|
||||||
|
@ -525,6 +528,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
LinearLayoutManager layoutManager
|
LinearLayoutManager layoutManager
|
||||||
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||||
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
|
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
|
||||||
|
} else if (status.reactions != null && status.reactions.size() > 0) {
|
||||||
|
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
|
||||||
|
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.reactions, true, false);
|
||||||
|
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
|
||||||
|
LinearLayoutManager layoutManager
|
||||||
|
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
|
||||||
|
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
|
||||||
} else {
|
} else {
|
||||||
holder.binding.layoutReactions.getRoot().setVisibility(View.GONE);
|
holder.binding.layoutReactions.getRoot().setVisibility(View.GONE);
|
||||||
holder.binding.layoutReactions.reactionsView.setAdapter(null);
|
holder.binding.layoutReactions.reactionsView.setAdapter(null);
|
||||||
|
@ -537,33 +547,57 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
}).setOnEmojiClickListener((emoji, imageView) -> {
|
}).setOnEmojiClickListener((emoji, imageView) -> {
|
||||||
String emojiStr = imageView.getUnicode();
|
String emojiStr = imageView.getUnicode();
|
||||||
boolean alreadyAdded = false;
|
boolean alreadyAdded = false;
|
||||||
if (status.pleroma == null || status.pleroma.emoji_reactions == null) {
|
if (status.pleroma != null && status.pleroma.emoji_reactions != null) {
|
||||||
return;
|
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
||||||
}
|
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
||||||
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
alreadyAdded = true;
|
||||||
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
reaction.count = (reaction.count - 1);
|
||||||
alreadyAdded = true;
|
if (reaction.count == 0) {
|
||||||
reaction.count = (reaction.count - 1);
|
status.pleroma.emoji_reactions.remove(reaction);
|
||||||
if (reaction.count == 0) {
|
}
|
||||||
status.pleroma.emoji_reactions.remove(reaction);
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if (!alreadyAdded) {
|
||||||
if (!alreadyAdded) {
|
Reaction reaction = new Reaction();
|
||||||
Reaction reaction = new Reaction();
|
reaction.me = true;
|
||||||
reaction.me = true;
|
reaction.count = 1;
|
||||||
reaction.count = 1;
|
reaction.name = emojiStr;
|
||||||
reaction.name = emojiStr;
|
status.pleroma.emoji_reactions.add(0, reaction);
|
||||||
status.pleroma.emoji_reactions.add(0, reaction);
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
}
|
||||||
}
|
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
||||||
ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
if (alreadyAdded) {
|
||||||
if (alreadyAdded) {
|
actionVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
actionVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
} else {
|
||||||
} else {
|
actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
}
|
||||||
|
} else if (status.reactions != null) {
|
||||||
|
for (Reaction reaction : status.reactions) {
|
||||||
|
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
||||||
|
alreadyAdded = true;
|
||||||
|
reaction.count = (reaction.count - 1);
|
||||||
|
if (reaction.count == 0) {
|
||||||
|
status.reactions.remove(reaction);
|
||||||
|
}
|
||||||
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
Reaction reaction = new Reaction();
|
||||||
|
reaction.me = true;
|
||||||
|
reaction.count = 1;
|
||||||
|
reaction.name = emojiStr;
|
||||||
|
status.reactions.add(0, reaction);
|
||||||
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
}
|
||||||
|
if (alreadyAdded) {
|
||||||
|
statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
|
} else {
|
||||||
|
statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.build(holder.binding.layoutReactions.fakeEdittext);
|
.build(holder.binding.layoutReactions.fakeEdittext);
|
||||||
|
@ -589,32 +623,61 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
String url = emojis.get(BaseMainActivity.currentInstance).get(index).url;
|
String url = emojis.get(BaseMainActivity.currentInstance).get(index).url;
|
||||||
String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url;
|
String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url;
|
||||||
boolean alreadyAdded = false;
|
boolean alreadyAdded = false;
|
||||||
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
if (status.pleroma != null && status.pleroma.emoji_reactions != null) {
|
||||||
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
for (Reaction reaction : status.pleroma.emoji_reactions) {
|
||||||
alreadyAdded = true;
|
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
||||||
reaction.count = (reaction.count - 1);
|
alreadyAdded = true;
|
||||||
if (reaction.count == 0) {
|
reaction.count = (reaction.count - 1);
|
||||||
status.pleroma.emoji_reactions.remove(reaction);
|
if (reaction.count == 0) {
|
||||||
|
status.pleroma.emoji_reactions.remove(reaction);
|
||||||
|
}
|
||||||
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if (!alreadyAdded) {
|
||||||
if (!alreadyAdded) {
|
Reaction reaction = new Reaction();
|
||||||
Reaction reaction = new Reaction();
|
reaction.me = true;
|
||||||
reaction.me = true;
|
reaction.count = 1;
|
||||||
reaction.count = 1;
|
reaction.name = emojiStr;
|
||||||
reaction.name = emojiStr;
|
reaction.url = url;
|
||||||
reaction.url = url;
|
reaction.static_url = static_url;
|
||||||
reaction.static_url = static_url;
|
status.pleroma.emoji_reactions.add(0, reaction);
|
||||||
status.pleroma.emoji_reactions.add(0, reaction);
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
}
|
||||||
}
|
ActionsVM actionsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
||||||
ActionsVM actionsVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class);
|
if (alreadyAdded) {
|
||||||
if (alreadyAdded) {
|
actionsVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
actionsVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
} else {
|
||||||
} else {
|
actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
}
|
||||||
|
} else if (status.reactions != null) {
|
||||||
|
for (Reaction reaction : status.reactions) {
|
||||||
|
if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) {
|
||||||
|
alreadyAdded = true;
|
||||||
|
reaction.count = (reaction.count - 1);
|
||||||
|
if (reaction.count == 0) {
|
||||||
|
status.reactions.remove(reaction);
|
||||||
|
}
|
||||||
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!alreadyAdded) {
|
||||||
|
Reaction reaction = new Reaction();
|
||||||
|
reaction.me = true;
|
||||||
|
reaction.count = 1;
|
||||||
|
reaction.name = emojiStr;
|
||||||
|
reaction.url = url;
|
||||||
|
reaction.static_url = static_url;
|
||||||
|
status.reactions.add(0, reaction);
|
||||||
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
}
|
||||||
|
if (alreadyAdded) {
|
||||||
|
statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
|
} else {
|
||||||
|
statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
|
gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp);
|
||||||
|
@ -1067,7 +1130,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
}
|
}
|
||||||
//Button sizes depending of the defined scale
|
//Button sizes depending of the defined scale
|
||||||
float normalSize = Helper.convertDpToPixel(28, context);
|
float normalSize = Helper.convertDpToPixel(28, context);
|
||||||
|
|
||||||
holder.binding.actionButtonReply.getLayoutParams().width = (int) (normalSize * scaleIcon);
|
holder.binding.actionButtonReply.getLayoutParams().width = (int) (normalSize * scaleIcon);
|
||||||
holder.binding.actionButtonReply.getLayoutParams().height = (int) (normalSize * scaleIcon);
|
holder.binding.actionButtonReply.getLayoutParams().height = (int) (normalSize * scaleIcon);
|
||||||
holder.binding.actionButtonReply.requestLayout();
|
holder.binding.actionButtonReply.requestLayout();
|
||||||
|
@ -1080,6 +1142,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
holder.binding.actionButtonFavorite.setImageSize((int) (normalSize * scaleIcon));
|
holder.binding.actionButtonFavorite.setImageSize((int) (normalSize * scaleIcon));
|
||||||
holder.binding.actionButtonBookmark.setImageSize((int) (normalSize * scaleIcon));
|
holder.binding.actionButtonBookmark.setImageSize((int) (normalSize * scaleIcon));
|
||||||
|
|
||||||
|
|
||||||
holder.binding.statusAddCustomEmoji.getLayoutParams().width = (int) (normalSize * scaleIcon);
|
holder.binding.statusAddCustomEmoji.getLayoutParams().width = (int) (normalSize * scaleIcon);
|
||||||
holder.binding.statusAddCustomEmoji.getLayoutParams().height = (int) (normalSize * scaleIcon);
|
holder.binding.statusAddCustomEmoji.getLayoutParams().height = (int) (normalSize * scaleIcon);
|
||||||
holder.binding.statusAddCustomEmoji.requestLayout();
|
holder.binding.statusAddCustomEmoji.requestLayout();
|
||||||
|
@ -2095,44 +2158,65 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.isFetchMore && fetchMoreCallBack != null) {
|
if (status.isFetchMore && fetchMoreCallBack != null) {
|
||||||
DrawerFetchMoreBinding drawerFetchMoreBinding = DrawerFetchMoreBinding.inflate(LayoutInflater.from(context));
|
if (!autofetch) {
|
||||||
if (status.positionFetchMore == Status.PositionFetchMore.BOTTOM) {
|
DrawerFetchMoreBinding drawerFetchMoreBinding = DrawerFetchMoreBinding.inflate(LayoutInflater.from(context));
|
||||||
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
|
if (status.positionFetchMore == Status.PositionFetchMore.BOTTOM) {
|
||||||
holder.binding.fetchMoreContainerTop.setVisibility(View.VISIBLE);
|
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
|
||||||
holder.binding.fetchMoreContainerTop.removeAllViews();
|
holder.binding.fetchMoreContainerTop.setVisibility(View.VISIBLE);
|
||||||
holder.binding.fetchMoreContainerTop.addView(drawerFetchMoreBinding.getRoot());
|
holder.binding.fetchMoreContainerTop.removeAllViews();
|
||||||
} else {
|
holder.binding.fetchMoreContainerTop.addView(drawerFetchMoreBinding.getRoot());
|
||||||
holder.binding.fetchMoreContainerBottom.setVisibility(View.VISIBLE);
|
} else {
|
||||||
holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
|
holder.binding.fetchMoreContainerBottom.setVisibility(View.VISIBLE);
|
||||||
holder.binding.fetchMoreContainerBottom.removeAllViews();
|
holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
|
||||||
holder.binding.fetchMoreContainerBottom.addView(drawerFetchMoreBinding.getRoot());
|
holder.binding.fetchMoreContainerBottom.removeAllViews();
|
||||||
}
|
holder.binding.fetchMoreContainerBottom.addView(drawerFetchMoreBinding.getRoot());
|
||||||
drawerFetchMoreBinding.fetchMoreMin.setOnClickListener(v -> {
|
}
|
||||||
status.isFetchMore = false;
|
drawerFetchMoreBinding.fetchMoreMin.setOnClickListener(v -> {
|
||||||
int position = holder.getBindingAdapterPosition();
|
status.isFetchMore = false;
|
||||||
adapter.notifyItemChanged(position);
|
int position = holder.getBindingAdapterPosition();
|
||||||
if (position < statusList.size() - 1) {
|
adapter.notifyItemChanged(position);
|
||||||
|
if (position < statusList.size() - 1) {
|
||||||
|
String fromId;
|
||||||
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
|
fromId = statusList.get(position + 1).id;
|
||||||
|
} else {
|
||||||
|
fromId = status.id;
|
||||||
|
}
|
||||||
|
fetchMoreCallBack.onClickMinId(fromId, status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
drawerFetchMoreBinding.fetchMoreMax.setOnClickListener(v -> {
|
||||||
|
//We hide the button
|
||||||
|
status.isFetchMore = false;
|
||||||
String fromId;
|
String fromId;
|
||||||
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
fromId = statusList.get(position + 1).id;
|
fromId = statusList.get(holder.getBindingAdapterPosition()).id;
|
||||||
} else {
|
} else {
|
||||||
fromId = status.id;
|
fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
||||||
}
|
}
|
||||||
fetchMoreCallBack.onClickMinId(fromId, status);
|
fetchMoreCallBack.onClickMaxId(fromId, status);
|
||||||
}
|
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
});
|
});
|
||||||
drawerFetchMoreBinding.fetchMoreMax.setOnClickListener(v -> {
|
} else {
|
||||||
//We hide the button
|
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
|
||||||
|
holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
|
||||||
status.isFetchMore = false;
|
status.isFetchMore = false;
|
||||||
String fromId;
|
int position = holder.getBindingAdapterPosition();
|
||||||
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
String statusIdMin = null, statusIdMax;
|
||||||
fromId = statusList.get(holder.getBindingAdapterPosition()).id;
|
if (position < statusList.size() - 1) {
|
||||||
} else {
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
statusIdMin = statusList.get(position + 1).id;
|
||||||
|
} else {
|
||||||
|
statusIdMin = status.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fetchMoreCallBack.onClickMaxId(fromId, status);
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
|
statusIdMax = statusList.get(holder.getBindingAdapterPosition()).id;
|
||||||
});
|
} else {
|
||||||
|
statusIdMax = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
||||||
|
}
|
||||||
|
fetchMoreCallBack.autoFetch(statusIdMin, statusIdMax, status);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
|
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
|
||||||
holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
|
holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
|
||||||
|
@ -2236,6 +2320,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
if ((!fullAttachement || statusToDeal.sensitive) && !singleImage) {
|
if ((!fullAttachement || statusToDeal.sensitive) && !singleImage) {
|
||||||
layoutMediaBinding.count.setText(String.format(Locale.getDefault(), "%d/%d", mediaPosition, statusToDeal.media_attachments.size()));
|
layoutMediaBinding.count.setText(String.format(Locale.getDefault(), "%d/%d", mediaPosition, statusToDeal.media_attachments.size()));
|
||||||
}
|
}
|
||||||
|
if (attachment.description != null && attachment.description.trim().length() > 0) {
|
||||||
|
layoutMediaBinding.media.setContentDescription(attachment.description.trim());
|
||||||
|
}
|
||||||
String finalUrl;
|
String finalUrl;
|
||||||
if (attachment.url == null) {
|
if (attachment.url == null) {
|
||||||
finalUrl = attachment.remote_url;
|
finalUrl = attachment.remote_url;
|
||||||
|
@ -2590,32 +2677,53 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
holder.bindingFilteredHide.dividerCard.setVisibility(View.GONE);
|
holder.bindingFilteredHide.dividerCard.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
if (status.isFetchMore && fetchMoreCallBack != null) {
|
if (status.isFetchMore && fetchMoreCallBack != null) {
|
||||||
holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE);
|
boolean autofetch = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_FETCH_MISSING_MESSAGES), false);
|
||||||
holder.bindingFilteredHide.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> {
|
if (!autofetch) {
|
||||||
status.isFetchMore = false;
|
holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE);
|
||||||
notifyItemChanged(holder.getBindingAdapterPosition());
|
holder.bindingFilteredHide.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> {
|
||||||
if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
|
status.isFetchMore = false;
|
||||||
|
notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
|
if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
|
||||||
|
String fromId;
|
||||||
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
|
fromId = statusList.get(holder.getBindingAdapterPosition() + 1).id;
|
||||||
|
} else {
|
||||||
|
fromId = status.id;
|
||||||
|
}
|
||||||
|
fetchMoreCallBack.onClickMinId(fromId, status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.bindingFilteredHide.layoutFetchMore.fetchMoreMax.setOnClickListener(v -> {
|
||||||
|
//We hide the button
|
||||||
|
status.isFetchMore = false;
|
||||||
|
notifyItemChanged(holder.getBindingAdapterPosition());
|
||||||
String fromId;
|
String fromId;
|
||||||
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
fromId = statusList.get(holder.getBindingAdapterPosition() + 1).id;
|
fromId = statusList.get(holder.getBindingAdapterPosition()).id;
|
||||||
} else {
|
} else {
|
||||||
fromId = status.id;
|
fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
||||||
}
|
}
|
||||||
fetchMoreCallBack.onClickMinId(fromId, status);
|
fetchMoreCallBack.onClickMaxId(fromId, status);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
holder.bindingFilteredHide.layoutFetchMore.fetchMoreMax.setOnClickListener(v -> {
|
} else {
|
||||||
//We hide the button
|
|
||||||
status.isFetchMore = false;
|
status.isFetchMore = false;
|
||||||
String fromId;
|
String minId = null, maxId;
|
||||||
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
|
||||||
fromId = statusList.get(holder.getBindingAdapterPosition()).id;
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
} else {
|
minId = statusList.get(holder.getBindingAdapterPosition() + 1).id;
|
||||||
fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
} else {
|
||||||
|
minId = status.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fetchMoreCallBack.onClickMaxId(fromId, status);
|
if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
|
||||||
notifyItemChanged(holder.getBindingAdapterPosition());
|
maxId = statusList.get(holder.getBindingAdapterPosition()).id;
|
||||||
});
|
} else {
|
||||||
|
maxId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
|
||||||
|
}
|
||||||
|
fetchMoreCallBack.autoFetch(minId, maxId, status);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.GONE);
|
holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -2771,6 +2879,8 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||||
void onClickMinId(String min_id, Status statusToUpdate);
|
void onClickMinId(String min_id, Status statusToUpdate);
|
||||||
|
|
||||||
void onClickMaxId(String max_id, Status statusToUpdate);
|
void onClickMaxId(String max_id, Status statusToUpdate);
|
||||||
|
|
||||||
|
void autoFetch(String min_id, String max_id, Status status);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StatusViewHolder extends RecyclerView.ViewHolder {
|
public static class StatusViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
|
@ -23,9 +23,10 @@ import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.preference.SwitchPreference;
|
import androidx.preference.SwitchPreference;
|
||||||
import androidx.preference.SwitchPreferenceCompat;
|
import androidx.work.Data;
|
||||||
import androidx.work.WorkManager;
|
import androidx.work.WorkManager;
|
||||||
|
|
||||||
|
import app.fedilab.android.BaseMainActivity;
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
import app.fedilab.android.activities.MainActivity;
|
import app.fedilab.android.activities.MainActivity;
|
||||||
import app.fedilab.android.mastodon.helper.Helper;
|
import app.fedilab.android.mastodon.helper.Helper;
|
||||||
|
@ -53,7 +54,7 @@ public class FragmentHomeCacheSettings extends PreferenceFragmentCompat implemen
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||||
SwitchPreferenceCompat SET_FETCH_HOME = findPreference(getString(R.string.SET_FETCH_HOME));
|
SwitchPreference SET_FETCH_HOME = findPreference(getString(R.string.SET_FETCH_HOME));
|
||||||
if (SET_FETCH_HOME != null) {
|
if (SET_FETCH_HOME != null) {
|
||||||
boolean checked = sharedpreferences.getBoolean(getString(R.string.SET_FETCH_HOME) + MainActivity.currentUserID + MainActivity.currentInstance, false);
|
boolean checked = sharedpreferences.getBoolean(getString(R.string.SET_FETCH_HOME) + MainActivity.currentUserID + MainActivity.currentInstance, false);
|
||||||
SET_FETCH_HOME.setChecked(checked);
|
SET_FETCH_HOME.setChecked(checked);
|
||||||
|
@ -69,27 +70,33 @@ public class FragmentHomeCacheSettings extends PreferenceFragmentCompat implemen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
if (getActivity() != null) {
|
||||||
if (key.compareToIgnoreCase(getString(R.string.SET_FETCH_HOME)) == 0) {
|
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
Data inputData = new Data.Builder()
|
||||||
SwitchPreference SET_FETCH_HOME = findPreference(getString(R.string.SET_FETCH_HOME));
|
.putString(Helper.ARG_INSTANCE, BaseMainActivity.currentInstance)
|
||||||
if (SET_FETCH_HOME != null) {
|
.putString(Helper.ARG_USER_ID, BaseMainActivity.currentUserID)
|
||||||
editor.putBoolean(getString(R.string.SET_FETCH_HOME) + MainActivity.currentUserID + MainActivity.currentInstance, SET_FETCH_HOME.isChecked());
|
.build();
|
||||||
editor.commit();
|
if (key.compareToIgnoreCase(getString(R.string.SET_FETCH_HOME)) == 0) {
|
||||||
if (SET_FETCH_HOME.isChecked()) {
|
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||||
FetchHomeWorker.setRepeatHome(requireActivity(), MainActivity.currentAccount);
|
SwitchPreference SET_FETCH_HOME = findPreference(getString(R.string.SET_FETCH_HOME));
|
||||||
} else {
|
if (SET_FETCH_HOME != null) {
|
||||||
WorkManager.getInstance(requireActivity()).cancelAllWorkByTag(Helper.WORKER_REFRESH_HOME + MainActivity.currentUserID + MainActivity.currentInstance);
|
editor.putBoolean(getString(R.string.SET_FETCH_HOME) + MainActivity.currentUserID + MainActivity.currentInstance, SET_FETCH_HOME.isChecked());
|
||||||
|
editor.commit();
|
||||||
|
if (SET_FETCH_HOME.isChecked()) {
|
||||||
|
FetchHomeWorker.setRepeatHome(requireActivity(), MainActivity.currentAccount, inputData);
|
||||||
|
} else {
|
||||||
|
WorkManager.getInstance(requireActivity()).cancelAllWorkByTag(Helper.WORKER_REFRESH_HOME + MainActivity.currentUserID + MainActivity.currentInstance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (key.compareToIgnoreCase(getString(R.string.SET_FETCH_HOME_DELAY_VALUE)) == 0) {
|
||||||
if (key.compareToIgnoreCase(getString(R.string.SET_FETCH_HOME_DELAY_VALUE)) == 0) {
|
ListPreference SET_FETCH_HOME_DELAY_VALUE = findPreference(getString(R.string.SET_FETCH_HOME_DELAY_VALUE));
|
||||||
ListPreference SET_FETCH_HOME_DELAY_VALUE = findPreference(getString(R.string.SET_FETCH_HOME_DELAY_VALUE));
|
if (SET_FETCH_HOME_DELAY_VALUE != null) {
|
||||||
if (SET_FETCH_HOME_DELAY_VALUE != null) {
|
SharedPreferences.Editor editor = sharedpreferences.edit();
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
editor.putString(getString(R.string.SET_FETCH_HOME_DELAY_VALUE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_FETCH_HOME_DELAY_VALUE.getValue());
|
||||||
editor.putString(getString(R.string.SET_FETCH_HOME_DELAY_VALUE) + MainActivity.currentUserID + MainActivity.currentInstance, SET_FETCH_HOME_DELAY_VALUE.getValue());
|
editor.commit();
|
||||||
editor.commit();
|
FetchHomeWorker.setRepeatHome(requireActivity(), MainActivity.currentAccount, inputData);
|
||||||
FetchHomeWorker.setRepeatHome(requireActivity(), MainActivity.currentAccount);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class FragmentSettingsCategories extends PreferenceFragmentCompat {
|
||||||
Preference pref_export_settings = findPreference(getString(R.string.pref_export_settings));
|
Preference pref_export_settings = findPreference(getString(R.string.pref_export_settings));
|
||||||
if (pref_export_settings != null) {
|
if (pref_export_settings != null) {
|
||||||
pref_export_settings.setOnPreferenceClickListener(preference -> {
|
pref_export_settings.setOnPreferenceClickListener(preference -> {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -75,7 +75,7 @@ import es.dmoral.toasty.Toasty;
|
||||||
|
|
||||||
public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.FetchMoreCallBack {
|
public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.FetchMoreCallBack {
|
||||||
|
|
||||||
|
private boolean scrollingUp;
|
||||||
private static final int PRELOAD_AHEAD_ITEMS = 10;
|
private static final int PRELOAD_AHEAD_ITEMS = 10;
|
||||||
public UpdateCounters update;
|
public UpdateCounters update;
|
||||||
private FragmentPaginationBinding binding;
|
private FragmentPaginationBinding binding;
|
||||||
|
@ -506,9 +506,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
} else if (update != null && insertedStatus == 0 && direction == DIRECTION.REFRESH) {
|
} else if (update != null && insertedStatus == 0 && direction == DIRECTION.REFRESH) {
|
||||||
update.onUpdate(0, timelineType, slug);
|
update.onUpdate(0, timelineType, slug);
|
||||||
}
|
}
|
||||||
|
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||||
if (direction == DIRECTION.TOP && fetchingMissing) {
|
if (direction == DIRECTION.TOP && fetchingMissing) {
|
||||||
int position = getAbsolutePosition(fetched_statuses.statuses.get(fetched_statuses.statuses.size() - 1));
|
int position = getAbsolutePosition(fetched_statuses.statuses.get(fetched_statuses.statuses.size() - 1));
|
||||||
|
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
binding.recyclerView.scrollToPosition(position + 1);
|
binding.recyclerView.scrollToPosition(position + 1);
|
||||||
}
|
}
|
||||||
|
@ -656,7 +656,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||||
|
scrollingUp = dy < 0;
|
||||||
if (requireActivity() instanceof BaseMainActivity) {
|
if (requireActivity() instanceof BaseMainActivity) {
|
||||||
if (dy < 0 && !((BaseMainActivity) requireActivity()).getFloatingVisibility())
|
if (dy < 0 && !((BaseMainActivity) requireActivity()).getFloatingVisibility())
|
||||||
((BaseMainActivity) requireActivity()).manageFloatingButton(true);
|
((BaseMainActivity) requireActivity()).manageFloatingButton(true);
|
||||||
|
@ -1228,6 +1228,17 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
route(DIRECTION.BOTTOM, true, statusToUpdate);
|
route(DIRECTION.BOTTOM, true, statusToUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoFetch(String min_id, String max_id, Status statusToUpdate) {
|
||||||
|
if (scrollingUp) {
|
||||||
|
min_id_fetch_more = min_id;
|
||||||
|
route(DIRECTION.TOP, true, statusToUpdate);
|
||||||
|
} else {
|
||||||
|
max_id_fetch_more = max_id;
|
||||||
|
route(DIRECTION.BOTTOM, true, statusToUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum DIRECTION {
|
public enum DIRECTION {
|
||||||
TOP,
|
TOP,
|
||||||
BOTTOM,
|
BOTTOM,
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import app.fedilab.android.R;
|
import app.fedilab.android.R;
|
||||||
|
import app.fedilab.android.mastodon.client.endpoints.MastodonAnnouncementsService;
|
||||||
import app.fedilab.android.mastodon.client.endpoints.MastodonStatusesService;
|
import app.fedilab.android.mastodon.client.endpoints.MastodonStatusesService;
|
||||||
import app.fedilab.android.mastodon.client.entities.api.Account;
|
import app.fedilab.android.mastodon.client.entities.api.Account;
|
||||||
import app.fedilab.android.mastodon.client.entities.api.Accounts;
|
import app.fedilab.android.mastodon.client.entities.api.Accounts;
|
||||||
|
@ -1292,4 +1293,48 @@ public class StatusesVM extends AndroidViewModel {
|
||||||
}).start();
|
}).start();
|
||||||
return voidMutableLiveData;
|
return voidMutableLiveData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React to a status with an emoji.
|
||||||
|
*
|
||||||
|
* @param instance Instance domain of the active account
|
||||||
|
* @param token Access token of the active account
|
||||||
|
* @param id Local ID of an announcement
|
||||||
|
* @param name Unicode emoji, or shortcode of custom emoji
|
||||||
|
*/
|
||||||
|
public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
|
||||||
|
MastodonStatusesService mastodonStatusesService = init(instance);
|
||||||
|
new Thread(() -> {
|
||||||
|
Call<Void> addReactionCall = mastodonStatusesService.addReaction(token, id, name);
|
||||||
|
if (addReactionCall != null) {
|
||||||
|
try {
|
||||||
|
addReactionCall.execute();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo a react emoji to a status.
|
||||||
|
*
|
||||||
|
* @param instance Instance domain of the active account
|
||||||
|
* @param token Access token of the active account
|
||||||
|
* @param id Local ID of an announcement
|
||||||
|
* @param name Unicode emoji, or shortcode of custom emoji
|
||||||
|
*/
|
||||||
|
public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) {
|
||||||
|
MastodonStatusesService mastodonStatusesService = init(instance);
|
||||||
|
new Thread(() -> {
|
||||||
|
Call<Void> removeReactionCall = mastodonStatusesService.removeReaction(token, id, name);
|
||||||
|
if (removeReactionCall != null) {
|
||||||
|
try {
|
||||||
|
removeReactionCall.execute();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -821,7 +821,7 @@ public class Helper {
|
||||||
|
|
||||||
public static void requestPermissionAndProceed(Activity activity, PermissionGranted permissionGranted) {
|
public static void requestPermissionAndProceed(Activity activity, PermissionGranted permissionGranted) {
|
||||||
if (Build.VERSION.SDK_INT >= 23) {
|
if (Build.VERSION.SDK_INT >= 23) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, app.fedilab.android.mastodon.helper.Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
|
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, app.fedilab.android.mastodon.helper.Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -93,6 +93,15 @@ public class Sqlite extends SQLiteOpenHelper {
|
||||||
public static final String COL_ABOUT = "ABOUT";
|
public static final String COL_ABOUT = "ABOUT";
|
||||||
public static final String COL_USER_INSTANCE = "USER_INSTANCE";
|
public static final String COL_USER_INSTANCE = "USER_INSTANCE";
|
||||||
|
|
||||||
|
//Home fetch logs
|
||||||
|
public static final String TABLE_HOME_FETCH_LOGS = "TABLE_HOME_FETCH_LOGS";
|
||||||
|
public static final String COL_INSERTED = "INSERTED";
|
||||||
|
public static final String COL_UPDATED = "UPDATED";
|
||||||
|
public static final String COL_FAILED = "FAILED";
|
||||||
|
public static final String COL_FREQUENCY = "FREQUENCY";
|
||||||
|
public static final String COL_FETCHED_COUNT = "FETCHED_COUNT";
|
||||||
|
|
||||||
|
|
||||||
private static final String CREATE_TABLE_USER_ACCOUNT = "CREATE TABLE " + TABLE_USER_ACCOUNT + " ("
|
private static final String CREATE_TABLE_USER_ACCOUNT = "CREATE TABLE " + TABLE_USER_ACCOUNT + " ("
|
||||||
+ COL_USER_ID + " TEXT NOT NULL, "
|
+ COL_USER_ID + " TEXT NOT NULL, "
|
||||||
+ COL_INSTANCE + " TEXT NOT NULL, "
|
+ COL_INSTANCE + " TEXT NOT NULL, "
|
||||||
|
@ -192,8 +201,8 @@ public class Sqlite extends SQLiteOpenHelper {
|
||||||
+ COL_USER_ID + " TEXT NOT NULL, "
|
+ COL_USER_ID + " TEXT NOT NULL, "
|
||||||
+ COL_TYPE + " TEXT NOT NULL, "
|
+ COL_TYPE + " TEXT NOT NULL, "
|
||||||
+ COL_MUTED_ACCOUNTS + " TEXT)";
|
+ COL_MUTED_ACCOUNTS + " TEXT)";
|
||||||
public static SQLiteDatabase db;
|
|
||||||
private static Sqlite sInstance;
|
|
||||||
private final String CREATE_TABLE_STORED_INSTANCES = "CREATE TABLE "
|
private final String CREATE_TABLE_STORED_INSTANCES = "CREATE TABLE "
|
||||||
+ TABLE_BOOKMARKED_INSTANCES + "("
|
+ TABLE_BOOKMARKED_INSTANCES + "("
|
||||||
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
+ COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||||
|
@ -202,6 +211,11 @@ public class Sqlite extends SQLiteOpenHelper {
|
||||||
+ COL_ABOUT + " TEXT NOT NULL, "
|
+ COL_ABOUT + " TEXT NOT NULL, "
|
||||||
+ COL_USER_INSTANCE + " TEXT NOT NULL)";
|
+ COL_USER_INSTANCE + " TEXT NOT NULL)";
|
||||||
|
|
||||||
|
|
||||||
|
public static SQLiteDatabase db;
|
||||||
|
private static Sqlite sInstance;
|
||||||
|
|
||||||
|
|
||||||
public Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
|
public Sqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
|
||||||
super(context, name, factory, version);
|
super(context, name, factory, version);
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,7 +237,7 @@ public class FragmentLoginMain extends Fragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (itemId == R.id.action_import_data) {
|
} else if (itemId == R.id.action_import_data) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||||
} else {
|
} else {
|
||||||
proceed();
|
proceed();
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:autoMirrored="true"
|
android:autoMirrored="true"
|
||||||
android:tint="?attr/colorControlNormal"
|
android:tint="?colorControlNormal"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/white"
|
||||||
android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z" />
|
android:pathData="M14.91,6.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L8.91,11.3c-0.39,0.39 -0.39,1.02 0,1.41l4.59,4.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L11.03,12l3.88,-3.88c0.38,-0.39 0.38,-1.03 0,-1.41z" />
|
||||||
</vector>
|
</vector>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:autoMirrored="true"
|
||||||
|
android:tint="?colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M9.31,6.71c-0.39,0.39 -0.39,1.02 0,1.41L13.19,12l-3.88,3.88c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0l4.59,-4.59c0.39,-0.39 0.39,-1.02 0,-1.41L10.72,6.7c-0.38,-0.38 -1.02,-0.38 -1.41,0.01z" />
|
||||||
|
</vector>
|
|
@ -21,7 +21,7 @@
|
||||||
android:text="@string/bookmarks"
|
android:text="@string/bookmarks"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
android:text="@string/muted_menu"
|
android:text="@string/muted_menu"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
android:text="@string/muted_menu_home"
|
android:text="@string/muted_menu_home"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
android:text="@string/blocked_menu"
|
android:text="@string/blocked_menu"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
android:text="@string/favourite"
|
android:text="@string/favourite"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
android:text="@string/blocked_domains"
|
android:text="@string/blocked_domains"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
android:textColor="?attr/colorAccent"
|
android:textColor="?attr/colorAccent"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end"
|
app:iconGravity="end"
|
||||||
app:iconTint="?attr/colorAccent"
|
app:iconTint="?attr/colorAccent"
|
||||||
app:strokeColor="?attr/colorAccent" />
|
app:strokeColor="?attr/colorAccent" />
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
android:paddingVertical="12dp"
|
android:paddingVertical="12dp"
|
||||||
android:text="@string/reports"
|
android:text="@string/reports"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end" />
|
app:iconGravity="end" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
android:paddingVertical="12dp"
|
android:paddingVertical="12dp"
|
||||||
android:text="@string/accounts"
|
android:text="@string/accounts"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end" />
|
app:iconGravity="end" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
android:paddingVertical="12dp"
|
android:paddingVertical="12dp"
|
||||||
android:text="@string/blocked_domains"
|
android:text="@string/blocked_domains"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end" />
|
app:iconGravity="end" />
|
||||||
|
|
||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
-->
|
-->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<DatePicker
|
<DatePicker
|
||||||
android:id="@+id/date_picker"
|
android:id="@+id/date_picker"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:calendarViewShown="true"
|
android:datePickerMode="calendar"
|
||||||
android:spinnersShown="false"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
@ -47,67 +47,58 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/date_time_cancel"
|
android:id="@+id/date_time_cancel"
|
||||||
|
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_marginVertical="12dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
android:text="@string/cancel"
|
android:text="@string/cancel"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/date_time_previous"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/date_time_previous"
|
android:id="@+id/date_time_previous"
|
||||||
style="@style/Widget.Material3.Button.Icon"
|
style="@style/Widget.Material3.Button.IconButton.Outlined"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="12dp"
|
||||||
android:contentDescription="@string/previous"
|
android:contentDescription="@string/previous"
|
||||||
android:padding="0dp"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:icon="@drawable/ic_baseline_skip_previous_24"
|
app:icon="@drawable/ic_navigate_before"
|
||||||
app:iconGravity="textStart"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/date_time_next"
|
app:layout_constraintEnd_toStartOf="@id/date_time_next"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/date_time_cancel"
|
app:layout_constraintStart_toEndOf="@id/date_time_cancel"
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/date_time_next"
|
android:id="@+id/date_time_next"
|
||||||
style="@style/Widget.Material3.Button.Icon"
|
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_margin="12dp"
|
||||||
android:contentDescription="@string/next"
|
android:contentDescription="@string/next"
|
||||||
android:padding="0dp"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:icon="@drawable/ic_baseline_skip_next_24"
|
|
||||||
app:iconGravity="textStart"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/date_time_set"
|
app:layout_constraintEnd_toStartOf="@id/date_time_set"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/date_time_previous"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/date_time_set"
|
android:id="@+id/date_time_set"
|
||||||
style="@style/Widget.Material3.Button.Icon"
|
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||||
android:layout_width="40dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="40dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dp"
|
android:layout_marginVertical="12dp"
|
||||||
android:contentDescription="@string/validate"
|
android:layout_marginEnd="12dp"
|
||||||
android:padding="0dp"
|
android:contentDescription="@string/schedule"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:icon="@drawable/ic_baseline_check_24"
|
app:icon="@drawable/ic_baseline_check_24"
|
||||||
app:iconGravity="textStart"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom"
|
||||||
app:layout_constraintStart_toEndOf="@id/date_time_next"
|
tools:visibility="visible" />
|
||||||
app:layout_constraintTop_toBottomOf="@id/barrier_date_time_bottom" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -8,5 +8,5 @@
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:paddingVertical="12dp"
|
android:paddingVertical="12dp"
|
||||||
android:textAlignment="textStart"
|
android:textAlignment="textStart"
|
||||||
app:icon="@drawable/ic_baseline_navigate_next_24"
|
app:icon="@drawable/ic_navigate_next"
|
||||||
app:iconGravity="end" />
|
app:iconGravity="end" />
|
|
@ -630,10 +630,10 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_bias="0.0">
|
app:layout_constraintVertical_bias="0.0">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/action_button_reply"
|
android:id="@+id/action_button_reply"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -671,10 +671,10 @@
|
||||||
app:primaryColor="@color/boost_icon"
|
app:primaryColor="@color/boost_icon"
|
||||||
app:secondaryColor="@color/boost_icon" />
|
app:secondaryColor="@color/boost_icon" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/action_button_quote"
|
android:id="@+id/action_button_quote"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -726,10 +726,10 @@
|
||||||
sparkbutton:iconSize="28dp" />
|
sparkbutton:iconSize="28dp" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/action_button_translate"
|
android:id="@+id/action_button_translate"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -745,10 +745,10 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/action_button_maths"
|
android:id="@+id/action_button_maths"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -763,10 +763,10 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/status_add_custom_emoji"
|
android:id="@+id/status_add_custom_emoji"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -781,10 +781,10 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/status_emoji"
|
android:id="@+id/status_emoji"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
@ -799,10 +799,10 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/action_button_more"
|
android:id="@+id/action_button_more"
|
||||||
android:layout_width="48dp"
|
android:layout_width="28dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="28dp"
|
||||||
android:layout_gravity="center|end"
|
android:layout_gravity="center|end"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@color/transparent"
|
android:background="@color/transparent"
|
||||||
|
|
|
@ -41,14 +41,6 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<de.timfreiheit.mathjax.android.MathJaxView
|
|
||||||
android:id="@+id/laTexView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
app:automaticLinebreaks="true"
|
|
||||||
app:input="TeX"
|
|
||||||
app:output="SVG" />
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="fetch_home_every">Fetch Home every</string>
|
|
||||||
<string name="type_of_home_delay_title">Home fetch time</string>
|
|
||||||
<string name="set_fetch_home">Automatically fetch home messages</string>
|
|
||||||
<string name="home_cache">Home cache</string>
|
|
||||||
</resources>
|
</resources>
|
|
@ -999,4 +999,11 @@
|
||||||
<string name="following">Sledující</string>
|
<string name="following">Sledující</string>
|
||||||
<string name="toast_error_peertube_not_supported">Vaše instance Peertube je příliš stará a nemůže být aplikací podporována.</string>
|
<string name="toast_error_peertube_not_supported">Vaše instance Peertube je příliš stará a nemůže být aplikací podporována.</string>
|
||||||
<string name="compose_shortcut_short_label1">Vytváření</string>
|
<string name="compose_shortcut_short_label1">Vytváření</string>
|
||||||
|
<string name="otp_message">Token pro dvoufaktorovou autentizaci</string>
|
||||||
|
<string name="fetch_home_every">Načíst Domov každých</string>
|
||||||
|
<string name="home_cache">Cache pro Domov</string>
|
||||||
|
<string name="type_of_home_delay_title">Čas načtení Domova</string>
|
||||||
|
<string name="set_fetch_home">Automaticky načítat domácí zprávy</string>
|
||||||
|
<string name="fetch_home_messages">Načíst domácí zprávy</string>
|
||||||
|
<string name="auto_fetch_missing">Automaticky načítat chybějící zprávy</string>
|
||||||
</resources>
|
</resources>
|
|
@ -989,4 +989,11 @@
|
||||||
<string name="about_peertube">\"PeerTube ist ein Tool zum Teilen von Online-Videos, das von Framasoft entwickelt wurde, einer französischen Non-Profit-Organisation....PeerTube ermöglicht es, Plattformen miteinander zu verbinden und so ein großes Netzwerk von Plattformen zu schaffen, die sowohl autonom als auch miteinander verbunden sind.\"</string>
|
<string name="about_peertube">\"PeerTube ist ein Tool zum Teilen von Online-Videos, das von Framasoft entwickelt wurde, einer französischen Non-Profit-Organisation....PeerTube ermöglicht es, Plattformen miteinander zu verbinden und so ein großes Netzwerk von Plattformen zu schaffen, die sowohl autonom als auch miteinander verbunden sind.\"</string>
|
||||||
<string name="compose_shortcut_short_label1">Entwerfen</string>
|
<string name="compose_shortcut_short_label1">Entwerfen</string>
|
||||||
<string name="toast_error_peertube_not_supported">Ihr Peertube ist zu alt und wird von der App nicht unterstützt.</string>
|
<string name="toast_error_peertube_not_supported">Ihr Peertube ist zu alt und wird von der App nicht unterstützt.</string>
|
||||||
|
<string name="set_fetch_home">Automatisch Beiträge der Startseite abrufen</string>
|
||||||
|
<string name="type_of_home_delay_title">Aktualisierungsintervall der Startseite</string>
|
||||||
|
<string name="auto_fetch_missing">Automatisch fehlende Beiträge der Startseite abrufen</string>
|
||||||
|
<string name="fetch_home_every">Startseite aktualisieren alle</string>
|
||||||
|
<string name="otp_message">Zwei-Faktor-Authentifizierungstoken</string>
|
||||||
|
<string name="home_cache">Cache der Startseite</string>
|
||||||
|
<string name="fetch_home_messages">Beiträge auf der Startseite abrufen</string>
|
||||||
</resources>
|
</resources>
|
|
@ -983,4 +983,11 @@
|
||||||
<string name="about_peertube">\"PeerTube é unha ferramenta desenvolta por Framasoft (organización sen ánimo de lucro) para compartir vídeos en internet. PeerTube permite que unhas plataformas se conecten con outras, creando unha gran rede na que as partes son autónomas e están interconectadas.\"</string>
|
<string name="about_peertube">\"PeerTube é unha ferramenta desenvolta por Framasoft (organización sen ánimo de lucro) para compartir vídeos en internet. PeerTube permite que unhas plataformas se conecten con outras, creando unha gran rede na que as partes son autónomas e están interconectadas.\"</string>
|
||||||
<string name="compose_shortcut_short_label1">Redactar</string>
|
<string name="compose_shortcut_short_label1">Redactar</string>
|
||||||
<string name="toast_error_peertube_not_supported">O teu Peertube é demasiado antigo e non pode usarse coa app.</string>
|
<string name="toast_error_peertube_not_supported">O teu Peertube é demasiado antigo e non pode usarse coa app.</string>
|
||||||
|
<string name="otp_message">Token do segundo factor de autenticación</string>
|
||||||
|
<string name="fetch_home_every">Actualizar Inicio cada</string>
|
||||||
|
<string name="set_fetch_home">Actualizar automáticamente mensaxes de inicio</string>
|
||||||
|
<string name="type_of_home_delay_title">Intervalo de actualización</string>
|
||||||
|
<string name="home_cache">Caché do Inicio</string>
|
||||||
|
<string name="fetch_home_messages">Obter mensaxes</string>
|
||||||
|
<string name="auto_fetch_missing">Obter automáticamente as mensaxes que faltan</string>
|
||||||
</resources>
|
</resources>
|
|
@ -906,4 +906,6 @@
|
||||||
<string name="set_maths_support">Escrever fórmula</string>
|
<string name="set_maths_support">Escrever fórmula</string>
|
||||||
<string name="show_privates">Mostrar mensagens diretas</string>
|
<string name="show_privates">Mostrar mensagens diretas</string>
|
||||||
<string name="about_peertube">\"PeerTube é uma ferramenta para compartilhar vídeos online desenvolvida pela Framasoft, uma organização francesa sem fins lucrativos.…PeerTube permite que as plataformas sejam conectadas umas às outras, criando uma grande rede de plataformas autônomas e interconectadas.\"</string>
|
<string name="about_peertube">\"PeerTube é uma ferramenta para compartilhar vídeos online desenvolvida pela Framasoft, uma organização francesa sem fins lucrativos.…PeerTube permite que as plataformas sejam conectadas umas às outras, criando uma grande rede de plataformas autônomas e interconectadas.\"</string>
|
||||||
|
<string name="toast_error_peertube_not_supported">Seu Peertube é muito antigo e não é suportado pelo aplicativo.</string>
|
||||||
|
<string name="otp_message">Token de autenticação de dois fatores</string>
|
||||||
</resources>
|
</resources>
|
|
@ -977,4 +977,14 @@
|
||||||
<string name="filter_languages">Filtra is limbas</string>
|
<string name="filter_languages">Filtra is limbas</string>
|
||||||
<string name="translate_in">Borta in</string>
|
<string name="translate_in">Borta in</string>
|
||||||
<string name="proxy_protocol_socks">SOCKS</string>
|
<string name="proxy_protocol_socks">SOCKS</string>
|
||||||
|
<string name="about_peertube">\"PeerTube est unu traste pro cumpartzire vìdeos in lìnia isvilupadu dae Framasoft, un\'organizatzione frantzesa chene punna de lucru.…PeerTube permitit a sas prataformas de si collegare s\'una cun s\'àtera, creende una rete manna de prataformas chi sunt siat autònomas siat connessas.\"</string>
|
||||||
|
<string name="compose_shortcut_short_label1">Cumpone</string>
|
||||||
|
<string name="toast_error_peertube_not_supported">Su PeerTube tuo est tropu betzu e non podet èssere suportadu dae s\'aplicatzione.</string>
|
||||||
|
<string name="otp_message">Getone de autenticatzione a duos fatores</string>
|
||||||
|
<string name="fetch_home_messages">Recùpera is messàgios de sa lìnia printzipale</string>
|
||||||
|
<string name="auto_fetch_missing">Recùpera in automàticu is messàgios chi mancant</string>
|
||||||
|
<string name="fetch_home_every">Recùpera sa lìnia printzipale cada</string>
|
||||||
|
<string name="home_cache">Memòria temporànea lìnia printzipale</string>
|
||||||
|
<string name="type_of_home_delay_title">Tempus de recùperu de sa lìnia printzipale</string>
|
||||||
|
<string name="set_fetch_home">Recùpera in automàticu is messàgios de sa lìnia printzipale</string>
|
||||||
</resources>
|
</resources>
|
|
@ -987,4 +987,11 @@
|
||||||
<string name="about_peertube">\"PeerTube kar amacı gütmeyen bir Fransız kuruluşu olan Framasoft tarafından geliştirilen bir çevrim içi video paylaşım aracıdır.…PeerTube platformların birbirine bağlanmasına olanak tanıyarak hem özerk hem de birbirine bağlı büyük bir platform ağı oluşturur.\"</string>
|
<string name="about_peertube">\"PeerTube kar amacı gütmeyen bir Fransız kuruluşu olan Framasoft tarafından geliştirilen bir çevrim içi video paylaşım aracıdır.…PeerTube platformların birbirine bağlanmasına olanak tanıyarak hem özerk hem de birbirine bağlı büyük bir platform ağı oluşturur.\"</string>
|
||||||
<string name="toast_error_peertube_not_supported">Peertube sürümünüz çok eski ve uygulama tarafından desteklenemiyor.</string>
|
<string name="toast_error_peertube_not_supported">Peertube sürümünüz çok eski ve uygulama tarafından desteklenemiyor.</string>
|
||||||
<string name="compose_shortcut_short_label1">Oluştur</string>
|
<string name="compose_shortcut_short_label1">Oluştur</string>
|
||||||
|
<string name="otp_message">İki aşamalı kimlik doğrulama belirteci</string>
|
||||||
|
<string name="fetch_home_every">Ana sayfayı alma sıklığı</string>
|
||||||
|
<string name="type_of_home_delay_title">Ana sayfa alma zamanı</string>
|
||||||
|
<string name="set_fetch_home">Ana sayfa mesajlarını otomatik olarak al</string>
|
||||||
|
<string name="home_cache">Ana sayfa önbelleği</string>
|
||||||
|
<string name="auto_fetch_missing">Eksik mesajları otomatik olarak al</string>
|
||||||
|
<string name="fetch_home_messages">Ana sayfa mesajlarını al</string>
|
||||||
</resources>
|
</resources>
|
|
@ -581,4 +581,21 @@
|
||||||
<string name="no_distributors_found">No distributors found!</string>
|
<string name="no_distributors_found">No distributors found!</string>
|
||||||
<string name="no_distributors_explanation">You need a distributor for receiving push notifications.\nYou will find more details at %1$s.\n\nYou can also disable push notifications in settings for ignoring that message.</string>
|
<string name="no_distributors_explanation">You need a distributor for receiving push notifications.\nYou will find more details at %1$s.\n\nYou can also disable push notifications in settings for ignoring that message.</string>
|
||||||
<string name="select_distributors">Select a distributor</string>
|
<string name="select_distributors">Select a distributor</string>
|
||||||
|
<string name="account_approved">Обліковий запис затверджено</string>
|
||||||
|
<string name="admin_domainblock_domain">Блокування домену не перешкоджатиме створенню облікових записів у базі даних, але заднім числом автоматично застосовуватиме певні методи модерації до цих облікових записів.</string>
|
||||||
|
<string name="aggregate_notifications_summary">При ввімкненні застосунок згортає пов\'язані з ним сповіщення</string>
|
||||||
|
<string name="restart_the_app_theme">Для того, щоб зміни набули чинності, потрібно перезапустити застосунок.</string>
|
||||||
|
<string name="toast_token">Застосунок не зміг отримати токен</string>
|
||||||
|
<string name="restart_the_app">Перезапустити застосунок\?</string>
|
||||||
|
<string name="toast_error_fetch_message">Застосунок не знайшов віддалене повідомлення.</string>
|
||||||
|
<string name="set_extand_extra_features">Увімкнувши цю опцію, застосунок відображатиме додаткові функції. Ця функція передбачена для соціальних програм, таких як Pleroma, Akkoma або Glitch Social</string>
|
||||||
|
<string name="change_logo_description">Змінити логотип застосунку на вашому пристрої</string>
|
||||||
|
<string name="toast_error_peertube_not_supported">Ваш Peertube застарілий і не підтримується застосунком.</string>
|
||||||
|
<string name="my_app">Мій застосунок</string>
|
||||||
|
<string name="set_single_topbar">Якщо увімкнено, у застосунку буде лише одна смуга для часових шкал</string>
|
||||||
|
<string name="set_use_cache_indication">Часові шкали будуть кешуватися, щоб застосунок працював швидше.</string>
|
||||||
|
<string name="toast_error_add_to_list">Застосунку не вдалося додати обліковий запис до списку!</string>
|
||||||
|
<string name="toast_fetch_error">Застосунок не може знайти віддалені дані!</string>
|
||||||
|
<string name="set_remote_profile">Застосунок відображатиме профілі у відкритому доступі, щоб отримувати всі повідомлення. Взаємодія потребуватиме додаткового кроку для об\'єднання повідомлень.</string>
|
||||||
|
<string name="set_disable_release_notes_indication">Коли публікується нова версія, ви не отримаєте сповіщення в застосунку.</string>
|
||||||
</resources>
|
</resources>
|
|
@ -854,7 +854,7 @@
|
||||||
<string name="toast_unpin">消息不再置顶!</string>
|
<string name="toast_unpin">消息不再置顶!</string>
|
||||||
<string name="toast_pin">消息已置顶</string>
|
<string name="toast_pin">消息已置顶</string>
|
||||||
<string name="staff">职员</string>
|
<string name="staff">职员</string>
|
||||||
<string name="approved">得到正式认可的</string>
|
<string name="approved">已批准</string>
|
||||||
<string name="approve">批准</string>
|
<string name="approve">批准</string>
|
||||||
<string name="set_unlisted_replies">不公开回复</string>
|
<string name="set_unlisted_replies">不公开回复</string>
|
||||||
<string name="max_indentation_thread">同主题帖子中最大缩进</string>
|
<string name="max_indentation_thread">同主题帖子中最大缩进</string>
|
||||||
|
@ -987,4 +987,11 @@
|
||||||
<string name="toast_error_peertube_not_supported">您的 Peertube 太旧,应用程序不支持。</string>
|
<string name="toast_error_peertube_not_supported">您的 Peertube 太旧,应用程序不支持。</string>
|
||||||
<string name="customize_timelines">自定义时间线</string>
|
<string name="customize_timelines">自定义时间线</string>
|
||||||
<string name="also_followed_by">关注者:</string>
|
<string name="also_followed_by">关注者:</string>
|
||||||
|
<string name="otp_message">双因素身份验证令牌</string>
|
||||||
|
<string name="set_fetch_home">自动获取主页消息</string>
|
||||||
|
<string name="home_cache">主页缓存</string>
|
||||||
|
<string name="fetch_home_messages">获取主页消息</string>
|
||||||
|
<string name="type_of_home_delay_title">主页获取延迟</string>
|
||||||
|
<string name="fetch_home_every">获取主页消息每隔</string>
|
||||||
|
<string name="auto_fetch_missing">自动获取缺失的消息</string>
|
||||||
</resources>
|
</resources>
|
|
@ -1390,6 +1390,8 @@
|
||||||
|
|
||||||
<string name="SET_DISABLE_ANIMATED_EMOJI" translatable="false">SET_DISABLE_ANIMATED_EMOJI</string>
|
<string name="SET_DISABLE_ANIMATED_EMOJI" translatable="false">SET_DISABLE_ANIMATED_EMOJI</string>
|
||||||
<string name="SET_CAPITALIZE" translatable="false">SET_CAPITALIZE</string>
|
<string name="SET_CAPITALIZE" translatable="false">SET_CAPITALIZE</string>
|
||||||
|
<string name="SET_MENTIONS_AT_TOP" translatable="false">SET_MENTIONS_AT_TOP</string>
|
||||||
|
|
||||||
<string name="SET_THEME_BASE" translatable="false">SET_THEME_BASE</string>
|
<string name="SET_THEME_BASE" translatable="false">SET_THEME_BASE</string>
|
||||||
<string name="SET_DYNAMICCOLOR" translatable="false">SET_DYNAMICCOLOR</string>
|
<string name="SET_DYNAMICCOLOR" translatable="false">SET_DYNAMICCOLOR</string>
|
||||||
<string name="SET_CARDVIEW" translatable="false">SET_CARDVIEW</string>
|
<string name="SET_CARDVIEW" translatable="false">SET_CARDVIEW</string>
|
||||||
|
@ -1476,6 +1478,7 @@
|
||||||
<string name="SET_INNER_MARKER" translatable="false">SET_INNER_MARKER</string>
|
<string name="SET_INNER_MARKER" translatable="false">SET_INNER_MARKER</string>
|
||||||
<string name="SET_NOTIF_SILENT" translatable="false">SET_NOTIF_SILENT</string>
|
<string name="SET_NOTIF_SILENT" translatable="false">SET_NOTIF_SILENT</string>
|
||||||
<string name="SET_REMEMBER_POSITION" translatable="false">SET_REMEMBER_POSITION</string>
|
<string name="SET_REMEMBER_POSITION" translatable="false">SET_REMEMBER_POSITION</string>
|
||||||
|
<string name="SET_AUTO_FETCH_MISSING_MESSAGES" translatable="false">SET_AUTO_FETCH_MISSING_MESSAGES</string>
|
||||||
<string name="SET_EXPAND_CW" translatable="false">SET_EXPAND_CW</string>
|
<string name="SET_EXPAND_CW" translatable="false">SET_EXPAND_CW</string>
|
||||||
<string name="SET_DISPLAY_ALL_NOTIFICATIONS_TYPE" translatable="false">SET_DISPLAY_ALL_NOTIFICATIONS_TYPE</string>
|
<string name="SET_DISPLAY_ALL_NOTIFICATIONS_TYPE" translatable="false">SET_DISPLAY_ALL_NOTIFICATIONS_TYPE</string>
|
||||||
<string name="SET_EXCLUDED_NOTIFICATIONS_TYPE" translatable="false">SET_EXCLUDED_NOTIFICATIONS_TYPE</string>
|
<string name="SET_EXCLUDED_NOTIFICATIONS_TYPE" translatable="false">SET_EXCLUDED_NOTIFICATIONS_TYPE</string>
|
||||||
|
@ -2236,4 +2239,14 @@
|
||||||
<string name="compose_shortcut_short_label1">Compose</string>
|
<string name="compose_shortcut_short_label1">Compose</string>
|
||||||
<string name="toast_error_peertube_not_supported">Your Peertube is too old and cannot be supported by the app.</string>
|
<string name="toast_error_peertube_not_supported">Your Peertube is too old and cannot be supported by the app.</string>
|
||||||
<string name="otp_message">Two factor authentication token</string>
|
<string name="otp_message">Two factor authentication token</string>
|
||||||
|
|
||||||
|
<string name="fetch_home_every">Fetch Home every</string>
|
||||||
|
<string name="type_of_home_delay_title">Home fetch time</string>
|
||||||
|
<string name="set_fetch_home">Automatically fetch home messages</string>
|
||||||
|
<string name="home_cache">Home cache</string>
|
||||||
|
<string name="fetch_home_messages">Fetch home messages</string>
|
||||||
|
<string name="auto_fetch_missing">Automatically fetch missing messages</string>
|
||||||
|
|
||||||
|
<string name="set_mention_at_top">Mentions at the top</string>
|
||||||
|
<string name="set_mention_at_top_indication">When replying mentions will all be added to the beginning of the message</string>
|
||||||
</resources>
|
</resources>
|
|
@ -13,6 +13,14 @@
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:summary="@string/set_capitalize_indication"
|
app:summary="@string/set_capitalize_indication"
|
||||||
app:title="@string/set_capitalize" />
|
app:title="@string/set_capitalize" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:defaultValue="false"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="@string/SET_MENTIONS_AT_TOP"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:summary="@string/set_mention_at_top_indication"
|
||||||
|
app:title="@string/set_mention_at_top" />
|
||||||
<!--
|
<!--
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
app:defaultValue="false"
|
app:defaultValue="false"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreference
|
||||||
app:defaultValue="false"
|
app:defaultValue="false"
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
app:key="@string/SET_FETCH_HOME"
|
app:key="@string/SET_FETCH_HOME"
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
app:key="@string/SET_REMEMBER_POSITION"
|
app:key="@string/SET_REMEMBER_POSITION"
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:title="@string/remember_position" />
|
app:title="@string/remember_position" />
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="@string/SET_AUTO_FETCH_MISSING_MESSAGES"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:title="@string/auto_fetch_missing" />
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
|
|
|
@ -194,6 +194,11 @@ public class SparkButton extends FrameLayout implements View.OnClickListener {
|
||||||
|
|
||||||
public void setImageSize(@Px int imageSize) {
|
public void setImageSize(@Px int imageSize) {
|
||||||
this.imageSize = imageSize;
|
this.imageSize = imageSize;
|
||||||
|
if (imageView != null) {
|
||||||
|
imageView.getLayoutParams().width = imageSize;
|
||||||
|
imageView.getLayoutParams().height = imageSize;
|
||||||
|
imageView.requestLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @ColorInt
|
public @ColorInt
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
Added:
|
||||||
|
- Cache home in background (default disabled -> New settings category and per account) / change frequency
|
||||||
|
- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)
|
||||||
|
- Automatically switch between tabs when searching
|
||||||
|
|
||||||
|
Fixed:
|
||||||
|
- Some crashes
|
17
src/fdroid/fastlane/metadata/android/en/changelogs/477.txt
Normal file
17
src/fdroid/fastlane/metadata/android/en/changelogs/477.txt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Added:
|
||||||
|
- Peertube 2FA support
|
||||||
|
- Cache home in background (default disabled -> New settings category and per account) / change frequency
|
||||||
|
- Auto-fetch missing messages for the Home (default disabled -> in Settings - Timelines)
|
||||||
|
- Automatically switch between tabs when searching
|
||||||
|
- More deep links detection
|
||||||
|
- Allow to group mentions at the top (default: disabled)
|
||||||
|
|
||||||
|
|
||||||
|
Fixed:
|
||||||
|
- Dynamic color for Android 12+
|
||||||
|
- Missing media description for previews
|
||||||
|
- Fix a crash when replying
|
||||||
|
- Fix button size not changed
|
||||||
|
- Forward tags in replies
|
||||||
|
- Media cannot be downloaded or shared with Android 10
|
||||||
|
- Some crashes
|
|
@ -0,0 +1,2 @@
|
||||||
|
- Виправлено деякі помилки
|
||||||
|
- Дозволити поділитися зі застосунком
|
20
src/fdroid/fastlane/metadata/android/uk/changelogs/405.txt
Normal file
20
src/fdroid/fastlane/metadata/android/uk/changelogs/405.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Додано:
|
||||||
|
- Налаштування експорту
|
||||||
|
- Поширення ручного переупорядкування списків на шкалі часу в підменю "Списки"
|
||||||
|
- Дозволено змінювати розподільник push-розсилок у налаштуваннях
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Покращено попередній перегляд зображень
|
||||||
|
- Покращено сповіщення
|
||||||
|
- Медіа профілю відображаються у сітці
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Не працюють деякі відео з Peertube
|
||||||
|
- Поважати обліковий запис видимості за замовчуванням під час відповіді
|
||||||
|
- Відрізняти gif від зображень
|
||||||
|
- Застосунок аварійно завершує роботу під час відкриття зовнішнього екземпляра на шкалі часу
|
||||||
|
- Кнопка "Видалити" у композиторі потоку призводить до аварійного завершення роботи програми
|
||||||
|
- Кнопка "Назад" відкриває багато старих активностей перед закриттям застосунку
|
||||||
|
- Проблеми зі спільним доступом
|
||||||
|
- Переупорядкування списків з проблемою інтерфейсу при зміні видимості
|
||||||
|
- Посилання неправильно відображається у повідомленнях з Friendica
|
15
src/fdroid/fastlane/metadata/android/uk/changelogs/418.txt
Normal file
15
src/fdroid/fastlane/metadata/android/uk/changelogs/418.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Додано:
|
||||||
|
- Зміна іконки застосунку (Налаштування > Інтерфейс)
|
||||||
|
- Дозволено відключати "запам'ятовувати позицію" в хронологіях
|
||||||
|
- Дозволено відключати агрегацію сповіщень у налаштуваннях
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Дозволено вимикати/вмикати медіа для сповіщень
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Допис втрачав "спойлер" при додаванні медіа
|
||||||
|
- Камера не працює на Android 11
|
||||||
|
- Агрегація сповіщень
|
||||||
|
- Вібрація при отриманні нових сповіщень
|
||||||
|
- Виправлено проблему з хронологією медіа
|
||||||
|
- Деякі збої в роботі
|
22
src/fdroid/fastlane/metadata/android/uk/changelogs/421.txt
Normal file
22
src/fdroid/fastlane/metadata/android/uk/changelogs/421.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Додано:
|
||||||
|
- Редагування повідомлень (якщо ваш екземпляр підтримує цю функцію)
|
||||||
|
- Закріплення/відкріплення повідомлень
|
||||||
|
- Встановлення мови за замовчуванням для перекладів
|
||||||
|
- Зміна іконки застосунку (Налаштування > Інтерфейс)
|
||||||
|
- Дозволити вимкнути "запам'ятовувати позицію" на часових шкалах
|
||||||
|
- Дозволити вимкнути агрегацію сповіщень у налаштуваннях
|
||||||
|
- Іконка на прев'ю медіа за наявності опису
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Дозволено вимикати/вмикати медіа для сповіщень
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Допис втрачав "спойлер" при додаванні медіа
|
||||||
|
- Камера не працює на Android 11
|
||||||
|
- Агрегація сповіщень
|
||||||
|
- Вібрація при отриманні нових сповіщень
|
||||||
|
- Виправлено проблему зі шкалою часу для медіа
|
||||||
|
- Виправлено деякі проблеми з темами
|
||||||
|
- Вирішено проблему з вбудованим браузером та openId
|
||||||
|
- Погана поведінка з Хронологією Артів
|
||||||
|
- Деякі збої
|
13
src/fdroid/fastlane/metadata/android/uk/changelogs/422.txt
Normal file
13
src/fdroid/fastlane/metadata/android/uk/changelogs/422.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Додано:
|
||||||
|
- Відображення клієнта в детальних повідомленнях
|
||||||
|
- Візуальна підтримка лапок, що починаються з ">"
|
||||||
|
- Збільшення відступів для потоків (від нуля до 20, за замовчуванням 5)
|
||||||
|
- Видимість публічних відповідей встановлено на unlisted (можна вимкнути)
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Зменшено розмір заголовка при збільшенні розміру тексту
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Фільтри не застосовуються
|
||||||
|
- Блокування акаунта не видаляє повідомлення у кеші
|
||||||
|
- Виправлено деякі збої
|
14
src/fdroid/fastlane/metadata/android/uk/changelogs/428.txt
Normal file
14
src/fdroid/fastlane/metadata/android/uk/changelogs/428.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Додано:
|
||||||
|
- Підтримка відкриття посилань, що містять у своєму шляху /@display_name/ (працює на старих пристроях)
|
||||||
|
- Відображення кількості відповідей при увімкнених лічильниках
|
||||||
|
- Додано підтримку фільтрації повідомлень профілю
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Складання подання займає всю ширину навіть у потоках
|
||||||
|
- Скинуто маркер push-сповіщення при очищенні кешу
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Чернетка зберігається при відповіді "ні" або діалоговому запиті без змін
|
||||||
|
- Фільтри не працюють з теґами
|
||||||
|
- Додано спеціальне повідомлення про помилку для теґів, за якими слідкують
|
||||||
|
- Порожні сторінки під час запуску застосунку
|
14
src/fdroid/fastlane/metadata/android/uk/changelogs/431.txt
Normal file
14
src/fdroid/fastlane/metadata/android/uk/changelogs/431.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Додано:
|
||||||
|
- Повна підтримка нових фільтрів для Mastodon 4
|
||||||
|
- Відвідувати профілі без авторизації / Дозволити відображати всі їхні повідомлення
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Компонування перегляду займає всю ширину навіть у потоках
|
||||||
|
- Облікові записи можна вимкнути за таймером з їхнього профілю
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Чернетка зберігається при відповіді "ні" або діалоговому запиті без змін
|
||||||
|
- Порожні сторінки під час запуску застосунку
|
||||||
|
- На деяких пристроях не вдається зберігати та ділитися медіа на деяких пристроях
|
||||||
|
- Додано підтримку сповіщень адміністратора
|
||||||
|
- Копіювання вмісту повідомлення
|
13
src/fdroid/fastlane/metadata/android/uk/changelogs/432.txt
Normal file
13
src/fdroid/fastlane/metadata/android/uk/changelogs/432.txt
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Додано:
|
||||||
|
- Список заблокованих доменів (дозволити розблокувати)
|
||||||
|
- Підтримати посилання gemini
|
||||||
|
- Запропоновані підписники
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Дозволено редагування пошукового запиту
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Чернетки видалялися без попередження
|
||||||
|
- Застосунок вилітає, коли встановлено проксі
|
||||||
|
- Фільтр не синхронізується після редагування
|
||||||
|
- Деякі збої
|
18
src/fdroid/fastlane/metadata/android/uk/changelogs/433.txt
Normal file
18
src/fdroid/fastlane/metadata/android/uk/changelogs/433.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
Додано:
|
||||||
|
- Список заблокованих доменів (дозволити розблокувати)
|
||||||
|
- Підтримати посилання gemini
|
||||||
|
- Запропоновані підписники
|
||||||
|
- Мод/Адмін: Керування екземплярами заблокованих доменів
|
||||||
|
- Відкривати повідомлення з іншим обліковим записом
|
||||||
|
- Дозволити відключити сповіщення для адміністраторів
|
||||||
|
- Сортування списків
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Дозволено редагування пошукового запиту
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Чернетки видалялися без попередження
|
||||||
|
- Видалено списки з "Керування термінами"
|
||||||
|
- Застосунок вилітає, коли встановлено проксі
|
||||||
|
- Фільтр не синхронізується після редагування
|
||||||
|
- Деякі збої / покращення
|
33
src/fdroid/fastlane/metadata/android/uk/changelogs/454.txt
Normal file
33
src/fdroid/fastlane/metadata/android/uk/changelogs/454.txt
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
Додано:
|
||||||
|
- Публікуйте випадкові цитати
|
||||||
|
- Групові репости на домашній шкалі часу
|
||||||
|
- Перейменування часових шкал Nitter
|
||||||
|
- Підтримка Android 13
|
||||||
|
- Нумерація з пошуком / трендом
|
||||||
|
- Дозволити видалення лівого поля в повідомленнях (за замовчуванням: вимкнено)
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Відображати кнопку перекладу лише тоді, коли мова відрізняється
|
||||||
|
- Повага до пробілів між словами у повідомленнях
|
||||||
|
- Кнопка фокусування стала доступнішою під час редагування медіа
|
||||||
|
- Візуальний зворотний зв'язок для блокування у списку облікових записів
|
||||||
|
- Візуальні зміни за допомогою композиції / верхньої панелі
|
||||||
|
- Використовуйте власну назву часової шкали Nitter для керування часовими шкалами
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Поведінка з перемикачем cw
|
||||||
|
- Урізані посилання на gimini
|
||||||
|
- Кнопки навігації не видно з медіа (Світла тема)
|
||||||
|
- Рядок стану з Android 5
|
||||||
|
- Виправлено посилання, на які не можна натиснути
|
||||||
|
- Виправлено глибокі посилання
|
||||||
|
- Виправлення віддалених потоків, які не відображаються у деяких випадках
|
||||||
|
- Додавання опису до спільних медіафайлів
|
||||||
|
- Відкриття з іншими обліковими записами
|
||||||
|
- Розмір символів не дотримується для Android 5-6
|
||||||
|
- Неправильний екземпляр отримано для instances.social
|
||||||
|
- Стрибає шкала часу при оновленні
|
||||||
|
- Посилання на згадки, теґи, URL-адреси не відображаються.
|
||||||
|
- Кастомні звуки каналів не застосовуються
|
||||||
|
- Користувачі з коротким іменем користувача не пов'язані між собою
|
||||||
|
- Виправлено збої
|
21
src/fdroid/fastlane/metadata/android/uk/changelogs/462.txt
Normal file
21
src/fdroid/fastlane/metadata/android/uk/changelogs/462.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Додано:
|
||||||
|
|
||||||
|
- Додано підтримку бульбашкової шкали часу в додаткових функціях з фільтрами
|
||||||
|
- Дозволено відображати публічні профілі за замовчуванням для отримання всіх повідомлень (Налаштування > Інтерфейс)
|
||||||
|
- Виправлено помилку: Дозволено публікувати повідомлення локально (можна вимкнути у Налаштуваннях)
|
||||||
|
- Pixelfed: Спеціальний макет для повного відображення медіа (також працює в інших застосунках, де є медіа)
|
||||||
|
- Дозволено вирівнювати ліві кнопки дій у повідомленнях
|
||||||
|
|
||||||
|
Змінено:
|
||||||
|
- Повністю перероблено посилання у повідомленнях (також згадки та теґи)
|
||||||
|
- Додано закріплений теґ у "будь-який", щоб уникнути його втрати під час перейменування часової шкали
|
||||||
|
|
||||||
|
Виправлено:
|
||||||
|
- Посилання на повідомлення, які не обробляються застосунком
|
||||||
|
- CW при редагуванні повідомлення
|
||||||
|
- Виправлено push-сповіщення з кількома обліковими записами
|
||||||
|
- Нові повідомлення або сповіщення про редагування не надсилаються
|
||||||
|
- Виправлено цитати з теґами/згадками
|
||||||
|
- Виправлено сповіщення
|
||||||
|
- Виправлено надсилання кількох медіа
|
||||||
|
- Виправлено збої в роботі
|
|
@ -1,16 +1,12 @@
|
||||||
It supports:
|
Він підтримує:
|
||||||
- Mastodon, Pleroma, Pixelfed, Peertube, GNU Social, Friendica.
|
- Mastodon, Pleroma, Pixelfed, Peertube, GNU Social, Friendica.
|
||||||
|
|
||||||
|
Застосунок має розширені особливості:
|
||||||
|
|
||||||
The app has advanced features (especially for Pleroma and Mastodon):
|
- Складання потоків
|
||||||
|
- Підтримка мультиоблікових записів
|
||||||
- Multi-accounts support
|
- Запланувати повідомлення від пристрою
|
||||||
- Schedule messages from the device
|
- Відстежуйте та взаємодійте з віддаленими екземплярами
|
||||||
- Schedule boosts
|
- Дії між обліковими записами за допомогою довгого натискання
|
||||||
- Bookmark messages
|
- Функція перекладу
|
||||||
- Follow and interact with remote instances
|
- Хронологія Артів
|
||||||
- Timed mute accounts
|
|
||||||
- Cross-account actions with a long press
|
|
||||||
- Translation feature
|
|
||||||
- Art timelines
|
|
||||||
- Video timelines
|
|
||||||
|
|
Loading…
Reference in a new issue